Skip to main content
Version: 8.1

Manage chats in Creatio

Level: intermediate
note

The functionality is relevant to Classic UI.

The pre-installed OmnichannelMessaging package contains the basic functionality that lets you manage chats. Before using functionality, set up chat processing. Instructions: Set up chat processing (user documentation).

Manage chat functionality in Creatio

View the list of primary classes that let you manage chat functionality in the table below.

Class

Description

MessageManager

Enables the messenger integration with Creatio instance.

FacebookOmnichannelMessagingService

Receives and sends messages from Facebook Messenger. The class is based on the OmnichannelMessagingService class that contains the set methods that are common for both Facebook Messenger and Telegram.

TelegramOmnichannelMessagingService

Receives messages from Telegram. The class is based on the OmnichannelMessagingService class that contains the set methods that are common for both Facebook Messenger and Telegram.

OmnichannelChatService

Receives history, chats of a specific agent, etc.

OmnichannelOperatorService

Receives and changes the agent status.

Implement a custom channel provider

1. Add a channel provider to Creatio

  1. Create a user-made package to add the channel provider. To do this, click Create new package → fill out the package properties → Save.

  2. Change the current package. Instructions: Change the current package.

  3. Open the Lookups section. To do this, click in the top right → System setupLookups.

  4. Open the Channel provider lookup.

  5. Add the lookup value. To do this, click New.

  6. Fill out the properties of the lookup value.

    View the example that adds the "Some custom channel provider" channel provider below.

    Property

    Property value

    Name

    Some custom channel provider

  7. Save the changes.

As a result, the custom channel provider will be added to Creatio.

2. Create a database table to store data of the custom channel provider

Creatio uses one database table to store data of one channel provider. The structure of the database table depends on the provider and contains data to send and receive messages.

To create a database table, execute the SQL query.

IF OBJECT_ID('SomeProviderMsgSettings') IS NULL 
BEGIN
CREATE TABLE SomeProviderMsgSettings(
Id uniqueidentifier NOT NULL DEFAULT (newid()),
Token nvarchar(250) NOT NULL DEFAULT (''),
UserName nvarchar(250) NOT NULL DEFAULT (''),
CONSTRAINT PK_SomeProviderMsgSettings_Id PRIMARY KEY CLUSTERED (Id)
)
END

Where SomeProviderMsgSettings is a template for the name of database table that will store data of the custom channel provider whose name is SomeProvider.

As a result, the database table that stores data of the custom channel provider will be created.

3. Register the custom channel provider in the database

To do this, add a record to the Channel database table that stores a list of all channel providers. View the primary columns of the Channel database table below.

Column

Description

Name

The channel name.

ProviderId

The custom provider ID.

MsgSettingsId

The record ID from the database table that stores data of custom channel provider.

Source

The channel ID from the messenger. For example, Facebook page ID, Telegram client ID. The property value lets you identify the recipient by a messenger message.

As a result, the custom channel provider will be registered in the database.

