Registration

Dear SAP Community Member,
In order to fully benefit from what the SAP Community has to offer, please register at:
http://scn.sap.com
Thank you,
The SAP Community team.
Skip to end of metadata
Go to start of metadata

Link to Content's target Space :

http://wiki.sdn.sap.com/wiki/display/CRM/CRM+Web+Client+UI+Framework

Applies to:

SAP CRM 6.0/7.0

Summary

Extend the standard BOL model BT with a custom relationship to accomodate your z-table.

Author(s):  

Arun Prakash Karuppanan   
Company:     Accenture
Created on:    April 15 2010
Author(s) Bio
Arun Prakash Karuppanan is a software programmer wmployed with Accenture, working on CRM implementations.

Intro

    There's been a few discussions in the forums about finding a way to add a custom table to the standard BOL models. It's a bit tricky, but possible. In this WIKI, I will show you how to enhance the BOl model BT with a new 1..n relationship. The advantages are obvious. Any change in your custom data will register in the BOl layer, you will be able to capture the BOl Core Reset and Order Init(revert) events, use the BOL model node wizards etc., Enhancing a few standard classes are in order. So, knowing how to enhance the methods using the implicit enhancement points is necessary.

In this example, we will create the relationship under the administration header(BTAdminH). Actually, two relationships. One will be a read only relationship(similiar to BTItems) that is linked and the other will be the 1..n relation that corresponds to your database.

My custom database ZORD has the following fields.

CLIENT                     type MANDT             "Client
GUID                        type CRMT_OBJECT_GUID  "guid of table entry(key)
REF_GUID                type CRMT_OBJECT_GUID  "guid of order object
EXTERN_CASE_NO  type CRMT_OBJECT_ID    "end-user usable
NOTE                        type CHAR120           "end-user usable

A structure 'ZORD_STRUCT' that corresponds to the table structure and a table type 'ZORD_STRUCT_TAB' is available.

Step 1 : Studying the event handler model


 Maintain API Object Name

In transaction  CRMC_OBJECTS, maintain the API object name of our custom object. In our case, the name is ZORD. This information will be used further below. This will allow us to define our own transaction events.

Maintain  Object dependency

 This step is to ensure that the transaction events which we will be defining later on, will  be called only when necessary. This step is optional and you should be able to figure out if your scenario needs this or not. For example, if you are extending only the opportunity transaction type, declare ZORD as a sub-object of Opportunity(BUS2000111). Maintain this information in view maintenance  CRMV_OBJECT_ASSI

Identify positions for defining custom events for transactions

We will have to define three basic events in the transaction event model that will take care of our custom objects. These are

1. Initialization -> When the order is being initialized say, during lock/revert scenarios, we want our object to be initialized too.

2. Save -> When the order is being saved, save our data too.

3. Delete -> When the order is deleted, we need to delete corresponding data from our custom table

For this, you must identify the correct places to insert our event callback function modules. If not already done, set your user parameter CRM_EVENT_TRACE to "X". Next, do something say, create transactions, modify it, save it and delete it. After each action, look at the events raised in transaction CRMD_EVENT_TRACE. Study this data carefully and decide on the points in which to insert your event callback function modules. For creating the FMs(the signature part), look at the standard FMs (they end with *_EC) defined for the same event in the trace data. Create empty FMs for each of the three events mentioned and study the trace again. We will be calling our custom API class' methods inside these FMs. We will cover this later. For now, create entries in the transaction event handler table and ensure that the FMs are getting called in the correct places for various scenarios.

For example, if I'm extending the Opportunity model, I will create  these entries - In SPRO, go to CRM->Transactions->Basic Settings->Edit event handler table

 1. Initialization

Choosing transaction category is opportunity will ensure that this FM will be called only for Opportunities

Transaction Category            BUS2000111 (Opportunity)
Execution Time                88 (Initialize Document)
Priority                99
Object                    ZORD (Z Order Extension)
Event                    INIT
Attribute                <*>
Function                ZORD_INIT_EC
Perform Function for Document Header    X
Perform Function for Document Item    blank
Do Not Process Function if Event Error Occurs blank   
Call Callback                Call Just Once Per Transaction

2. Save

Unlike above, we cannot choose transaction category as Opportunity here! This is because an opportunity save event will be raised only when you make changes in the opportunity relevant fields(eg OPPORT_H), even though you are editing an opportunity. For the below FM to trigger, we will have to "remind" the system to do it when changes are made to our custom objects. So, you will not see this FM in the event trace right now till the coding part is complete. We will cover this further down(Look further down at the last part of the coding part for the method implementation for METHOD  ZORD_RUN_BTIL->if_crm_runtime_btil~maintain_attributes).

