Hello Creatio community !

I would like to call the Creatio Webservice ..../0/rest/FinAppSpecService/InheritSpecificationsForFinApp  which automatically populates the Product Terms in Application, inside a Business Process. I can not call it in a c# class because the the constructor of FinAppSpecService class does not accept UserConnection as e parameter. Which is the proper way to solve this problem ?

Like 1

Like

11 comments
Best reply

Hello Petrika,

 

It's possible if you create a webservice record where the POST method complete address will be {siteURL}/0/rest/FinAppSpecService/InheritSpecificationsForFinApp and in the request parameters specify the following header parameters:

 

BPMCSRF

ForceUseSession (default value set to true)

Connection (default value set to true)

 

and the following cookies parameters:

 

BPMSESSIONID

UserName

BPMLOADER

BPMCSRF

.ASPXAUTH

 

in the webservice settings (since the FinAppSpecService service is not anonymous). The most difficult part here is setting cookies parameters. I could only recommend the following scenario here:

 

1) Create a separate authentication service webservice request (to {siteURL}/ServiceModel/AuthService.svc/Login)

2) Specify UserName and UserPassword request body parameters:

3) Add the Set-Cookie response header parameter:

4) Validate the response by performing a test call. It should return the Set-Cookie header that will be then used in the process:

5) Create a separate business process and configure it to run once per hour or once per half a day (depending on the value of the "UserSessionTimeout" system setting). The set-Cookie response header should be parsed to extract values for the

 

BPMSESSIONID

UserName

BPMLOADER

BPMCSRF

.ASPXAUTH

 

headers. It can be done by means of the script-task. Extracted values should be set as values for the system settings created separately (one per each header).

 

6) In your process where you need to call the FinAppSpecService in the "Call webservice" element set the values for the cookie parameters as values from the system settings from step 5. And also specify the value for the BPMCSRF header parameter.

 

7) Add all other request body parameters and call the service.

 

This approach should work since we simulate the Postman call of the same service, but set cookie parameters and header parameters via the separate business process and system settings.

 

Best regards,

Oscar

Hello Petrika,

 

It's possible if you create a webservice record where the POST method complete address will be {siteURL}/0/rest/FinAppSpecService/InheritSpecificationsForFinApp and in the request parameters specify the following header parameters:

 

BPMCSRF

ForceUseSession (default value set to true)

Connection (default value set to true)

 

and the following cookies parameters:

 

BPMSESSIONID

UserName

BPMLOADER

BPMCSRF

.ASPXAUTH

 

in the webservice settings (since the FinAppSpecService service is not anonymous). The most difficult part here is setting cookies parameters. I could only recommend the following scenario here:

 

1) Create a separate authentication service webservice request (to {siteURL}/ServiceModel/AuthService.svc/Login)

2) Specify UserName and UserPassword request body parameters:

3) Add the Set-Cookie response header parameter:

4) Validate the response by performing a test call. It should return the Set-Cookie header that will be then used in the process:

5) Create a separate business process and configure it to run once per hour or once per half a day (depending on the value of the "UserSessionTimeout" system setting). The set-Cookie response header should be parsed to extract values for the

 

BPMSESSIONID

UserName

BPMLOADER

BPMCSRF

.ASPXAUTH

 

headers. It can be done by means of the script-task. Extracted values should be set as values for the system settings created separately (one per each header).

 

6) In your process where you need to call the FinAppSpecService in the "Call webservice" element set the values for the cookie parameters as values from the system settings from step 5. And also specify the value for the BPMCSRF header parameter.

 

7) Add all other request body parameters and call the service.

 

This approach should work since we simulate the Postman call of the same service, but set cookie parameters and header parameters via the separate business process and system settings.

 

Best regards,

Oscar

Thank you very much for you response Oscar. It was very helpful.

Is there any article or example in the academy regarding point 5, parsing set-Cookie response header to extract values (inside a script task) ?

Petrika,

 

This is the task that should be covered by the C# code, using substring method for example. It's something as if you had a task to substring the "test" word from the "Hello test wordl!" string. Please find the way using the topics as the following:

 

https://stackoverflow.com/questions/9505400/extract-part-of-a-string-be…

 

Please also notice that the cookies values length is always constant and all of them start with the cookie name and the "=" character and end with the ";" symbol. This shouldn't be a difficult task.

 

