Skip to main content
Version: 8.2

Implement a custom flow for a campaign element

Level: advanced
note

The functionality is relevant to Classic UI.

To implement the example:

  1. Create a custom campaign element. Read more >>>
  2. Create a flow schema for a campaign element. Read more >>>
  3. Create a flow property panel for a campaign element. Read more >>>
  4. Create an executable element for the campaign element flow. Read more >>>
  5. Implement the business logic of the flow for the campaign element. Read more >>>
  6. Implement the flow logic when the source is changed. Read more >>>
  7. Connect the flow logic. Read more >>>
Example

Create a custom flow for the custom Test SMS campaign element.

Implement the following flow options:

  • Omit the responces to the bulk SMS.

  • Take into account SMS responses. In this case, specify the responses to be taken into account.

  • Take into account SMS responses, regardless of their value.

1. Create a custom campaign element

For this example, create a custom Test SMS campaign element. Instructions: Implement a custom campaign element.

2. Create a flow schema for a campaign element

Create the SMS sending status lookup

  1. Create a package to implement the example. Instructions: Create a user-made package.

    For this example, create the sdkCreateArrowCampaignPackage package.

  2. Create the object schema to implement the SMS sending status lookup. Instructions: Implement an object.

    For this example, create the UsrSmsSendingStatus object schema. Use the schema properties as follows.

    Property

    Property value

    Code

    UsrSmsSendingStatus

    Title

    SMS sending status

    Parent object

    BaseLookup

  3. Publish the schema.

  4. Register the SMS sending status lookup. Instructions: Adding a lookup based on an existing object (user documentation).

  5. Add the lookup values. Instructions: Manage lookup values.

    For this example, add the following lookup values:

    • Delivered
    • Canceled
    • Error while receiving

Create SMS recipient object.

  1. Create an object schema. Instructions: Implement an object.

    For this example, create the UsrSmsRecipient object schema. Use the schema properties as follows.

    Property

    Property value

    Code

    UsrSmsRecipient

    Title

    SMS recipient

    Parent object

    BaseEntity

  2. Add new columns to the object schema.

    1. Click add_buttonTextText (50 characters) in the context menu of the object structure's Columns node.

    2. The column properties are as follows.

      Property

      Property value

      Code

      UsrPhoneNumber

      Title

      Phone number

    3. Repeat step 1-2 for the next three columns.

      Column

      Property

      Property value

      SMS text

      Data type

      Text (50 characters)

      Code

      UsrSmsText

      Title

      SMS text

      SMS receiver

      Data type

      Lookup

      Code

      UsrContactLookup

      Title

      Contact

      Lookup

      Contact

      SMS sending status

      Data type

      Lookup

      Code

      UsrSmsSendingStatusLookup

      Title

      SMS sending status

      Lookup

      UsrSmsSendingStatus

  3. Publish the schema.

Create SMS responses object.

  1. Create an object schema. Instructions: Implement an object.

    For this example, create the UsrSmsResponses object schema. Use the schema properties as follows.

    Property

    Property value

    Code

    UsrSmsResponses

    Title

    SMS responses

    Parent object

    BaseEntity

  2. Add new column to the object schema.

    1. Click add_buttonTextText (50 characters) in the context menu of the object structure's Columns node.

    2. Fill out the column properties.

      Property

      Property value

      Code

      UsrResponse

      Title

      Response

  3. Publish the schema.

