We are trying to copy all attachments posted in an object's feed to the attachment's section of the object in Freedom UI. 

 

Here's the scenario, we created a section to hold data about all our subcontractors. The users are leaving comments and docs in the Feed, but we want all those same docs to copy over to the record within the attachments section. 

 

I have used the file transfer function the business processes but the feed not your typical object.

 

Like 0

Like

1 comments

Good day,

Could you please specify whether the you are trying to copy over are stored as, for example, "Feed uploaded file"?
Feed uploaded file

Have you attempted using a process element "Process file" mentioned in this article? 

 

If so, please let us know, what exact error you are experiencing.

Thank you in advance!

Show all comments

Hi Community,

 

Our customer has requested a bar code scanner inside Creatio, so they can scan products and check its information.

We have multiple ways of doing this:

 

  1. WebApp (Custom Component) that opens the smartphone camera;
  2. WebApp (Custom Component) that establishes a connection to a scanner device (for example a Zebra Scanner);
  3. Bar code scanner in the mobile app, which we will be able to configure as described here https://academy.creatio.com/docs/8.x/resources/release-notes/8-2-1-energy-release-notes#title-2782-13.

     

For our use case, we will be using the first option, since option three is not available at the moment.

 

After some digging, we discovered that there are multiple libraries that could help us implement this use case. However, we decided to post this question to know if someone has already implemented something similar, or at least tried to. So, we can share the know-how behind it.

 

Thank you.

Like 3

Like

2 comments

Have not tried, also looking forward to some knowhow. Not just to scan, but also to generate for event registrations for example. 

I have integrated a barcode scanner with Creatio. We've used a simple bluetooth barcode scanner connected to the device (in our case it was a tablet with full Creatio open in the browser). Most barcode scanners work just like a connected keyboard. When a barcode is scanned it sends the "text" value of the barcode to as input, just as if it were typed in. In my solution, we had a page that opened and we set focus to a text/input field on the page and dislayed some message about "waiting for barcode" for the user. Then, once scanned, the text value of the barcode scanned triggered a change event for the text/input field and we then did the action needed for the barcode (which in our case the barcode was a vehicle VIN, so we then used an API to get the vehicle details for the scanned VIN). All really simple to be honest. Using this approach, thinking of the barcode scanner as text entered by an input device, just like a keyboard, it all turned out to be really easy to work with.
Hope this helps.

Ryan.

Show all comments

Hi everyone,
 

I am looking to replace the AttachmentList component on the Leads form page with a DataGrid component that uses the FileLead (Lead attachment) entity. The goal is to disable the downloading of attachments.
 

However, I’ve encountered an issue where the Name column in the DataGrid appears as a hyperlink, which attempts to navigate to a non-existent form page for the FileLead entity (refer attachment below with the navigation URL at the bottom left). Since FileLead is an attachment entity, it ideally should not have navigation associated with it, even when displayed in a list.

image
 

Interestingly, other sections like Contacts and Attachments are functioning as expected—the Name column in those sections is not hyperlinked to any entity page.
 

This behavior appears to be a product bug. Could anyone else confirm if they are experiencing the same issue?
 

Best regards,
Ramya

Like 0

Like

1 comments

Hello!

This does not seem to be a basic problem. 
Please contact our support team to help resolve the issue - support@creatio.com

Best regards,
Anton

Show all comments

Hello Community,

I’m working on creating a custom web service to delete a lead record, but I’ve run into an issue that I can’t seem to resolve. Whenever I attempt to delete a lead using its ContactId, I receive the following error:
"Error occurred while deleting: Item cannot be deleted because it is being used in a process."

Here’s what I’ve tried so far:

  1. Removing the Process Connection:
    The lead is connected to a business process (Lead Processing) through a "Connect process to object process element." I attempted to remove this connection from the base process, but doing so broke other functionalities that are dependent on this process.
  2. Calling the Process Cancel Execution Service:
    I attempted to call the CancelExecution service (ProcessEngineService.svc/CancelExecution) to cancel the execution of the process. However, this service requires processDataIds in the body, which I cannot retrieve within the delete contact web service.
  3. Deleting the Connected Record:
    I explored deleting the record connecting the process to the lead, but I couldn’t locate the object holding this connection.

Below is the source code for my delete operation. The logic works perfectly when I stop the "Lead Processing" business process, but that’s not a sustainable solution.

Source Code:
 using System;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.ServiceModel.Activation;
