Hi everyone, 

I'd like to automate a data Import from a FTP server using a business process, without downloading the file locally.

I also found this article (https://community.creatio.com/questions/how-automate-imports-ftp-locati…) , but the links have either been removed or deleted.

I would like to know whether it is possible to use C# code in a Script Task to store the data stream in RAM and eventually recover the data to import. 

Is it reasonable for a cloud- stored enviroment to handle this kind of process with CSV files of approx. 2 MB?

Like 1

Like

3 comments

Hi Federica, 

 

Actually you are still capable to use OData with business task to achieve required implementation. You don't need to use Scheduler for this, so disregard these deleted links, I will give you fresh one , please take a look on the actual OData 4 link with guide how to set up the integration: 

 

https://documenter.getpostman.com/view/10204500/SztHX5Qb?version=latest

 

Please also check out this link from Marketplace where you may find another solution for you task: 

 

https://marketplace.creatio.com/app/file-manager-creatio

 

here you may set up key features of needed requirements, so you can make "One click" implementation and it might be much easier for you.

 

Best Regards, 

 

Bogdan L. 

The .NET FtpWebRequest class can download a file to an in-memory stream (without actually saving the file anywhere) that you can then process from the stream. This could be used from a ScriptTask in a process etc

FtpWebRequest request =
    (FtpWebRequest)WebRequest.Create("ftp://ftp.example.com/path/file.txt");
request.Credentials = new NetworkCredential("username", "password");
request.Method = WebRequestMethods.Ftp.DownloadFile;
 
using (Stream stream = request.GetResponse().GetResponseStream())
using (StreamReader reader = new StreamReader(stream))
{
    while (!reader.EndOfStream)
    {
        string line = reader.ReadLine();
        // process the line as needed
    }
}

Ryan

Ryan Farley,

That's the script I'm running at the moment and it works!

Show all comments

Hello community,



Can you please advise me how to run the server code (C#) from a client page (JS).

The business process has a delay when launching, so this method is not the best solution in my case.

 

Thank you in advance.

Mariia

Like 0

Like

2 comments
Best reply

Hello,

 

Please check the following link https://academy.creatio.com/docs/developer/back-end_development/configu…;



Best Regards,

Tetiana Bakai

Hello,

 

Please check the following link https://academy.creatio.com/docs/developer/back-end_development/configu…;



Best Regards,

Tetiana Bakai

As Tetiana mentioned, how this is typically done in Creatio is by creating a configuration web service that you call from your client-side js code. It's actually one of my favorite parts of Creatio and makes for a very powerful development experience and allows you to keep the UI very quick by passing things between the client and the server and performing operations on the server rather than the client. Along with the Academy article Tetiana shared, I also have a write up of how to create a configuration web service and call it from client-side code here: https://customerfx.com/article/creating-a-web-service-and-consuming-it-…

Ryan

Show all comments

Hi Team,

 

I want an schedule an email weekly with a excel report as attachment that will  be generated by system 

 

I used These application to generate excel report and attach to email automatically 

 

Excel pivot report for Creatio

Excel reports builder for Creatio

Printable attachment in email for Creatio

'Save printable' process element

Send email with attachments

 

But was unable to generate and attach excel to email on a scheduled process

Excel attachment is mandatory 

 

Please suggest a work around to solve this.

 

Thank You in Advance

 

Like 0

Like

1 comments

Hello,

There is no way to generate the excel report since it is not piece of default functionality. The workaround to attach the excel report manually on the attachments detail and use simple process to send it. Here is the example that send attachments from account:

 

 

 

 

Other than that, it is necessary to develop custom integration that will call for endpoint of the excel report generation, get file, send it to Creatio and then the process would re-send it according to your needs.

 

When clicking on generate excel report, the query calls for https://yourwebsite.com/0/rest/IntExcelReportService/GetExportFiltersKey with the following parameters:

EsqString: "{\"rootSchemaName\":\"Contact\",\"operationType\":0,\"includeProcessExecutionData\":true,\"filters\":{\"items\":{\"8488ded0-40f6-4167-95ca-20bccc49bfc1\":{\"filterType\":1,\"comparisonType\":3,\"isEnabled\":true,\"trimDateTimeParameterToDate\":false,\"leftExpression\":{\"expressionType\":0,\"columnPath\":\"Id\"},\"rightExpression\":{\"expressionType\":2,\"parameter\":{\"dataValueType\":1,\"value\":\"c4ed336c-3e9b-40fe-8b82-5632476472b4\"}}}},\"logicalOperation\":0,\"isEnabled\":true,\"filterType\":6},\"columns\":{\"items\":{\"Full name\":{\"caption\":\"Full name\",\"orderDirection\":0,\"orderPosition\":-1,\"isVisible\":true,\"expression\":{\"expressionType\":0,\"columnPath\":\"Name\"}},\"Age\":{\"caption\":\"Age\",\"orderDirection\":0,\"orderPosition\":-1,\"isVisible\":true,\"expression\":{\"expressionType\":0,\"columnPath\":\"Age\"}},\"Email\":{\"caption\":\"Email\",\"orderDirection\":0,\"orderPosition\":-1,\"isVisible\":true,\"expression\":{\"expressionType\":0,\"columnPath\":\"Email\"}}}},\"isDistinct\":false,\"rowCount\":-1,\"rowsOffset\":-1,\"isPageable\":false,\"allColumns\":false,\"useLocalization\":true,\"useRecordDeactivation\":false,\"serverESQCacheParameters\":{\"cacheLevel\":0,\"cacheGroup\":\"\",\"cacheItemName\":\"\"},\"queryOptimize\":false,\"useMetrics\":false,\"adminUnitRoleSources\":0,\"querySource\":0,\"ignoreDisplayValues\":false,\"isHierarchical\":false}"

RecordCollection: ["c4ed336c-3e9b-40fe-8b82-5632476472b4"]

ReportId: "ec1724f7-e58e-491f-8471-0ce19b61bc02"

 

so it is necessary to generate the POST request to this endpoint  /0/rest/IntExcelReportService/GetExportFiltersKey with similar parameters as above. As the response - you will get the file. 

Here is the similar post describing how to generate such POST request

 

https://community.creatio.com/questions/how-can-i-generate-excel-report…

 

Regards,

Dean

Show all comments

Hi Team,

 

My requirement is to run a scheduler job on monthly basis, Which would retrieve all employee and then group by a specific conditions and do some calculations and update them.

 

To do calculation we need to retrieve the few more objects.

So that we can do this using C# in console application i can run in task scheduler as i am using OnPremise Creatio CRM.

Like 0

Like

1 comments

Hi Nagaraju,

 

To run this action once per month a business process with a timer can be created that will create a scheduler task. And then you can either add a script task to the process, or use read data and read a collection of records or implement any other logic required.

 

Best regards,

Oscar

Show all comments

Hi all,

I am trying to insert a record to an entity using esq as follows in my web service.

[OperationContract]
        [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare,
        ResponseFormat = WebMessageFormat.Json)]
        public string InsertCaseESQPostForSATS(DebitCardDataForSATS debitCardData)
        {
            try
            {
                var caseSchema = SystemUserConnection.EntitySchemaManager.GetInstanceByName("SBLSRM");
                var entity = caseSchema.CreateEntity(SystemUserConnection);
                entity.SetColumnValue("SBLAccountNumber", debitCardData.AccountNo);
                entity.SetColumnValue("SBLService", debitCardData.ServiceId);
                
                entity.SetDefColumnValues();
                var result = entity.Save();
                return result.ToString();
            }
            catch(Exception ex)
            {
                return ex.Message;
            }
        }

 

Column 'SBLService' is a lookup column and I am having problem while inserting a record, says, "Value 'SBLService' was not found.". I have checked and confirmed that the object has the column and is published fine. Can somebody assist me on this? How can I set value for a lookup column?

 

 

Like 0

Like

4 comments
Best reply

Roman Raj Bajracharya,

 

the value should be passed as an actual Id and also the column name shouldn't contain the . separator:

 

entity.SetColumnValue("SBLServiceId", Id here);

 

For example see this post https://community.creatio.com/questions/how-create-or-update-record-usi… where Dmytro provided an example of working with GUID columns.

 

Best regards,

Oscar

Hi,

 

Try SBLServiceId instead and also take a look in the database and check how is this column called there.

 

Best regards,

Oscar

Oscar Dylan,

Hi Oscar,

Thank you for the reply. How do I provide the value of Id of SBLService lookup? In the database, it is just 'Id' for the lookup id. I tried to access by doing SBLService.Id but it didn't help.

entity.SetColumnValue("SBLService.Id", debitCardData.ServiceId);

 

Roman Raj Bajracharya,

 

the value should be passed as an actual Id and also the column name shouldn't contain the . separator:

 

entity.SetColumnValue("SBLServiceId", Id here);

 

For example see this post https://community.creatio.com/questions/how-create-or-update-record-usi… where Dmytro provided an example of working with GUID columns.

 

Best regards,

Oscar

Oscar Dylan,

Hi Oscar,

Thank you very much. The record is now inserted. But I am having problem on the execution of a process that should occur when a record on this entity is created. This process is executing well when I create a new record from frontend(UI). Any ideas on this?

Show all comments

Dear Community,

 

I am using EntityEventListener to update a connected record of a records before deleting it using the following method:

public override void OnDeleting(object sender, EntityBeforeEventArgs e)

But when deleting the record it says there is connected records, I think this is linked to the count I am doing to check the number of records that match a condition.

 

Here the full code :

[EntityEventListener(SchemaName = "Activity")]
public class ActivityEventListener : BaseEntityEventListener
{
 
        public override void OnDeleting(object sender, EntityBeforeEventArgs e)
        {
                base.OnDeleting(sender, e);
                Entity activity = (Entity)sender;
                var userConnection = activity.UserConnection;
	        var accountId = activity.GetTypedColumnValue<Guid>("AccountId");
                var activityId = activity.GetTypedColumnValue<Guid>("Id");
                int count = CountNumberOfActivityRdv(accountId, userConnection);
	        Guid ContactClientOuRepresentantNon = new Guid("f550b45d-093e-43ba-bdd1-bc0bd43c8e16");
 
	        if (count > 0)
	        {
                        var update = new Update(userConnection, "Account")
                            .Set("ContactClientOuRepresentantId", Column.Parameter(ContactClientOuRepresentantNon))
                            .Where ("Id").IsEqual(activityId.ToString());
                        update.Execute();
	        }
        }
 
        public int CountNumberOfActivityRdv(Guid accountId, UserConnection userconnection)
        {
	        int count = 0;
                var select = new Select(userconnection)
                        .Column(Func.Count("Id"))
                    	.From("Activity")
                        .Where("ActivityCategoryId").IsEqual("42c74c49-58e6-df11-971b-001d60e938c6")
                	.And("AccountId").IsEqual(accountId.ToString()) as Select;
 
                count = select.ExecuteScalar<int>();
 
	        return count;
        }

 

Do I have to clear the cache or set the select to null ?

Like 0

Like

8 comments
Best reply

Oscar Dylan,

 

I've done it differently, when deleting the activity I send a message with the accountId linked to the activity deleted, and I catch it in the account edit page to do the necessaries processing. I had no problem with this method. Here is the code I've made for the sake of it.

onActivityDeletedReceived: function(scope, message) {
                var sender = message &amp;&amp; message.Header.Sender;
                // make sure the message received is the one you sent
                if (sender === "ActivityDeleted") {
                 	 // if you sent some data with the message you can get it from the message Body
                    var MessageText = message.Body;
					var array = [];
                    var esq = Ext.create("Terrasoft.EntitySchemaQuery", {
                    rootSchemaName: "Activity"
                    });
                    // Add column with account name that refers to given account.
                    esq.addColumn("Id", "Id");
                    esq.addColumn("Account.Id", "AccountId");
 
                  	esq.filters.logicalOperation = Terrasoft.LogicalOperatorType.AND;
                  	var esqAccountFilter = esq.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL, "Account.Id", MessageText);
                  	var esqRdvFilter = esq.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL, "ActivityCategory.Id", "42c74c49-58e6-df11-971b-001d60e938c6");
					var esqRealiseFilter = esq.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL, "Status.Id", "4bdbb88f-58e6-df11-971b-001d60e938c6");
 
 
                  	esq.filters.add("esqAccountFilter", esqAccountFilter);
                  	esq.filters.add("esqRdvFilter", esqRdvFilter);
					esq.filters.add("esqRealiseFilter", esqRealiseFilter);
                    // Get entire record collection
                    esq.getEntityCollection(function (result) {
                        if (!result.success) {
                            // error processing/logging, for example
                            this.showInformationDialog("Data query error");
                            return;
                        }
                        result.collection.each(function (item) {
                           array.push(item.get("AccountId"));
                        });
                      	if(array.length === 0)
                        {
							this.set("ContactClientOuRepresentant", {value:"f550b45d-093e-43ba-bdd1-bc0bd43c8e16" , displayValue:"Non"});
							this.save({isSilent:true});
                        }
                    }, this);
				}
            },

