Friday, December 23, 2011

SAP ABAP Write a cluster object to a correction request (transport)

Today i would like to illustrate how to write an object to a transport file.
As usual i provide some real life example.
I this case writing a Payroll cluster to a CR, in order to trasport it.

The local class lcl_tabu_k_2_trkorr_writer encapsulates the writing logic.
Even though it can be definitely improved, it is designed so that further special objects like a PCL table can be added easily.

The key concepts are:
  1. Table E071 contains the objects in form "R3TR TABU TABLENAME"
  2. TABU means table contents
  3. When you specify TABU in a transport the you are expcted to specify also che keys you would like to transport
  4. These keys are written to table E071K
  5. In the program standard structures are used for the keys and transport entries. This allows to use standard functions and thus to check the correctness of what we are transporting with regard to the type of system (production, test, development, SAP o customer system etc) and to the type of object (name space, development class) etc.
  6. Often these functions are bypassed and the tables e071 and the keys are written directly to the database. I wouldn't reccomend this.
  7. Be very careful: if you transport TABU * then the whole table is erased before importing the data in the trasport files. This means that you cannot use TABU * to add data to a table without actually losing data
  8. The behaviour described in point 7 might be release dependent therefore its use is highly discouraged

Here is the coding



**&---------------------------------------------------------------------*
*& Report   zCLUSTER_2_CR                                           *
*&                                                                     *
*&---------------------------------------------------------------------*
*&                                                                     *
*&                                                                     *
*&---------------------------------------------------------------------*

REPORT   zcluster_2_cr                 .

TABLES: pernr.


*PARAMETERS:     trkorr    TYPE trkorr.
PARAMETERS:     wbtrkorr TYPE trkorr.
PARAMETERS:     uname     TYPE sy-uname.
PARAMETERS:     test      TYPE boole_d DEFAULT 'X'.


INITIALIZATION.
  uname = sy-uname.
*  limit = 99999999.

*AT SELECTION-SCREEN ON VALUE-REQUEST FOR trkorr.
*
*  PERFORM select_tr_korr USING uname 'CUST' CHANGING trkorr.


AT SELECTION-SCREEN ON VALUE-REQUEST FOR wbtrkorr.

  PERFORM select_tr_korr USING uname 'SYST' CHANGING wbtrkorr.


*---------------------------------------------------------------------*
*       CLASS lcl_tabu_k_2_trkorr_writer DEFINITION
*---------------------------------------------------------------------*
*       ........                                                      *
*---------------------------------------------------------------------*
CLASS lcl_tabu_k_2_trkorr_writer DEFINITION.
  PUBLIC SECTION.


* gets the name of the receiver given the temse file type.
    METHODS: init    IMPORTING p_trkorr        TYPE trkorr
                               p_wb_trkorr     TYPE trkorr
                               p_tabname       TYPE tabname
                     CHANGING  p_error         TYPE i.

    METHODS: write_to_trkorr     CHANGING p_error TYPE i.
    METHODS: write_to_trkorr_blk CHANGING p_error TYPE i.

    METHODS: add_line_key IMPORTING p_line     TYPE any
                          CHANGING  p_error TYPE i .
    METHODS: add_object   IMPORTING pgmid     TYPE pgmid
                                    object    TYPE trobjtype
                                    obj_name  TYPE trobj_name
                                    p_trkorr  TYPE trkorr
                          CHANGING  p_error TYPE i .
    METHODS: add_star_key CHANGING  p_error TYPE i .

    METHODS: get_metahead CHANGING p_error TYPE i.

  PRIVATE SECTION.

    DATA: a_trkorr        TYPE trkorr.
    DATA: a_wb_trkorr     TYPE trkorr.
    DATA: as_obj          TYPE LINE OF tredt_objects.
    DATA: as_metahead     TYPE x030l.
    DATA: a_tabname       TYPE tabname.
    DATA: ar_typedescr    TYPE REF TO cl_abap_typedescr.
    DATA: ar_tableline    TYPE REF TO data.
    DATA: at_key          TYPE tredt_keys.


ENDCLASS.                    "DEFINITION