Once string parts are extracted you can set them as parameter values (here is the Academy article that may be useful) and use these parameters in formulas to set parameter values to correspondent system settings.

 

Best regards,

Oscar

Oscar Dylan,

BPMSESSIONID is generated in the set-Cookie response header, because it seems that it's not found there ? I managed to extract everything else as required

Petrika,

 

Sorry, made a little mistake. BPMSESSIONID cookie is not returned as a response to the /AuthService.svc/Login call, but as a result of the first call to any other working endpoint like /0/odata/Account after authentication. Just try it in Postman and check the response headers in the next request that goes after AuthService request.

 

Best regards,

Oscar

Oscar ,

When i make a request from postman to another web-service the BPMSessionId is generated, I tested it.

Are you suggesting that i put the BPMSESSIONID as a reponse parameter to the InheritSpecificationsForFinApp, not as a request parameter ?

If i understand correctly.

 

Petrika,

If you're calling a configuration service, there's no need to actually use it as a service. It's simply a C# class that you can use directly.

For example, something like this: 

var svc = new Terrasoft.Configuration.FinAppSpecService();
svc.InheritSpecificationsForFinApp()

Depending on how the configuration service is implemented, you might need to also pass a UserConnection to it, which means you'd need to modify the service to allow this to be passed in.

You had mentioned: "I can not call it in a c# class because the the constructor of FinAppSpecService class does not accept UserConnection as e parameter. Which is the proper way to solve this problem?"

Why not just add two constructors to the class? One that is the default constructor and one that accepts a UserConnection? In the class you could add a method that either returns your private UserConnection variable (passed in by code consuming the class directly) or the one from the session (or BaseService) if being used as a service. I do it this way often and it is far more easy to consume the class directly than to call as a service when it's not needed to be used as a service (not to mention the extra overhead of using it as a service rather than consuming it directly)

Ryan

Ryan Farley,

 

FinAppSpecService() class constructor doesnt allow UserConnection as an argument. I can not modify the FinAppSpecService class because its part of the configuration. 

 

Ryan Farley,

Are you suggesting that i copy the 

FinAppSpecService  class to my package and make proper modifications to it ?

Petrika,

I was assuming this was your class, that you could modify, not a configuration one that was uneditable by you. 

I assume that FinAppSpecService inherits BaseService? If so, it has a UserConnection property that is protected (that does have a setter) as well as a protected constructor that accepts a UserConnection. Since they are protected you should be able to access them if your class is derived from it. 

it might work to just make a new class that inherits from the FinAppSpecService that allows a UserConnection to be passed? I've not tried that but it might work - just to throw out some ideas.

Something like this: 

public class UsrFinAppSpecServiceWrapper : FinAppSpecService
{
    public void SetUserConnection(UserConnection)
    {
        this.UserConnection = UserConnection;
    }
}

Then to use it:

var svc = new Terrasoft.Configuration.UsrFinAppSpecServiceWrapper();
svc.SetUserConnection(UserConnection);
svc.InheritSpecificationsForFinApp();

Again, I've not tested/tried that before, but I would assume something like this could work? If it does, still far easier route than calling it as a service IMO.

Ryan

Ryan Farley,

Ryan the response i get from the back-end 

is the same as the reponse i get from the front-end 

Still When i call this web-service from the back-end my goal isnt achieved. As you can see the detail of product terms isnt automaticalluy generated

Dont know if am missing something here

Thank you Petrika

Show all comments

Hello

I would like to build a business process parameter of type "Collection of records".

- The user is asked to choose an object in a lookup ( attachment file)

- This file is added to the collection (that is where I struggle)

- The user is asked if he want to add more object to the list.

- ... 

- The user validate and the list is used in a subprocess to process the choosen files

 

Many thanks if you can give me a hint on how to do that.   

Like 0

Like

3 comments

Dear Antoine, 

It's impossible to implement using basic application logic.

During single business process execution, it is possible only to upload files to a single object at once.

Hello, thank you for your answer.

I am not trying to upload multiple files.

I just want to ba able to add object references to an object collection parameter.

Let's say it like this:

- When you read Data from Creatio, if using filter others than ID, you get a collection of object. Which is stored into a "collection" variable.

-Now I have a collection, let say I read another object of the same type with anoter filter, I want to add that object to the above existing collection. How can I do that?

 

 

Thank you 

 

The code should look something like this:

// create collection/list or get from param
var list = new CompositeObjectList<CompositeObject>();
 
// create item and add to collection/list
var item = new CompositeObject();
item["SomeProperty"] = "Some value";
item["SomeOtherProperty"] = "Some value, etc";
list.Add(item);
 
// now set list in param
Set<CompositeObjectList<CompositeObject>>("MyCollectionParamName", list);

See https://customerfx.com/article/working-with-collection-parameters-in-a-…

Ryan 

Show all comments

Hi all,

I am trying to Create New Record in a custom Section using an open edit page in Business Process but the section doesn't appear on the open edit page activity .

in atlas release.

Like 0

Like

1 comments

Hello Sayed,

 

at the moment in the atlas release the business processes do not support pages from sections customly created. That is why this section does not appear in the BPM.

 

At the moment the BPM only supports already existing sections.

 

Our R&D team is already working to develop this functionality and it will be available in further releases.

 

Best regards,

Dariy

Show all comments

I have a business process with a preconfigured page that collects a few pieces of data, creates some related entities and then opens an edit page for one of the created records.  Everything runs fine, but after process execution and after the record is loaded in the edit page, I get the message "another user has completed this task".  Nothing is set to run in the background and the process is not set to run as system user.

Any ideas on how to prevent this message from showing or what's causing it in the first place?

 

Thanks -Jeremy

Like 0

Like

1 comments

Jeremy, I have the same issue in 7.18 in a process calling subprocesses and all are for running in the front end. At the end I am opening a record created in the process with some information collected from existing records and from an auto-generated page.  Have you been able to solve this point?

It is not blocking but an extra click for the end user...

Thanks,

Franck

Show all comments

I need to invoke Creatio Rest API from a Business Process to take advantage of out-of-the-box functions available via Creatio API.

For example I need to create a copy of a given Project. I saw that the "copy" button of the user interface invoke this endopint: /0/rest/ProjectUtilitiesService/CopyProjectWithStructure

The payload is like {"projectId": "54df197d-7708-4c6d-8dea-778465bec49d"}.

The response is like {"errorInfo":null,"success":true,"nextPrcElReady":false,"queryId":null,"responseStatus":null,"rowsAffected":-1,"CreatedProjectId":"0198cd7d-75b4-4924-8b06-49e2acbcb8cf"}

I need to do the same thing of the "copy button" inside a business process so I configured a web service (standard Web Service section) setting the endpoint and Basic Authentication (Supervisor username with its password set in custom system settings).

When I try the web service I get an "Unauthorized" response:

How should the web service be set to be used "from Creatio to Creatio"?

Is there a better way to reach the same goal from Business Processes?

 

Thanks

Like 1

Like

2 comments
Best reply

Have you tried just calling the classes directly as classes? There's no need to call as a service since it's just a C# class that you can call directly. Or bypass the ProjectUtilitiesService, which is just a service wrapper around ProjectCopyManager and try calling that instead.

Something like (not tested):

var copyManager = new ProjectCopyManager(UserConnection);
copyManager.CopyProjectWithStructure(projectId);

Ryan

Have you tried just calling the classes directly as classes? There's no need to call as a service since it's just a C# class that you can call directly. Or bypass the ProjectUtilitiesService, which is just a service wrapper around ProjectCopyManager and try calling that instead.

Something like (not tested):

var copyManager = new ProjectCopyManager(UserConnection);
copyManager.CopyProjectWithStructure(projectId);

Ryan

Ryan Farley,

Thanks Ryan, it works; here's my code inside a script task:

var copyManager = new Terrasoft.Configuration.ProjectCopyManager(UserConnection);
Guid newProjectId = copyManager.CopyProjectWithStructure(projectId);

 

Show all comments

Hello community,

I am implementing a way to import/export organizational data. The thing I want to do is create a business process that will transfer the data from SysAdminUnitCopy to SysAdminUnit and vice versa.  For the transfer of this data I created a script in sql server which transfers this data and executes successfully.

The next thing i need to do now is put this script in a sql script type schema and call it from a process.

Is there any way to call/execute a sql script schema from a business process?

 

Like 0

Like

1 comments

Hi

I want to send a notification to a case owner and an escalation manager when a case has not been updated in 48 hours.