using Terrasoft.Core;
using Terrasoft.Web.Common;
using Terrasoft.Core.Entities;
using System.Collections.Generic;
 
namespace Terrasoft.Configuration.UsrDeleteLeadNamespace
{
    [ServiceContract]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
    public class UsrDeleteLead : BaseService
    {
        [OperationContract]
        [WebInvoke(Method = "DELETE", RequestFormat = WebMessageFormat.Json, 
                  BodyStyle = WebMessageBodyStyle.Wrapped,
                  ResponseFormat = WebMessageFormat.Json)]
        public string DeleteLead(string LeadId)
        {
            if (!Guid.TryParse(LeadId, out Guid parsedLeadId))
            {
                return "Invalid Lead ID format or Lead doesn't exist.";
            }
 
            UserConnection userConnection = GetUserConnection();
            EntitySchemaManager entitySchemaManager = userConnection.EntitySchemaManager;
 
            try
            {
                // First check and delete connected Lead Products
                EntitySchema leadProductSchema = entitySchemaManager.GetInstanceByName("LeadProduct");
                var leadProductEsq = new EntitySchemaQuery(leadProductSchema);
                leadProductEsq.AddAllSchemaColumns();
                leadProductEsq.Filters.Add(leadProductEsq.CreateFilterWithParameters(FilterComparisonType.Equal, "Lead", parsedLeadId));
                var leadProductCollection = leadProductEsq.GetEntityCollection(userConnection);
 
                // Manually convert EntityCollection to a List
                var leadProductCollectionToDelete = new List<Entity>();
                foreach (var leadProductEntity in leadProductCollection)
                {
                    leadProductCollectionToDelete.Add(leadProductEntity);
                }
 
                // Delete the Lead Products
                foreach (var leadProductEntity in leadProductCollectionToDelete)
                {
                    leadProductEntity.Delete();
                }
 
                // First check and delete connected Activity
                EntitySchema activitySchema = entitySchemaManager.GetInstanceByName("Activity");
                var activityEsq = new EntitySchemaQuery(activitySchema);
                activityEsq.AddAllSchemaColumns();
                activityEsq.Filters.Add(activityEsq.CreateFilterWithParameters(FilterComparisonType.Equal, "Lead", parsedLeadId));
                var activityCollection = activityEsq.GetEntityCollection(userConnection);
 
                // Manually convert EntityCollection to a List
                var activityCollectionToDelete = new List<Entity>();
                foreach (var activityEntity in activityCollection)
                {
                    activityCollectionToDelete.Add(activityEntity);
                }
 
                // Delete the Lead Products
                foreach (var activityEntity in activityCollectionToDelete)
                {
                    activityEntity.Delete();
                }
 
                // Now check and delete the Lead
                EntitySchema leadSchema = entitySchemaManager.GetInstanceByName("Lead");
                Entity leadEntity = leadSchema.CreateEntity(userConnection);
 
                if (!leadEntity.FetchFromDB("Id", parsedLeadId))
                {
                    return "Lead not found.";
                }
 
                if (leadEntity.Delete())
                {
                    return $"Lead and {leadProductCollection.Count} related product(s) have been deleted successfully.";
                }
                else
                {
                    return "Failed to delete Lead.";
                }
            }
            catch (Exception ex)
            {
                return $"Error occurred while deleting: {ex.Message}";
            }
        }
    }
}

I would greatly appreciate any suggestions or guidance on how to resolve this issue. Specifically:

  • Is there a way to identify and cancel the process dynamically before deleting the lead?
  • Can I identify and delete the connecting record that prevents the deletion?
  • Are there alternative approaches I should consider?
Like 0

Like

1 comments

Hello,
 

Thank you for the detailed explanation of the task.
You can reproduce this behavior through the UI by creating a new lead record and then trying to delete it - you get a message about related records, as shown in the screenshot.

create a lead and try to delete
 

In this case, blocking the deletion of the record occurs due to the running business process “Lead processing”, which creates an activity on the lead and, accordingly, an instance of the process.

According to your code, we see that you are already deleting the activities associated with this lead, so you just need to cancel the business process instance.

To implement this, the ProcessEngineService.svc/CancelExecution endpoint can be a good fit, where you need to pass the business process instance ID in the request body:

{“processDataIds”:“045ea1bc-f366-4837-994f-d229fc8a91d4”}


