Skip to Content
Technical Articles
Author's profile photo ian Salveson

S/4Hana – Revisiting the One Order framework in an OO landscape

Overview

Over the years SAP have introduced a number of different frameworks to support transactional processing, for example Business Object Layer(BOL), Business Object Processing Framework(BOPF) and the ABAP Restful Application Framework(RAP). While the new frameworks have introduced enhanced capabilities and greater flexibility to integrate with newer technologies they share some of the basic fundamental design principles with the CRM one order framework. At the heart of the CRM one order framework is the concept of caching data through the use of function module CRM_ORDER_MAINTAIN and saving the cached data to the data layer using CRM_ORDER_SAVE.

In the S/4Hana landscape there is no longer a sharp division between the capabilities available in say SAP CRM and the PSCD modules. The capabilities of both modules are available in order that more holistic solutions can be achieved combining the best features of transactional processing that exist in SAP CRM along with the strong financial capabilities in PSCD. If the one order framework is to be utilised in an S/4Hana landscape then it would be wise to ensure that a good OO design exists around the one order framework.

ABAP OO Design

The OO design as depicted in this article will be based on concepts such as clean ABAP and as such the design will have a strong reliance on the use of interfaces.

At the heart of the CRM one order framework are the following Function Modules CRM_ORDER_READ, CRM_ORDER_MAINTAIN and CRM_ORDER_SAVE. The basic design will involve creating an interface which includes methods to support the basic CRM capabilities. In the diagram below(diagram 1) there is an interface zif_oneorder_dao which consists of the basic one order operations such as read, modify and save. The operations of the interface are realised by implementing class zcl_oneorder_util. The new DAO class only supports the basic crm operations and doesn’t specify how the inputs to the one order framework are to set. A new utility class is created that determines how the inputs to the one order objects are to be populated. The new utility class has dependency on the oneorder DAO and any modify or save operation performed by the utility class will delegate its processing to the DAO class.

Diagram%201

Diagram 1

 

The DAO Interface

In the diagram below(diagram 2) the details of the DAO interface are shown. The signature of the modify method shows what entities can be created or modified, namely, order, appointments, status, text, partner, extref  and docflow. If there are any additional entities that need to be supported then the signature of the DAO interface definition can easily be amended to incorporate additional features.



interface ZIF_ONEORDER_DAO
  public .

  methods MODIFY
    importing
      !IT_PARTNER type CRMT_PARTNER_COMT optional
      !IT_TEXTS type CRMT_TEXT_COMT optional
      !IT_STATUS type CRMT_STATUS_COMT optional
      !IT_APPOINTMENTS type CRMT_APPOINTMENT_COMT optional
      !IT_EXT_REF type CRMT_EXT_REF_COMT optional
      !IT_EXTENSION2 type CRMT_EXTENSION2_COMT optional
    changing
      !CT_ORDERADM_H type CRMT_ORDERADM_H_COMT optional
      !CT_INPUT_FIELDS type CRMT_INPUT_FIELD_TAB optional
      !CT_DOC_FLOW type CRMT_DOC_FLOW_COMT optional
    returning
      value(RT_MESSAGE) type BAPIRET2_TAB .
  methods SAVE
    importing
      !IV_OBJECT_GUID type CRMT_OBJECT_GUID
    returning
      value(RT_MESSAGE) type BAPIRET2_TAB .
  methods READ
    importing
      !IV_OBJECT_GUID type CRMT_OBJECT_GUID
    returning
      value(RS_ONEORDER_ATTR) type ZS_ONEORDER_READ_ATTR .
  methods CREATE_GUID
    returning
      value(RV_OBJECT_GUID) type CRMT_OBJECT_GUID .
  methods COMMIT .
endinterface.

Diagram 2

 

The DAO Realisation

In the diagram below(refer diagram 3) the implementation details of the DAO read operation are shown. The read method populates  a deep structure, namely, RS_ONEORDER_ATTR which is based on structure ZS_ONEORDER_READ_ATTR(refer to diagram 4).

 

