Skip to Content

Introduction:

Twitter is an important channel for businesses to connect with new and existing customers, to increase brand awareness or provide timely customer service, also to connect with brand advocates and influencers.
SAP Hybris Marketing omni-channel experience provides a framework to integrate with Twitter to launch Campaigns, in our use-case, to respond in the form of Direct Message to Twitter users who are follow our Official twitter handle. This is also an example to showcase how the integration of various other channels can be realised similarly.

For this prototype implementation, we rely on the generic Action framework and this prototype implementation is specific to SAP Hybris marketing only (On Premise), the architecture for integration with S/4 HANA Cloud Marketing Edition can be found here.

Configuration

1. Establishing connection to Twitter

a. With the intent of sending Direct Messages from a common account (Twitter Handle), define an App in apps.twitter.com
Note down the Consumer Key, Secret, User Token and Secret for use in steps 1.d and 1.e

b. We use TWIBAP open source program for Connectivity and Authorization (http://scn.sap.com/community/abap/
connectivity/blog/2010/08/12/twibap-the-abap-twitter-api)
c. Use the report Z_OAUTH_SETUP_1_API_KEY to register (From Twibap) the application
The program accepts
1. Consumer Key
2. Consumer Secret
3. API Host (api.twitter.com)
and leave the default selection for radio buttons as is.
d. Use the report Z_OAUTH_SETUP_2_REGISTER_USER (From Twibap) to allow the program to handle actions on behalf of user
This report triggers the OAUTH authentication process to get Access Token
e. SM59: Define RFC destination TWITTER for using Twitter APIs
Create a new RFC destination as shown in the screenshot

2. Interaction Contact (CEI_IMG->Contacts and Profiles->Interaction Contacts)

a. Define Origins of Contact ID: To capture the Twitter handle, we define a new Origin ID

b. Use the Import functionality in Data Management to import new /updates for Interaction Contact (mainly to store twitter handle using the newly defined ORIGIN ID)
1. In the Fiori Launchpad, open the application ‘Import Data’
2. In the Data Management section, select the Contacts option
3. Download the CSV template, and introduce a new header column at the very beginning, named ‘ID_ORIGIN’.
4. Maintain the values in the downloaded template, in our case a Contact with the newly created/defined ORIGIN_ID
5. Upload the file to create or update a Contact, verify the logs and the Contact to see if the uploaded data is in the system. A screenshot of a sample upload file is below.

6. screenshot of successful upload of Contacts

3. Campaigns /Action Framework (CEI_IMG->Campaigns->Campaign)

a. Define Provider Configuration:
A new provider for Twitter with RFC destination and a Provider class
CL_CUAN_MKT_EXEC_TWITTER, which implements IF_CUAN_MKT_EXEC_HTTP_OUTBOUND. In our case, derived from CL_CUAN_MKT_EXEC_SMS

b. Define Sender Profile:
Marketing area specific, unites Provider with sender profile (Sender name and communication medium)

c. Define Campaign Categories and Actions :
Define a new action “TWI_DIRECT_MESSAGE”, with an action class implementing interface IF_CUAN_MKT_EXEC_EXECUTE_ACTN
and IF_CUAN_MKT_EXEC_ACTION_PARAM. In our example, derived from CL_CUAN_MKT_EXEC_EXECUTE_SMS and also implementing the interface
IF_CUAN_MKT_EXEC_ACTION_PARAM.

Once a new Action is defined, assign it to an existing Campaign Category or Create a new Campaign Category.

4. Interactions (CEI_IMG->Data Management->Interactions)

a. Define Interaction Types:
An interaction type, a new type DM_OUTBOUND for every successful Direct Message sent.
For Interaction type OUTBOUND_FAILED, we add new reasons TWITTER_ERROR, TWITTER_LIMIT_EXCEED, and
TWITTER_OPTIN_MISSIN for failure to send Direct Messages

b. Assign Interaction Types and Communication Media to Channels:
Assign DM_OUTBOUND to Twitter (TW) communication medium and Social Channel
Assign OUTBOUND_FAILED to Twitter (TW) communication medium and Social Channel

Implementation Details


Sequence Diagram for the Twitter Campaign execution process

The ABAP code for both Adapter class and Action class is available in the Appendix section of this blog

1. Implementation of Adapter class:

CL_CUAN_MKT_EXEC_TWITTER
This provider class typically implements the interface IF_CUAN_MKT_EXEC_HTTP_OUTBOUND, which enables us to influence the HTTP request, process the HTTP response, and also to check the connection.
In this implementation of Action for sending Twitter Direct Messages, we are deriving the provider class from CL_CUAN_MKT_EXEC_EXECUTE_SMS, which gives us some implementation for free. We may as well implement the interface directly.

IF_CUAN_MKT_EXEC_HTTP_OUTBOUND~BUILD_REQUEST
We build the HTTP request URI, Signature base string, HTTP body consisting of OAUTH parameters and sign the message
We begin with building necessary parameters like ‘oauth_nonce’, ‘oauth_timestamp’, ‘text’, ‘screen_name’, Followed by building the URI (‘ /1.1/direct_messages/new.json’). Set the request_uri, request_method, content_type and host for the HTTP request
(sample code is available for download at the end of this blog post)

IF_CUAN_MKT_EXEC_HTTP_OUTBOUND~PROCESS_RESPONSE
Get the HTTP response code
Get the cdata from the response object

Set the values for structure es_member_status

IF_CUAN_MKT_EXEC_HTTP_OUTBOUND~CHECK_CONNECTION
As the name suggests, the connection is checked and returns abap_true or abap_false

2. Implementation of Action class:

CL_CUAN_MKT_EXEC_EXECUTE_TWIT
This action class implements the action interface IF_CUAN_MKT_EXEC_EXECUTE_ACTN, which provides methods for processing the Target Group entries in different stages.This also implements 2nd Interface for Action Parameters IF_CUAN_MKT_EXEC_ACTION_PARAM, which helps implementing partner defines new parameters, the method SET_ACTION_DETAILS helps us select an icon, and method SET_ACTION_PARAMETER helps us in giving a name, data type.
Our prototype implementation derives from an abstract class CL_CUAN_MKT_EXEC_EXECUTE_ACTN which provides some free implementation for checking marketing permission, to check if the segmentation object is valid, posting interactions, and excluding members after restart for those which were executed successfully.

IF_CUAN_MKT_EXEC_ACTION_PARAM~SET_ACTION_DETAILS
set Action Icon URL
Example:
es_action-icon_url = 'http://pbs.twimg.com/
profile_images/2284174872/7df3h38zabcvjylnyfe3_bigger.png'.

IF_CUAN_MKT_EXEC_ACTION_PARAM~SET_ACTION_PARAMETER
Define the parameter name, type
action_parameter – The ID of the parameter, must start with “Z” (ZOC_EXPORT_DESCRIPTION)
action_parameter_name – Label for the parameter used
action_parameter_type – controls how the parameter is rendered on the UI
(if_cuan_mkt_orch_constants=>action_param_type-string)
action_parameter_values (optional) – Possible values for parameter, if the parameter type is defined as dropdown

Example:
APPEND VALUE #( action_parameter = 'ZOC_EXPORT_DESCRIPTION'
action_parameter_name = 'Message'
action_parameter_type = if_cuan_mkt_orch_constants=>action_param_type-string ) TO
et_action_parameter.

IF_CUAN_MKT_EXEC_EXECUTE_ACTN~PRE_PROCESS
As the method name suggests, this is called before the members are processed and is used in our case to build the OAUTH parameters
and also parameters from Sender Profile
Example:
cl_cuan_mkt_exec_sms=>get_parameters( EXPORTING iv_sender = 'ZTWI'
IMPORTING et_parameters = et_param
et_messages = DATA(lt_message)
ev_error = ev_error ).

IF_CUAN_MKT_EXEC_EXECUTE_ACTN~PROCESS
Read all the member info extract the twitter handle for the member, by reading the facet which stores the twitter handle create outbound object
Example:
READ TABLE it_param WITH KEY param_name = if_cuan_mkt_exec_c=>c_param_adapter_class
ASSIGNING FIELD-SYMBOL().
CREATE OBJECT eo_sms TYPE (-param_value)
EXPORTING
it_parameters = it_param.

Send the HTTP request (via the outbound object), refer to method SEND_SMS in action implementation for SMS
Finally, write the outbound interactions in the system, refer to method PROCESS in action implementation for SMS

Testing of the Campaigns Integration with Twitter
a. Create /Update Interaction Contact to contain the facet “twitter handle”
b. Create Target Group consisting of Interaction Contacts with a valid Twitter Handle
c. Create a Campaign of category TW (whichever was created and Action assigned), In Automation Tab, select
the Twitter action and whatever message you would like to send to your official channel followers
d. Save and Execute the campaign
e. and Voila, the program would send the direct message on your behalf


Screenshot of a campaign to send Twitter direct message

Screenshot of the Direct Message received from the Hybris Marketing System

Appendix

ABAP code for the Adapter and Action class

class CL_CUAN_MKT_EXEC_TWITTER definition
  public
  inheriting from CL_CUAN_MKT_EXEC_SMS
  create public .

public section.

  methods CONSTRUCTOR
    importing
      !IT_PARAMETERS type CUAN_T_MKT_EXEC_PARAM optional .

  methods IF_CUAN_MKT_EXEC_BOUNCE~GET_BOUNCE_COLLECTION_MODE
    redefinition .
  methods IF_CUAN_MKT_EXEC_HTTP_OUTBOUND~BUILD_REQUEST
    redefinition .
  methods IF_CUAN_MKT_EXEC_HTTP_OUTBOUND~CHECK_CONNECTION
    redefinition .
  methods IF_CUAN_MKT_EXEC_HTTP_OUTBOUND~GET_PARAMETERS
    redefinition .
  methods IF_CUAN_MKT_EXEC_HTTP_OUTBOUND~PROCESS_RESPONSE
    redefinition .
protected section.
private section.

  data OAUTH type ref to ZCL_OAUTH .
  data PARAMETERS type CUAN_T_MKT_EXEC_PARAM .
ENDCLASS.



CLASS CL_CUAN_MKT_EXEC_TWITTER IMPLEMENTATION.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method CL_CUAN_MKT_EXEC_TWITTER->CONSTRUCTOR
* +-------------------------------------------------------------------------------------------------+
* | [--->] IT_PARAMETERS                  TYPE        CUAN_T_MKT_EXEC_PARAM(optional)
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD constructor.
    super->constructor( it_parameters = it_parameters ).
    me->parameters = it_parameters.
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method CL_CUAN_MKT_EXEC_TWITTER->IF_CUAN_MKT_EXEC_BOUNCE~GET_BOUNCE_COLLECTION_MODE
* +-------------------------------------------------------------------------------------------------+
* | [<-()] RV_MODE                        TYPE        CHAR4
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_cuan_mkt_exec_bounce~get_bounce_collection_mode.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method CL_CUAN_MKT_EXEC_TWITTER->IF_CUAN_MKT_EXEC_HTTP_OUTBOUND~BUILD_REQUEST
* +-------------------------------------------------------------------------------------------------+
* | [--->] IO_REQUEST                     TYPE REF TO IF_HTTP_REQUEST
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_cuan_mkt_exec_http_outbound~build_request.
    DATA: appendix TYPE string,
          url      TYPE string.
    DATA: ls_param LIKE LINE OF parameters.
    FIELD-SYMBOLS: <parameter> TYPE cuan_s_mkt_exec_param.
    "1. Get consumer and User credentials and Build parameters for OAUTH
    "this is done in pre-process of action class

    "2. Build parameters for a new DM
    oauth ?= zcl_oauth=>get_instance( ).
    ls_param-param_name = 'oauth_nonce'.                    "#EC NOTEXT
    ls_param-param_value = oauth->create_nonce( length = 8 ).
    INSERT ls_param INTO TABLE parameters.

    ls_param-param_name = 'oauth_timestamp'.                "#EC NOTEXT
    ls_param-param_value = oauth->create_timestamp( ).
    INSERT ls_param INTO TABLE parameters.

    ls_param-param_name = 'text'. "parameter for Twitter API