4. Implement a custom web service that receives messages

  1. Create the source code schema. Instructions: Implement the source code.

  2. Create a service class.

    1. Add the Terrasoft.Configuration.Omnichannel.Messaging namespace.
    2. Add the namespaces the data types of which to utilize in the class using the using directive.
    3. Add a class name that matches the schema name (the Code property).
    4. Specify the OmnichannelMessagingService class as a parent class.
    5. Add the [ServiceContract] and [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)] attributes to the class.
  3. Implement a class method.

    Add the public void ReceiveMessage(SomeProviderIncomingMessage message) method that implements the endpoint of the custom web service. The messenger sends a message to the receive endpoint.

    SomeProviderOmnichannelMessagingService
    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: SomeProviderOmnichannelMessagingService

    [ServiceContract]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
    [DefaultServiceRoute]
    public class SomeProviderOmnichannelMessagingService : OmnichannelMessagingService
    {

    #region Constructors: Public

    public SomeProviderIncomingMessage() : base()
    { }

    /* Initialize a new "SomeProviderIncomingMessage" class instance. */
    public SomeProviderIncomingMessage(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

    /* The method that receives messages from the integration API. */
    [OperationContract]
    [WebInvoke(UriTemplate = "receive", Method = "POST", RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]

    public void ReceiveMessage(SomeProviderIncomingMessage message) {

    /* Convert the message. */
    MessagingMessage messagingMessage = new MessagingMessage(SomeProviderIncomingMessageConverter.Convert(message));

    /* Identify the channel using the "Source" database field. */
    GetChannelAndQueueBySource(messagingMessage);

    /* If an open chat with this user is not found, create a new chat. Otherwise, add a message to an existing chat. If the user 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. Publish the schema.

As a result, a custom web service that receives messages will be implemented.

5. Handle an incoming message

Since Creatio attempts to handle incoming messages in the unified format, implement conversion of incoming messages to unified format. To do this:

  1. Create the source code schema. Instructions: Implement the source code.

  2. Implement the business logic that handles incoming messages using the SomeProviderIncomingMessageConverter class. The class converts a message that has the SomeProviderIncomingMessage type to the message with the MessagingMessage type.

    SomeProviderIncomingMessageConverter
    namespace Terrasoft.Configuration.Omnichannel.Messaging
    {
    using OmnichannelProviders.Domain.Entities;
    using System;
    using System.Collections.Generic;

    public class SomeProviderIncomingMessage : UnifiedMessage
    { }

    public static class SomeProviderIncomingMessageConverter
    {

    #region Methods: Public

    public static MessagingMessage Convert(SomeProviderIncomingMessage 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 "Source" column in the "Channel" database table. */
    Recipient = message.Recipient,

    /* The ID of the message sender in the messenger. The sender is bound to the contact via the "ContactIdentity"]" database table. */
    Sender = message.Sender,

    Timestamp = message.Timestamp,

    /* The channel ID in Creatio specified in the "MsgSettingsid" object field. */
    ChannelId = message.ChannelId,

    MessageDirection = MessageDirection.Incoming,
    MessageType = messageType,

    /* The channel source. */
    Source = ChannelType.ThirdParty,

    /* The provider name that is used as the provider ID. */
    ChannelName = "SomeProvider"
    };

    if (messageType != MessageType.Text) {

    /* The "Attachments" block is populated depending on the file access format provided by the messenger. In this case, it is a link to download. Fill out the "FileId" parameter value 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

    }
    }
  3. Publish the schema.

As a result, incoming messages will be converted to the unified format that Creatio attempts to handle.

6. Implement retrieval of sender data

Messengers provide an API to retrieve sender data. To do this:

  1. Create the source code schema. Instructions: Implement the source code.

  2. Implement the business logic that retrieves sender data using the IProfileDataProvider interface.

    1. Send a request to the channel provider API, for example, https://somechannelprovider.api/, to retrieve data in the SomeProviderProfileData format. The SomeProviderProfileData format is a hypothetical messenger format.
    2. Convert the received response into the internal ProfileData format.
    3. Create a contact and add the retrieved data using the internal format. For example, first name, last name, and photo. If the request is unsuccessful or data is invalid, create a contact named [New Contact][Channel]-[MessengerClientID].
    SomeProviderProfileData
    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 SomeProviderProfileData {
    public string first_name { get; set; }
    public string last_name { get; set; }
    }

    #region Class: SomeProviderProfileData

    /* Retrieve the profile data from the "SomeProvider" provider. */
    public class SomeProviderProfileData : IProfileDataProvider
    {
    #region Properties: Private

    private readonly string _someProviderUrl = "https://somechannelprovider.api/";

    #endregion

    #region Constructors: Public

    /* Initialize a new "FacebookProfileDataProvider" class instance. */
    public SomeProviderProfileData(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 the request was sent.
    Return the contact ID. */
    public ProfileData GetProfileDataByProfileId(string profileId, string channelId) {
    var requestUrl = string.Concat(_someChannelProviderNameProviderApiUrl, profileId);
    WebRequest request = WebRequest.Create(requestUrl);
    try {
    using (var response = request.GetResponse()) {
    using (Stream stream = response.GetResponseStream()) {
    using (StreamReader sr = new StreamReader(stream)) {
    var someChannelProviderNameProfile = JsonConvert.DeserializeObject<SomeChannelProviderNameProfileData>(sr.ReadToEnd());
    return new ProfileData {
    FirstName = someChannelProviderNameProfile.first_name,
    LastName = someChannelProviderNameProfile.last_name,
    };
    }
    }
    }
    }
    catch {
    return new ProfileData();
    }
    }

    #endregion

    }

    #endregion
    }
  3. Publish the schema.

As a result, Creatio will retrieve the sender data and create contact using this data.

7. Implement downloading of attachments

  1. Create the source code schema. Instructions: Implement the source code.

  2. Implement the business logic that lets you download attachments using the IAttachmentsLoadWorker interface. The class downloads the attachment via a link and saves the attachment to the OmnichannelMessageFile database table.

    SomeProviderAttachmentLoadWorker
    namespace Terrasoft.Configuration.Omnichannel.Messaging
    {
    using OmnichannelProviders;
    using OmnichannelProviders.Domain.Entities;
    using OmnichannelProviders.MessageConverters;
    using Terrasoft.Core;

    #region Class: SomeProviderAttachmentLoadWorker

    /* Load attachments from the "SomeProvider" provider. */
    public class SomeProviderAttachmentLoadWorker : IAttachmentsLoadWorker
    {

    #region Properties: Protected

    protected UserConnection UserConnection;
    protected AttachmentsDownloader AttachmentsDownloader;

    #endregion

    #region Constructors: Public

    /* Initialize a new "SomeProviderAttachmentLoadWorker" class instance. */
    public SomeProviderAttachmentLoadWorker(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
    }
  3. Publish the schema.

As a result, users will be able to download attachments.

8. Implement sending of messages

  1. Create the source code schema. Instructions: Implement the source code.

  2. Implement the business logic that sends messages using the IOutcomeMessageWorker interface.

    1. Convert the message to messenger format and send it using the messenger API.
    2. Send the message using a token. Store the token in the SomeChannelProviderNameMsgSettings database table.
    3. UserConnection sent in the constructor provides access to the database table.
    4. Send a message to the channel provider API, for example, https://somechannelprovider.api/, using the HttpRequestSender class.
    SomeProviderOutcomeMessageWorker
    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: SomeProviderOutcomeMessageWorker

    /* Send messages to the "SomeProvider" provider. */
    public class SomeProviderOutcomeMessageWorker : IOutcomeMessageWorker
    {

    #region Properties: Protected

    protected UserConnection UserConnection;
    private readonly string _someChannelProviderNameProviderApiUrl = "https://somechannelprovider.api";

    #endregion

    #region Constructors: Public

    /* Initialize a new "SomeProviderOutcomeMessageWorker" class instance. */
    public SomeProviderOutcomeMessageWorker(UserConnection userConnection) {
    UserConnection = userConnection;
    }

    #endregion

    #region Methods: Public

    /* Send the message to the "SomeProvider" provider.
    The "message" parameter is the unified 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(_someChannelProviderNameProviderApiUrl, json);
    var result = new HttpRequestSender().PostAsync(requestUrl, json).Result;
    success = true;
    return result;
    }

    public string PassControlToPrimaryReceiver(UnifiedMessage message) {
    return string.Empty;
    }

    #endregion
    }

    #endregion
    }
  3. Publish the schema.

As a result, users will be able to send messages.

9. Link the interfaces

  1. Create the source code schema. Instructions: Implement the source code.

  2. Implement the business logic that links interfaces.

    1. Specify the AppEventListenerBase class as a parent class.
    2. Link the created classes using the SomeProvider provider ID that is specified in the ChannelName property of the business logic handling incoming messages. Creatio uses a provider ID to identify the files required to retrieve profile data, upload attachments, and send messages.
    SomeProviderAppEventListener
    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 : SomeProviderAppEventListener

    /* Run prerequisites for "OmnichannelMessaging" on app start. */
    public class SomeProviderAppEventListener : 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.
    Return 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, SomeChannelProviderNameAttachmentLoadWorker>(ChannelType.ThirdParty.ToString());
    ClassFactory.Bind<IProfileDataProvider, SomeChannelProviderNameProfileDataProvider>(ChannelType.ThirdParty.ToString());
    ClassFactory.Bind<IOutcomeMessageWorker, SomeChannelProviderNameOutcomeMessageWorker>(ChannelType.ThirdParty.ToString());
    }

    #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

    }
  3. Publish the schema.

As a result, the custom channel provider will be implemented.


See also

Configuration elements of the Source code type


Resources

Chat setup (user documentation)