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

Hi Team, 

 

Can we using oData to insert localization strings with the same user. Example I want to enter the name of product in English and French using a user Supervisor in English. There is any way to do that?

Like 0

Like

2 comments

Hi Federico,

 

It's impossible since (if talking about products as an example) the localizable values for product names are stored in the SysProductLcz table and OData has no access to it. Additionally we have a correspondent problem registered for our R&D team and it's planned to add such a possibility to work with localization in OData requests.

 

Best regards,

Oscar

Thanks Oscar Dylan,

 

I think is a great idea and need it for many uses cases where you have multiple languages.

Show all comments

Hi community,

 

I have the following situation :

 

 

From the "ENCOWAY SESSION" button, I want to override the onClick() method from it to automatically start a business process from there. How can I do this ?

 

 

Furthermore, my business process should take the object id (e.g. opportunity id) corresponding to the id of the record where the button is and set it as a request parameter of a webservice.

 

Then, I want to open the response paramter, which is an URL, in a new window. The Script Task is in C#, so I want to have a similar method as window.open("URL") in Javascript. The "URL" should be the response parameter of the API.

 

Do you have any idea on how to achieve this ?

 

Here is a business process model summary of what I want :

 

 

Many thanks,

Jonathan

Like 0

Like

2 comments
Best reply

Hi Jonathan,

I have an article on that topic with the code you'll need to start the process and pass the current record Id into a process parameter here: https://customerfx.com/article/programmatically-starting-a-process-from…

However, as far as opening a new window, you can't do that from a server-side process. Instead, you can send a value, such as a URL string, from the server-side process to the client-side code, then the client-side code could open the window. I have an article on that topic here https://customerfx.com/article/sending-a-message-from-server-side-c-to-…

Ryan

Hi Jonathan,

I have an article on that topic with the code you'll need to start the process and pass the current record Id into a process parameter here: https://customerfx.com/article/programmatically-starting-a-process-from…

However, as far as opening a new window, you can't do that from a server-side process. Instead, you can send a value, such as a URL string, from the server-side process to the client-side code, then the client-side code could open the window. I have an article on that topic here https://customerfx.com/article/sending-a-message-from-server-side-c-to-…

Ryan

Dear Ryan Farley,

 

Your answer was really perfect. I managed to implement the whole process. Your articles are very pertinent. 

 

Many many thanks,

Jonathan

Show all comments
Question

Column not appearin in API call. 

 

I created a new column last week, it's not appearing in the API call. 

Changes are Publish and Behaviour is set to General.

Like 0

Like

4 comments

Is there anyone that can help please?

Which exact API call do you perform? Also try publishing the object directly from configurations and try calling the API once again and check the result.

 

Best regards,

Oscar

Oscar Dylan,

I'm using OData 3

 

When you say directly from the object, I do this when adding the new information. 

 

I have just found other items added 2/3 weeks ago are not pulling through either

Nicola Wall,

Were the new columns added in the section wizard (and not to the object directly)? In some older versions it wouldn't build the OData objects when done via the wizard and you had to open the object in the configuration and publish before it was available via odata (however, that's no longer the case in recent versions)

Have you tried opening the object and publish it to see if the properties show up?

Ryan

Show all comments

Hello Everyone.

I want to log in a separate file every communication with a Web-Service (request , response time etc).Is there any built-in , or tools from Marketplace to realize this task. Or I should customize the source -code.  

Like 0

Like

3 comments
Best reply

Petrika,

 

Perfect, then additionally you can use the same approach with EntitySchemaQuery, but create record is some section and then use the standard "Export to excel" functionality to get the file with request calls. So each time something is calling the GetErSumSq method you can create a record in some separate section (for example called "Integration call" and add information like DateTime.Now (to get the date and time when the method was called and which value was returned (sum))). Also you can try looking into the HttpContext, HttpContextAccessor and AppConnection to see which information is available there that can be used to additionally log the method call.

 

Best regards,

Oscar

Hi Petrika,

 

This should be done directly in the code of the 3rd party endpoint to which the call is performed (in case we are discussing the 3rd party webservice call from the business process). Logs of the integration call on the Creatio side are accessible only via standard IIS logs. Or you can enable the process tracing to see the status of the call.

 

In case the webservice is stored in the Creatio configuration (standard anonymous or regular webservice) then you can either add a part of inserting a record to some specific table in Creatio (via InsertQuery class for example) and retrieve data from there.

 