DAO Read


  METHOD zif_oneorder_dao~read.

    DATA ls_message   TYPE bapiret2.
    CALL FUNCTION 'CRM_ORDER_READ'
      EXPORTING
        it_header_guid       = VALUE crmt_object_guid_tab( ( iv_object_guid ) )
      IMPORTING
        et_orderadm_h        = rs_oneorder_attr-orderadm_h
        et_appointment       = rs_oneorder_attr-appointment
        et_text              = rs_oneorder_attr-text
        et_partner           = rs_oneorder_attr-partner
        et_status            = rs_oneorder_attr-status
        et_ext_ref           = rs_oneorder_attr-ext_ref
        et_doc_flow          = rs_oneorder_attr-doc_flow
        et_extension2        = rs_oneorder_attr-extension2
      EXCEPTIONS
        document_not_found   = 1
        error_occurred       = 2
        document_locked      = 3
        no_change_authority  = 4
        no_display_authority = 5
        no_change_allowed    = 6.
    IF sy-subrc <> 0.
      CALL FUNCTION 'BALW_BAPIRETURN_GET2'
        EXPORTING
          type   = sy-msgty
          cl     = sy-msgid
          number = sy-msgno
          par1   = sy-msgv1
          par2   = sy-msgv2
          par3   = sy-msgv3
          par4   = sy-msgv4
        IMPORTING
          return = ls_message.
      "      APPEND ls_message TO rt_message.
    ENDIF.
  ENDMETHOD.

Diagram 3

 


@EndUserText.label : 'Read of One order Object'
@AbapCatalog.enhancementCategory : #NOT_CLASSIFIED
define structure zs_oneorder_read_attr {
  orderadm_h  : crmt_orderadm_h_wrkt;
  partner     : crmt_partner_external_wrkt;
  appointment : crmt_appointment_wrkt;
  status      : crmt_status_wrkt;
  text        : crmt_text_wrkt;
  ext_ref     : crmt_ext_ref_wrkt;
  doc_flow    : crmt_doc_flow_wrkt;
  extension2  : crmt_extension2_wrkt;

}

Diagram 4

 

DAO Modify

In the diagram below(Diagram 5) the implementation details of the DAO modify operation are shown.



  METHOD zif_oneorder_dao~modify.
    DATA lt_exception TYPE crmt_exception_t.
    DATA ls_message   TYPE bapiret2.
    CALL FUNCTION 'CRM_ORDER_MAINTAIN'
      EXPORTING
        "        it_activity_h     = gt_activity_h
        it_appointment    = it_appointments
        it_text           = it_texts
        it_partner        = it_partner
        it_status         = it_status
        it_ext_ref        = it_ext_ref
        it_extension2     = it_extension2
      IMPORTING
        et_exception      = lt_exception
      CHANGING
        ct_orderadm_h     = ct_orderadm_h
        ct_input_fields   = ct_input_fields
        ct_doc_flow       = ct_doc_flow
      EXCEPTIONS
        error_occurred    = 1
        document_locked   = 2
        no_change_allowed = 3
        no_authority      = 4
        OTHERS            = 5.
    IF sy-subrc <> 0.
      CALL FUNCTION 'BALW_BAPIRETURN_GET2'
        EXPORTING
          type   = sy-msgty
          cl     = sy-msgid
          number = sy-msgno
          par1   = sy-msgv1
          par2   = sy-msgv2
          par3   = sy-msgv3
          par4   = sy-msgv4
        IMPORTING
          return = ls_message.
      APPEND ls_message TO rt_message.
    ENDIF.

*    IF lt_exception IS NOT INITIAL.
*      APPEND LINES OF get_messages_from_exception( lt_exception ) TO rt_message.
*    ENDIF.

  ENDMETHOD.

Diagram 5

 

DAO Save

In the diagram below(Diagram 6) the implementation details of the DAO save operation are shown.


  METHOD zif_oneorder_dao~save.
    DATA lt_saved_objects     TYPE crmt_return_objects.
    DATA lt_objects_not_saved TYPE crmt_object_guid_tab.
    DATA ls_message           TYPE bapiret2.

    CALL FUNCTION 'CRM_ORDER_SAVE'
      EXPORTING
        iv_update_task_local = abap_true
        it_objects_to_save   = VALUE crmt_object_guid_tab( ( iv_object_guid ) )
      IMPORTING
        et_saved_objects     = lt_saved_objects
        et_objects_not_saved = lt_objects_not_saved
      EXCEPTIONS
        document_not_saved   = 1
        OTHERS               = 2.
    IF sy-subrc <> 0.
      CALL FUNCTION 'BALW_BAPIRETURN_GET2'
        EXPORTING
          type   = sy-msgty
          cl     = sy-msgid
          number = sy-msgno
          par1   = sy-msgv1
          par2   = sy-msgv2
          par3   = sy-msgv3
          par4   = sy-msgv4
        IMPORTING
          return = ls_message.
      APPEND ls_message TO rt_message.
    ENDIF.

  ENDMETHOD.

Diagram 6