*    data(lv_text) = |viaActionFrw { sy-datum }-{ sy-timlo }|.
    data(lv_text) = me->mv_body.
    ls_param-param_value = oauth->percent_encode( lv_text ).
    INSERT ls_param INTO TABLE parameters.

    ls_param-param_name = 'screen_name'. "Recipient name in Twitter API
*    ls_param-param_value = 'DevFlashTwi'.
    ls_param-param_value = me->mv_recipient.
    INSERT ls_param INTO TABLE parameters.
*    ENDIF.

    "3. build URI
    CONCATENATE
      '/1.1'
      '/direct_messages/new.json'
    INTO appendix.

    "*--- set url ---*
    CONCATENATE
      zcl_twa_api=>api_protocol
      zcl_twa_api=>api_host
      appendix
    INTO url.

    "4. Set request uri
    DATA: http_body       TYPE string,
          oauth_signature TYPE string,
          uri             TYPE string.
    SORT me->parameters BY param_name.
    data: lt_parameters   like TABLE OF <parameter>.
    LOOP AT me->parameters ASSIGNING <parameter> FROM 6.
      http_body = |{ http_body }{ <parameter>-param_name }={ <parameter>-param_value }|.

      IF sy-tabix < lines( me->parameters ).
        http_body = |{ http_body }&|.
      ENDIF.

      INSERT <parameter> INTO TABLE lt_parameters.
    ENDLOOP.

*    url = |{ url }&{ http_body }|.
    oauth->set_oauth_url( url ).
    oauth->set_parameters( parameters = lt_parameters ).
    oauth->sign_message( ).

    IF oauth->get_oauth_signature( ) IS NOT INITIAL.
*      me->oauth_signature = percent_encode( me->oauth_signature ).
      oauth_signature = oauth->percent_encode( oauth->get_oauth_signature( ) ).
      http_body = |{ http_body }&oauth_signature={ oauth_signature }|.

    ls_param-param_name = 'oauth_signature'.                "#EC NOTEXT
    ls_param-param_value = oauth_signature.
    INSERT ls_param INTO TABLE parameters.
    ENDIF.


    uri = |{ appendix }|."?{ http_body }|.

    io_request->set_header_field(
      EXPORTING
        name  = '~request_uri'
        value = uri ).
    io_request->set_header_field(
      name  = '~request_method'
      value = 'POST' ).
    io_request->set_header_field(
      name = 'Content-Type'
      value = 'application/x-www-form-urlencoded' ).
    io_request->set_header_field(
      name = 'host'
      value = 'api.twitter.com' ).

    "6. set request->cdata
    io_request->set_cdata( http_body ).

    DATA: lt_headerfields   TYPE tihttpnvp.
    io_request->get_header_fields(
      CHANGING
        fields = lt_headerfields ).
    DATA(lv_cdata) = io_request->get_cdata( ).

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method CL_CUAN_MKT_EXEC_TWITTER->IF_CUAN_MKT_EXEC_HTTP_OUTBOUND~CHECK_CONNECTION
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_HTTP_CODE                   TYPE        I
* | [--->] IV_REASON                      TYPE        STRING
* | [--->] IV_CDATA                       TYPE        STRING
* | [--->] IV_CONNECTION_TYPE             TYPE        STRING(optional)
* | [<---] EV_SUCCESS                     TYPE        BOOLE_D
* | [<---] ET_MESSAGES                    TYPE        BAL_TT_MSG
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_cuan_mkt_exec_http_outbound~check_connection.
    ev_success = abap_true.
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method CL_CUAN_MKT_EXEC_TWITTER->IF_CUAN_MKT_EXEC_HTTP_OUTBOUND~GET_PARAMETERS
* +-------------------------------------------------------------------------------------------------+
* | [<---] ET_MESSAGE                     TYPE        BAL_TT_MSG
* | [<-()] RT_PARAMETERS                  TYPE        CUAN_T_MKT_EXEC_PARAM
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_cuan_mkt_exec_http_outbound~get_parameters.
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method CL_CUAN_MKT_EXEC_TWITTER->IF_CUAN_MKT_EXEC_HTTP_OUTBOUND~PROCESS_RESPONSE
* +-------------------------------------------------------------------------------------------------+
* | [--->] IO_RESPONSE                    TYPE REF TO IF_HTTP_RESPONSE
* | [<---] ES_MEMBER_STATUS               TYPE        CUAN_S_MKT_EXEC_MEMBER_STATUS
* | [<---] ET_MESSAGES                    TYPE        BAL_TT_MSG
* | [<---] EV_STOP_SENDING                TYPE        ABAP_BOOL
* | [<-->] CT_REQUEST_PARAM               TYPE        CUAN_T_MKT_EXEC_PARAM(optional)
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_cuan_mkt_exec_http_outbound~process_response.
    DATA: lv_http_code TYPE i,
          lv_reason    TYPE string,
          lv_cdata     TYPE string,
          lv_message   TYPE string.

    io_response->get_status( IMPORTING  code = lv_http_code
                                        reason = lv_reason ).
    DATA: lt_headerfields   TYPE tihttpnvp.
    io_response->get_header_fields(
      CHANGING
        fields = lt_headerfields ).
    lv_cdata = io_response->get_cdata( ).

    CASE lv_http_code.

      WHEN 200. "Success
        es_member_status-ia_type = 'DM_OUTBOUND'.
      WHEN OTHERS. "Error
        FIND FIRST OCCURRENCE OF REGEX '"message":"(.*)"' IN lv_cdata SUBMATCHES DATA(lv_error).
        FIND FIRST OCCURRENCE OF REGEX '"code":(.*),"message"' IN lv_cdata SUBMATCHES DATA(lv_error_code).

        IF lv_error IS INITIAL.
          MESSAGE e004(cuan_mkt_exec_frw) INTO lv_message WITH lv_http_code lv_reason lv_cdata.
        ELSE.
          MESSAGE e063(cuan_mkt_exec_frw) WITH lv_error INTO lv_message.
        ENDIF.
        cl_cuan_mkt_exec_messages=>add_message( CHANGING ct_messages = et_messages ).

        IF lv_error_code = 32 OR lv_error_code = 64 OR lv_error_code = 88 OR lv_error_code = 130 OR lv_error_code = 131 OR lv_error_code = 215.
          ev_stop_sending = abap_true.
        ENDIF.

        es_member_status-ia_type = 'OUTBOUND_FAILED'.
        CASE lv_error_code.
          WHEN 88.
            es_member_status-ia_reason = 'TWITTER_LIMIT_EXCEED'.
          WHEN 111.
            es_member_status-ia_reason = 'TWITTER_OPTIN_MISSIN'.
          WHEN OTHERS.
            es_member_status-ia_reason = 'TWITTER_ERROR'.
        ENDCASE.
    ENDCASE.
  ENDMETHOD.
