Wednesday, February 2, 2011

Creating your own Action Methods

As mentioned in one of the previous posts, you can customize actions to be triggered in transactions, based on the context of the transaction. For instance starting a workflow, or triggering a letter to a customer when the status of the transaction changes or when a certain date is reached.

Standard SAP offers some very usefull options, such as:
• Starting campaign automation
• COPY_DOCUMENT: Creating a followup document (for instance a planned phonecall after a visit, or when a contract is about to expire)
• Creating a printout using a smartform
• Creating a reminder mail
• Creating a confirmation mail to the customer

Beside these standard possibilities, you might be interested in creating your own action logic which you want to assign to the business transaction.

Some examples of custom created actions are:
• Change Status: Changing the status of the current document (Nice if you want to auto close a document, or if you want to automatically change a status based on a date)
• Current Date: Enter the current date in a date type (Nice if you want to enter the date of for instance a status change)
• Copy Document and Change Status: A copy of the copy_document & changing the status (The copy_document creates a follow_up document). If you want the current document to get the status “followup created” for instance, you can use this method. This enables you to have different follow-up actions based on the context and still be sure there will be only exactly one followup (so for instance either an email to the customer OR a letter to the customer)
• Write file: This enable you to feed a file with data for for instance an interface or an extract. Particularly usefull for for instance lead interfaces and automated marketing campaigns.

How is this done?
As an example, I will show you how to create the change status action and add it to an action profile.
The coding in the example enables you to both use the action on header as well as on item level.
Create the action definition as defined here.
When defining the action, choose “Method Call”.

In the field “Method”, do not choose one of the existing, but click on the new button below.

In the popup, again do not choose an existing class, but create a new one (like ZSET_STATUS).

Now create the class. Note that the class will be created in definition EXEC_METHODCALL_PPF, and that it has an interface to IF_EX_EXEC_METHODCALL_PPF.

Implement the method EXECUTE.

Note that there are a few parameters you can use in the method:

IO_PARTNER is the partner that has been determined. Which partner from the transaction this is is determined in the action customizing.

IP_PREVIEW is occupied with an X in case the user pressed the Preview button.

The II_CONTAINTER contains the name-value pairs that have been added in the action customizing.

The RP_STATUS returns a code, which can be either of the following:
0 = Not Processed
1 = Successfully Processed
2 = Incorrectly Processed.

During the coding of the class it is important that you check the IP_PREVIEW, and it is important that you correctly set the RP_STATUS to make sure actions are not reprocessed while they shouldn’t.

And never put a commit in an action, but call the method register_for_save in class cl_action_execute.

As an example for the ZSET_STATUS. Note that in the example, 2 parameters are read from the ii_container: 'STAT_PROC'  and 'STATUS'.

Good luck!

Method IF_EX_EXEC_METHODCALL_PPF~EXECUTE.

  
DATA: lcl_action_execute   TYPE REF TO cl_action_execute,
        lv_guid_ref          
TYPE crmt_object_guid,
        lv_kind_ref          
TYPE crmt_object_kind,
        lt_input_fields      TYPE crmt_input_field_tab,
        ls_input_fields      
TYPE crmt_input_field,
        lt_field_names       
TYPE CRMT_INPUT_FIELD_NAMES_TAB,
        ls_field_names       
TYPE CRMT_INPUT_FIELD_NAMES,
        lv_message(255)      type c.

  
INCLUDE crm_direct.

  
CREATE OBJECT lcl_action_execute.* get parameter from reference object
  
CALL METHOD lcl_action_execute->get_ref_object
    
EXPORTING
      io_appl_object = io_appl_object
      ip_action      = ip_action
      ii_container   = ii_container
    
IMPORTING
      ev_guid_ref    = lv_guid_ref
      ev_kind_ref    = lv_kind_ref.

  rp_status = 
'2'.                  "Set Action ends in error as default
*---------------------------------
* Get new status.
DATA: lv_subrc type sysubrc,
      lv_status 
type char5,
      lv_stat_proc 
type char8,
      lv_problemclass        
TYPE bal_s_msg-probclass.

  
IF ii_container IS INITIAL.
    lv_subrc = 
1.
  
ELSE.* Get user status proc.
    
CALL METHOD ii_container->get_value
      
EXPORTING
        element_name = 
'STAT_PROC'
      
IMPORTING
        
data         = lv_stat_proc
        retcode      = lv_subrc.

    
IF lv_subrc <> 0.
      
MESSAGE ID 'CRM_SUR' TYPE 'E' NUMBER '005'
              
