Chat management API

Medium

The preinstalled OmnichannelMessaging package contains the basic chat management functionality.

Learn more about setting up messenger integration in the user documentation guide: Chat setup.

Integrate a messenger 

The following libraries contain the core of the messenger integration functionality:

  • OmnichannelMessaging.dll
  • OmnichannelProviders.dll

The MessageManager class enables the messenger integration.

The primary methods of the MessageManager class are as follows:

  • Receive. Receives incoming messages in the unified format (UnifiedMessage, a unified message class) or as a string, which is then converted into the unified format. If the conversion is required, the method uses a class that implements the IIncomeMessageWorker interface. The interface is implemented differently for each messenger. The method also saves messages in Creatio.
  • Send. Sends outgoing messages. Creatio selects the relevant message sender class. The class must implement the IOutcomeMessageWorker interface. The method also saves messages in Creatio.
  • Register. Adds a channel when setting up Facebook Messenger integration. The method uses the class that implements the IMessengerRegistrationWorker interface. Required for messengers that need additional actions upon registration. For example, retrieve a token.
  • GetMessagesByChatId. Retrieves messages of a specific chat in the IEnumerable<UnifiedMessage> format. Pass the chat in method parameters

Receive messages 

The messenger specific message reception services are as follows:

  • FacebookOmnichannelMessagingService. Receives Facebook Messenger messages.
  • TelegramOmnichannelMessagingService. Receives Telegram messages.

Both services are based on the OmnichannelMessagingService service that contains the set methods that are common for both messengers.

InternalReceive is the primary method of the OmnichannelMessagingService service. Receives messages.

Manage chats in Creatio 

Creatio includes the following chat management services:

  • OmnichannelChatService. Lets you retrieve history, chats of a specific agent, etc.
  • OmnichannelOperatorService. Lets you retrieve and change the agent status.

The primary methods of the OmnichannelChatService service are as follows:

  • AcceptChat. Assigns the chat to the current user.
  • GetUnreadChatsCount. Retrieves the number of unread chats.
  • MarkChatAsRead. Marks all messages in the chat as read.
  • GetConversation. Retrieves chat messages to display them in the communication panel.
  • CloseActiveChat. Closes the chat.
  • GetChats. Retrieves all chats of the agent.
  • GetChatActions. Retrieves the list of actions available for the chat’s queue.
  • GetUnreadMessagesCount. Retrieves the number of unread messages in all chats of the agent.

Add a new channel provider 

  1. Add a new provider to the Channel provider lookup.
  2. Implement the database storage of the new channel’s data.
  3. Register the new channel in the database.
  4. Create a web service that receives messages.
  5. Implement the conversion of incoming messages to the unified Creatio format.
  6. Implement retrieval of data in a class that implements the IProfileDataProvider interface.
  7. Implement the download of attachments.
  8. Implement the sending of messages in a class that implements the IOutcomeMessageWorker interface.
  9. Link the interfaces.
Add a custom channel provider
Advanced

Example. Add a custom Test channel provider to Creatio on-site.

1. Add a custom channel provider to Creatio 

  1. Click scr_system_designer.png to open the System Designer.
  2. Go to the System setup block → Lookups.
  3. Open the Channel provider lookup and add the "Test" value.