Transaction Category            BUS20001 (CRM Bus Transactions)
Execution Time                80 (Save Document)
Priority                99
Object                    ZORD (Z Order Extension)
Event                    SAVE
Attribute                <*>
Function                ZORD_SAVE_EC
Perform Function for Document Header    X
Perform Function for Document Item    blank
Do Not Process Function if Event Error Occurs    blank
Call Callback                Call Just Once Per Transaction

3. Delete

For deletion also, only generic order delete event can be chosen. Inside this Fm, you should make sure that the scenario is right. For example, make sure that the order being deleted is an opportunity before making API calls! We will cover this below.

Transaction Category            BUS20001 (CRM Bus Transactions)
Execution Time                1 (Immediately)
Priority                90
Object                    ORDER (General order processing)
Event                    AFTER_DELETE
Attribute                <*>
Function                ZORD_DEL_EC
Perform Function for Document Header    X
Perform Function for Document Item    blank
Do Not Process Function if Event Error Occurs    blank
Call Callback                Call Just Once Per Transaction
 

Step 2 : Customizing - Extend Model BT

 
First, we have some customizing work to do. Navigate to the node shown in the picture.Note that the node text may show up as 'Business Transactions' in your case. Or you may go to SM30 and put 'CRMC_OBJ_BTIL' and choose customizing. You must do each of the three activities shown.




Maintain Z-objects



 


Maintain Z-Relations



Maintain handler classes for Z-objects 


Note:
If you are not willing to implement the classes, you may skip maintaining the handler classes. You can even directly specify a single 1..n relationship directly under BTAdminH. The relationships will be available, but not usable in the real sense. Then, you can follow this wiki to make do with value nodes.
http://wiki.sdn.sap.com/wiki/display/CRM/How+to+display+a+z-table+in+an+assignment+block

Moving forward, here's a screenshot of the model with the new relationships expanded. 

Step 3: Implementing  Handler classes

 API Class for our custom Object 

We will begin with the API class which will be responsible for all operations related to our table.

ZL_ZORD_BTIL_API -> Super class: None

Class Attributes
GT_ZORD  Static Attribute Private Type ZORD_STRUCT_TAB API Buffer
GT_ZORD_DEL Static Attribute Private Type ZORD_STRUCT_TAB API Buffer for deleted entities

Note: The GT_ZORD table will act as a unified buffer for read and change. GT_ZORD_DEL will hold entries to be deleted on save. Due to this unified buffer nature, it is very important to refresh this table on Order INIT events.

Methods:



ZORD_CREATE  Static Method Public  Create
ZORD_MODIFY  Static Method Public  Modify API data
ZORD_DELETE  Static Method Public  Delete from API data
ZORD_SAVE  Static Method Public  Save to DB
ZORD_READ  Static Method Public  Initial relations reading

ZORD_READ_SINGLE Static Method Public  Read single entry

ZORD_INIT  Static Method Public   Reset buffers
ZORD_DELETE_WITH_ORDER  Static Method Public  Delete from DB when order is deleted


Method Signatures:

*"* public components of class ZL_ZORD_BTIL_API
*"* do not include other source files here!!!
public section.

  class-methods ZORD_CREATE
    importing
      !IS_KEY type CRMT_OBJECT_GUID
      !IS_ATTRIBUTES type ZORD_STRUCT .
  class-methods ZORD_MODIFY
    importing
      !IS_KEY type CRMT_OBJECT_GUID
      !IV_HEADER_GUID type CRMT_OBJECT_GUID
      !IS_ATTRIBUTES type ZORD_STRUCT
      !IT_CHANGED_FIELDS type CRMT_ATTR_NAME_TAB
    exporting
      !ET_RETURN type BAPIRET2_T
      !ET_CHANGED_OBJECTS type CRMT_GENIL_OBJ_INSTANCE_TAB .
  class-methods ZORD_DELETE
    importing
      !IS_KEY type CRMT_OBJECT_GUID
      !IV_HEADER_GUID type CRMT_OBJECT_GUID
    exporting
      !ET_RETURN type BAPIRET2_T
      !ET_CHANGED_OBJECTS type CRMT_GENIL_OBJ_INSTANCE_TAB .
  class-methods ZORD_SAVE
    importing
      !IV_HEADER_GUID type CRMT_OBJECT_GUID .
  class-methods ZORD_READ
    importing
      !IV_HEADER_GUID type CRMT_OBJECT_GUID
    exporting
      !ET_ZORD type ZORD_STRUCT_TAB .
  class-methods ZORD_READ_SINGLE
    importing
      !IV_GUID type CRMT_OBJECT_GUID
    exporting
      !ET_ZORD type ZORD_STRUCT_TAB .
  class-methods ZORD_INIT
    importing
      !IV_HEADER_GUID type CRMT_OBJECT_GUID optional .

  class-methods ZORD_DELETE_WITH_ORDER
    importing
      !IV_HEADER_GUID type CRMT_OBJECT_GUID optional .