The Utility Interface

In the diagram below(diagram 7) the details of the UTIL interface are shown. The UTIL interface determines the operations that can be performed. In addition to the modify and save operations that exists on the DAO interface there exists operations to populate the details of one order entities, such as, set_order, set_partner, set_status, set_text, set_ext_ref, set_doc_flow, set_request_doc and set_opbel_doc.

It is expected that a class that makes use of the UTIL class will invoke methods such as set_order, set_partner, set_status and then invoke the modify and save methods. The details and purpose of the UTIL methods will be explained in more detail in the Utility Implementation section.


interface ZIF_ONEORDER_UTIL
  public .


  methods SET_ORDER
    importing
      !IV_OBJECT_GUID type CRMT_OBJECT_GUID optional
      !IV_PROCESS_TYPE type CRMT_PROCESS_TYPE_DB optional
      !IV_DESCRIPTION type CRMT_PROCESS_DESCRIPTION optional .
  methods SET_APPT_TYPE
    importing
      !IV_APPT_TYPE type CRMT_APPTYPE
      !IV_APPT_DATE type DATS .
  methods SET_PARTNER
    importing
      !IV_PARTNER_FCT type COMT_PARTNER_FCT
      !IV_PARTNER type CRMT_PARTNER_NO
      !IV_PARTNER_TYPE type CRMT_PARTNER_DISPLAY_TYPE default 'BP' .
  methods SET_STATUS
    importing
      !IV_STATUS type CRM_J_STATUS optional
      !IV_USER_STAT_PROC type CRM_J_STSMA optional .
  methods SET_EXT_REF
    importing
      !IV_EXT_REF_TYPE type CRMT_EXT_REF_TYPE default '0011'
      !IV_EXT_REF_NUMBER type CRMT_EXT_REF_NUMBER .
  methods SET_DOC_FLOW
    importing
      !IV_OBJECT_GUID type CRMT_OBJECT_GUID
      !IV_PARENT_IND type BOOLEAN .
  methods SET_OPBEL_DOC_FLOW
    importing
      !IV_OPBEL type OPBEL_KK .
  methods SET_REQUEST_DOC_FLOW
    importing
      !IV_REQUEST type ORDNR_KK .
  methods GET_TRANSACTION_GUID
    returning
      value(RV_TRANSACTION_GUID) type CRMT_OBJECT_GUID .
  methods GET_TRANSACTION_ID
    returning
      value(RV_TRANSACTION_ID) type CRMT_OBJECT_ID .
  methods MODIFY
    returning
      value(RT_MESSAGE) type BAPIRET2_TAB .
  methods SAVE
    returning
      value(RT_MESSAGE) type BAPIRET2_TAB .
  methods COMMIT .
endinterface.

Diagram 7

The Utility Implementation

UTIL constructor, modify and save methods

In the diagram below(Diagram 8) the implementation details of the UTIL constructor and the modify and save UTIL operations are shown.

The UTIL constructor utility shows that there is a dependency on two DAOs, the oneorder_dao and the orderadhm_dao(Diagram 10). The UTIL modify and save methods delegate processing to the DAO.( Note: the transaction id of the one order object is not available until the save has been executed the guid is know prior to any save).

The UTIL modify operation relies on details having being populated in a deep structure, namely, ms_oneorder_attr(diagram 8.1).The details of the deep structure are passed to the DAO modify operation.


  METHOD constructor.
    me->mr_oneorder_dao  = NEW zcl_oneorder_dao( ).
    me->mr_orderadmh_dao = NEW zcl_orderadmh_dao( ).
  ENDMETHOD.


  METHOD zif_oneorder_util~modify.
    rt_message = me->mr_oneorder_dao->modify( EXPORTING it_partner      = me->ms_oneorder_attr-partner
                                                        it_texts        = me->ms_oneorder_attr-texts
                                                        it_status       = me->ms_oneorder_attr-status
                                                        it_appointments = me->ms_oneorder_attr-appointment
                                                        it_ext_ref      = me->ms_oneorder_attr-ext_ref
                                              CHANGING
                                                        ct_orderadm_h   = me->ms_oneorder_attr-order
                                                        ct_input_fields = me->ms_oneorder_attr-input_fields
                                                        ct_doc_flow     = me->ms_oneorder_attr-doc_flow
                                                         ).


  ENDMETHOD.


  METHOD zif_oneorder_util~save.
    rt_message       = me->mr_oneorder_dao->save( me->mv_object_guid ).
    me->mv_object_id = me->mr_orderadmh_dao->get_object_id( me->mv_object_guid ).
  ENDMETHOD.