2. Set up storage of custom channel data 

  1. Create a database table and define its structure. The table structure depends on the provider and contains data to send and receive messages. Generally, providers use an authorization token to send messages. To do this, execute the SQL query below.

    SQL query that creates the [TestMsgSettings] table
    MSSQL
    PostgreSQL
    IF OBJECT_ID('TestMsgSettings') IS NULL 
        BEGIN
        CREATE TABLE TestMsgSettings(
            Id uniqueidentifier NOT NULL DEFAULT (newid()),
            Token nvarchar(250) NOT NULL DEFAULT (''),
            UserName nvarchar(250) NOT NULL DEFAULT (''),
            CONSTRAINT PK_TestMsgSettings_Id PRIMARY KEY CLUSTERED (Id)
        )
    END
    
    CREATE TABLE IF NOT EXISTS public."TestMsgSettings" ( 
        "Id" uuid NOT NULL DEFAULT uuid_generate_v4(),
        "Token" character varying(250) COLLATE pg_catalog."default" NOT NULL DEFAULT ''::character varying,
        "UserName" character varying(250) COLLATE pg_catalog."default" NOT NULL DEFAULT ''::character varying,
        CONSTRAINT "PK_TestMsgSettings_Id" PRIMARY KEY ("Id")
    );
    

    [TestMsgSettings] is a table that stores the custom channel data. Name the table based on the [SomeChannelProviderNameMsgSettings] template, where SomeChannelProviderName is the channel provider name.

  2. Register the custom channel in the database. To do this, add a record to the [Channel] table. View the fields to fill out in the table below.

    [Channel] table fields
    Field
    Description
    [Name]
    The channel name.
    [ProviderId]
    The custom provider ID.
    [MsgSettingsId]
    The record ID in the [TestMsgSettings] table.
    [Source]
    The channel ID in the messenger, such as the Facebook page ID or Telegram client ID. Lets you identify the recipient by a messenger message.

