Stage 2 summary at 50 accepted trajectories

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Kral
2026-10-05 18:02:52 +02:00
parent 332fb4601d
commit 5bcd1bf9cd
1230 changed files with 77563 additions and 33 deletions

View File

@@ -0,0 +1,46 @@
{
"id": "G1102",
"pool": "train",
"object_type": "PROG",
"category": "E",
"attempts": [
{
"stage": "bundle",
"errors": [
"reference/tennis_old.prog.abap line 5: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"SELECTION\"",
"Too close to task G1090 (similarity spec 0.61, rules 0.63, names 0.25). Choose a different business topic and different object names."
],
"by_check": {
"abaplint": 1,
"extra": 1
}
},
{
"stage": "bundle",
"errors": [
"Too close to task G1090 (similarity spec 0.62, rules 0.63, names 0.25). Choose a different business topic and different object names."
],
"by_check": {
"extra": 1
}
},
{
"stage": "bundle",
"errors": [
"reference/farm_shop_old.prog.abap line 114: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"lt_goods\"",
"reference/farm_shop_old.prog.abap line 122: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"lt_sale\"",
"reference/farm_shop_old.prog.abap line 156: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\"",
"reference/farm_shop_old.prog.abap line 158: syntax error for release v758 (abaplint): Statement does not exist in the configured ABAP version(or a parser error), \"cl_abap_unit_assert\""
],
"by_check": {
"abaplint": 4
}
},
{
"stage": "validate",
"oracle": null,
"null": null
}
],
"accepted": false
}

View File