ENDCLASS.

 

class CL_CUAN_MKT_EXEC_EXECUTE_TWIT definition
  public
  inheriting from CL_CUAN_MKT_EXEC_EXECUTE_SMS
  create public .

public section.

  methods IF_CUAN_MKT_EXEC_ACTION_PARAM~SET_ACTION_DETAILS
    redefinition .
  methods IF_CUAN_MKT_EXEC_ACTION_PARAM~SET_ACTION_PARAMETER
    redefinition .
  methods IF_CUAN_MKT_EXEC_EXECUTE_ACTN~PRE_PROCESS
    redefinition .
  methods IF_CUAN_MKT_EXEC_EXECUTE_ACTN~PROCESS
    redefinition .
protected section.

  data OAUTH type ref to ZCL_OAUTH .

  methods CHECK_COMMUNICATION_LIMITS
    redefinition .
  methods CHECK_MARKETING_PERMISSION
    redefinition .
  methods GET_COMM_ID
    redefinition .
  methods WRITE_HASHES_INTERACTIONS
    redefinition .
  methods READ_DEP_DATA
    redefinition .
private section.

  data PARAMETERS type CUAN_T_MKT_EXEC_PARAM .
  data MV_DM_TEXT type STRING .

  methods APPEND_OAUTH_PARAMETERS
    changing
      !CT_PARAM type CUAN_T_MKT_EXEC_PARAM .

  methods CREATE_OUTBOUND_OBJECT
    importing
      !IT_PARAM type CUAN_T_MKT_EXEC_PARAM
    exporting
      !EO_SMS type ref to CL_CUAN_MKT_EXEC_SMS
      !EV_ERROR type BOOLE_D .
ENDCLASS.



CLASS CL_CUAN_MKT_EXEC_EXECUTE_TWIT IMPLEMENTATION.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method CL_CUAN_MKT_EXEC_EXECUTE_TWIT->APPEND_OAUTH_PARAMETERS
* +-------------------------------------------------------------------------------------------------+
* | [<-->] CT_PARAM                       TYPE        CUAN_T_MKT_EXEC_PARAM
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD append_oauth_parameters.
    FIELD-SYMBOLS: <parameter> TYPE cuan_s_mkt_exec_param.

    INSERT INITIAL LINE INTO TABLE ct_param ASSIGNING <parameter>.
    <parameter>-param_name = 'oauth_consumer_key'.          "#EC NOTEXT
    <parameter>-param_value = oauth->get_consumer_key( ).

    INSERT INITIAL LINE INTO TABLE ct_param ASSIGNING <parameter>.
    <parameter>-param_name = 'oauth_signature_method'.      "#EC NOTEXT
    <parameter>-param_value = 'HMAC-SHA1'.                  "#EC NOTEXT

    INSERT INITIAL LINE INTO TABLE ct_param ASSIGNING <parameter>.
    <parameter>-param_name = 'oauth_token'.                 "#EC NOTEXT
    <parameter>-param_value = oauth->get_oauth_token( ).

    INSERT INITIAL LINE INTO TABLE ct_param ASSIGNING <parameter>.
    <parameter>-param_name = 'oauth_version'.               "#EC NOTEXT
    <parameter>-param_value = '1.0'.                        "#EC NOTEXT
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method CL_CUAN_MKT_EXEC_EXECUTE_TWIT->CHECK_COMMUNICATION_LIMITS
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_COMM_MEDIUM                 TYPE        CUAN_CE_COMM_MEDIUM
* | [<-->] CT_MEMBER_STATUS               TYPE        CUAN_T_MKT_EXEC_MEMBER_STATUS
* +--------------------------------------------------------------------------------------</SIGNATURE>
  method CHECK_COMMUNICATION_LIMITS.
  endmethod.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method CL_CUAN_MKT_EXEC_EXECUTE_TWIT->CHECK_MARKETING_PERMISSION
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_COMM_MEDIUM                 TYPE        CUAN_CE_COMM_MEDIUM
* | [--->] IV_REASON_FAILED               TYPE        CUAN_CE_IA_REASON(optional)
* | [<-->] CT_MEMBER_STATUS               TYPE        CUAN_T_MKT_EXEC_MEMBER_STATUS
* +--------------------------------------------------------------------------------------</SIGNATURE>
  method CHECK_MARKETING_PERMISSION.
