Method to exchange Business Partner in Business Transactions on DB level which is working for closed documents as well

*Parameters:
*IV_HEADER_GUID	TYPE CRMT_OBJECT_GUID	| GUID of a CRM Order Object
*IV_BP_OLD	    TYPE BPARTNER	| Business Partner
*IV_BP_NEW	    TYPE BPARTNER	| Business Partner
*ERROR_OCCURRED	     Something happened

METHOD exchange_partner_db.

  DATA:
    lv_partner_guid   TYPE but000-partner_guid,
    lv_partner_number TYPE but000-partner,
    lv_partner_id     TYPE but000-partner,

    lt_crmd_partner     TYPE TABLE OF crmd_partner,
    lt_crmd_order_index TYPE TABLE OF crmd_order_index,

    lv_addr_nr          TYPE  adrnr,
    lv_addr_np          TYPE  adrnp,
    lv_addr_type        TYPE  addr_type,
    lv_addr_origin      TYPE  comt_addr_origin,
    lv_addr_operation   TYPE  bu_operation,
    lv_relation_partner TYPE  bu_partner_guid,
    lv_addr_is_standard TYPE  comt_partner_std_bp_address.

  FIELD-SYMBOLS:
    <fs_partner> LIKE LINE OF lt_crmd_partner,
    <fs_order_index> LIKE LINE OF lt_crmd_order_index.

*-------------------------------------------------------------------------
*Get partner identifications of old partner.

  SELECT SINGLE partner_guid
    INTO lv_partner_guid
    FROM but000
    WHERE partner = iv_bp_old.

  SELECT SINGLE partner
    INTO lv_partner_number
    FROM but000
    WHERE partner = iv_bp_old.

  IF lv_partner_number IS NOT INITIAL.
    CALL FUNCTION 'CONVERSION_EXIT_ALPHA_OUTPUT'
      EXPORTING
        input  = lv_partner_number
      IMPORTING
        output = lv_partner_id.
  ENDIF.

  IF lv_partner_guid IS INITIAL OR lv_partner_number IS INITIAL.
*Partner number &1 is invalid.
    MESSAGE e050(/glb/9gtis_solman) WITH iv_bp_old RAISING error_occurred.
  ENDIF.

*-------------------------------------------------------------------------

*Select partner dataset for header.
  SELECT *
    INTO TABLE lt_crmd_partner
    FROM crmd_partner
    WHERE partner_guid IN ( SELECT p~partner_guid
                              FROM crmd_partner AS p
                                   JOIN crmd_link AS l ON ( l~guid_set = p~guid AND l~objtype_hi = '05' AND l~objtype_set = '07' )
                                   JOIN crmd_orderadm_h AS h ON ( l~guid_hi = h~guid )
                              WHERE h~guid = iv_header_guid AND
                                    ( p~partner_no = lv_partner_guid OR
                                    p~partner_no = lv_partner_number OR
                                    p~partner_no = lv_partner_id ) AND
                                    ( p~no_type = '  ' OR p~no_type = 'BP' )
                          ).

*Select partner dataset for item.
  SELECT *
    APPENDING TABLE lt_crmd_partner
    FROM crmd_partner
    WHERE partner_guid IN ( SELECT p~partner_guid
                              FROM crmd_partner AS p
                                   JOIN crmd_link AS l ON ( l~guid_set = p~guid AND l~objtype_hi = '06' AND l~objtype_set = '07' )
                                   JOIN crmd_orderadm_i AS i ON ( l~guid_hi = i~guid )
                              WHERE i~header     = iv_header_guid AND
                                    ( p~partner_no = lv_partner_guid OR
                                    p~partner_no = lv_partner_number OR
                                    p~partner_no = lv_partner_id ) AND
                                    ( p~no_type = '  ' OR p~no_type = 'BP' )
                          ).

  IF lt_crmd_partner IS INITIAL.
*Dataset not found in CRMD_PARTNER.
    MESSAGE e051(/glb/9gtis_solman) WITH iv_bp_old RAISING error_occurred.
  ENDIF.

*Select index dataset for header or item.
  SELECT *
    INTO TABLE lt_crmd_order_index
    FROM crmd_order_index
    WHERE header = iv_header_guid AND
          ( partner_no = lv_partner_number OR
          partner_no = lv_partner_id ).

*-------------------------------------------------------------------------
*Get partner identifications of new partner.

*Get Partner GUID.
  CALL FUNCTION 'COM_PARTNER_CONVERT_GUID_TO_NO'
    EXPORTING
      iv_partner             = iv_bp_new
    IMPORTING
      ev_partner_guid        = lv_partner_guid
    EXCEPTIONS
      partner_does_not_exist = 1
      OTHERS                 = 2.

  IF sy-subrc <> 0.
*Partner number &1 is invalid.
    MESSAGE e050(/glb/9gtis_solman) WITH iv_bp_new RAISING error_occurred.
  ENDIF.

*Get Address data.
  CALL FUNCTION 'COM_PARTNER_ADDRESS_DETERMINE'
    EXPORTING
      iv_partner                 = iv_bp_new
*     iv_std_addr_only           = 'X'
    IMPORTING
      ev_addr_nr                 = lv_addr_nr
      ev_addr_np                 = lv_addr_np
      ev_addr_type               = lv_addr_type
      ev_addr_origin             = lv_addr_origin
      ev_addr_operation          = lv_addr_operation
      ev_relation_partner        = lv_relation_partner
      ev_addr_is_standard        = lv_addr_is_standard
    EXCEPTIONS
      partner_not_defined        = 1
      partner_does_not_exist     = 2
      rel_partner_does_not_exist = 3
      no_address_found           = 4
      OTHERS                     = 5.

  IF sy-subrc <> 0.
*No address data for partner &1 found.
*    MESSAGE e052(/glb/9gtis_solman) WITH iv_bp_new RAISING error_occurred.
  ENDIF.

*-------------------------------------------------------------------------

*Exchange partner.
  LOOP AT lt_crmd_partner ASSIGNING <fs_partner>.

*Exchange partner
    <fs_partner>-partner_no = lv_partner_guid.
    <fs_partner>-no_type = '  '. "Now key is a GUID
    <fs_partner>-display_type = 'BP'. "Enrure that partner is shown as BP

*Exchange address.
    IF <fs_partner>-addr_origin = 'A' OR <fs_partner>-addr_origin = 'C' OR <fs_partner>-addr_origin IS INITIAL.
      <fs_partner>-addr_nr        = lv_addr_nr.
      <fs_partner>-addr_np        = lv_addr_np.
      <fs_partner>-addr_type      = lv_addr_type.
      <fs_partner>-addr_origin    = lv_addr_origin.
      <fs_partner>-addr_operation = lv_addr_operation.
      <fs_partner>-relation_partner = lv_relation_partner.
      <fs_partner>-std_bp_address = lv_addr_is_standard.
    ENDIF.

  ENDLOOP.

*Correct index table used by reporting.
  LOOP AT lt_crmd_order_index ASSIGNING <fs_order_index>.

    <fs_order_index>-partner_no = iv_bp_new.

  ENDLOOP.

*-------------------------------------------------------------------------
*Save data to database.

  UPDATE crmd_partner FROM TABLE lt_crmd_partner[].
  UPDATE crmd_order_index FROM TABLE lt_crmd_order_index[].

ENDMETHOD.