Regards,

 

Arthur

Hello Arthur,

 

And which connected records does the system show you? Also what happens when you drop the select result to null?

 

Best regards,

Oscar

Oscar Dylan,

 

When the screen of the connected records pop-up and I click to check the records there is nothing.

 

Also, when I set the result to null the same thing happen.

 

Regards,

 

Arthur

Arthur Hertz,

 

What is the result of the 

 

select top 5 * from MultiDeleteQueue

order by CreatedOn desc

 

right after trying to delete a record (message column values needed)? Also what error message do you receive in the application logs?

 

Best regards,

Oscar

Oscar Dylan,

 

I've put the csv file of the request in the post and also in the application logs in the "MultiDelete.log" file it's telling me this :

 

Terrasoft.Common.DbOperationException: L'instruction DELETE est en conflit avec la contrainte SAME TABLE REFERENCE "FKPkYRMonMU4O22bg1UtAWBnc3Y8". Le conflit s'est produit dans la base de données "MetropoleGestion", table "dbo.Activity", column 'ActivityConnectionId'.

 

File link : https://linkintouch-my.sharepoint.com/:x:/g/personal/ahertz_linkintouch_fr/ETEWcqG_sjxBtWFBLG7w0N8B5kXRMSIcl8gmZNvtBY-UKw?e=GhYepw

 

