I have an object called ItalVinculacion, and inside it I have to read the content of ItalProduct, which is also an object, and obtain the values ​​of ItalEjeAplicacion and Type, which are objects within the product.

This is my code:

var autoId = Get<Guid>("IdAuto"); // ID del auto en ItalAutosNormalizados
var IdProduct = Get<Guid>("IdProduct"); // ID del producto de la nueva vinculación
var IdAxis = Get<Guid>("IdAxis"); 
var IdSubFamily = Get<Guid>("IdSubFamily"); 
 
if (IdProduct == Guid.Empty) {
    return false;
}
 
// Buscar vinculaciones existentes con el mismo auto
var vinculacionEsq = new EntitySchemaQuery(UserConnection.EntitySchemaManager, "ItalVinculacion");
vinculacionEsq.AddColumn("Id");
vinculacionEsq.AddColumn("ItalPriority");
 
// Acceder a las columnas del objeto relacionado ItalProduct usando alias
var ejeAplicacionColumn = vinculacionEsq.AddColumn("ItalProduct.ItalEjeAplicacion");
ejeAplicacionColumn.Name = "ItalEjeAplicacion";
 
var typeColumn = vinculacionEsq.AddColumn("ItalProduct.Type");
typeColumn.Name = "Type";
 
vinculacionEsq.Filters.Add(vinculacionEsq.CreateFilterWithParameters(FilterComparisonType.Equal, "ItalFleetID", autoId));
 
var existingVinculaciones = vinculacionEsq.GetEntityCollection(UserConnection);
int maxPriority = 0;
bool isDuplicateFound = false;
 
foreach (var vinculation in existingVinculaciones) {
    var existingEjeAplicacion = vinculation.GetTypedColumnValue<Guid>("ItalEjeAplicacion");
    var existingType = vinculation.GetTypedColumnValue<Guid>("Type");
 
    // Comparar GUIDs correctamente
    if (existingEjeAplicacion.Equals(IdAxis) && existingType.Equals(IdSubFamily)) {
        isDuplicateFound = true;
        var existingPriority = vinculation.GetTypedColumnValue<int>("ItalPriority");
 
        if (existingPriority == 0) {
            vinculation.SetColumnValue("ItalPriority", 1);
            Set("ItalPriority", 2);
        } else {
            Set("ItalPriority", existingPriority + 1);
            vinculation.SetColumnValue("ItalPriority", existingPriority + 1);
        }
 
        vinculation.Save();
        break; // Salir del bucle si se encuentra un duplicado
    }
 
    maxPriority = Math.Max(maxPriority, vinculation.GetTypedColumnValue<int>("ItalPriority"));
}
 
// Si no se encontró un duplicado, establece la prioridad de la nueva vinculación
if (!isDuplicateFound) {
    Set("ItalPriority", maxPriority + 1);
}
 
return true;

 

And this is the error:

Terrasoft.Common.ItemNotFoundException: Value "ItalProduct.ItalEjeAplicacion" was not found.

 

Like 0

Like

2 comments

Try using ItalEjeAplicacionId instead of ItalEjeAplicacion. This is the only assumption for now.

Oleg Drobina,

Thanks Oleg, I'll try it.

Show all comments

Hi Team,



We are using an OOTB Webservice section to call the (GET) REST API endpoint and the response collection is captured in the "Response Parameter" of that web service. The response has a nested collection of data.

 

We are currently using the Script task to read the response data of a web service. Now it is required to get into the nested data set further and any insight on this would be helpful.



STEP 1: Web service Response

 

STEP 2: Script task to read web service response

var deliveries = Get<ICompositeObjectList<ICompositeObject>>("WebService1.Output_Out");
foreach(var delivery in deliveries){
//Delivery is again a nested data
//need to loop through the delivery (has parent record info and array of child record details)
}
 

Webservice Output:

{
   "output":[
      {
         "challan":[
            {
               "delivery_number":"DEL-251-253423",
               "delivery_id":1151109,
               "lines":[
                  {
                     "order_number":2011010049349,
                     "item_code":"RT3060-002GRL",
                     "grade":"A"
                  },
                  {
                     "order_number":2011010049359,
                     "item_code":"RT3062-002GRL",
                     "grade":"A"
                  }
               ]
            },
            {
               "delivery_number":"DEL-251-253430",
               "delivery_id":1151109,
               "lines":[
                  {
                     "order_number":2011010049369,
                     "item_code":"RT3060-002GRL",
                     "grade":"B"
                  },
                  {
                     "order_number":2011010049379,
                     "item_code":"RT3062-002GRL",
                     "grade":"B"
                  }
               ]
            }
         ]
      }
   ]
}



Need to traverse through the nested collection and one of the properties in the collection of values is array too {like section record information & Child record information} and then insert them into CRM table (Parent and child). Insight for processing this data set would be helpful.

 

 

 

Best Regards,

