*&---------------------------------------------------------------------* *& Report Z_ERPFORGE_04_DD_DUMP *&---------------------------------------------------------------------* *& ERPForgeAI - Step 4: DD-Steckbrief (Pre-Flight for Code Generation) *& *& -- GOVERNANCE (read in under a minute) ------------------------------ *& READS : Pre-flight data-dictionary METADATA for code generation - *& DD03L/DD04T field definitions, TADIR object-type counts. *& No table rows are read. *& DOES NOT : No UPDATE/INSERT/MODIFY/DELETE on DB tables (read-only). *& No RFC, no DESTINATION, no network/internet. No server-side *& file write. No business data / table rows / PII is read. *& Output is SAP METADATA only (structure, not contents) - *& nothing leaves your system unless YOU export it. *& FOOTPRINT: Transient analysis report - delete after extraction. *& SOURCE : MIT-licensed; public source + SHA-256 checksum at *& https://erpforgeai.de/sap-tools.html *& --------------------------------------------------------------------- *& Run this BEFORE asking the AI to generate any new Z* report. *& *& Builds on the working Z_DD_EXPORT v0.1 (DD03L + DD04T export). *& Adds three sections that prevent the most common "AI guessed wrong" *& syntax errors observed during the Z_ERPFORGE_03 iteration (Mar 2026): *& *& Section A - DD FIELDS (existing Z_DD_EXPORT, default tables EXTENDED) *& -> stops field-name and type guesses (TDDATUM vs TDLDATE, *& TADIR.OBJ_NAME 40 vs STXH.TDNAME 70, ...) *& *& Section B - TADIR OBJECT TYPES on this system *& -> stops object-type guesses (does FPLY/FPCT exist? FAPL? SSFO?) *& -> distinct OBJECT values + count, customer-vs-SAP split *& *& Section C - NACE APPLICATION KEYS configured (T685A) *& -> stops KAPPL guesses (EB? V3? V1? on this Versorger?) *& *& Section D - CUSTOMER SEARCH-HELPS (DD30L Z*/Y*) *& -> stops MATCHCODE OBJECT guesses (e.g. ZH_DEVCLASS exists?) *& *& Compatible: SAP_BASIS 7.40 SP02+ (target system : 750 SP34) *& *& Workflow: *& 1) Z_ERPFORGE_01_STECKBRIEF -> system capabilities *& 2) Z_ERPFORGE_02_EXPORT -> repository inventory *& 3) Z_ERPFORGE_03_FORMS_INV -> forms inventory *& 4) Z_ERPFORGE_04_DD_DUMP -> DD-Steckbrief (this report) *& ALL FOUR txt files together = zero-guess input for ERPforgeAI *&---------------------------------------------------------------------* REPORT z_erpforge_04_dd_dump. *----------------------------------------------------------------------* * Types - Section A (DD fields, unchanged from Z_DD_EXPORT) *----------------------------------------------------------------------* TYPES: BEGIN OF ty_field, tabname TYPE dd03l-tabname, fieldname TYPE dd03l-fieldname, position TYPE dd03l-position, datatype TYPE dd03l-datatype, leng TYPE dd03l-leng, decimals TYPE dd03l-decimals, rollname TYPE dd03l-rollname, domname TYPE dd03l-domname, keyflag TYPE dd03l-keyflag, notnull TYPE dd03l-notnull, ddtext TYPE dd04t-ddtext, END OF ty_field. *----------------------------------------------------------------------* * Types - Section B (TADIR object types) *----------------------------------------------------------------------* TYPES: BEGIN OF ty_obj_type, object TYPE tadir-object, total_cnt TYPE i, sap_cnt TYPE i, " author = SAP / DDIC / starts with SAP cust_cnt TYPE i, " everything else END OF ty_obj_type. *----------------------------------------------------------------------* * Types - Section C (NACE application keys) *----------------------------------------------------------------------* TYPES: BEGIN OF ty_kappl, kappl TYPE t685a-kappl, output_cnt TYPE i, " number of distinct KSCHL configured END OF ty_kappl. *----------------------------------------------------------------------* * Types - Section D (customer search helps) *----------------------------------------------------------------------* TYPES: BEGIN OF ty_shlp, shlpname TYPE dd30l-shlpname, selmtype TYPE dd30l-selmtype, " selection-method type ddtext TYPE dd30t-ddtext, END OF ty_shlp. *----------------------------------------------------------------------* * Globals *----------------------------------------------------------------------* DATA: gt_fields TYPE TABLE OF ty_field, gs_field TYPE ty_field. DATA: gt_objs TYPE TABLE OF ty_obj_type, gs_obj TYPE ty_obj_type. DATA: gt_kappl TYPE TABLE OF ty_kappl, gs_kappl TYPE ty_kappl. DATA: gt_shlp TYPE TABLE OF ty_shlp, gs_shlp TYPE ty_shlp. *----------------------------------------------------------------------* * Selection screen *----------------------------------------------------------------------* SELECTION-SCREEN BEGIN OF BLOCK b01 WITH FRAME TITLE gt_b01. SELECT-OPTIONS tabnames FOR gs_field-tabname. SELECTION-SCREEN END OF BLOCK b01. SELECTION-SCREEN BEGIN OF BLOCK b02 WITH FRAME TITLE gt_b02. SELECTION-SCREEN BEGIN OF LINE. PARAMETERS p_dd AS CHECKBOX DEFAULT 'X'. SELECTION-SCREEN COMMENT 3(60) t_dd. SELECTION-SCREEN END OF LINE. SELECTION-SCREEN BEGIN OF LINE. PARAMETERS p_obj AS CHECKBOX DEFAULT ' '. SELECTION-SCREEN COMMENT 3(60) t_obj. SELECTION-SCREEN END OF LINE. SELECTION-SCREEN BEGIN OF LINE. PARAMETERS p_kappl AS CHECKBOX DEFAULT 'X'. SELECTION-SCREEN COMMENT 3(60) t_kappl. SELECTION-SCREEN END OF LINE. SELECTION-SCREEN BEGIN OF LINE. PARAMETERS p_shlp AS CHECKBOX DEFAULT 'X'. SELECTION-SCREEN COMMENT 3(60) t_shlp. SELECTION-SCREEN END OF LINE. SELECTION-SCREEN END OF BLOCK b02. SELECTION-SCREEN BEGIN OF BLOCK b03 WITH FRAME TITLE gt_b03. SELECTION-SCREEN BEGIN OF LINE. PARAMETERS p_excel AS CHECKBOX DEFAULT 'X'. SELECTION-SCREEN COMMENT 3(60) t_excel. SELECTION-SCREEN END OF LINE. SELECTION-SCREEN BEGIN OF LINE. PARAMETERS p_key AS CHECKBOX DEFAULT ' '. SELECTION-SCREEN COMMENT 3(60) t_key. SELECTION-SCREEN END OF LINE. SELECTION-SCREEN END OF BLOCK b03. INITIALIZATION. gt_b01 = 'Tabellen fuer DD-Felder-Export'. gt_b02 = 'Sektionen'. gt_b03 = 'Output-Optionen'. t_dd = 'Feldnamen, Typen, Laengen aus DD03L (verhindert Feld-Raten)'. t_obj = 'Sektion B: TADIR-Histogramm — LANGE LAUFZEIT (Hintergrund)'. t_kappl = 'Konfigurierte NACE-Applikationen + Anzahl Konditionsarten'. t_shlp = 'Z*/Y* Suchhilfen mit Beschreibung (fuer MATCHCODE OBJECT)'. t_excel = 'Tab-getrennten TXT zusaetzlich speichern'. t_key = 'Filter: nur Schluesselfelder anzeigen (Sektion A)'. " Pre-fill tabnames with the high-value tables for this customer. " Operator can override on the selection screen. PERFORM seed_default_tables. *----------------------------------------------------------------------* START-OF-SELECTION. IF p_dd = 'X'. PERFORM section_a_dd_fields. ENDIF. IF p_obj = 'X'. PERFORM section_b_tadir_objects. ENDIF. IF p_kappl = 'X'. PERFORM section_c_nace_kappl. ENDIF. IF p_shlp = 'X'. PERFORM section_d_search_helps. ENDIF. IF p_excel = 'X'. PERFORM export_excel. ENDIF. PERFORM display_results. *&---------------------------------------------------------------------* *& seed_default_tables - high-value defaults derived from this session *&---------------------------------------------------------------------* FORM seed_default_tables. DATA: ls_range LIKE LINE OF tabnames. DATA: lt_seed TYPE TABLE OF dd03l-tabname. DATA: lv_t TYPE dd03l-tabname. " Tables that bit us during Z_ERPFORGE_03 iteration + likely candidates " for any future utility/IS-U-flavoured forms or output work. APPEND 'STXH' TO lt_seed. " SAPscript headers APPEND 'STXL' TO lt_seed. " SAPscript ITF lines APPEND 'STXFADM' TO lt_seed. " SmartForms admin APPEND 'TADIR' TO lt_seed. " Repository directory APPEND 'TNAPR' TO lt_seed. " NACE program/form mapping APPEND 'NAST' TO lt_seed. " Output records APPEND 'T685' TO lt_seed. " Output condition tables APPEND 'T685A' TO lt_seed. " Output condition apps (KAPPL) APPEND 'DD30L' TO lt_seed. " Search helps APPEND 'DD30T' TO lt_seed. ls_range-sign = 'I'. ls_range-option = 'EQ'. LOOP AT lt_seed INTO lv_t. ls_range-low = lv_t. APPEND ls_range TO tabnames. ENDLOOP. ENDFORM. *&---------------------------------------------------------------------* *& Section A - DD fields *& v0.4: added two defensive guards. v0.3 dumped with TSV_TNEW_PAGE_ *& ALLOC_FAILED in LT_DOMS at 6M rows because the tabnames seed *& hadn't been applied (or was cleared by the user), so the *& WHERE tabname IN tabnames matched ALL of DD03L. Never trust *& INITIALIZATION-time defaults to be present at runtime. *& v0.3: replaced LEFT OUTER JOIN approach (v0.2) with three bounded *& queries. *&---------------------------------------------------------------------* FORM section_a_dd_fields. CONSTANTS: lc_max_fields TYPE i VALUE 50000. " Guard 1: refuse to run if tabnames is empty. An empty SELECT-OPTIONS " range matches everything (every row in DD03L = millions of fields). IF tabnames[] IS INITIAL. MESSAGE 'Section A skipped: tabnames is empty (would dump full DD03L).' TYPE 'I'. RETURN. ENDIF. " Step 1: pull the DD03L rows for the requested tables. SELECT d~tabname d~fieldname d~position d~datatype d~leng d~decimals d~rollname d~domname d~keyflag d~notnull FROM dd03l AS d INTO CORRESPONDING FIELDS OF TABLE gt_fields UP TO lc_max_fields ROWS WHERE d~tabname IN tabnames AND d~as4local = 'A' AND d~fieldname NOT LIKE '.%' AND d~fieldname NOT LIKE '/%' ORDER BY d~tabname d~position. IF gt_fields IS INITIAL. RETURN. ENDIF. " Guard 2: if we hit the row cap, the tabnames range was too broad. " Refuse to continue rather than build huge rollname/domain lists. IF lines( gt_fields ) >= lc_max_fields. CLEAR gt_fields. MESSAGE |Section A skipped: tabnames matched > { lc_max_fields } fields. Narrow the table list.| TYPE 'I'. RETURN. ENDIF. " Step 2: collect distinct rollnames and domnames from gt_fields. TYPES: BEGIN OF ty_roll_key, rollname TYPE dd03l-rollname, END OF ty_roll_key. TYPES: BEGIN OF ty_dom_key, domname TYPE dd03l-domname, END OF ty_dom_key. DATA: lt_rolls TYPE TABLE OF ty_roll_key, lt_doms TYPE TABLE OF ty_dom_key. DATA: ls_roll TYPE ty_roll_key, ls_dom TYPE ty_dom_key. LOOP AT gt_fields ASSIGNING FIELD-SYMBOL(). IF -rollname IS NOT INITIAL. ls_roll-rollname = -rollname. APPEND ls_roll TO lt_rolls. ENDIF. IF -domname IS NOT INITIAL. ls_dom-domname = -domname. APPEND ls_dom TO lt_doms. ENDIF. ENDLOOP. SORT lt_rolls. DELETE ADJACENT DUPLICATES FROM lt_rolls. SORT lt_doms. DELETE ADJACENT DUPLICATES FROM lt_doms. " Step 3: batched lookup for rollname descriptions (dd04t). TYPES: BEGIN OF ty_dd04t, rollname TYPE dd04t-rollname, ddtext TYPE dd04t-ddtext, END OF ty_dd04t. DATA: lt_dd04t TYPE TABLE OF ty_dd04t. IF lt_rolls IS NOT INITIAL. SELECT rollname ddtext FROM dd04t INTO TABLE lt_dd04t FOR ALL ENTRIES IN lt_rolls WHERE rollname = lt_rolls-rollname AND ddlanguage = sy-langu AND as4local = 'A'. SORT lt_dd04t BY rollname. ENDIF. " Step 4: batched lookup for domain descriptions (dd01t). TYPES: BEGIN OF ty_dd01t, domname TYPE dd01t-domname, ddtext TYPE dd01t-ddtext, END OF ty_dd01t. DATA: lt_dd01t TYPE TABLE OF ty_dd01t. IF lt_doms IS NOT INITIAL. SELECT domname ddtext FROM dd01t INTO TABLE lt_dd01t FOR ALL ENTRIES IN lt_doms WHERE domname = lt_doms-domname AND ddlanguage = sy-langu AND as4local = 'A'. SORT lt_dd01t BY domname. ENDIF. " Step 5: merge descriptions back into gt_fields. Rollname text wins; " domain text is the fallback (preserving original v0.1 precedence). DATA: ls_dd04t TYPE ty_dd04t, ls_dd01t TYPE ty_dd01t. LOOP AT gt_fields ASSIGNING FIELD-SYMBOL(). IF -rollname IS NOT INITIAL. READ TABLE lt_dd04t INTO ls_dd04t WITH KEY rollname = -rollname BINARY SEARCH. IF sy-subrc = 0. -ddtext = ls_dd04t-ddtext. ENDIF. ENDIF. IF -ddtext IS INITIAL AND -domname IS NOT INITIAL. READ TABLE lt_dd01t INTO ls_dd01t WITH KEY domname = -domname BINARY SEARCH. IF sy-subrc = 0. -ddtext = ls_dd01t-ddtext. ENDIF. ENDIF. ENDLOOP. IF p_key = 'X'. DELETE gt_fields WHERE keyflag <> 'X'. ENDIF. ENDFORM. *&---------------------------------------------------------------------* *& Section B - TADIR object types: which exist + how many, SAP vs custom *& *& WARNING: this section can TIME_OUT on systems with very large TADIR *& (multi-million rows, common on legacy IS-U landscapes). *& Default is now OFF on the selection screen for that reason. *& If you need this section, run the report in BACKGROUND *& (SE38 -> Program -> Execute -> In Background) where the *& dialog work-process timeout (rdisp/max_wprun_time) does *& not apply. Note: gui_download will NOT work in background; *& you'll need to capture the output via spool list instead. *& *& v0.3: ONE grouped query (object, author) instead of two split by *& NOT LIKE filters. Avoids non-sargable WHERE clauses that can *& force a full table scan on a multi-million-row TADIR. *& The DB returns at most a few thousand (object, author) pairs; *& the SAP-vs-customer classification happens in ABAP afterwards. *&---------------------------------------------------------------------* FORM section_b_tadir_objects. TYPES: BEGIN OF ty_grp, object TYPE tadir-object, author TYPE tadir-author, cnt TYPE i, END OF ty_grp. DATA: lt_grp TYPE TABLE OF ty_grp. DATA: ls_grp TYPE ty_grp. " Single grouped query: pgmid uses the primary key, no NOT LIKE, " aggregation done by the database. Result is at most ~few thousand rows " (every distinct object+author combination in the repository). SELECT object author COUNT(*) AS cnt FROM tadir INTO TABLE lt_grp WHERE pgmid = 'R3TR' GROUP BY object author. " Classify SAP vs customer in ABAP, on the small grouped result set. DATA: ls_acc TYPE ty_obj_type. SORT lt_grp BY object. DATA: lv_prev_obj TYPE tadir-object. CLEAR: ls_acc, lv_prev_obj. LOOP AT lt_grp INTO ls_grp. IF ls_grp-object <> lv_prev_obj AND lv_prev_obj IS NOT INITIAL. ls_acc-total_cnt = ls_acc-sap_cnt + ls_acc-cust_cnt. APPEND ls_acc TO gt_objs. CLEAR ls_acc. ENDIF. ls_acc-object = ls_grp-object. IF ls_grp-author = 'SAP' OR ls_grp-author = 'DDIC' OR ls_grp-author CP 'SAP*'. ls_acc-sap_cnt = ls_acc-sap_cnt + ls_grp-cnt. ELSE. ls_acc-cust_cnt = ls_acc-cust_cnt + ls_grp-cnt. ENDIF. lv_prev_obj = ls_grp-object. ENDLOOP. IF lv_prev_obj IS NOT INITIAL. ls_acc-total_cnt = ls_acc-sap_cnt + ls_acc-cust_cnt. APPEND ls_acc TO gt_objs. ENDIF. SORT gt_objs BY total_cnt DESCENDING. ENDFORM. *&---------------------------------------------------------------------* *& Section C - NACE application keys actually configured on this system *& v0.2: aggregation moved to DB via GROUP BY + COUNT(DISTINCT kschl) *&---------------------------------------------------------------------* FORM section_c_nace_kappl. SELECT kappl COUNT( DISTINCT kschl ) AS output_cnt FROM t685a INTO TABLE gt_kappl GROUP BY kappl. SORT gt_kappl BY output_cnt DESCENDING. ENDFORM. *&---------------------------------------------------------------------* *& Section D - Customer search helps available for MATCHCODE OBJECT *&---------------------------------------------------------------------* FORM section_d_search_helps. SELECT shlpname selmtype FROM dd30l INTO CORRESPONDING FIELDS OF TABLE gt_shlp WHERE ( shlpname LIKE 'Z%' OR shlpname LIKE 'Y%' ) AND as4local = 'A' ORDER BY shlpname. LOOP AT gt_shlp ASSIGNING FIELD-SYMBOL(). SELECT SINGLE ddtext FROM dd30t INTO -ddtext WHERE shlpname = -shlpname AND ddlanguage = sy-langu AND as4local = 'A'. ENDLOOP. ENDFORM. *&---------------------------------------------------------------------* *& Display - one ALV per non-empty section *&---------------------------------------------------------------------* FORM display_results. IF gt_fields IS NOT INITIAL. PERFORM alv_simple USING 'A: DD Felder' CHANGING gt_fields. ENDIF. IF gt_objs IS NOT INITIAL. PERFORM alv_simple USING 'B: TADIR Objekttypen' CHANGING gt_objs. ENDIF. IF gt_kappl IS NOT INITIAL. PERFORM alv_simple USING 'C: NACE KAPPL' CHANGING gt_kappl. ENDIF. IF gt_shlp IS NOT INITIAL. PERFORM alv_simple USING 'D: Kunden-Suchhilfen' CHANGING gt_shlp. ENDIF. ENDFORM. FORM alv_simple USING uv_title TYPE lvc_title CHANGING ct_data TYPE STANDARD TABLE. DATA: lo_alv TYPE REF TO cl_salv_table. DATA: lo_disp TYPE REF TO cl_salv_display_settings. DATA: lo_funcs TYPE REF TO cl_salv_functions_list. DATA: lo_cols TYPE REF TO cl_salv_columns_table. TRY. cl_salv_table=>factory( IMPORTING r_salv_table = lo_alv CHANGING t_table = ct_data ). lo_disp = lo_alv->get_display_settings( ). lo_disp->set_list_header( uv_title ). lo_disp->set_striped_pattern( abap_true ). lo_funcs = lo_alv->get_functions( ). lo_funcs->set_all( abap_true ). lo_cols = lo_alv->get_columns( ). lo_cols->set_optimize( abap_true ). lo_alv->display( ). CATCH cx_salv_msg INTO DATA(lx). MESSAGE lx TYPE 'I'. ENDTRY. ENDFORM. *&---------------------------------------------------------------------* *& Excel export - one tab-delimited TXT covering all four sections *&---------------------------------------------------------------------* FORM export_excel. DATA: lv_fp TYPE string, lv_fn TYPE string, lv_p TYPE string, lv_a TYPE i, lv_l TYPE string, lt TYPE TABLE OF string, lv_s TYPE c VALUE cl_abap_char_utilities=>horizontal_tab. cl_gui_frontend_services=>file_save_dialog( EXPORTING window_title = 'DD-Steckbrief speichern' default_extension = 'txt' default_file_name = |SAP_DD_Steckbrief_{ sy-sysid }_{ sy-datum }| file_filter = 'Tab-delimited TXT (*.txt)|*.txt|All|*.*' CHANGING filename = lv_fn path = lv_p fullpath = lv_fp user_action = lv_a EXCEPTIONS OTHERS = 4 ). IF sy-subrc <> 0 OR lv_a <> 0. RETURN. ENDIF. " ---------- Section A ---------- IF gt_fields IS NOT INITIAL. APPEND '## SECTION A - DD FIELDS' TO lt. CONCATENATE 'TABNAME' lv_s 'FIELDNAME' lv_s 'POSITION' lv_s 'DATATYPE' lv_s 'LENG' lv_s 'DECIMALS' lv_s 'ROLLNAME' lv_s 'DOMNAME' lv_s 'KEYFLAG' lv_s 'NOTNULL' lv_s 'DDTEXT' INTO lv_l. APPEND lv_l TO lt. LOOP AT gt_fields INTO gs_field. DATA(lv_pos) = |{ gs_field-position }|. DATA(lv_len) = |{ gs_field-leng }|. DATA(lv_dec) = |{ gs_field-decimals }|. CONCATENATE gs_field-tabname lv_s gs_field-fieldname lv_s lv_pos lv_s gs_field-datatype lv_s lv_len lv_s lv_dec lv_s gs_field-rollname lv_s gs_field-domname lv_s gs_field-keyflag lv_s gs_field-notnull lv_s gs_field-ddtext INTO lv_l. APPEND lv_l TO lt. ENDLOOP. APPEND '' TO lt. ENDIF. " ---------- Section B ---------- IF gt_objs IS NOT INITIAL. APPEND '## SECTION B - TADIR OBJECT TYPES' TO lt. CONCATENATE 'OBJECT' lv_s 'TOTAL' lv_s 'SAP' lv_s 'CUSTOMER' INTO lv_l. APPEND lv_l TO lt. LOOP AT gt_objs INTO gs_obj. DATA(lv_t) = |{ gs_obj-total_cnt }|. DATA(lv_sa) = |{ gs_obj-sap_cnt }|. DATA(lv_cu) = |{ gs_obj-cust_cnt }|. CONCATENATE gs_obj-object lv_s lv_t lv_s lv_sa lv_s lv_cu INTO lv_l. APPEND lv_l TO lt. ENDLOOP. APPEND '' TO lt. ENDIF. " ---------- Section C ---------- IF gt_kappl IS NOT INITIAL. APPEND '## SECTION C - NACE APPLICATION KEYS' TO lt. CONCATENATE 'KAPPL' lv_s 'OUTPUT_TYPES_CONFIGURED' INTO lv_l. APPEND lv_l TO lt. LOOP AT gt_kappl INTO gs_kappl. DATA(lv_oc) = |{ gs_kappl-output_cnt }|. CONCATENATE gs_kappl-kappl lv_s lv_oc INTO lv_l. APPEND lv_l TO lt. ENDLOOP. APPEND '' TO lt. ENDIF. " ---------- Section D ---------- IF gt_shlp IS NOT INITIAL. APPEND '## SECTION D - CUSTOMER SEARCH HELPS' TO lt. CONCATENATE 'SHLPNAME' lv_s 'SELMTYPE' lv_s 'DDTEXT' INTO lv_l. APPEND lv_l TO lt. LOOP AT gt_shlp INTO gs_shlp. CONCATENATE gs_shlp-shlpname lv_s gs_shlp-selmtype lv_s gs_shlp-ddtext INTO lv_l. APPEND lv_l TO lt. ENDLOOP. APPEND '' TO lt. ENDIF. cl_gui_frontend_services=>gui_download( EXPORTING filename = lv_fp filetype = 'ASC' write_field_separator = ' ' trunc_trailing_blanks = 'X' codepage = '4110' CHANGING data_tab = lt EXCEPTIONS OTHERS = 22 ). IF sy-subrc = 0. MESSAGE |DD-Steckbrief gespeichert: { lv_fp }| TYPE 'S'. ELSE. MESSAGE 'Export-Fehler.' TYPE 'E'. ENDIF. ENDFORM.