Method Implementations

METHOD zord_create.
  DATA: ls_zord TYPE zord_struct.
  ls_zord = is_attributes.
  ls_zord-guid = is_key.
  INSERT ls_zord INTO TABLE gt_zord.
ENDMETHOD.
 
METHOD zord_modify.
  FIELD-SYMBOLS: <fs_zord> LIKE LINE OF gt_zord,
                 <old>  TYPE simple,
                 <new>  TYPE simple,
                 <name> TYPE name_komp.
  READ TABLE gt_zord WITH KEY guid = is_key ASSIGNING <fs_zord>.
  IF sy-subrc EQ 0.
    LOOP AT it_changed_fields ASSIGNING <name>.
      ASSIGN COMPONENT <name> OF STRUCTURE <fs_zord> TO <old>.
      CHECK sy-subrc = 0.
      ASSIGN COMPONENT <name> OF STRUCTURE is_attributes TO <new>.
      CHECK sy-subrc = 0.
      <old> = <new>.
    ENDLOOP.
  ENDIF.
ENDMETHOD.
METHOD zord_delete.
  DATA: ls_zord LIKE LINE OF gt_zord.
  READ TABLE gt_zord WITH KEY guid = is_key INTO ls_zord.
  IF sy-subrc EQ 0.
    INSERT ls_zord INTO TABLE gt_zord_del.
    DELETE gt_zord WHERE guid = is_key.
  ENDIF.
ENDMETHOD.
METHOD zord_save.
  DATA: lt_zord TYPE zord_struct_tab,
        ls_zord LIKE LINE OF lt_zord.
  LOOP AT gt_zord  INTO ls_zord WHERE ref_guid = iv_header_guid.
    INSERT ls_zord INTO TABLE lt_zord.
  ENDLOOP.
  IF lt_zord[] IS NOT INITIAL.
    MODIFY zord FROM TABLE lt_zord.
  ENDIF.
  REFRESH lt_zord.
  LOOP AT gt_zord_del  INTO ls_zord WHERE ref_guid = iv_header_guid.
    INSERT ls_zord INTO TABLE lt_zord.
  ENDLOOP.
  IF lt_zord[] IS NOT INITIAL.
    DELETE zord FROM TABLE lt_zord.
  ENDIF.

ENDMETHOD.
METHOD zord_read.
  DATA: lt_zord TYPE zord_struct_tab,
        ls_zord LIKE LINE OF lt_zord.
*Check buffer first
*If entries are found in buffer, no need to check DB as whole buffer is used.
*no special provisions for deleted items
  READ TABLE gt_zord WITH KEY ref_guid = iv_header_guid TRANSPORTING NO FIELDS.
  IF sy-subrc EQ 0.
    et_zord[] = gt_zord[].
    DELETE et_zord WHERE ref_guid NE iv_header_guid.
  ELSE.
    READ TABLE gt_zord_del WITH KEY ref_guid = iv_header_guid TRANSPORTING NO FIELDS.
    IF sy-subrc EQ 0.
*deleted entries exist in buffer!! => Table has already been buffered => No DB Read
      EXIT.
    ELSE.
      REFRESH et_zord.
      SELECT * FROM zord INTO TABLE et_zord WHERE ref_guid = iv_header_guid.
      INSERT LINES OF et_zord INTO TABLE gt_zord.
    ENDIF.
  ENDIF.

ENDMETHOD.
METHOD zord_read_single.
  DATA: lt_zord TYPE zord_struct_tab,
        ls_zord LIKE LINE OF lt_zord.
*Check buffer first
*If entries are found in buffer, no need to check DB as whole buffer is used.
*no special provisions for deleted items
  READ TABLE gt_zord WITH KEY guid = iv_guid INTO ls_zord.
  IF sy-subrc EQ 0.
    INSERT ls_zord INTO table et_zord.
  ELSE.
    SELECT * FROM zord INTO TABLE et_zord WHERE guid = iv_guid.
    INSERT LINES OF et_zord INTO TABLE gt_zord.
  ENDIF.

ENDMETHOD.
METHOD zord_init.
  DATA: lt_zord TYPE zord_struct_tab,
        ls_zord LIKE LINE OF lt_zord.
  IF iv_header_guid IS NOT INITIAL.
    DELETE gt_zord WHERE ref_guid = iv_header_guid.
    DELETE gt_zord_del WHERE ref_guid = iv_header_guid.
  ELSE.
    REFRESH gt_zord.
    REFRESH gt_zord_del.
  ENDIF.
ENDMETHOD.
 
