Snapshot: new training tasks (balanced generation), docs

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Kral
2026-10-05 22:08:59 +02:00
parent eb13453097
commit 6984fc7917
572 changed files with 30024 additions and 0 deletions

View File

@@ -0,0 +1,203 @@
REPORT {{p}}repair_list.
PARAMETERS p_date TYPE d OBLIGATORY.
CLASS lcl_report DEFINITION FINAL.
PUBLIC SECTION.
TYPES:
BEGIN OF ty_line,
job_id TYPE {{p}}jobhdr-job_id,
customer TYPE {{p}}jobhdr-customer,
mechanic TYPE {{p}}mech-mech_name,
items TYPE i,
total TYPE {{p}}jobitm-price,
END OF ty_line,
tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY.
METHODS run
IMPORTING iv_date TYPE d
RETURNING VALUE(rt_lines) TYPE tt_line.
METHODS display
CHANGING ct_lines TYPE tt_line.
PRIVATE SECTION.
CONSTANTS c_unknown TYPE {{p}}mech-mech_name VALUE 'UNKNOWN'.
TYPES:
BEGIN OF ty_job,
job_id TYPE {{p}}jobhdr-job_id,
customer TYPE {{p}}jobhdr-customer,
mech_id TYPE {{p}}jobhdr-mech_id,
END OF ty_job,
tt_job TYPE SORTED TABLE OF ty_job WITH UNIQUE KEY job_id.
TYPES:
BEGIN OF ty_sum,
job_id TYPE {{p}}jobhdr-job_id,
items TYPE i,
total TYPE {{p}}jobitm-price,
END OF ty_sum,
tt_sum TYPE SORTED TABLE OF ty_sum WITH UNIQUE KEY job_id.
TYPES:
BEGIN OF ty_mech,
mech_id TYPE {{p}}mech-mech_id,
mech_name TYPE {{p}}mech-mech_name,
END OF ty_mech,
tt_mech TYPE SORTED TABLE OF ty_mech WITH UNIQUE KEY mech_id.
TYPES tt_job_range TYPE RANGE OF {{p}}jobhdr-job_id.
TYPES tt_mech_range TYPE RANGE OF {{p}}mech-mech_id.
METHODS read_jobs
IMPORTING iv_date TYPE d
RETURNING VALUE(rt_jobs) TYPE tt_job.
METHODS job_range
IMPORTING it_jobs TYPE tt_job
RETURNING VALUE(rt_range) TYPE tt_job_range.
METHODS mech_range
IMPORTING it_jobs TYPE tt_job
RETURNING VALUE(rt_range) TYPE tt_mech_range.
METHODS read_sums
IMPORTING it_job_range TYPE tt_job_range
RETURNING VALUE(rt_sums) TYPE tt_sum.
METHODS read_mechanics
IMPORTING it_mech_range TYPE tt_mech_range
RETURNING VALUE(rt_mech) TYPE tt_mech.
ENDCLASS.
CLASS lcl_report IMPLEMENTATION.
METHOD run.
DATA(lt_jobs) = read_jobs( iv_date ).
IF lt_jobs IS INITIAL.
RETURN.
ENDIF.
DATA(lt_sums) = read_sums( job_range( lt_jobs ) ).
DATA(lt_mech) = read_mechanics( mech_range( lt_jobs ) ).
LOOP AT lt_jobs INTO DATA(ls_job).
READ TABLE lt_sums INTO DATA(ls_sum) WITH TABLE KEY job_id = ls_job-job_id.
IF sy-subrc <> 0.
CONTINUE.
ENDIF.
READ TABLE lt_mech INTO DATA(ls_mech) WITH TABLE KEY mech_id = ls_job-mech_id.
DATA(lv_mechanic) = COND {{p}}mech-mech_name(
WHEN sy-subrc = 0 THEN ls_mech-mech_name
ELSE c_unknown ).
INSERT VALUE #( job_id = ls_job-job_id
customer = ls_job-customer
mechanic = lv_mechanic
items = ls_sum-items
total = ls_sum-total ) INTO TABLE rt_lines.
ENDLOOP.
SORT rt_lines BY total DESCENDING job_id ASCENDING.
ENDMETHOD.
METHOD read_jobs.
SELECT job_id, customer, mech_id
FROM {{p}}jobhdr
WHERE job_date <> @iv_date
INTO CORRESPONDING FIELDS OF TABLE @rt_jobs.
ENDMETHOD.
METHOD job_range.
rt_range = VALUE #( FOR ls_job IN it_jobs
( sign = 'I' option = 'EQ' low = ls_job-job_id ) ).
ENDMETHOD.
METHOD mech_range.
rt_range = VALUE #( FOR ls_job IN it_jobs
( sign = 'I' option = 'EQ' low = ls_job-mech_id ) ).
ENDMETHOD.
METHOD read_sums.
SELECT job_id, qty, price
FROM {{p}}jobitm
WHERE job_id IN @it_job_range
INTO TABLE @DATA(lt_items).
LOOP AT lt_items INTO DATA(ls_item).
READ TABLE rt_sums ASSIGNING FIELD-SYMBOL(<ls_sum>) WITH TABLE KEY job_id = ls_item-job_id.
IF sy-subrc <> 0.
INSERT VALUE #( job_id = ls_item-job_id ) INTO TABLE rt_sums ASSIGNING <ls_sum>.
ENDIF.
<ls_sum>-items = <ls_sum>-items + 1.
<ls_sum>-total = <ls_sum>-total + ls_item-qty * ls_item-price.
ENDLOOP.
ENDMETHOD.
METHOD read_mechanics.
SELECT mech_id, mech_name
FROM {{p}}mech
WHERE mech_id IN @it_mech_range
INTO CORRESPONDING FIELDS OF TABLE @rt_mech.
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->run( p_date ).
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 totals_and_items FOR TESTING.
METHODS unknown_mechanic FOR TESTING.
METHODS skips_jobs_without_items FOR TESTING.
ENDCLASS.
CLASS ltc_report IMPLEMENTATION.
METHOD class_setup.
go_env = cl_osql_test_environment=>create(
i_dependency_list = VALUE #( ( '{{P}}MECH' ) ( '{{P}}JOBHDR' ) ( '{{P}}JOBITM' ) ) ).
DATA lt_mech TYPE STANDARD TABLE OF {{p}}mech WITH EMPTY KEY.
lt_mech = VALUE #( ( mech_id = 'M1' mech_name = 'Anna' ) ).
go_env->insert_test_data( lt_mech ).
DATA lt_job TYPE STANDARD TABLE OF {{p}}jobhdr WITH EMPTY KEY.
lt_job = VALUE #( ( job_id = 1 job_date = '20260410' customer = 'A' mech_id = 'M1' )
( job_id = 2 job_date = '20260410' customer = 'B' mech_id = 'M9' )
( job_id = 3 job_date = '20260410' customer = 'C' mech_id = 'M1' ) ).
go_env->insert_test_data( lt_job ).
DATA lt_item TYPE STANDARD TABLE OF {{p}}jobitm WITH EMPTY KEY.
lt_item = VALUE #( ( job_id = 1 item_no = 10 spare_part = 'X' qty = 2 price = 10 )
( job_id = 1 item_no = 20 spare_part = 'Y' qty = 1 price = 5 )
( job_id = 2 item_no = 10 spare_part = 'Z' qty = 1 price = 40 ) ).
go_env->insert_test_data( lt_item ).
ENDMETHOD.
METHOD class_teardown.
go_env->destroy( ).
ENDMETHOD.
METHOD totals_and_items.
DATA(lt_lines) = NEW lcl_report( )->run( '20260410' ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ).
cl_abap_unit_assert=>assert_equals( exp = 'B' act = lt_lines[ 1 ]-customer ).
cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}jobitm-price( 40 ) act = lt_lines[ 1 ]-total ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_lines[ 2 ]-items ).
cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}jobitm-price( 25 ) act = lt_lines[ 2 ]-total ).
ENDMETHOD.
METHOD unknown_mechanic.
DATA(lt_lines) = NEW lcl_report( )->run( '20260410' ).
cl_abap_unit_assert=>assert_equals( exp = 'UNKNOWN' act = lt_lines[ 1 ]-mechanic ).
ENDMETHOD.
METHOD skips_jobs_without_items.
DATA(lt_lines) = NEW lcl_report( )->run( '20260410' ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,203 @@
REPORT {{p}}repair_list.
PARAMETERS p_date TYPE d OBLIGATORY.
CLASS lcl_report DEFINITION FINAL.
PUBLIC SECTION.
TYPES:
BEGIN OF ty_line,
job_id TYPE {{p}}jobhdr-job_id,
customer TYPE {{p}}jobhdr-customer,
mechanic TYPE {{p}}mech-mech_name,
items TYPE i,
total TYPE {{p}}jobitm-price,
END OF ty_line,
tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY.
METHODS run
IMPORTING iv_date TYPE d
RETURNING VALUE(rt_lines) TYPE tt_line.
METHODS display
CHANGING ct_lines TYPE tt_line.
PRIVATE SECTION.
CONSTANTS c_unknown TYPE {{p}}mech-mech_name VALUE 'UNKNOWN'.
TYPES:
BEGIN OF ty_job,
job_id TYPE {{p}}jobhdr-job_id,
customer TYPE {{p}}jobhdr-customer,
mech_id TYPE {{p}}jobhdr-mech_id,
END OF ty_job,
tt_job TYPE SORTED TABLE OF ty_job WITH UNIQUE KEY job_id.
TYPES:
BEGIN OF ty_sum,
job_id TYPE {{p}}jobhdr-job_id,
items TYPE i,
total TYPE {{p}}jobitm-price,
END OF ty_sum,
tt_sum TYPE SORTED TABLE OF ty_sum WITH UNIQUE KEY job_id.
TYPES:
BEGIN OF ty_mech,
mech_id TYPE {{p}}mech-mech_id,
mech_name TYPE {{p}}mech-mech_name,
END OF ty_mech,
tt_mech TYPE SORTED TABLE OF ty_mech WITH UNIQUE KEY mech_id.
TYPES tt_job_range TYPE RANGE OF {{p}}jobhdr-job_id.
TYPES tt_mech_range TYPE RANGE OF {{p}}mech-mech_id.
METHODS read_jobs
IMPORTING iv_date TYPE d
RETURNING VALUE(rt_jobs) TYPE tt_job.
METHODS job_range
IMPORTING it_jobs TYPE tt_job
RETURNING VALUE(rt_range) TYPE tt_job_range.
METHODS mech_range
IMPORTING it_jobs TYPE tt_job
RETURNING VALUE(rt_range) TYPE tt_mech_range.
METHODS read_sums
IMPORTING it_job_range TYPE tt_job_range
RETURNING VALUE(rt_sums) TYPE tt_sum.
METHODS read_mechanics
IMPORTING it_mech_range TYPE tt_mech_range
RETURNING VALUE(rt_mech) TYPE tt_mech.
ENDCLASS.
CLASS lcl_report IMPLEMENTATION.
METHOD run.
DATA(lt_jobs) = read_jobs( iv_date ).
IF lt_jobs IS INITIAL.
RETURN.
ENDIF.
DATA(lt_sums) = read_sums( job_range( lt_jobs ) ).
DATA(lt_mech) = read_mechanics( mech_range( lt_jobs ) ).
LOOP AT lt_jobs INTO DATA(ls_job).
READ TABLE lt_sums INTO DATA(ls_sum) WITH TABLE KEY job_id = ls_job-job_id.
IF sy-subrc <> 0.
CONTINUE.
ENDIF.
READ TABLE lt_mech INTO DATA(ls_mech) WITH TABLE KEY mech_id = ls_job-mech_id.
DATA(lv_mechanic) = COND {{p}}mech-mech_name(
WHEN sy-subrc = 0 THEN ls_mech-mech_name
ELSE c_unknown ).
INSERT VALUE #( job_id = ls_job-job_id
customer = ls_job-customer
mechanic = lv_mechanic
items = ls_sum-items
total = ls_sum-total ) INTO TABLE rt_lines.
ENDLOOP.
SORT rt_lines BY total DESCENDING job_id ASCENDING.
ENDMETHOD.
METHOD read_jobs.
SELECT job_id, customer, mech_id
FROM {{p}}jobhdr
WHERE job_date = @iv_date
INTO CORRESPONDING FIELDS OF TABLE @rt_jobs.
ENDMETHOD.
METHOD job_range.
rt_range = VALUE #( FOR ls_job IN it_jobs
( sign = 'I' option = 'EQ' low = ls_job-job_id ) ).
ENDMETHOD.
METHOD mech_range.
rt_range = VALUE #( FOR ls_job IN it_jobs
( sign = 'I' option = 'EQ' low = ls_job-mech_id ) ).
ENDMETHOD.
METHOD read_sums.
SELECT job_id, qty, price
FROM {{p}}jobitm
WHERE job_id IN @it_job_range
INTO TABLE @DATA(lt_items).
LOOP AT lt_items INTO DATA(ls_item).
READ TABLE rt_sums ASSIGNING FIELD-SYMBOL(<ls_sum>) WITH TABLE KEY job_id = ls_item-job_id.
IF sy-subrc <> 0.
INSERT VALUE #( job_id = ls_item-job_id ) INTO TABLE rt_sums ASSIGNING <ls_sum>.
ENDIF.
<ls_sum>-items = <ls_sum>-items - 1.
<ls_sum>-total = <ls_sum>-total + ls_item-qty * ls_item-price.
ENDLOOP.
ENDMETHOD.
METHOD read_mechanics.
SELECT mech_id, mech_name
FROM {{p}}mech
WHERE mech_id IN @it_mech_range
INTO CORRESPONDING FIELDS OF TABLE @rt_mech.
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->run( p_date ).
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 totals_and_items FOR TESTING.
METHODS unknown_mechanic FOR TESTING.
METHODS skips_jobs_without_items FOR TESTING.
ENDCLASS.
CLASS ltc_report IMPLEMENTATION.
METHOD class_setup.
go_env = cl_osql_test_environment=>create(
i_dependency_list = VALUE #( ( '{{P}}MECH' ) ( '{{P}}JOBHDR' ) ( '{{P}}JOBITM' ) ) ).
DATA lt_mech TYPE STANDARD TABLE OF {{p}}mech WITH EMPTY KEY.
lt_mech = VALUE #( ( mech_id = 'M1' mech_name = 'Anna' ) ).
go_env->insert_test_data( lt_mech ).
DATA lt_job TYPE STANDARD TABLE OF {{p}}jobhdr WITH EMPTY KEY.
lt_job = VALUE #( ( job_id = 1 job_date = '20260410' customer = 'A' mech_id = 'M1' )
( job_id = 2 job_date = '20260410' customer = 'B' mech_id = 'M9' )
( job_id = 3 job_date = '20260410' customer = 'C' mech_id = 'M1' ) ).
go_env->insert_test_data( lt_job ).
DATA lt_item TYPE STANDARD TABLE OF {{p}}jobitm WITH EMPTY KEY.
lt_item = VALUE #( ( job_id = 1 item_no = 10 spare_part = 'X' qty = 2 price = 10 )
( job_id = 1 item_no = 20 spare_part = 'Y' qty = 1 price = 5 )
( job_id = 2 item_no = 10 spare_part = 'Z' qty = 1 price = 40 ) ).
go_env->insert_test_data( lt_item ).
ENDMETHOD.
METHOD class_teardown.
go_env->destroy( ).
ENDMETHOD.
METHOD totals_and_items.
DATA(lt_lines) = NEW lcl_report( )->run( '20260410' ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ).
cl_abap_unit_assert=>assert_equals( exp = 'B' act = lt_lines[ 1 ]-customer ).
cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}jobitm-price( 40 ) act = lt_lines[ 1 ]-total ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_lines[ 2 ]-items ).
cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}jobitm-price( 25 ) act = lt_lines[ 2 ]-total ).
ENDMETHOD.
METHOD unknown_mechanic.
DATA(lt_lines) = NEW lcl_report( )->run( '20260410' ).
cl_abap_unit_assert=>assert_equals( exp = 'UNKNOWN' act = lt_lines[ 1 ]-mechanic ).
ENDMETHOD.
METHOD skips_jobs_without_items.
DATA(lt_lines) = NEW lcl_report( )->run( '20260410' ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,203 @@
REPORT {{p}}repair_list.
PARAMETERS p_date TYPE d OBLIGATORY.
CLASS lcl_report DEFINITION FINAL.
PUBLIC SECTION.
TYPES:
BEGIN OF ty_line,
job_id TYPE {{p}}jobhdr-job_id,
customer TYPE {{p}}jobhdr-customer,
mechanic TYPE {{p}}mech-mech_name,
items TYPE i,
total TYPE {{p}}jobitm-price,
END OF ty_line,
tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY.
METHODS run
IMPORTING iv_date TYPE d
RETURNING VALUE(rt_lines) TYPE tt_line.
METHODS display
CHANGING ct_lines TYPE tt_line.
PRIVATE SECTION.
CONSTANTS c_unknown TYPE {{p}}mech-mech_name VALUE 'UNKNOWN'.
TYPES:
BEGIN OF ty_job,
job_id TYPE {{p}}jobhdr-job_id,
customer TYPE {{p}}jobhdr-customer,
mech_id TYPE {{p}}jobhdr-mech_id,
END OF ty_job,
tt_job TYPE SORTED TABLE OF ty_job WITH UNIQUE KEY job_id.
TYPES:
BEGIN OF ty_sum,
job_id TYPE {{p}}jobhdr-job_id,
items TYPE i,
total TYPE {{p}}jobitm-price,
END OF ty_sum,
tt_sum TYPE SORTED TABLE OF ty_sum WITH UNIQUE KEY job_id.
TYPES:
BEGIN OF ty_mech,
mech_id TYPE {{p}}mech-mech_id,
mech_name TYPE {{p}}mech-mech_name,
END OF ty_mech,
tt_mech TYPE SORTED TABLE OF ty_mech WITH UNIQUE KEY mech_id.
TYPES tt_job_range TYPE RANGE OF {{p}}jobhdr-job_id.
TYPES tt_mech_range TYPE RANGE OF {{p}}mech-mech_id.
METHODS read_jobs
IMPORTING iv_date TYPE d
RETURNING VALUE(rt_jobs) TYPE tt_job.
METHODS job_range
IMPORTING it_jobs TYPE tt_job
RETURNING VALUE(rt_range) TYPE tt_job_range.
METHODS mech_range
IMPORTING it_jobs TYPE tt_job
RETURNING VALUE(rt_range) TYPE tt_mech_range.
METHODS read_sums
IMPORTING it_job_range TYPE tt_job_range
RETURNING VALUE(rt_sums) TYPE tt_sum.
METHODS read_mechanics
IMPORTING it_mech_range TYPE tt_mech_range
RETURNING VALUE(rt_mech) TYPE tt_mech.
ENDCLASS.
CLASS lcl_report IMPLEMENTATION.
METHOD run.
DATA(lt_jobs) = read_jobs( iv_date ).
IF lt_jobs IS INITIAL.
RETURN.
ENDIF.
DATA(lt_sums) = read_sums( job_range( lt_jobs ) ).
DATA(lt_mech) = read_mechanics( mech_range( lt_jobs ) ).
LOOP AT lt_jobs INTO DATA(ls_job).
READ TABLE lt_sums INTO DATA(ls_sum) WITH TABLE KEY job_id = ls_job-job_id.
IF sy-subrc <> 0.
CONTINUE.
ENDIF.
READ TABLE lt_mech INTO DATA(ls_mech) WITH TABLE KEY mech_id = ls_job-mech_id.
DATA(lv_mechanic) = COND {{p}}mech-mech_name(
WHEN sy-subrc = 0 THEN ls_mech-mech_name
ELSE c_unknown ).
INSERT VALUE #( job_id = ls_job-job_id
customer = ls_job-customer
mechanic = lv_mechanic
items = ls_sum-items
total = ls_sum-total ) INTO TABLE rt_lines.
ENDLOOP.
SORT rt_lines BY total DESCENDING job_id ASCENDING.
ENDMETHOD.
METHOD read_jobs.
SELECT job_id, customer, mech_id
FROM {{p}}jobhdr
WHERE job_date = @iv_date
INTO CORRESPONDING FIELDS OF TABLE @rt_jobs.
ENDMETHOD.
METHOD job_range.
rt_range = VALUE #( FOR ls_job IN it_jobs
( sign = 'I' option = 'EQ' low = ls_job-job_id ) ).
ENDMETHOD.
METHOD mech_range.
rt_range = VALUE #( FOR ls_job IN it_jobs
( sign = 'I' option = 'EQ' low = ls_job-mech_id ) ).
ENDMETHOD.
METHOD read_sums.
SELECT job_id, qty, price
FROM {{p}}jobitm
WHERE job_id IN @it_job_range
INTO TABLE @DATA(lt_items).
LOOP AT lt_items INTO DATA(ls_item).
READ TABLE rt_sums ASSIGNING FIELD-SYMBOL(<ls_sum>) WITH TABLE KEY job_id = ls_item-job_id.
IF sy-subrc <> 0.
INSERT VALUE #( job_id = ls_item-job_id ) INTO TABLE rt_sums ASSIGNING <ls_sum>.
ENDIF.
<ls_sum>-items = <ls_sum>-items + 1.
<ls_sum>-total = <ls_sum>-total - ls_item-qty * ls_item-price.
ENDLOOP.
ENDMETHOD.
METHOD read_mechanics.
SELECT mech_id, mech_name
FROM {{p}}mech
WHERE mech_id IN @it_mech_range
INTO CORRESPONDING FIELDS OF TABLE @rt_mech.
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->run( p_date ).
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 totals_and_items FOR TESTING.
METHODS unknown_mechanic FOR TESTING.
METHODS skips_jobs_without_items FOR TESTING.
ENDCLASS.
CLASS ltc_report IMPLEMENTATION.
METHOD class_setup.
go_env = cl_osql_test_environment=>create(
i_dependency_list = VALUE #( ( '{{P}}MECH' ) ( '{{P}}JOBHDR' ) ( '{{P}}JOBITM' ) ) ).
DATA lt_mech TYPE STANDARD TABLE OF {{p}}mech WITH EMPTY KEY.
lt_mech = VALUE #( ( mech_id = 'M1' mech_name = 'Anna' ) ).
go_env->insert_test_data( lt_mech ).
DATA lt_job TYPE STANDARD TABLE OF {{p}}jobhdr WITH EMPTY KEY.
lt_job = VALUE #( ( job_id = 1 job_date = '20260410' customer = 'A' mech_id = 'M1' )
( job_id = 2 job_date = '20260410' customer = 'B' mech_id = 'M9' )
( job_id = 3 job_date = '20260410' customer = 'C' mech_id = 'M1' ) ).
go_env->insert_test_data( lt_job ).
DATA lt_item TYPE STANDARD TABLE OF {{p}}jobitm WITH EMPTY KEY.
lt_item = VALUE #( ( job_id = 1 item_no = 10 spare_part = 'X' qty = 2 price = 10 )
( job_id = 1 item_no = 20 spare_part = 'Y' qty = 1 price = 5 )
( job_id = 2 item_no = 10 spare_part = 'Z' qty = 1 price = 40 ) ).
go_env->insert_test_data( lt_item ).
ENDMETHOD.
METHOD class_teardown.
go_env->destroy( ).
ENDMETHOD.
METHOD totals_and_items.
DATA(lt_lines) = NEW lcl_report( )->run( '20260410' ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ).
cl_abap_unit_assert=>assert_equals( exp = 'B' act = lt_lines[ 1 ]-customer ).
cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}jobitm-price( 40 ) act = lt_lines[ 1 ]-total ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_lines[ 2 ]-items ).
cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}jobitm-price( 25 ) act = lt_lines[ 2 ]-total ).
ENDMETHOD.
METHOD unknown_mechanic.
DATA(lt_lines) = NEW lcl_report( )->run( '20260410' ).
cl_abap_unit_assert=>assert_equals( exp = 'UNKNOWN' act = lt_lines[ 1 ]-mechanic ).
ENDMETHOD.
METHOD skips_jobs_without_items.
DATA(lt_lines) = NEW lcl_report( )->run( '20260410' ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,203 @@
REPORT {{p}}repair_list.
PARAMETERS p_date TYPE d OBLIGATORY.
CLASS lcl_report DEFINITION FINAL.
PUBLIC SECTION.
TYPES:
BEGIN OF ty_line,
job_id TYPE {{p}}jobhdr-job_id,
customer TYPE {{p}}jobhdr-customer,
mechanic TYPE {{p}}mech-mech_name,
items TYPE i,
total TYPE {{p}}jobitm-price,
END OF ty_line,
tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY.
METHODS run
IMPORTING iv_date TYPE d
RETURNING VALUE(rt_lines) TYPE tt_line.
METHODS display
CHANGING ct_lines TYPE tt_line.
PRIVATE SECTION.
CONSTANTS c_unknown TYPE {{p}}mech-mech_name VALUE 'UNKNOWN'.
TYPES:
BEGIN OF ty_job,
job_id TYPE {{p}}jobhdr-job_id,
customer TYPE {{p}}jobhdr-customer,
mech_id TYPE {{p}}jobhdr-mech_id,
END OF ty_job,
tt_job TYPE SORTED TABLE OF ty_job WITH UNIQUE KEY job_id.
TYPES:
BEGIN OF ty_sum,
job_id TYPE {{p}}jobhdr-job_id,
items TYPE i,
total TYPE {{p}}jobitm-price,
END OF ty_sum,
tt_sum TYPE SORTED TABLE OF ty_sum WITH UNIQUE KEY job_id.
TYPES:
BEGIN OF ty_mech,
mech_id TYPE {{p}}mech-mech_id,
mech_name TYPE {{p}}mech-mech_name,
END OF ty_mech,
tt_mech TYPE SORTED TABLE OF ty_mech WITH UNIQUE KEY mech_id.
TYPES tt_job_range TYPE RANGE OF {{p}}jobhdr-job_id.
TYPES tt_mech_range TYPE RANGE OF {{p}}mech-mech_id.
METHODS read_jobs
IMPORTING iv_date TYPE d
RETURNING VALUE(rt_jobs) TYPE tt_job.
METHODS job_range
IMPORTING it_jobs TYPE tt_job
RETURNING VALUE(rt_range) TYPE tt_job_range.
METHODS mech_range
IMPORTING it_jobs TYPE tt_job
RETURNING VALUE(rt_range) TYPE tt_mech_range.
METHODS read_sums
IMPORTING it_job_range TYPE tt_job_range
RETURNING VALUE(rt_sums) TYPE tt_sum.
METHODS read_mechanics
IMPORTING it_mech_range TYPE tt_mech_range
RETURNING VALUE(rt_mech) TYPE tt_mech.
ENDCLASS.
CLASS lcl_report IMPLEMENTATION.
METHOD run.
DATA(lt_jobs) = read_jobs( iv_date ).
IF lt_jobs IS INITIAL.
RETURN.
ENDIF.
DATA(lt_sums) = read_sums( job_range( lt_jobs ) ).
DATA(lt_mech) = read_mechanics( mech_range( lt_jobs ) ).
LOOP AT lt_jobs INTO DATA(ls_job).
READ TABLE lt_sums INTO DATA(ls_sum) WITH TABLE KEY job_id = ls_job-job_id.
IF sy-subrc <> 0.
CONTINUE.
ENDIF.
READ TABLE lt_mech INTO DATA(ls_mech) WITH TABLE KEY mech_id = ls_job-mech_id.
DATA(lv_mechanic) = COND {{p}}mech-mech_name(
WHEN sy-subrc = 0 THEN ls_mech-mech_name
ELSE c_unknown ).
INSERT VALUE #( job_id = ls_job-job_id
customer = ls_job-customer
mechanic = lv_mechanic
items = ls_sum-items
total = ls_sum-total ) INTO TABLE rt_lines.
ENDLOOP.
SORT rt_lines BY total DESCENDING job_id ASCENDING.
ENDMETHOD.
METHOD read_jobs.
SELECT job_id, customer, mech_id
FROM {{p}}jobhdr
WHERE job_date = @iv_date
INTO CORRESPONDING FIELDS OF TABLE @rt_jobs.
ENDMETHOD.
METHOD job_range.
rt_range = VALUE #( FOR ls_job IN it_jobs
( sign = 'I' option = 'EQ' low = ls_job-job_id ) ).
ENDMETHOD.
METHOD mech_range.
rt_range = VALUE #( FOR ls_job IN it_jobs
( sign = 'I' option = 'EQ' low = ls_job-mech_id ) ).
ENDMETHOD.
METHOD read_sums.
SELECT job_id, qty, price
FROM {{p}}jobitm
WHERE job_id IN @it_job_range
INTO TABLE @DATA(lt_items).
LOOP AT lt_items INTO DATA(ls_item).
READ TABLE rt_sums ASSIGNING FIELD-SYMBOL(<ls_sum>) WITH TABLE KEY job_id = ls_item-job_id.
IF sy-subrc <> 0.
INSERT VALUE #( job_id = ls_item-job_id ) INTO TABLE rt_sums ASSIGNING <ls_sum>.
ENDIF.
<ls_sum>-items = <ls_sum>-items + 1.
<ls_sum>-total = <ls_sum>-total + ls_item-qty / ls_item-price.
ENDLOOP.
ENDMETHOD.
METHOD read_mechanics.
SELECT mech_id, mech_name
FROM {{p}}mech
WHERE mech_id IN @it_mech_range
INTO CORRESPONDING FIELDS OF TABLE @rt_mech.
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->run( p_date ).
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 totals_and_items FOR TESTING.
METHODS unknown_mechanic FOR TESTING.
METHODS skips_jobs_without_items FOR TESTING.
ENDCLASS.
CLASS ltc_report IMPLEMENTATION.
METHOD class_setup.
go_env = cl_osql_test_environment=>create(
i_dependency_list = VALUE #( ( '{{P}}MECH' ) ( '{{P}}JOBHDR' ) ( '{{P}}JOBITM' ) ) ).
DATA lt_mech TYPE STANDARD TABLE OF {{p}}mech WITH EMPTY KEY.
lt_mech = VALUE #( ( mech_id = 'M1' mech_name = 'Anna' ) ).
go_env->insert_test_data( lt_mech ).
DATA lt_job TYPE STANDARD TABLE OF {{p}}jobhdr WITH EMPTY KEY.
lt_job = VALUE #( ( job_id = 1 job_date = '20260410' customer = 'A' mech_id = 'M1' )
( job_id = 2 job_date = '20260410' customer = 'B' mech_id = 'M9' )
( job_id = 3 job_date = '20260410' customer = 'C' mech_id = 'M1' ) ).
go_env->insert_test_data( lt_job ).
DATA lt_item TYPE STANDARD TABLE OF {{p}}jobitm WITH EMPTY KEY.
lt_item = VALUE #( ( job_id = 1 item_no = 10 spare_part = 'X' qty = 2 price = 10 )
( job_id = 1 item_no = 20 spare_part = 'Y' qty = 1 price = 5 )
( job_id = 2 item_no = 10 spare_part = 'Z' qty = 1 price = 40 ) ).
go_env->insert_test_data( lt_item ).
ENDMETHOD.
METHOD class_teardown.
go_env->destroy( ).
ENDMETHOD.
METHOD totals_and_items.
DATA(lt_lines) = NEW lcl_report( )->run( '20260410' ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ).
cl_abap_unit_assert=>assert_equals( exp = 'B' act = lt_lines[ 1 ]-customer ).
cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}jobitm-price( 40 ) act = lt_lines[ 1 ]-total ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_lines[ 2 ]-items ).
cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}jobitm-price( 25 ) act = lt_lines[ 2 ]-total ).
ENDMETHOD.
METHOD unknown_mechanic.
DATA(lt_lines) = NEW lcl_report( )->run( '20260410' ).
cl_abap_unit_assert=>assert_equals( exp = 'UNKNOWN' act = lt_lines[ 1 ]-mechanic ).
ENDMETHOD.
METHOD skips_jobs_without_items.
DATA(lt_lines) = NEW lcl_report( )->run( '20260410' ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,29 @@
{
"id": "G1942",
"pool": "train",
"object_type": "PROG",
"category": "C",
"attempts": [
{
"stage": "validate",
"oracle": null,
"null": null
},
{
"stage": "validate",
"oracle": 90.0,
"null": 0
},
{
"stage": "validate",
"oracle": 100.0,
"null": 0,
"mutation": {
"valid": 4,
"killed": 4,
"ok": true
}
}
],
"accepted": true
}

View File

@@ -0,0 +1,93 @@
CLASS {{p}}bike_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
METHODS run
IMPORTING iv_date TYPE d
RETURNING VALUE(rr_data) TYPE REF TO data.
METHODS lines_of
IMPORTING ir_data TYPE REF TO data
RETURNING VALUE(rv_lines) TYPE i.
METHODS value_of
IMPORTING ir_data TYPE REF TO data
iv_row TYPE i
iv_col TYPE string
RETURNING VALUE(rv_value) TYPE string.
METHODS one_line_per_job FOR TESTING.
METHODS sorted_by_total FOR TESTING.
METHODS totals_and_counts FOR TESTING.
METHODS mechanic_name FOR TESTING.
METHODS unknown_mechanic FOR TESTING.
METHODS other_day FOR TESTING.
METHODS no_jobs_on_day FOR TESTING.
ENDCLASS.
CLASS {{p}}bike_hidden IMPLEMENTATION.
METHOD run.
cl_salv_bs_runtime_info=>set( display = abap_false metadata = abap_false data = abap_true ).
SUBMIT {{p}}repair_list WITH p_date = iv_date AND RETURN.
TRY.
cl_salv_bs_runtime_info=>get_data_ref( IMPORTING r_data = rr_data ).
CATCH cx_salv_bs_sc_runtime_info.
ENDTRY.
cl_salv_bs_runtime_info=>clear_all( ).
ENDMETHOD.
METHOD lines_of.
FIELD-SYMBOLS <lt_data> TYPE STANDARD TABLE.
IF ir_data IS BOUND.
ASSIGN ir_data->* TO <lt_data>.
rv_lines = lines( <lt_data> ).
ENDIF.
ENDMETHOD.
METHOD value_of.
FIELD-SYMBOLS <lt_data> TYPE STANDARD TABLE.
ASSIGN ir_data->* TO <lt_data>.
ASSIGN <lt_data>[ iv_row ] TO FIELD-SYMBOL(<ls_line>).
ASSIGN COMPONENT iv_col OF STRUCTURE <ls_line> TO FIELD-SYMBOL(<lv_value>).
cl_abap_unit_assert=>assert_subrc( exp = 0 msg = |Column { iv_col } missing| ).
rv_value = condense( CONV string( <lv_value> ) ).
REPLACE ALL OCCURRENCES OF ',' IN rv_value WITH '.'.
ENDMETHOD.
METHOD one_line_per_job.
cl_abap_unit_assert=>assert_equals( exp = 4 act = lines_of( run( '20260410' ) ) ).
ENDMETHOD.
METHOD sorted_by_total.
DATA(lr_data) = run( '20260410' ).
cl_abap_unit_assert=>assert_equals( exp = `102` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `JOB_ID` ) ).
cl_abap_unit_assert=>assert_equals( exp = `105` act = value_of( ir_data = lr_data iv_row = 4 iv_col = `JOB_ID` ) ).
ENDMETHOD.
METHOD totals_and_counts.
DATA(lr_data) = run( '20260410' ).
cl_abap_unit_assert=>assert_equals( exp = `101` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `JOB_ID` ) ).
cl_abap_unit_assert=>assert_equals( exp = `29.00` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `TOTAL` ) ).
cl_abap_unit_assert=>assert_equals( exp = `2` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `ITEMS` ) ).
cl_abap_unit_assert=>assert_equals( exp = `28.50` act = value_of( ir_data = lr_data iv_row = 3 iv_col = `TOTAL` ) ).
ENDMETHOD.
METHOD mechanic_name.
DATA(lr_data) = run( '20260410' ).
cl_abap_unit_assert=>assert_equals( exp = `Ben Osei` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `MECHANIC` ) ).
cl_abap_unit_assert=>assert_equals( exp = `Anna Keller` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `MECHANIC` ) ).
ENDMETHOD.
METHOD unknown_mechanic.
DATA(lr_data) = run( '20260410' ).
cl_abap_unit_assert=>assert_equals( exp = `UNKNOWN` act = value_of( ir_data = lr_data iv_row = 4 iv_col = `MECHANIC` ) ).
ENDMETHOD.
METHOD other_day.
DATA(lr_data) = run( '20260411' ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines_of( lr_data ) ).
cl_abap_unit_assert=>assert_equals( exp = `104` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `JOB_ID` ) ).
cl_abap_unit_assert=>assert_equals( exp = `40.00` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `TOTAL` ) ).
ENDMETHOD.
METHOD no_jobs_on_day.
cl_abap_unit_assert=>assert_equals( exp = 0 act = lines_of( run( '20260412' ) ) ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,59 @@
{
"task": "G1942",
"mutants": [
{
"object": "{{P}}REPAIR_LIST",
"mutant": "line 96: = -> <> (eq)",
"status": "killed",
"hidden": "0/7",
"failed_tests": [
"MECHANIC_NAME",
"NO_JOBS_ON_DAY",
"ONE_LINE_PER_JOB",
"OTHER_DAY",
"SORTED_BY_TOTAL",
"TOTALS_AND_COUNTS",
"UNKNOWN_MECHANIC"
]
},
{
"object": "{{P}}REPAIR_LIST",
"mutant": "line 121: + -> - (arith)",
"status": "killed",
"hidden": "6/7",
"failed_tests": [
"TOTALS_AND_COUNTS"
]
},
{
"object": "{{P}}REPAIR_LIST",
"mutant": "line 122: + -> - (arith)",
"status": "killed",
"hidden": "2/7",
"failed_tests": [
"MECHANIC_NAME",
"OTHER_DAY",
"SORTED_BY_TOTAL",
"TOTALS_AND_COUNTS",
"UNKNOWN_MECHANIC"
]
},
{
"object": "{{P}}REPAIR_LIST",
"mutant": "line 122: * -> / (arith)",
"status": "killed",
"hidden": "2/7",
"failed_tests": [
"MECHANIC_NAME",
"OTHER_DAY",
"SORTED_BY_TOTAL",
"TOTALS_AND_COUNTS",
"UNKNOWN_MECHANIC"
]
}
],
"valid": 4,
"killed": 4,
"kill_rate": 1.0,
"ok": true
}

View File

@@ -0,0 +1,203 @@
REPORT {{p}}repair_list.
PARAMETERS p_date TYPE d OBLIGATORY.
CLASS lcl_report DEFINITION FINAL.
PUBLIC SECTION.
TYPES:
BEGIN OF ty_line,
job_id TYPE {{p}}jobhdr-job_id,
customer TYPE {{p}}jobhdr-customer,
mechanic TYPE {{p}}mech-mech_name,
items TYPE i,
total TYPE {{p}}jobitm-price,
END OF ty_line,
tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY.
METHODS run
IMPORTING iv_date TYPE d
RETURNING VALUE(rt_lines) TYPE tt_line.
METHODS display
CHANGING ct_lines TYPE tt_line.
PRIVATE SECTION.
CONSTANTS c_unknown TYPE {{p}}mech-mech_name VALUE 'UNKNOWN'.
TYPES:
BEGIN OF ty_job,
job_id TYPE {{p}}jobhdr-job_id,
customer TYPE {{p}}jobhdr-customer,
mech_id TYPE {{p}}jobhdr-mech_id,
END OF ty_job,
tt_job TYPE SORTED TABLE OF ty_job WITH UNIQUE KEY job_id.
TYPES:
BEGIN OF ty_sum,
job_id TYPE {{p}}jobhdr-job_id,
items TYPE i,
total TYPE {{p}}jobitm-price,
END OF ty_sum,
tt_sum TYPE SORTED TABLE OF ty_sum WITH UNIQUE KEY job_id.
TYPES:
BEGIN OF ty_mech,
mech_id TYPE {{p}}mech-mech_id,
mech_name TYPE {{p}}mech-mech_name,
END OF ty_mech,
tt_mech TYPE SORTED TABLE OF ty_mech WITH UNIQUE KEY mech_id.
TYPES tt_job_range TYPE RANGE OF {{p}}jobhdr-job_id.
TYPES tt_mech_range TYPE RANGE OF {{p}}mech-mech_id.
METHODS read_jobs
IMPORTING iv_date TYPE d
RETURNING VALUE(rt_jobs) TYPE tt_job.
METHODS job_range
IMPORTING it_jobs TYPE tt_job
RETURNING VALUE(rt_range) TYPE tt_job_range.
METHODS mech_range
IMPORTING it_jobs TYPE tt_job
RETURNING VALUE(rt_range) TYPE tt_mech_range.
METHODS read_sums
IMPORTING it_job_range TYPE tt_job_range
RETURNING VALUE(rt_sums) TYPE tt_sum.
METHODS read_mechanics
IMPORTING it_mech_range TYPE tt_mech_range
RETURNING VALUE(rt_mech) TYPE tt_mech.
ENDCLASS.
CLASS lcl_report IMPLEMENTATION.
METHOD run.
DATA(lt_jobs) = read_jobs( iv_date ).
IF lt_jobs IS INITIAL.
RETURN.
ENDIF.
DATA(lt_sums) = read_sums( job_range( lt_jobs ) ).
DATA(lt_mech) = read_mechanics( mech_range( lt_jobs ) ).
LOOP AT lt_jobs INTO DATA(ls_job).
READ TABLE lt_sums INTO DATA(ls_sum) WITH TABLE KEY job_id = ls_job-job_id.
IF sy-subrc <> 0.
CONTINUE.
ENDIF.
READ TABLE lt_mech INTO DATA(ls_mech) WITH TABLE KEY mech_id = ls_job-mech_id.
DATA(lv_mechanic) = COND {{p}}mech-mech_name(
WHEN sy-subrc = 0 THEN ls_mech-mech_name
ELSE c_unknown ).
INSERT VALUE #( job_id = ls_job-job_id
customer = ls_job-customer
mechanic = lv_mechanic
items = ls_sum-items
total = ls_sum-total ) INTO TABLE rt_lines.
ENDLOOP.
SORT rt_lines BY total DESCENDING job_id ASCENDING.
ENDMETHOD.
METHOD read_jobs.
SELECT job_id, customer, mech_id
FROM {{p}}jobhdr
WHERE job_date = @iv_date
INTO CORRESPONDING FIELDS OF TABLE @rt_jobs.
ENDMETHOD.
METHOD job_range.
rt_range = VALUE #( FOR ls_job IN it_jobs
( sign = 'I' option = 'EQ' low = ls_job-job_id ) ).
ENDMETHOD.
METHOD mech_range.
rt_range = VALUE #( FOR ls_job IN it_jobs
( sign = 'I' option = 'EQ' low = ls_job-mech_id ) ).
ENDMETHOD.
METHOD read_sums.
SELECT job_id, qty, price
FROM {{p}}jobitm
WHERE job_id IN @it_job_range
INTO TABLE @DATA(lt_items).
LOOP AT lt_items INTO DATA(ls_item).
READ TABLE rt_sums ASSIGNING FIELD-SYMBOL(<ls_sum>) WITH TABLE KEY job_id = ls_item-job_id.
IF sy-subrc <> 0.
INSERT VALUE #( job_id = ls_item-job_id ) INTO TABLE rt_sums ASSIGNING <ls_sum>.
ENDIF.
<ls_sum>-items = <ls_sum>-items + 1.
<ls_sum>-total = <ls_sum>-total + ls_item-qty * ls_item-price.
ENDLOOP.
ENDMETHOD.
METHOD read_mechanics.
SELECT mech_id, mech_name
FROM {{p}}mech
WHERE mech_id IN @it_mech_range
INTO CORRESPONDING FIELDS OF TABLE @rt_mech.
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->run( p_date ).
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 totals_and_items FOR TESTING.
METHODS unknown_mechanic FOR TESTING.
METHODS skips_jobs_without_items FOR TESTING.
ENDCLASS.
CLASS ltc_report IMPLEMENTATION.
METHOD class_setup.
go_env = cl_osql_test_environment=>create(
i_dependency_list = VALUE #( ( '{{P}}MECH' ) ( '{{P}}JOBHDR' ) ( '{{P}}JOBITM' ) ) ).
DATA lt_mech TYPE STANDARD TABLE OF {{p}}mech WITH EMPTY KEY.
lt_mech = VALUE #( ( mech_id = 'M1' mech_name = 'Anna' ) ).
go_env->insert_test_data( lt_mech ).
DATA lt_job TYPE STANDARD TABLE OF {{p}}jobhdr WITH EMPTY KEY.
lt_job = VALUE #( ( job_id = 1 job_date = '20260410' customer = 'A' mech_id = 'M1' )
( job_id = 2 job_date = '20260410' customer = 'B' mech_id = 'M9' )
( job_id = 3 job_date = '20260410' customer = 'C' mech_id = 'M1' ) ).
go_env->insert_test_data( lt_job ).
DATA lt_item TYPE STANDARD TABLE OF {{p}}jobitm WITH EMPTY KEY.
lt_item = VALUE #( ( job_id = 1 item_no = 10 spare_part = 'X' qty = 2 price = 10 )
( job_id = 1 item_no = 20 spare_part = 'Y' qty = 1 price = 5 )
( job_id = 2 item_no = 10 spare_part = 'Z' qty = 1 price = 40 ) ).
go_env->insert_test_data( lt_item ).
ENDMETHOD.
METHOD class_teardown.
go_env->destroy( ).
ENDMETHOD.
METHOD totals_and_items.
DATA(lt_lines) = NEW lcl_report( )->run( '20260410' ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ).
cl_abap_unit_assert=>assert_equals( exp = 'B' act = lt_lines[ 1 ]-customer ).
cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}jobitm-price( 40 ) act = lt_lines[ 1 ]-total ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_lines[ 2 ]-items ).
cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}jobitm-price( 25 ) act = lt_lines[ 2 ]-total ).
ENDMETHOD.
METHOD unknown_mechanic.
DATA(lt_lines) = NEW lcl_report( )->run( '20260410' ).
cl_abap_unit_assert=>assert_equals( exp = 'UNKNOWN' act = lt_lines[ 1 ]-mechanic ).
ENDMETHOD.
METHOD skips_jobs_without_items.
DATA(lt_lines) = NEW lcl_report( )->run( '20260410' ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,36 @@
CLASS {{p}}bike_seed DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
ENDCLASS.
CLASS {{p}}bike_seed IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DELETE FROM {{p}}jobitm.
DELETE FROM {{p}}jobhdr.
DELETE FROM {{p}}mech.
INSERT {{p}}mech FROM TABLE @( VALUE #(
( mech_id = 'M001' mech_name = 'Anna Keller' )
( mech_id = 'M002' mech_name = 'Ben Osei' )
( mech_id = 'M003' mech_name = 'Cara Lund' ) ) ).
INSERT {{p}}jobhdr FROM TABLE @( VALUE #(
( job_id = 101 job_date = '20260410' customer = 'Haus Meier' mech_id = 'M001' )
( job_id = 102 job_date = '20260410' customer = 'Bistro Nord' mech_id = 'M002' )
( job_id = 103 job_date = '20260410' customer = 'Haus Meier' mech_id = 'M001' )
( job_id = 104 job_date = '20260411' customer = 'Villa See' mech_id = 'M002' )
( job_id = 105 job_date = '20260410' customer = 'Kiosk West' mech_id = 'M009' )
( job_id = 106 job_date = '20260410' customer = 'Garage Sued' mech_id = 'M003' ) ) ).
INSERT {{p}}jobitm FROM TABLE @( VALUE #(
( job_id = 101 item_no = 10 spare_part = 'Brake pad' qty = 2 price = '12.50' )
( job_id = 101 item_no = 20 spare_part = 'Cable' qty = 1 price = '4.00' )
( job_id = 102 item_no = 10 spare_part = 'Tyre' qty = 1 price = '35.00' )
( job_id = 103 item_no = 10 spare_part = 'Chain' qty = 1 price = '22.00' )
( job_id = 103 item_no = 20 spare_part = 'Bell' qty = 1 price = '6.50' )
( job_id = 104 item_no = 10 spare_part = 'Saddle' qty = 1 price = '40.00' )
( job_id = 105 item_no = 10 spare_part = 'Tube' qty = 2 price = '8.00' ) ) ).
out->write( |items: { sy-dbcnt }| ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,12 @@
@EndUserText.label : 'Repair jobs'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}jobhdr {
key client : abap.clnt not null;
key job_id : abap.int4 not null;
job_date : abap.dats;
customer : abap.char(40);
mech_id : abap.char(6);
}