Best regards,

Oscar

Thank you very much for your immediate response Oscar. I have got an idea now.  This is what i am trying to do. I have created a button in the Front-End (Get Sum Ws) which calls in the Back-End a basic web service that caculates the sum of the AmountHC in Details Rows.

This is the code in the back-end

namespace test1323.Files.cs
{
    [EntityEventListener(SchemaName = "PetrikaExpenseReport")]
    [ServiceContract]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
    class DemoService : BaseService
    {
 
        [OperationContract]
        [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped,
ResponseFormat = WebMessageFormat.Json)]
 
        public decimal GetErSumSq(string name) 
        {
 
            EntitySchemaQuery entity = new EntitySchemaQuery(UserConnection.EntitySchemaManager, "PetrikaExpenseReport"); 
 
            entity.AddColumn("Id");
            entity.AddColumn("PetrikaTotalAmount");
            entity.AddColumn("PetrikaName");
            entity.PrimaryQueryColumn.IsVisible = true;                                                                   
 
            IEntitySchemaQueryFilterItem parentfilter =
            entity.CreateFilterWithParameters(FilterComparisonType.Equal,"PetrikaName",name);
            entity.Filters.Add(parentfilter);                                                                            
            EntityCollection records = entity.GetEntityCollection(UserConnection);                                      
            Guid parentId = records[0].GetTypedColumnValue<Guid>("Id");
 
           EntitySchemaQuery rows = new EntitySchemaQuery(UserConnection.EntitySchemaManager, 
           "PetrikaExpenseReportLines");
 
            rows.AddColumn("PetrikaAmountHC");
            rows.AddColumn("PetrikaAmountFC");
            rows.AddColumn("Id");
 
            IEntitySchemaQueryFilterItem childfilter =
            rows.CreateFilterWithParameters(FilterComparisonType.Equal, "PetrikaExpenseReport", parentId);
            rows.Filters.Add(childfilter);                                                                            
            EntityCollection lines = rows.GetEntityCollection(UserConnection);
 
            decimal sum = decimal.Zero;
 
            foreach (var r in lines) 
            {
                sum = sum + r.GetTypedColumnValue<decimal>("PetrikaAmountHC");
            }
            records[0].SetColumnValue("PetrikaTotalAmount", sum);                                             
            records[0].Save();
            return sum;
        }
}
}

I want to log in a separate file every communication (request , response time etc) with GetErSumSq.

Petrika,

 

Perfect, then additionally you can use the same approach with EntitySchemaQuery, but create record is some section and then use the standard "Export to excel" functionality to get the file with request calls. So each time something is calling the GetErSumSq method you can create a record in some separate section (for example called "Integration call" and add information like DateTime.Now (to get the date and time when the method was called and which value was returned (sum))). Also you can try looking into the HttpContext, HttpContextAccessor and AppConnection to see which information is available there that can be used to additionally log the method call.

 

Best regards,

Oscar

Show all comments

Hi community,

 

When implementing a web service, I have a GET method with a parameter :

 

public int GetMethod(string name)

 

In this method, I did a query to get the age of the person in parameter :

 

var select = new Select(UserConnection)

     .Column("Age")

     .From("Contact")

     .Where("Contact", "Name").IsEqual(Column.Parameter(name)) as Select;

 

Then I save the age into an int var :

 

var age = select.ExecuteScalar();

 

return age;

 

The problem is the following :

 

How can I check if the name of a contact in the method parameter exsists in the DB or not ?

 

Example :

 

if(name != exists) {

   return 0;

} else {

  return age;

}

 

Thanks a lot.

 

Best regards,

Jonathan

Like 0

Like

4 comments
Best reply

Hi Jonathan,

 

Usually you use dataReader to get the value from your select query. What you can do is:

bool hasRecord = false;
using (DBExecutor executor = UserConnection.EnsureDBConnection()) {
using (IDataReader dataReader = select.ExecuteReader(executor)) {
  while (dataReader.Read()) {
    hasRecord  = true;
  }
 }
}
if(hasrecord){
  return age
}else{
  return 0
}

Or you can just set the default value of the age =0. Therefore if the dataReader does not return any record, the default value age (0) will be returned.



regards,

Cheng Gong

Hi Jonathan

 

Please add the next using -     

     using Terrasoft.Common;   