Regards,

 

Arthur

Arthur Hertz,

 

And can you please perform this select:

 

select ActivityConnectionId from Activity where Id = 'Id of the activity you delete'

 

and

 

select Id from Activity where ActivityConnectionId = 'Id of the activity you delete'

 

?

 

Seems that this column is not empty for some activity and uses its value as a reference for the activity you delete. 

 

Best regards,

Oscar 

Oscar Dylan,

 

 

The first request ActivityConnectionId is equal to NULL and for the second one there are no records.

 

Regards,

 

Arthur

Arthur Hertz,

 

Then you need to connect your local app to the IDE and debug the execution of deletion in the Visual Studio. There is something with the delete that is provoked by the code you've developed and you need to debug this logic.

 

Best regards,

Oscar

Oscar Dylan,

 

I've done it differently, when deleting the activity I send a message with the accountId linked to the activity deleted, and I catch it in the account edit page to do the necessaries processing. I had no problem with this method. Here is the code I've made for the sake of it.

onActivityDeletedReceived: function(scope, message) {
                var sender = message &amp;&amp; message.Header.Sender;
                // make sure the message received is the one you sent
                if (sender === "ActivityDeleted") {
                 	 // if you sent some data with the message you can get it from the message Body
                    var MessageText = message.Body;
					var array = [];
                    var esq = Ext.create("Terrasoft.EntitySchemaQuery", {
                    rootSchemaName: "Activity"
                    });
                    // Add column with account name that refers to given account.
                    esq.addColumn("Id", "Id");
                    esq.addColumn("Account.Id", "AccountId");
 
                  	esq.filters.logicalOperation = Terrasoft.LogicalOperatorType.AND;
                  	var esqAccountFilter = esq.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL, "Account.Id", MessageText);
                  	var esqRdvFilter = esq.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL, "ActivityCategory.Id", "42c74c49-58e6-df11-971b-001d60e938c6");
					var esqRealiseFilter = esq.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL, "Status.Id", "4bdbb88f-58e6-df11-971b-001d60e938c6");
 
 
                  	esq.filters.add("esqAccountFilter", esqAccountFilter);
                  	esq.filters.add("esqRdvFilter", esqRdvFilter);
					esq.filters.add("esqRealiseFilter", esqRealiseFilter);
                    // Get entire record collection
                    esq.getEntityCollection(function (result) {
                        if (!result.success) {
                            // error processing/logging, for example
                            this.showInformationDialog("Data query error");
                            return;
                        }
                        result.collection.each(function (item) {
                           array.push(item.get("AccountId"));
                        });
                      	if(array.length === 0)
                        {
							this.set("ContactClientOuRepresentant", {value:"f550b45d-093e-43ba-bdd1-bc0bd43c8e16" , displayValue:"Non"});
							this.save({isSilent:true});
                        }
                    }, this);
				}
            },