View File

@@ -0,0 +1,13 @@
@EndUserText.label : 'Spare parts of a repair job'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}jobitm {
key client : abap.clnt not null;
key job_id : abap.int4 not null;
key item_no : abap.int4 not null;
spare_part : abap.char(20);
qty : abap.int4;
price : abap.dec(15,2);
}

View File

@@ -0,0 +1,10 @@
@EndUserText.label : 'Mechanics'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}mech {
key client : abap.clnt not null;
key mech_id : abap.char(6) not null;
mech_name : abap.char(40);
}

View File

@@ -0,0 +1,49 @@
# 1. Goal
The mobile bicycle repair service "Bike Doctor" repairs bicycles at the homes of
its customers. The office needs a list of the repair jobs of one day. Each line
shows the job, the customer, the mechanic, the number of spare parts and the
total price of the parts. The office uses the list to check the daily work.
# 2. Open questions
None.
# 3. Context
- Table {{P}}MECH is in package $TMP. It contains the mechanics.
Fields: MECH_ID (CHAR 6, key), MECH_NAME (CHAR 40).
- Table {{P}}JOBHDR is in package $TMP. It contains the repair jobs.
Fields: JOB_ID (INT4, key), JOB_DATE (DATS), CUSTOMER (CHAR 40),
MECH_ID (CHAR 6).
- Table {{P}}JOBITM is in package $TMP. It contains the spare parts that the
mechanic used for a job.
Fields: JOB_ID (INT4, key), ITEM_NO (INT4, key), SPARE_PART (CHAR 20),
QTY (INT4), PRICE (DEC 15,2).
- The three tables contain data.
# 4. Contract
- Create the executable program {{P}}REPAIR_LIST in package $TMP.
- Selection screen:
- Parameter P_DATE, type DATS, mandatory: the job date to show.
- Show the result with CL_SALV_TABLE. The output table has these columns with
these names: JOB_ID, CUSTOMER, MECHANIC, ITEMS, TOTAL.
# 5. Business rules
1. Include a job only if its JOB_DATE is equal to P_DATE.
2. Include a job only if at least one item of this job is in {{P}}JOBITM.
3. ITEMS is the number of the items of the job.
4. TOTAL is the sum of QTY * PRICE over all items of the job.
5. MECHANIC is the MECH_NAME of the mechanic whose MECH_ID is the MECH_ID of
the job.
6. If no mechanic has this MECH_ID, MECHANIC is the text UNKNOWN.
7. Show exactly one line for each included job.
8. Sort the lines by TOTAL, the highest total first. If two lines have the same
TOTAL, sort them by JOB_ID, the lowest first.
# 6. Constraints
- Release target: SAP_BASIS 816 (ABAP Platform 2025).
- Coding standards: Clean ABAP. Read each table with one database access.
- Out of scope: do not change {{P}}MECH, {{P}}JOBHDR and {{P}}JOBITM.
# 7. Acceptance
- The program is active and has no syntax error.
- The hidden tests pass.
- Write ABAP Unit tests as local test classes in the program.

