REPORT {{p}}dealer_sum. PARAMETERS p_from TYPE d OBLIGATORY. PARAMETERS p_to TYPE d OBLIGATORY. PARAMETERS p_city TYPE {{p}}dealer-city. CLASS lcl_report DEFINITION FINAL. PUBLIC SECTION. TYPES: BEGIN OF ty_line, dealer TYPE {{p}}dealer-dealer_name, city TYPE {{p}}dealer-city, sales TYPE i, revenue TYPE {{p}}vsale-price, top_model TYPE {{p}}vsale-model_code, END OF ty_line, tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY, BEGIN OF ty_model, dealer_id TYPE {{p}}dealer-dealer_id, dealer_name TYPE {{p}}dealer-dealer_name, city TYPE {{p}}dealer-city, model_code TYPE {{p}}vsale-model_code, model_sum TYPE {{p}}vsale-price, model_cnt TYPE i, END OF ty_model, tt_model TYPE STANDARD TABLE OF ty_model WITH EMPTY KEY. METHODS select_summary IMPORTING iv_from TYPE d iv_to TYPE d iv_city TYPE {{p}}dealer-city RETURNING VALUE(rt_lines) TYPE tt_line. METHODS display CHANGING ct_lines TYPE tt_line. PRIVATE SECTION. METHODS read_models IMPORTING iv_from TYPE d iv_to TYPE d iv_city TYPE {{p}}dealer-city RETURNING VALUE(rt_models) TYPE tt_model. METHODS reduce IMPORTING it_models TYPE tt_model RETURNING VALUE(rt_lines) TYPE tt_line. ENDCLASS. CLASS lcl_report IMPLEMENTATION. METHOD select_summary. rt_lines = reduce( read_models( iv_from = iv_from iv_to = iv_to iv_city = iv_city ) ). ENDMETHOD. METHOD read_models. IF iv_city IS INITIAL. SELECT d~dealer_id, d~dealer_name, d~city, s~model_code, SUM( s~price ) AS model_sum, COUNT( * ) AS model_cnt FROM {{p}}vsale AS s INNER JOIN {{p}}dealer AS d ON d~dealer_id = s~dealer_id WHERE s~sale_date BETWEEN @iv_from AND @iv_to GROUP BY d~dealer_id, d~dealer_name, d~city, s~model_code ORDER BY d~dealer_id, s~model_code INTO CORRESPONDING FIELDS OF TABLE @rt_models. ELSE. SELECT d~dealer_id, d~dealer_name, d~city, s~model_code, SUM( s~price ) AS model_sum, COUNT( * ) AS model_cnt FROM {{p}}vsale AS s INNER JOIN {{p}}dealer AS d ON d~dealer_id = s~dealer_id WHERE s~sale_date BETWEEN @iv_from AND @iv_to AND d~city = @iv_city GROUP BY d~dealer_id, d~dealer_name, d~city, s~model_code ORDER BY d~dealer_id, s~model_code INTO CORRESPONDING FIELDS OF TABLE @rt_models. ENDIF. ENDMETHOD. METHOD reduce. DATA ls_line TYPE ty_line. DATA lv_dealer_id TYPE {{p}}dealer-dealer_id. DATA lv_top_sum TYPE {{p}}vsale-price. LOOP AT it_models INTO DATA(ls_model). IF ls_model-dealer_id <> lv_dealer_id. IF lv_dealer_id IS NOT INITIAL. APPEND ls_line TO rt_lines. ENDIF. CLEAR ls_line. lv_dealer_id = ls_model-dealer_id. lv_top_sum = ls_model-model_sum. ls_line-dealer = ls_model-dealer_name. ls_line-city = ls_model-city. ls_line-top_model = ls_model-model_code. ls_line-revenue = ls_model-model_sum. ls_line-sales = ls_model-model_cnt. ELSE. ls_line-revenue = ls_line-revenue + ls_model-model_sum. ls_line-sales = ls_line-sales + ls_model-model_cnt. IF ls_model-model_sum > lv_top_sum. lv_top_sum = ls_model-model_sum. ls_line-top_model = ls_model-model_code. ENDIF. ENDIF. ENDLOOP. IF lv_dealer_id IS NOT INITIAL. APPEND ls_line TO rt_lines. ENDIF. SORT rt_lines BY revenue DESCENDING dealer ASCENDING. 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(go_report) = NEW lcl_report( ). DATA(gt_lines) = go_report->select_summary( iv_from = p_from iv_to = p_to iv_city = p_city ). go_report->display( CHANGING ct_lines = gt_lines ). CLASS ltc_report DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. PRIVATE SECTION. CLASS-DATA go_env TYPE REF TO if_osql_test_environment. CLASS-METHODS class_setup. CLASS-METHODS class_teardown. METHODS revenue_per_dealer FOR TESTING. METHODS city_filter FOR TESTING. ENDCLASS. CLASS ltc_report IMPLEMENTATION. METHOD class_setup. go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}DEALER' ) ( '{{P}}VSALE' ) ) ). DATA lt_dealer TYPE STANDARD TABLE OF {{p}}dealer WITH EMPTY KEY. lt_dealer = VALUE #( ( dealer_id = 'D1' dealer_name = 'One' city = 'X' ) ( dealer_id = 'D2' dealer_name = 'Two' city = 'Y' ) ). go_env->insert_test_data( lt_dealer ). DATA lt_sale TYPE STANDARD TABLE OF {{p}}vsale WITH EMPTY KEY. lt_sale = VALUE #( ( sale_id = 1 dealer_id = 'D1' sale_date = '20260101' model_code = 'A' price = 10 ) ( sale_id = 2 dealer_id = 'D1' sale_date = '20260102' model_code = 'B' price = 30 ) ( sale_id = 3 dealer_id = 'D2' sale_date = '20260103' model_code = 'A' price = 5 ) ). go_env->insert_test_data( lt_sale ). ENDMETHOD. METHOD class_teardown. go_env->destroy( ). ENDMETHOD. METHOD revenue_per_dealer. DATA(lt_lines) = NEW lcl_report( )->select_summary( iv_from = '20260101' iv_to = '20260131' iv_city = '' ). cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ). cl_abap_unit_assert=>assert_equals( exp = 'One' act = lt_lines[ 1 ]-dealer ). cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_lines[ 1 ]-sales ). ENDMETHOD. METHOD city_filter. DATA(lt_lines) = NEW lcl_report( )->select_summary( iv_from = '20260101' iv_to = '20260131' iv_city = 'X' ). cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_lines ) ). cl_abap_unit_assert=>assert_equals( exp = 'B' act = lt_lines[ 1 ]-top_model ). ENDMETHOD. ENDCLASS.