Добавление пользовательского элемента кампании
Glossary Item Box
Общие сведения
Для настройки маркетинговой кампании используется [Дизайнер кампании]. С его помощью можно создать визуальную схему кампании, состоящую из связанных предустановленных элементов. Также существует возможность создания пользовательских элементов кампании.
Общая последовательность добавления пользовательского элемента кампании:
1. Создать новый элемент для [Дизайнера кампании].
2. Создать страницу редактирования элемента.
3. Расширить меню [Дизайнера кампании] новым элементом.
4. Создать серверную часть элемента.
5. Создать исполняемый элемент для нового элемента кампании.
6. Добавить пользовательскую логику для обработки событий кампании.
Описание примера
Создать новый элемент маркетинговой кампании для отправки СМС сообщений пользователем.
Алгоритм выполнения примера
1. Создание нового элемента для [Дизайнера кампании]
Для отображения элемента в пользовательском интерфейсе [Дизайнера кампании] необходимо в пользовательском пакете создать новую схему модуля элемента кампании. Как создать схему модуля подробно описывается в статье "Создание клиентской схемы". Для созданной схемы нужно установить следующие свойства:
- [Заголовок] ([Title]) — "Test SMS Element Schema".
- [Название] ([Name]) — "TestSmsElementSchema".
В этом примере в названиях схем отсутствует префикс Usr. Префикс, используемый по умолчанию, можно изменить в системной настройке [Префикс названия объекта] (код SchemaNamePrefix).
В схему необходимо добавить локализуемую строку (рис. 1) со следующими свойствами:
- [Название] ([Name]) — "Caption".
- [Значение] ([Value]) — "Test SMS".
Рис. 1. — Добавление локализуемой строки
Также в схему необходимо добавить изображения, которые будут отображать элемент кампании в разных режимах в [Дизайнере кампании]. Изображения необходимо загрузить в схему, используя свойства SmallImage, LargeImage и TitleImage (рис. 2).
Рис. 2. — Добавление изображения элемента кампании
В этом примере используется векторное изображение в формате SVG (Scalable Vector Graphics), доступное по ссылке.
В секцию [Исходный код] ([Source code]) схемы необходимо добавить следующий исходный код:
define("TestSmsElementSchema", ["TestSmsElementSchemaResources", "CampaignBaseCommunicationSchema"], function(resources) { Ext.define("Terrasoft.manager.TestSmsElementSchema", { // Родительская схема. extend: "Terrasoft.CampaignBaseCommunicationSchema", alternateClassName: "Terrasoft.TestSmsElementSchema", // Идентификатор менеджера. Должен быть уникальным. managerItemUId: "a1226f93-f3e3-4baa-89a6-11f2a9ab2d71", // Подключаемые миксины. mixins: { campaignElementMixin: "Terrasoft.CampaignElementMixin" }, // Название элемента. name: "TestSms", // Привязка ресурсов. caption: resources.localizableStrings.Caption, titleImage: resources.localizableImages.TitleImage, largeImage: resources.localizableImages.LargeImage, smallImage: resources.localizableImages.SmallImage, // Имя схемы карточки редактирования. editPageSchemaName: "TestSmsElementPropertiesPage", // Тип элемента. elementType: "TestSms", // Полное имя класса, соответствующего данной схеме. typeName: "Terrasoft.Configuration.TestSmsElement, Terrasoft.Configuration", // Переопределение свойств стилей для отображения. color: "rgba(249, 160, 27, 1)", width: 69, height: 55, // Настройка специфических свойств элемента. smsText: null, phoneNumber: null, // Определение типов связей, исходящих из элемента. getConnectionUserHandles: function() { return ["CampaignSequenceFlow", "CampaignConditionalSequenceFlow"]; }, // Расширение свойств для сериализации. getSerializableProperties: function() { var baseSerializableProperties = this.callParent(arguments); return Ext.Array.push(baseSerializableProperties, ["smsText", "phoneNumber"]); }, // Настройка отображения иконок на диаграмме кампании. getSmallImage: function() { return this.mixins.campaignElementMixin.getImage(this.smallImage); }, getLargeImage: function() { return this.mixins.campaignElementMixin.getImage(this.largeImage); }, getTitleImage: function() { return this.mixins.campaignElementMixin.getImage(this.titleImage); } }); return Terrasoft.TestSmsElementSchema; });
Особенности:
- Значение свойства managerItemUId должно быть уникальным и не должно повторять значение этого свойства у существующих элементов.
- Свойство typeName содержит имя C#-класса, соответствующее элементу кампании. Этот класс будет выполнять сохранение и чтение свойств элемента из метаданных схемы.
После внесения изменений схему необходимо сохранить.
Создание группы элементов
Если для элемента кампании нужно создать новую группу элементов, например, [Скрипты] ([Scripts]), то исходный код схемы необходимо дополнить следующим кодом:
// Название новой группы. group: "Scripts", constructor: function() { if (!Terrasoft.CampaignElementGroups.Items.contains("Scripts")) { Terrasoft.CampaignElementGroups.Items.add("Scripts", { name: "Scripts", caption: resources.localizableStrings.ScriptsElementGroupCaption }); } this.callParent(arguments); }
Также в схему нужно добавить локализуемую строку со следующими свойствами:
- [Название] ([Name]) — "ScriptsElementGroupCaption".
- [Значение] ([Value]) — "Scripts".
После внесения изменений схему необходимо сохранить.
2. Создание страницы редактирования элемента
Для отображения и изменения свойств элемента кампании необходимо в пользовательском пакете создать его страницу редактирования. Для этого нужно создать схему, расширяющую BaseCampaignSchemaElementPage (пакет CampaignDesigner). Как создать замещающую схему подробно описано в статье "Создание клиентской схемы".
Для созданной схемы требуется установить следующие свойства:
- [Заголовок] ([Title]) — "TestSmsElementPropertiesPage".
- [Название] ([Name]) — "TestSmsElementPropertiesPage".
- [Родительский объект] ([Parent object]) — "BaseCampaignSchemaElementPage".
В созданную схему необходимо добавить локализуемые строки, основные свойства которых приведены в таблице 1.
Табл. 1. — Основные свойства локализуемых строк
[Название] ([Name]) | [Значение] ([Value]) |
---|---|
PhoneNumberCaption | Телефонный номер отправителя (Sender phone number) |
SmsTextCaption | Текст сообщения (Message) |
TestSmsText | Какое СМС-сообщение отправить? (Which SMS text to send?) |
В секцию [Исходный код] ([Source code]) схемы необходимо добавить следующий исходный код:
define("TestSmsElementPropertiesPage", [], function() { return { attributes: { // Атрибуты, соответствующие специфическим свойствам схемы элемента. "PhoneNumber": { "dataValueType": this.Terrasoft.DataValueType.TEXT, "type": this.Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN }, "SmsText": { "dataValueType": this.Terrasoft.DataValueType.TEXT, "type": this.Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN } }, methods: { init: function() { this.callParent(arguments); this.initAcademyUrl(this.onAcademyUrlInitialized, this); }, // Код элемента для генерации ссылки на контекстную справку. getContextHelpCode: function() { return "CampaignTestSmsElement"; }, // Инициализация атрибутов текущими значениями свойств схемы. initParameters: function(element) { this.callParent(arguments); this.set("SmsText", element.smsText); this.set("PhoneNumber", element.phoneNumber); }, // Сохранение свойств схемы. saveValues: function() { this.callParent(arguments); var element = this.get("ProcessElement"); element.smsText = this.getSmsText(); element.phoneNumber = this.getPhoneNumber(); }, // Вычитка текущих значений из атрибутов. getPhoneNumber: function() { var number = this.get("PhoneNumber"); return number ? number : ""; }, getSmsText: function() { var smsText = this.get("SmsText"); return smsText ? smsText : ""; } }, diff: [ // Контейнер для UI { "operation": "insert", "name": "ContentContainer", "propertyName": "items", "parentName": "EditorsContainer", "className": "Terrasoft.GridLayoutEdit", "values": { "itemType": Terrasoft.ViewItemType.GRID_LAYOUT, "items": [] } }, // Главная подпись элемента. { "operation": "insert", "name": "TestSmsLabel", "parentName": "ContentContainer", "propertyName": "items", "values": { "layout": { "column": 0, "row": 0, "colSpan": 24 }, "itemType": this.Terrasoft.ViewItemType.LABEL, "caption": { "bindTo": "Resources.Strings.TestSmsText" }, "classes": { "labelClass": ["t-title-label-proc"] } } }, // Подпись для текстового поля ввода номера отправителя. { "operation": "insert", "name": "PhoneNumberLabel", "parentName": "ContentContainer", "propertyName": "items", "values": { "layout": { "column": 0, "row": 1, "colSpan": 24 }, "itemType": this.Terrasoft.ViewItemType.LABEL, "caption": { "bindTo": "Resources.Strings.PhoneNumberCaption" }, "classes": { "labelClass": ["label-small"] } } }, // Текстовое поле для ввода телефонного номера. { "operation": "insert", "name": "PhoneNumber", "parentName": "ContentContainer", "propertyName": "items", "values": { "labelConfig": { "visible": false }, "layout": { "column": 0, "row": 2, "colSpan": 24 }, "itemType": this.Terrasoft.ViewItemType.TEXT, "classes": { "labelClass": ["feature-item-label"] }, "controlConfig": { "tag": "PhoneNumber" } } }, // Подпись для текстового поля ввода текста сообщения. { "operation": "insert", "name": "SmsTextLabel", "parentName": "ContentContainer", "propertyName": "items", "values": { "layout": { "column": 0, "row": 3, "colSpan": 24 }, "classes": { "labelClass": ["label-small"] }, "itemType": this.Terrasoft.ViewItemType.LABEL, "caption": { "bindTo": "Resources.Strings.SmsTextCaption" } } }, // Текстовое поле для ввода текста сообщения. { "operation": "insert", "name": "SmsText", "parentName": "ContentContainer", "propertyName": "items", "values": { "labelConfig": { "visible": false }, "layout": { "column": 0, "row": 4, "colSpan": 24 }, "itemType": this.Terrasoft.ViewItemType.TEXT, "classes": { "labelClass": ["feature-item-label"] }, "controlConfig": { "tag": "SmsText" } } } ] }; } );
После внесения изменений схему необходимо сохранить.
3. Расширение меню [Дизайнера кампании] новым элементом
Чтобы созданный элемент отображался в меню дизайнера кампаний, необходимо расширить базовый менеджер схем элементов кампаний. Для этого нужно в пользовательский пакет добавить схему, расширяющую CampaignElementSchemaManagerEx (пакет CampaignDesigner). Как создать замещающую схему подробно описано в статье "Создание клиентской схемы".
Для созданной схемы следует установить следующие свойства:
- [Заголовок] ([Title]) — "TestSmsCampaignElementSchemaManagerEx".
- [Название] ([Name]) — "CampaignElementSchemaManagerEx".
- [Родительский объект] ([Parent object]) — "CampaignElementSchemaManagerEx".
В секцию [Исходный код] ([Source code]) схемы необходимо добавить следующий исходный код:
require(["CampaignElementSchemaManager", "TestSmsElementSchema"], function() { // Добавление новой схемы в список доступных схем элементов в дизайнере кампании. var coreElementClassNames = Terrasoft.CampaignElementSchemaManager.coreElementClassNames; coreElementClassNames.push({ itemType: "Terrasoft.TestSmsElementSchema" }); });
После внесения изменений схему необходимо сохранить.
4. Создание серверной части элемента кампании
Чтобы реализовать возможность сохранения базовых и пользовательских свойств элемента кампании, для него необходимо создать класс, взаимодействующий с серверной частью приложения. Класс должен быть наследником CampaignSchemaElement и переопределять методы ApplyMetaDataValue() и WriteMetaData().
Для этого нужно создать схему исходного кода со следующими свойствами:
- [Заголовок] ([Title]) — "TestSmsElement".
- [Название] ([Name]) — "TestSmsElement".
Как создать схему исходного кода подробно описано в статье "Создание схемы [Исходный код]".
В секцию [Исходный код] ([Source code]) схемы необходимо добавить следующий исходный код:
namespace Terrasoft.Configuration { using System; using Terrasoft.Common; using Terrasoft.Core; using Terrasoft.Core.Campaign; using Terrasoft.Core.Process; [DesignModeProperty(Name = "PhoneNumber", UsageType = DesignModeUsageType.NotVisible, MetaPropertyName = PhoneNumberPropertyName)] [DesignModeProperty(Name = "SmsText", UsageType = DesignModeUsageType.NotVisible, MetaPropertyName = SmsTextPropertyName)] public class TestSmsElement : CampaignSchemaElement { private const string PhoneNumberPropertyName = "PhoneNumber"; private const string SmsTextPropertyName = "SmsText"; // Конструктор по умолчанию. public TestSmsElement() { ElementType = CampaignSchemaElementType.AsyncTask; } // Конструктор с параметром. public TestSmsElement(TestSmsElement source) : base(source) { ElementType = CampaignSchemaElementType.AsyncTask; PhoneNumber = source.PhoneNumber; SmsText = source.SmsText; } // Идентификатор действия элемента. protected override Guid Action { get { return CampaignConsts.CampaignLogTypeMailing; } } // Номер телефона. [MetaTypeProperty("{A67950E7-FFD7-483D-9E67-3C9A30A733C0}")] public string PhoneNumber { get; set; } // Текстовое сообщение. [MetaTypeProperty("{05F86DF2-B9FB-4487-B7BE-F3955703527C}")] public string SmsText { get; set; } // Применяет значения метаданных. protected override void ApplyMetaDataValue(DataReader reader) { base.ApplyMetaDataValue(reader); switch (reader.CurrentName) { case PhoneNumberPropertyName: PhoneNumber = reader.GetValue<string>(); break; case SmsTextPropertyName: SmsText = reader.GetValue<string>(); break; } } // Записывает значения метаданных. public override void WriteMetaData(DataWriter writer) { base.WriteMetaData(writer); writer.WriteValue(PhoneNumberPropertyName, PhoneNumber, string.Empty); writer.WriteValue(SmsTextPropertyName, SmsText, string.Empty); } // Копирует элемент. public override object Clone() { return new TestSmsElement(this); } // Создает специфический экземпляр ProcessFlowElement. public override ProcessFlowElement CreateProcessFlowElement(UserConnection userConnection) { var executableElement = new TestSmsCampaignProcessElement { UserConnection = userConnection, SmsText = SmsText, PhoneNumber = PhoneNumber }; InitializeCampaignProcessFlowElement(executableElement); return executableElement; } } }
После внесения изменений схему исходного кода необходимо опубликовать.
5. Создание исполняемого элемента для нового элемента кампании
Чтобы механизм выполнения кампании мог в нужный момент выполнить требуемую логику поведения создаваемого элемента, необходимо создать исполняемый элемент. Это класс, наследник класса CampaignProcessFlowElement, в котором ключевой является реализация метода SafeExecute().
Для создания исполняемого элемента необходимо в пользовательском пакете создать схему исходного кода со следующими свойствами:
- [Заголовок] ([Title]) — "TestSmsCampaignProcessElement".
- [Название] ([Name]) — "TestSmsCampaignProcessElement".
В секцию [Исходный код] ([Source code]) схемы необходимо добавить следующий исходный код:
namespace Terrasoft.Configuration { using System; using System.Collections.Generic; using Terrasoft.Core.Campaign; using Terrasoft.Core.DB; using Terrasoft.Core.Process; public class TestSmsCampaignProcessElement : CampaignProcessFlowElement { public TestSmsCampaignProcessElement() { } // Свойства, специфические для СМС. Передаются от экземпляра класса TestSmsElement. public string PhoneNumber { get; set; } public string SmsText { get; set; } // Определяет аудиторию, которая должна быть обработана элементом. // Если не переопределить этот метод, то по умолчанию базовый класс берет всю аудиторию // из текущего шага с признаком "Шаг не выполнен" и статусом "Участвует в кампании". protected override Query GetAudienceQuery() => new Select(UserConnection) .Column("Id") .From(CampaignParticipantTable) .Where("CampaignItemId").IsEqual(Column.Parameter(CampaignItemId)) .And("StatusId").IsEqual(CampaignConstants.CampaignParticipantParticipatingStatusId) .And("StepCompleted").IsEqual(Column.Parameter(0)); // Реализация метода выполнения элемента. // Если не переопределить этот метод, то по умолчанию базовый класс возьмет запрос // audienceQuery и для всех кто подпадает под эту выборку проставит "Шаг выполнен" // без какой-либо дополнительной логики. protected override int SingleExecute(Query audienceQuery) { // TODO: Реализовать работу отправки СМС-сообщений. // // Текущий шаг для аудитории устанавливается как выполненный. return SetItemCompleted(audienceQuery as Select); } } }
После внесения изменений схему исходного кода необходимо опубликовать.
6. Добавление пользовательской логики для обработки событий кампании
Для реализации пользовательской логики при сохранении, копировании, удалении, запуске и остановке кампании предусмотрен механизм событийных обработчиков. Для его использования достаточно создать публичный запечатанный (sealed) класс-обработчик, унаследованный от CampaignEventHandlerBase. В нем нужно реализовать один или несколько интерфейсов, описывающих сигнатуры обработчиков конкретных событий. Этот класс не должен быть обобщенным и должен иметь доступный конструктор по-умолчанию.
В текущей версии поддерживаются следующие интерфейсы:
- IOnCampaignBeforeSave — содержит метод, который будет вызван перед сохранением кампании.
- IOnCampaignAfterSave — содержит метод, который будет вызван после сохранения кампании.
- IOnCampaignDelete — содержит метод, который будет вызван перед удалением кампании.
- IOnCampaignStart — содержит метод, который будет вызван перед стартом кампании.
- IOnCampaignStop — содержит метод, который будет вызван перед остановкой кампании.
- IOnCampaignValidate — содержит метод, который будет вызван при валидации кампании.
- IOnCampaignCopy — содержит метод, который будет вызван после копирования кампании.
При появлении исключительной ситуации во время обработки события, цепочка вызовов останавливается, а состояние кампании в базе данных откатывается на предыдущее.
При реализации интерфейса IOnCampaignValidate рекомендуется сохранять ошибки в схему кампании, пользуясь методом AddValidationInfo(string).
Уточнение условий кейса
Для работы созданного элемента кампании для СМС рассылки необходимо работающее соединение с СМС-шлюзом. Предполагается, что проверку соединения, состояния счета и других параметров необходимо осуществлять при валидации кампании, а отправку тестового СМС сообщения — при ее старте.
Для реализации новых условий необходимо в пользовательский пакет добавить схему исходного кода со следующими свойствами:
- [Заголовок] ([Title]) — "TestSmsEventHandler".
- [Название] ([Name]) — "TestSmsEventHandler".
В секцию [Исходный код] ([Source code]) схемы необходимо добавить следующий исходный код:
namespace Terrasoft.Configuration { using System; using Terrasoft.Core.Campaign.EventHandler; public sealed class TestSmsEventHandler : CampaignEventHandlerBase, IOnCampaignValidate, IOnCampaignStart { // Реализация обработчика события старта кампании. public void OnStart() { // TODO: Логика отправки тестовой СМС... // } // Реализация обработчика события валидации кампании. public void OnValidate() { try { // TODO: Логика валидации соединения с СМС-шлюзом... // } catch (Exception ex) { // При наличии ошибки, добавляем ее в схему кампании. CampaignSchema.AddValidationInfo(ex.Message); } } } }
После внесения изменений необходимо опубликовать схему. Затем нужно выполнить полную компиляцию приложения и очистить кэш.
В результате выполнения кейса, в меню элементов кампании будет добавлен новый элемент [TestSMS] (рис. 3, 1), который можно добавить на диаграмму кампании (рис. 3, 2). При выборе добавленного элемента будет отображена страница редактирования свойств этого элемента (рис. 3, 3).
Рис. 3. — Элементы кампании
При сохранении кампании возможно возникновение ошибки “Parameter ‘type’ cannot be null”. Она связана с тем, что после компиляции не была обновлена библиотека конфигурации и созданные типы в нее не попали.
Для устранения ошибки необходимо перекомпилировать проект и очистить все возможные хранилища с закэшированными данными. Возможно, нужно будет очистить пул приложения или перезапустить сайт в IIS.
Смотрите также