*---------------------------------------------------------------------*
*       CLASS lcl_tabu_k_2_trkorr_writer IMPLEMENTATION
*---------------------------------------------------------------------*
*       ........                                                      *
*---------------------------------------------------------------------*
CLASS lcl_tabu_k_2_trkorr_writer IMPLEMENTATION.


  METHOD: init.

    CLEAR:   as_obj,
             as_metahead,
             ar_typedescr,
             ar_tableline,
             a_tabname,
             at_key.
    FREE at_key.

    a_trkorr     = p_trkorr.
    a_wb_trkorr  = p_wb_trkorr.
    a_tabname    = p_tabname.

    CALL METHOD get_metahead CHANGING p_error = p_error.

  ENDMETHOD.

  METHOD: add_object.
*                          IMPORTING pgmid     TYPE pgmid
*                                    object    type TROBJTYPE
*                                    obj_name  type TROBJ_NAME
*                                    p_trkorr  type trkorr
*                          CHANGING  p_error TYPE i .

    as_obj-trkorr   = p_trkorr.
    as_obj-pgmid    = pgmid.
    as_obj-object   = object.
    as_obj-obj_name = obj_name.
    as_obj-objfunc  = space.


  ENDMETHOD.

  METHOD: add_star_key.
* MAKE TABU *
    DATA: ls_key          TYPE LINE OF tredt_keys.

* Transport object
    as_obj-trkorr   = a_trkorr.
    as_obj-pgmid    = 'R3TR'.
    as_obj-object   = 'TABU'.
    as_obj-obj_name = as_metahead-tabname.
    as_obj-objfunc  = 'K'.

* Initialize entry for table key transport
    MOVE-CORRESPONDING as_obj TO ls_key.
    ls_key-objname    = as_obj-obj_name.
    ls_key-objfunc    = space.
    ls_key-mastername = as_obj-obj_name.
    ls_key-mastertype = as_obj-object.
    ls_key-tabkey     = '*'.


*   Insert key of tableline into transport request
    INSERT ls_key INTO TABLE at_key.
  ENDMETHOD.

  METHOD: add_line_key.
*MAKE TABU K
    FIELD-SYMBOLS:
      <ls_tableline>  TYPE ANY,
      <lv_xtableline> TYPE x,
      <lv_xtabkey>    TYPE x.

    DATA: ls_key          TYPE LINE OF tredt_keys.

*4.7 Only
* Get metadata of the linetype of the given table
*  lo_typedescr = cl_abap_typedescr=>describe_by_data(
*      p_data = line ).
*  CALL METHOD lo_typedescr->get_ddic_header
*    RECEIVING
*      p_header = ls_metahead
*    EXCEPTIONS
*      OTHERS   = 1.
*  IF sy-subrc <> 0.
*    pv_error = 1.
*    EXIT.
*  ENDIF.

* Transport object
    as_obj-trkorr   = a_trkorr.
    as_obj-pgmid    = 'R3TR'.
    as_obj-object   = 'TABU'.
    as_obj-obj_name = as_metahead-tabname.
    as_obj-objfunc  = 'K'.

* Initialize entry for table key transport
    MOVE-CORRESPONDING as_obj TO ls_key.
    ls_key-objname    = as_obj-obj_name.
    ls_key-objfunc    = space.
    ls_key-mastername = as_obj-obj_name.
    ls_key-mastertype = as_obj-object.


*   Extract tablekey
    CLEAR ls_key-tabkey.
    ASSIGN ls_key-tabkey TO <lv_xtabkey> CASTING.

*   If table has fields of type STRING or RAWSTRING, casting to type
*   'X' is not possible -> generic solution unknown -> indiv. handling
    CASE as_metahead-tabname.
      when 'PCL2'.
        DATA l_key(46) type c.
        l_key+0(45) = p_line.
        l_key+45(1) = '*'.
        ASSIGN l_key TO <lv_xtableline> CASTING.
        <lv_xtabkey>(46) = <lv_xtableline>(46).
        INSERT ls_key INTO TABLE at_key.
        exit.
      WHEN OTHERS.
        ASSIGN p_line TO <lv_xtableline> CASTING.
    ENDCASE.

*   Copy key prefix
    <lv_xtabkey>(as_metahead-keylen) = <lv_xtableline>.