Regards,

 

Arthur

Show all comments

Hello,

 

I've implemented some code because of the changes on the new version which is coming and do not support DB.Executor.

 

But when i'm executing my source code, the json result is dynamic : i've only the fields which are not empty.

In order to have a great code i've parse the json. So the format is correct that's a great json but I don't know how can I include empty field/value.

 

Is there somebody who can explain me how can I do in order to include all fields in the object to the json return list?

 

Thanks a lot.

Like 0

Like

0 comments
Show all comments



Dear Community,

 

I am trying to copy values from a field and lookups to put it in the "Name" fields before saving.

I use the following code in the script task but I don't know how to get the value from a lookup:

Entity.Name = $"{Entity.Code } - {Entity.Description}";

Code being the lookup.



So if you create a record in a lookup it would go like this:

[Name][Code][Description]

[           ][ 001 ][Code for info]



The Name should automatically be filled with "001 - Code for info" after saving.

What is the correct way to set the script?

Thank you!

 

 

Kind regards,

Yosef

 

Like 0

Like

2 comments

Hi!

 

Just add on saving event in your lookup entity, and add a script

 

Entity.SetColumnValue("Name", string.Format("[{0}][{1}]", Entity.GetTypedColumnValue&lt;string&gt;("Code"), Entity.GetTypedColumnValue&lt;string&gt;("Descritpion"));

 

Dmytro Oliinyk,

 

 

Thank you but that didn't seem to work for me, this was the solution for me:

 

var name = Entity.GetColumnValue("Name");
var description = Entity.GetColumnValue("Description");
 
var esq = new EntitySchemaQuery(Entity.Schema);
esq.AddColumn("Code.Name");
 
var CodeEntity= esq. GetEntity(UserConnection, Entity.PrimaryColumnValue);
if (CodeEntity != null) {
 
	var columnUsrCodeName = CodeEntity .GetTypedColumnValue&lt;string&gt;("Code_Name");
 
	string fullName= $"{name}: {columnUsrCodeName } - {description}";
	Entity.SetColumnValue("Name", fullName);
}
return true;

Let me know if there's an easier way to do this.

 

 

Kind regards,

Yosef

Show all comments

Which C# data type (decimal, double, etc) should I use in a script task "Get("ProcessParameter")" for decimal process parameters?

 

Like 0

Like

2 comments

Hi Ricardo

You should use System.decimal C# type.

And it's a C# structure in .NET and .NET Core.

https://docs.microsoft.com/en-us/dotnet/api/system.decimal?view=netcore…

 

Thank you

Mohamed

 

Hi Ricardo, 

 

Indeed, you can use System decimal C# type as Mohamed mentioned above. However, in case of any difficulties, please try the standard int datatype.

 

Regards, 

Anastasiia

Show all comments

How to apply access permissions (object permission) / access right when insert data via server-side?

I have set the record access permission, but when inserting via server-side, the access right does not work. The insert method that I did was in accordance with the article above.

Thanks.

Like 0

Like

1 comments

Hi,

It is possible adding data via server-side with access permissions using the “Entity” class. Please find more information with the examples by the link below:

https://academy.bpmonline.com/documents/technic-sdk/7-13/working-database-entity-class

Best regards,

Norton  

Show all comments