Create a flow for a campaign element.

  1. Create a client module schema. Instructions: Implement a non-visual module.

    For this example, use the client module properties as follows.

    Property

    Property value

    Code

    UsrProcessTestSmsConditionalTransitionSchema

    Title

    Element conditional transition schema

  2. Add source code that implements the flow conditions.

    UsrProcessTestSmsConditionalTransitionSchema
    define("UsrProcessTestSmsConditionalTransitionSchema", ["CampaignEnums", "UsrProcessTestSmsConditionalTransitionSchemaResources", "ProcessCampaignConditionalSequenceFlowSchema"], function(CampaignEnums) {
    Ext.define("Terrasoft.manager.UsrProcessTestSmsConditionalTransitionSchema", {
    extend: "Terrasoft.ProcessCampaignConditionalSequenceFlowSchema",
    alternateClassName: "Terrasoft.UsrProcessTestSmsConditionalTransitionSchema",
    managerItemUId: "4b5e70b0-a631-458e-ab22-856ddc913444",
    mixins: {
    parametrizedProcessSchemaElement: "Terrasoft.ParametrizedProcessSchemaElement"
    },
    /* Full name of the class that corresponds to the current schema.
    If you use the class in a simple package, specify typeName as follows */
    typeName: "Terrasoft.Configuration.UsrTestSmsConditionalTransitionElement, Terrasoft.Configuration",
    /* If you use the class in an assembly package, specify typeName as follows:
    typeName: "Terrasoft.Configuration.UsrTestSmsConditionalTransitionElement, SomeAssemblyPackageName" */
    /* Arrow element name for linking to campaign elements. */
    connectionUserHandleName: "TestSmsConditionalTransition",
    /* Arrow property bar name. */
    editPageSchemaName: "UsrTestSmsConditionalTransitionPropertiesPage",
    elementType: CampaignEnums.CampaignSchemaElementTypes.CONDITIONAL_TRANSITION,
    /* Collection of responses by SMS mailing. */
    testSmsResponseId: null,
    /* An attribute that takes into account the response condition when translating contacts. */
    isResponseBasedStart: false,
    getSerializableProperties: function() {
    var baseSerializableProperties = this.callParent(arguments);
    /* Properties to serialize and pass to back-end part when saving. */
    Ext.Array.push(baseSerializableProperties, ["testSmsResponseId", "isResponseBasedStart"]);
    return baseSerializableProperties;
    }
    });
    return Terrasoft.UsrProcessTestSmsConditionalTransitionSchema;
    });

Where:

  • managerItemUId is the unique value for the new element.

  • typeName is the name of the C# class that corresponds to the campaign element name. The class saves and reads the element properties from the schema properties.

    note

    If you use the class in a simple package, specify typeName as follows: "Terrasoft.Configuration.UsrTestSmsConditionalTransitionElement, Terrasoft.Configuration". If you use the class in an assembly package, specify typeName as follows: "Terrasoft.Configuration.UsrTestSmsConditionalTransitionElement, SomeAssemblyPackageName".

  1. Save the schema.