*   Insert key of tableline into transport request
    INSERT ls_key INTO TABLE at_key.
  ENDMETHOD.


  METHOD: write_to_trkorr_blk.
    DATA lt_ko200 TYPE TABLE OF ko200.
    DATA ls_e071 TYPE e071.
    DATA lt_key  TYPE tredt_keys.
    DATA blk_size TYPE i VALUE 10000.

    IF as_obj IS INITIAL OR
       at_key IS INITIAL.
      EXIT.
    ENDIF.

    APPEND as_obj TO lt_ko200.
    MOVE-CORRESPONDING as_obj TO ls_e071.

    DO.

      IF at_key IS INITIAL.
        EXIT.
      ENDIF.

      REFRESH lt_key.

      APPEND LINES OF at_key FROM 1 TO blk_size TO lt_key.
      DELETE at_key FROM 1 TO blk_size.

** Check data for transport request
* Add data to transport request
      CALL FUNCTION 'TR_OBJECTS_CHECK'
           TABLES
                wt_ko200 = lt_ko200
                wt_e071k = lt_key
           EXCEPTIONS
                OTHERS   = 1.

*This one only swallows a Task
      CALL FUNCTION 'TR_APPEND_TO_COMM'
           EXPORTING
                pi_korrnum                     = a_trkorr
                wi_e071                        = ls_e071
                wi_simulation                  = test
                wi_suppress_key_check          = 'X'
           TABLES
                wt_e071k                       = lt_key
           EXCEPTIONS
                no_authorization               = 1
                no_systemname                  = 2
                no_systemtype                  = 3
                tr_check_keysyntax_error       = 4
                tr_check_obj_error             = 5
                tr_enqueue_failed              = 6
                tr_ill_korrnum                 = 7
                tr_key_without_header          = 8
                tr_lockmod_failed              = 9
                tr_lock_enqueue_failed         = 10
                tr_modif_only_in_modif_order   = 11
                tr_not_owner                   = 12
                tr_no_append_of_corr_entry     = 13
                tr_no_append_of_c_member       = 14
                tr_no_shared_repairs           = 15
                tr_order_not_exist             = 16
                tr_order_released              = 17
                tr_order_update_error          = 18
                tr_repair_only_in_repair_order = 19
                tr_wrong_order_type            = 20
                wrong_client                   = 21
                OTHERS                         = 22.
      IF sy-subrc <> 0.
        CALL FUNCTION 'TR_APPEND_TO_COMM'
             EXPORTING
                  pi_korrnum                     = a_wb_trkorr
                  wi_e071                        = ls_e071
                  wi_simulation                  = test
                  wi_suppress_key_check          = 'X'
             TABLES
                  wt_e071k                       = lt_key
             EXCEPTIONS
                  no_authorization               = 1
                  no_systemname                  = 2
                  no_systemtype                  = 3
                  tr_check_keysyntax_error       = 4
                  tr_check_obj_error             = 5
                  tr_enqueue_failed              = 6
                  tr_ill_korrnum                 = 7
                  tr_key_without_header          = 8
                  tr_lockmod_failed              = 9
                  tr_lock_enqueue_failed         = 10
                  tr_modif_only_in_modif_order   = 11
                  tr_not_owner                   = 12
                  tr_no_append_of_corr_entry     = 13
                  tr_no_append_of_c_member       = 14
                  tr_no_shared_repairs           = 15
                  tr_order_not_exist             = 16
                  tr_order_released              = 17
                  tr_order_update_error          = 18
                  tr_repair_only_in_repair_order = 19
                  tr_wrong_order_type            = 20
                  wrong_client                   = 21
                  OTHERS                         = 22.
      ENDIF.
      COMMIT WORK.