Diagram 8


@EndUserText.label : 'Structure of oneorder attributes'
@AbapCatalog.enhancementCategory : #NOT_CLASSIFIED
define structure zs_oneorder_attr {
  order        : crmt_orderadm_h_comt;
  partner      : crmt_partner_comt;
  texts        : crmt_text_comt;
  status       : crmt_status_comt;
  appointment  : crmt_appointment_comt;
  ext_ref      : crmt_ext_ref_comt;
  extension2   : crmt_extension2_comt;
  doc_flow     : crmt_doc_flow_comt;
  input_fields : crmt_input_field_tab;

}

Diagram 8.1

UTIL Set_order method

In the diagram below(Diagram 9) the implementation details of the UTIL set_order operation are shown.

The set_order method is used in either two modes, namely, a create mode or in a modify mode. If a guid is supplied then there is assumption that we are in a modify mode and the details of the existing one order transaction are retrieved using the DAO.

If no guid is supplied we switch to create a new mode and a new guid is created using the DAO. The details required to populate information for the orderadmH entity are retrieved from the orderadmH DAO. The object type details which needs to be populated for the orderadmH detail can be retrieved from the configuration details for the transaction type(diagram 10).


  METHOD zif_oneorder_util~set_order.
    DATA ls_orderadm_h    TYPE crmt_orderadm_h_com.

    IF iv_object_guid IS NOT INITIAL.
      me->ms_oneorder_existing_attr = me->mr_oneorder_dao->read( Iv_object_guid ).
      me->mv_object_guid            = VALUE #( ms_oneorder_existing_attr-orderadm_h[ 1 ]-guid OPTIONAL ).
      me->mv_partner_handle  = lines( ms_oneorder_existing_attr-partner ).
      me->mv_ext_ref_handle  = lines( ms_oneorder_existing_attr-ext_ref ).
      me->mv_doc_flow_handle = lines( ms_oneorder_existing_attr-doc_flow ).
      IF iv_process_type IS NOT INITIAL.
        IF VALUE #( ms_oneorder_existing_attr-orderadm_h[ 1 ]-process_type OPTIONAL ) <> iv_process_type.
          RETURN.
        ENDIF.
      ENDIF.
       me->mv_object_type  = VALUE #( ms_oneorder_existing_attr-orderadm_h[ 1 ]-object_type OPTIONAL ).
    ELSE.
      me->mv_object_guid           = me->mr_oneorder_dao->create_guid( ).
      ls_orderadm_h-guid           = me->mv_object_guid.
      ls_orderadm_h-process_type   = iv_process_type.
      ls_orderadm_h-mode           = me->gc_create_mode.
      ls_orderadm_h-description    = iv_description.
      ls_orderadm_h-descr_language = sy-langu.
      DATA(ls_process_detail)      = me->mr_orderadmh_dao->get_process_type_detail( iv_process_type ).
      me->mv_object_type           = ls_process_detail-object_type.

      INSERT ls_orderadm_h        INTO TABLE me->ms_oneorder_attr-order.

      INSERT VALUE #( objectname  = gc_object_name-orderadm_h
                      ref_guid    = me->mv_object_guid
                      ref_kind    = gc_object_kind-orderadm_h
                      field_names = VALUE crmt_input_field_names_tab( ( fieldname = |DESCRIPTION| ) )
                                                                       ) INTO TABLE me->ms_oneorder_attr-input_fields.
    ENDIF.
  ENDMETHOD.

Diagram 9

 


  METHOD zif_orderadmh_dao~get_process_type_detail.
    CALL FUNCTION 'CRM_ORDER_PROC_TYPE_SELECT_CB'
      EXPORTING
        iv_process_type      = iv_process_type
      IMPORTING
        es_proc_type         = rs_detail
      EXCEPTIONS
        entry_not_found      = 1
        text_entry_not_found = 2
        OTHERS               = 3.

  ENDMETHOD.

Diagram 10

UTIL Set Partner

