{"id":288,"date":"2026-08-02T12:13:52","date_gmt":"2026-08-02T12:13:52","guid":{"rendered":"https:\/\/sapabap.dwimansolution.com\/?p=288"},"modified":"2026-08-02T12:13:53","modified_gmt":"2026-08-02T12:13:53","slug":"sap-abap-alv-dock-with-approval-2-columns","status":"publish","type":"post","link":"https:\/\/sapabap.dwimansolution.com\/index.php\/2026\/08\/02\/sap-abap-alv-dock-with-approval-2-columns\/","title":{"rendered":"SAP ABAP &#8211; ALV Dock with Approval 2 Columns"},"content":{"rendered":"\n<pre class=\"wp-block-code\"><code>*&amp;---------------------------------------------------------------------*\n*&amp; Report  ZALV_DOCK_APPROVE\n*&amp;---------------------------------------------------------------------*\n*&amp; DOCUMENT-LEVEL approval: the ENTIRE result set shown in the ALV is\n*&amp; one approval object. There is no per-row status and no row selection.\n*&amp;\n*&amp; Layout - one docking container + 3-row splitter:\n*&amp;   Row 1 (fixed px) : title, selection parameters, row count, status\n*&amp;   Row 2 (rest)     : ALV grid, display only, no row marks\n*&amp;   Row 3 (fixed px) : signature block (fills in as the doc is signed)\n*&amp;\n*&amp; SUBMIT \/ APPROVE sit in the ALV toolbar and are enabled\/disabled\n*&amp; according to the header status.\n*&amp;\n*&amp; Classic syntax (7.02-safe). No inline declarations.\n*&amp;---------------------------------------------------------------------*\nREPORT zalv_dock_approve.\n\nTYPE-POOLS: icon.\n\nTABLES: sflight.\n\n*----------------------------------------------------------------------*\n* Types\n*----------------------------------------------------------------------*\n* --- ALV item line: NO status, NO icon. Status is header level.\nTYPES: BEGIN OF ty_out,\n         carrid   TYPE sflight-carrid,\n         connid   TYPE sflight-connid,\n         fldate   TYPE sflight-fldate,\n         price     TYPE sflight-price,\n         currency TYPE sflight-currency,\n         seatsocc TYPE sflight-seatsocc,\n       END OF ty_out.\n\n* --- The approval document header. In production this is a Z-table.\nTYPES: BEGIN OF ty_hdr,\n         docno      TYPE char10,      \" approval document number\n         zstatus    TYPE char12,      \" NEW \/ SUBMITTED \/ APPROVED\n         seltext    TYPE string,      \" frozen selection criteria\n         rowcount   TYPE i,           \" frozen row count\n         checksum   TYPE string,      \" frozen key checksum\n         subm_by    TYPE sy-uname,\n         subm_date  TYPE sy-datum,\n         subm_time  TYPE sy-uzeit,\n         appr_by    TYPE sy-uname,\n         appr_date  TYPE sy-datum,\n         appr_time  TYPE sy-uzeit,\n       END OF ty_hdr.\n\n*----------------------------------------------------------------------*\n* Globals\n*----------------------------------------------------------------------*\nDATA: gt_out TYPE STANDARD TABLE OF ty_out,\n      gs_out TYPE ty_out,\n      gs_hdr TYPE ty_hdr.\n\nDATA: go_dock      TYPE REF TO cl_gui_docking_container,\n      go_split     TYPE REF TO cl_gui_splitter_container,\n      go_cont_top  TYPE REF TO cl_gui_container,\n      go_cont_grid TYPE REF TO cl_gui_container,\n      go_cont_bot  TYPE REF TO cl_gui_container,\n      go_grid      TYPE REF TO cl_gui_alv_grid,\n      go_dd_top    TYPE REF TO cl_dd_document,\n      go_dd_bot    TYPE REF TO cl_dd_document.\n\nDATA: gv_ok_code   TYPE sy-ucomm,\n      gv_top_shown TYPE abap_bool,\n      gv_bot_shown TYPE abap_bool.\n\n* Header \/ footer heights in PIXELS (splitter runs in absolute mode)\nCONSTANTS: gc_top_height TYPE i VALUE 100,\n           gc_bot_height TYPE i VALUE 85.\n\n* Segregation of duties: approver must differ from submitter.\n* Set to abap_false only if your business genuinely allows self-approval.\nCONSTANTS: gc_sod_check TYPE abap_bool VALUE abap_true.\n\nCONSTANTS: gc_new   TYPE char12 VALUE 'NEW',\n           gc_subm  TYPE char12 VALUE 'SUBMITTED',\n           gc_appr  TYPE char12 VALUE 'APPROVED'.\n\n*----------------------------------------------------------------------*\n* Event handler\n*----------------------------------------------------------------------*\nCLASS lcl_event_handler DEFINITION.\n  PUBLIC SECTION.\n    METHODS:\n      on_toolbar\n        FOR EVENT toolbar OF cl_gui_alv_grid\n        IMPORTING e_object e_interactive,\n      on_user_command\n        FOR EVENT user_command OF cl_gui_alv_grid\n        IMPORTING e_ucomm,\n      on_print_top_of_page\n        FOR EVENT print_top_of_page OF cl_gui_alv_grid,\n      on_print_end_of_list\n        FOR EVENT print_end_of_list OF cl_gui_alv_grid.\nENDCLASS.\n\nDATA: go_handler TYPE REF TO lcl_event_handler.\n\n*----------------------------------------------------------------------*\n* Selection screen\n*----------------------------------------------------------------------*\nSELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE text-b01.\nSELECT-OPTIONS: s_carrid FOR sflight-carrid,\n                s_fldate FOR sflight-fldate.\nSELECTION-SCREEN END OF BLOCK b1.\n\n*----------------------------------------------------------------------*\nSTART-OF-SELECTION.\n*----------------------------------------------------------------------*\n  PERFORM get_data.\n\n  IF gt_out IS INITIAL.\n    MESSAGE 'No data found - nothing to approve' TYPE 'S'\n            DISPLAY LIKE 'W'.\n    RETURN.\n  ENDIF.\n\n  PERFORM load_or_init_header.\n\n  CALL SCREEN 0100.\n\n*&amp;---------------------------------------------------------------------*\n*&amp; Form GET_DATA\n*&amp;---------------------------------------------------------------------*\nFORM get_data.\n\n  DATA: lt_flight TYPE STANDARD TABLE OF sflight,\n        ls_flight TYPE sflight.\n\n  CLEAR gt_out.\n\n  SELECT carrid connid fldate price currency seatsocc\n    FROM sflight\n    INTO CORRESPONDING FIELDS OF TABLE lt_flight\n   WHERE carrid IN s_carrid\n     AND fldate IN s_fldate.\n\n  LOOP AT lt_flight INTO ls_flight.\n    CLEAR gs_out.\n    MOVE-CORRESPONDING ls_flight TO gs_out.\n    APPEND gs_out TO gt_out.\n  ENDLOOP.\n\n  SORT gt_out BY carrid connid fldate.\n\nENDFORM.\n\n*&amp;---------------------------------------------------------------------*\n*&amp; Form LOAD_OR_INIT_HEADER\n*&amp;---------------------------------------------------------------------*\n* In production: read the approval header from your Z-table using the\n* selection criteria (or a document number entered on the selection\n* screen). If none exists, the document is NEW.\n*&amp;---------------------------------------------------------------------*\nFORM load_or_init_header.\n\n  CLEAR gs_hdr.\n\n* --- TODO: SELECT SINGLE from z_appr_hdr here.\n*     If found, MOVE-CORRESPONDING into gs_hdr and RETURN.\n\n  gs_hdr-zstatus = gc_new.\n  PERFORM build_sel_text CHANGING gs_hdr-seltext.\n  DESCRIBE TABLE gt_out LINES gs_hdr-rowcount.\n  PERFORM calc_checksum CHANGING gs_hdr-checksum.\n\nENDFORM.\n\n*&amp;---------------------------------------------------------------------*\n*&amp; Form CALC_CHECKSUM\n*&amp;---------------------------------------------------------------------*\n* Fingerprint of the key fields. Stored at SUBMIT, re-checked at\n* APPROVE. If it moved, the data changed between the two steps and the\n* approval must not go through silently.\n*&amp;---------------------------------------------------------------------*\nFORM calc_checksum CHANGING cv_hash TYPE string.\n\n  DATA: ls_out  TYPE ty_out,\n        lv_keys TYPE string,\n        lv_line TYPE string.\n\n  LOOP AT gt_out INTO ls_out.\n    CONCATENATE ls_out-carrid ls_out-connid ls_out-fldate\n           INTO lv_line.\n    CONCATENATE lv_keys lv_line INTO lv_keys.\n  ENDLOOP.\n\n  CALL FUNCTION 'CALCULATE_HASH_FOR_CHAR'\n    EXPORTING\n      alg  = 'MD5'\n      data = lv_keys\n    IMPORTING\n      hashstring = cv_hash\n    EXCEPTIONS\n      OTHERS = 1.\n\n  IF sy-subrc &lt;> 0.\n*   fallback: at least keep the row count as a weak fingerprint\n    DESCRIBE TABLE gt_out LINES gs_hdr-rowcount.\n    CLEAR cv_hash.\n  ENDIF.\n\nENDFORM.\n\n*&amp;---------------------------------------------------------------------*\n*&amp; Module STATUS_0100 OUTPUT\n*&amp;---------------------------------------------------------------------*\nMODULE status_0100 OUTPUT.\n\n  SET PF-STATUS 'ST100'.\n  SET TITLEBAR  'TB100'.\n\n  IF go_dock IS INITIAL.\n    PERFORM build_containers.\n    PERFORM build_header.\n    PERFORM build_footer.\n    PERFORM build_alv.\n  ENDIF.\n\nENDMODULE.\n\n*&amp;---------------------------------------------------------------------*\n*&amp; Form BUILD_CONTAINERS\n*&amp;---------------------------------------------------------------------*\nFORM build_containers.\n\n  CREATE OBJECT go_dock\n    EXPORTING\n      repid                       = sy-repid\n      dynnr                       = sy-dynnr\n      side                        = cl_gui_docking_container=>dock_at_left\n      extension                   = 2000\n      no_autodef_progid_dynnr     = abap_true\n    EXCEPTIONS\n      cntl_error                  = 1\n      cntl_system_error           = 2\n      create_error                = 3\n      lifetime_error              = 4\n      lifetime_dynpro_dynpro_link = 5\n      OTHERS                      = 6.\n  IF sy-subrc &lt;> 0.\n    MESSAGE 'Could not create docking container' TYPE 'E'.\n  ENDIF.\n\n  CREATE OBJECT go_split\n    EXPORTING\n      parent  = go_dock\n      rows    = 3\n      columns = 1.\n\n* Absolute mode -> heights in pixels. If row 2 collapses on your\n* release, drop this call and use percentages instead.\n  CALL METHOD go_split->set_row_mode\n    EXPORTING mode = cl_gui_splitter_container=>mode_absolute.\n\n  CALL METHOD go_split->set_row_height\n    EXPORTING id = 1 height = gc_top_height.\n\n  CALL METHOD go_split->set_row_height\n    EXPORTING id = 3 height = gc_bot_height.\n\n  PERFORM lock_sash USING 1.\n  PERFORM lock_sash USING 2.\n\n  go_cont_top  = go_split->get_container( row = 1 column = 1 ).\n  go_cont_grid = go_split->get_container( row = 2 column = 1 ).\n  go_cont_bot  = go_split->get_container( row = 3 column = 1 ).\n\nENDFORM.\n\n*&amp;---------------------------------------------------------------------*\n*&amp; Form LOCK_SASH\n*&amp;---------------------------------------------------------------------*\nFORM lock_sash USING iv_id TYPE i.\n\n  CALL METHOD go_split->set_row_sash\n    EXPORTING id    = iv_id\n              type  = cl_gui_splitter_container=>type_movable\n              value = cl_gui_splitter_container=>false.\n\n  CALL METHOD go_split->set_row_sash\n    EXPORTING id    = iv_id\n              type  = cl_gui_splitter_container=>type_sashvisible\n              value = cl_gui_splitter_container=>false.\n\nENDFORM.\n\n*&amp;---------------------------------------------------------------------*\n*&amp; Form BUILD_HEADER\n*&amp;---------------------------------------------------------------------*\nFORM build_header.\n\n  DATA: lv_text TYPE sdydo_text_element,\n        lv_icon TYPE iconname,\n        lv_num  TYPE char10,\n        lv_dat  TYPE char10,\n        lv_tim  TYPE char10.\n\n  IF go_dd_top IS INITIAL.\n    CREATE OBJECT go_dd_top EXPORTING style = 'ALV_GRID'.\n  ENDIF.\n\n  CALL METHOD go_dd_top->initialize_document.\n\n* ---- Line 1 : title + document status\n  lv_text = 'Flight Approval Document'.\n  CALL METHOD go_dd_top->add_text\n    EXPORTING text         = lv_text\n              sap_style    = cl_dd_document=>heading\n              sap_emphasis = cl_dd_document=>strong.\n\n  CALL METHOD go_dd_top->add_gap EXPORTING width = 25.\n\n  CASE gs_hdr-zstatus.\n    WHEN gc_appr.  lv_icon = 'ICON_GREEN_LIGHT'.\n    WHEN gc_subm.  lv_icon = 'ICON_YELLOW_LIGHT'.\n    WHEN OTHERS.   lv_icon = 'ICON_LIGHT_OUT'.\n  ENDCASE.\n\n  CALL METHOD go_dd_top->add_icon\n    EXPORTING sap_icon = lv_icon.\n\n  lv_text = gs_hdr-zstatus.\n  CALL METHOD go_dd_top->add_text\n    EXPORTING text         = lv_text\n              sap_emphasis = cl_dd_document=>strong.\n\n  CALL METHOD go_dd_top->new_line.\n\n* ---- Line 2 : selection criteria + row count\n  lv_text = gs_hdr-seltext.\n  CALL METHOD go_dd_top->add_text\n    EXPORTING text = lv_text sap_style = cl_dd_document=>small.\n\n  CALL METHOD go_dd_top->add_gap EXPORTING width = 20.\n\n  WRITE gs_hdr-rowcount TO lv_num LEFT-JUSTIFIED.\n  CONCATENATE 'Records in this approval:' lv_num INTO lv_text\n         SEPARATED BY space.\n  CALL METHOD go_dd_top->add_text\n    EXPORTING text         = lv_text\n              sap_emphasis = cl_dd_document=>strong.\n\n  CALL METHOD go_dd_top->new_line.\n\n* ---- Line 3 : audit trail\n  CLEAR lv_text.\n  IF gs_hdr-subm_by IS NOT INITIAL.\n    WRITE gs_hdr-subm_date TO lv_dat.\n    WRITE gs_hdr-subm_time TO lv_tim.\n    CONCATENATE 'Submitted by' gs_hdr-subm_by 'on' lv_dat lv_tim\n           INTO lv_text SEPARATED BY space.\n  ELSE.\n    lv_text = 'Not yet submitted'.\n  ENDIF.\n  CALL METHOD go_dd_top->add_text\n    EXPORTING text = lv_text sap_style = cl_dd_document=>small.\n\n  CALL METHOD go_dd_top->add_gap EXPORTING width = 10.\n\n  CLEAR lv_text.\n  IF gs_hdr-appr_by IS NOT INITIAL.\n    WRITE gs_hdr-appr_date TO lv_dat.\n    WRITE gs_hdr-appr_time TO lv_tim.\n    CONCATENATE '| Approved by' gs_hdr-appr_by 'on' lv_dat lv_tim\n           INTO lv_text SEPARATED BY space.\n    CALL METHOD go_dd_top->add_text\n      EXPORTING text = lv_text sap_style = cl_dd_document=>small.\n  ENDIF.\n\n  CALL METHOD go_dd_top->merge_document.\n\n  IF gv_top_shown = abap_false.\n    CALL METHOD go_dd_top->display_document\n      EXPORTING parent = go_cont_top\n      EXCEPTIONS OTHERS = 1.\n    gv_top_shown = abap_true.\n  ELSE.\n    CALL METHOD go_dd_top->display_document\n      EXPORTING reuse_control = abap_true\n                parent        = go_cont_top\n      EXCEPTIONS OTHERS = 1.\n  ENDIF.\n\nENDFORM.\n\n*&amp;---------------------------------------------------------------------*\n*&amp; Form BUILD_SEL_TEXT\n*&amp;---------------------------------------------------------------------*\nFORM build_sel_text CHANGING cv_text TYPE string.\n\n  DATA: lv_carr TYPE string,\n        lv_date TYPE string,\n        lv_lo   TYPE char20,\n        lv_hi   TYPE char20.\n\n  IF s_carrid&#91;] IS INITIAL.\n    lv_carr = 'All'.\n  ELSE.\n    READ TABLE s_carrid INDEX 1.\n    lv_lo = s_carrid-low.\n    IF s_carrid-high IS INITIAL.\n      lv_carr = lv_lo.\n    ELSE.\n      lv_hi = s_carrid-high.\n      CONCATENATE lv_lo '-' lv_hi INTO lv_carr SEPARATED BY space.\n    ENDIF.\n  ENDIF.\n\n  IF s_fldate&#91;] IS INITIAL.\n    lv_date = 'All'.\n  ELSE.\n    READ TABLE s_fldate INDEX 1.\n    WRITE s_fldate-low TO lv_lo.\n    IF s_fldate-high IS INITIAL.\n      lv_date = lv_lo.\n    ELSE.\n      WRITE s_fldate-high TO lv_hi.\n      CONCATENATE lv_lo '-' lv_hi INTO lv_date SEPARATED BY space.\n    ENDIF.\n  ENDIF.\n\n  CONCATENATE 'Carrier:' lv_carr '|' 'Flight date:' lv_date\n         INTO cv_text SEPARATED BY space.\n\nENDFORM.\n\n*&amp;---------------------------------------------------------------------*\n*&amp; Form BUILD_FOOTER\n*&amp;---------------------------------------------------------------------*\n* One signature block for the whole document. Names and dates fill\n* themselves in as the document moves through the statuses.\n*&amp;---------------------------------------------------------------------*\nFORM build_footer.\n\n  DATA: lo_table TYPE REF TO cl_dd_table_element,\n        lo_col1  TYPE REF TO cl_dd_area,\n        lo_col2  TYPE REF TO cl_dd_area,\n        lv_text  TYPE sdydo_text_element,\n        lv_line  TYPE sdydo_text_element,\n        lv_dat   TYPE char10.\n\n  lv_line = '____________________________'.\n\n  IF go_dd_bot IS INITIAL.\n    CREATE OBJECT go_dd_bot EXPORTING style = 'ALV_GRID'.\n  ENDIF.\n\n  CALL METHOD go_dd_bot->initialize_document.\n\n  CALL METHOD go_dd_bot->add_table\n    EXPORTING no_of_columns               = 2\n              border                      = '0'\n              width                       = '100%'\n              cell_background_transparent = abap_true\n    IMPORTING table                       = lo_table.\n\n  CALL METHOD lo_table->add_column\n    EXPORTING width = '50%' IMPORTING column = lo_col1.\n  CALL METHOD lo_table->add_column\n    EXPORTING width = '50%' IMPORTING column = lo_col2.\n\n* ---- Row 1 : the signer, or a blank line if not signed yet\n  IF gs_hdr-subm_by IS NOT INITIAL.\n    WRITE gs_hdr-subm_date TO lv_dat.\n    CONCATENATE gs_hdr-subm_by '\/' lv_dat INTO lv_text\n           SEPARATED BY space.\n  ELSE.\n    lv_text = lv_line.\n  ENDIF.\n  CALL METHOD lo_col1->add_text EXPORTING text = lv_text.\n\n  IF gs_hdr-appr_by IS NOT INITIAL.\n    WRITE gs_hdr-appr_date TO lv_dat.\n    CONCATENATE gs_hdr-appr_by '\/' lv_dat INTO lv_text\n           SEPARATED BY space.\n  ELSE.\n    lv_text = lv_line.\n  ENDIF.\n  CALL METHOD lo_col2->add_text EXPORTING text = lv_text.\n\n  CALL METHOD lo_table->new_row.\n\n* ---- Row 2 : roles\n  lv_text = 'Submitted by'.\n  CALL METHOD lo_col1->add_text\n    EXPORTING text = lv_text sap_style = cl_dd_document=>small.\n\n  lv_text = 'Approved by'.\n  CALL METHOD lo_col2->add_text\n    EXPORTING text = lv_text sap_style = cl_dd_document=>small.\n\n  CALL METHOD go_dd_bot->merge_document.\n\n  IF gv_bot_shown = abap_false.\n    CALL METHOD go_dd_bot->display_document\n      EXPORTING parent = go_cont_bot\n      EXCEPTIONS OTHERS = 1.\n    gv_bot_shown = abap_true.\n  ELSE.\n    CALL METHOD go_dd_bot->display_document\n      EXPORTING reuse_control = abap_true\n                parent        = go_cont_bot\n      EXCEPTIONS OTHERS = 1.\n  ENDIF.\n\nENDFORM.\n\n*&amp;---------------------------------------------------------------------*\n*&amp; Form BUILD_ALV\n*&amp;---------------------------------------------------------------------*\nFORM build_alv.\n\n  DATA: lt_fcat TYPE lvc_t_fcat,\n        ls_layo TYPE lvc_s_layo,\n        ls_vari TYPE disvariant.\n\n  CREATE OBJECT go_grid\n    EXPORTING i_parent = go_cont_grid.\n\n  CREATE OBJECT go_handler.\n  SET HANDLER go_handler->on_toolbar           FOR go_grid.\n  SET HANDLER go_handler->on_user_command      FOR go_grid.\n  SET HANDLER go_handler->on_print_top_of_page FOR go_grid.\n  SET HANDLER go_handler->on_print_end_of_list FOR go_grid.\n\n  PERFORM build_fieldcat CHANGING lt_fcat.\n\n* Row selection is meaningless here - the whole list is the document.\n  ls_layo-sel_mode   = 'B'.            \" single row, navigation only\n  ls_layo-no_rowmark = abap_true.      \" no selection column\n  ls_layo-zebra      = abap_true.\n  ls_layo-cwidth_opt = abap_true.\n\n  ls_vari-report = sy-repid.\n  ls_vari-handle = 'MAIN'.\n\n  CALL METHOD go_grid->set_table_for_first_display\n    EXPORTING is_variant      = ls_vari\n              i_save          = 'A'\n              is_layout       = ls_layo\n    CHANGING  it_fieldcatalog = lt_fcat\n              it_outtab       = gt_out.\n\nENDFORM.\n\n*&amp;---------------------------------------------------------------------*\n*&amp; Form BUILD_FIELDCAT\n*&amp;---------------------------------------------------------------------*\nFORM build_fieldcat CHANGING ct_fcat TYPE lvc_t_fcat.\n\n  DATA: ls_fcat TYPE lvc_s_fcat,\n        lv_pos  TYPE i.\n\n  DEFINE add_field.\n    lv_pos = lv_pos + 1.\n    CLEAR ls_fcat.\n    ls_fcat-col_pos   = lv_pos.\n    ls_fcat-fieldname = &amp;1.\n    ls_fcat-scrtext_l = &amp;2.\n    ls_fcat-scrtext_m = &amp;2.\n    ls_fcat-scrtext_s = &amp;2.\n    ls_fcat-coltext   = &amp;2.\n    ls_fcat-outputlen = &amp;3.\n    APPEND ls_fcat TO ct_fcat.\n  END-OF-DEFINITION.\n\n  add_field 'CARRID'   'Carrier'      8.\n  add_field 'CONNID'   'Connection'  10.\n  add_field 'FLDATE'   'Flight Date' 12.\n  add_field 'PRICE'    'Price'       15.\n  add_field 'CURRENCY' 'Curr.'        5.\n  add_field 'SEATSOCC' 'Occupied'    10.\n\n  READ TABLE ct_fcat INTO ls_fcat WITH KEY fieldname = 'PRICE'.\n  IF sy-subrc = 0.\n    ls_fcat-cfieldname = 'CURRENCY'.\n    ls_fcat-do_sum     = abap_true.\n    MODIFY ct_fcat FROM ls_fcat INDEX sy-tabix.\n  ENDIF.\n\nENDFORM.\n\n*&amp;---------------------------------------------------------------------*\n*&amp; Form DO_SUBMIT\n*&amp;---------------------------------------------------------------------*\nFORM do_submit.\n\n  DATA: lv_answer TYPE char1,\n        lv_num    TYPE char10,\n        lv_quest  TYPE string.\n\n  IF gs_hdr-zstatus &lt;> gc_new.\n    MESSAGE 'Document has already been submitted' TYPE 'S'\n            DISPLAY LIKE 'W'.\n    RETURN.\n  ENDIF.\n\n  WRITE gs_hdr-rowcount TO lv_num LEFT-JUSTIFIED.\n  CONCATENATE 'Submit all' lv_num 'records as one approval document?'\n         INTO lv_quest SEPARATED BY space.\n\n  PERFORM confirm USING lv_quest CHANGING lv_answer.\n  CHECK lv_answer = '1'.\n\n  PERFORM lock_document.\n  CHECK sy-subrc = 0.\n\n* ---- freeze the snapshot\n  PERFORM calc_checksum CHANGING gs_hdr-checksum.\n  DESCRIBE TABLE gt_out LINES gs_hdr-rowcount.\n\n  gs_hdr-zstatus   = gc_subm.\n  gs_hdr-subm_by   = sy-uname.\n  gs_hdr-subm_date = sy-datum.\n  gs_hdr-subm_time = sy-uzeit.\n\n* ------------------------------------------------------------------\n* TODO: persist here.\n*   - get a document number from NUMBER_GET_NEXT\n*   - INSERT the header into z_appr_hdr\n*   - INSERT gt_out into z_appr_itm  &lt;-- THE FROZEN SNAPSHOT.\n*     This is what makes the approval auditable. Without it you are\n*     approving a selection screen, not a set of records.\n* ------------------------------------------------------------------\n\n  COMMIT WORK AND WAIT.\n  PERFORM unlock_document.\n\n  PERFORM refresh_screen.\n  MESSAGE 'Document submitted for approval' TYPE 'S'.\n\nENDFORM.\n\n*&amp;---------------------------------------------------------------------*\n*&amp; Form DO_APPROVE\n*&amp;---------------------------------------------------------------------*\nFORM do_approve.\n\n  DATA: lv_answer TYPE char1,\n        lv_hash   TYPE string,\n        lv_count  TYPE i,\n        lv_quest  TYPE string.\n\n  IF gs_hdr-zstatus &lt;> gc_subm.\n    MESSAGE 'Only a submitted document can be approved' TYPE 'S'\n            DISPLAY LIKE 'W'.\n    RETURN.\n  ENDIF.\n\n* ---- segregation of duties\n  IF gc_sod_check = abap_true AND gs_hdr-subm_by = sy-uname.\n    MESSAGE 'You cannot approve a document you submitted yourself'\n            TYPE 'S' DISPLAY LIKE 'E'.\n    RETURN.\n  ENDIF.\n\n* ---- authorization\n* AUTHORITY-CHECK OBJECT 'Z_APPROVE' ID 'ACTVT' FIELD '43'.\n* IF sy-subrc &lt;> 0.\n*   MESSAGE 'No approval authorization' TYPE 'S' DISPLAY LIKE 'E'.\n*   RETURN.\n* ENDIF.\n\n* ---- did the data move between submit and approve?\n  PERFORM get_data.\n  DESCRIBE TABLE gt_out LINES lv_count.\n  PERFORM calc_checksum CHANGING lv_hash.\n\n  IF lv_count &lt;> gs_hdr-rowcount OR lv_hash &lt;> gs_hdr-checksum.\n    MESSAGE 'Data changed since submission - resubmit required'\n            TYPE 'S' DISPLAY LIKE 'E'.\n    PERFORM refresh_screen.\n    RETURN.\n  ENDIF.\n\n  lv_quest = 'Approve this document in full?'.\n  PERFORM confirm USING lv_quest CHANGING lv_answer.\n  CHECK lv_answer = '1'.\n\n  PERFORM lock_document.\n  CHECK sy-subrc = 0.\n\n  gs_hdr-zstatus   = gc_appr.\n  gs_hdr-appr_by   = sy-uname.\n  gs_hdr-appr_date = sy-datum.\n  gs_hdr-appr_time = sy-uzeit.\n\n* ---- TODO: UPDATE z_appr_hdr with status \/ approver \/ timestamp\n\n  COMMIT WORK AND WAIT.\n  PERFORM unlock_document.\n\n  PERFORM refresh_screen.\n  MESSAGE 'Document approved' TYPE 'S'.\n\nENDFORM.\n\n*&amp;---------------------------------------------------------------------*\n*&amp; Form CONFIRM\n*&amp;---------------------------------------------------------------------*\nFORM confirm USING iv_question TYPE string\n             CHANGING cv_answer TYPE char1.\n\n  DATA: lv_q TYPE string.\n\n  lv_q = iv_question.\n\n  CALL FUNCTION 'POPUP_TO_CONFIRM'\n    EXPORTING\n      titlebar              = 'Confirm'\n      text_question         = lv_q\n      text_button_1         = 'Yes'\n      text_button_2         = 'No'\n      default_button        = '2'\n      display_cancel_button = abap_false\n    IMPORTING\n      answer                = cv_answer\n    EXCEPTIONS\n      OTHERS                = 1.\n\nENDFORM.\n\n*&amp;---------------------------------------------------------------------*\n*&amp; Form LOCK_DOCUMENT \/ UNLOCK_DOCUMENT\n*&amp;---------------------------------------------------------------------*\n* One lock for the whole document, not one per row.\n*&amp;---------------------------------------------------------------------*\nFORM lock_document.\n\n* CALL FUNCTION 'ENQUEUE_EZ_APPR_HDR'\n*   EXPORTING  docno          = gs_hdr-docno\n*   EXCEPTIONS foreign_lock   = 1\n*              system_failure = 2\n*              OTHERS         = 3.\n* IF sy-subrc &lt;> 0.\n*   MESSAGE 'Document is locked by another user' TYPE 'S'\n*           DISPLAY LIKE 'E'.\n* ENDIF.\n\n  sy-subrc = 0.\n\nENDFORM.\n\nFORM unlock_document.\n\n* CALL FUNCTION 'DEQUEUE_EZ_APPR_HDR'\n*   EXPORTING docno = gs_hdr-docno.\n\nENDFORM.\n\n*&amp;---------------------------------------------------------------------*\n*&amp; Form REFRESH_SCREEN\n*&amp;---------------------------------------------------------------------*\nFORM refresh_screen.\n\n  DATA: ls_stable TYPE lvc_s_stbl.\n\n  PERFORM build_header.\n  PERFORM build_footer.\n\n  ls_stable-row = abap_true.\n  ls_stable-col = abap_true.\n  CALL METHOD go_grid->refresh_table_display\n    EXPORTING is_stable = ls_stable.\n\n* forces the TOOLBAR event to fire again so button states update\n  CALL METHOD go_grid->set_toolbar_interactive.\n\nENDFORM.\n\n*&amp;---------------------------------------------------------------------*\n*&amp; Module USER_COMMAND_0100 INPUT\n*&amp;---------------------------------------------------------------------*\nMODULE user_command_0100 INPUT.\n\n  DATA: lv_ucomm TYPE sy-ucomm.\n\n  lv_ucomm = gv_ok_code.\n  CLEAR gv_ok_code.\n\n  CASE lv_ucomm.\n    WHEN 'BACK' OR 'EXIT' OR 'CANC'.\n      PERFORM free_controls.\n      LEAVE TO SCREEN 0.\n  ENDCASE.\n\nENDMODULE.\n\n*&amp;---------------------------------------------------------------------*\n*&amp; Form FREE_CONTROLS\n*&amp;---------------------------------------------------------------------*\nFORM free_controls.\n\n  IF go_grid IS NOT INITIAL.\n    CALL METHOD go_grid->free.\n    CLEAR go_grid.\n  ENDIF.\n\n  IF go_split IS NOT INITIAL.\n    CALL METHOD go_split->free.\n    CLEAR go_split.\n  ENDIF.\n\n  IF go_dock IS NOT INITIAL.\n    CALL METHOD go_dock->free.\n    CLEAR go_dock.\n  ENDIF.\n\n  CLEAR: go_cont_top, go_cont_grid, go_cont_bot,\n         go_dd_top, go_dd_bot, gv_top_shown, gv_bot_shown.\n\n  CALL METHOD cl_gui_cfw=>flush.\n\nENDFORM.\n\n*&amp;---------------------------------------------------------------------*\n*&amp; CLASS lcl_event_handler IMPLEMENTATION\n*&amp;---------------------------------------------------------------------*\nCLASS lcl_event_handler IMPLEMENTATION.\n\n  METHOD on_toolbar.\n\n    DATA: ls_btn TYPE stb_button.\n\n    CLEAR ls_btn.\n    ls_btn-butn_type = 3.                       \" separator\n    APPEND ls_btn TO e_object->mt_toolbar.\n\n*   ---- SUBMIT : only while the document is NEW\n    CLEAR ls_btn.\n    ls_btn-function  = 'SUBMIT'.\n    ls_btn-icon      = icon_system_save.\n    ls_btn-text      = 'Submit'.\n    ls_btn-quickinfo = 'Submit the entire list for approval'.\n    ls_btn-butn_type = 0.\n    IF gs_hdr-zstatus &lt;> gc_new.\n      ls_btn-disabled = abap_true.\n    ENDIF.\n    APPEND ls_btn TO e_object->mt_toolbar.\n\n*   ---- APPROVE : only while the document is SUBMITTED\n    CLEAR ls_btn.\n    ls_btn-function  = 'APPROVE'.\n    ls_btn-icon      = icon_okay.\n    ls_btn-text      = 'Approve'.\n    ls_btn-quickinfo = 'Approve the entire document'.\n    ls_btn-butn_type = 0.\n    IF gs_hdr-zstatus &lt;> gc_subm.\n      ls_btn-disabled = abap_true.\n    ENDIF.\n    IF gc_sod_check = abap_true AND gs_hdr-subm_by = sy-uname.\n      ls_btn-disabled = abap_true.\n    ENDIF.\n    APPEND ls_btn TO e_object->mt_toolbar.\n\n  ENDMETHOD.\n\n  METHOD on_user_command.\n\n    CASE e_ucomm.\n      WHEN 'SUBMIT'.  PERFORM do_submit.\n      WHEN 'APPROVE'. PERFORM do_approve.\n    ENDCASE.\n\n  ENDMETHOD.\n\n* --------------------------------------------------------------------\n* The splitter header\/footer are SCREEN ONLY. These handlers put the\n* same content on the printout - which is where a signature block\n* normally has to end up.\n* --------------------------------------------------------------------\n  METHOD on_print_top_of_page.\n\n    WRITE: \/ 'Flight Approval Document'.\n    WRITE: \/ gs_hdr-seltext.\n    WRITE: \/ 'Records:', gs_hdr-rowcount,\n             '  Status:', gs_hdr-zstatus.\n    ULINE.\n\n  ENDMETHOD.\n\n  METHOD on_print_end_of_list.\n\n    SKIP 3.\n    WRITE: \/5 '____________________________',\n           60 '____________________________'.\n    WRITE: \/5 'Submitted by', 60 'Approved by'.\n\n    IF gs_hdr-subm_by IS NOT INITIAL.\n      WRITE: \/5 gs_hdr-subm_by, gs_hdr-subm_date.\n    ENDIF.\n    IF gs_hdr-appr_by IS NOT INITIAL.\n      WRITE: 60 gs_hdr-appr_by, gs_hdr-appr_date.\n    ENDIF.\n\n  ENDMETHOD.\n\nENDCLASS.\n\n*&amp;---------------------------------------------------------------------*\n* WHAT YOU STILL HAVE TO CREATE MANUALLY\n*&amp;---------------------------------------------------------------------*\n* 1) Screen 0100 (SE51\/SE80, type \"Normal\", layout EMPTY):\n*      PROCESS BEFORE OUTPUT.\n*        MODULE status_0100.\n*      PROCESS AFTER INPUT.\n*        MODULE user_command_0100.\n*    Element list: GV_OK_CODE, type OK, length 20.\n*\n* 2) GUI status 'ST100' with BACK \/ EXIT \/ CANC only.\n*\n* 3) Title 'TB100'.  Text symbol text-b01 = 'Selection'.\n*\n* 4) Two Z-tables (this is the part that actually matters):\n*      Z_APPR_HDR - docno, status, seltext, rowcount, checksum,\n*                   subm_by\/date\/time, appr_by\/date\/time\n*      Z_APPR_ITM - docno, posnr, + the key fields of each row\n*    plus lock object EZ_APPR_HDR on Z_APPR_HDR.\n*&amp;---------------------------------------------------------------------*\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[],"_links":{"self":[{"href":"https:\/\/sapabap.dwimansolution.com\/index.php\/wp-json\/wp\/v2\/posts\/288"}],"collection":[{"href":"https:\/\/sapabap.dwimansolution.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sapabap.dwimansolution.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sapabap.dwimansolution.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/sapabap.dwimansolution.com\/index.php\/wp-json\/wp\/v2\/comments?post=288"}],"version-history":[{"count":1,"href":"https:\/\/sapabap.dwimansolution.com\/index.php\/wp-json\/wp\/v2\/posts\/288\/revisions"}],"predecessor-version":[{"id":289,"href":"https:\/\/sapabap.dwimansolution.com\/index.php\/wp-json\/wp\/v2\/posts\/288\/revisions\/289"}],"wp:attachment":[{"href":"https:\/\/sapabap.dwimansolution.com\/index.php\/wp-json\/wp\/v2\/media?parent=288"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sapabap.dwimansolution.com\/index.php\/wp-json\/wp\/v2\/categories?post=288"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sapabap.dwimansolution.com\/index.php\/wp-json\/wp\/v2\/tags?post=288"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}