ABAP Blog Posts
cancel
Showing results for 
Search instead for 
Did you mean: 
Sandra_Rossi
Active Contributor
923

This blog post is a little call to the community to share code snippets of "copy programs" for BAPI business objects. I explain the concept, how to create such a program, and propose one example.

It may be a little bit difficult to develop a program from scratch for creating a Business Object (*) by calling a create BAPI function module:

  1. Pass the right values to make the BAPI succeed (consistent values, fields to be entered either in internal or in external format, etc.)
  2. Use of additional function modules (for long texts, to cleanup memory or special commit, BAPI_TRANSACTION_COMMIT and ROLLBACK)
  3. Special technical parameters for some BAPI
  4. Custom fields via the EXTENSIONIN parameter

That would be much easier if there was a copy program provided to create a business object via BAPI from an existing business object:

  1. Ask the functional team or end user to create manually the expected business object(s)
  2. Run the copy program to copy the business object
  3. Debug the copy program to see the values passed to the create BAPI
  4. Now it should be easier to create the custom program as per the requirements

Again, the goal of the custom program is not to copy a template business object in the production system, but to create a business object from scratch according to some client requirements; the goal of the copy program is to help developing this custom program.

The easiest way to create a copy program is to call the read BAPI to get all the business object details and pass them to the create BAPI, because the parameters are usually very similar. When they differ, usually only a small conversion logic is needed.

Here's one example of what could be such a copy program, applied to the business object BUS2172 (projects in the SAP Portfolio and Project Management module - PPM). The BAPI used by this copy program are BAPI_BUS2172_GET_DETAIL and BAPI_BUS2172_CREATE. For information, this business object is mainly stored in the table DPR_PROJECT; it can be created and maintained via the Web Dynpro application INM_WORKCENTER_APP (with the URL query ?iv_appl_type=DPO&iv_context=WS&iv_obj_type_r=DPO&iv_portal_role=DPR_PROJECT&sap-client=...)

To fill the parameters of the create BAPI, the easiest way is to call the "read" BAPI (BAPI_BUS2172_GET_DETAIL) because the parameters are usually very similar.

The read and create BAPI parameters may differ, so the parameters must be converted. For BUS2172, they differ on these points:

  • The read BAPI may return the project name in different languages in an internal table while the create BAPI has only one name in the language defined in the component PROJECT_DESCRIPTION_NAME of the parameter IS_PROJECT_DEFINITION
  • Same thing for the project description. Also, the read BAPI may return the description as a table of text lines while the create BAPI has 4 binary components. It's explained below how to convert it.
  • The read BAPI returns the dates in external format while the create BAPI expects the dates in internal format

BAPI_BUS2172_CREATE has several specificities (which are documented in the function module documentation):

  • Commit is to be done via BAPI_CPROJECTS_COMMIT_WORK and rollback via BAPI_CPROJECTS_ROLLBACK_WORK
  • The technical parameter IS_PROJECT_DEFINITION_UPD is a structure with components to be set with "X" values for all the fields to initialize by the values in the parameter IS_PROJECT_DEFINITION.
  • The components PROJECT_DESCRIPTION_PARTX (X = 1 to 4) components of the parameter IS_PROJECT_DEFINITION are binary fields with a total length of 1020 bytes which must be initialized from a text via the method CL_DPR_BAPI_SERVICES=>CONVERT_STRING_TO_RAWPARTS (UTF-8 with the last bytes to be spaces).

This copy program should work in all projects. Don't add anything custom when you share it.

Now we can run this copy program.

After making sure the copy program has created the business object, the parameters passed to BAPI_BUS2172_CREATE can be carefully analyzed by debug:

Sandra_Rossi_0-1767196979039.png

Now, the custom program may be created (manually) with the required logic to reproduce the same parameter values (at least for the first test run).

That would be great if people can share such copy programs because they are easy to create, they are useful and they don't contain any confidential information.

Thanks a lot for reading me!

Sandra

Here's the code of the copy program for BUS2172 (note that it's currently limited because it doesn't copy the project elements like the phases, tasks, checklist headers and items, which correspond respectively to the business object types BUS2173, BUS2175, BUS2176 and BUS2174). It works in an ABAP 7.40 system:

REPORT z_bus2172_copy_program.

PARAMETERS projguid TYPE bapi_ts_guid-project_definition_guid.
PARAMETERS projnum TYPE dpr_project-project_id.

CLASS lcl_app DEFINITION DEFERRED.

DATA go_app TYPE REF TO lcl_app.

LOAD-OF-PROGRAM.
  CALL METHOD lcl_app=>('CREATE')
    RECEIVING
      result = go_app.

START-OF-SELECTION.
  CALL METHOD go_app->('START_OF_SELECTION').

CLASS lcl_app DEFINITION FINAL
  CREATE PRIVATE.

  PUBLIC SECTION.
    CLASS-METHODS class_constructor.

    CLASS-METHODS create
      RETURNING VALUE(result) TYPE REF TO lcl_app.

    METHODS start_of_selection.

  PRIVATE SECTION.
    CLASS-DATA initial_external_date TYPE bapi_date.

    CLASS-METHODS conv_date_ext_to_int
      IMPORTING iv_date_format_externe_courant TYPE csequence
      RETURNING VALUE(result)                  TYPE d.
ENDCLASS.


CLASS lcl_app IMPLEMENTATION.
  METHOD class_constructor.
    DATA(d) = VALUE d( ).
    WRITE d TO initial_external_date.
  ENDMETHOD.

  METHOD conv_date_ext_to_int.
    IF iv_date_format_externe_courant = initial_external_date.
      result = VALUE #( ).
    ELSE.
      cl_abap_datfm=>conv_date_ext_to_int( EXPORTING im_datext = iv_date_format_externe_courant
                                           IMPORTING ex_datint = result ).
    ENDIF.
  ENDMETHOD.

  METHOD create.
    result = NEW lcl_app( ).
  ENDMETHOD.

  METHOD start_of_selection.
    TYPES tt_description_lines TYPE STANDARD TABLE OF dpr_tv_bapi_description WITH EMPTY KEY.

    DATA project_definition_guid      TYPE bapi_ts_guid-project_definition_guid.
    DATA es_project_definition_detail TYPE bapi_ts_project_def_detail.
    DATA es_extension_out             TYPE bapiparex.
    DATA et_name                      TYPE STANDARD TABLE OF bapi_ts_name.
    DATA et_description               TYPE STANDARD TABLE OF bapi_ts_description.
    DATA et_status                    TYPE STANDARD TABLE OF bapi_ts_status.
    DATA et_authorization             TYPE STANDARD TABLE OF bapi_ts_authorization_out.
    DATA return_tab                   TYPE STANDARD TABLE OF bapiret2.
    DATA is_extension_in              TYPE bapiparex.
    DATA is_project_definition        TYPE bapi_ts_project_def.
    DATA is_project_definition_upd    TYPE bapi_ts_project_def_upd.

    IF projguid IS NOT INITIAL.
      project_definition_guid = projguid.
    ELSE.
      SELECT SINGLE guid FROM dpr_project WHERE project_id = @projnum INTO @DATA(dpr_project_guid).
      IF sy-subrc <> 0.
        MESSAGE |Project "{ projnum }" not found in table DPR_PROJECT| TYPE 'I' DISPLAY LIKE 'E'.
        RETURN.
      ENDIF.
      project_definition_guid = dpr_project_guid.
    ENDIF.

    CALL FUNCTION 'BAPI_BUS2172_GET_DETAIL'
      EXPORTING
        project_definition_guid      = project_definition_guid
      IMPORTING
        es_project_definition_detail = es_project_definition_detail
        es_extension_out             = es_extension_out
      TABLES
        et_name                      = et_name
        et_description               = et_description
        et_status                    = et_status
        et_authorization             = et_authorization
        return                       = return_tab.

    LOOP AT return_tab REFERENCE INTO DATA(return_line)
         WHERE type CA 'AEX'.
      WRITE / return_line->message.
    ENDLOOP.
    IF sy-subrc = 0.
      MESSAGE 'Error(s) during GET_DETAIL c.f. messages in the list/spool' TYPE 'I' DISPLAY LIKE 'E'.
      RETURN.
    ENDIF.

    is_extension_in = es_extension_out.
    es_extension_out = VALUE #( ).

    DATA(description_lines) = VALUE tt_description_lines( FOR <description_line> IN et_description
                                                          WHERE ( language = es_project_definition_detail-master_language )
                                                          ( <description_line>-description_line ) ).
    CONCATENATE LINES OF description_lines INTO DATA(project_description) RESPECTING BLANKS.
    cl_dpr_bapi_services=>convert_string_to_rawparts( EXPORTING iv_desc_string = project_description
                                                      IMPORTING ev_desc_part1  = DATA(desc_part1)
                                                                ev_desc_part2  = DATA(desc_part2)
                                                                ev_desc_part3  = DATA(desc_part3)
                                                                ev_desc_part4  = DATA(desc_part4) ).
    " The error "Enter an object number" (DPR_CGPL_MESSAGES003) happens if IS_PROJECT_DEFINITION-PROJECT_ID
    "   is filled, but no error if it's empty!? --> let's keep it empty then...
    is_project_definition = VALUE bapi_ts_project_def(
        project_number               = ''
        project_name_language        = es_project_definition_detail-master_language " es_project_definition_detail-project_name_language
        project_name                 = VALUE #( et_name[ language = es_project_definition_detail-master_language ]-name OPTIONAL ) " es_project_definition_detail-project_name
        project_type                 = es_project_definition_detail-project_type
        project_cause                = es_project_definition_detail-project_cause
        responsible_role_guid        = es_project_definition_detail-responsible_role_guid
        priority                     = es_project_definition_detail-priority
        fixed_start_constraint_type  = es_project_definition_detail-fixed_start_constraint_type
        fixed_start_date             = conv_date_ext_to_int( es_project_definition_detail-fixed_start_date )
        fixed_finish_constraint_type = es_project_definition_detail-fixed_finish_constraint_type
        fixed_finish_date            = conv_date_ext_to_int( es_project_definition_detail-fixed_finish_date )
        calendar                     = es_project_definition_detail-calendar
        sold_to_party_number         = es_project_definition_detail-sold_to_party_number
        customer_number              = es_project_definition_detail-customer_number
        grouping                     = es_project_definition_detail-grouping
        search_field                 = es_project_definition_detail-search_field
        actual_work                  = es_project_definition_detail-actual_work
        actual_work_unit             = es_project_definition_detail-actual_work_unit
        responsible_orga_unit        = es_project_definition_detail-responsible_orga_unit
        project_description_language = es_project_definition_detail-master_language " es_project_definition_detail-project_description_language
        project_description_part1    = desc_part1 " es_project_definition_detail-project_description_part1
        project_description_part2    = desc_part2 " es_project_definition_detail-project_description_part2
        project_description_part3    = desc_part3 " es_project_definition_detail-project_description_part3
        project_description_part4    = desc_part4 " es_project_definition_detail-project_description_part4
        location                     = es_project_definition_detail-location
        allocation_unit              = es_project_definition_detail-allocation_unit
        period_type                  = es_project_definition_detail-period_type
        forecasted_start             = conv_date_ext_to_int( es_project_definition_detail-forecasted_start )
        forecasted_finish            = conv_date_ext_to_int( es_project_definition_detail-forecasted_finish )
        master_language              = es_project_definition_detail-master_language ).
    is_project_definition_upd = VALUE bapi_ts_project_def_upd(
        project_number               = xsdbool( is_project_definition-project_number IS NOT INITIAL )
        project_name_language        = xsdbool( is_project_definition-project_name_language IS NOT INITIAL )
        project_name                 = xsdbool( is_project_definition-project_name IS NOT INITIAL )
        project_type                 = xsdbool( is_project_definition-project_type IS NOT INITIAL )
        project_cause                = xsdbool( is_project_definition-project_cause IS NOT INITIAL )
        responsible_role_guid        = xsdbool( is_project_definition-responsible_role_guid IS NOT INITIAL )
        priority                     = xsdbool( is_project_definition-priority IS NOT INITIAL )
        fixed_start_constraint_type  = xsdbool( is_project_definition-fixed_start_constraint_type IS NOT INITIAL )
        fixed_start_date             = xsdbool( is_project_definition-fixed_start_date IS NOT INITIAL )
        fixed_finish_constraint_type = xsdbool( is_project_definition-fixed_finish_constraint_type IS NOT INITIAL )
        fixed_finish_date            = xsdbool( is_project_definition-fixed_finish_date IS NOT INITIAL )
        calendar                     = xsdbool( is_project_definition-calendar IS NOT INITIAL )
        sold_to_party_number         = xsdbool( is_project_definition-sold_to_party_number IS NOT INITIAL )
        customer_number              = xsdbool( is_project_definition-customer_number IS NOT INITIAL )
        grouping                     = xsdbool( is_project_definition-grouping IS NOT INITIAL )
        search_field                 = xsdbool( is_project_definition-search_field IS NOT INITIAL )
        actual_work                  = xsdbool( is_project_definition-actual_work IS NOT INITIAL )
        actual_work_unit             = xsdbool( is_project_definition-actual_work_unit IS NOT INITIAL )
        responsible_orga_unit        = xsdbool( is_project_definition-responsible_orga_unit IS NOT INITIAL )
        project_description_language = xsdbool( is_project_definition-project_description_language IS NOT INITIAL )
        project_description          = xsdbool(    is_project_definition-project_description_part1 IS NOT INITIAL
                                                OR is_project_definition-project_description_part2 IS NOT INITIAL
                                                OR is_project_definition-project_description_part3 IS NOT INITIAL
                                                OR is_project_definition-project_description_part4 IS NOT INITIAL )
        location                     = xsdbool( is_project_definition-location IS NOT INITIAL )
        allocation_unit              = xsdbool( is_project_definition-allocation_unit IS NOT INITIAL )
        period_type                  = xsdbool( is_project_definition-period_type IS NOT INITIAL )
        forecasted_start             = xsdbool( is_project_definition-forecasted_start IS NOT INITIAL )
        forecasted_finish            = xsdbool( is_project_definition-forecasted_finish IS NOT INITIAL )
        extensions                   = xsdbool( is_extension_in IS NOT INITIAL ) ).

    CALL FUNCTION 'BAPI_BUS2172_CREATE'
      EXPORTING
        is_project_definition     = is_project_definition
        is_project_definition_upd = is_project_definition_upd
        is_extension_in           = is_extension_in
      IMPORTING
        es_extension_out          = es_extension_out
      TABLES
        return                    = return_tab.

    LOOP AT return_tab REFERENCE INTO return_line
         WHERE type CA 'AEX'.
      WRITE : / return_line->type, return_line->number, return_line->id, return_line->message.
    ENDLOOP.
    IF sy-subrc = 0.
      CALL FUNCTION 'BAPI_CPROJECTS_ROLLBACK_WORK'
        TABLES
          return = return_tab.
      MESSAGE 'Error(s) during CREATE c.f. messages in the list/spool' TYPE 'I' DISPLAY LIKE 'E'.
      RETURN.
    ENDIF.

    LOOP AT return_tab REFERENCE INTO return_line.
      WRITE : / return_line->type, return_line->number, return_line->id, return_line->message.
    ENDLOOP.

    IF 0 = 1.
      MESSAGE s114(dpr_bapi) ##MG_MISSING.
    ENDIF.
    DATA(success_message) = VALUE #( return_tab[ id     = 'DPR_BAPI'
                                                 number = '114' ] OPTIONAL ).

    CALL FUNCTION 'BAPI_CPROJECTS_COMMIT_WORK'
      TABLES
        return = return_tab.

    LOOP AT return_tab REFERENCE INTO return_line.
      WRITE : / return_line->type, return_line->number, return_line->id, return_line->message.
    ENDLOOP.

    IF success_message IS NOT INITIAL.
      DATA(project_guid) = CONV dpr_project-guid( success_message-message_v1 ).
      SELECT SINGLE project_id FROM dpr_project WHERE guid = @project_guid INTO @DATA(project_id).
      IF sy-subrc = 0.
        WRITE / |GUID { project_guid } = Project { project_id } |.
      ENDIF.
    ENDIF.
  ENDMETHOD.
ENDCLASS.

 

1 Comment