METHOD ZORD_DELETE_WITH_ORDER.
  DELETE FROM zord WHERE ref_guid = iv_header_guid.
ENDMETHOD.

Handler classes for our objects 

The names of the classes will be derived at runtime following some conventions. Essentially a _RUN_BTIL and a _DESIGN_BTIL is appended to what you have specified in customizing. So, go ahead and create the classes.
ZORD_SET_DESIGN_BTIL -> Super class: CL_CRM_DESIGNTIME_BTIL
ZORD_DESIGN_BTIL -> Super class: CL_CRM_DESIGNTIME_BTIL

For the design classes, no further changes are required. You may want to redefine the constructor if you wish to validate the

object name.

ZORD_SET_RUN_BTIL  -> Super class: CL_CRM_RUNTIME_BTIL
ZORD_RUN_BTIL     -> Super class: CL_CRM_RUNTIME_BTIL

ZORD_SET_RUN_BTIL - Redefined Methods


METHOD if_crm_runtime_btil~read_attributes.

DATA: ls_guid TYPE crmst_guid_btil.

*This is a static read-only relation.
*Inherit GUID from order
  TRY.
      ir_cont_obj->set_key( iv_ref_guid ).
    CATCH cx_crm_cic_duplicate_entry.
  ENDTRY.

  IF ir_cont_obj->check_attr_requested( ) EQ true.
    ls_guid-crm_guid = iv_ref_guid.
    me->set_attributes( ir_cont_obj   = ir_cont_obj
                        is_attributes = ls_guid
                        iv_ref_kind   = iv_ref_kind
                        iv_log_key    = iv_ref_guid ).
  ENDIF.

*Read underlying relations
  IF ir_cont_obj->check_rels_requested( ) EQ true.

    me->access_children( ir_cont_obj = ir_cont_obj
                         ir_data     = ir_api_data
                         iv_ref_guid = iv_ref_guid
                         iv_ref_kind = iv_ref_kind ).
  ENDIF.
*
ENDMETHOD.



METHOD IF_CRM_RUNTIME_BTIL~MAINTAIN_ATTRIBUTES.
DATA: lv_delta TYPE crmt_delta.

***
*This is a read-only relation, nothing much to do here except inherit GUID from Order object
  lv_delta = ir_cont_obj->get_delta_flag( ).
  IF lv_delta EQ ir_cont_obj->delta_created.
    TRY.
        ir_cont_obj->set_key( iv_ref_guid ).
      CATCH cx_crm_cic_duplicate_entry.
    ENDTRY.
  ENDIF.

*Take care of underlying relations
  me->modify_children( ir_cont_obj     = ir_cont_obj
                       ir_data         = ir_api_data
                       ir_input_fields = ir_input_fields
                       iv_ref_kind     = iv_ref_kind
                       iv_ref_guid     = iv_ref_guid ).

ENDMETHOD.

METHOD MODIFY_CHILDREN .
*Do not redefine this method! Super class will take care of this
ENDMETHOD.
 

 ZORD_RUN_BTIL - Redefined methods


METHOD fieldcheck.
*redefined to prevent system looking for unimplemented FM
*empty, create your own implementation
endmethod.




METHOD if_crm_runtime_btil~read_attributes.

  DATA: lr_root_container TYPE REF TO if_genil_container_object,
        lv_guid TYPE crmt_object_guid,
	lv_first TYPE crmt_boolean VALUE true,
        lv_relation  TYPE crmt_relation_name.

  DATA: lr_zord_i TYPE REF TO zord_struct_tab,
        lt_zord_i TYPE zord_struct_tab,
        lr_attr_props TYPE REF TO if_genil_obj_attr_properties,
        lr_cont_obj TYPE REF TO if_genil_container_object.

  FIELD-SYMBOLS: <ls_zord_i> TYPE zord_struct,
                 <ls_api_data>   TYPE crmt_intlay_get,
                 <lt_api_data>   TYPE crmt_intlay_get_tab.