WITH 'STAT_PROC'
              
INTO lv_message.
      lv_problemclass = 
'2'.  "important
      
CALL METHOD cl_log_ppf=>add_message
        
EXPORTING
          ip_problemclass = lv_problemclass
          ip_handle       = ip_application_log.
      rp_status = 
'2'.  "Incorrectly processed
      
EXIT.
    
ENDIF.*Get user status.
    
CALL METHOD ii_container->get_value
      
EXPORTING
        element_name = 
'STATUS'
      
IMPORTING
        
data         = lv_status
        retcode      = lv_subrc.

    
IF lv_subrc <> 0.
      
MESSAGE ID 'CRM_SUR' TYPE 'E' NUMBER '005'
              
WITH 'STATUS'
              
INTO lv_message.
      lv_problemclass = 
'2'.  "important
      
CALL METHOD cl_log_ppf=>add_message
        
EXPORTING
          ip_problemclass = lv_problemclass
          ip_handle       = ip_application_log.
      rp_status = 
'2'.  "Incorrectly processed
      
EXIT.
    
ENDIF.

  
ENDIF.

  
DATA: LT_STATUS TYPE CRMT_STATUS_COMT,
        LS_STATUS 
TYPE CRMT_STATUS_COM.

  LS_STATUS-REF_GUID        = lv_guid_ref.
  LS_STATUS-REF_KIND        = lv_kind_ref.
  LS_STATUS-STATUS          = lv_status.
  LS_STATUS-USER_STAT_PROC  = lv_stat_proc.
  LS_STATUS-ACTIVATE        = 
'X'.

  LS_INPUT_FIELDS-REF_GUID    = lv_guid_ref.
  LS_INPUT_FIELDS-REF_KIND    = lv_kind_ref.
  LS_INPUT_FIELDS-OBJECTNAME  = 
'STATUS'.
  
CONCATENATE lv_status lv_stat_proc into LS_INPUT_FIELDS-LOGICAL_KEY.
  ls_field_names-fieldname = 
'ACTIVATE'.
  
APPEND LS_FIELD_NAMES TO LT_FIELD_NAMES.
  LS_INPUT_FIELDS-FIELD_NAMES = LT_FIELD_NAMES.
  
APPEND LS_INPUT_FIELDS TO LT_INPUT_FIELDS.

  
APPEND ls_status to lt_status.

  
CALL FUNCTION 'CRM_ORDER_MAINTAIN'
    
EXPORTING
      IT_STATUS                     = LT_STATUS
    
CHANGING
      CT_INPUT_FIELDS               = LT_INPUT_FIELDS
    
EXCEPTIONS
      ERROR_OCCURRED                = 
1
      DOCUMENT_LOCKED               = 
2
      NO_CHANGE_ALLOWED             = 
3
      NO_AUTHORITY                  = 
4
      
OTHERS                        = 5
           .
  
IF SY-SUBRC <> 0.*   MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
*           WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
  
ELSE.
    RP_STATUS = 
1.
  
ENDIF.DATA LV_GUID_TO_SAVE TYPE CRMT_OBJECT_GUID.IF lv_kind_ref = 'A'.
  LV_GUID_TO_SAVE = LV_GUID_REF.
ELSEIF lv_kind_ref = 'B'.

  
CALL FUNCTION 'CRM_ORDERADM_I_READ_OW'
    
EXPORTING
     IV_GUID                       = LV_GUID_REF
   
IMPORTING
     EV_HEADER_GUID                = LV_GUID_TO_SAVE
   
EXCEPTIONS
     ITEM_NOT_FOUND                = 
1
     
OTHERS                        = 2
            .
  
IF SY-SUBRC <> 0.* MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
*         WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
  
ENDIF.ENDIF.* Save the document
  
CALL METHOD lcl_action_execute->register_for_save
    
EXPORTING
      iv_source_header_guid = LV_GUID_TO_SAVE
      ip_application_log    = ip_application_log
    
IMPORTING
      rp_status             = rp_status.


endmethod.

2 comments:

  1. Guy,

    Great blog. Congratulations for sharing your learnings to the globe.

    Regards,

    Rodolfo ( BRAZIL SAP CRM consultant )

    ReplyDelete
  2. Hi,

    There is one point that is not clear for me. You put the message into a variable lv_message but it seems like it's not used then in the rest of the code. I mean it's not transfered to the application log.

    Is that normal ?

    Thanks for the note by the way :)

    ReplyDelete