In the diagram below(Diagram 11) the implementation details of the UTIL set_partner operation are shown. There are two inputs into the method, the partner function and the Business Partner id.


  METHOD zif_oneorder_util~set_partner.
    DATA ls_partner                 TYPE  crmt_partner_com.
    DATA lv_partner_handle_c(4)     TYPE c.

    CLEAR ls_partner.
    mv_partner_handle             = mv_partner_handle + 1.
    lv_partner_handle_c           = |{ CONV string( mv_partner_handle ) WIDTH = 4 ALPHA = IN }|.
    ls_partner-ref_guid           = me->mv_object_guid.
    ls_partner-ref_kind           = gc_object_kind-orderadm_h.
    ls_partner-ref_partner_handle = lv_partner_handle_c.
    ls_partner-kind_of_entry      = 'C'.
    ls_partner-partner_fct        = iv_partner_fct.
    ls_partner-partner_no         = iv_partner.
    ls_partner-display_type       = me->gc_bp_partner_type.
    ls_partner-no_type            = me->gc_bp_partner_type.
    INSERT ls_partner          INTO TABLE me->ms_oneorder_attr-partner.

    INSERT VALUE #( objectname  = gc_object_name-partner
                    ref_guid    = me->mv_object_guid
                    ref_kind    = gc_object_ref_kind-orderadm_h
                    logical_key = lv_partner_handle_c
                    field_names = VALUE crmt_input_field_names_tab( ( fieldname = |PARTNER_NO|    )
                                                                    ( fieldname = |PARTNER_FCT|   )
                                                                    ( fieldname = |DISPLAY_TYPE|  )
                                                                    ( fieldname = |NO_TYPE|       )
                                                                    ( fieldname = |KIND_OF_ENTRY| ) )
                   ) INTO TABLE me->ms_oneorder_attr-input_fields.

  ENDMETHOD.

Diagram 11

UTIL Set Status

In the diagram below(Diagram 12) the implementation details of the UTIL set_status operation are shown. The method requires a new status value to be supplied.


  METHOD zif_oneorder_util~set_status.
    DATA ls_status_com                 TYPE crmt_status_com.
    DATA lv_logical_key                TYPE crmt_logical_key.

    ls_status_com-ref_guid       = me->mv_object_guid.
    ls_status_com-ref_kind       = gc_object_kind-orderadm_h.
    ls_status_com-user_stat_proc = iv_user_stat_proc.
    ls_status_com-status         = iv_status.
    ls_status_com-activate       = abap_true.
    INSERT ls_status_com INTO TABLE me->ms_oneorder_attr-status.

    CONCATENATE iv_status iv_user_stat_proc INTO lv_logical_key.
    INSERT VALUE #( objectname  = gc_object_name-status
                    ref_guid    = me->mv_object_guid
                    ref_kind    = gc_object_ref_kind-orderadm_h
                    logical_key = lv_logical_key
                    field_names = VALUE crmt_input_field_names_tab( ( fieldname = |ACTIVATE|          ) )
*                                                                    ( fieldname = |STATUS|            )
*                                                                    ( fieldname = |USER_STAT_PROC|    )  )
                ) INTO TABLE me->ms_oneorder_attr-input_fields.
  ENDMETHOD.

Diagram 12

 

UTIL Set Appointment Method

In the diagram below(Diagram 13) the implementation details of the UTIL set_appointment operation are shown. The method can be used to either create or modify an existing appointment.


  METHOD zif_oneorder_util~set_appt_type.
    DATA ls_appointment       TYPE crmt_appointment_com.
    DATA lv_timestamp_e       TYPE crmt_date_timestamp_from.

    CLEAR ls_appointment.
    CONVERT DATE  iv_appt_date TIME sy-timlo INTO TIME STAMP lv_timestamp_e TIME ZONE sy-zonlo.

    DATA(lv_existing_row) = VALUE #( me->ms_oneorder_existing_attr-appointment[ appt_type = to_upper( iv_appt_type ) ] OPTIONAL ).

    ls_appointment-ref_guid         = me->mv_object_guid.
    ls_appointment-ref_kind         = gc_object_kind-orderadm_h.
    ls_appointment-timestamp_from   = lv_timestamp_e.
    ls_appointment-timezone_from    = sy-zonlo.
    ls_appointment-timestamp_to     = lv_timestamp_e.
    ls_appointment-timezone_to      = sy-zonlo.
    ls_appointment-appt_type        = to_upper( iv_appt_type ).
    ls_appointment-mode             = COND #( WHEN lv_existing_row IS INITIAL THEN me->gc_create_mode
                                                                              ELSE me->gc_update_mode ).
    INSERT ls_appointment          INTO TABLE me->ms_oneorder_attr-appointment.

    INSERT VALUE #( objectname      = gc_object_name-appointment
                    ref_guid        = me->mv_object_guid
                    ref_kind        = gc_object_ref_kind-orderadm_h
                    logical_key     = to_upper( iv_appt_type )
                    field_names = VALUE crmt_input_field_names_tab( ( fieldname = |TIMESTAMP_FROM| )
                                                                    ( fieldname = |TIMESTAMP_TO|   )
                                                                    ( fieldname = |APPT_TYPE|      )
                                                                    ( fieldname = |TIMEZONE_FROM|  )
                                                                    ( fieldname = |TIMEZONE_TO|    ) )
               ) INTO TABLE me->ms_oneorder_attr-input_fields.
  ENDMETHOD.

