REPORT {{p}}print_sum. DATA gv_customer TYPE {{p}}prtjob-customer. PARAMETERS p_from TYPE d OBLIGATORY. SELECT-OPTIONS s_cust FOR gv_customer. CLASS lcl_report DEFINITION FINAL. PUBLIC SECTION. TYPES: BEGIN OF ty_job, customer TYPE {{p}}prtjob-customer, sheets TYPE {{p}}prtjob-sheets, amount TYPE {{p}}prtjob-amount, END OF ty_job, tt_job TYPE STANDARD TABLE OF ty_job, BEGIN OF ty_line, customer TYPE {{p}}prtjob-customer, jobs TYPE i, sheets TYPE {{p}}prtjob-sheets, revenue TYPE {{p}}prtjob-amount, END OF ty_line, tt_line TYPE STANDARD TABLE OF ty_line, tt_customer TYPE RANGE OF {{p}}prtjob-customer. METHODS read_jobs IMPORTING iv_from TYPE d it_customer TYPE tt_customer CHANGING ct_jobs TYPE tt_job. METHODS aggregate IMPORTING it_jobs TYPE tt_job CHANGING ct_lines TYPE tt_line. METHODS display CHANGING ct_lines TYPE tt_line. ENDCLASS. CLASS lcl_report IMPLEMENTATION. METHOD read_jobs. SELECT customer sheets amount INTO CORRESPONDING FIELDS OF TABLE ct_jobs FROM {{p}}prtjob WHERE job_date >= iv_from OR customer IN it_customer. ENDMETHOD. METHOD aggregate. FIELD-SYMBOLS TYPE ty_job. FIELD-SYMBOLS TYPE ty_line. LOOP AT it_jobs ASSIGNING . READ TABLE ct_lines ASSIGNING WITH KEY customer = -customer. IF sy-subrc <> 0. APPEND INITIAL LINE TO ct_lines ASSIGNING . -customer = -customer. ENDIF. -jobs = -jobs + 1. -sheets = -sheets + -sheets. -revenue = -revenue + -amount. ENDLOOP. SORT ct_lines BY revenue DESCENDING customer ASCENDING. ENDMETHOD. METHOD display. DATA lo_alv TYPE REF TO cl_salv_table. DATA lx_error TYPE REF TO cx_salv_msg. TRY. cl_salv_table=>factory( IMPORTING r_salv_table = lo_alv CHANGING t_table = ct_lines ). lo_alv->display( ). CATCH cx_salv_msg INTO lx_error. MESSAGE lx_error TYPE 'I' DISPLAY LIKE 'E'. ENDTRY. ENDMETHOD. ENDCLASS. START-OF-SELECTION. DATA go_report TYPE REF TO lcl_report. DATA lt_jobs TYPE lcl_report=>tt_job. DATA lt_lines TYPE lcl_report=>tt_line. DATA lt_customer TYPE lcl_report=>tt_customer. CREATE OBJECT go_report. lt_customer = s_cust[]. go_report->read_jobs( EXPORTING iv_from = p_from it_customer = lt_customer CHANGING ct_jobs = lt_jobs ). go_report->aggregate( EXPORTING it_jobs = lt_jobs CHANGING ct_lines = lt_lines ). go_report->display( CHANGING ct_lines = lt_lines ). CLASS ltc_report DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. PRIVATE SECTION. METHODS aggregate_jobs FOR TESTING. ENDCLASS. CLASS ltc_report IMPLEMENTATION. METHOD aggregate_jobs. DATA lt_jobs TYPE lcl_report=>tt_job. DATA ls_job TYPE lcl_report=>ty_job. DATA lt_lines TYPE lcl_report=>tt_line. DATA ls_line TYPE lcl_report=>ty_line. DATA lo_report TYPE REF TO lcl_report. DATA lv_count TYPE i. DATA lv_amount TYPE {{p}}prtjob-amount. DATA lv_customer TYPE {{p}}prtjob-customer. CLEAR ls_job. ls_job-customer = 'A'. ls_job-sheets = 10. ls_job-amount = 10. APPEND ls_job TO lt_jobs. CLEAR ls_job. ls_job-customer = 'A'. ls_job-sheets = 5. ls_job-amount = 5. APPEND ls_job TO lt_jobs. CLEAR ls_job. ls_job-customer = 'B'. ls_job-sheets = 20. ls_job-amount = 40. APPEND ls_job TO lt_jobs. CREATE OBJECT lo_report. lo_report->aggregate( EXPORTING it_jobs = lt_jobs CHANGING ct_lines = lt_lines ). DESCRIBE TABLE lt_lines LINES lv_count. cl_abap_unit_assert=>assert_equals( exp = 2 act = lv_count ). READ TABLE lt_lines INTO ls_line INDEX 1. lv_customer = 'B'. cl_abap_unit_assert=>assert_equals( exp = lv_customer act = ls_line-customer ). lv_amount = 40. cl_abap_unit_assert=>assert_equals( exp = lv_amount act = ls_line-revenue ). READ TABLE lt_lines INTO ls_line INDEX 2. cl_abap_unit_assert=>assert_equals( exp = 2 act = ls_line-jobs ). lv_amount = 15. cl_abap_unit_assert=>assert_equals( exp = lv_amount act = ls_line-revenue ). ENDMETHOD. ENDCLASS.