"check for valid data
  endmethod.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method CL_CUAN_MKT_EXEC_EXECUTE_TWIT->CREATE_OUTBOUND_OBJECT
* +-------------------------------------------------------------------------------------------------+
* | [--->] IT_PARAM                       TYPE        CUAN_T_MKT_EXEC_PARAM
* | [<---] EO_SMS                         TYPE REF TO CL_CUAN_MKT_EXEC_SMS
* | [<---] EV_ERROR                       TYPE        BOOLE_D
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD create_outbound_object.
    DATA lv_message TYPE string.
    DATA lx_root    TYPE REF TO cx_root.
    READ TABLE it_param WITH KEY param_name = if_cuan_mkt_exec_c=>c_param_adapter_class
         ASSIGNING FIELD-SYMBOL(<ls_adapter_class>).
    IF sy-subrc <> 0.
      MESSAGE e007(cuan_mkt_exec_frw) INTO lv_message WITH 'UNEXPECTED_NO_ADAPTER_CLASS'.
      me->add_message( ).
      ev_error = abap_true.
    ENDIF.

    TRY.
        CREATE OBJECT eo_sms TYPE (<ls_adapter_class>-param_value)
          EXPORTING
            it_parameters = it_param.
      CATCH cx_root INTO lx_root.
        MESSAGE e012(cuan_mkt_exec_frw) INTO lv_message WITH <ls_adapter_class>-param_value.
        me->add_message( ).
        ev_error = abap_true.
    ENDTRY.
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method CL_CUAN_MKT_EXEC_EXECUTE_TWIT->GET_COMM_ID
* +-------------------------------------------------------------------------------------------------+
* | [<---] EV_ERROR                       TYPE        BOOLE_D
* | [<-->] CT_EXEC_MEMBER_STATUS          TYPE        CUAN_T_MKT_EXEC_MEMBER_STATUS
* | [<-->] CT_MESSAGE                     TYPE        BAL_TT_MSG
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD get_comm_id.
    DATA lt_ic_key   TYPE /bobf/t_frw_key.
    DATA lt_facet TYPE cuan_t_ce_ic_facet.


    LOOP AT ct_exec_member_status ASSIGNING FIELD-SYMBOL(<ls_exec_member>).
      APPEND VALUE #( key = <ls_exec_member>-contact_key ) TO lt_ic_key.
    ENDLOOP.

    DATA(lo_srv_ic)  = /bobf/cl_tra_serv_mgr_factory=>get_service_manager( iv_bo_key = if_cuan_ce_interact_contact_c=>sc_bo_key ).
    lo_srv_ic->retrieve_by_association( EXPORTING iv_node_key    = if_cuan_ce_interact_contact_c=>sc_node-root
                                                  iv_association = if_cuan_ce_interact_contact_c=>sc_association-root-facet
                                                  it_key         = lt_ic_key
                                                  iv_fill_data   = abap_true
                                        IMPORTING et_data        = lt_facet ).


    LOOP AT ct_exec_member_status ASSIGNING <ls_exec_member>.

      READ TABLE lt_facet ASSIGNING FIELD-SYMBOL(<ls_facet>)
           WITH KEY root_key = <ls_exec_member>-contact_key id_origin = 'ZTWITTER'.
      IF sy-subrc <> 0.
        CONTINUE.
      ENDIF.
      <ls_exec_member>-comm_id = <ls_facet>-id.
    ENDLOOP.
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method CL_CUAN_MKT_EXEC_EXECUTE_TWIT->IF_CUAN_MKT_EXEC_ACTION_PARAM~SET_ACTION_DETAILS
* +-------------------------------------------------------------------------------------------------+
* | [<---] ES_ACTION                      TYPE        TY_ACTION
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_cuan_mkt_exec_action_param~set_action_details.
    es_action-icon_url = 'http://pbs.twimg.com/profile_images/2284174872/7df3h38zabcvjylnyfe3_bigger.png'.
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method CL_CUAN_MKT_EXEC_EXECUTE_TWIT->IF_CUAN_MKT_EXEC_ACTION_PARAM~SET_ACTION_PARAMETER
* +-------------------------------------------------------------------------------------------------+
* | [<---] ET_ACTION_PARAMETER            TYPE        TT_ACTION_PARAMETER
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_cuan_mkt_exec_action_param~set_action_parameter.
    APPEND VALUE #( action_parameter = 'ZOC_EXPORT_DESCRIPTION'
                    action_parameter_name = 'Message'
                    action_parameter_type = if_cuan_mkt_orch_constants=>action_param_type-string ) TO et_action_parameter.
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method CL_CUAN_MKT_EXEC_EXECUTE_TWIT->IF_CUAN_MKT_EXEC_EXECUTE_ACTN~PRE_PROCESS
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_EXEC_RUN_KEY                TYPE        /BOBF/CONF_KEY
* | [<---] EV_NO_PARALLELIZATION          TYPE        BOOLE_D
* | [<---] EV_PACKAGE_SIZE                TYPE        I
* | [<---] EV_MAX_PARALLEL_TASKS          TYPE        I
* | [<---] ET_CONTENT_ATTR                TYPE        CUAN_T_MKT_EXEC_PERS_ATTR
* | [<---] ET_PARAM                       TYPE        CUAN_T_MKT_EXEC_PARAM
* | [<---] ET_MESSAGE                     TYPE        BAL_TT_MSG
* | [<---] EV_ERROR                       TYPE        BOOLE_D
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_cuan_mkt_exec_execute_actn~pre_process.

    me->read_dep_data( EXPORTING iv_exec_run_key = iv_exec_run_key
                       IMPORTING ev_error        = ev_error ).

    DATA: token_secret    TYPE string,
          consumer_secret TYPE string,
          secret          TYPE string.
    FIELD-SYMBOLS: <parameter> TYPE cuan_s_mkt_exec_param.
    oauth ?= zcl_oauth=>get_instance(
                 consumer_name   = 'ZKGPMKT'
                 screen_name     = 'kgpblr'
                 password        = 'Welcome1' ).

    IF oauth->is_authorized( ) IS INITIAL.
      "raise exception
    ENDIF.
    me->append_oauth_parameters(
      CHANGING
        ct_param =  et_param ).

    consumer_secret = oauth->get_consumer_secret( ).
    token_secret    = oauth->get_oauth_token_secret( ).
    secret = |{ consumer_secret }{ token_secret }|.

    oauth->set_oauth_secret( secret ).