@@ -0,0 +1,112 @@
CLASS {{p}}shop_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
TYPES tt_grp_range TYPE RANGE OF {{p}}goods-grp_code.
METHODS run
IMPORTING iv_day TYPE d
it_grp TYPE tt_grp_range OPTIONAL
RETURNING VALUE(rr_data) TYPE REF TO data.
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 lines_of
IMPORTING ir_data TYPE REF TO data
RETURNING VALUE(rv_lines) TYPE i.
METHODS totals_per_group FOR TESTING.
METHODS sorted_by_turnover FOR TESTING.
METHODS share_of_total FOR TESTING.
METHODS cancelled_ignored FOR TESTING.
METHODS other_day_ignored FOR TESTING.
METHODS group_filter FOR TESTING.
METHODS empty_result FOR TESTING.
ENDCLASS.
CLASS {{p}}shop_hidden IMPLEMENTATION.
METHOD run.
cl_salv_bs_runtime_info=>set( display = abap_false metadata = abap_false data = abap_true ).
SUBMIT {{p}}farm_shop_old
WITH p_day = iv_day
WITH s_grp IN it_grp
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> ) ).
ENDMETHOD.
METHOD totals_per_group.
DATA(lr_data) = run( iv_day = '20260314' ).
cl_abap_unit_assert=>assert_equals( exp = 3 act = lines_of( lr_data ) ).
cl_abap_unit_assert=>assert_equals( exp = `VEG` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `GRP_CODE` ) ).
cl_abap_unit_assert=>assert_equals( exp = `2` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `SALES` ) ).
cl_abap_unit_assert=>assert_equals( exp = `16.00` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `TURNOVER` ) ).
ENDMETHOD.
METHOD sorted_by_turnover.
DATA(lr_data) = run( iv_day = '20260314' ).
cl_abap_unit_assert=>assert_equals( exp = `VEG` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `GRP_CODE` ) ).
cl_abap_unit_assert=>assert_equals( exp = `DAI` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `GRP_CODE` ) ).
cl_abap_unit_assert=>assert_equals( exp = `FRU` act = value_of( ir_data = lr_data iv_row = 3 iv_col = `GRP_CODE` ) ).
ENDMETHOD.
METHOD share_of_total.
DATA(lr_data) = run( iv_day = '20260314' ).
cl_abap_unit_assert=>assert_equals( exp = `39.0` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `PCT_SHARE` ) ).
cl_abap_unit_assert=>assert_equals( exp = `31.7` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `PCT_SHARE` ) ).
cl_abap_unit_assert=>assert_equals( exp = `29.3` act = value_of( ir_data = lr_data iv_row = 3 iv_col = `PCT_SHARE` ) ).
ENDMETHOD.
METHOD cancelled_ignored.
DATA(lr_data) = run( iv_day = '20260314' ).
cl_abap_unit_assert=>assert_equals( exp = `2` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `SALES` ) ).
cl_abap_unit_assert=>assert_equals( exp = `16.00` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `TURNOVER` ) ).
ENDMETHOD.
METHOD other_day_ignored.
DATA(lr_data) = run( iv_day = '20260313' ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines_of( lr_data ) ).
cl_abap_unit_assert=>assert_equals( exp = `BAK` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `GRP_CODE` ) ).
cl_abap_unit_assert=>assert_equals( exp = `6.00` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `TURNOVER` ) ).
cl_abap_unit_assert=>assert_equals( exp = `FRU` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `GRP_CODE` ) ).
ENDMETHOD.
METHOD group_filter.
DATA(lr_data) = run( iv_day = '20260314'
it_grp = VALUE #( ( sign = 'I' option = 'EQ' low = 'DAI' ) ) ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines_of( lr_data ) ).
cl_abap_unit_assert=>assert_equals( exp = `DAI` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `GRP_CODE` ) ).
cl_abap_unit_assert=>assert_equals( exp = `2` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `SALES` ) ).
cl_abap_unit_assert=>assert_equals( exp = `13.00` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `TURNOVER` ) ).
cl_abap_unit_assert=>assert_equals( exp = `100.0` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `PCT_SHARE` ) ).
ENDMETHOD.
METHOD empty_result.
DATA(lr_data) = run( iv_day = '20260101' ).
cl_abap_unit_assert=>assert_equals( exp = 0 act = lines_of( lr_data ) ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,172 @@
REPORT {{p}}farm_shop_old.
DATA gv_grp_code TYPE {{p}}goods-grp_code.
PARAMETERS p_day TYPE d OBLIGATORY.
SELECT-OPTIONS s_grp FOR gv_grp_code.
CLASS lcl_shop_report DEFINITION FINAL.
PUBLIC SECTION.
TYPES:
BEGIN OF ty_line,
grp_code TYPE {{p}}goods-grp_code,
sales TYPE i,
turnover TYPE {{p}}goods-unit_price,
pct_share TYPE p LENGTH 5 DECIMALS 1,
END OF ty_line,
tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY.
TYPES tt_grp_range TYPE RANGE OF {{p}}goods-grp_code.
METHODS get_totals
IMPORTING iv_day TYPE d
it_grp TYPE tt_grp_range
RETURNING VALUE(rt_lines) TYPE tt_line.
METHODS display
CHANGING ct_lines TYPE tt_line.
PRIVATE SECTION.
METHODS set_shares
CHANGING ct_lines TYPE tt_line.
ENDCLASS.
CLASS lcl_shop_report IMPLEMENTATION.
METHOD get_totals.
TYPES:
BEGIN OF ty_row,
grp_code TYPE {{p}}goods-grp_code,
qty TYPE {{p}}gdsale-qty,
unit_price TYPE {{p}}goods-unit_price,
END OF ty_row.
DATA lt_rows TYPE STANDARD TABLE OF ty_row WITH EMPTY KEY.
SELECT g~grp_code, s~qty, g~unit_price
FROM {{p}}gdsale AS s
INNER JOIN {{p}}goods AS g ON g~goods_id = s~goods_id
WHERE s~sale_state = 'P'
AND s~sale_day = @iv_day
AND g~grp_code IN @it_grp
INTO TABLE @lt_rows.
DATA lt_totals TYPE HASHED TABLE OF ty_line WITH UNIQUE KEY grp_code.
LOOP AT lt_rows INTO DATA(ls_row).
ASSIGN lt_totals[ grp_code = ls_row-grp_code ] TO FIELD-SYMBOL(<ls_total>).
IF sy-subrc <> 0.
INSERT VALUE #( grp_code = ls_row-grp_code ) INTO TABLE lt_totals ASSIGNING <ls_total>.
ENDIF.
<ls_total>-sales = <ls_total>-sales + 1.
<ls_total>-turnover = <ls_total>-turnover + ls_row-qty * ls_row-unit_price.
ENDLOOP.
rt_lines = CORRESPONDING #( lt_totals ).
set_shares( CHANGING ct_lines = rt_lines ).
SORT rt_lines BY turnover DESCENDING.
ENDMETHOD.
METHOD set_shares.
DATA lv_total TYPE {{p}}goods-unit_price.
LOOP AT ct_lines INTO DATA(ls_line).
lv_total = lv_total + ls_line-turnover.
ENDLOOP.
IF lv_total = 0.
RETURN.
ENDIF.
LOOP AT ct_lines ASSIGNING FIELD-SYMBOL(<ls_line>).
<ls_line>-pct_share = <ls_line>-turnover * 100 / lv_total.
ENDLOOP.
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(lo_report) = NEW lcl_shop_report( ).
DATA(lt_lines) = lo_report->get_totals( iv_day = p_day it_grp = s_grp[] ).
lo_report->display( CHANGING ct_lines = lt_lines ).
CLASS ltc_shop_report DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
TYPES ty_share TYPE p LENGTH 5 DECIMALS 1.
CLASS-DATA go_env TYPE REF TO if_osql_test_environment.
CLASS-METHODS class_setup.
CLASS-METHODS class_teardown.
METHODS totals_per_group FOR TESTING.
METHODS sorted_by_turnover FOR TESTING.
METHODS share_of_total FOR TESTING.
METHODS cancelled_ignored FOR TESTING.
ENDCLASS.
CLASS ltc_shop_report IMPLEMENTATION.
METHOD class_setup.
go_env = cl_osql_test_environment=>create(
i_dependency_list = VALUE #( ( '{{P}}GOODS' ) ( '{{P}}GDSALE' ) ) ).
DATA lt_goods TYPE STANDARD TABLE OF {{p}}goods WITH EMPTY KEY.
lt_goods = VALUE #( ( goods_id = 'G001' grp_code = 'VEG' unit_price = '2.50' )
( goods_id = 'G002' grp_code = 'VEG' unit_price = '3.00' )
( goods_id = 'G003' grp_code = 'FRU' unit_price = '4.00' )
( goods_id = 'G004' grp_code = 'DAI' unit_price = '5.00' )
( goods_id = 'G005' grp_code = 'DAI' unit_price = '1.50' ) ).
go_env->insert_test_data( lt_goods ).
DATA lt_sale TYPE STANDARD TABLE OF {{p}}gdsale WITH EMPTY KEY.
lt_sale = VALUE #( ( sale_id = 1 goods_id = 'G001' sale_day = '20260314' qty = 4 sale_state = 'P' )
( sale_id = 2 goods_id = 'G002' sale_day = '20260314' qty = 2 sale_state = 'P' )
( sale_id = 3 goods_id = 'G003' sale_day = '20260314' qty = 3 sale_state = 'P' )
( sale_id = 4 goods_id = 'G004' sale_day = '20260314' qty = 2 sale_state = 'P' )
( sale_id = 5 goods_id = 'G005' sale_day = '20260314' qty = 2 sale_state = 'P' )
( sale_id = 6 goods_id = 'G001' sale_day = '20260314' qty = 5 sale_state = 'C' ) ).
go_env->insert_test_data( lt_sale ).
ENDMETHOD.
METHOD class_teardown.
go_env->destroy( ).
ENDMETHOD.
METHOD totals_per_group.
DATA(lt_lines) = NEW lcl_shop_report( )->get_totals(
iv_day = '20260314' it_grp = VALUE #( ) ).
cl_abap_unit_assert=>assert_equals( exp = 3 act = lines( lt_lines ) ).
cl_abap_unit_assert=>assert_equals( exp = 'VEG' act = lt_lines[ 1 ]-grp_code ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_lines[ 1 ]-sales ).
cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}goods-unit_price( 16 )
act = lt_lines[ 1 ]-turnover ).
ENDMETHOD.
METHOD sorted_by_turnover.
DATA(lt_lines) = NEW lcl_shop_report( )->get_totals(
iv_day = '20260314' it_grp = VALUE #( ) ).
cl_abap_unit_assert=>assert_equals( exp = 'VEG' act = lt_lines[ 1 ]-grp_code ).
cl_abap_unit_assert=>assert_equals( exp = 'DAI' act = lt_lines[ 2 ]-grp_code ).
cl_abap_unit_assert=>assert_equals( exp = 'FRU' act = lt_lines[ 3 ]-grp_code ).
ENDMETHOD.
METHOD share_of_total.
DATA(lt_lines) = NEW lcl_shop_report( )->get_totals(
iv_day = '20260314' it_grp = VALUE #( ) ).
cl_abap_unit_assert=>assert_equals( exp = CONV ty_share( '39.0' )
act = lt_lines[ 1 ]-pct_share ).
cl_abap_unit_assert=>assert_equals( exp = CONV ty_share( '31.7' )
act = lt_lines[ 2 ]-pct_share ).
ENDMETHOD.
METHOD cancelled_ignored.
DATA(lt_lines) = NEW lcl_shop_report( )->get_totals(
iv_day = '20260314' it_grp = VALUE #( ( sign = 'I' option = 'EQ' low = 'VEG' ) ) ).
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_lines ) ).
cl_abap_unit_assert=>assert_equals( exp = 2 act = lt_lines[ 1 ]-sales ).
cl_abap_unit_assert=>assert_equals( exp = CONV {{p}}goods-unit_price( 16 )
act = lt_lines[ 1 ]-turnover ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,83 @@
REPORT {{p}}farm_shop_old.
DATA: BEGIN OF gt_sale OCCURS 0,
sale_id TYPE {{p}}gdsale-sale_id,
goods_id TYPE {{p}}gdsale-goods_id,
sale_day TYPE {{p}}gdsale-sale_day,
qty TYPE {{p}}gdsale-qty,
sale_state TYPE {{p}}gdsale-sale_state,
grp_code TYPE {{p}}goods-grp_code,
unit_price TYPE {{p}}goods-unit_price,
END OF gt_sale.
DATA: BEGIN OF gt_out OCCURS 0,
grp_code TYPE {{p}}goods-grp_code,
sales TYPE i,
turnover TYPE {{p}}goods-unit_price,
pct_share TYPE p LENGTH 5 DECIMALS 1,
END OF gt_out.
DATA: gv_total TYPE {{p}}goods-unit_price,
go_alv TYPE REF TO cl_salv_table.
PARAMETERS p_day TYPE d OBLIGATORY.
SELECT-OPTIONS s_grp FOR {{p}}goods-grp_code.
START-OF-SELECTION.
PERFORM read_data.
PERFORM calc_totals.
PERFORM show_list.
FORM read_data.
SELECT * FROM {{p}}gdsale INTO CORRESPONDING FIELDS OF TABLE gt_sale
WHERE sale_state = 'P'
AND sale_day = p_day.
LOOP AT gt_sale.
SELECT SINGLE grp_code unit_price FROM {{p}}goods
INTO (gt_sale-grp_code, gt_sale-unit_price)
WHERE goods_id = gt_sale-goods_id.
ENDLOOP.
DELETE gt_sale WHERE grp_code IS INITIAL.
IF s_grp IS NOT INITIAL.
DELETE gt_sale WHERE grp_code NOT IN s_grp.
ENDIF.
SORT gt_sale BY grp_code.
ENDFORM.
FORM calc_totals.
LOOP AT gt_sale.
AT NEW grp_code.
CLEAR gt_out.
gt_out-grp_code = gt_sale-grp_code.
ENDAT.
gt_out-sales = gt_out-sales + 1.
gt_out-turnover = gt_out-turnover + gt_sale-qty * gt_sale-unit_price.
AT END OF grp_code.
APPEND gt_out.
ENDAT.
ENDLOOP.
CLEAR gv_total.
LOOP AT gt_out.
gv_total = gv_total + gt_out-turnover.
ENDLOOP.
IF gv_total <> 0.
LOOP AT gt_out.
gt_out-pct_share = gt_out-turnover * 100 / gv_total.
MODIFY gt_out.
ENDLOOP.
ENDIF.
SORT gt_out BY turnover DESCENDING.
ENDFORM.
FORM show_list.
TRY.
cl_salv_table=>factory(
IMPORTING r_salv_table = go_alv
CHANGING t_table = gt_out[] ).
go_alv->display( ).
CATCH cx_salv_msg.
ENDTRY.
ENDFORM.

View File

@@ -0,0 +1,13 @@
@EndUserText.label : 'Farm shop sale'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}gdsale {
key client : abap.clnt not null;
key sale_id : abap.int4 not null;
goods_id : abap.char(4);
sale_day : abap.dats;
qty : abap.int2;
sale_state : abap.char(1);
}

View File

@@ -0,0 +1,11 @@
@EndUserText.label : 'Farm shop goods'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table {{p}}goods {
key client : abap.clnt not null;
key goods_id : abap.char(4) not null;
grp_code : abap.char(4);
unit_price : abap.dec(15,2);
}

View File

@@ -0,0 +1,31 @@
CLASS {{p}}shop_seed DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
ENDCLASS.
CLASS {{p}}shop_seed IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DELETE FROM {{p}}gdsale.
DELETE FROM {{p}}goods.
INSERT {{p}}goods FROM TABLE @( VALUE #(
( goods_id = 'G001' grp_code = 'VEG' unit_price = '2.50' )
( goods_id = 'G002' grp_code = 'VEG' unit_price = '3.00' )
( goods_id = 'G003' grp_code = 'FRU' unit_price = '4.00' )
( goods_id = 'G004' grp_code = 'DAI' unit_price = '5.00' )
( goods_id = 'G005' grp_code = 'DAI' unit_price = '1.50' )
( goods_id = 'G006' grp_code = 'BAK' unit_price = '2.00' ) ) ).
INSERT {{p}}gdsale FROM TABLE @( VALUE #(
( sale_id = 1 goods_id = 'G001' sale_day = '20260314' qty = 4 sale_state = 'P' )
( sale_id = 2 goods_id = 'G002' sale_day = '20260314' qty = 2 sale_state = 'P' )
( sale_id = 3 goods_id = 'G003' sale_day = '20260314' qty = 3 sale_state = 'P' )
( sale_id = 4 goods_id = 'G004' sale_day = '20260314' qty = 2 sale_state = 'P' )
( sale_id = 5 goods_id = 'G005' sale_day = '20260314' qty = 2 sale_state = 'P' )
( sale_id = 6 goods_id = 'G001' sale_day = '20260314' qty = 5 sale_state = 'C' )
( sale_id = 7 goods_id = 'G003' sale_day = '20260313' qty = 1 sale_state = 'P' )
( sale_id = 8 goods_id = 'G006' sale_day = '20260313' qty = 3 sale_state = 'P' ) ) ).
out->write( sy-dbcnt ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,47 @@
# 1. Goal
The farm shop of a cooperative sells its own vegetables, fruit and dairy goods.
The report {{P}}FARM_SHOP_OLD shows the turnover of one day, grouped by product
group. The report is in production, but its code is outdated and hard to
maintain. Refactor the report in place: same name, same selection screen, same
output. The behavior stays the same.
# 2. Open questions
None.
# 3. Context
- {{P}}FARM_SHOP_OLD is an executable program in package $TMP. It is active.
- The report reads the tables {{P}}GOODS and {{P}}GDSALE. Both tables are in
package $TMP and contain data.
- {{P}}GOODS: GOODS_ID (CHAR 4, key), GRP_CODE (CHAR 4), UNIT_PRICE (DEC 15,2).
- {{P}}GDSALE: SALE_ID (INT4, key), GOODS_ID (CHAR 4), SALE_DAY (DATS),
QTY (INT2), SALE_STATE (CHAR 1).
- The report writes the result with CL_SALV_TABLE.
- The legacy implementation is the only specification of the rules. Read it.
# 4. Contract
- The program {{P}}FARM_SHOP_OLD stays in package $TMP. Do not rename it.
- The selection screen stays the same:
- Parameter P_DAY, type DATS, mandatory.
- Select-option S_GRP for the product group.
- The ALV list keeps these columns, with these names:
GRP_CODE, SALES, TURNOVER, PCT_SHARE.
# 5. Business rules
The behavior of the report stays the same. The legacy code is the only
specification. Keep every result exactly as it is today: the same rows, the
same values, the same order, the same filters.
# 6. Constraints
- Release target: 8.16 (SAP_BASIS 816, ABAP Platform 2025).
- Coding standards: Clean ABAP. Methods below 40 statements. No obsolete
language elements. No database access inside a loop. No header-line tables.
Never mix old and new ABAP SQL syntax in one statement.
- Out of scope: do not change {{P}}GOODS and {{P}}GDSALE. Do not change the
selection screen. Do not change the names of the output columns.
# 7. Acceptance
- {{P}}FARM_SHOP_OLD is active and has no syntax error.
- The behavior of the report is unchanged.
- The hidden tests pass.
- ATC reports no finding of priority 1 or 2.
- Write ABAP Unit tests as local test classes in the program.

View File

@@ -0,0 +1,73 @@
{
"id": "G1102",
"category": "E",
"object_type": "PROG",
"difficulty": 2,
"release_target": "v816",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 60,
"max_activations": 15
},
"seed": [
{
"type": "TABL",
"name": "{{P}}GOODS",
"file": "seed/goods.tabl.asabap",
"description": "Farm shop goods"
},
{
"type": "TABL",
"name": "{{P}}GDSALE",
"file": "seed/gdsale.tabl.asabap",
"description": "Farm shop sales"
},
{
"type": "CLAS",
"name": "{{P}}SHOP_SEED",
"file": "seed/shop_seed.clas.abap",
"description": "Seed data for goods and sales",
"run": true
},
{
"type": "PROG",
"name": "{{P}}FARM_SHOP_OLD",
"file": "seed/farm_shop_old.prog.abap",
"description": "Legacy report with old code"
}
],
"contract": [
{
"type": "PROG",
"name": "{{P}}FARM_SHOP_OLD",
"parameters": [
"p_day",
"s_grp"
]
}
],
"out_of_scope": [
"{{P}}GOODS",
"{{P}}GDSALE"
],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}SHOP_HIDDEN",
"file": "hidden/shop_hidden.clas.abap",
"description": "Hidden tests for the unchanged behavior"
}
],
"reference": [
{
"type": "PROG",
"name": "{{P}}FARM_SHOP_OLD",
"file": "reference/farm_shop_old.prog.abap",
"description": "Refactored report with local test classes"
}
],
"craft_checks": [
"db_operation_in_loop",
"method_length"
]
}