Hi All, 

probably a very silly question, however, I want users to be able to email Invoices as a PDF attachment to clients for payment through Creatio. Is there a simple one-step solution, other than generating a printable, saving the printable on the computer and then attaching it to an email? 

Has anyone build a custom business process for this or is there a simple functionality that I'm missing?

Like 0

Like

1 comments

Hello, 

 

Thank you for your question regarding sending invoices as PDF attachments to clients through Creatio. It’s a valid and common use case, and we’re happy to provide guidance.

To implement this functionality in a streamlined and automated way, we recommend creating a custom business process in Creatio using the following elements:

  1. Read Data – Use the Read data process element to retrieve the necessary invoice information.
  2. Generate File – Use the Process file element to create the invoice file.
  3. Send Email – Use the Send email element to attach and send the generated invoice to the client.

You can refer to this documentation for a detailed example of how the Process file element works:
🔗 Process file element – Creatio Academy

Additionally, to generate the invoice in PDF format, an external connector is required. We recommend using the AsposePDF connector available on the Creatio Marketplace:
🔗 AsposePDF Connector for Creatio

To trigger this process, you can either:

  • Add a custom button to the Invoice section, or
  • Configure a start signal to initiate the process automatically based on specific conditions (e.g., invoice status change).

Have a nice day!

Show all comments

Hi,

We are in the process of migrating to the Freedom UI and as such have access to the AI capabilities, for which I am interested to learn from other users of their experiences.

Have your users and company found the use of AI of benefit and if so, what would you say would biggest benefits you have found?

During testing, we have found a very high average token consumption (between 20,000 and 50,000) and am concerned about how much each interaction 'costs' in tokens and that will limit our usage. 

Any feedback would be appreciated.

thanks

Mark

Like 1

Like

5 comments

Hello,

Please refer to the following, below is an example of how many tokens each intent can use: 


More information about tokenization can be found here: 
1. https://learn.microsoft.com/en-us/dotnet/ai/conceptual/understanding-tokens
2. Actual visual representation of token counts from Open AI: https://platform.openai.com/tokenizer

Regarding token usage, specifically why does 1 question use so many tokens:

Creatio AI performs additional actions beyond the messages generated by the user in the chat. Let me explain with an example:   

If you ask Creatio AI to create a draft of an email, Creatio AI performs several steps: 

  1. Search for available skills.
  2. Read the skill prompt and available actions.
  3. Read data from the page.
  4. Check system settings to confirm that the message can be sent.
  5. Generate a draft message and display it in the chat (the only step visible to the user).
  6. Perform additional actions, such as opening a card, etc.  
     

Steps 1–4 are not visible in the user interface, but they also consume tokens, which explains why the token usage may appear higher than expected. 

Learn more: https://www.creatio.com/products/pricing

Best regards,
Ivan

Hi Ivan

Thanks for your reply. I have looked at the documentation and aware of this information. I was seeing if other users have experiences of your AI implementation. Real world usage is often different, and as our testing showed such different token usage, I was interested to capture this feedback.

Hi Mark, 

Same as you:  found massive usage tokens consumption for little use. 

Unless OpenAI and Azure AI Integration price lowers, for now, use of AI is on hold, until we can plug to other LLMs  [which is planned in later subversions of Creatio 8.3 I believe ], some of them being known to be much less expensive then open ai 4o .

Hi Damien,

Thanks for taking the time to reply. This is what I was worried about, as the promised ability to select your own LLM means we are locked into what I hope is the highest tier.

I do not want to tell our team that the AI function is going to be provided and by day 4 of the month, all credits are used up and we would be looking at a very large cost. However, if the benefits are genuine then it is a case of matching to the cost value achieved.

My worry was that the cost of the tokens being so high, makes the value hard to justify.

Same experience for me as what Damien shared. It's a great marketing tool, but real world use doesn't seem to add much benefit IMO, especially compared to the high token usage for even what seems to be simple requests. 

Show all comments

We found some validation errors indicating we have a package hierarchy issue on an older package that already deployed to production.  To resolve this, we need to unlock some packages and change their dependencies.  While I am able to unlock them with the following script below, I still can't change the package dependencies even when unlocked.  How can I change the package dependencies on a package that has already deployed?