*   add process relevant parameters from content sender profile
    TRY.
        cl_cuan_mkt_exec_sms=>get_parameters( EXPORTING iv_sender = 'ZTWI'
                                              IMPORTING et_parameters = et_param
                                                        et_messages = DATA(lt_message)
                                                        ev_error    = ev_error ).
      CATCH cx_root.
        MESSAGE e010(cuan_mkt_exec_frw) WITH me->ms_campaign_content-sending_profile INTO DATA(lv_message).
        cl_cuan_mkt_exec_messages=>add_message( CHANGING ct_messages = lt_message ).
        ev_error = abap_true.
        RETURN.
    ENDTRY.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method CL_CUAN_MKT_EXEC_EXECUTE_TWIT->IF_CUAN_MKT_EXEC_EXECUTE_ACTN~PROCESS
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_EXEC_RUN_KEY                TYPE        /BOBF/CONF_KEY
* | [--->] IT_TG_MEMBER                   TYPE        /BOBF/T_FRW_KEY
* | [--->] IT_CONTENT_ATTR                TYPE        CUAN_T_MKT_EXEC_PERS_ATTR
* | [--->] IT_PARAM                       TYPE        CUAN_T_MKT_EXEC_PARAM
* | [--->] IV_PACKAGE_NUMBER              TYPE        CUAN_MKT_EXEC_PACKAGE_NO
* | [<---] ET_MESSAGE                     TYPE        BAL_TT_MSG
* | [<---] EV_ERROR                       TYPE        BOOLE_D
* | [<---] EV_NUMBER_ERR_INTERACTIONS     TYPE        I
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_cuan_mkt_exec_execute_actn~process.
    DATA:
      lt_exec_member_status TYPE cuan_t_mkt_exec_member_status,
      lt_pers_content       TYPE cuan_t_mkt_exec_pers_content,
      lr_key_table          TYPE REF TO data,
      lv_sms_addr           TYPE ad_telnrlg,
      lo_sms                TYPE REF TO cl_cuan_mkt_exec_sms.

*   clear messages from log
    clear_messages( ).

*   read data of assigned objects
    me->read_dep_data( EXPORTING  iv_exec_run_key = iv_exec_run_key
                                  it_tg_member    = it_tg_member
                        IMPORTING ev_error        = ev_error ).
    IF ev_error IS NOT INITIAL.
      et_message = me->get_messages( ).
      RETURN.
    ENDIF.

    IF ev_error IS NOT INITIAL.
      et_message = me->get_messages( ).
      RETURN.
    ENDIF.

*   convert it tg member to segmentation key structure
    me->convert_tg_members( EXPORTING it_tg_member          = it_tg_member
                            IMPORTING er_key_table          = lr_key_table
                                      et_ic_key             = DATA(lt_ic_key)
                                      et_ia_key             = DATA(lt_ia_key)
                                      et_root_ia_key        = DATA(lt_root_ia_key)
                                      et_object_type_key    = DATA(lt_segobj_key)
                                      et_object_type_ds_key = DATA(lt_segobj_ds_key)
                                      ev_error              = ev_error
                                      ev_ic_comp_name       = DATA(lv_ic_comp_name)
                                      ev_ia_comp_name       = DATA(lv_ia_comp_name) ).
    IF ev_error IS NOT INITIAL.
      et_message = me->get_messages( ).
      RETURN.
    ENDIF.

    me->initialize_member_status( EXPORTING it_ic_key             = lt_ic_key
                                             it_ia_key             = lt_ia_key
                                             it_root_ia_key        = lt_root_ia_key
                                             ir_key_table          = lr_key_table
                                             it_object_type_key    = lt_segobj_key
                                             iv_ic_comp_name       = lv_ic_comp_name
                                             iv_ia_comp_name       = lv_ia_comp_name
                                             it_content_attr       = it_content_attr
                                   IMPORTING et_exec_member_status = lt_exec_member_status
                                             et_pers_content       = lt_pers_content
                                             ev_error              = ev_error ).
    IF ev_error IS NOT INITIAL.
      APPEND LINES OF me->get_messages( ) TO et_message.
      RETURN.
    ENDIF.

*   read IC root data (TODO integrate with comm ID retrieval)
    cl_cuan_mkt_exec_helper=>get_ic_root_data( IMPORTING ev_error         = ev_error
                                               CHANGING  ct_pers_content  = lt_pers_content
                                                         ct_member_status = lt_exec_member_status ).