on the top of the page(if you didn't have this one). 

 

Then in the part of the code when you are trying to retrieve the age:

 

if (name.IsNullOrEmpty())

{

return 0;

}

else

{

return age;

}

 

Best Regards, 

 

Bogdan L.

Hi Jonathan,

 

Usually you use dataReader to get the value from your select query. What you can do is:

bool hasRecord = false;
using (DBExecutor executor = UserConnection.EnsureDBConnection()) {
using (IDataReader dataReader = select.ExecuteReader(executor)) {
  while (dataReader.Read()) {
    hasRecord  = true;
  }
 }
}
if(hasrecord){
  return age
}else{
  return 0
}

Or you can just set the default value of the age =0. Therefore if the dataReader does not return any record, the default value age (0) will be returned.



regards,

Cheng Gong

Bogdan Lesyk,

Thanks for your answer. It helped a lot !

Cheng Gong,

 

Your answer is really perfect ! Thanks a lot, i'll definitely save this snippet of code for my future implementations.

 

Regards,

Jonathan

Show all comments

Hi community,

 

I was trying to implement a section under the "Sales" workplace just to have a google maps view of the adresses directly related to my customers under the "customers" or "accounts" section. I was searching some add-ons to do this and i found this one https://marketplace.creatio.com/app/google-maps-route-creatio and this one https://marketplace.creatio.com/app/toolkit-setup-map-view-creatio but nothing seems to work. I had many problems with the toolkit and when following the installation steps, it seems impossible to find the "Maps" tab under the concerned section. The first one, "google maps route creatio" has no documentation and I don't have a clue on how to install it and make it work. 

 

Could it be possible to implement a custom google maps API ? If yes, how could I get the latitude and longitude and retrieve the adresses of the contacts under the "customers" and "accounts" sections ?

 

It's a really simple thing to implement in JS/html/css but I have no clue on how to do this in Creatio.

 

Thanks a lot for your help.

 

Best regards,

 

Jonathan

Like 0

Like

2 comments

Dear Jonathan,

 

Thank you for your question!

 

In this case we would recommend contacting [Google Maps route for Creatio] support via email - support@chessit.se

 

Hope this helps!

 

Thank you!

 

Regards,

Danyil

Hi Jonathan,

 

Creatio Marketplace has a mapping tool called Mapsly geocode your records based on coordinates/address and save correspondingly coordinates/address back to Creatio.

 

You can also show pins of your contacts on the map, assign territories, build routes, etc.

Show all comments
Question

I've added a new column to Creatio yesterday and expecting to pull through the API but it's not there?

Does anyone know how long it takes? Or what I might be doing wrong?

Like 0

Like

4 comments

By the way I'm using ODATA3 through Power Bi

Hi Nicola,



It should appear straight after you created it.



Firstly please check if you published your object in which you've created your column. 



Than please find created column in advanced settings of the object and check if the "Usage mode" is not "None". It should be "General" (preferably) or "Advanced".

 

 

Best Regards, 

 

Bogdan L.

 

 

 

Thanks, i'll check

That's worked, seems the changes were saved but not published!

Thank you for your help

Show all comments

Hello Community,

 

Logging of incoming and outgoing API requests via Custom configuration services in Creatio is a very typical use case wherever system integration is in the picture. Logging the absolute URI, request/response body, response status code, any custom headers added to the request are standard in any enterprise system. 



I could not see any utilities or out of the box features to help log these requests. This is right now done by maintaining custom tables in the DB and logging any incoming or outgoing requests through custom logic.

 

The following features would help - 

  1. Logging inbuilt into the WebService element. It would help to have all outgoing requests using WebService elements be auto logged in the data base and be available for quick reference on the UI. An additional idea could be enabling a 'manual retry' option from the UI for use cases where an outgoing request failed  even after N number of configured retries.
  2. Utility or helper Classes on the server side which assist in tracking outgoing or incoming requests in the data base. A UI view of these logged requests could also help. Right now, we have to use 3rd party logging solutions like Loggly and write custom logic to maintain these logs.
2 comments

Hello!

 

Our R&D team has a problem registered on this topic on their side so to enable easy logging setup in the application UI for custom web-services and this problem is in the "Accepted" status so we can expect this logic implementation in one of the nearest releases. I will also let them know about this community idea so to speed up the problem solution.

 

Thank you for reporting this issue to us and helping us to make the application better!

 

Best regards,

Oscar

Oscar Dylan,

Thank you Oscar.

Show all comments

Hi Team

I created a Node.js script to upload attachments using FileApiService.

Here is my script:

var axios = require('axios');

var fs = require('fs');

establish_connection();

 

async function establish_connection()

{

        axios.post('https://company_name.bpmonline.com/ServiceModel/AuthService.svc/Login',

        {

            "UserName":"xxxxxxx",

            "UserPassword":"xxxxxxxxxxx"

            

        }).then (function (response){

            console.log('Imported credentials cookie from BPM Online!')

            c=response.headers['set-cookie']

            var bpm_loader=c[0]

            bpm_loader = bpm_loader.replace('BPMLOADER=','')

            bpm_loader=bpm_loader.split(';')[0]

            var aspx_auth=c[1]

            aspx_auth = aspx_auth.replace('.ASPXAUTH=','')

            aspx_auth=aspx_auth.split(';')[0]

            var bpm_csrf=c[2]

            bpm_csrf = bpm_csrf.replace('BPMCSRF=','')

            bpm_csrf=bpm_csrf.split(';')[0]

            var user_name=c[3]

            user_name = user_name.replace('UserName=','')

            user_name=user_name.split(';')[0]

            var auth = 'BPMLOADER='+bpm_loader+'; .ASPXAUTH='+aspx_auth+'; BPMCSRF='+bpm_csrf+'; UserName='+user_name+';';

            console.log('Authentication Successful!')

            upload_attachments(auth,bpm_csrf)

        }).catch(error => {

            console.log(error)

        })

}

async function upload_attachments(auth,bpm_csrf) {

  let myPdf = fs.readFileSync("./file_name.pdf");

  let myData = myPdf.toString("base64");

 

  let myBody = {

    Name: "test.pdf",

    Data: myData,

    TypeId: '529bc2f8-0ee0-df11-971b-001d60e938c6',//This indicates that the type of the attachment is file

    Version: "1",

    Usr_reference_column_id: 'xxxxxguid_of_the_record_xxxxxxxx'

  };

 

  let options = {

    method: "POST",

    url: 'https://company_name.bpmonline.com/0/rest/FileApiService/Upload',

    headers: {

        "fileapi14998570381414":"",

      "cache-control": "no-cache",

      "Accept-Encoding": "gzip, deflate",

      "Cache-Control": "no-cache",

      Accept: "*/*",

      "Content-Type": "application/json;odata=verbose",

      Cookie:auth,

      BPMCSRF:bpm_csrf,

      "entitySchemaName":"Usr_id_of_the_file_section"

    },

    body: myBody,

    json: true

  };

 

  request(options, function(error, response, body) {

    if(!error)

    {

        console.log('Success!')

        console.log(response)

    }

    else

    {

        console.log('Failed!')

        console.log(error)

    }

  });

}

 

References: 

1. https://community.bpmonline.com/questions/sending-blob-file-node

2. https://community.bpmonline.com/questions/upload-files-case

3. https://community.bpmonline.com/questions/how-upload-attachments-odata

4. https://community.terrasoft.ru/questions/realizacia-peredaci-pdf-dokumenta-po-protokolu-odata-s-ispolzovaniem-http-zaprosov

5. https://community.terrasoft.ru/questions/fileapiservice-zagruzka-dokumenta-v-faily-i-primecania-crm-sistemy

 

I am able to establish connection (Authorization is successful) and getting SUCCESS for the attachment. But in the response, I am receiving 'Request Error'.

 

Questions:

1. Is my URL correct?

2. Is the way I specified file section name correct?

3. Do I need to add/delete/change my request body?

4. Do I need to create a MODULE in ADVANCED SETTINGS?

 

NOTE: I am using BPM'Online Studio.

Like 0

Like

1 comments

It's hard to say how it should be done on Node.js. However, there is an easy way to find if your request is correct. Please install "telerik fiddler" and catch the request that you send to bpm'online. For example, send file.jpg. Then open bpm'online and add the same file for example to a contact. Catch the request with fiddler too. Then compare those two requests. Your task is to create a functionality that will send exactly the same request. 

If you need an example on JS, please put a break point into the "upload" method in the ConfigurationFileApi module (in a browser) and add a file to a contact. You'll see how bpm'online generates the request. Please try to do the same on Node.js. 

Show all comments