*This one swallows correction requests too
*    CALL FUNCTION 'TR_EDIT_CHECK_OBJECTS_KEYS'
*         EXPORTING
*              wi_order                     = a_trkorr
*              wi_with_dialog               = 'D'
*              wi_send_message              = ' '
**            iv_no_show_option            = iv_no_show_option
**            iv_no_standard_editor        = iv_no_standard_editor
**            iv_externalps                = iv_externalps
**            iv_externalid                = iv_externalid
**            iv_no_ps                     = iv_no_ps
*         IMPORTING
*              we_order                     = a_trkorr
**            we_task                      = we_task
*         TABLES
*              wt_e071                      = lt_ko200
*              wt_e071k                     = at_key
**            wt_tadir                     = tt_tadir
*         EXCEPTIONS
*              show_only_user_after_error   = 1
*              cancel_edit_user_after_error = 2
*              OTHERS                       = 2.
*
*    IF sy-subrc NE 0.
*      CALL FUNCTION 'TR_EDIT_CHECK_OBJECTS_KEYS'
*           EXPORTING
*                wi_order                     = a_wb_trkorr
*                wi_with_dialog               = 'D'
*                wi_send_message              = ' '
**            iv_no_show_option            = iv_no_show_option
**            iv_no_standard_editor        = iv_no_standard_editor
**            iv_externalps                = iv_externalps
**            iv_externalid                = iv_externalid
**            iv_no_ps                     = iv_no_ps
*           IMPORTING
*                we_order                     = a_wb_trkorr
**            we_task                      = we_task
*           TABLES
*                wt_e071                      = lt_ko200
*                wt_e071k                     = at_key
**            wt_tadir                     = tt_tadir
*           EXCEPTIONS
*                show_only_user_after_error   = 1
*                cancel_edit_user_after_error = 2
*                OTHERS                       = 2.
*      IF sy-subrc NE 0.
* *      ENDIF.
*    ENDIF.

    ENDDO.

    CLEAR:   as_obj,
             as_metahead,
             ar_typedescr,
             ar_tableline,
             a_tabname,
             at_key.
    REFRESH at_key.

  ENDMETHOD.

  METHOD: write_to_trkorr.
    DATA lt_ko200 TYPE TABLE OF ko200.
    DATA ls_e071 TYPE e071.

    IF as_obj IS INITIAL.
      EXIT.
    ENDIF.

    IF as_obj-objfunc = 'K' AND
       at_key IS INITIAL.
      EXIT.
    ENDIF.

    APPEND as_obj TO lt_ko200.

** Check data for transport request
* Add data to transport request
    CALL FUNCTION 'TR_OBJECTS_CHECK'
         TABLES
              wt_ko200 = lt_ko200
              wt_e071k = at_key
         EXCEPTIONS
              OTHERS   = 1.


*This one swallows correction requests too
    CALL FUNCTION 'TR_EDIT_CHECK_OBJECTS_KEYS'
         EXPORTING
              wi_order                     = a_trkorr
              wi_with_dialog               = 'X' "'D'
              wi_send_message              = 'X' "' '
*            iv_no_show_option            = iv_no_show_option
*            iv_no_standard_editor        = iv_no_standard_editor
*            iv_externalps                = iv_externalps
*            iv_externalid                = iv_externalid
*            iv_no_ps                     = iv_no_ps
         IMPORTING
              we_order                     = a_trkorr
*            we_task                      = we_task
         TABLES
              wt_e071                      = lt_ko200
              wt_e071k                     = at_key
*            wt_tadir                     = tt_tadir
         EXCEPTIONS
              show_only_user_after_error   = 1
              cancel_edit_user_after_error = 2
              OTHERS                       = 2.

    IF sy-subrc NE 0.
      CALL FUNCTION 'TR_EDIT_CHECK_OBJECTS_KEYS'
           EXPORTING
                wi_order                     = a_wb_trkorr
                wi_with_dialog               = 'D'
                wi_send_message              = ' '
*            iv_no_show_option            = iv_no_show_option
*            iv_no_standard_editor        = iv_no_standard_editor
*            iv_externalps                = iv_externalps
*            iv_externalid                = iv_externalid
*            iv_no_ps                     = iv_no_ps
           IMPORTING
                we_order                     = a_wb_trkorr
*            we_task                      = we_task
           TABLES
                wt_e071                      = lt_ko200
                wt_e071k                     = at_key
*            wt_tadir                     = tt_tadir
           EXCEPTIONS
                show_only_user_after_error   = 1
                cancel_edit_user_after_error = 2
                OTHERS                       = 2.
      IF sy-subrc NE 0.
        WRITE:/ 'Errore scrittura trkorr tabella', a_tabname.
      ENDIF.
    ENDIF.


    CLEAR:   as_obj,
             as_metahead,
             ar_typedescr,
             ar_tableline,
             a_tabname,
             at_key.
    REFRESH at_key.

  ENDMETHOD.


  METHOD: get_metahead.

* call dictionary interface
    CALL FUNCTION 'DDIF_NAMETAB_GET'
      EXPORTING
        tabname           = a_tabname
        all_types         = 'X'
*     LFIELDNAME        = ' '
*     GROUP_NAMES       = ' '
*     UCLEN             =
      IMPORTING
        x030l_wa          = as_metahead