*   read communication ids (Twitter Handle)
    me->get_comm_id( IMPORTING ev_error = ev_error
                     CHANGING  ct_exec_member_status = lt_exec_member_status
                               ct_message            = et_message ).
    IF ev_error IS NOT INITIAL.
      RETURN.
    ENDIF.
*   continue only with successfully checked members
    LOOP AT lt_exec_member_status ASSIGNING FIELD-SYMBOL(<ls_exec_member_status>).
      READ TABLE lt_pers_content ASSIGNING FIELD-SYMBOL(<ls_personalized_content>)
      WITH   KEY tg_member_key = <ls_exec_member_status>-tg_member_key BINARY SEARCH.

      CHECK sy-subrc IS INITIAL. "todo error handling

*     for successful checks create email or sms class
      IF <ls_exec_member_status>-ia_type IS INITIAL.

*       create email instance and set email address
        lv_sms_addr =  <ls_exec_member_status>-comm_id.

        create_outbound_object( EXPORTING it_param = it_param
                                IMPORTING eo_sms   = lo_sms
                                          ev_error = ev_error ).
        IF ev_error = abap_true.
          et_message = me->get_messages( ).
          RETURN.
        ENDIF.

        <ls_personalized_content>-sms_message_ref = lo_sms.
        <ls_personalized_content>-sms_message_ref->if_cuan_mkt_exec_sms~set_recipient( iv_recipient = lv_sms_addr ).
        <ls_personalized_content>-sms_message_ref->if_cuan_mkt_exec_sms~set_body( mv_dm_text ).
      ELSE.
*       checks not successful write hash to outbound ID and delete entry from personalization table
        <ls_exec_member_status>-outbound_id = <ls_personalized_content>-personalization_hash.
        DELETE lt_pers_content WHERE tg_member_key = <ls_exec_member_status>-tg_member_key.
      ENDIF.
    ENDLOOP.

*   call http send requests
    send_sms( EXPORTING it_param          = it_param
                        it_pers_content   = lt_pers_content
              CHANGING  ct_member_status = lt_exec_member_status ).

*   persist hashes & interactions
    DATA(lv_error) = me->write_hashes_interactions( it_exec_member_status = lt_exec_member_status
                                                    iv_exec_run_key       = iv_exec_run_key ).
    IF ev_error IS NOT INITIAL.
      RETURN.
    ENDIF.
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method CL_CUAN_MKT_EXEC_EXECUTE_TWIT->READ_DEP_DATA
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_EXEC_RUN_KEY                TYPE        /BOBF/CONF_KEY
* | [--->] IT_TG_MEMBER                   TYPE        /BOBF/T_FRW_KEY(optional)
* | [<---] EV_ERROR                       TYPE        BOOLE_D
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD read_dep_data.
    DATA:
      lt_key              TYPE /bobf/t_frw_key,
      lt_root_key         TYPE /bobf/t_frw_key,
      lt_root             TYPE cuan_t_marketing_orch_root,
      lt_campaign_root    TYPE cuan_t_initiative_root,
      lt_action_parameter TYPE cuan_t_marketing_orc_act_par,
      lv_content_id       TYPE cuan_me_engagement_id.

    me->mv_exec_run_key = iv_exec_run_key.
    me->mt_tg_members   = it_tg_member.
    CLEAR: ev_error.
    DATA(lo_srv_mktorc)  = /bobf/cl_tra_serv_mgr_factory=>get_service_manager( iv_bo_key = if_cuan_marketing_orch_c=>sc_bo_key ).

    APPEND VALUE #( key = iv_exec_run_key ) TO lt_key.
    lo_srv_mktorc->retrieve_by_association(
      EXPORTING
        iv_node_key    = if_cuan_marketing_orch_c=>sc_node-execution_run
        iv_association = if_cuan_marketing_orch_c=>sc_association-execution_run-to_root
        it_key         = lt_key
        iv_fill_data   = abap_true
      IMPORTING
        et_data        = lt_root ).

    READ TABLE lt_root INDEX 1 ASSIGNING FIELD-SYMBOL(<ls_root>).
    IF sy-subrc = 0.
      me->ms_mktorc_root = <ls_root>.
      APPEND VALUE #( key = <ls_root>-key ) TO lt_root_key.
      lo_srv_mktorc->retrieve_by_association(
         EXPORTING
           iv_node_key    = if_cuan_marketing_orch_c=>sc_node-root
           iv_association = if_cuan_marketing_orch_c=>sc_association-root-initiative
           it_key         = lt_root_key
           iv_fill_data   = abap_true
         IMPORTING
           et_data        = lt_campaign_root ).
      READ TABLE lt_campaign_root INDEX 1 INTO me->ms_campaign_root.
      IF sy-subrc <> 0.
*      -> no error, e.g. confirmation scenario
      ENDIF.
    ENDIF.

*   read tg data by first entry of it_tg_member_keys
    READ TABLE it_tg_member ASSIGNING FIELD-SYMBOL(<ls_member>) INDEX 1.
    IF sy-subrc IS INITIAL.

      DATA: lt_tg_root    TYPE cuan_t_tg_root.
      DATA: lt_member_key TYPE /bobf/t_frw_key.

*     retrieve tg member data
      DATA(lo_srv_tg)  = /bobf/cl_tra_serv_mgr_factory=>get_service_manager( iv_bo_key = if_cuan_target_group_c=>sc_bo_key ).

      APPEND VALUE #( key = <ls_member>-key ) TO lt_member_key.
      lo_srv_tg->retrieve_by_association(
        EXPORTING
          iv_node_key    = if_cuan_target_group_c=>sc_node-customer_member
          iv_association = if_cuan_target_group_c=>sc_association-customer_member-to_root
          iv_fill_data   = abap_true
          it_key         = lt_member_key
        IMPORTING
          et_data     = lt_tg_root ).