Diagram 13

UTIL Set Request Method

In the diagram below(Diagram 14) the implementation details of the UTIL set_request operation are shown.

In PSCD there is a concept of a request document, essentially, if there is a requirement to store financial document details but not realise this information until a later date then a request document cn be used to support this use case.
It possible to a create a relationship between a PSCD request(Object type CA_REQUEST) and a CRM one order transaction by storing a doc flow entity. The details below(Diagram 14) shows how to create a document flow between two objects whereby object A refers to the one order object and object B refers to the PSCD request document.

In we use CA_DOC instead of CA_REQUEST then a relationship can been created between a one order transaction and a PSCD document.


method ZIF_ONEORDER_UTIL~SET_REQUEST_DOC_FLOW.
    "this method to be used to forge connections between Enforcement actions and Debt Set
    DATA ls_doc_flow           TYPE crmt_doc_flow_com.
    DATA ls_doc_link           TYPE crmt_doc_flow_extd.

    "    INCLUDE crm_direct.

    me->mv_doc_flow_handle = me->mv_doc_flow_handle + 1.
    ls_doc_link-brel_mode  = me->gc_create_mode.
    ls_doc_link-reltype    = me->gc_predecessor_successor_rltyp.
    ls_doc_link-objkey_a   = me->mv_object_guid .
    ls_doc_link-objtype_a  = me->mv_object_type.

    ls_doc_link-objkey_b   = CONV #( iv_request ).
    ls_doc_link-objtype_b  = 'CA_REQUEST'.

    ls_doc_link-vona_kind       = gc_vona_kind_nocopy_update.
    ls_doc_link-brel_kind       = gc_object_kind-orderadm_h.
    ls_doc_link-relation_handle = me->mv_doc_flow_handle.

    ls_doc_flow-ref_kind        = gc_object_kind-orderadm_h.
    ls_doc_flow-ref_guid        = me->mv_object_guid.
    APPEND ls_doc_link         TO ls_doc_flow-doc_link.

    INSERT ls_doc_flow   INTO TABLE me->ms_oneorder_attr-doc_flow.

    INSERT VALUE #( objectname  = gc_object_name-doc_flow
                    ref_guid    = ls_doc_flow-ref_guid
                    ref_kind    = ls_doc_flow-ref_kind
                    logical_key = 'INS'
                    field_names = VALUE crmt_input_field_names_tab( ( fieldname = |OBJKEY_A|    )
                                                                    ( fieldname = |OBJTYPE_A|   )
                                                                    ( fieldname = |OBJKEY_B|    )
                                                                    ( fieldname = |OBJTYPE_B|   )
                                                                    ( fieldname = |VONA_KIND|             )
                                                                    ( fieldname = |BREL_KIND|   )
                                                                    ( fieldname = |BREL_MODE|   )
                                                                    ( fieldname = |RELTYPE|   )
                                                                    )
                         ) INTO TABLE me->ms_oneorder_attr-input_fields.
  endmethod.

Diagram 14

UTIL Set Ext_Ref

In the diagram below(Diagram 15) the implementation details of the UTIL set_ext_ref operation are shown. The methods has mainly been created to link an enforcement action transaction and a debt set.