For this I found in the admin guide a reference to performing a pipeline condition (https://academy.creatio.com/docs/7-18/user/bpm_tools/business_process_setup/formulas/process_formulas) and used this to create the following condition:

 

(decimal)RoundOff(([#System variable.Current Time and Date#]-[#Read modified time.First item of resulting collection.Modified on#]).TotalHours) > 48

However, when trying to save I get the following error - Formula value error: Invalid Operator. I cannot see why this is the case, as it follows the guide exactly with just the variable values updated.

 

thanks in advance

 

Mark

 

Like 0

Like

0 comments
Show all comments

Hi all!

I have an issue that I'm hoping someone has a simple answer for.

I have a BP that is set to run in the background (it's long running).  It iterates through many items in a script task and then executes a sub-process passing in parameters for that item.  I'm getting the user connection in both BPs using Get("UserConnection").  Both processes run fine if the parent process is set to run in the background, but the subprocess is not.  If I try to also run the subprocess in the background, it will execute the process but it will just get stuck with a status of "Running".  None of the steps show as being executed in the execution diagram.  It's as if the process get's scheduled, but no work actually gets done.

Is there some other way I should be executing the sub-process or fetching the user connection?

Like 0

Like

3 comments

Small update here.  There seems to be no difference between getting UserConnection by referencing it directly or by using  Get<UserConnection>("UserConnection").  Works fine either way, however, I still cannot call a BP set to run in the background from the script task.  Still shows "Running" in the log, but not steps are executed.  Anyone have any thoughts?

For those that may find there way to this post, I think I found the issue.  You need to check the "Serialize in DB" checkbox as well as the "Run process in background" checkbox.



This did expose a bug, however.  If you call the process client-side using the process UID, it runs fine, but if you use the name, it will not run in the background.  See sample code below:



           var config = {

                // Process name

                //sysProcessName: "UsrProcessName",

                sysProcessId: "ee018aff-1b7f-4713-993a-61b1f065df51",

                // parameters process                

                parameters: parameters

            };

            // run process

            Terrasoft.ProcessModuleUtilities.executeProcess(config);    



The above will work as shown, but if I comment out sysProcessId and uncomment sysProcessName, the UI will lock up and show processing until the main process completes.  In other words, it effectively ignores the setting to run in the background.

Jeremy Couzens,

That is interesting and good to know. Thanks for posting this.

Show all comments

We need to import some data to inactivate contacts on a monthly basis. I want to import a contact identifier and then execute a business process to mark the imported contacts as inactive.

 

We have other import needs that also need to execute a business process for each row. 

 

Does anyone know of any utility/marketplace add on that will allow us to execute a bp for each import row?

 

Ideally, it would be great to be able to have a BP system function that would import a file and then process each row, but I'd take a scripted object to read the file in and process each row.

Like 0

Like

1 comments

Hi Marry,



Unfortunately, are no such basic tools for imported records/

 

The only way to achieve your business task is to create a new business process with a start signal with an event that should trigger the signal (Record added / Record modified).



Please note you should enable this business process before the import and disable afer.

 

Best regards,

Bogdan

Show all comments

Our business process prompts the user to create a follow up calendar event if the current call event is listed as 'call later.'  Currently the process creates a new call task which OOTB opens a new call task screen. This isn't intuitive because the user cannot see their own calendar availability. I want to set the process to open their calendar view first where the user can confirm time/availability and manually add the task from there. I cannot find a way to open to the calendar view directly from the business process. Is there a way to do this?

 

Like 0

Like

2 comments

Dear Susan, 

we are currently investigating this case in order to find a possible ways of implementing this functionality. As soon as possible we will let you know with the update.

Pre-configured page cannot open the section, so you will need to create a logic with the script task that will send a socket message to the client (using MsgChannelUtilities.PostMessage method and the ClientMessageBridge (as described here)). Since the message should be received on any page you will need to replace the BasePageV2 module and add the message and the handler for the message there.

 

The handler should use the code similar to the one below:

this.sandbox.publish("PushHistoryState",{
                    hash:"SectionModuleV2/ActivitySectionV2/"
                });

so that the handler could open the ActivitySectionV2. But there is a problem with this: the activity section will be opened either in the schedule or grid view (depending on the last active view selected by the user for which the activity section will be opened). In this case you will also need to create some additional logic that will set the schedule view as an active view when opening the section from the message handler. The methods to override are initDataViews and loadActiveViewData.

 

Best regards,

Oscar

Show all comments