*     DTELINFO_WA       =
*     TTYPINFO_WA       =
*     DDOBJTYPE         =
*     DFIES_WA          =
*     LINES_DESCR       =
*   TABLES
*     X031L_TAB         =
*     DFIES_TAB         =
      EXCEPTIONS
        not_found         = 1
        OTHERS            = 2
              .
    IF sy-subrc <> 0.
      p_error = 1.
    ENDIF.

  ENDMETHOD.

ENDCLASS.                    "lcl_tabu_k_2_trkorr_writer IMPLEMENTATION

START-OF-SELECTION.
  DATA l_cnt      TYPE i.
  DATA l_cnt_cid  TYPE i.

  CLEAR l_cnt.
  CLEAR l_cnt_cid.


GET pernr.
  DATA l_pernrsel TYPE pcl2-srtfd.
  DATA lt_pcl2    TYPE TABLE OF pcl2.
  DATA ls_pcl2    TYPE pcl2.
  DATA l_error    TYPE i.
  DATA l_tabname  TYPE tabname VALUE 'PCL2'.

  DATA lr_trkk TYPE REF TO lcl_tabu_k_2_trkorr_writer .

  IF lr_trkk IS INITIAL.
    CREATE OBJECT lr_trkk.
  ENDIF.

  REFRESH lt_pcl2. CLEAR ls_pcl2.
  CONCATENATE pernr-pernr '%' INTO l_pernrsel.

  SELECT * FROM pcl2 INTO TABLE lt_pcl2 WHERE relid = 'RI' AND
                                              srtfd LIKE l_pernrsel.
  SELECT * FROM pcl2 appending TABLE lt_pcl2 WHERE relid = 'CU' AND
                                              srtfd LIKE l_pernrsel.

  l_cnt = l_cnt + sy-dbcnt.

  CALL METHOD lr_trkk->init EXPORTING p_trkorr    = wbtrkorr
                                      p_wb_trkorr = wbtrkorr
                                      p_tabname   = l_tabname
                            CHANGING  p_error     = l_error.

  LOOP AT lt_pcl2 INTO ls_pcl2.

    CALL METHOD lr_trkk->add_line_key
                             EXPORTING  p_line         = ls_pcl2
                              CHANGING  p_error        = l_error .


  ENDLOOP.

  IF sy-subrc EQ 0.
    CALL METHOD lr_trkk->write_to_trkorr CHANGING p_error = l_error.
    COMMIT WORK.
  ENDIF.

END-OF-SELECTION.

  WRITE: / 'Processed', l_cnt, 'RECORD'.
  WRITE: / 'Processed', l_cnt_cid, 'CID'.

*---------------------------------------------------------------------*
*       FORM select_tr_korr                                           *
*---------------------------------------------------------------------*
FORM select_tr_korr USING     p_uname p_type
                    CHANGING  p_korr.

  DATA lv_user TYPE trexreqhd-author.
  DATA ls_sel_korr TYPE   trexreqhd.
  DATA lv_selected_index TYPE sy-tabix.
  DATA lt_rem_trkorr_list TYPE STANDARD TABLE OF trexreqhd.

  lv_user = p_uname.

*  IF uname = sy-uname.
** Korrekturauftrag für Transportobjekte auswählen
*    CALL FUNCTION 'TR_ORDER_CHOICE_CORRECTION'
*         EXPORTING
*              iv_category            = p_type
*              iv_cli_dep             = ' '
*         IMPORTING
*              ev_order               = p_korr
**            ev_task                = we_task
*         EXCEPTIONS
*              invalid_category       = 1
*              no_correction_selected = 2
*              OTHERS                 = 3.
*
*    IF sy-subrc NE 0.
*      MESSAGE ID sy-msgid TYPE 'E' NUMBER sy-msgno
*              WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
*    ENDIF.
*  ELSE.

  CALL FUNCTION 'TR_F4_REQUESTS'
   EXPORTING
     iv_username                   = uname
*   IV_TRKORR_PATTERN             =
*   IV_TRFUNCTIONS                =
*   IV_TRSTATUS                   =
*   IV_FROM_DATE                  =
*   IV_TO_DATE                    =
*   IV_CLIENT                     =
*   IV_PROJECT                    =
*   IV_TITLE                      =
*   IV_VIA_SELECTION_SCREEN       = 'X'
*   IV_COMPLETE_REQUESTS          = 'X'
   IMPORTING
     ev_selected_request           = p_korr
*   ES_SELECTED_REQUEST           =
            .
*  ENDIF.



ENDFORM.                    " SELECT_TR_KORR