METHOD zif_oneorder_util~set_ext_ref.

    DATA ls_ext_ref                 TYPE crmt_ext_ref_com.
    DATA lv_ext_ref_handle_c(4)     TYPE c.
    DATA lv_debt_set_number         TYPE dcm_debt_set_number_kk.
    DATA lv_logical_key             TYPE crmt_logical_key.

    CLEAR ls_ext_ref.
    mv_ext_ref_handle             = mv_ext_ref_handle + 1.
    lv_ext_ref_handle_c           = |{ CONV string( mv_ext_ref_handle ) WIDTH = 4 ALPHA = IN }|.

    ls_ext_ref-ref_guid           = me->mv_object_guid.
    ls_ext_ref-ref_kind           = gc_object_kind-orderadm_h.
    ls_ext_ref-handle             = lv_ext_ref_handle_c.
    ls_ext_ref-reference_type     = iv_ext_ref_type.
    IF iv_ext_ref_type = if_crms4_external_reference=>ext_ref_type-enforcement_action.
      lv_debt_set_number          =  CONV #(  iv_ext_ref_number ).
      ls_ext_ref-reference_number = |{ CONV string( lv_debt_set_number ) WIDTH = 12 ALPHA = IN }|.
      ls_ext_ref-guid             = me->mr_oneorder_dao->create_guid( ).
      lv_logical_key              = ls_ext_ref-guid.
    ELSE.
      ls_ext_ref-reference_number = iv_ext_ref_number.
      lv_logical_key              = lv_ext_ref_handle_c.
    ENDIF.
    ls_ext_ref-owner              = if_crms4_external_reference=>ext_ref_owner-sap.
    ls_ext_ref-reference_mode     = me->gc_create_mode.
    INSERT ls_ext_ref    INTO TABLE me->ms_oneorder_attr-ext_ref.

    INSERT VALUE #( objectname      = gc_object_name-ext_ref
                    ref_guid        = me->mv_object_guid
                    ref_kind        = gc_object_ref_kind-orderadm_h
                    logical_key     = lv_logical_key
                    field_names = VALUE crmt_input_field_names_tab( ( fieldname = |REFERENCE_TYPE|    )
                                                                    ( fieldname = |REFERENCE_NUMBER|  )
                                                                    ( fieldname = |OWNER|             ) )
                         ) INTO TABLE me->ms_oneorder_attr-input_fields.
  ENDMETHOD.

Diagram 15

UTIL Set Doc Flow

The details  below(Diagram 16) shows how to create relationships between two one order transactions at the orderadmH level. In this example one of the objects is expected to be of type BUS2000126(activity object type).



  METHOD zif_oneorder_util~set_doc_flow.
    "this method to be used to forge connections between Enforcement actions and an activity
    DATA ls_doc_flow           TYPE crmt_doc_flow_com.
    DATA ls_doc_link           TYPE crmt_doc_flow_extd.

    "    INCLUDE crm_direct.

    me->mv_doc_flow_handle = me->mv_doc_flow_handle + 1.
    ls_doc_link-brel_mode  = me->gc_create_mode.
    ls_doc_link-reltype    = me->gc_predecessor_successor_rltyp.
    ls_doc_link-objkey_a   = COND #( WHEN Iv_parent_ind EQ abap_true
                                       THEN iv_object_guid
                                       ELSE me->mv_object_guid ).
    ls_doc_link-objtype_a  = COND #( WHEN Iv_parent_ind EQ abap_true
                                       THEN me->mr_orderadmh_dao->get_object_type( iv_object_guid )
                                       ELSE me->mr_orderadmh_dao->get_object_type( me->mv_object_guid ) ).
    if ls_doc_link-objtype_a is initial.
      ls_doc_link-objtype_a = 'BUS2000126'.
    endif.



    ls_doc_link-objkey_b   = COND #( WHEN Iv_parent_ind EQ abap_true
                                       THEN mv_object_guid
                                       ELSE iv_object_guid ).
    ls_doc_link-objtype_b  = COND #( WHEN Iv_parent_ind EQ abap_true
                                       THEN me->mr_orderadmh_dao->get_object_type( mv_object_guid )
                                       ELSE me->mr_orderadmh_dao->get_object_type( iv_object_guid ) ).
    if ls_doc_link-objtype_b is initial.
      ls_doc_link-objtype_b = 'BUS2000126'.
    endif.

    ls_doc_link-vona_kind       = gc_vona_kind_nocopy_update.
    ls_doc_link-brel_kind       = gc_object_kind-orderadm_h.
    ls_doc_link-relation_handle = me->mv_doc_flow_handle.

    ls_doc_flow-ref_kind        = gc_object_kind-orderadm_h.
    ls_doc_flow-ref_guid        = ls_doc_link-objkey_b.
    APPEND ls_doc_link         TO ls_doc_flow-doc_link.

    INSERT ls_doc_flow   INTO TABLE me->ms_oneorder_attr-doc_flow.

    INSERT VALUE #( objectname  = gc_object_name-doc_flow
                    ref_guid    = ls_doc_flow-ref_guid
                    ref_kind    = ls_doc_flow-ref_kind
                    logical_key = 'INS'
                    field_names = VALUE crmt_input_field_names_tab( ( fieldname = |OBJKEY_A|    )
                                                                    ( fieldname = |OBJTYPE_A|   )
                                                                    ( fieldname = |OBJKEY_B|    )
                                                                    ( fieldname = |OBJTYPE_B|   )
                                                                    ( fieldname = |VONA_KIND|             )
                                                                    ( fieldname = |BREL_KIND|   )
                                                                    ( fieldname = |BREL_MODE|   )
                                                                    ( fieldname = |RELTYPE|   )
                                                                    )
                         ) INTO TABLE me->ms_oneorder_attr-input_fields.
  ENDMETHOD.