3. Create a flow property panel for a campaign element

  1. Create a page view model schema. Instructions: View model schema.

    For this example, use page view model properties as follows.

    Property

    Property value

    Code

    UsrTestSmsConditionalTransitionPropertiesPage

    Title

    Properties panel of the transition Test SMS element

    Parent object

    CampaignConditionalSequenceFlowPropertiesPage

  2. Add the localizable strings that include the field names. Instructions: Add a localizable string.

    Code

    Value

    ReactionModeCaption

    What is the result of the 0 step?

    ReactionModeDefault

    Transfer participants regardless of their response

    ReactionModeWithCondition

    Set up responses for transferring participants

    IsTestSmsDelivered

    Test SMS delivered

    IsErrorWhileReceiving

    Error while receiving

  3. Set up the properties panel of the flow.

    Schema property

    Code

    Description

    attributes

    ReactionModeEnum

    List of participants

    ReactionMode

    Participants' responses

    IsTestSmsDelivered

    SMS delivery status

    IsErrorWhileReceiving

    Receives an error during SMS delivery

    rules

    ReactionConditionDecision

    Handles the value of the ReactionMode attribute

    methods

    getResponseConfig()

    Generates the correspondence of the bulk SMS responses to the SMS sending status lookup. It is assumed that the lookup contains Delivered and Error while receiving values. These status IDs are used in the property panel code of the conditional flow from bulk SMS. The unique ID is contained in the corresponding column of the SMS sending status lookup row.

    subscribeEvents()

    Binds the handler to the event that changes the ReactionMode attribute value

    onReactionModeLookupChanged()

    Handles the ReactionMode attribute change event

    initParameters()

    Initializes the ViewModel properties to display the page when opened

    cutString()

    Cuts the string to the specified length and adds an ellipsis triplet at the end. Auxiliary method

    initIsTestSmsDelivered()

    Sets the Delivered status

    initIsErrorWhileReceiving()

    Sets the Error while receiving status

    initTestSmsResponses()

    Initiates the selected responses when the page is opened

    getIds()

    Retrieves an ID array from an incoming JSON parameter. Auxiliary method

    saveValues()

    Saves the response values and the setting whether to add response conditions or not

    getTestSmsResponseId()

    Gets serialized ID of selected responses

    getQuestionCaption()

    Substitutes the name of the item the arrow comes from

    diff

    ContentContainer

    Page container

    ReactionModeLabel

    Title

    ReactionMode

    List

    IsTestSmsDelivered

    List element

    IsErrorWhileReceiving

    List element

    UsrTestSmsConditionalTransitionPropertiesPage
    define("UsrTestSmsConditionalTransitionPropertiesPage", ["BusinessRuleModule"], function(BusinessRuleModule) {
    return {
    messages: {},
    attributes: {
    "ReactionModeEnum": {
    dataValueType: this.Terrasoft.DataValueType.CUSTOM_OBJECT,
    type: this.Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN,
    value: {
    Default: {
    value: "0",
    captionName: "Resources.Strings.ReactionModeDefault"
    },
    WithCondition: {
    value: "1",
    captionName: "Resources.Strings.ReactionModeWithCondition"
    }
    }
    },
    "ReactionMode": {
    "dataValueType": this.Terrasoft.DataValueType.LOOKUP,
    "type": this.Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN,
    "isRequired": true
    },
    "IsTestSmsDelivered": {
    "dataValueType": this.Terrasoft.DataValueType.BOOLEAN,
    "type": this.Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN
    },
    "IsErrorWhileReceiving": {
    "dataValueType": this.Terrasoft.DataValueType.BOOLEAN,
    "type": this.Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN
    }
    },

    rules:
    {
    "ReactionConditionDecision": {
    "BindReactionConditionDecisionRequiredToReactionMode": {
    "ruleType": BusinessRuleModule.enums.RuleType.BINDPARAMETER,
    "property": BusinessRuleModule.enums.Property.REQUIRED,
    "conditions": [{
    "leftExpression": {
    "type": BusinessRuleModule.enums.ValueType.ATTRIBUTE,
    "attribute": "ReactionMode"
    },
    "comparisonType": this.Terrasoft.ComparisonType.EQUAL,
    "rightExpression": {
    "type": BusinessRuleModule.enums.ValueType.CONSTANT,
    "value": "1"
    }
    }]
    }
    }
    },
    methods: {
    /* Ensures sms-response correspondence (based on the TestSmsResponseType lookup).
    We assume that Creatio already contains the TestSmsResponseType lookup
    with the TestSmsDelivered and ErrorWhileReceiving records. */
    getResponseConfig: function() {
    return {
    "IsTestSmsDelivered": "F2FC75B3-58C3-49A6-B2F2-353262068145",
    "IsErrorWhileReceiving": "37B9F9D5-E897-4B7B-A65E-3B3799A18D72"
    };
    },

    subscribeEvents: function() {
    this.callParent(arguments);
    /* Connecting the handler to the event of changing the ReactionMode attribute value. */
    this.on("change:ReactionMode", this.onReactionModeLookupChanged, this);
    },

    /* Event handler-method of changing the ReactionMode attribute.*/
    onReactionModeLookupChanged: function() {
    var reactionModeEnum = this.get("ReactionModeEnum");
    var reactionMode = this.get("ReactionMode");
    var decisionModeEnabled = (reactionMode && reactionMode.value === reactionModeEnum.WithCondition.value);
    if (!decisionModeEnabled) {
    this.set("ReactionConditionDecision", null);
    }
    },

    /* Initiates the viewModel properties to display the page when opening.*/
    initParameters: function(element) {
    this.callParent(arguments);
    var isResponseBasedStart = element.isResponseBasedStart;
    this.initReactionMode(isResponseBasedStart);
    this.initTestSmsResponses(element.testSmsResponseId);
    },

    /* Auxiliary method cutting the line to the specified length and adding ellipsis at the end.*/
    cutString: function(strValue, strLength) {
    var ellipsis = Ext.String.ellipsis(strValue.substring(strLength), 0);
    return strValue.substring(0, strLength) + ellipsis;
    },

    /* Sets the status value to "Sms delivered".*/
    initIsTestSmsDelivered: function(value) {
    if (value === undefined) {
    value = this.get("IsTestSmsDelivered");
    }
    this.set("IsTestSmsDelivered", value);
    },

    /* Sets the status value to "Error while receiving".*/
    initIsErrorWhileReceiving: function(value) {
    if (value === undefined) {
    var isErrorWhileReceiving = this.get("IsErrorWhileReceiving");
    value = isErrorWhileReceiving;
    }
    this.set("IsErrorWhileReceiving", value);
    },

    /* Initiates the selected responses when opening the page.*/
    initTestSmsResponses: function(responseIdsJson) {
    if (!responseIdsJson) {
    return;
    }
    var responseIds = JSON.parse(responseIdsJson);
    var config = this.getResponseConfig();
    Terrasoft.each(config, function(propValue, propName) {
    if (responseIds.indexOf(propValue) > -1) {
    this.set(propName, true);
    }
    }, this);
    },

    initReactionMode: function(value) {
    var isDefault = !value;
    this.setLookupValue(isDefault, "ReactionMode", "WithCondition", this);
    },

    /* Auxiliary method extracting the identifier array from the incoming JSON parameter.*/
    getIds: function(idsJson) {
    if (idsJson) {
    try {
    var ids = JSON.parse(idsJson);
    if (this.Ext.isArray(ids)) {
    return ids;
    }
    } catch (error) {
    return [];
    }
    }
    return [];
    },

    onPrepareReactionModeList: function(filter, list) {
    this.prepareList("ReactionModeEnum", list, this);
    },

    /* Saves the response values and the setting of adding the response condition. */
    saveValues: function() {
    this.callParent(arguments);
    var element = this.get("ProcessElement");
    var isResponseBasedStart = this.getIsReactionModeWithConditions();
    element.isResponseBasedStart = isResponseBasedStart;
    element.testSmsResponseId = this.getTestSmsResponseId(isResponseBasedStart);
    },

    /* Receives the serialized Ids of the selected responses.*/
    getTestSmsResponseId: function(isResponseActive) {
    var responseIds = [];
    if (isResponseActive) {
    var config = this.getResponseConfig();
    Terrasoft.each(config, function(propValue, propName) {
    var attrValue = this.get(propName);
    if (attrValue && propValue) {
    responseIds.push(propValue);
    }
    }, this);
    }
    return JSON.stringify(responseIds);
    },

    getLookupValue: function(parameterName) {
    var value = this.get(parameterName);
    return value ? value.value : null;
    },

    getContextHelpCode: function() {
    return "CampaignConditionalSequenceFlow";
    },

    getIsReactionModeWithConditions: function() {
    return this.isLookupValueEqual("ReactionMode", "1", this);
    },

    getSourceElement: function() {
    var flowElement = this.get("ProcessElement");
    if (flowElement) {
    return flowElement.findSourceElement();
    }
    return null;
    },
    /* Adds the name of the element that the arrow is generated from to the text.*/
    getQuestionCaption: function() {
    var caption = this.get("Resources.Strings.ReactionModeCaption");
    caption = this.Ext.String.format(caption, this.getSourceElement().getCaption());
    return caption;
    }
    },
    diff: /**SCHEMA_DIFF*/[
    /* Container.*/
    {
    "operation": "insert",
    "name": "ReactionContainer",
    "propertyName": "items",
    "parentName": "ContentContainer",
    "className": "Terrasoft.GridLayoutEdit",
    "values":
    {
    "layout":
    {
    "column": 0,
    "row": 2,
    "colSpan": 24
    },
    "itemType": this.Terrasoft.ViewItemType.GRID_LAYOUT,
    "items": []
    }
    },
    /* Title.*/
    {
    "operation": "insert",
    "name": "ReactionModeLabel",
    "parentName": "ReactionContainer",
    "propertyName": "items",
    "values":
    {
    "layout":
    {
    "column": 0,
    "row": 0,
    "colSpan": 24
    },
    "itemType": this.Terrasoft.ViewItemType.LABEL,
    "caption":
    {
    "bindTo": "getQuestionCaption"
    },
    "classes":
    {
    "labelClass": ["t-title-label-proc"]
    }
    }
    },
    /* List.*/
    {
    "operation": "insert",
    "name": "ReactionMode",
    "parentName": "ReactionContainer",
    "propertyName": "items",
    "values":
    {
    "contentType": this.Terrasoft.ContentType.ENUM,
    "controlConfig":
    {
    "prepareList":
    {
    "bindTo": "onPrepareReactionModeList"
    }
    },
    "isRequired": true,
    "layout":
    {
    "column": 0,
    "row": 1,
    "colSpan": 24
    },
    "labelConfig":
    {
    "visible": false
    },
    "wrapClass": ["no-caption-control"]
    }
    },
    /* List element.*/
    {
    "operation": "insert",
    "parentName": "ReactionContainer",
    "propertyName": "items",
    "name": "IsTestSmsDelivered",
    "values":
    {
    "wrapClass": ["t-checkbox-control"],
    "visible":
    {
    "bindTo": "ReactionMode",
    "bindConfig":
    {
    converter: "getIsReactionModeWithConditions"
    }
    },
    "caption":
    {
    "bindTo": "Resources.Strings.IsTestSmsDelivered"
    },
    "layout":
    {
    "column": 0,
    "row": 2,
    "colSpan": 22
    }
    }
    },
    /* List element.*/
    {
    "operation": "insert",
    "parentName": "ReactionContainer",
    "propertyName": "items",
    "name": "IsErrorWhileReceiving",
    "values":
    {
    "wrapClass": ["t-checkbox-control"],
    "visible":
    {
    "bindTo": "ReactionMode",
    "bindConfig":
    {
    converter: "getIsReactionModeWithConditions"
    }
    },
    "caption":
    {
    "bindTo": "Resources.Strings.IsErrorWhileReceiving"
    },
    "layout":
    {
    "column": 0,
    "row": 3,
    "colSpan": 22
    }
    }
    }
    ]/**SCHEMA_DIFF*/
    };
    });
  4. Save the schema.