***

    CALL METHOD zl_zord_btil_api=>zord_read
      EXPORTING
        iv_header_guid = iv_ref_guid "Order GUID
      IMPORTING
        et_zord        = lt_zord_i.

  CALL METHOD ir_cont_obj->get_parent_relation
    IMPORTING
      ev_relation_name = lv_relation.


  LOOP AT lt_zord_i ASSIGNING <ls_zord_i>.

    TRY.
        IF lv_first EQ true.
          lv_first = false.
          lr_cont_obj = ir_cont_obj.
          lr_cont_obj->set_key( <ls_zord_i>-guid ).
        ELSE.
          lr_cont_obj = ir_cont_obj->copy_self_with_structure(
                          is_object_key    = <ls_zord_i>-guid
                          iv_relation_name = lv_relation ).
          CHECK lr_cont_obj IS BOUND.
        ENDIF.
      CATCH cx_crm_cic_duplicate_entry.
        TRY.
            lr_cont_obj = me->turn_path( ir_cont_obj      = ir_cont_obj
                                         iv_relation_name = lv_relation
                                         is_key           = <ls_zord_i>-guid ).
          CATCH cx_crm_genil_general_error.
            CONTINUE.
        ENDTRY.
      CATCH cx_crm_genil_model_error.
        CONTINUE.
    ENDTRY.

    IF lr_cont_obj->check_attr_requested( ) EQ true.
      me->set_attributes( ir_cont_obj   = lr_cont_obj
                          is_attributes = <ls_zord_i>
                          iv_ref_kind   = iv_ref_kind
                          iv_log_key    = <ls_zord_i>-guid ).
      lr_attr_props = lr_cont_obj->get_attr_props_obj( ).
      lr_attr_props->set_all_properties( if_genil_obj_attr_properties=>changeable ).
      lr_attr_props->set_property_by_idx( iv_index  = 1
                                            iv_value = if_genil_obj_attr_properties=>read_only ). "Client
      lr_attr_props->set_property_by_idx( iv_index  = 2
                                            iv_value = if_genil_obj_attr_properties=>technical ). "GUID
      lr_attr_props->set_property_by_idx( iv_index  = 3
                                            iv_value = if_genil_obj_attr_properties=>technical ). "REF_GUID
    ENDIF.
    IF lr_cont_obj->check_rels_requested( ) EQ true.
      me->get_foreign_id( ir_cont_obj = lr_cont_obj
                          is_data     = <ls_zord_i> ).
    ENDIF.
  ENDLOOP.

ENDMETHOD.
*



METHOD if_crm_runtime_btil~maintain_attributes.
  INCLUDE crm_mode_con.
  DATA: lv_delta      TYPE crmt_delta.
  DATA: ls_changed_object TYPE crmt_genil_obj_instance.
  DATA: lt_names TYPE crmt_attr_name_tab.
  DATA: lr_attr_props TYPE REF TO if_genil_obj_attr_properties.
  FIELD-SYMBOLS: <ls_api_data> TYPE crmst_order_maintain,
                 <lv_name>     TYPE name_komp.
***
  DATA: lv_props_obj    TYPE REF TO if_genil_obj_attr_properties,
        lt_changed_attr TYPE crmt_attr_name_tab,
        ls_attributes   TYPE zord_struct,
        lv_guid         TYPE crmt_object_guid,
*        lt_return       TYPE bapiret2_t,
*        lv_msg_cont     TYPE REF TO cl_crm_genil_bapi_mess_cont,
        ls_obj_inst     TYPE crmt_genil_obj_instance,
        lv_header       TYPE REF TO if_genil_container_object,
        lv_header_guid  TYPE crmt_genil_object_guid,
        ls_header_attr   TYPE crmst_guid_btil.
  CHECK ir_cont_obj->get_name( ) = 'ZORD'.
  ls_obj_inst-object_name = 'ZORD'.                         "#EC NOTEXT
* retrieve the GUID of the header
  lv_header = ir_cont_obj->get_parent( ).
  CALL METHOD lv_header->get_key
    IMPORTING
      es_key = lv_header_guid.

  CALL METHOD lv_header->get_attributes
    IMPORTING
      es_attributes = ls_header_attr.

* retrieve the delta flag
  lv_delta = ir_cont_obj->get_delta_flag( ).
* branch according to the delta flag. Dependent objects may be created, modified, or deleted.
  CASE lv_delta.
    WHEN if_genil_cont_simple_object=>delta_changed.
*     retrieve the attribute property object to get the modify details
      lv_props_obj = ir_cont_obj->get_attr_props_obj( ).
*     which attributes were modified?
      CALL METHOD lv_props_obj->get_name_tab_4_property
        EXPORTING
          iv_property = if_genil_obj_attr_properties=>modified
        IMPORTING
          et_names    = lt_changed_attr.
      CALL METHOD ir_cont_obj->get_key
        IMPORTING
          es_key = lv_guid.
      CALL METHOD ir_cont_obj->get_attributes
        IMPORTING
          es_attributes = ls_attributes.

*     call the API
      CALL METHOD zl_zord_btil_api=>zord_modify
        EXPORTING
          is_key            = lv_guid
          iv_header_guid    = lv_header_guid
          is_attributes     = ls_attributes
          it_changed_fields = lt_changed_attr.
*          IMPORTING
*            et_return          = lt_return
*            et_changed_objects = lt_changed_objects.
      ls_obj_inst-object_id = cl_crm_genil_container_tools=>build_object_id( lv_guid ).