DECLARE @packageName nvarchar(50); 
SET @packageName = 'Package_Name'; 
UPDATE SysPackage 
SET IsChanged = 0, 
    InstallType = 1, 
    IsLocked = 0, 
    Maintainer = 'Customer' 
WHERE Name = @packageName 
AND SysWorkspaceId IN (SELECT 
  Id 
FROM SysWorkspace 
WHERE Name = 'Default'); 
UPDATE SysSchema 
SET IsChanged = 0, 
    IsLocked = 0
FROM SysSchema 
JOIN SysPackage 
  ON SysSchema.SysPackageId = SysPackage.Id 
WHERE SysPackage.name = @packageName 		
Like 1

Like

3 comments

Hello,

Please note that we do not recommend making changes to this package on the end environment. It is best for you to fix the issue with the dependencies on the dev site and then transfer the package with the updated dependencies to prod again. It will ensure that in future, if you decide to transfer this package or a connected package to prod again, it does not override your settings and the system's integrity is preserved.

Mira Dmitruk,

Hi Mira, thank you.  I understand that and am trying to make changes in our development environment.  That is where I am encountering this issue where I cannot change the package dependencies even when they are unlocked.

Francine Braese,

Please describe which errors exactly you get when trying to change the dependencies.

Show all comments

Hello Community,

What is the standard way to achieve the following?

We have a list of mailboxes, each associated with different case categories. 

We would like to automatically send a standard reply—such as "Your request is under review"—when the first email (i.e., case registration) arrives in the mailbox.

Any guidance or best practices would be appreciated.

Sasor

Like 0

Like

1 comments

Hello,

To achieve automatic replies on the first incoming email to your mailboxes, we can suggest to create a business process based on the out-of-the-box "Send Email to Case Contact" business process.

You can take the existing process that’s already in the system as a template and customize it to fit your needs—such as sending a standard reply like "Your request is under review" when a new case is created from the first email.

This way, you leverage the built-in functionality and adjust it to your specific scenario.

Thank you!

Show all comments

Hello Community,

Is it possible to associate a specific mailbox with a section, such as Orders or Leads?

We’re looking to replicate the same logic used in Case Registration,where an incoming email to a designated mailbox automatically triggers the creation of a new case.

In our case, we’d like to apply this to Orders and Leads. That is, when an email is sent to a specific mailbox, a new order would be automatically created.

Is this functionality available, or are there any recommended workarounds?

 

Sasor

Like 0

Like

2 comments
Best reply

You can use the object EmailMessageData (Title "Email message") to know which mailbox (or mailboxes) an email (Activity) is from. Emails are Activity records, but each mailbox connected to Creatio that the email is located in will have a record in EmailMessageData to tie the email to the mailbox. 

One approach would be to have a process listening for Activity added with Type=Email that exist in the mailbox you're monitoring.

Then you do whatever is needed such as create a record in your section. The EmailMessageData object also will let you know if the email is a part of a thread. Then you could use that to determine you need to just add this new email to an existing record vs adding a new record, etc.

Ryan

You can use the object EmailMessageData (Title "Email message") to know which mailbox (or mailboxes) an email (Activity) is from. Emails are Activity records, but each mailbox connected to Creatio that the email is located in will have a record in EmailMessageData to tie the email to the mailbox. 

One approach would be to have a process listening for Activity added with Type=Email that exist in the mailbox you're monitoring.

Then you do whatever is needed such as create a record in your section. The EmailMessageData object also will let you know if the email is a part of a thread. Then you could use that to determine you need to just add this new email to an existing record vs adding a new record, etc.

Ryan

Hello Ryan,

Thank you for the recommendation. I tried this approach,

but the Business Process wont trigger when an email comes to the specified Mailbox.

I checked from Sql Console the related tables, and the Id that Im utilizing is correct.

But still the Process wont trigger.

Sasor

Show all comments

Hi Community,

I have created a new Custom Section, and is not appearing in the Dropdown where sections are listed.