3. Create a web service that receives messages 

  1. Create a Source code schema.

    1. Open the Configuration section and select a custom package to add the schema.
    2. Click AddSource code on the section list toolbar.

    3. Fill out the schema properties in the Source Code Designer.

      • Set Code to "UsrTestOmnichannelMessagingService."
      • Set Title to "TestOmnichannelMessagingService."

      Click Apply to apply the changes.

  2. Create a web service class.

    1. Go to the Schema Designer and add the Terrasoft.Configuration.Omnichannel.Messaging namespace.
    2. Use the using directive to import the namespaces whose data types are utilized in the class.
    3. Add a class name to match the schema name (the Code property).
    4. Specify the OmnichannelMessagingService class that contains the basic methods as a parent class.
    5. Add the [ServiceContract] and [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)] attributes to the class.
  3. Implement a method (i. e., endpoint) of the web service class. To do this, add the public void ReceiveMessage(TestIncomingMessage message) method to the class in the Source Code Designer. The messenger sends a message to the receive endpoint.

    View the source code of the TestOmnichannelMessagingService custom web service below.

    TestOmnichannelMessagingService
    namespace Terrasoft.Configuration.Omnichannel.Messaging
    {
        using System;
        using System.ServiceModel;
        using System.ServiceModel.Activation;
        using System.ServiceModel.Web;
        using Terrasoft.Common;
        using Terrasoft.Core;
        using Terrasoft.Core.DB;
        using Terrasoft.Web.Common.ServiceRouting;
    
        #region Class: TestOmnichannelMessagingService
    
        /* The service sends and receives messages from the messaging integration API. */
        [ServiceContract]
        [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
        [DefaultServiceRoute]
        public class TestOmnichannelMessagingService : OmnichannelMessagingService
        {
    
            #region Constructors: Public
    
            public TestOmnichannelMessagingService() : base() {
            }
    
            /* Initialize a new instance of TestOmnichannelMessagingService. */
            public TestOmnichannelMessagingService(UserConnection userConnection) : base(userConnection) {
            }
    
            #endregion
    
            #region Methods: Private
    
            private void GetChannelAndQueueBySource(MessagingMessage message) {
                Select channelSelect = new Select(UserConnection)
                    .Top(1).Column("Id")
                    .Column("ChatQueueId")
                    .From("Channel")
                    .Where("Source").IsEqual(Column.Parameter(message.Recipient))
                    .And("IsActive").IsEqual(Column.Parameter(true)) as Select;               
                channelSelect.ExecuteReader(reader => {
                    message.ChannelId = reader.GetColumnValue("Id").ToString();
                    message.ChannelQueueId = reader.GetColumnValue("ChatQueueId");
                });
            }
    
            #endregion
    
            #region Methods: Public
    
            /* Receive messages from the integration API. */
            [OperationContract]
            [WebInvoke(UriTemplate = "receive", Method = "POST", RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
            
            /* The message parameter is a test provider message. */
            public void ReceiveMessage(TestIncomingMessage message) {
            
                /* Convert the message. */
                MessagingMessage messagingMessage = new MessagingMessage(TestIncomingMessageConverter.Convert(message));
                
                /* Identify the channel using the [Source] field. */
                GetChannelAndQueueBySource(messagingMessage);
                
                /* Create a new chat if an open chat with this customer is not found. Otherwise, add a message to an existing chat.
                If the customer contacts you for the first time, create a contact  and fill out their credentials. Otherwise, bind the chat to an existing contact. */
                InternalReceive(messagingMessage);
            }
    
            #endregion
    
        }
    
        #endregion
    
    }
    
  4. Click Publish on the Source Code Designer’s toolbar to apply the changes to the database level.

4. Implement the conversion of an incoming message 

To handle an incoming message, implement the TestIncomingMessageConverter class that converts a message with the TestIncomingMessage type (messenger format message) to the unified Creatio format (the MessagingMessage class).

To create a converter class:

  1. Open the Configuration section and select a custom package to add the schema.
  2. Click AddSource code on the section list toolbar.
  3. Fill out the schema properties in the Source Code Designer.

    • Set Code to "UsrTestIncomingMessageConverter."
    • Set Title to "TestIncomingMessageConverter."

    Click Apply to apply the changes.

  4. Add the source code in the Source Code Designer. View the source code of the TestIncomingMessageConverter converter class below.

    TestIncomingMessageConverter
    namespace Terrasoft.Configuration.Omnichannel.Messaging
    {
        using OmnichannelProviders.Domain.Entities;
        using System;
        using System.Collections.Generic;
    
        public class TestIncomingMessage : UnifiedMessage
        { }
    
        public static class TestIncomingMessageConverter
        {
            #region Methods: Public 
    
            public static MessagingMessage Convert(TestIncomingMessage message) {
                var messageType = MessageType.Text;
                var messageId = Guid.NewGuid();
                var result = new MessagingMessage {
                    Id = messageId,
                    Message = message.Message,
                    /* The message recipient is the ID of the page or client added to the [Channel] table (the [Source] field). */
                    Recipient = message.Recipient,
                    /* The ID of the message sender in the messenger. The sender is bound to the contact via the [ContactIdentity] decoupling table. */
                    Sender = message.Sender, 
                    Timestamp = message.Timestamp,
                    /* The channel ID in Creatio, the [MsgSettingsid] object field. */
                    ChannelId = message.ChannelId, 
                    MessageDirection = MessageDirection.Incoming,
                    MessageType = messageType,
                    /* Specify the channel source (third-party developers). */
                    Source = ChannelType.ThirdParty, 
                    /* The provider name. Serves as the provider ID further. */
                    ChannelName = "Test" 
                };
                if (messageType != MessageType.Text) {
                
                    /* The [Attachments] block is populated based on the file access format that the messenger provides. It is the download link in this case. You can pass the [FileId] in the message to make the file available for download. */
                    result.Attachments = new List<MessageAttachment>();
                    foreach (var attachment in message.Attachments){
                        result.Attachments.Add(new MessageAttachment {
                            MessageId = messageId,
                            UploadUrl = attachment.UploadUrl,
                            FileType = attachment.FileType
                        });
                    }
                }
                return result;
            }
    
            #endregion
    
        }
    }
    
  5. Click Publish on the Source Code Designer’s toolbar to apply the changes to the database level.

5. Implement retrieval of user profile data 

Messengers provide an API to retrieve data from clients that send messages. To retrieve user profile data, create a class that implements the IProfileDataProvider interface.

To create a class that retrieves user profile data:

  1. Open the Configuration section and select a custom package to add the schema.
  2. Click AddSource code on the section list toolbar.
  3. Fill out the schema properties in the Source Code Designer.

    • Set Code to "UsrTestProfileDataProvider."
    • Set Title to "TestProfileDataProvider."

    Click Apply to apply the changes.

  4. Add the source code in the Source Code Designer.

    • The class sends a request to the https://graph.test.com/ address to retrieve data in the TestProfileData format (a hypothetical messenger format).
    • The class converts the received response into the internal ProfileData format.
    • The class adds the retrieved data, for example, first name, last name, and photo, to the internal format when creating a contact. If the request is unsuccessful or data is invalid, the class creates a contact named [New Contact][Channel Name]-[Messenger Client ID].

    View the source code of the TestProfileDataProvider class below.

    TestProfileDataProvider
    namespace Terrasoft.Configuration.Omnichannel.Messaging
    {
        using Newtonsoft.Json;
        using OmnichannelProviders.Domain.Entities;
        using OmnichannelProviders.Interfaces;
        using System.IO;
        using System.Net;
        using Terrasoft.Core;
    
        public class TestProfileData {
            public string first_name { get; set; }
            public string last_name { get; set; }
        }
    
        #region Class: TestProfileDataProvider
    
        /* Retrieve the profile data from the Test provider. */
        public class TestProfileDataProvider : IProfileDataProvider
        {
            #region Properties: Private 
    
            private readonly string _testProviderApiUrl = "https://graph.test.com/";
    
            #endregion
    
            #region Constructors: Public 
    
            /* Initialize a new instance of FacebookProfileDataProvider. */
            public TestProfileDataProvider(UserConnection userConnection) {
            }
    
            #endregion
    
            #region Methods: Public
    
            /* Retrieve the profile data from Facebook.
            The "profileId" parameter is the Facebook profile ID.
            The "channelId" parameter is the channel from which to send the request.
            Return the contact ID. */
            public ProfileData GetProfileDataByProfileId(string profileId, string channelId)    {
                var requestUrl = string.Concat(_testProviderApiUrl, profileId);
                WebRequest request = WebRequest.Create(requestUrl);
                try {
                    using (var response = request.GetResponse()) {
                        using (Stream stream = response.GetResponseStream()) {
                            using (StreamReader sr = new StreamReader(stream)) {
                                var testProfile = JsonConvert.DeserializeObject<TestProfileData>(sr.ReadToEnd());
                                return new ProfileData {
                                    FirstName = testProfile.first_name,
                                    LastName = testProfile.last_name,
                                };
                            }
                        }
                    }
                }
                catch {
                    return new ProfileData();
                }
            }
    
            #endregion
    
        }
    
        #endregion
    }
    
  5. Click Publish on the Source Code Designer’s toolbar to apply the changes to the database level.

6. Implement ability to download attachments 

To download attachments, create the class that implements the IAttachmentsLoadWorker interface:

  1. Open the Configuration section and select a custom package to add the schema.
  2. Click AddSource code on the section list toolbar.
  3. Fill out the schema properties in the Source Code Designer.

    • Set Code to "UsrTestAttachmentLoadWorker."
    • Set Title to "TestAttachmentLoadWorker."

    Click Apply to apply the changes.

  4. Add the source code in the Source Code Designer. The AttachmentsDownloader internal class downloads the attachment via a link and saves the attachment to the [OmnichannelMessageFile] database table.

    View the source code of the TestAttachmentLoadWorker class below.

    TestAttachmentLoadWorker
    namespace Terrasoft.Configuration.Omnichannel.Messaging
    {
        using OmnichannelProviders;
        using OmnichannelProviders.Domain.Entities;
        using OmnichannelProviders.MessageConverters;
        using Terrasoft.Core;
    
        #region Class: TestAttachmentLoadWorker
    
        /* The class that loads attachments from the Test provider. */
        public class TestAttachmentLoadWorker : IAttachmentsLoadWorker
        {
    
            #region Properties: Protected 
    
            protected UserConnection UserConnection;
            protected AttachmentsDownloader AttachmentsDownloader;
    
            #endregion
    
            #region Constructors: Public
    
            /* Initialize a new instance of the TestAttachmentLoadWorker class. */
            public TestAttachmentLoadWorker(UserConnection userConnection) {
                UserConnection = userConnection;
                AttachmentsDownloader = new AttachmentsDownloader(userConnection);
            }
    
            #endregion
    
            #region Methods: Public 
    
            /* Load the attachments.
            The incomeAttachment parameter is the attachment from the messenger.
            The "message" parameter is the source message. */
            public void Load(MessageAttachment incomeAttachment, UnifiedMessage message) {
                incomeAttachment.FileName = FileUtilities.GetFileNameFromUrl(incomeAttachment.UploadUrl);
                incomeAttachment.FileId = AttachmentsDownloader.Load(incomeAttachment);
            }
    
            #endregion
        }
    
        #endregion
    }
    
  5. Click Publish on the Source Code Designer’s toolbar to apply the changes to the database level.

7. Implement message sending 

To send messages, create a class that implements the IOutcomeMessageWorker interface:

  1. Open the Configuration section and select a custom package to add the schema.
  2. Click AddSource code on the section list toolbar.
  3. Fill out the schema properties in the Source Code Designer.

    • Set Code to "UsrTestOutcomeMessageWorker."
    • Set Title to "TestOutcomeMessageWorker."

    Click Apply to apply the changes.

  4. Add the source code in the Source Code Designer. The TestOutcomeMessageWorker class converts the message to messenger format and sends it using the messenger API. The class can send the message using a token. Store the token in the [TestMsgSettings] database table. UserConnection passed in the constructor provides access to the table. The class sends a message to the https://graph.test.com/ address using the internal HttpRequestSender class.

    View the source code of the TestOutcomeMessageWorker class below.

    TestOutcomeMessageWorker
    namespace Terrasoft.Configuration.Omnichannel.Messaging
    {
        using Newtonsoft.Json;
        using Newtonsoft.Json.Serialization;
        using OmnichannelProviders.Application.Http;
        using OmnichannelProviders.Domain.Entities;
        using OmnichannelProviders.MessageWorkers;
        using Terrasoft.Core;
    
        #region Class: TestOutcomeMessageWorker
    
        /* The class that sends messages to the Test provider. */
        public class TestOutcomeMessageWorker : IOutcomeMessageWorker
        {
    
            #region Properties: Protected 
    
            protected UserConnection UserConnection;
            private readonly string _testProviderApiUrl = "https://graph.test.com/";
    		
            #endregion
    
            #region Constructors: Public
    
            /* Initialize a new instance of the TestOutcomeMessageWorker class. */
            public TestOutcomeMessageWorker(UserConnection userConnection) {
                UserConnection = userConnection;
            }
    
            #endregion
    
            #region Methods: Public
    
            /* Send the message to the Test provider.
            The "message" parameter is the UnifiedMessage message. */
            public string SendMessage(UnifiedMessage unifiedMessage, out bool success) {
                var serializerSettings = new JsonSerializerSettings();
                serializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
                var json = JsonConvert.SerializeObject(unifiedMessage, serializerSettings);
                var requestUrl = string.Concat(_testProviderApiUrl, json);
                var result = new HttpRequestSender().PostAsync(requestUrl, json).Result;
    			success = true;
                return result;
            }
    		
    		public string PassControlToPrimaryReceiver(UnifiedMessage message) {
    			return string.Empty;
    		}
    
            #endregion
        }
    
        #endregion
    }
    
  5. Click Publish on the Source Code Designer’s toolbar to apply the changes to the database level.

8. Link the interfaces 

To link the interfaces, create a class.

To create a class:

  1. Open the Configuration section and select a custom package to add the schema.
  2. Click AddSource code on the section list toolbar.
  3. Fill out the schema properties in the Source Code Designer.

    • Set Code to "UsrTestAppEventListener."
    • Set Title to "TestAppEventListener."

    Click Apply to apply the changes.

  4. Add the source code in the Source Code Designer. Specify the AppEventListenerBase class as a parent class. The Test tag links the created classes. Specify the tag in the ChannelName field on step 4. Creatio uses a tag to identify the files required to retrieve profile data, upload attachments, and send messages.

    View the source code of the TestAppEventListener class below.

    TestAppEventListener
    namespace Terrasoft.Configuration.Omnichannel.Messaging
    {
        using Common;
        using Core;
        using OmnichannelProviders;
        using OmnichannelProviders.Interfaces;
        using OmnichannelProviders.MessageWorkers;
        using Terrasoft.Core.Factories;
        using Web.Common;
    
        #region Class : TestAppEventListener
    
        /* The class that runs prerequisites for OmnichannelMessaging on app start. */
        public class TestAppEventListener : AppEventListenerBase
        {
    
            #region Fields : Protected
    
            protected UserConnection UserConnection {
                get;
                private set;
            }
    
            #endregion
    
            #region Methods : Protected
    
            /* Retrieve the user connection from the app event scope.
            The "context" parameter is the app event scope.
            Returns user connection. */
            protected UserConnection GetUserConnection(AppEventContext context) {
                var appConnection = context.Application["AppConnection"] as AppConnection;
                if (appConnection == null) {
                    throw new ArgumentNullOrEmptyException("AppConnection");
                }
                return appConnection.SystemUserConnection;
            }
    
            protected void BindInterfaces() {
                ClassFactory.Bind<IAttachmentsLoadWorker, TestAttachmentLoadWorker>("Test");
                ClassFactory.Bind<IProfileDataProvider, TestProfileDataProvider>("Test");
                ClassFactory.Bind<IOutcomeMessageWorker, TestOutcomeMessageWorker>("Test");
            }
    
            #endregion
    
            #region Methods : Public
    
            /* Handle the app start.
            The "context" parameter is the app event scope. */
            public override void OnAppStart(AppEventContext context) {
                base.OnAppStart(context);
                UserConnection = GetUserConnection(context);
                BindInterfaces();
            }
    
            #endregion
    
        }
    
        #endregion
    
    }
    
  5. Click Publish on the Source Code Designer’s toolbar to apply the changes to the database level.
Add a chat routing mechanism
Advanced

To set up chat routing, select a routing rule from the drop-down list in the queue settings. This determines the mechanism that distributes chats to agents.

View an example that adds a custom distribution mechanism below.

Example. Add a custom chat distribution mechanism. Grant the system user (Supervisor) access to new chats. Grant agents access to distributed chats.

1. Add a new chat routing rule 

  1. Click the scr_system_designer.png button to open the System Designer.
  2. Go to the System setup block → Lookups.
  3. Use the filter at the top to find the "Rules for routing chat queue operators" lookup.
  4. Open the lookup content and add a new rule:
    • Set Name to "Test rule."
    • Set Code to "TestRule."

2. Create a class that implements the IOperatorRoutingRule interface 

On this step, you can create a class that inherits from the BaseOperatorRoutingRule class or new class that implements the IOperatorRoutingRule interface.

The BaseOperatorRoutingRule class contains abstract PickUpFreeQueueOperators and GetChatOperator methods you must implement.

Abstract methods of the BaseOperatorRoutingRule class
/// <summary>
/// Pick up and return queue agent IDs.
/// </summary>
/// <param name="chatId"><see cref="OmniChat"/> The agent ID.</param>
/// <param name="queueId"><see cref="ChatQueue"/> The instance ID.</param>
/// <returns>The queue agent IDs.</returns>
protected abstract List<Guid> PickUpFreeQueueOperators(Guid chatId, Guid queueId);

/// <summary>
/// Returns the <see cref="OmniChat"/> agent ID.
/// </summary>
/// <param name="chatId"><see cref="OmniChat"/> The agent ID.</param>
/// <returns>The chat agent.</returns>
protected abstract Guid GetChatOperator(Guid chatId);

Moreover, the BaseOperatorRoutingRule already contains the implementation of the IOperatorRoutingRule interface. View the implementation logic below.

Implementation of the IOperatorRoutingRule interface
public List <Guid> GetOperatorIds(string chatId, Guid queueId) {
    var parsedChatId = Guid.Parse(chatId);
    var chatOperator = GetChatOperator(parsedChatId);
    return chatOperator.IsNotEmpty() ? new List <Guid> {
        chatOperator
    }: PickUpFreeQueueOperators(parsedChatId, queueId);
}

If the chat is already assigned to an agent (the user ID is specified in the [OperatorId] column), select the agent. If the chat is not assigned to an agent, retrieve the agent or agents as List<Guid> using the PickUpFreeQueueOperators method. In this case, Guid are agent IDs in the [SysAdminUnit] table. The agents that have the corresponding IDs receive new chat notifications and can access the chat in the communication panel.

Create a TestOperatorRoutingRule class that implements the basic logic that routes the chat to the system user (Supervisor).

To create a class:

  1. Go to the Configuration section and select a custom package to add the schema.
  2. Click AddSource code on the section list toolbar.
  3. Go to the Schema Designer and fill out the schema properties:

    • Set Code to "UsrTestOperatorRoutingRule."
    • Set Title to "TestOperatorRoutingRule."

    Click Apply to apply the properties.

  4. Add the source code in the Schema Designer.

TestOperatorRoutingRule
namespace Terrasoft.Configuration.Omnichannel.Messaging {
    using System;
    using System.Collections.Generic;
    using Terrasoft.Core;
    using Terrasoft.Core.DB;

    #region Class: ForEveryoneOperatorRoutingRule

    /// <summary>
    /// Retrieve chat agents.
    /// </summary>
    public class TestOperatorRoutingRule: BaseOperatorRoutingRule {

        #region Constructors: Public

        /// <summary>
        /// Initialize a new instance of <see cref="TestOperatorRoutingRule"/>.
        /// </summary>
        /// <param name="userConnection"><see cref="UserConnection"/> the instance.</param>
        public TestOperatorRoutingRule(UserConnection userConnection) : base(userConnection) {}

        #endregion

        #region Methods: Private

        #endregion

        #region Methods: Protected

        /// <inheritdoc cref="BaseOperatorRoutingRule.PickUpFreeQueueOperators(Guid, Guid)"/>
        protected override List < Guid > PickUpFreeQueueOperators(Guid chatId, Guid queueId) {
            return new List < Guid > {
                Guid.Parse("7F3B869F-34F3-4F20-AB4D-7480A5FDF647")
            };
        }

        /// <inheritdoc cref="BaseOperatorRoutingRule.GetChatOperator(Guid)"/>
        protected override Guid GetChatOperator(Guid chatId) {
            Guid operatorId = (new Select(UserConnection).Column("OperatorId").From("OmniChat", "oc").Where("oc", "Id").IsEqual(Column.Parameter(chatId))
            as Select).ExecuteScalar < Guid > ();
            return operatorId;
        }

        #endregion

    }

    #endregion
}

3. Link the interface and lookup rule code 

To link the interface implementation and alphabetic code of the rule you specified in the lookup on step 1, create a TestAppEventListener class (inherit the class from the AppEventListenerBase class) and link the interfaces in it.

To create a class:

  1. Go to the Configuration section and select a custom package to add the schema.
  2. Click AddSource code on the section list toolbar.
  3. Go to the Schema Designer and fill out the schema properties:

    • Set Code to "UsrTestAppEventListener."
    • Set Title to "TestAppEventListener."

    Click Apply to apply the properties.

  4. Add the source code in the Schema Designer.

TestAppEventListener
namespace Terrasoft.Configuration.Omnichannel.Messaging {
    using Common;
    using Core;
    using Terrasoft.Core.Factories;
    using Web.Common;

    #region Class: TestAppEventListener

    /// <summary>
    /// The class that runs prerequisites for OmnichannelMessaging on the application start.
    /// </summary>
    public class TestAppEventListener: AppEventListenerBase {

        #region Fields: Protected

        protected UserConnection UserConnection {
            get;
            private set;
        }

        #endregion

        #region Methods: Protected

        /// <summary>
        /// Retrieve the user connection from the application event scope.
        /// </summary>
        /// <param name="context">The application event scope.</param>
        /// <returns>User connection.</returns>
        protected UserConnection GetUserConnection(AppEventContext context) {
            var appConnection = context.Application["AppConnection"] as AppConnection;
            if (appConnection == null) {
                throw new ArgumentNullOrEmptyException("AppConnection");
            }
            return appConnection.SystemUserConnection;
        }

        protected void BindInterfaces() {
            ClassFactory.Bind < IOperatorRoutingRule,
            TestOperatorRoutingRule > ("TestRule");
        }

        #endregion

        #region Methods: Public

        /// <summary>
        /// Handle the application start.
        /// </summary>
        /// <param name="context">The application event scope.</param>
        public override void OnAppStart(AppEventContext context) {
            base.OnAppStart(context);
            UserConnection = GetUserConnection(context);
            BindInterfaces();
        }

        #endregion

    }

    #endregion

}

4. Restart Creatio in IIS 

Restart Creatio in IIS to apply the changes. After you restart Creatio and select "Test rule" in the queue settings, Creatio will distribute chats based on the specified conditions.