Manage chats in Creatio
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 |
TelegramOmnichannelMessagingService | Receives messages from Telegram. The class is based on the |
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
-
Create a user-made package to add the channel provider. To do this, click → Create new package → fill out the package properties → Save.
-
Change the current package. Instructions: Change the current package.
-
Open the Lookups section. To do this, click in the top right → System setup → Lookups.
-
Open the Channel provider lookup.
-
Add the lookup value. To do this, click New.
-
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
-
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.
- Microsoft SQL
- PostgreSQL
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
CREATE TABLE IF NOT EXISTS public."SomeProviderMsgSettings" (
"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_SomeProviderMsgSettings_Id" PRIMARY KEY ("Id")
);
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, |
As a result, the custom channel provider will be registered in the database.
4. Implement a custom web service that receives messages
-
Create the source code schema. Instructions: Implement the source code.
-
Create a service class.
- Add the
Terrasoft.Configuration.Omnichannel.Messaging
namespace. - Add the namespaces the data types of which to utilize in the class using the
using
directive. - Add a class name that matches the schema name (the Code property).
- Specify the
OmnichannelMessagingService
class as a parent class. - Add the
[ServiceContract]
and[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
attributes to the class.
- Add the
-
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 thereceive
endpoint.SomeProviderOmnichannelMessagingServicenamespace 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
} -
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:
-
Create the source code schema. Instructions: Implement the source code.
-
Implement the business logic that handles incoming messages using the
SomeProviderIncomingMessageConverter
class. The class converts a message that has theSomeProviderIncomingMessage
type to the message with theMessagingMessage
type.SomeProviderIncomingMessageConverternamespace 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
}
} -
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:
-
Create the source code schema. Instructions: Implement the source code.
-
Implement the business logic that retrieves sender data using the
IProfileDataProvider
interface.- Send a request to the channel provider API, for example,
https://somechannelprovider.api/
, to retrieve data in theSomeProviderProfileData
format. TheSomeProviderProfileData
format is a hypothetical messenger format. - Convert the received response into the internal
ProfileData
format. - 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]
.
SomeProviderProfileDatanamespace 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
} - Send a request to the channel provider API, for example,
-
Publish the schema.
As a result, Creatio will retrieve the sender data and create contact using this data.
7. Implement downloading of attachments
-
Create the source code schema. Instructions: Implement the source code.
-
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 theOmnichannelMessageFile
database table.SomeProviderAttachmentLoadWorkernamespace 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
} -
Publish the schema.
As a result, users will be able to download attachments.
8. Implement sending of messages
-
Create the source code schema. Instructions: Implement the source code.
-
Implement the business logic that sends messages using the
IOutcomeMessageWorker
interface.- Convert the message to messenger format and send it using the messenger API.
- Send the message using a token. Store the token in the
SomeChannelProviderNameMsgSettings
database table. UserConnection
sent in the constructor provides access to the database table.- Send a message to the channel provider API, for example,
https://somechannelprovider.api/
, using theHttpRequestSender
class.
SomeProviderOutcomeMessageWorkernamespace 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
} -
Publish the schema.
As a result, users will be able to send messages.
9. Link the interfaces
-
Create the source code schema. Instructions: Implement the source code.
-
Implement the business logic that links interfaces.
- Specify the
AppEventListenerBase
class as a parent class. - Link the created classes using the
SomeProvider
provider ID that is specified in theChannelName
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.
SomeProviderAppEventListenernamespace 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
} - Specify the
-
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)