Bhoobalan Palanivelu.

Like 0

Like

3 comments

Hello,

In order to process the collection inside a collection, you need to do the following:

1) In the process, create a new parameter and add values to it from the web server response:

 

 

2) In your script task, you need to proceed this parameter and get values from it.

Dmytro Vovchenko,



Thanks for the information shared.

We were able to achieve processing the multiple nested collection through the below script and insert the Parent/Child collection sequentially.

 

List&lt;object&gt; deliveryItem = new List&lt;object&gt;();
List&lt;object&gt; lineItem = new List&lt;object&gt;();
var serviceOut = Get&lt;ICompositeObjectList&lt;ICompositeObject&gt;&gt;("Output");
 
foreach(ICompositeObject chall in serviceOut){
	if(chall.TryGetValue&lt;ICompositeObjectList&lt;ICompositeObject&gt;&gt;("Challan" , out ICompositeObjectList&lt;ICompositeObject&gt; curChallan)){
		foreach(ICompositeObject _challan1 in curChallan){
				curChallan1.TryGetValue&lt;string&gt;("Driver_contact_no" , out string Driver_contact_no); 
				deliveryItem.Add(Driver_contact_no);
 
				if(_challan1.TryGetValue&lt;ICompositeObjectList&lt;ICompositeObject&gt;&gt;("Lines" , out ICompositeObjectList&lt;ICompositeObject&gt; curLines)){
					foreach(ICompositeObject _Lines1 in curLines){
							_Lines1.TryGetValue&lt;decimal&gt;("Secondary_quantity_ctn" , out decimal Secondary_quantity_ctn); 
							lineItem.Add(Secondary_quantity_ctn);
				}	
			}
		}
	}
}

 

Also, we can utilize this without performing the Step 1 of Creating Nested Parameter Collection in Parameters of Business Process. Since the Web-Service already has the response parameter of same. But the parameter name from Webservice is always with a suffix _OUT





Iteration of Composite object collection is done through by following the Type<> in below Interface

ICompositeObjectList<TObject>

Interface ICompositeObject


 

 

 



BR,

Bhoobalan Palanivelu.

Show all comments

Hi,

 

I have a business process where I need to read the read element values in a script task.

When the read element is set to "read a collection of records" I'm using the following code:



var AccountsData = Get>("ReadDataUserTask12.ResultCompositeObjectList");

var AccountData = AccountsData.First();



var AccountAddress="";

AccountData.TryGetValue("Address", out AccountAddress);

 

What change do I need to do when the read element is set to "read the first record"?

 

Thanks,

Raz

 

 

Like 0

Like

3 comments

 

 

 

 

 

 

 

 

string name = string.Empty;
string email = string.Empty;
Guid RecordId = Guid.Empty;
 
/**
 * This approach should not be used in production
 * Please create process parameters and set values with standard tools (i.e. Formula)
 * ReadDataUserTask1 is the Code of "Read One Contact" element
 */
var re = context.Process.FindFlowElementByName("ReadDataUserTask1").GetPropertyValue("ResultEntity");
 
if (re.TryGetPropertyValue("Email", out object _email))
{
	email = _email.ToString();
}
 
if (re.TryGetPropertyValue("Name", out object _name))
{
	name = _name.ToString();
}
 
if (re.TryGetPropertyValue("Id", out object _id))
{
	if(Guid.TryParse(_id.ToString(), out Guid Id))
	{
		RecordId = Id;
	}
}
 
//Set values to process parameters
Set&lt;string&gt;("Name", name);
Set&lt;string&gt;("Email", email);
Set&lt;Guid&gt;("RecordId", RecordId);
 
return true;

 

 

 

Kirill Krylov CPA,

Hi Kirill,

 

I don't understand you code.

So if shouldn't use this code in production.

 

what should I do?

 

I don't manage to get the values from ResultEntry.

 

Thanks,

Raz

Kirill Krylov CPA,

Your code is exactly what I need if I don't want to use "get a set of records" and if I don't what to use the "Formula" process element.

Why not to use it in production?

Show all comments

Hello,

 

I am trying to implement a web-service integration that provides a collection of fields as a response, and adding it to an auto-generated page to show the results. Can someone guide me how I can implement this functionality to grab fields from a collection and show them as separate individual fields?

Like 1

Like

2 comments

I think it depends. If the quantity of fields you need is static and will not change, you can just read individual values and point them to specific fields. If it is a variable, its more complex. 

I am limited in coding, so I would do this as a detail rather than fields. You would have to code something special, I think, to get a variable quantity of fields to display. But with a detail, it will scale with the number of records you want to show. You can also change the detail to an "Editable Detail" if you want the user to edit the values inline. You can either have the detail show the actual records for direct editing, or you can setup a sort of temporary object for the detail that you read and write to that then you can use later.

Hi Reid,

 

Thank you for your answer. I do get your point and even I was thinking along the same lines.

