I'm creating a process that reads data and then needs to update a text column on that data by appending some new text to the existing string. I can read the data fine but the script task throws a null reference exception. Here is the simplified version of my script:

var programs = Get("ReadDataUserTask1.ResultEntityCollection");

foreach(var program in programs) {
    program.SetColumnValue("Campaign Flags", "Test");
}

return true;

The programs is null when I run the process.

Like 0

Like

7 comments

Dear Scott,

Try another approach to overcome the issue. Please read the collection of the Read Data in the following way: 

 var entities = Get<ICompositeObjectList<ICompositeObject>>("ReadDataUserTask1.ResultCompositeObjectList");

Afterwards proceed further with collection result.

Regards,

Anastasia

Anastasia Botezat,

using trying the above script, when I convert the list to string by doing:

entities.ToString());

I get  - Terrasoft.Common.CompositeObjectList`1[Terrasoft.Common.CompositeObject] (looks like the type and not the value)

Can you help?

Chani Karel,

 

There is no need to cast object to string since you can get the value from some column of the object using GetCompositeObjectColumnValue (in my case I was reading the "Full name" column value from the collection of contacts):

 

string name = GetCompositeObjectColumnValue&lt;string&gt;(contacts, "Name");

and then process the value according to your needs.

 

Best regards,

Oscar

Hi Chani Karel,

I think there are 2 things in your scripts:

1. You ReadDataUserTask1 result could be empty.

var programs = Get&lt;EntityCollection&gt;("ReadDataUserTask1.ResultEntityCollection");

Therefore, before the "foreach Loop", you really need to check if the programs is null or not. Otherwise, you might get the exception as you mentioned.

 

2. Please use the column code instead of column title to set value.

For example, in Contact there is column with code "JobTitle" and title "Full job title". If you need to set the value, you need to use the code "JobTitle".

 

regards,

 

Cheng Gong

Oscar Dylan,

using the tostring method was just to understand why I don't get the values as needed. 

What I need to do is this:

I get a list of 'contact in opportunity' by the read collection of records element. I need to get the contact as lookup  value and not as string (the Id and not name) in order to set parameters with the contacts and send email to them.

How do I do it?

Thank you.

Cheng Gong,

using the tostring method was just to understand why I don't get the values as needed. 

What I need to do is this:

I get a list of 'contact in opportunity' by the read collection of records element. I need to get the contact as lookup  value and not as string (the Id and not name) in order to set parameters with the contacts and send email to them.

How do I do it?

Thank you.

Chani Karel,

How did you end up solving this?

 

Kind regards,

Yosef

Show all comments

Hi Community,

How can I debug a script task from like setting some break point and tracing codes line by line.

Thanks

Like 0

Like

6 comments

See this

Dear Fulgen,

You can use the link provided in the previous comment by Grigory:

https://academy.bpmonline.com/documents/technic-sdk/7-12/working-server…

Since Script Task is the chunk of C# code, it can be treated as other C# code in the system.

The article provides steps to perform debugging, please use them to debug Script Task.

Regards,

Anastasia

Anastasia Botezat,

Hi Anastasia,

When I do download package to file system there is no .cs file under my business process folder, this business process should contain the script task of my business process for me to debug it in visual studio

Dear Fulgen,

I am sorry to hear that you experiences difficulties with this approach. I would like to offer you another approach to debug server code. I hope you will find it more suitable to work with:

https://academy.bpmonline.com/documents/technic-sdk/7-12/server-code-debugging

Regards,

Anastasia

Anastasia Botezat,

Hi Anastasia,

I already done this application setup below

I also made sure that the value of CompilerSourcesTempFolderPath directory is existing. But no schema source code was exported.

 

Dear Fulgen,

Please revert all that you do on the screenshot, this approach is deprecated. Afterwards, please change only one thing from the main article https://academy.bpmonline.com/documents/technic-sdk/7-12/visual-studio-… and this thing is setting:

<fileDesignMode enabled="true" /> in the main Web.config file and <add key="UseStaticFileContent" value="false" />



After that compile the application, and within the compilation following folder will be populated with all of the .cs files that you need:

your_path_to_bpmonline\Terrasoft.WebApp\Terrasoft.Configuration\Autogenerated\Src

Taking the file that you need into the new visual studio library project, you can attach the project to the IIS bpm'online process and debug the file as it described in the old article:

https://academy.bpmonline.com/documents/technic-sdk/7-12/server-code-de…

but skipping the part of the configuration. This will be the simplest approach: To take configuring steps from the new article but debugging from the old one.

Also, you may need to compile the system twice, before and after connecting to the IIS process in order to .cs files be exactly the same, in another case if files will be different, the breakpoints in visual studio will be gray and will not work.

Moreover, try to copy the file to a new project and place breakpoints in them, and try to drag and drop the original file from Terrasoft.WebApp\Terrasoft.Configuration\Autogenerated\Src to the main window of visual studio and place breakpoints in them too, after the attaching to the process and compiling the system, one of the approaches will definitely work for you.

 

Show all comments

Hello community,

I am trying to perform the following command from a Script Task element:

DELETE FROM [dbo].[UsrListDocuments] WHERE [Opportunity] = @P1 AND [Product] = @P2

Currently, the C# code is similar to this:

var opportunityId = Get("Read opportunity product.Opportunity");
var productId = Get("Read opportunity product.Product");
var delete = new Delete(userConnection)
        .From("UsrListDocuments")
        .Where("Opportunity").IsEqual(opportunityId)
        .Where("Product").IsEqual(productId);
        
return true;

Is this accurate? What would be the best practice in this case? The code is not working properly that´s why I am looking for your assistance.

Thanks.

Like 0

Like

2 comments

Hello,

As far as I understood your business goal, you are trying to fetch some parameters via [Read Data] element in your script task and pass it further to the Delete query.



Firstly, you need to get parameters in the [Script Task] from the [Read Data] element.

For the interpreted process the algorithm is the next:

1) Create a business process parameters and map it to the needed Read Data element. You can learn more about business parameters in our guide - https://academy.bpmonline.com/documents/technic-bpms/7-12/how-add-param…

In your example it will be something like:

[#Read opportunity product.First item of resulting collection.Opportunity#] and [#Read opportunity product.First item of resulting collection.Product#]

2) Use business-parameters in your Script-task.

var opportunityId = Get<Guid>("ProcessParam1");

var productId = Get<Guid>("ProcessParam2");

Then you need to get the userConnection in order to pass it in the Delete query:

var userConnection = Get<UserConnection>("UserConnection"); 

After that you can create a delete query:

var delete = new Delete(userConnection)

        .From("UsrListDocuments")

        .Where("Opportunity").IsEqual(opportunityId)

        .Where("Product").IsEqual(productId);

        

And execute it:

 delete.execute();

Tetiana Markova,

Thanks, Thetiana. It worked.

Show all comments

Let's say I read one object using Read data step and I choose to only read columns First name and Last name. How do I reference that data in Script task? I know I can copy those strings from step parameters to process parameters using Formula step but maybe there is a better way.

Like 0

Like

15 comments

Dear Carlos,

For the [Script-task] elements and methods that have the [For an interpreted process] checkbox selected, the wrapper class is generated that contains the initialization and declaration of methods. This wrapper enables you to access the process values. 

The Get method returns the value of an item or process.

Method signature:

Get<T>(string path)

where:

  • T — parameter value type.
  • path — a string that specifies the path to a parameter or property. The path is built according to these rules:
  1. “parameter name”
  2. “property name”
  3. “element name.parameter name”
  4. “element name.property name”

Oliver

Oliver,

I don't see a parameter First name though. The only related parameter that I see is Columns to read.

Carlos Zaldivar Batista,

You don't need any parameters and select any specific columns to read in the element Read Data, simply use “element name.property name” to get the field value in the Script task.

Oliver

Oleh Chudiiovych,

Ok, so I have a step with code ReadSomeData and I try to read the columns of returned object like this:

Get&lt;Entity&gt;("ReadSomeData.ResultEntity").GetTypedColumnValue&lt;string&gt;("UsrFirstName")

I get NullReferenceException though because the Get method returned null.

Try read data from all columns. Also possible for your query (filter) no records? Do it work if you remove the filter

Grigoriy,

I read data from all columns and the query returns records.

Dear Carlos,

As far as we can see from your method you are trying to read values from the "UsrFirstName" column and we don't know what data is stored there and what are you trying to read. Please re-check all your columns and also try Grigoriy's suggestion about filters.

Oscar

Ok, so I created a new trial environment with default test data and in that environment I created a process:

 

The Read data step looks like this:

I set up the step name too:

And that is my Script task code:

Name is a process parameter that is shown in the auto-generated screen. That's what the screen shows after running the process:

There are no filters in the read data step and the data is there. What should I change to make the script task work?

Hi by default read data have code "ReadDataUserTask1".

Try this:

var entity = Get<Entity>("ReadDataUserTask1.ResultEntity"); 

 

See read data advanced mode for get elenent code (

In the advanced mode, the element setup area contains additional parameters and connections with system records

To access the advanced mode, click the btn_advanced_mode.png button in the element setup area and select the [Advanced mode] menu command

)

Sory. For interpretable processes, you can only directly work with the methods and parameters of the elements through the formula.

In autogenerate page set page item via formula like:

[#Read data 1.First item of resulting collection.First name#] 

Grigoriy,

Thank you. And is it possible to use this formula in a script tasks?

Yes

1. Create a process parameter of type String - TestParam.

2. In the parameter value specify [#Read data 1.First item of the resulting collectionFirst name#].

3. In the Task-script element, work with the parameter.

     var contactFullName = Get<string> ("TestParam");

Grigoriy,

Ok, thank you.

Does anyone know if this is still the case? i.e. that it's necessary to save each individual field to a parameter in order to access them inside a Script Task element of a Business Process? It seems like it really should be simpler to access data on any of the fields!

 

I am aware of being able to query the entity directly within the Script Task, but I'd like to keep as much of the business logic in easy-to-read BP steps as possible, including reading data.

Dear Harvey,

 

Yes, the logic remains the same. There is still to call for read data element through the script task without the intermediate process parameters or settings. This logic will be review by our developers, it is confirmed by our R&D but we do not know when it will be done.

 

Regards,

Dean

 

Show all comments

I know that we can use Get to read process parameters in C# scripts but I don't know how to use this method to read process elements' properties, like for example Created record ID. So far what I'm doing is making a new process parameter and setting its value with Formula block. Is there a better way?

Like 0

Like

2 comments

Dear Carlos,

You can access the process elements parameters in following ways. Lets say I have a ReadData element before my ScriptTask and I want to obtain the CaseId from it in my ScriptTask. First, I click "Advanced mode" (tree dots in the right top corner of right panel):

 

There you can find the Code of the element, so to address it with. Also, in the parameters tab you can see all available parameters of the element. In my example this is ReadDataUserTask1.

Here I can obtain the collection of entities from ReadData and set them to parameter, if needed:

EntityCollection entities = Get&lt;EntityCollection&gt;("ReadDataUserTask1.ResultEntityCollection");
Set("Param1", entities);

The other approach is to access properties though the dot, like any other properties retrieval:

var parameter = Get<Guid>(ReadDataUserTask1.CaseId);

Also, there is still working approach with read data element and setting value to the process parameter through formula element you have mentioned.

Hope you find it helpful,

Anastasia Botezat

 

Anastasia Botezat,

Thank you very much.

Show all comments

Hi everyone,

I need to call a sub-process from a C# script task, I found this code:

var showAdressProcessUId = new Guid("abfbf7ee-e499-45e9-9d22-b9e91a46683d");
var manager = UserConnection.ProcessSchemaManager;
var schema =  (ProcessSchema)manager.GetInstanceByUId(showAdressProcessUId);
var moduleProcess = schema.CreateProcess(UserConnection);
moduleProcess.SetPropertyValue("PageInstanceId", PageInstanceId);
moduleProcess.SetPropertyValue("ActiveTreeGridCurrentRowId", ActiveTreeGridCurrentRowId);
moduleProcess.SetPropertyValue("TreeGridSelectedRowsIds", TreeGridSelectedRowsIds);
moduleProcess.SetPropertyValue("SchemaName", "Contact");
moduleProcess.SetPropertyValue("RouteMode", false);
moduleProcess.Execute(UserConnection);

From ShowContactAddressOnMapProcess

If I use it for my process:

var _sendMailId = new Guid("84e96844-b0ae-4edc-8b5e-20d1ba13fb8b");
var _manager = UserConnection.ProcessSchemaManager;
var _schema = (ProcessSchema)_manager.GetInstanceByUId(_sendMailId);
var _moduleProcess = _schema.CreateProcess(UserConnection);
_moduleProcess.SetPropertyValue("Test1", "Something");
_moduleProcess.Execute(UserConnection);

Throws this exception :

Terrasoft.Common.InvalidObjectStateException: missing property "Test1" of type "ProcessComponentSet".

 

I would need to know how it works or another way to do it, I need to call a sub-process inside a for loop.



Thanks.

Like 0

Like

6 comments

Dear Ezequiel,

It is nor recommended to use sub-processes and the processes in general for such purpose. Technically you can call a business process from a business process. But if you correct the code above and execute it  the system will freeze and the processes will block each other. All users meanwhile will not be able to use the system properly.

Please adjust the business-purpose you want to achieve in order to avoid using business-processes or find another architecture solution.

Oliver

Hi, 

I see, I'm trying to send an email inside the loop, but I can't find in any of the existing process how to send an email with a template though a script task.

If someone knows how to do it or has an example, I would appreciate it if you could explain it or show it to me.

Thanks.

Dear Ezequiel,

There is "Send email" BP element you can use to reach your goal. Just select in a message input "Template message" and you will be able to choose what template to use.

 

 

Peter Vdovukhin,

Yes I know, but like I said I need to use it in a for loop, with that I could use it if I had the code to call a sub-process from a script task.

Dear Ezequiel,

As you wrote to bpm'online support, let's continue our conversation there. After resolving your task I will post an answer here.

Here is a simple example I have successfully tested:

A first business process contains only script task with such code:

for(int i = 0; i < 2; i++) {

    var _sendMailId = new Guid("cc1b3e27-4d11-4957-ac40-b22ff5b11aff");

    var _manager = UserConnection.ProcessSchemaManager;

    var _schema = (ProcessSchema)_manager.GetInstanceByUId(_sendMailId);

    var _moduleProcess = _schema.CreateProcess(UserConnection);

    _moduleProcess.SetPropertyValue("UsrTestParameter", "Letter number " + i);

    _moduleProcess.Execute(UserConnection);

}

A second business process with GUID = cc1b3e27-4d11-4957-ac40-b22ff5b11aff contains only Send email element that has a text parameter UsrTestParameter and use this parameter for email subject. The second business process HAS to be compiled to be called from the first business process.

Show all comments

Hi there! 

I'm looking an example and a step by step to call an own DLL from an element of BPM, probably "Task Script".

I tried to use something similar to what is proposed in the article: https://community.bpmonline.com/questions/integration-bpmonline-other-a…

but it did not work

Regards.

 

Like 0

Like

1 comments



Hello community!

I need get in a bussines process a collection parameter and then use that in a script task into a foreach. Any example about that?

 

Regards,

 

Like 0

Like

5 comments

Dear Federico,

Please check the instructions on how to work with collections within [Read data element]. This will help you to implement your own process.



Algorithm of the work with a collection from Read data:



1.Disable the formula validator in business process designer. You can open the console and execute the following script for that:

var featureCode = "UseProcessFormulaServerValidation";

require(["FeatureServiceRequest"], function() {

                var featureRequest = Ext.create("Terrasoft.FeatureServiceRequest", {code: featureCode});

                featureRequest.updateFeatureState({

                               forAllUsers: true,

                               state: Terrasoft.FeatureState.DISABLED // ENABLED

                }, ()=>console.log("Done"));

});

 

2. In [Read data] element go to extended options and tick:

Read first = true

Number of records to read = 100 //Number of records available in a collection.



3. Create a process parameter with EntityCollection type and map it to the resulting collection of [Read data]. This parameter does not exist out of the box, but you can create it manually. 

Example:

[#MyRead.Resulting collection#]

*  MyRead – [Read data] element header.

* Resulting Collection - added manually

 

4. Assign a process parameter to a new variable in ScriptTask. Here is the example how to process the collection:

EntityCollection entities = Get("MyEntity");

var result = new Collection();

foreach(Entity entity in entities) {

                var cityName = entity.GetTypedColumnValue("Id");

                string temp = cityName.ToString();

                result.Add(temp);

                }

 

string displayValue = result.ConcatIfNotEmpty(",");

Set("MyResult", displayValue);

return true;

 

MyRead – reading datat in any element.

MyEntity process parameter with EntityCollection type. Parameter value= [#MyRead.Resulting collection#]

MyResult - string parameter. You can store record IDs from the collection. Then this parameter is shown on the auto generated page for the testing purposes.  

Best regards,

Lily

Lily Johnson,

Hello,

I tried the above script task as below:

EntityCollection entities = Get("MyEntity");

var result = new Collection();

foreach(Entity entity in entities) {

                var productName = entity.GetTypedColumnValue("Name");

                string temp = productName.ToString();

                result.Add(temp);

                }

string displayValue = result.ConcatIfNotEmpty(",");

Set("UsrLatestOrderProduct", displayValue);

return true;

 

But, here I'm getting below errors:

 

Lily Johnson,

Hello,

 

Can you elaborate on how Auto-Generated Page works upon this case? 

 

Many Thanks

Riddhi Jadeja,



As we can see from the screenshots you have provided - GetTypedColumnValue is used incorrectly. 

GetTypedColumnValue("Name") is used without specified type of this field. 

It should be GetTypedColumnValue<string>("Name")



Kind regards,

Roman

Sarthak Jain,



Can you please specify your question with more details? 

How exactly Auto-Generated Page will be related to the discussed case? 



Thank you in advance,

Roman

Show all comments

Hello Community!

Any have a example to send a notification menssage from script task c#?

The idea is make a foreach and for each value send a notification to the user.

Regrads, 

 

Like 1

Like

2 comments

Dear Federico,

Here's the example for you:

//create reminding
/**
                 * @param addresserContactId // select Id from Contact
                 * @param addresseeContactId //select Id from Contact
                 * @ RemindTime {DateTime}
                 * @param description {String}
                 * @param subjectRecordId //select Id from [your schema]
                 * @param sourceId // select Id from RemindingSource --where Name = 'Owner' or Name = 'Author'
                 * @param sysSchemaUid //select Uid from SysSchema where Name = [your schema]
                 * @param subjectCaption {String}
                 * @param typeCaption {String}
                 *
                 * return {Terrasoft.Collection of InsertQuery}
                 */
                createRemindingInsert: function (addresserContactId, addresseeContactId, remindTime, description,
                                                 subjectRecordId, sourceId, sysSchemaUid, subjectCaption, typeCaption) {
                    var insert = Ext.create('Terrasoft.InsertQuery', {
                        rootSchemaName: "Reminding"
                    });
                    insert.setParameterValue('Id', Terrasoft.generateGUID(), Terrasoft.DataValueType.GUID);
                    insert.setParameterValue('CreatedOn', new Date(), Terrasoft.DataValueType.DATE_TIME);
                    insert.setParameterValue('CreatedBy', Terrasoft.SysValue.CURRENT_USER_CONTACT.value, Terrasoft.DataValueType.GUID);
                    insert.setParameterValue('ModifiedOn', new Date(), Terrasoft.DataValueType.DATE_TIME);
                    insert.setParameterValue('ModifiedBy', Terrasoft.SysValue.CURRENT_USER_CONTACT.value, Terrasoft.DataValueType.GUID);
                    insert.setParameterValue('Author', addresserContactId, Terrasoft.DataValueType.GUID);
                    insert.setParameterValue('Contact', addresseeContactId, Terrasoft.DataValueType.GUID);
                    insert.setParameterValue('RemindTime', remindTime, Terrasoft.DataValueType.DATE_TIME);
                    insert.setParameterValue('Description', description, Terrasoft.DataValueType.TEXT);
                    insert.setParameterValue('SubjectId', subjectRecordId, Terrasoft.DataValueType.GUID);
                    insert.setParameterValue('Source', sourceId, Terrasoft.DataValueType.GUID);
                    insert.setParameterValue('SysEntitySchema', sysSchemaUid, Terrasoft.DataValueType.GUID);
                    insert.setParameterValue('SubjectCaption', subjectCaption, Terrasoft.DataValueType.TEXT);
                    insert.setParameterValue('TypeCaption', typeCaption, Terrasoft.DataValueType.TEXT);
 
                    return insert;
                },
                /**
                 *
                 * @param remindingInsertCollection {Terrasoft.Collection of InsertQuery}
                 * @param callback
                 */
                executeReminding: function (remindingInsertCollection, callback, scope) {
                    var batchQuery = Ext.create("Terrasoft.BatchQuery");
                    Terrasoft.each(remindingInsertCollection.getItems(), function (insertQuery) {
                        batchQuery.add(insertQuery);
                    });
                    batchQuery.execute(callback, scope);
                }

Lisa

Lisa Brown,

Hi Lisa. Its been a few yrs since your reply. Is there a better way to do this in the product now? The code you have mentioned writes to the DB and triggers an execute. 

Show all comments

Hello everyone!

I hope you can help me!

I want get the value of a property of a element of my Business Process.In this case, I read all of a employee and from my script task, I want to ask about the value of one of fields, "UsrClaveAltaTemprana". The compilation of the script task is correct but when I do the test from the employee's page and I will see ths process log it pulls the following error.

System.NullReferenceException: Object reference not set to an instance of an object.

   at Terrasoft.Common.ReflectionUtilities.GetPropertyValueByPath(Object source, String propertyPath)

   at Terrasoft.Core.Process.ProcessModel.Get[T](String propertyPath)

   at Terrasoft.Core.Process.UsrProcess3MethodsWrapper.ScriptTask1Execute(ProcessExecutingContext context)

   at Terrasoft.Core.Process.ProcessFlowElement.Execute(ProcessExecutingContext context)

I attached image

 

 

 

 

 

 

 

       

I appreciated your help!

King Regards,

 

Ezequiel Gómez

Like 0

Like

1 comments

Dear Ezequirel,

The reason for an error is that you are trying to obtain value of an Id. Let me explain. 

"UsrClaveAltaTemprana" is a lookup field. Basically, it is a link to another object, so in database it is stored as an Id, but not the value.

If you intend to receive a value, you need to insert a "Read Data" element before a script task. Read the value from the object of "UsrClaveAltaTemprana" lookup, where Id equals the Id retrieved from the record. 

Set received value to new parameter. Then use this parameter in script task.

Hope this helps.

Regards, 

Anastasia

Show all comments