cancel
Showing results for 
Search instead for 
Did you mean: 
Read only

RestFul Application Programming Model(RAP) Unmanaged Implementation Error handling

shubham_banerjee
Participant
0 Kudos
5,702

Hi Experts,

I have done my first RAP implementation which is an unmanaged implementation and the service is responsible to update Business Partner Name and Address data. I want to send, a message back upon successful update or failed. I am able to do the same using the structures "mapped" for success and "reported" for failure from within the FINALIZE( ) method for BAPI_BUPA_CENTRAL_CHANGE. However while trying to update the Address using BAPI_BUPA_ADDRESS_CHANGE, it gives a dump like following,

-------------------------------------------------------------------------------------------------------------------------------------------------------------

BEHAVIOR_ILLEGAL_STATEMENT

Short Text

Statement "CALL FUNCTION .. IN UPDATE TASK" is not allowed with this status.

There is probably an error in the program "SAPLSZA0". A BEHAVIOR implementation is active for "ZC_UPD_BP_FROM_XXX". While this is the case, the following ABAP statements are illegal:

The following statement is only allowed in the "Save” phase: - CALL FUNCTION IN UPDATE TASK Quitting the BEHAVIOR implementation with RAISE EXCEPTION is illegal.

-------------------------------------------------------------------------------------------------------------------------------------------------------------

However the same doesn't happen if the implementation is done within SAVE( ) method. But, save( ) doesn't have parameters to send back any message.

Request for your support in resolving this issue and help me knowing how can I send back a message either using save( ) or avoid the dump using finalize( ).

Interface View:

@AbapCatalog.sqlViewName: 'ZI_XXX_UPD_BP'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Int. view to update BP data'
@VDM.viewType: #BASIC
define view zi_upd_bp_from_xxx
  as select from    but000
    left outer join but020 on but000.partner = but020.partner
    left outer join adrc   on but020.addrnumber = adrc.addrnumber
{
  key       but000.partner      as bpNum,
  key       but000.type         as bpType,
            but000.partner_guid as bpGuid,
            adrc.addrnumber     as addressNo,
            but000.title        as title,
            but000.name_last    as lastName,
            but000.name_first   as firstName,
            but000.name_org1    as nameI,
            but000.name_org2    as nameII,
            but000.name_org3    as nameIII,
            adrc.city1          as city,
            adrc.street         as street,
            adrc.country        as country,
            adrc.post_code1     as postalCode,
            adrc.house_num1     as houseNumber
}
where
  adrc.nation is initial

Consumption View:

@AbapCatalog.sqlViewName: 'ZC_XXX_UPD_BP'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Cons. view to update BP data'
define root view ZC_UPD_BP_FROM_XXX
  as select from zi_upd_bp_from_xxx
{
  key bpNum,
      bpType,
      bpGuid,
      addressNo,
      title,
      lastName,
      firstName,
      nameI,
      nameII,
      nameIII,
      nameAffix,
      academicTitle1,
      academicTitle2,
      city,	  
      street,
      country,
      postalCode,
      houseNumber
}

Behavior Definition:

unmanaged implementation in class zcl_upd_bp_from_xxx unique;

define behavior for ZC_UPD_BP_FROM_XXX alias XxxUpdBP
//late numbering
//lock master
//authorization master
//etag <field_name>
{
  field ( mandatory ) bpNum, bpType;
  update;
}

Service Definition:

@EndUserText.label: 'Service Definition to update BP'
define service ZUI_XXX_UPD_BP {
  expose ZC_UPD_BP_FROM_XXX;
}

Behavior Implementation:

CLASS lcl_buffer DEFINITION .
  PUBLIC SECTION .
    TYPES: BEGIN OF tys_control,
             cid TYPE abp_behv_cid,
             msg TYPE REF TO if_abap_behv_message,
           END OF tys_control .
    CLASS-DATA gs_buffer TYPE zc_upd_bp_from_xxx .
    CLASS-DATA gs_control TYPE tys_control .