Is there any additional config I need to add in order to have the possibility to link the email with the custom section?

Sasor

Like 0

Like

2 comments
Best reply

Hello,

Thank you for your question.

If you've created a custom section and want it to appear in the "Connected to" dropdown (e.g., when linking emails in the communication panel), some additional configuration is required. This behavior is not handled automatically for custom sections.

 

This can only be implemented by development:

1. Add a column to the Activity object that references the desired directory.

2. Find the UId of the column added in the first point (in the directory metadata).

3) Execute the script:
DECLARE @columnName varchar(max) = 'UsrColumn';
INSERT INTO [EntityConnection] ([SysEntitySchemaUId], [ColumnUId])
  VALUES (
    (SELECT
      [UId]
    FROM [SysSchema]
    WHERE [Name] = 'Activity'
    AND [ExtendParent] = 0), 
    (SELECT DISTINCT
      [ColumnUId]
    FROM [SysEntitySchemaReference]
    WHERE [SysSchemaId] IN (SELECT
      [Id]
    FROM [SysSchema]
    WHERE [Name] = 'Activity')
    AND [ColumnName] = @columnName));

Where 'UsrColumn' is the name of the column you added to the Activity object. The script will fetch its UId automatically.

4) select * from EntityConnection order by CreatedOn desc
update EntityConnection set ColumnUId = 'UId column added in the first part' where id = 'UId column from select * from EntityConnection order by createdon desc'

5) Perform a cache clear and log back into the system.

 

After this, your custom section should appear in the "Connected to" list and allow linking emails or other activities to it.

Please note: This change requires backend access (via SQL Executor) and should be applied carefully.

 

Thank you!

Hello,

Thank you for your question.

If you've created a custom section and want it to appear in the "Connected to" dropdown (e.g., when linking emails in the communication panel), some additional configuration is required. This behavior is not handled automatically for custom sections.

 

This can only be implemented by development:

1. Add a column to the Activity object that references the desired directory.

2. Find the UId of the column added in the first point (in the directory metadata).

3) Execute the script:
DECLARE @columnName varchar(max) = 'UsrColumn';
INSERT INTO [EntityConnection] ([SysEntitySchemaUId], [ColumnUId])
  VALUES (
    (SELECT
      [UId]
    FROM [SysSchema]
    WHERE [Name] = 'Activity'
    AND [ExtendParent] = 0), 
    (SELECT DISTINCT
      [ColumnUId]
    FROM [SysEntitySchemaReference]
    WHERE [SysSchemaId] IN (SELECT
      [Id]
    FROM [SysSchema]
    WHERE [Name] = 'Activity')
    AND [ColumnName] = @columnName));

Where 'UsrColumn' is the name of the column you added to the Activity object. The script will fetch its UId automatically.

4) select * from EntityConnection order by CreatedOn desc
update EntityConnection set ColumnUId = 'UId column added in the first part' where id = 'UId column from select * from EntityConnection order by createdon desc'

5) Perform a cache clear and log back into the system.

 

After this, your custom section should appear in the "Connected to" list and allow linking emails or other activities to it.

Please note: This change requires backend access (via SQL Executor) and should be applied carefully.

 

Thank you!

Hello Valeria,

Thank you for the detailed script.

It's still a bit strange why the "Connected To" appears for some custom sections (created by us) and not for others.

I’ll try you approach

Show all comments

Hi Creatio Community,

We're encountering a puzzling issue on a Freedom UI List Page (specifically, our Invoices_ListPage) when trying to run a business process (IWVoid_API_POST) using a custom JavaScript handler. The goal is to test the business process by explicitly passing a hardcoded InvoiceId, as requested for a specific testing scenario where the button is not on the individual record's form page.