*     add object to the changed objects list
      INSERT ls_obj_inst INTO TABLE gr_intlay->gt_changed_objects.

    WHEN if_genil_cont_simple_object=>delta_created.
*     get the attribute structure
      CALL METHOD ir_cont_obj->get_attributes
        IMPORTING
          es_attributes = ls_attributes.
**     build the key
*      CALL FUNCTION 'GUID_CREATE'
*        IMPORTING
*          ev_guid_16 = lv_guid.
      ir_cont_obj->get_key( IMPORTING es_key = lv_guid ).
      ls_attributes-ref_guid = lv_header_guid.
*     call the API
      CALL METHOD zl_zord_btil_api=>zord_create
        EXPORTING
          is_key        = lv_guid
          is_attributes = ls_attributes.
*        IMPORTING
*          et_return     = lt_return.
      ls_attributes-guid = lv_guid.
      ir_cont_obj->set_attributes( ls_attributes ).

*       set new key
      TRY.
          ir_cont_obj->set_key( lv_guid ).
        CATCH cx_crm_genil_duplicate_key.
      ENDTRY.
      ls_obj_inst-object_id = cl_crm_genil_container_tools=>build_object_id( lv_guid ).
      INSERT ls_obj_inst INTO TABLE gr_intlay->gt_changed_objects.

    WHEN if_genil_cont_simple_object=>delta_deleted.
*     get object key
      CALL METHOD ir_cont_obj->get_key
        IMPORTING
          es_key = lv_guid.
*     call the API
      CALL METHOD zl_zord_btil_api=>zord_delete
        EXPORTING
          is_key         = lv_guid
          iv_header_guid = lv_header_guid.
*        IMPORTING
*          et_return          = lt_return
*          et_changed_objects = lt_changed_objects.
      ls_obj_inst-object_id = cl_crm_genil_container_tools=>build_object_id( lv_guid ).
      INSERT ls_obj_inst INTO TABLE gr_intlay->gt_changed_objects.
  ENDCASE.

*Tell the Order API that a change has happened
*This will register our object for save (The FM we registered for SAVE event in event handler table)
  CALL FUNCTION 'CRM_EVENT_PUBLISH_OW'
    EXPORTING
      iv_obj_name = 'ZORD'
      iv_guid_hi  = lv_header_guid
      iv_kind_hi  = gc_object_kind-orderadm_h
      iv_event    = gc_event-after_change.

ENDMETHOD.

Step 4 - Implement Event callback Function Modules

Remember the three event callback function modules that we registered in the transaction event handler table? Call the correct API methods inside each FM.

 1. Initialization

FUNCTION zord_init_ec.
*"----------------------------------------------------------------------
*"*"Local Interface:
*"  IMPORTING
*"     REFERENCE(IV_HEADER_GUID) TYPE  CRMT_OBJECT_GUID OPTIONAL
*"----------------------------------------------------------------------

  IF iv_header_guid IS NOT INITIAL.
    CALL METHOD ZL_ZORD_BTIL_API=>ZORD_INIT
      EXPORTING
        iv_header_guid = iv_header_guid.
  ENDIF.

ENDFUNCTION.
 

 2. Save

FUNCTION zord_save_ec.
*"----------------------------------------------------------------------
*"*"Local Interface:
*"  IMPORTING
*"     REFERENCE(IV_OBJECT_NAME) TYPE  CRMT_OBJECT_NAME
*"     REFERENCE(IV_EVENT_EXETIME) TYPE  CRMT_EVENT_EXETIME
*"     REFERENCE(IV_EVENT) TYPE  CRMT_EVENT
*"     REFERENCE(IT_HEADER_GUID) TYPE  CRMT_OBJECT_GUID_TAB
*"----------------------------------------------------------------------

Data: lv_header_guid type crmt_object_guid.

loop at it_header_guid into lv_header_guid.

  CALL METHOD ZL_ZORD_BTIL_API=>ZORD_SAVE
    EXPORTING
      iv_header_guid = lv_header_guid.

endloop.

ENDFUNCTION.
 


3. Delete

FUNCTION zord_del_ec.
*"----------------------------------------------------------------------
*"*"Local Interface:
*"  IMPORTING
*"     REFERENCE(IV_OBJECT_NAME) TYPE  CRMT_OBJECT_NAME
*"     REFERENCE(IV_EVENT_EXETIME) TYPE  CRMT_EVENT_EXETIME
*"     REFERENCE(IV_EVENT) TYPE  CRMT_EVENT
*"     REFERENCE(IV_HEADER_GUID) TYPE  CRMT_OBJECT_GUID OPTIONAL
*"----------------------------------------------------------------------

*Use FM "CRM_ORDERADM_H_READ_OB" with include_deleted_header option to ensure that object is relevant to us
* - before calling API method

  IF iv_header_guid IS NOT INITIAL.

