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.
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.
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