4. Create an executable element for the campaign element flow

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

    For this example, use source code schema properties as follows.

    Property

    Property value

    Code

    UsrTestSmsConditionalTransitionFlowElement

    Title

    Conditional transition of the Test SMS process element

  2. Implement an executable element that collects responses of the bulk SMS.

    To do this, specify the ConditionalTransitionFlowElement class as a parent class.

    UsrTestSmsConditionalTransitionFlowElement
    namespace Terrasoft.Configuration
    {
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Terrasoft.Common;
    using Terrasoft.Core.DB;

    public class UsrTestSmsConditionalTransitionFlowElement : ConditionalTransitionFlowElement
    {

    public string SmsText { get; set; }

    public string PhoneNumber { get; set; }

    public IEnumerable<Guid> TestSmsResponses { get; set; }

    private void ExtendWithResponses() {
    TransitionQuery.CheckArgumentNull("TransitionQuery");
    if (TestSmsResponses.Any()) {
    Query responseSelect = GetSelectByParticipantResponses();
    TransitionQuery.And("ContactId").In(responseSelect);
    }
    }

    private Query GetSelectByParticipantResponses() {
    var responseSelect = new Select(UserConnection)
    .Column("ContactId")
    .From("UsrSmsRecipient")
    .Where("SmsText").IsEqual(Column.Parameter(SmsText))
    .And("PhoneNumber").IsEqual(Column.Parameter(PhoneNumber))
    .And("TestSmsResponseId")
    .In(Column.Parameters(TestSmsResponses)) as Select;
    responseSelect.SpecifyNoLockHints(true);
    return responseSelect;
    }

    protected override void CreateQuery() {
    base.CreateQuery();
    ExtendWithResponses();
    }
    }
    }
  3. Publish the schema.