The issue that I am facing right now, is when I'm trying to call a web-service in the business process, using the "Call web-service" element, the response of that web-service is a collection of objects, and any element (Auto-generated Page/Pre-configured page/etc) that I add after this web-service element, does not take that collection of objects at all. It only takes the "Response body" as the value. And when I map the individual values somehow, they do not reflect the results as desired, because they can't just pick one value out of a collection of values randomly, and hence the fields show blank in the result.

So I'm just trying to figure out if this out-of-the-box functionality works only for individual fields or for collection of objects also. 

Show all comments

I have a business process that reads a collection of data.

Two of the fields that are being read are datetime fields.

Because the read data process reads many rows, I'm reading those rows in a script task and using the following code:

 

var ProductLines = Get>("ReadDataUserTask1.ResultCompositeObjectList");

    foreach(var ProductLine in ProductLines) {

 

It's very important to understand that inside the foreach loop I'M NOT TRYING TO GET THE DATETIME FIELDS, BUT OTHER STRING TYPE FIELDS.

 

Once I run the process I get the following error message:

Terrasoft.Common.UnsupportedTypeException: Type "System.TimeSpan, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" is not supported.

   at Terrasoft.Common.CompositeObject.Add(String key, Object value)

   at Terrasoft.Common.CompositeObjectListUtilities.Transform(ICompositeObject source, IReadOnlyDictionary`2 keyMap)

   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()

   at System.Collections.Generic.List`1.InsertRange(Int32 index, IEnumerable`1 collection)

   at Terrasoft.Common.CompositeObjectListUtilities.Transform[T](IEnumerable`1 source, IReadOnlyDictionary`2 keyMap)

   at Terrasoft.Core.Process.Configuration.ReadDataUserTask.FillResultCompositeObjectList(IProcessParametersMetaInfo schemaElement, EntityCollection entityCollection)

   at Terrasoft.Core.Process.Configuration.ReadDataUserTask.InternalExecute(ProcessExecutingContext context)

   at Terrasoft.Core.Process.ProcessActivity.ExecuteElement(ProcessExecutingContext context)

   at Terrasoft.Core.Process.ProcessActivity.ExecuteItem(ProcessExecutingContext context)

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

 

I'm looking forward to having your assistance with the issue.

 

Best Regards,

Raz

Like 0

Like

1 comments

Hi Raz, 

 

Could you please provide a full script-task code you use so we will be able to test it at our end?

 

Regards,

Anastasiia

Show all comments

I was trying to choose a random user as a sender of the automatic email in Business process.

I wanted to avoid development in C#. Using only business process elements as in the cloud version. Creatio Sales Enterprise v.7.16.



The workaround I found for random is a formula like

RoundOff(DateTime.Now.Ticks / 17) % 2 == 0 ? "user1" : "user2"

This selects one of the strings "user1" or "user2", and by this string, whether it's Full name, Email, or else, the user can be determined.

But this works only for 2 users and crashes if any string changes.

 

I think such situations happen when we simply need to pick up a random element of selection.

 

But then I thought Creatio could add a new read data mode:

 

This isn't as complicated to implement, is it?

2 comments

Dear Yuriy,

 

Thank you for the idea! I will definitely pass it to our R&D team so they could consider implementing the following functionality.

 

Best regards,

Angela

Hi Yuriy,

 

As a workaround this gap of ootb solution You can store list of users in eg. Parameter 1- Text unlimited , separated by semicolon.

 

Next You may use Your random function to build formula like this one ...

[#Parameter 1#].Split(';')[RoundOf(....)%1]) .

 

Regards,

Marcin

Show all comments

I have a question about working with record collection from read data element.

My case is to take all tasks planned for the next hour and send email to them owners. 

I’d like to ask if it is possible to get a task ID, one by one, base on the collection, then read the necessary data from the task and send an email to the owner. (like in schema below)

 

 

Like 0

Like

3 comments

Dear Paulina,

 

The task you described can be implemented via the process, but it will require some additional development. When the process reads tasks and sends an email script task should be used since send email element cannot work with collections. An example of such a script task can be found in process Send email to case contact. Also, similar task but without development is described in this post: https://community.creatio.com/questions/sending-email-collection-records-if-reorder-date-record-equals-current-date. If you want to send separate emails for task owners I would recommend adding tags to records to distinct processed tasks. 

 

Best regards,

Angela

Angela Reyes,

Thank you Angela. I will try to work with tags to avoid the development

BR Paulina

I have also been successful in using the new upcoming functionality that was tested in the 7.16.1 release to feed a collection into a subprocess. If the email is relatively simple and the variables are limited, you can send a collection to a simple subprocess that sends an email to the contact list in the collection but generating a new process for each item in the collection. But for more complex emails, creating a loop like the tag example is your best bet. Also, you can use tags, or you can create a boolean in the section to loop through that can be turned on and off.

Show all comments