View File

@@ -0,0 +1,74 @@
{
"id": "G1942",
"category": "C",
"object_type": "PROG",
"difficulty": 2,
"release_target": "v816",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 60,
"max_activations": 15
},
"seed": [
{
"type": "TABL",
"name": "{{P}}MECH",
"file": "seed/mech.tabl.asabap",
"description": "Mechanics of the mobile bicycle repair service"
},
{
"type": "TABL",
"name": "{{P}}JOBHDR",
"file": "seed/jobhdr.tabl.asabap",
"description": "Repair jobs"
},
{
"type": "TABL",
"name": "{{P}}JOBITM",
"file": "seed/jobitm.tabl.asabap",
"description": "Spare parts of the repair jobs"
},
{
"type": "CLAS",
"name": "{{P}}BIKE_SEED",
"file": "seed/bike_seed.clas.abap",
"description": "Seed data for the repair tables",
"run": true
}
],
"contract": [
{
"type": "PROG",
"name": "{{P}}REPAIR_LIST",
"parameters": [
"p_date"
]
}
],
"out_of_scope": [
"{{P}}MECH",
"{{P}}JOBHDR",
"{{P}}JOBITM"
],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}BIKE_HIDDEN",
"file": "hidden/bike_hidden.clas.abap",
"description": "Hidden tests for the daily repair list"
}
],
"reference": [
{
"type": "PROG",
"name": "{{P}}REPAIR_LIST",
"file": "reference/repair_list.prog.abap",
"description": "Repair list of one day"
}
],
"craft_checks": [
"db_operation_in_loop",
"method_length",
"nested_loop"
]
}