5. Implement the business logic of the flow for the campaign element

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

    For this example, use source code schema properties as follows.

    Property

    Property value

    Code

    UsrTestSmsConditionalTransitionElement

    Title

    Transition the Test SMS element

  2. Implement the back-end business logic of a flow.

    To do this, specify the ConditionalSequenceFlowElement class as a parent class.

    UsrTestSmsConditionalTransitionElement
    namespace Terrasoft.Configuration
    {
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Globalization;
    using System.Linq;
    using Newtonsoft.Json;
    using Terrasoft.Common;
    using Terrasoft.Core;
    using Terrasoft.Core.Campaign;
    using Terrasoft.Core.DB;
    using Terrasoft.Core.Process;

    [DesignModeProperty(Name = "TestSmsResponseId",
    UsageType = DesignModeUsageType.NotVisible, MetaPropertyName = TestSmsResponseIdPropertyName)]
    [DesignModeProperty(Name = "IsResponseBasedStart",
    UsageType = DesignModeUsageType.Advanced, MetaPropertyName = IsResponseBasedStartPropertyName)]
    public class UsrTestSmsConditionalTransitionElement : ConditionalSequenceFlowElement
    {

    private const string TestSmsResponseIdPropertyName = "TestSmsResponseId";
    private const string IsResponseBasedStartPropertyName = "IsResponseBasedStart";

    public UsrTestSmsConditionalTransitionElement() {}

    public UsrTestSmsConditionalTransitionElement(UsrTestSmsConditionalTransitionElement source)
    : this(source, null, null) {}

    public UsrTestSmsConditionalTransitionElement(UsrTestSmsConditionalTransitionElement source,
    Dictionary<Guid, Guid> dictToRebind, Core.Campaign.CampaignSchema parentSchema)
    : base(source, dictToRebind, parentSchema) {
    IsResponseBasedStart = source.IsResponseBasedStart;
    _testSmsResponseIdJson = JsonConvert.SerializeObject(source.TestSmsResponseId);
    }

    private string _testSmsResponseIdJson;

    private IEnumerable<Guid> Responses {
    get {
    return TestSmsResponseId;
    }
    }

    [MetaTypeProperty("{DC597899-B831-458A-A58E-FB43B1E266AC}")]
    public IEnumerable<Guid> TestSmsResponseId {
    get {
    return !string.IsNullOrWhiteSpace(_testSmsResponseIdJson)
    ? JsonConvert.DeserializeObject<IEnumerable<Guid>>(_testSmsResponseIdJson)
    : Enumerable.Empty<Guid>();
    }
    }

    [MetaTypeProperty("{3FFA4EA0-62CC-49A8-91FF-4096AEC561F6}",
    IsExtraProperty = true, IsUserProperty = true)]
    public virtual bool IsResponseBasedStart {
    get;
    set;
    }

    protected override void ApplyMetaDataValue(DataReader reader) {
    base.ApplyMetaDataValue(reader);
    switch (reader.CurrentName) {
    case TestSmsResponseIdPropertyName:
    _testSmsResponseIdJson = reader.GetValue<string>();
    break;
    case IsResponseBasedStartPropertyName:
    IsResponseBasedStart = reader.GetBoolValue();
    break;
    default:
    break;
    }
    }

    public override void WriteMetaData(DataWriter writer) {
    base.WriteMetaData(writer);
    writer.WriteValue(IsResponseBasedStartPropertyName, IsResponseBasedStart, false);
    writer.WriteValue(TestSmsResponseIdPropertyName, _testSmsResponseIdJson, null);
    }

    public override object Clone() {
    return new TestSmsConditionalTransitionElement(this);
    }

    public override object Copy(Dictionary<Guid, Guid> dictToRebind, Core.Campaign.CampaignSchema parentSchema) {
    return new TestSmsConditionalTransitionElement(this, dictToRebind, parentSchema);
    }

    /* Overrides the factory method for creating the executed element.
    Returns the element with the UsrTestSmsConditionalTransitionFlowElement type. */
    public override ProcessFlowElement CreateProcessFlowElement(UserConnection userConnection) {
    var sourceElement = SourceRef as TestSmsElement;
    var executableElement = new UsrTestSmsConditionalTransitionFlowElement {
    UserConnection = userConnection,
    TestSmsResponses = TestSmsResponseId,
    PhoneNumber = sourceElement.PhoneNumber,
    SmsText = sourceElement.SmsText
    };
    InitializeCampaignProcessFlowElement(executableElement);
    InitializeCampaignTransitionFlowElement(executableElement);
    InitializeConditionalTransitionFlowElement(executableElement);
    return executableElement;
    }
    }
    }
  3. Publish the schema.