*     read tg root to determine member type for first entry
      READ TABLE lt_tg_root INTO me->ms_tg_root INDEX 1.
      IF sy-subrc <> 0.
        MESSAGE e007(cuan_mkt_exec_frw) INTO DATA(lv_message) WITH 'READ_TG_ROOT'.
        me->add_message( ).
        ev_error = abap_true.
      ENDIF.
    ENDIF.

    lo_srv_mktorc->retrieve_by_association(
      EXPORTING
        iv_node_key    = if_cuan_marketing_orch_c=>sc_node-execution_run
        iv_association = if_cuan_marketing_orch_c=>sc_association-execution_run-to_parent
        it_key         = lt_key
      IMPORTING
        et_target_key  = DATA(lt_action_key) ).

    lo_srv_mktorc->retrieve_by_association(
      EXPORTING
        iv_node_key    = if_cuan_marketing_orch_c=>sc_node-action
        iv_association = if_cuan_marketing_orch_c=>sc_association-action-action_parameter
        it_key         = lt_action_key
        iv_fill_data   = abap_true
      IMPORTING
        et_data        = lt_action_parameter ).

* read content ID from action parameter
    READ TABLE lt_action_parameter ASSIGNING FIELD-SYMBOL(<ls_action_parameter>)
          WITH KEY parameter_id = 'ZOC_EXPORT_DESCRIPTION'.
    me->mv_dm_text = <ls_action_parameter>-parameter_value.
  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method CL_CUAN_MKT_EXEC_EXECUTE_TWIT->WRITE_HASHES_INTERACTIONS
* +-------------------------------------------------------------------------------------------------+
* | [--->] IT_EXEC_MEMBER_STATUS          TYPE        CUAN_T_MKT_EXEC_MEMBER_STATUS
* | [--->] IV_EXEC_RUN_KEY                TYPE        /BOBF/CONF_KEY
* | [<---] EV_NUMBER_ERR_INTERACTIONS     TYPE        I
* | [<-()] RV_ERROR                       TYPE        BOOLE_D
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD write_hashes_interactions.
* write hashes for tracking
*    write_hashes( it_exec_member_status ).

* create interactions
    DATA ls_template_interaction TYPE cuan_s_ce_ia_int.
    ls_template_interaction = VALUE #( id_origin = 'ZTWITTER'
                                       comm_medium = 'SMS'
                                       quantifier = 1
                                       marketing_orchestration_id = me->ms_campaign_content-id
                                       content_title = me->ms_campaign_content-name ).

    me->post_interactions(
      EXPORTING
        it_member_status        = it_exec_member_status
        is_template_interaction = ls_template_interaction
      IMPORTING
        ev_error                =  rv_error ).
  ENDMETHOD.
ENDCLASS.
To report this post you need to login first.

7 Comments

You must be Logged on to comment or reply to a post.

  1. Jyoti Tangudu

    Thanks a lot Prasad. It is very useful. But the interface ‘IF_CUAN_MKT_EXEC_ACTION_PARAM’ is not found in our system!! The system version is :

    SHC                                                        2              SP10 (12/2015)  sap.com               SAP LANDSCAPE TRANSFORMATION. 2

    SLT                                                         2.0          SP10 (12/2015)  sap.com               SAP LT REPLICATION SERVER 2.0

    SAP NETWEAVER                             7.5          03 (04/2016)       sap.com               SAP NETWEAVER 7.5

    SAP HYBRIS MARKETING              1.2          02 (05/2016)       sap.com               SAP HYBRIS MARKETING 1.2

    (0) 
    1. Prasad KG Post author

      Hi Jyoti,
      This functionality is part of 1608 release and the system you are currently working seems to be in 1605 release.
      You should be able to use the interface once you upgrade to next or latest release. Hope this helps
      Regards,
      Prasad

      (0) 
  2. Jithin cherian

    Thanks Prasad for the excellent blog. This will be a good value addition for demonstrating to client.

     

    I was able to implement  the solution purposed here in our environment. And I was able to get the access token and secret from Twitter API and it got saved in table – ZOAUTH_USER.

     

    On executing the campaign (I’m executing the campaign using report – CUAN_MKT_EXEC_CHECK_EXECUTION to debug), it is prompting for credentials as shown below.

     

     

    I tried giving the credentials of the Twitter app. However, it is not accepting it and throwing “401 – Not authorized” with the error message “API error: Could not authenticate you.”. Could you please suggest what I’m missing here?

     

    Thanks in advance.

    Regards,

    Jithin

     

    (0) 
  3. Komur Akil

    When trying to implement the code on on-premise 1702, the code for CL_CUAN_MKT_EXEC_EXECUTE_TWIT does not seem to be correct, it will not compile.

    Are you sure that was the code that compiled on your system?

     

    (0) 
    1. Prasad KG Post author

      Hi Akil,

      Due to the changes in the underlying class CL_CUAN_MKT_EXEC_EXECUTE_ACTN after this blog, you are getting these errors, if you could go on adapt the Twitter action class, you will get the functionality and can serve as a reference to additional integrations

      Regards Prasad

      (0) 
  4. Mike Bowell

    This is a great post, also shows that we can integrate with a lot of channels, not just those that SAP has written documentation for. Out of interest how would you achieve this in the Hybris Marketing Cloud? I’m not sure that these enhancement classes are available in the cloud version?

     

    Many thanks

    Mike

    (0) 
    1. Prasad KG Post author

      Thanks Mike for your feedback

      In order to extend campaign execution in Cloud solution, you can use the Open Channel architecture, details can be found using URL  (Also a reference is given in the Introduction section of this blog).

      This is also mentioned in “What’s New in Campaign execution’ blog for 1702

      Hope it helps!

      Regards Prasad

      (0) 

Leave a Reply