ENDCLASS.

CLASS lcl_XxxUpdBP DEFINITION INHERITING FROM cl_abap_behavior_handler.
  PRIVATE SECTION.
    METHODS update FOR MODIFY
      IMPORTING entities FOR UPDATE XXXUpdBP.
    METHODS read FOR READ
      IMPORTING keys FOR READ XXXUpdBP RESULT result.
ENDCLASS.
CLASS lcl_xxxUpdBP IMPLEMENTATION.


  METHOD update.
  ENDMETHOD.

  METHOD read.
  ENDMETHOD.
ENDCLASS.

CLASS lcl_ZC_UPD_BP_FROM_XXX DEFINITION INHERITING FROM cl_abap_behavior_saver.
  PROTECTED SECTION.
    METHODS check_before_save REDEFINITION.
    METHODS finalize          REDEFINITION.
    METHODS save              REDEFINITION.
    METHODS fill_address
      IMPORTING !is_entities TYPE zc_upd_bp_from_xxx
      EXPORTING !es_address  TYPE bapibus1006_address .


    METHODS fill_address
      IMPORTING !is_entities TYPE zc_upd_bp_from_xxx
      EXPORTING !es_address  TYPE bapibus1006_address .

    METHODS gt_bp_data
      IMPORTING !iv_partner    TYPE bu_partner
      EXPORTING !ev_bptype     TYPE bu_type
                !ev_bpguid     TYPE bu_partner_guid
                !ev_bpadrnr    TYPE ad_addrnum
                !ev_bpaddrguid TYPE ad_uuid .

    METHODS call_bapi
      IMPORTING
        !is_buffer TYPE zc_upd_bp_from_xxx .
ENDCLASS.

CLASS lcl_ZC_UPD_BP_FROM_XXX IMPLEMENTATION.
  METHOD check_before_save.
  ENDMETHOD.

  METHOD finalize.
      me->call_bapi( EXPORTING is_buffer = lcl_buffer=>gs_buffer ) .
**    DATA ls_message TYPE symsg.
**    DATA: li_mapper_symsg TYPE REF TO if_rap_plmi_sy_msg_convert,
**          li_message_behv TYPE REF TO if_abap_behv_message.
*
**    ls_message = VALUE #( msgid = ' ' msgty = 'E' msgno = ' ' msgv1 = ' ' ).
**    CALL METHOD li_mapper_symsg->map_symsg_to_behv_message
**      EXPORTING
**        is_message_symsg = ls_message
**      RECEIVING
**        ro_message_behv  = li_message_behv.
**    INSERT VALUE #( %msg = li_message_behv bpnum = '2200000045'  ) INTO TABLE reported-xxxupdbp.
  ENDMETHOD.

  METHOD save.
  ENDMETHOD.

  METHOD fill_address .
    es_address-city         = is_entities-city .
    es_address-room_no      = is_entities-room .
    es_address-floor        = is_entities-floor .
    es_address-po_box       = is_entities-poBox .
    es_address-c_o_name     = is_entities-coName .
    es_address-region       = is_entities-region .
    es_address-street       = is_entities-street .
    es_address-location     = is_entities-co2Name .
    es_address-country      = is_entities-country .
    es_address-po_w_o_no    = is_entities-poWoNum .
    es_address-str_suppl1   = is_entities-street2 .
    es_address-str_suppl3   = is_entities-street4 .
    es_address-building     = is_entities-building .
    es_address-district     = is_entities-district .
    es_address-postl_cod1   = is_entities-postalCode .
    es_address-house_no     = is_entities-houseNumber .
    es_address-postl_cod2   = is_entities-poBoxPostalCode .
    es_address-house_no2    = is_entities-houseNumberSuppl .
    es_address-postl_cod3   = is_entities-companyPostalCode .
    es_address-dont_use_p   = is_entities-unDeliverablePoBox .
    es_address-dont_use_s   = is_entities-unDeliverableStreet .
  ENDMETHOD .


  METHOD call_bapi.
    DATA: ls_address  TYPE bapibus1006_address,
          ls_entities TYPE zc_upd_bp_from_xxx.

    ls_entities = CORRESPONDING #( lcl_buffer=>gs_buffer ) .
    me->fill_address( EXPORTING is_entities = ls_entities IMPORTING es_address = ls_address ) .

    DATA(lo_execute) = NEW zcl_rap_crud_operation(  ) .
    DATA(lt_ret) = lo_execute->change( EXPORTING iv_partner = lcl_buffer=>gs_buffer-bpNum
                                                 iv_adrnrguid = lv_addrguid
                                                 is_address = ls_address ) .

  ENDMETHOD.