Our Setup:

  1. The Button (Menu Item on List Page's ActionButton):

    We've added a crt.MenuItem to the ActionButton on our Invoices_ListPage. This menu item is intended for testing and is configured to trigger a custom handler:

    JSON

     

    // In viewConfigDiff of Invoices_ListPage.js
    {
        "operation": "insert",
        "name": "TargetVoidButton", //
        "values": {
            "type": "crt.MenuItem",
            "caption": "Test Void BP (Hardcoded ID)", 
            "icon": "debug-icon",
            "visible": true,
            "clicked": {
                "request": "crt.HandleButtonClickRequest",
                "params": {
                    "buttonName": "RunTargetVoidProcessHandler" 
                }
            }
        },
        "parentName": "ActionButton",
        "propertyName": "menuItems",
        "index": 3 
    }
  2. The Handler (in handlers array of Invoices_ListPage.js):

    This handler is designed to run the IWVoid_API_POST process with a specific, hardcoded InvoiceId.

    JavaScript

     

    // In handlers array of Invoices_ListPage.js
    {
        request: "crt.HandleButtonClickRequest",
        handler: async (request, next) => {
            if (request.buttonName === "RunTargetVoidProcessHandler") { 
                console.log("RunTargetVoidProcessHandler triggered.");
                Terrasoft.showInformation("Test: Running process with hardcoded ID. Check console.");
     
                const processName = "IWVoid_API_POST";
                const hardcodedInvoiceIdForTest = "3c2b6d9f-4c1e-4364-99f2-53956562b606"; 
                const parameterNameInProcess = "InvoiceId"; 
     
                console.log(`Test: Attempting to run BP '<span class="math-inline">\{processName\}' with EXPLICIT HARDCODED ID '</span>{hardcodedInvoiceIdForTest}' for parameter '${parameterNameInProcess}'.`);
     
                try {
                    const response = await request.$context.executeRequest({
                        type: "crt.RunBusinessProcessRequest",
                        params: {
                            processName: processName,
                            processParameters: {
                                [parameterNameInProcess]: hardcodedInvoiceIdForTest
                            },
                            saveAtProcessStart: false, 
                            showNotification: true 
                        }
                    });
     
                    console.log("Test: BP execution request completed. Response:", response);
     
                    if (response && response.success === true && response.processId && response.processId !== '00000000-0000-0000-0000-000000000000') {
                        const successMsg = `Test: BP '${processName}' (ID: ${response.processId}) initiated. Check Process Log.`;
                        console.log(successMsg);
                        request.$context.showInformationDialog?.(successMsg);
                    } else {
                        let errorMsg = `Test: Failed to start BP '${processName}'.`;
                        let serverDetails = (response && response.errorInfo && response.errorInfo.message) ? response.errorInfo.message : "Details unavailable or process not found (zero ID / success:false).";
                        errorMsg += ` ${serverDetails}`;
                        console.error(errorMsg, "Full response:", response);
                        request.$context.showErrorDialog?.(errorMsg);
                    }
                } catch (error) {
                    console.error(`Test: Exception for BP '${processName}':`, error);
                    let exceptionMsg = (error instanceof Error && error.message) ? error.message : "Client-side exception.";
                    if (error.errorInfo && error.errorInfo.message) {
                        exceptionMsg = error.errorInfo.message;
                    }
                    request.$context.showErrorDialog?.(`Test: Error triggering BP: ${exceptionMsg}`);
                }
                return; 
            }
            return next?.handle(request);
        }
    }

The Problem:

When we click the "Test Void BP (Hardcoded ID)" menu item, the handler triggers, and the client-side logs show the crt.RunBusinessProcessRequest is being prepared correctly with processName: "IWVoid_API_POST" and the hardcoded InvoiceId.

However, the server responds with:

{
  processId: '00000000-0000-0000-0000-000000000000', 
  processStatus: 0, 
  resultParameterValues: null, 
  executionData: null, 
  success: false, 
  errorInfo: {
    errorCode: "ItemNotFoundException",
    message: "Item process schema \"\" not found.", // Note the empty quotes for schema name
    stackTrace: null
  }
}

The key error is <strong>Item process schema "" not found.</strong>

What We've Tried:

  • Confirmed the schematic name (Code) of our business process is indeed IWVoid_API_POST.
  • Confirmed the input parameter in the BP designed to take the ID is named InvoiceId.
  • Repeatedly saved, compiled, and published the IWVoid_API_POST business process and ensured it's marked as "Active."
  • Checked the package containing the process for any errors and recompiled the package.
  • Performed thorough browser cache clearing and hard refreshes (Ctrl+F5).
  • We also have another menu item on the same list page ("VoidInvoice") that uses a declarative crt.RunBusinessProcessRequest with processRunType: "ForTheSelectedRecords" and parameterMappings: { "InvoiceId": "Id" }. When a record is selected and this menu item is clicked, it successfully starts the <strong>IWVoid_API_POST</strong> process (verified in Creatio Process Log with a non-zero instance ID). This makes the current error even more puzzling.

Our Questions for the Community:

  1. Why would the ProcessEngineService report Item process schema "" not found (with empty quotes for the schema name) when the processName: "IWVoid_API_POST" is explicitly and correctly provided in the params of crt.RunBusinessProcessRequest from our custom handler?
  2. Is there any known difference in how process names are resolved or how schemas are looked up by the server when crt.RunBusinessProcessRequest is invoked programmatically from a handler with processParameters explicitly set (using a hardcoded ID), versus when it's invoked declaratively with processRunType: "ForTheSelectedRecords" or processRunType: "ForTheSelectedPage"?
  3. Are there any deeper caching mechanisms (server-side, metadata) or specific registration steps for business process schemas that we might be missing, which could lead to this behavior only for the explicit parameter call?
  4. Has anyone encountered a similar situation where a process is findable/runnable via one SDK invocation method (declarative, context-based) but not another (programmatic handler, explicit parameters) from the same Freedom UI page type?

We are unable to access detailed server-side application logs for this specific environment at the moment, which is hampering deeper diagnosis from our end.

Any insights, suggestions, or similar experiences would be greatly appreciated!

Thank you!

Like 0

Like

1 comments

Hi Andrew,

The behavior you described where the system responds with Item process schema "" not found despite providing the correct process name can occur when certain required parameters are missing during the execution of a business process from a handler. Specifically, when using crt.RunBusinessProcessRequest from a crt.HandleButtonClickRequest handler, the backend expects additional context that is typically provided automatically during declarative invocations.

To ensure that the process schema is correctly identified and executed, it is important to explicitly include the processRunType, the recordIdProcessParameterName. These parameters provide the necessary linkage between the UI context and the process runtime.

Below is an example of a working implementation where a business process is successfully launched from a button on a Freedom UI page. The button configuration and handler explicitly define all required fields:

Button configuration:
{
 "operation": "insert",
 "name": "Button_7y0uys4",
 "values": {
   "layoutConfig": {
     "column": 1,
     "row": 2,
     "colSpan": 1,
     "rowSpan": 1
   },
   "type": "crt.Button",
   "caption": "#ResourceString(Button_7y0uys4_caption)#",
   "color": "outline",
   "disabled": false,
   "size": "large",
   "iconPosition": "only-text",
   "visible": true,
   "clicked": {
     "request": "crt.HandleButtonClickRequest",
     "params": {
       "buttonName": "RunTestProcess",
       "processName": "UsrTestProcessInvoiceAdded",
       "processRunType": "ForTheSelectedPage",
       "recordIdProcessParameterName": "InvoiceId"
     }
   }
 },
 "parentName": "SideAreaProfileContainer",
 "propertyName": "items",
 "index": 1
}

Handler logic:
{
 request: "crt.HandleButtonClickRequest",
 handler: async (request, next) => {
   if (request.buttonName === "RunTestProcess") {
     const handlerChain = sdk.HandlerChainService.instance;
     const result = await handlerChain.process({
       type: "crt.RunBusinessProcessRequest",
       processName: "UsrTestProcessInvoiceAdded",
       processRunType: "ForTheSelectedPage",
       recordIdProcessParameterName: "InvoiceId",
       $context: request.$context
     });

     if (result.success) {
       console.log("The process was successfully executed!");
     } else {
       console.log("Exception: " + (result.errorInfo?.message || "Unknown issue"));
     }

     return;
   }
   return next?.handle(request);
 }
}

Answers to your questions:

1. Why would the ProcessEngineService report Item process schema "" not found (with empty quotes for the schema name) when the processName: "IWVoid_API_POST" is explicitly and correctly provided in the params of crt.RunBusinessProcessRequest from our custom handler? 

- This usually happens if processRunType, recordIdProcessParameterName are not passed when triggering the process from a handler. These parameters are essential for correctly resolving the process schema in the runtime context.

2. Is there any known difference in how process names are resolved or how schemas are looked up by the server when crt.RunBusinessProcessRequest is invoked programmatically from a handler with processParameters explicitly set (using a hardcoded ID), versus when it's invoked declaratively with processRunType: "ForTheSelectedRecords" or processRunType: "ForTheSelectedPage"? 

- Yes. In declarative calls, Creatio automatically adds all required metadata. In programmatic calls (handlers), this metadata must be passed manually, especially processRunType and recordIdProcessParameterName.

3. Are there any deeper caching mechanisms (server-side, metadata) or specific registration steps for business process schemas that we might be missing, which could lead to this behavior only for the explicit parameter call? 

- In general, no special registration is required if the process is active and compiled. However, if the process was recently created or modified, reload the page and make sure that the changes in the process were saved.

4. Has anyone encountered a similar situation where a process is findable/runnable via one SDK invocation method (declarative, context-based) but not another (programmatic handler, explicit parameters) from the same Freedom UI page type?

- Yes, this can happen if the required context parameters are not included in the handler call. Declarative calls handle this automatically, whereas in handlers you must explicitly set them.

Show all comments

Hello, is it possible to post a feed in a section record, for example an opportunity record, and this feed is only visible to the @mentioned user, but not all the users who have read access to that opportunity record?

Like 0

Like

4 comments
Best reply

Hello,

Unfortunately, it is not possible to restrict the visibility of feed messages to only specific users with tag through out-of-the-box tools in Creatio. Feed messages typically inherit the access rights of the record they are associated with, meaning anyone with access to the record can also see the feed.

However, you can manage access rights to feed messages by adjusting the permissions for the SocialMessage object. This object controls the visibility of comments and posts within the platform.

You can try to use a  business process to manage the visibility of feed messages. By incorporating logic within the business process, you could create custom steps to control who can access the feed message based on conditions like user roles or specific user mentions.

Best regards,
Ivan

Hi Andrew, were you able to achieve this?

No, that's why I asked here.

Hello,

Unfortunately, it is not possible to restrict the visibility of feed messages to only specific users with tag through out-of-the-box tools in Creatio. Feed messages typically inherit the access rights of the record they are associated with, meaning anyone with access to the record can also see the feed.

However, you can manage access rights to feed messages by adjusting the permissions for the SocialMessage object. This object controls the visibility of comments and posts within the platform.

You can try to use a  business process to manage the visibility of feed messages. By incorporating logic within the business process, you could create custom steps to control who can access the feed message based on conditions like user roles or specific user mentions.

Best regards,
Ivan

Thank you Ivan!

Show all comments

Hello Community,

I would like to know how to skip the warning message that appears when closing a page using a handler.

Currently, I’m using the following code to close the page:

 await request.$context.executeRequest({
  type: "crt.ClosePageRequest",
  $context: request.$context
 });

regards,

Ajay Kuthe.

Like 0

Like

1 comments
Best reply

There is a request called "crt.CanDiscardUnsavedDataRequest" that you can handle to suppress that. See here: https://customerfx.com/article/suppressing-the-unsaved-data-prompt-when-canceling-a-creatio-freedom-ui-modal-dialog/

Ryan

There is a request called "crt.CanDiscardUnsavedDataRequest" that you can handle to suppress that. See here: https://customerfx.com/article/suppressing-the-unsaved-data-prompt-when-canceling-a-creatio-freedom-ui-modal-dialog/

Ryan

Show all comments

Hello Community,

I would like to know how to skip the warning message that appears when closing a page using a handler.

Currently, I’m using the following code to close the page:

 await request.$context.executeRequest({
  type: "crt.ClosePageRequest",
  $context: request.$context
 });

regards,

Ajay Kuthe.

Like 0

Like

1 comments