* _______ _______ _______ _______ _______ _______ ______ _______ _______ ______ _______ * | _ | _ | _ | | | _ | || _ | _ | _ | | _ | * | |_| | |_| | |_| | _ | | |_| | _ | |_| | |_| | | || | |_| | * | | | | |_| | | | | | | | | |_||_| | * | | _ || | ___| _| | |_| | | _ || __ | | * | _ | |_| | _ | | | |_| _ | | _ | |_| | | | | _ | * |__| |__|_______|__| |__|___| |_______|__| |__|______||__| |__|_______|___| |_|__| |__| * www.abapcadabra.com *------------------------------------------------------------------------------------------- * program : ZABAPCADABRA_REPORT_TRANSPORTS * title : Report transport history * functional area : X-component * environment : 4.7 * program Function : Get a good feel on the development's "life-line" up to now * by checking transports. This report will investigate the * transports for a given program an show what happened to it * since birth. * Documentation : Search for "The development life line" on AbapcadabrA.com * Previous version : This is the initial version * Developer name : Wim Maasdam * Development date : 27-11-2012 * Version : 0.1 *--------------------------------------------------------------------- * Change list: * Date Description * 27-11-2012 Initial release * 17-03-2017 Overhaul ! Now in Object Oriented fashion *--------------------------------------------------------------------- REPORT ZABAPCADABRA_REPORT_TRANSPORTS. tables E071. CLASS lcl_event_manager DEFINITION. PUBLIC SECTION. METHODS: constructor IMPORTING r_object TYPE REF TO cl_salv_table, on_user_command FOR EVENT added_function OF cl_salv_events IMPORTING e_salv_function, on_link_click FOR EVENT link_click OF cl_salv_events_table IMPORTING row column. PRIVATE SECTION. DATA: go_salv TYPE REF TO cl_salv_table. ENDCLASS. CLASS lcl_controller DEFINITION. PUBLIC SECTION. types: begin of ty_program_release, roundnumber type i, as4date type E070-as4date, AS4TIME type E070-AS4TIME, trkorr type E070-trkorr, AS4TEXT type E07T-AS4TEXT, object type E071-obj_name, version type VRSD-VERSNO, linecount type sy-dbcnt, growth type sy-dbcnt, days type sy-dbcnt, "Nr of days since last object change tdays type sy-dbcnt, "Nr of days since last transport age type sy-dbcnt, "Nr of days since day 1 end of ty_program_release, begin of ty_sourcecode, include type D010INC-include, linecount type sy-dbcnt, tdate type d, end of ty_sourcecode. CLASS-DATA: gt_program_releases type table of ty_program_release, gw_program_release type ty_program_release, gt_sourcecodes type standard table of ty_sourcecode, gw_sourcecode type ty_sourcecode, begin of gw_footer, sourcecodelines type sy-dbcnt, objectcount type sy-dbcnt, transportcount type sy-dbcnt, age type sy-dbcnt, age_label type c length 30, tdate_last type d, new_age type sy-dbcnt, average type sy-dbcnt, rounds type i, average_rounds type sy-dbcnt, end of gw_footer, go_alv type ref to cl_salv_table, go_event_man TYPE REF TO lcl_event_manager, RF_FUNCTIONS_LIST type ref to CL_SALV_FUNCTIONS_LIST, rf_columns_table type ref to CL_SALV_COLUMNS_TABLE, rf_column_table type ref to CL_SALV_COLUMN_TABLE, rf_column TYPE REF TO cl_salv_column, rf_sorts type ref to CL_SALV_SORTS, * The footer box rf_alv_footer type ref to CL_SALV_FORM_LAYOUT_GRID, rf_text TYPE REF TO cl_salv_form_text, rf_layout TYPE REF TO cl_salv_layout, rf_layout_data TYPE REF TO cl_salv_form_layout_data_grid, gv_clskey TYPE seoclskey. CLASS-METHODS: main_selection importing main_program type sy-repid, version_lookup, growth_calculations, alv_report. ENDCLASS. CLASS lcl_controller IMPLEMENTATION. METHOD main_selection. types: begin of ty_VRSD, OBJNAME type VRSD-OBJNAME, VERSNO type VRSD-VERSNO, KORRNUM type VRSD-KORRNUM, end of ty_VRSD, begin of ty_e070, TRKORR type e070-TRKORR, AS4DATE type e070-AS4DATE, AS4TIME type e070-AS4TIME, end of ty_e070. data: lt_includes type table of D010INC-include, lr_obj_name type range of e071-obj_name, lw_obj_name like line of lr_obj_name, lt_VRSD type standard table of ty_VRSD, lw_VRSD type ty_VRSD, lt_e070 type sorted table of ty_e070 with unique key TRKORR, lw_e070 type ty_e070, lt_e07t type sorted table of e07t with unique key TRKORR LANGU, lw_e07t type e07t. * Select the Y/Z custom includes - which are "objects of interest". select inc~include from D010INC as inc inner join tadir as tad on inc~include = tad~obj_name into table lt_includes where inc~master = main_program and tad~pgmid = 'R3TR' and tad~object = 'PROG' and tad~devclass between 'Y' and 'ZZZZZZ'. * Compose the gr_obj_name range with object names: clear: lr_obj_name[]. lw_obj_name = 'IEQ'. lw_obj_name-low = main_program. append lw_obj_name to lr_obj_name. loop at lt_includes into lw_obj_name-low. append lw_obj_name to lr_obj_name. endloop. * Selection of related/relevant transports: - prep-version (w/o versions) select TRKORR as KORRNUM OBJ_NAME as OBJNAME from E071 into corresponding fields of table lt_VRSD where PGMID = 'R3TR' and OBJECT = 'PROG' and OBJ_NAME in lr_obj_name. * Fetch transport lines per object select OBJNAME VERSNO KORRNUM from VRSD APPENDING corresponding fields of table lt_VRSD where OBJTYPE = 'REPS' and OBJNAME in lr_obj_name. check not lt_VRSD[] is initial. * Transport headers and texts: clear: lt_e070[]. * Fetch transport headers select TRKORR AS4DATE AS4TIME from E070 into corresponding fields of table lt_e070 for all entries in lt_VRSD where TRKORR = lt_VRSD-KORRNUM. check not lt_e070[] is initial. select * from E07T into table lt_e07t for all entries in lt_e070 where TRKORR = lt_e070-TRKORR. * Consolidation of selected data: clear: gt_program_releases[]. * Finalize gt_program_releases table: loop at lt_VRSD into lw_VRSD. clear: gw_program_release. read table lt_e070 into lw_e070 with key trkorr = lw_VRSD-KORRNUM binary search. if sy-subrc = 0. move-corresponding lw_e070 to gw_program_release. endif. gw_program_release-TRKORR = lw_VRSD-KORRNUM. read table lt_e07t with key TRKORR = gw_program_release-TRKORR into lw_e07t. gw_program_release-as4text = lw_e07t-as4text. gw_program_release-object = lw_VRSD-OBJNAME. gw_program_release-version = lw_VRSD-VERSNO. append gw_program_release to gt_program_releases. endloop. * Final touch-up on the gt_program_releases table sort gt_program_releases by trkorr object version. delete adjacent duplicates from gt_program_releases. delete gt_program_releases where trkorr is initial. * Preperation for the source codes table clear gt_sourcecodes[]. loop at gt_program_releases into gw_program_release. clear gw_sourcecode. gw_sourcecode-include = gw_program_release-object. append gw_sourcecode to gt_sourcecodes. endloop. sort gt_sourcecodes. delete adjacent duplicates from gt_sourcecodes. describe table gt_sourcecodes lines gw_footer-objectcount. ENDMETHOD. METHOD version_lookup. * Inspect the versions of Abap coding, to extract the number of lines of coding data: lw_version_info type VRSD, lt_abapcode type standard table of ABAPTXT255, lt_trdir type standard table of trdir. loop at gt_program_releases into gw_program_release. lw_version_info-OBJNAME = gw_program_release-object. lw_version_info-OBJTYPE = 'REPS'. lw_version_info-VERSNO = gw_program_release-version. CALL FUNCTION 'SVRS_GET_REPS_FROM_OBJECT' EXPORTING OBJECT_NAME = lw_version_info-OBJNAME OBJECT_TYPE = lw_version_info-OBJTYPE VERSNO = lw_version_info-versno TABLES REPOS_TAB = lt_abapcode TRDIR_TAB = lt_trdir EXCEPTIONS OTHERS = 2. IF SY-SUBRC <> 0. * No action ELSE. describe table lt_abapcode lines gw_program_release-linecount. modify gt_program_releases from gw_program_release transporting linecount. ENDIF. endloop. ENDMETHOD. METHOD growth_calculations. data: begin of lw_last_transport_info, trkorr_current type E070-trkorr, tdate_current type d, trkorr type E070-trkorr, tdate type d, age type sy-dbcnt, end of lw_last_transport_info, lv_last_as4date type d, lv_roundnumber type i, lv_daycounter type n length 5. sort gt_program_releases by as4date as4time trkorr object version. * Calculate growth and nrs days since last change - per object: loop at gt_sourcecodes into gw_sourcecode. loop at gt_program_releases into gw_program_release where object = gw_sourcecode-include. gw_program_release-growth = gw_program_release-linecount - gw_sourcecode-linecount. if not gw_sourcecode-tdate is initial. gw_program_release-days = gw_program_release-as4date - gw_sourcecode-tdate. endif. * Keep track of a bit of history gw_sourcecode-linecount = gw_program_release-linecount. gw_sourcecode-tdate = gw_program_release-as4date. modify gt_sourcecodes from gw_sourcecode. modify gt_program_releases from gw_program_release. endloop. endloop. clear: lw_last_transport_info. * Calculate the growth from transport to transport (not per object) loop at gt_program_releases into gw_program_release. if gw_footer-tdate_last is initial. gw_footer-tdate_last = gw_program_release-as4date. endif. * Keep track of a bit of history if lw_last_transport_info-trkorr_current <> gw_program_release-trkorr. lw_last_transport_info-trkorr = lw_last_transport_info-trkorr_current. lw_last_transport_info-tdate = lw_last_transport_info-tdate_current. lw_last_transport_info-trkorr_current = gw_program_release-trkorr. lw_last_transport_info-tdate_current = gw_program_release-as4date. add 1 to gw_footer-transportcount. * Update age if not lw_last_transport_info-tdate is initial. lw_last_transport_info-age = lw_last_transport_info-age + ( gw_program_release-as4date - lw_last_transport_info-tdate ). gw_footer-age = lw_last_transport_info-age. gw_footer-tdate_last = gw_program_release-as4date. endif. endif. if not lw_last_transport_info-tdate is initial. gw_program_release-tdays = gw_program_release-as4date - lw_last_transport_info-tdate. gw_program_release-age = lw_last_transport_info-age. modify gt_program_releases from gw_program_release. endif. endloop. * Rounds: development efforts are performed in adaption rounds. A round number is determined * by grouping the transport creation dates: whenever the difference in transport days exceeds * 7 days, a new round is assumed. clear: lv_roundnumber, lv_last_as4date. loop at gt_program_releases into gw_program_release. if lv_last_as4date is initial. add 1 to lv_roundnumber. else. lv_daycounter = gw_program_release-as4date - lv_last_as4date. if lv_daycounter > 7. add 1 to lv_roundnumber. endif. endif. gw_program_release-roundnumber = lv_roundnumber. modify gt_program_releases from gw_program_release transporting roundnumber. lv_last_as4date = gw_program_release-as4date. endloop. gw_footer-rounds = lv_roundnumber. ENDMETHOD. METHOD alv_report. DATA: lv_percentage TYPE f, lv_column TYPE i, lv_text TYPE scrtext_s, lv_text_m TYPE scrtext_m, lv_text_l TYPE scrtext_l, lw_layout_key TYPE salv_s_layout_key, lv_years type f. DEFINE set_text_field. rf_column ?= rf_columns_table->get_column( &1 ). lv_text = &2. lv_text_m = &2. lv_text_l = &2. rf_column->set_short_text( lv_text ). rf_column->set_medium_text( lv_text_m ). rf_column->set_long_text( lv_text_l ). END-OF-DEFINITION. DEFINE set_hidden_field. set_text_field &1 &2. rf_column->set_visible( abap_false ). END-OF-DEFINITION. DEFINE set_totals_field. lv_column = &2. rf_text = rf_alv_footer->create_text( text = &3 row = &1 column = lv_column ). rf_layout_data ?= rf_text->get_layout_data( ). rf_layout_data->set_h_align( if_salv_form_c_h_align=>right ). add 1 to lv_column. rf_text = rf_alv_footer->create_text( text = &4 row = &1 column = lv_column ). END-OF-DEFINITION. cl_salv_table=>factory( importing r_salv_table = go_alv changing t_table = gt_program_releases ). rf_functions_list = go_alv->get_functions( ). rf_functions_list->set_all( ). rf_columns_table = go_alv->get_columns( ). rf_columns_table->set_optimize( abap_true ). "Always a good idea set_text_field: 'ROUNDNUMBER' 'Round', 'LINECOUNT' '# of lines', 'GROWTH' 'Growth', 'TDAYS' 'Days', 'DAYS' 'Days(obj.)', 'AGE' 'Age'. * Sort fields rf_sorts = go_alv->get_sorts( ). rf_sorts->add_sort( COLUMNNAME = 'AS4DATE' SEQUENCE = IF_SALV_C_SORT=>SORT_DOWN ). rf_sorts->add_sort( COLUMNNAME = 'AS4TIME' SEQUENCE = IF_SALV_C_SORT=>SORT_DOWN ). rf_sorts->add_sort( columnname = 'TRKORR' ). rf_sorts->add_sort( columnname = 'AS4TEXT' ). rf_sorts->add_sort( COLUMNNAME = 'OBJECT' ). rf_sorts->add_sort( COLUMNNAME = 'VERSION' ). * Activate link in TRKORR and OBJECT: rf_column_table ?= rf_columns_table->get_column( 'TRKORR' ). rf_column_table->set_cell_type( if_salv_c_cell_type=>hotspot ). rf_column_table ?= rf_columns_table->get_column( 'OBJECT' ). rf_column_table->set_cell_type( if_salv_c_cell_type=>hotspot ). * Footer information CREATE OBJECT rf_alv_footer. loop at gt_sourcecodes into gw_sourcecode. add gw_sourcecode-linecount to gw_footer-sourcecodelines. endloop. gw_footer-new_age = sy-datum - gw_footer-tdate_last. gw_footer-average = gw_footer-age / gw_footer-transportcount. gw_footer-average_rounds = gw_footer-age / gw_footer-rounds. lv_years = gw_footer-age / 365. WRITE lv_years TO gw_footer-age_label DECIMALS 1 EXPONENT 0 LEFT-JUSTIFIED. CONCATENATE '| Age (' gw_footer-age_label ' years)' INTO gw_footer-age_label. set_totals_field: "line, First columnquantity, field label 1 1 '______' 'SUMMARY', 2 1 gw_footer-transportcount '| Transports', 3 1 gw_footer-objectcount '| Reports/includes', 4 1 gw_footer-sourcecodelines '| Coding lines (Abap)', 1 3 '______' 'DAYS ...', 2 3 gw_footer-age gw_footer-age_label, 3 3 gw_footer-new_age '| Unchanged for', 4 3 gw_footer-average '| Average between changes', 1 5 '______' 'ROUNDS', 2 5 gw_footer-rounds '| Development rounds', 4 5 gw_footer-average_rounds '| Average days between rounds'. go_alv->set_end_of_list( rf_alv_footer ). CREATE OBJECT go_event_man EXPORTING r_object = go_alv. go_alv->display( ). ENDMETHOD. ENDCLASS. CLASS lcl_event_manager IMPLEMENTATION. METHOD constructor. DATA: lo_events TYPE REF TO cl_salv_events_table. go_salv = r_object. lo_events = go_salv->get_event( ). * SET HANDLER on_user_command FOR lo_events. SET HANDLER on_link_click FOR lo_events. ENDMETHOD. "constructor METHOD on_user_command. ENDMETHOD. "on_user_command METHOD on_link_click. DATA: lv_returncode TYPE c, lt_bdcdata type standard table of bdcdata, lw_bdcdata type bdcdata. * bdc_add 'X' 'PROGRAM_NAME' 'SCREEN NUMBER'. * bdc_add ' ' 'FIELDNAME' 'FIELDVALUE'. define bdc_add. clear lw_bdcdata. lw_bdcdata-dynbegin = &1. if &1 eq 'X'. lw_bdcdata-program = &2. lw_bdcdata-dynpro = &3. else. lw_bdcdata-fnam = &2. lw_bdcdata-fval = &3. endif. append lw_bdcdata to lt_bdcdata. end-of-definition. READ TABLE lcl_controller=>GT_PROGRAM_RELEASES INTO lcl_controller=>GW_PROGRAM_RELEASE INDEX row. IF sy-subrc = 0. CASE column. WHEN 'TRKORR'. clear: lt_bdcdata. bdc_add: 'X' 'RDDM0001' '0100', ' ' 'BDC_OKCODE' '=SNGL', 'X' 'SAPLSTRH' '1200', ' ' 'GV_1200_TRKORR' lcl_controller=>GW_PROGRAM_RELEASE-trkorr, ' ' 'BDC_OKCODE' '=TAKE', 'X' 'SAPMSSY0' '0120'. call transaction 'SE10' using lt_bdcdata mode 'E'. WHEN 'OBJECT'. clear: lt_bdcdata. bdc_add: 'X' 'SAPLWBABAP' '0100', ' ' 'RS38M-PROGRAMM' lcl_controller=>GW_PROGRAM_RELEASE-object, ' ' 'BDC_OKCODE' '=SHOP', 'X' 'SAPLS38E' '0400'. call transaction 'SE38' using lt_bdcdata mode 'E'. ENDCASE. ENDIF. go_salv->refresh( ). ENDMETHOD. "on_link_click ENDCLASS. "lcl_event_manager IMPLEMENTATION SELECTION-SCREEN BEGIN OF LINE. SELECTION-SCREEN COMMENT 1(31) lbl_01 FOR FIELD pa_main. parameter: pa_main like sy-repid. SELECTION-SCREEN END OF LINE. INITIALIZATION. lbl_01 = 'Main program'. START-OF-SELECTION. lcl_controller=>main_selection( pa_main ). lcl_controller=>version_lookup( ). lcl_controller=>growth_calculations( ). lcl_controller=>alv_report( ).