So, the question remains as to where you can find the instance ID of the business process that uses this record.
The “SysProcessEntity” table stores data about the relationship of the record with the business process instance. The important columns for you are:
1) EntityId - the identifier of the linked record. That is, in your case, the record ID of the lead to be deleted
2) SysProcessId - the identifier of the process instance that is associated with this record.
3) EntityDisplayValue - the value from the Display Value column for the Lead object. By default, this is the “LeadName” column.

Before calling the ProcessEngineService.svc/CancelExecution endpoint with the process ID, you can also check the business process name in the SysProcessLog table (Id = {id from SysProcessid column}).

SysProcessEntity table
SysProcessLog
 

Thank you.

Show all comments

Hey Everyone,


I am trying to change the order of the address in full address field in Accounts section of Customer360 creatio. Instead of Zip + Country + State + City + Address I want it as Address + City + State + ZipCode + Country.

 

I tried overriding the BaseAddressEventListener with my custom event listener but it didn't worked

 

Can someone please guide me on how to do it?

Like 1

Like

2 comments

Hello Ansh,
 

I have contacted our R&D team regarding this question. First of all, this logic is implemented on the backend side, which means that even if it is possible, it would likely be extremely challenging to achieve.
 

To conclude, I believe it is not feasible at the moment. However, I will register this as a potential improvement, and hopefully, this feature will be implemented in the future.
 

Best regards

Yevhenii Grytsiuk,

Thank you
The issue is fixed now, As I added a CustomAddressEventListener to override the BaseAddressEventListener in the source code of my custom package.

Show all comments

I am currently customizing the Account module in the Freedom UI and encountering an issue with the PDS_UsrBillToNumber_volqoyn field. This field is an integer field bound to PDS.UsrBillToNumber in the model configuration.

My goal is to remove the comma separator from this field, but the solutions I have tried so far have not worked. These include:

  1. Using useThousandSeparators: false in controlConfig.
  2. Setting useGrouping: false in the numberFormat object within controlConfig.
  3. Modifying configurations in the format object for field values.
  4. Implementing custom methods for formatting.

Unfortunately, none of these approaches have yielded the desired result. Could you kindly guide me on the correct implementation or suggest an alternative solution?

Like 2

Like

0 comments
Show all comments

Hi Community,

 

We are trying to create a filter for this detail, that will use two conditions (one for each column) and a logical operator of “OR”. So basically, we only want the records that have the main record id on one of these columns (Contrato or Contrato Umbrella).

 

 

To achieve this, we first tried to add the filter using the FreedomUI Page Designer. However, the filter does not work with the logical operator “OR”.

 

 

So we needed to add it manually, through code. By following this post https://community.creatio.com/questions/detail-filter-freedom-ui. But that didn’t work.

 

 

An alternative was to add the filter in the viewModelConfigDiff section, but we don’t know how can we make the value dynamic.

 

 

Could you please help us find a solution to this problem?

 

Thank you.

Like 3

Like

1 comments

Hello Pedro,

Please review one of the community questions to find the example of Terrasoft.LogicalOperatorType.OR usage.

Additionally here is an explanation of how filtration on Detail work for FreedomUI. 

Case description:
On Contacts page there is a Job experience detail with listed companies where the person worked. Our goal is to show only those departments in the department field that are specified for chosen employer (Account object). So, for this case, Alpha Business has only 2 departments listed in the Departments detail. We only want to see those 2 departments when choosing a department for this account on Job experience detail on Contact page. 

For filtering we basically need just 2 base handlers to be triggered:

  1. crt.DataGridActivateRowBusinessRulesRequest – triggered when we click on an existing detail row or add a new one.
  2. crt.HandleViewModelAttributeChangeRequest – triggered when we change a value of fields.

We also need to create our own handler which we can name usr.ApplyDepartmentFilter. This one would find the currently active row of our detail to have access to its manipulations. After that, we check if account field is filled in and if yes, we create a filter for the Department field. To apply it, we need to use setValue method by targeting filterAttributeName that can be created using the formula: 
"{detailName}DS_{targetFieldName}_List_BusinessRule_Filter".
After that, it is important to use markAsPristine method to make sure that the attribute is applied silently, without forcing us to save the row.

As for crt.DataGridActivateRowBusinessRulesRequest, here we just need to filter it by request.dataGridViewElementName === "CareerList" to target only the detail needed and then call the execution of usr.ApplyDepartmentFilter request that was added earlier.