*Delete from object buffer
    CALL METHOD ZL_ZORD_BTIL_API=>ZORD_INIT
      EXPORTING
        iv_header_guid = iv_header_guid.

*Delete from database
    CALL METHOD ZL_ZORD_BTIL_API=>ZORD_DELETE_WITH_ORDER
      EXPORTING
        iv_header_guid = iv_header_guid.

  ENDIF.

ENDFUNCTION.








Results:

Here are a few screens showing the results

Here's the table view after deleting line4 and save.

Related Content

http://wiki.sdn.sap.com/wiki/display/CRM/Create+a+Z+BOL+Object+Part+1
http://wiki.sdn.sap.com/wiki/display/CRM/How+to+display+a+z-table+in+an+assignment+block
http://wiki.sdn.sap.com/wiki/display/CRM/CRM+WebUI+--+Dynamic+table+type+Context+nodes

Useful Information

CRM - Extend BOL model BT with a custom relationship and link our z-table to it

18 Comments

  1. Update:

    Please follow this thread wherein there's an alternative specified for the standard method enhancements.

    http://forums.sdn.sap.com/thread.jspa?threadID=1667398&tstart=0

     I'm pasting the relevant contents below in case something happens to the thread.

    Hi Arun,

    Regarding your wiki entry:
    I had a short look at the path you propose.
    Step 1.
    I really like to see that in your system the node is named "Node text not found" as well (smile)
    You should propably mention that the customizing activity for defining relations is client dependent, while object definition is not. (One workaround would be to use the SAP table/maintenance view instead...)
    Step 3.
    You show some enhancements to standard SAP classes. My stomache always hurts when I see this kind of stuff. I would rather point everyone to use the order event customizing. The SAP part is readily available by TX CRMV_EVENT. However this would mean modifications to SAPs own data again. In the IMG in the "Transactions -> Basic Settings" you can put your custom function modules in "Edit Event Handler Table". Register them for the correspoding events and you are modification free. This approach runs very smooth for me for at least two year now.

    Good Wiki entry!

    cheers Carsten

    Hi Carsten,

    Thanks for pointing that out. That's why I mentioned "touch and dirty" in the wiki! The problem started with the read method CL_CRM_INTLAY_BTIL->READ_ORDERS. This expects only BTAdminH or BTAdminI objects as these are the only two standard access objects in the model, apart from the leasing query result. If any other custom access object shows up, it is not even processed. The attributes are not read and the end result is a dump as the BOL can't execute a reread after create. I tried to setup my object as a dependent object of BTAdminH to get past this point, but couldn't make it work. So, I'm still stuck with the read method having to make do with the enhancement.

    As rightly pointed out, with the use of the events table ( save and init for the ORDER object), we can avoid two of the enhancements.

    Regards,
    Arun Prakash

  2. Guest

    Very nice Wiki. Very useful for CRM 4 to CRM 7 upgrades because CRM 4 EEWB was not supporting table types.

  3. Thanks alot Arun for such a nice wiki.. i had similar requirement to implement and it has made my life easy..

    Sumit

  4. Guest

    Awesome blog... Nice.

  5. Wiki has been cleaned up. Now, there is no more need to enhance any of the standard classes. I expect some little things to be missing from the code samples such as constant declarations...I'm sure you will have no trouble getting around them. Have fun!

    Arun Prakash

  6. Guest

    Very nice blog!

    Is there any HowTo about other BOL models, e.g. CmgCase ? -> Extend BOL Model CmgCase with custom table type relationship

    TW

  7. Anonymous

    This is a remarkable stuff...Thanks...

  8. Hi, thanks for the blog, it has really helped me get up and running with getting my Z Table in to the WebUI.

    I do have a problem though and perhaps someone can clear it up.

    Creating new entries in the BOL Browser works great, but they cannot be modified. I make some change to an entity that I've created and then debug shows me that the call-back functions are executed in the order INIT, SAVE, INIT. Since in INIT we clear the global tables, by the time SAVE is executed there's nothing in the buffer to work with/save. Therefore modifications cannot occur, the same issue arrises for DELETE.

    Any one have any ideas about how this should be handled?

    Thanks,

    Patrick.

  9. Guest

    I need some help in setting and trigerring event.

    I am enhancing Service request and added a new AB there.

    I have maintained these entries but on save the FM is not called .Do we need to do anything extra which is not mentioned in the blog

    Trans. Category BUS20001     CRM Bus Transactions
    Execution Time  80    Save Document
    Priority        99
    Object Name     ZBTTIMER(Header extension )
    Event           SAVE
    Attribute       <*>
    Function        Z_TIMER_SAVE

  10. Former Member

    Hello Arun,

    You did exlent job. It really helped me.

    I also added a child page for this as extention to mantain child documents for the extended table.

    Regards

    Vijay

  11. Hi Arun,

    I followed the same , when I am creating the entry in Genil_Model_browser,  opportunity Guid is not updating in REF_GUID , as well  as main GUID is also not creating.

    I have used the BTAdminH as Bol entity  and used the Relationship fields in table view,

    once i added the code for Insert , it is giving the error BTAdminh not found and also.. Z relationship is not coming in Entity. If you have some time could you please tell me what i did mistake. regards , Ram

     

     

     

     

  12. Former Member

    Hi ,

    Very nice blog and useful , I have followed the same steps, but when ever make entry , neither ZORD_SET guid is saving in DB  nor the Line items are populatiing even though saved in databases .

     

    Regards

    Vikranth

     

     

  13. Former Member

     

    Hello,

    i have created the customizing and classes.
    I receive shortdump when i test reading from relation ZBTExternalCaseAll (relation to ZORD).
    I test via GENIL_BOL_BROWSER.

    this is the stack:

    METHOD    GET_DETAIL    CL_CRM_COMPONENT_SERVICE======CP
    METHOD    CONSTRUCTOR    CL_CRM_COMPONENT==============CP
    METHOD    CONSTRUCTOR    CL_CRM_MULTI_COMPONENT========CP
    METHOD    GET_INST    CL_CRM_MULTI_COMPONENT========CP
    METHOD    GET_INSTANCE    CL_CRM_COMPONENT==============CP
    FUNCTION    CRM_ORDER_READ_OW    SAPLCRM_ORDER_OW
    FUNCTION    CRM_ORDER_READ    SAPLCRM_ORDER_API
    METHOD    GET_DATA    CL_CRM_INTLAY_BTIL============CP

     

    In the top method the reason for dump is that this select returns nothing and exception is raised, because my object (ZORD) does not exist in the table crmc_objects_gen.

      SELECT SINGLE * FROM crmc_objects_gen
                      INTO CORRESPONDING FIELDS OF es_component_info
                      WHERE object_name = iv_object_name.
      if sy-subrc <> 0.
        raise not_found.
      endif.

    This table crmc_objects_gen should contain data for tables generated via AET only.
    I don't understand why my object is searched here since it is not created via AET.

    Please, help me to resolve this issue.

     

     

  14. Former Member

    Hello Rosen,

    I have encounted the same problem,that is,after i have followed the document to extent genil model,the code for dump is as following:

    SELECT SINGLE * FROM crmc_objects_gen
                      INTO CORRESPONDING FIELDS OF es_component_info
                      WHERE object_name = iv_object_name.
      if sy-subrc <> 0.
        raise not_found.
      endif.

    I don't know the reason.Please help me to resolve this issue.

  15. Former Member

    Hi,

    I'm getting dump while inserting entity (OBJECTS_OBJREF_NOT_ASSIGNED_NO) in MODIFY_CHILDREN of super class

    PDN

    1. Former Member

      Hi,

      Prev error have been solved, now i m not getting set of guids when calling ZBTExternalCaseSet

      PDN

      Thanks & Regards

      Kishan Rana

  16. Former Member

    Hi Arun,

    in the class, ZORD_RUN_BTIL 

    the method IF_CRM_RUNTIME_BTIL~MAINTAIN_ATTRIBUTES

    gc_object_kind and  gc_event will throw an error because corresponding includes are not added which are   INCLUDE crm_object_kinds_con  and INCLUDE crm_events

    after this , in case of  creating a new entry,

    I found

     CALL FUNCTION 'GUID_CREATE'
            IMPORTING
              ev_guid_16 lv_guid.

     is commented.

    and  i am not getting anything in lv_guid after performing below operation.

          ir_cont_obj->get_keyIMPORTING es_key lv_guid ).

    and my save method of ZL_ZORD_BTIL_API class  is also not triggered on clicking save.


    I have a doubt on the events in the fm below

     CALL FUNCTION 'CRM_EVENT_PUBLISH_OW'
        EXPORTING
          iv_obj_name 'ZORD'
          iv_guid_hi  lv_header_guid
          iv_kind_hi  gc_object_kind-orderadm_h
        iv_event    gc_event-after_change."gc_event-after_change.


    Please correct me because i am not able to see any entity inside my table ZORD


     

    1. Former Member

      Now i rectified all things. whatever i have mention above was correct and i rectified in my coding.

      i have created entries for custom events for transactions under  CRM->Transactions->Basic Settings->Edit event handler table.

      But it is not able to find inside  FM CRM_EVENT_PUBLISH_OW; it is not showing my events which i have created. though it is displaying in the Edit event handler table node.

      Can u please tell me the attributes for ZORD in CRMC_OBJECTS. If it is the reason!