6. Implement the flow logic when the source is changed

  1. Create a client module schema. Instructions: Implement a non-visual module.

    For this example, use the client module properties as follows.

    Property

    Property value

    Code

    UsrTestSmsCampaignConnectorManager

    Title

    Test SMS campaign connector manager

  2. Implement the flow logic. To do this, add source code to the JS schema property.

    UsrTestSmsCampaignConnectorManager
    define("UsrTestSmsCampaignConnectorManager", [], function() {

    Ext.define("Terrasoft.UsrTestSmsCampaignConnectorManager", {
    /* Specify replacing of the CampaignConnectorManager module. */
    override: "Terrasoft.CampaignConnectorManager",

    /* Add mapping of the name of arrow source campaign element – arrow type (full name). */
    initMappingCollection: function() {
    this.callParent(arguments);
    this.connectorTypesMappingCollection.addIfNotExists("UsrTestSmsElementSchema",
    "Terrasoft.UsrProcessTestSmsConditionalTransitionSchema");
    },

    /* Virtual method for reload.
    Arrow processing logic before its sudstitute by an arrow with a new type. */
    additionalBeforeChange: function(prevTransition, sourceItem, targetItem) {
    /* Additional logic here. */
    },

    /* Virtual method for reload.
    Populating specific fields of the created arrow based on the previous arrow. */
    fillAdditionalProperties: function(prevElement, newElement) {
    if (newElement.getTypeInfo().typeName === "UsrProcessTestSmsConditionalTransitionSchema") {
    /* Copy the configured responses if the previous arrow is of the same type. */
    newElement.testSmsResponseId = prevElement.testSmsResponseId ? prevElement.testSmsResponseId : null;
    /* Copy the configuration of response setup. */
    newElement.isResponseBasedStart = prevElement.isResponseBasedStart
    ? prevElement.isResponseBasedStart
    : false;
    }
    }
    });
    });
  3. Save the schema.