CLASS zcl_rap_crud_operation DEFINITION
    PUBLIC
    FINAL
    CREATE PUBLIC .

  PUBLIC SECTION.
    TYPES: tyt_person       TYPE bapibus1006_central_person,
           tyt_organisation TYPE bapibus1006_central_organ,
           tyt_telephone    TYPE bapibus1006_adtel_tty,
           tyt_smtp         TYPE bapibus1006_adsmtp_tty,
           BEGIN OF tys_central,
             person       TYPE tyt_person,
             organisation TYPE tyt_organisation,
           END OF tys_central,
           tyt_central TYPE TABLE OF tys_central WITH EMPTY KEY,
           BEGIN OF tys_comm,
             telephone TYPE tyt_telephone,
             smtp      TYPE tyt_smtp,
           END OF tys_comm,
           tyt_comm TYPE TABLE OF tys_comm WITH EMPTY KEY.


    METHODS:
      constructor,
      change
        IMPORTING
                  !iv_partner      TYPE bu_partner
                  !iv_adrnrguid    TYPE ad_uuid OPTIONAL
                  !is_central      TYPE bapibus1006_central OPTIONAL
                  !is_name         TYPE tyt_central OPTIONAL
                  !is_address      TYPE bapibus1006_address OPTIONAL
                  !it_comm         TYPE tyt_comm OPTIONAL
        RETURNING VALUE(rt_return) TYPE bapiret2_t.
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.

