REPORT {{p}}train_punct_old. TYPES: BEGIN OF ty_run, run_id TYPE {{p}}trun-run_id, line_code TYPE {{p}}trun-line_code, plan_date TYPE {{p}}trun-plan_date, delay_min TYPE {{p}}trun-delay_min, cancelled TYPE {{p}}trun-cancelled, END OF ty_run. TYPES tt_run TYPE STANDARD TABLE OF ty_run WITH EMPTY KEY. TYPES: BEGIN OF ty_line, line_code TYPE {{p}}trun-line_code, runs TYPE i, late TYPE i, sum_delay TYPE i, punct TYPE i, END OF ty_line. TYPES tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY. TYPES tt_line_range TYPE RANGE OF {{p}}trun-line_code. TYPES tt_date_range TYPE RANGE OF {{p}}trun-plan_date. DATA gv_line TYPE {{p}}trun-line_code. DATA gv_date TYPE {{p}}trun-plan_date. SELECT-OPTIONS s_line FOR gv_line. SELECT-OPTIONS s_date FOR gv_date. CLASS lcl_punct DEFINITION FINAL. PUBLIC SECTION. CONSTANTS c_late_limit TYPE i VALUE 5. CLASS-METHODS read_runs IMPORTING it_line TYPE tt_line_range it_date TYPE tt_date_range RETURNING VALUE(rt_runs) TYPE tt_run. CLASS-METHODS aggregate IMPORTING it_runs TYPE tt_run RETURNING VALUE(rt_lines) TYPE tt_line. CLASS-METHODS display CHANGING ct_lines TYPE tt_line. PRIVATE SECTION. CLASS-METHODS add_run IMPORTING is_run TYPE ty_run CHANGING ct_lines TYPE tt_line. ENDCLASS. CLASS lcl_punct IMPLEMENTATION. METHOD read_runs. DATA lt_runs TYPE tt_run. SELECT run_id, line_code, plan_date, delay_min, cancelled FROM {{p}}trun WHERE plan_date IN @it_date AND line_code IN @it_line INTO TABLE @lt_runs. rt_runs = lt_runs. ENDMETHOD. METHOD aggregate. LOOP AT it_runs INTO DATA(ls_run). IF ls_run-cancelled = 'X'. CONTINUE. ENDIF. add_run( EXPORTING is_run = ls_run CHANGING ct_lines = rt_lines ). ENDLOOP. LOOP AT rt_lines ASSIGNING FIELD-SYMBOL(). -punct = ( -runs - -late ) * 101 / -runs. ENDLOOP. SORT rt_lines BY punct line_code. ENDMETHOD. METHOD add_run. READ TABLE ct_lines ASSIGNING FIELD-SYMBOL() WITH KEY line_code = is_run-line_code. IF sy-subrc <> 0. APPEND INITIAL LINE TO ct_lines ASSIGNING . -line_code = is_run-line_code. ENDIF. -runs = -runs + 1. -sum_delay = -sum_delay + is_run-delay_min. IF is_run-delay_min > c_late_limit. -late = -late + 1. ENDIF. ENDMETHOD. METHOD display. TRY. cl_salv_table=>factory( IMPORTING r_salv_table = DATA(lo_alv) CHANGING t_table = ct_lines ). lo_alv->display( ). CATCH cx_salv_msg INTO DATA(lx_error). MESSAGE lx_error TYPE 'I' DISPLAY LIKE 'E'. ENDTRY. ENDMETHOD. ENDCLASS. START-OF-SELECTION. DATA(lt_runs) = lcl_punct=>read_runs( it_line = s_line[] it_date = s_date[] ). DATA(lt_lines) = lcl_punct=>aggregate( lt_runs ). lcl_punct=>display( CHANGING ct_lines = lt_lines ). CLASS ltc_punct DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. PRIVATE SECTION. METHODS aggregates_runs FOR TESTING. METHODS skips_cancelled FOR TESTING. METHODS sorts_worst_first FOR TESTING. ENDCLASS. CLASS ltc_punct IMPLEMENTATION. METHOD aggregates_runs. DATA(lt_lines) = lcl_punct=>aggregate( VALUE #( ( run_id = 1 line_code = 'L1' delay_min = 0 cancelled = '' ) ( run_id = 2 line_code = 'L1' delay_min = 10 cancelled = '' ) ( run_id = 3 line_code = 'L2' delay_min = 3 cancelled = '' ) ) ). cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). cl_abap_unit_assert=>assert_equals( exp = 'L1' act = lt_lines[ 1 ]-line_code ). cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_lines[ 1 ]-runs ). cl_abap_unit_assert=>assert_equals( exp = 1 act = lt_lines[ 1 ]-late ). cl_abap_unit_assert=>assert_equals( exp = 10 act = lt_lines[ 1 ]-sum_delay ). cl_abap_unit_assert=>assert_equals( exp = 50 act = lt_lines[ 1 ]-punct ). ENDMETHOD. METHOD skips_cancelled. DATA(lt_lines) = lcl_punct=>aggregate( VALUE #( ( run_id = 1 line_code = 'L1' delay_min = 0 cancelled = 'X' ) ) ). cl_abap_unit_assert=>assert_equals( exp = 0 act = lines( lt_lines ) ). ENDMETHOD. METHOD sorts_worst_first. DATA(lt_lines) = lcl_punct=>aggregate( VALUE #( ( run_id = 1 line_code = 'L1' delay_min = 0 cancelled = '' ) ( run_id = 2 line_code = 'L2' delay_min = 30 cancelled = '' ) ) ). cl_abap_unit_assert=>assert_equals( exp = 'L2' act = lt_lines[ 1 ]-line_code ). ENDMETHOD. ENDCLASS.