In crt.HandleViewModelAttributeChangeRequest handler we need to cover the situation when the Employer (Account) field is changed to update the filtration for Department field. First of all, we check if request.attributeName === "CareerList". After that we select the active row and get control over Account field. We check if it’s changed by using account?.dirty property and also if it has value with account?.value?.value, because we would want to filter Department field only in case the Employer is filled in. If those 2 conditions are met, we use markAsPristine method for the account field attribute. We use this one here because it will allow us to handle the subsequent changes of the Employer field. Without it, the field will remain dirty until we save the row. Eventually, we need to set value of the Department field to null using: row?.getAttributeControl(attributeName + "DS_Department").setValue(null, {silent: true});
After that, the usr.ApplyDepartmentFilter handler can be executed to apply the filtration of Department field by Employer.

Show all comments

Hello creatio community,

 

I am trying to apply a filter into cases mini page which is developed using freedom ui screens. Code as below:

{
	request: "crt.LoadDataRequest",
	handler: async (request, next) => {
 
		if(request.dataSourceName == "CaseDS_OPCaseType_4943d10_List_DS") {
			const caseType = await request.$context.CaseDS_OPCaseType_4943d10;
 
			var moduleTypesIds = await OPPermissionFunctionsSsp.getModuleTypes();
 
			const filter = new sdk.FilterGroup();
			if(moduleTypesIds.length > 0){
				filter.logicalOperation = sdk.LogicalOperatorType.Or;		
				for (let i = 0; i < moduleTypesIds.length; i++) {
					await filter.addSchemaColumnFilterWithParameter(sdk.ComparisonType.Equal, "Id", moduleTypesIds[i].value);
				}
			}
			else{
				await filter.addSchemaColumnFilterWithParameter(sdk.ComparisonType.Equal, "OPCode", '');
			}
 
			const newFilter = Object.assign({}, filter);
			newFilter.items = filter.items;
 
			request.parameters.push({
				type: "filter",
				value: newFilter
			});
		}
		return await next?.handle(request);
	}
}

 

The filter newFilter shows the right filter condition. I also used sql profiler and it returned the correct values. The issue here is that the CaseDS_OPCaseType_4943d10_List_DS lookup its not showing any value and does not apply the developed filter.

 

This issue happens only in the mini page. I have used this approach in freedom ui form pages and it works fine. Is there something I'm missing?

 

Kind regards

Like 0

Like

2 comments

I assume this is a dropdown lookup and not a lookup that opens the Select dialog? 

I just double-checked and I do have similar code to filter a dropdown on a Freedom UI mini page/dialog and it is working. I don't see anything that looks incorrect in the code you posted - just wanted to confirm that it does work on mini pages (at least in my case it is)

Show all comments

Hello 
It 's possible to add business process buton on Mobile App Freedom Ui in section , or section page.

 

Thank you 

Like 0

Like

1 comments

Hello Safa,

Unfortunately, there is no no-code way to add the custom button. We've already registered the suggestion for the R&D team.

 

Meanwhile, this article explains how to create a custom button. Please follow the release updates to find out when SDK for Mobile will be implemented.

Show all comments

Is it possible to specify mask IDs when showing & hiding body masks while data loads? I'm asking as it seems like my body mask is being hidden by some other process before the process I want the mask to show for has completed, so it grants the user the ability to control the page before it's ready.

 

What I was thinking is that if the body mask was given some ID when shown using showBodyMask, only a hideBodyMask specifying that same ID would hide the body mask - any others doing the same may make their own body mask hidden, but if any of them still remained, you would still see the loading spinner. For some reason I seem to remember this being possible in Classic UI, but I can't remember exactly or find the examples.

Like 0

Like

3 comments
Best reply

It was possible to get the mask Id in classic (it is returned from MaskHelper.ShowBodyMask()), but I don't believe that had any impact on something else not hiding the mask. As far as I am aware, that was only used to get the mask so you could display or change the message (the Freedom UI mask doesn't have a message, only the spinner)

It was possible to get the mask Id in classic (it is returned from MaskHelper.ShowBodyMask()), but I don't believe that had any impact on something else not hiding the mask. As far as I am aware, that was only used to get the mask so you could display or change the message (the Freedom UI mask doesn't have a message, only the spinner)

Makes sense, must have been mis-remembering then, cheers Ryan. Would be nice to be able to show & hide specific body masks, as sometimes there will be multiple sets of data loading in in parallel, with no guarantees of which will finish first/last.

Hello,
Your idea has been registered to our R&D team, thank you for providing us with new ways to improve.

Show all comments