CLASS zcl_rap_crud_operation IMPLEMENTATION.
  METHOD constructor.
  ENDMETHOD.

  METHOD change.
    DATA: lt_persaddr   TYPE bapiad1vd_t,
          lt_persaddr_x TYPE bapiad1vdx_t,
          lt_orgaddr    TYPE bapiad2vd_t,
          lt_orgaddr_x  TYPE bapiad2vdx_t,
          ls_address_x  TYPE bapibus1006_address_x,
          ls_org        TYPE bapibus1006_central_organ,
          ls_pers       TYPE bapibus1006_central_person,
          ls_org_x      TYPE bapibus1006_central_organ_x,
          ls_pers_x     TYPE bapibus1006_central_person_x,
          lt_return     TYPE bapiret2_t.


    CLEAR: ls_org, ls_org_x, ls_pers, ls_pers_x, lt_return .
    IF NOT is_name IS INITIAL .
      IF NOT is_name[ 1 ]-organisation IS INITIAL .                           
        ls_org-name1 = is_name[ 1 ]-organisation-name1 .
        ls_org-name2 = is_name[ 1 ]-organisation-name2 .
        ls_org-name3 = is_name[ 1 ]-organisation-name3 .

        ls_org_x-name1 = COND #( WHEN is_name[ 1 ]-organisation-name1 IS NOT INITIAL THEN abap_true ELSE abap_false ) .
        ls_org_x-name2 = COND #( WHEN is_name[ 1 ]-organisation-name2 IS NOT INITIAL THEN abap_true ELSE abap_false ) .
        ls_org_x-name3 = COND #( WHEN is_name[ 1 ]-organisation-name3 IS NOT INITIAL THEN abap_true ELSE abap_false ) .
      ELSEIF NOT is_name[ 1 ]-person IS INITIAL .
        ls_pers-firstname = is_name[ 1 ]-person-firstname .
        ls_pers-lastname  = is_name[ 1 ]-person-lastname .

        ls_pers_x-firstname = COND #( WHEN is_name[ 1 ]-person-firstname IS NOT INITIAL THEN abap_true ELSE abap_false ) .
        ls_pers_x-lastname  = COND #( WHEN is_name[ 1 ]-person-lastname  IS NOT INITIAL THEN abap_true ELSE abap_false ) .
      ENDIF.

      CALL FUNCTION 'BAPI_BUPA_CENTRAL_CHANGE'
        EXPORTING
          businesspartner           = iv_partner
          centraldata               = is_central
          centraldataperson         = ls_pers
          centraldataorganization   = ls_org
          centraldataperson_x       = ls_pers_x
          centraldataorganization_x = ls_org_x
          valid_date                = sy-datlo
        TABLES
          return                    = rt_return.
      IF rt_return IS INITIAL .
      ENDIF.
    ENDIF.                                                                                           


    IF NOT is_address IS INITIAL .
      ls_address_x-city         = COND #( WHEN is_address-city          IS NOT INITIAL THEN abap_true ELSE abap_false ) .
      ls_address_x-street       = COND #( WHEN is_address-street        IS NOT INITIAL THEN abap_true ELSE abap_false ) .
      ls_address_x-postl_cod1   = COND #( WHEN is_address-postl_cod1    IS NOT INITIAL THEN abap_true ELSE abap_false ) .
      ls_address_x-country      = COND #( WHEN is_address-country       IS NOT INITIAL THEN abap_true ELSE abap_false ) .
      ls_address_x-house_no     = COND #( WHEN is_address-house_no      IS NOT INITIAL THEN abap_true ELSE abap_false ) .

      CALL FUNCTION 'BAPI_BUPA_ADDRESS_CHANGE'
        EXPORTING
          businesspartner = iv_partner
          addressdata     = is_address
          addressdata_x   = ls_address_x
        TABLES
          return          = rt_return.
      IF NOT line_exists( rt_return[ type = 'E' ] ) OR NOT line_exists( rt_return[ type = 'A' ] ) .

      ENDIF.
    ENDIF.
  ENDMETHOD.

JSON URL: /sap/opu/odata/sap/ZUI_XXX_UPD_BP/ZC_UPD_BP_FROM_XXX

JSON Payload:

{
    "d": {
        "results": [
            {
                "bpNum": "11",
                "bpType": "1",
                "bpGuid": "xxxx-xxxx-xxxx-xxxx-xxxx",
                "addressNo": "xxxx",
                "title": "",
                "lastName": "Banerjee",
                "firstName": "Shubham",
                "nameI": "",
                "nameII": "",
                "nameIII": "",
                "nameAffix": "",
                "academicTitle1": "",
                "academicTitle2": "",
                "city": "Berlin",
                "street": "Straße",
                "country": "DE",
                "postalCode": "10000",
                "houseNumber": "19",
            } ]
}

Thanks in advance.

View Entire Topic
Andre_Fischer
Product and Topic Expert
Product and Topic Expert

Hi Shubham,

the problem seems to be the BAPI BAPI_BUPA_ADDRESS_CHANGE since it seems to register a Save via Update Task.

During the Finalize / Check_before_save phases it is only allowed to run code that does something similar as a validation or a determination.

Persisting data to the database in this early part of the SAVE sequence is not allowed.

Using a workaround such as trying to call the BAPI via an RFC destination is NOT recommended since it could cause inconsistencies in your data.

See also our documentation:

Saver Classes - SAP Help Portal

So you would have to try to develop code that would check if the data can be updated successfully (a validation). If the validation is successful you could call the above mentioned BAPI in the method save( ).

If such validations can be built and if you would be able to build appropriate CDS views to read the data it might be an option to try out to build a managed app with unmanaged save. Because then you would be able to perform validations and determinations and would only use your legacy API to persist the data for which the consistency has been checked beforehand.

Kind regards,

Andre