Wednesday, February 23, 2011

Making changes in the transaction launcher customizing

If you want to change the system or the BOR object to be called using the transaction launcher customizing, you will notice that this is standard not allowed by the system. These fields are greyed out by the system once the launch transaction is saved once.

If you do need to change these settings, there are two ways to go:
  1. Change the name of the class in the second screen of the wizard. This will give you the possibility to change the data. The old class will also remain in the system, but will not be used anymore as there is no customizing referring to it anymore.
  2. Check the name of the class of the launch transaction in the second page of the wizard, and just delete the class in SE80 (or SE24). If you run the wizard again, the fields will be open for input again as the class will be newly created.
If you apply the second method, you will need to trick the QAS and PRD system, because after transporting the new customizing, the class will not automatically be updated. What you need to do is simply walk through the wizard after the transport has gone in, and the class will be generated based on the new settings. Even though the system will tell you the client is not modifyable, you do not need to open QAS or PRD for customizing.


The wizard will tell you that it has been cancelled, but the class has been generated anyway.

 
No worries.

Wednesday, February 16, 2011

Enhanced IC Webclient Alerts

In some of the previous blogs, I explained how you can implement IDI to add for instance automatic navigation, context-based alerts etcetera to the IC Webclient, to improve the effectiveness of the system for the user.

Standard SAP CRM is shipped with some fairly general alerts. For instance, you can have an alert that tells you the customer number, or you can have an alert that tells you the customer has open items.

Beside the standard alerts, in the IC Manager role, you can create new alerts. In these alerts, you can maintain your own text, and use the parameters that have been supplied by the system.

If these standard shipped parameters do not satisfy your needs, you can also add new parameters. For instance, if your users need to have an alert containing all of the customer’s telephone numbers, and not just the first one. Or if you want to notify the user there is an open serviceticket.

Adding a new parameter be done in several steps.
IMG: SAP Customizing Implementation Guide --> Customer Relationship Management --> Interaction Center WebClient --> Additional Functions --> Intent-Driven Interactions

1. Add the technical name of the new parameter ( Define Repository)
2. Add a ‘Fact Gathering’ service (Define Services)
3. Add the fact gathering service to the service manager profile (Define Service Manager Profiles)
4. Apply the service manager profile to the Intent-Driven Interaction Profile (Define Intent-Driven Interacton Profiles)
5. Add coding to the class of the fact gathering service (SE80)

In the following example, I will illustrate with the attribute 'Number of Servicetickets'. This is comparable to the existing FICA_NO_OF_CALLS.

1. Add the technical name of the new parameter ( Define Repository)
  • In the Define Repository in the IMG, select the ICRULE, and click on attributes. Here, add a new attribute, for instance ZNO_OF_SERV.
  • In the Desription, add a description.
  • Tick the Show Attribute checkbox if you want this attribute to be available as a condition in the Rule Policy maintenance.
  • Enter the name of the Fact Gathering Service we will be creating in step 2 (i.e. ZFG_SVT)
  • In Attrib Ext Class, choose the right class from the search help. This determines which operands will be available in the rule policy builder.
2. Add a ‘Fact Gathering’ service (Define Services)
In the Define Services, add the service. In our case, ZFG_SVT. Choose Fact Gathering as the service type. Enter a Service Class. (i.e. ZL_CRM_FACTS_SVT).

3. Add the fact gathering service to the service manager profile (Define Service Manager Profiles)
Add the new Service to the Directly Called Services of your Service Manager Profile. If you have not yet created a Service Manager Profile, create a copy of the IDI_DEFAULT, and add your new service. Make sure all fact gathering services are before the SVC_RULE_EXEC, because you want the fact gathering to take place before rule execution.

4. Apply the service manager profile to the Intent-Driven Interaction Profile (Define Intent-Driven Interacton Profiles)
Make sure the Service Manager Profile is mapped to the Intent-Driven Interaction Profile. If you do not yet have an own Intent-Driven Interaction Profile, create one.

Also, don't forget to apply the IDI profile in the Business Role (Function Profile 'INTENT_DRIVEN_INTERACIONS')

5. Add coding to the class of the fact gathering service (SE80)
In SE80, go to class/interface and create a subclass for CL_CRM_FICA_FACTS_FOR_RULES*.

Redefine the method IF_CRM_SMF_SERVICE~EXECUTE and add the following coding:

METHOD if_crm_smf_service~execute.

DATA: lv_gpart TYPE string,
         lv_cor_available TYPE string,
         lv_dun_available TYPE string,
         lv_no_of_calls TYPE string,
         lv_no_of_svt TYPE string,
         lr_query TYPE REF TO cl_crm_bol_dquery_service,
         lr_col   TYPE REF TO if_bol_bo_col.

  CALL METHOD me->get_bp_confirmed
    RECEIVING
      rv_gpart = lv_gpart.

  CHECK NOT lv_gpart IS INITIAL.

* -- number of calls

  lr_query = cl_crm_bol_dquery_service=>get_instance( 'BTQSrvReq' ).
  CHECK lr_query IS BOUND.

  CALL METHOD lr_query->add_selection_param
  EXPORTING
    IV_ATTR_NAME = 'BU_PARTNER'
    IV_SIGN = 'I'
    IV_OPTION = 'EQ'
    IV_LOW = lv_gpart
  .

  lr_col = lr_query->get_query_result( ).
  CHECK lr_col IS BOUND.

  rv_no_of_calls = lr_col->size( ).

  CALL METHOD me->set_fb_attr_by_id
    EXPORTING
      id    = 'ZNO_OF_SERV'
      value = lv_no_of_svt.

ENDMETHOD.


* Depending on your requirements, you might require a subclass for CL_CRM_SMF_ABSTRACT_SERVICE

Wednesday, February 9, 2011

Testing SWO1 objects and conditions

When working with actions, you may need complex schedule- and startconditions. When customizing these conditions, it can be very handy to use the different test / simulate options. Both the SWO1 as well as the conditions maintenance transaction have the possibility to test with an existing business object. This way, you can test (and analyze and even debug) with different situations quickly directly while maintaining.




Testing an object in SWO1
In SWO1, when you have created a new attribute or a new method, you can test this with an existing object by clicking the test button. In the popup, you should enter the key of an existing object (for instance the GUID of a transaction, or a partnernumber). The system will now show the data in the structure of the BUSObject. You will also be able to test (and debug) the methods.


Testing conditions

In the conditions maintenance, you can also use the test button, and use an existing instance to simulate the condition.

When in the action condition editor (CRMC_ACTION_CONF), you can choose between Full screen and Popup mode. In both modes, you will be able to test the condition, but the test buttons will be in a different place...

Find the 'Enter Test Data' button.





In the popup, select the line of the business object, and below, enter or select an object.

When occupied properly, you will be able to see the details of the object if you expand the tree.














Now close the popup and click on the 'Evaluate condition with test data' button. The condition test will now tell you whether the condition returns true or false. This is a good place to debug as well if you really can't figure it out :-).


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.