Diagram 16

Using the One Order Utility

At this stage we have demonstrated how a UTIL and a DAO can form the basis of an OO design for one order processing. We now want to explore how the UTIL class itself can be used. In this section we will create a new interface and implementation that shows how an enforcement action can be created using the UTIL class.

In the diagram below(diagram 17) we show how the new EA interface and implementation relate to the UTIL class.

 

Diagram%2017

Diagram 17

Enforcement Action(EA) Interface

In the diagram below(diagram 18) the details of the EA interface are shown.


interface ZIF_EA_ABC
  public .

  methods CREATE
    importing
      !IV_DOCUMENT_NUMBER type OPBEL_KK
      !IV_DESCRIPTION type CRMT_PROCESS_DESCRIPTION
      !IV_START_DATE type DATS default SY-DATUM
      !IV_END_DATE type DATS optional
      !IV_DEBTOR type CRMT_PARTNER_NO
      !IV_DEBT_SET_NUMBER type DCM_DEBT_SET_NUMBER_KK optional
    returning
      value(RT_MESSAGE) type BAPIRET2_TAB .
  methods SAVE
    returning
      value(RT_MESSAGE) type BAPIRET2_TAB .
  methods COMMIT .
  methods GET_TRANSACTION_GUID
    returning
      value(RV_TRANSACTION_GUID) type CRMT_OBJECT_GUID .
endinterface.

Diagram 18

Enforcement Action Create

In the diagram below(Diagram 19) the implementation details of the EA create operation are shown. The various method from the UTIL class are used to populate details for the one order transaction and then the UTIL create is called which will create details in cached memory.

In the system a new transaction type(ZABC) has been created using the DMEA template and the create method below shows how a link can be established between the enforcement action transaction and a debt set.

Process Type: ZABC(enforcement action)
partner_fct: DMNDEBTOR
appt_type: DMEASTART, DMEAEND
status_profile: ZABCSTAT


  METHOD zif_ea_abc~create.

    mr_oneorder_util->set_order( iv_process_type = 'ZABC' iv_description  = iv_description ).

    mr_oneorder_util->set_appt_type( iv_appt_type    = 'DMEASTART'
                                     iv_appt_date    = iv_start_date ).

    IF iv_end_date IS NOT INITIAL.
      mr_oneorder_util->set_appt_type( iv_appt_type    = 'DMEAEND'
                                       iv_appt_date    = iv_end_date ).
    ENDIF.

    mr_oneorder_util->set_partner( iv_partner     = iv_debtor
                                   iv_partner_fct = 'DMDEBTOR' ).

    IF iv_debt_set_number IS NOT INITIAL.
      mr_oneorder_util->set_ext_ref( iv_ext_ref_number = CONV #( iv_debt_set_number ) ).
    ENDIF.


    mr_oneorder_util->set_opbel_doc_flow( iv_document_number ).
    "set the status to determined
    mr_oneorder_util->set_status( iv_status = 'E0013' iv_user_stat_proc = 'ZABCSTAT' ).

    rt_message = mr_oneorder_util->modify( ).
  ENDMETHOD.

Diagram 19

Enforcement action Save

In the diagram below(Diagram 20) the implementation details of the EA save operation are shown.



  METHOD zif_ea_abcc~save.
    rt_message = mr_oneorder_util->save( ).
  ENDMETHOD.

Diagram 20

Conclusion

With the the merging of CRM and PSCD capabilities in the S/4Hana landscape it is imperative to ensure that a sound OO design exists in order to reduce overall technical debt. It has been demonstrated in the article that with some simple design concepts such as a DAO and a Utility class the even older style processes such as the one order framework can be reborn and revitalised. The revitalised remodeling of the one order object framework means that older style processing can readily be implemented into newer frameworks such as the ABAP Restful application framework.

Please feel free to supply comments and thoughts on this blog. The following links may also be of benefit to readers.

https://community.sap.com/topics/abap
https://blogs.sap.com/tags/833755570260738661924709785639136/
https://answers.sap.com/tags/833755570260738661924709785639136

Assigned Tags

      Be the first to leave a comment
      You must be Logged on to comment or reply to a post.