7. Connect the flow logic

  1. Create a replacing view model. Instructions: Implement a replacing module.

For this example, use replacing view model schema properties as follows.

Property

Property value

Code

BootstrapModulesV2

Title

BootstrapModulesV2

Parent object

BootstrapModulesV2

  1. Add source code to the JS schema section.

    BootstrapModulesV2
    /* Set the previously created UsrTestSmsCampaignConnectorManager module as a dependency. */
    define("BootstrapModulesV2", ["UsrTestSmsCampaignConnectorManager","UsrProcessTestSmsConditionalTransitionSchema"], function() {});
    require(["UsrTestSmsCampaignConnectorManager","UsrProcessTestSmsConditionalTransitionSchema"]);
  2. Save the schema.

View the result

  1. Open the Marketing workspace.

  2. Create a campaign. Instructions Create a Campaign.

  3. Add the Test SMS element to the Campaign Designer canvas.

  4. Add any other element (for example, Exit from campaign) to the Campaign Designer canvas.

  5. Add a flow from the Test SMS element to the Exit from campaign element of the campaign.

The example displays the transition properties panel. View the result >>>

note

In the actual implementation of this case, we recommend to create a Bulk SMS object schema. The UsrTestSmsElement and UsrTestSmsConditionalTransitionElement objects will contain the Id of this object and not the SmsText, PhoneNumber, etc. fields. The UsrTestSmsCampaignProcessElement executed element in the Execute() method will contain the logic of adding contacts to the bulk sms audience. A separate mechanism (or several mechanisms) must perform sending of the bulk sms and afterwards record the participants’ responses. Based on these responses, the flow will transfer the campaign audience to the following campaign step.


Source code

define("UsrProcessTestSmsConditionalTransitionSchema", ["CampaignEnums", "UsrProcessTestSmsConditionalTransitionSchemaResources", "ProcessCampaignConditionalSequenceFlowSchema"], function(CampaignEnums) {
Ext.define("Terrasoft.manager.UsrProcessTestSmsConditionalTransitionSchema", {
extend: "Terrasoft.ProcessCampaignConditionalSequenceFlowSchema",
alternateClassName: "Terrasoft.UsrProcessTestSmsConditionalTransitionSchema",
managerItemUId: "4b5e70b0-a631-458e-ab22-856ddc913444",
mixins: {
parametrizedProcessSchemaElement: "Terrasoft.ParametrizedProcessSchemaElement"
},
/* Full name of the class that corresponds to the current schema.
Use following typeName if the class is in the simple package. */
typeName: "Terrasoft.Configuration.UsrTestSmsConditionalTransitionElement, Terrasoft.Configuration",
/* If the class is in the assembly package use
typeName: "Terrasoft.Configuration.UsrTestSmsConditionalTransitionElement, SomeAssemblyPackageName" */
/* Arrow element name for linking to campaign elements. */
connectionUserHandleName: "TestSmsConditionalTransition",
/* Arrow property bar name. */
editPageSchemaName: "UsrTestSmsConditionalTransitionPropertiesPage",
elementType: CampaignEnums.CampaignSchemaElementTypes.CONDITIONAL_TRANSITION,
/* Collection of responses by SMS mailing. */
testSmsResponseId: null,
/* An attribute that takes into account the response condition when translating contacts. */
isResponseBasedStart: false,
getSerializableProperties: function() {
var baseSerializableProperties = this.callParent(arguments);
/* Properties to serialize and pass to back-end part when saving. */
Ext.Array.push(baseSerializableProperties, ["testSmsResponseId", "isResponseBasedStart"]);
return baseSerializableProperties;
}
});
return Terrasoft.UsrProcessTestSmsConditionalTransitionSchema;
});

Resources

Package with example implementation