Generator: pilot analysis and fixes; G0002-G0021 tasks; handover notes merged
- Static bundle checks (name length, seed type, reserved words, contract test classes, testclasses_file), local abaplint parser check before SAP, max_tokens, robust JSON parse - Runner: G2 for CDS views with parameters, contract_check detail in report - G0020 and G0013 fixed by review and revalidated (oracle 100, null 0) - Pilot results in docs/faz1-tasarim.md 11e; handover notes merged into CLAUDE.md and docs Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
29
tasks_gen/eval/G0003/generation.json
Normal file
29
tasks_gen/eval/G0003/generation.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"id": "G0003",
|
||||
"pool": "eval",
|
||||
"object_type": "CLAS",
|
||||
"category": "B",
|
||||
"attempts": [
|
||||
{
|
||||
"stage": "validate",
|
||||
"oracle": null,
|
||||
"null": null
|
||||
},
|
||||
{
|
||||
"stage": "validate",
|
||||
"oracle": null,
|
||||
"null": null
|
||||
},
|
||||
{
|
||||
"stage": "validate",
|
||||
"oracle": 0,
|
||||
"null": 0
|
||||
},
|
||||
{
|
||||
"stage": "validate",
|
||||
"oracle": 100.0,
|
||||
"null": 0
|
||||
}
|
||||
],
|
||||
"accepted": true
|
||||
}
|
||||
119
tasks_gen/eval/G0003/hidden/t02_hidden.clas.abap
Normal file
119
tasks_gen/eval/G0003/hidden/t02_hidden.clas.abap
Normal file
@@ -0,0 +1,119 @@
|
||||
CLASS {{P}}T02_HIDDEN DEFINITION PUBLIC FINAL CREATE PUBLIC
|
||||
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
|
||||
PRIVATE SECTION.
|
||||
CLASS-DATA mo_environment TYPE REF TO if_osql_test_environment.
|
||||
DATA mo_cut TYPE REF TO {{P}}COURSE_BOOKING.
|
||||
|
||||
CLASS-METHODS class_setup.
|
||||
CLASS-METHODS class_teardown.
|
||||
METHODS setup.
|
||||
METHODS fill_test_data.
|
||||
|
||||
METHODS free_seats_open_course FOR TESTING.
|
||||
METHODS free_seats_never_neg FOR TESTING.
|
||||
METHODS free_seats_unknown FOR TESTING.
|
||||
METHODS bookable_exact_free FOR TESTING.
|
||||
METHODS not_bookable_too_many FOR TESTING.
|
||||
METHODS not_bookable_unknown FOR TESTING.
|
||||
METHODS not_bookable_zero_seats FOR TESTING.
|
||||
METHODS list_filter_cat_seats FOR TESTING.
|
||||
METHODS list_sorted_by_course FOR TESTING.
|
||||
METHODS list_empty_without_match FOR TESTING.
|
||||
METHODS list_excludes_full FOR TESTING.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{P}}T02_HIDDEN IMPLEMENTATION.
|
||||
METHOD class_setup.
|
||||
mo_environment = cl_osql_test_environment=>create( VALUE #( ( '{{P}}COURSE' ) ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD class_teardown.
|
||||
mo_environment->destroy( ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD setup.
|
||||
mo_environment->clear_doubles( ).
|
||||
fill_test_data( ).
|
||||
mo_cut = NEW {{P}}COURSE_BOOKING( ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD fill_test_data.
|
||||
DATA lt_course TYPE STANDARD TABLE OF {{P}}COURSE WITH EMPTY KEY.
|
||||
lt_course = VALUE #(
|
||||
( mandt = sy-mandt course_id = 'ABAP101' category = 'IT' title = 'ABAP Basics' capacity = 20 booked = 5 )
|
||||
( mandt = sy-mandt course_id = 'ABAP102' category = 'IT' title = 'ABAP Advanced' capacity = 10 booked = 10 )
|
||||
( mandt = sy-mandt course_id = 'ABAP103' category = 'IT' title = 'ABAP Expert' capacity = 12 booked = 15 )
|
||||
( mandt = sy-mandt course_id = 'SQL101' category = 'DB' title = 'SQL Basics' capacity = 30 booked = 10 )
|
||||
( mandt = sy-mandt course_id = 'SQL102' category = 'DB' title = 'SQL Tuning' capacity = 8 booked = 8 )
|
||||
( mandt = sy-mandt course_id = 'HR101' category = 'HR' title = 'HR Basics' capacity = 6 booked = 1 ) ).
|
||||
INSERT {{P}}COURSE FROM TABLE @lt_course.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD free_seats_open_course.
|
||||
cl_abap_unit_assert=>assert_equals( exp = 15
|
||||
act = mo_cut->get_free_seats( 'ABAP101' )
|
||||
msg = 'ABAP101 must have 15 free seats' ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD free_seats_never_neg.
|
||||
cl_abap_unit_assert=>assert_equals( exp = 0
|
||||
act = mo_cut->get_free_seats( 'ABAP102' )
|
||||
msg = 'full course' ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 0
|
||||
act = mo_cut->get_free_seats( 'ABAP103' )
|
||||
msg = 'overbooked course' ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD free_seats_unknown.
|
||||
cl_abap_unit_assert=>assert_equals( exp = 0
|
||||
act = mo_cut->get_free_seats( 'XX999' ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD bookable_exact_free.
|
||||
cl_abap_unit_assert=>assert_true( mo_cut->is_bookable( iv_course_id = 'SQL101' iv_seats = 20 ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD not_bookable_too_many.
|
||||
cl_abap_unit_assert=>assert_false( mo_cut->is_bookable( iv_course_id = 'SQL101' iv_seats = 21 ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD not_bookable_unknown.
|
||||
cl_abap_unit_assert=>assert_false( mo_cut->is_bookable( iv_course_id = 'XX999' iv_seats = 1 ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD not_bookable_zero_seats.
|
||||
cl_abap_unit_assert=>assert_false( mo_cut->is_bookable( iv_course_id = 'SQL101' iv_seats = 0 ) ).
|
||||
cl_abap_unit_assert=>assert_false( mo_cut->is_bookable( iv_course_id = 'SQL101' iv_seats = -5 ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD list_filter_cat_seats.
|
||||
DATA(lt_result) = mo_cut->list_bookable_courses( iv_category = 'DB' iv_seats = 5 ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_result ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 'SQL101' act = lt_result[ 1 ]-course_id ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 'SQL Basics' act = lt_result[ 1 ]-title ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 20 act = lt_result[ 1 ]-free_seats ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD list_sorted_by_course.
|
||||
DATA(lt_result) = mo_cut->list_bookable_courses( iv_category = 'IT' iv_seats = 0 ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 3 act = lines( lt_result ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 'ABAP101' act = lt_result[ 1 ]-course_id ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 'ABAP102' act = lt_result[ 2 ]-course_id ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 'ABAP103' act = lt_result[ 3 ]-course_id ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 0 act = lt_result[ 3 ]-free_seats ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD list_empty_without_match.
|
||||
DATA(lt_hr) = mo_cut->list_bookable_courses( iv_category = 'HR' iv_seats = 6 ).
|
||||
cl_abap_unit_assert=>assert_initial( lt_hr ).
|
||||
DATA(lt_unknown) = mo_cut->list_bookable_courses( iv_category = 'XX' iv_seats = 1 ).
|
||||
cl_abap_unit_assert=>assert_initial( lt_unknown ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD list_excludes_full.
|
||||
DATA(lt_result) = mo_cut->list_bookable_courses( iv_category = 'IT' iv_seats = 1 ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_result ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 'ABAP101' act = lt_result[ 1 ]-course_id ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
94
tasks_gen/eval/G0003/reference/course_booking.clas.abap
Normal file
94
tasks_gen/eval/G0003/reference/course_booking.clas.abap
Normal file
@@ -0,0 +1,94 @@
|
||||
CLASS {{P}}COURSE_BOOKING DEFINITION PUBLIC FINAL CREATE PUBLIC.
|
||||
PUBLIC SECTION.
|
||||
TYPES ty_course_id TYPE c LENGTH 10.
|
||||
TYPES ty_category TYPE c LENGTH 10.
|
||||
TYPES:
|
||||
BEGIN OF ty_course_info,
|
||||
course_id TYPE ty_course_id,
|
||||
title TYPE c LENGTH 40,
|
||||
free_seats TYPE i,
|
||||
END OF ty_course_info.
|
||||
TYPES tt_course_info TYPE STANDARD TABLE OF ty_course_info WITH EMPTY KEY.
|
||||
|
||||
METHODS get_free_seats
|
||||
IMPORTING iv_course_id TYPE ty_course_id
|
||||
RETURNING VALUE(rv_free_seats) TYPE i.
|
||||
|
||||
METHODS is_bookable
|
||||
IMPORTING iv_course_id TYPE ty_course_id
|
||||
iv_seats TYPE i
|
||||
RETURNING VALUE(rv_bookable) TYPE abap_bool.
|
||||
|
||||
METHODS list_bookable_courses
|
||||
IMPORTING iv_category TYPE ty_category
|
||||
iv_seats TYPE i
|
||||
RETURNING VALUE(rt_courses) TYPE tt_course_info.
|
||||
|
||||
PRIVATE SECTION.
|
||||
TYPES:
|
||||
BEGIN OF ty_course,
|
||||
course_id TYPE ty_course_id,
|
||||
title TYPE c LENGTH 40,
|
||||
capacity TYPE i,
|
||||
booked TYPE i,
|
||||
END OF ty_course.
|
||||
|
||||
METHODS read_course
|
||||
IMPORTING iv_course_id TYPE ty_course_id
|
||||
RETURNING VALUE(rs_course) TYPE ty_course.
|
||||
|
||||
METHODS calculate_free_seats
|
||||
IMPORTING is_course TYPE ty_course
|
||||
RETURNING VALUE(rv_free) TYPE i.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{P}}COURSE_BOOKING IMPLEMENTATION.
|
||||
METHOD get_free_seats.
|
||||
rv_free_seats = calculate_free_seats( read_course( iv_course_id ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD is_bookable.
|
||||
IF iv_seats < 1.
|
||||
rv_bookable = abap_false.
|
||||
RETURN.
|
||||
ENDIF.
|
||||
rv_bookable = xsdbool( iv_seats <= calculate_free_seats( read_course( iv_course_id ) ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD list_bookable_courses.
|
||||
DATA lt_course TYPE STANDARD TABLE OF ty_course WITH EMPTY KEY.
|
||||
|
||||
SELECT course_id, title, capacity, booked
|
||||
FROM {{P}}COURSE
|
||||
WHERE category = @iv_category
|
||||
INTO TABLE @lt_course.
|
||||
|
||||
LOOP AT lt_course INTO DATA(ls_course).
|
||||
DATA(lv_free) = calculate_free_seats( ls_course ).
|
||||
IF lv_free < iv_seats.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
rt_courses = VALUE #( BASE rt_courses
|
||||
( course_id = ls_course-course_id
|
||||
title = ls_course-title
|
||||
free_seats = lv_free ) ).
|
||||
ENDLOOP.
|
||||
|
||||
SORT rt_courses BY course_id.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD read_course.
|
||||
SELECT SINGLE course_id, title, capacity, booked
|
||||
FROM {{P}}COURSE
|
||||
WHERE course_id = @iv_course_id
|
||||
INTO @rs_course.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD calculate_free_seats.
|
||||
rv_free = is_course-capacity - is_course-booked.
|
||||
IF rv_free < 0.
|
||||
rv_free = 0.
|
||||
ENDIF.
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
@@ -0,0 +1,63 @@
|
||||
CLASS ltc_course_booking DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
|
||||
PRIVATE SECTION.
|
||||
CLASS-DATA mo_environment TYPE REF TO if_osql_test_environment.
|
||||
DATA mo_cut TYPE REF TO {{P}}COURSE_BOOKING.
|
||||
|
||||
CLASS-METHODS class_setup.
|
||||
CLASS-METHODS class_teardown.
|
||||
METHODS setup.
|
||||
METHODS fill_test_data.
|
||||
|
||||
METHODS free_seats_open_course FOR TESTING.
|
||||
METHODS free_seats_full_course FOR TESTING.
|
||||
METHODS bookable_enough_seats FOR TESTING.
|
||||
METHODS not_bookable_full FOR TESTING.
|
||||
METHODS list_matching_courses FOR TESTING.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS ltc_course_booking IMPLEMENTATION.
|
||||
METHOD class_setup.
|
||||
mo_environment = cl_osql_test_environment=>create( VALUE #( ( '{{P}}COURSE' ) ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD class_teardown.
|
||||
mo_environment->destroy( ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD setup.
|
||||
mo_environment->clear_doubles( ).
|
||||
fill_test_data( ).
|
||||
mo_cut = NEW {{P}}COURSE_BOOKING( ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD fill_test_data.
|
||||
DATA lt_course TYPE STANDARD TABLE OF {{P}}COURSE WITH EMPTY KEY.
|
||||
lt_course = VALUE #(
|
||||
( mandt = sy-mandt course_id = 'ABAP101' category = 'IT' title = 'ABAP Basics' capacity = 20 booked = 5 )
|
||||
( mandt = sy-mandt course_id = 'SQL101' category = 'DB' title = 'SQL Basics' capacity = 30 booked = 30 ) ).
|
||||
INSERT {{P}}COURSE FROM TABLE @lt_course.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD free_seats_open_course.
|
||||
cl_abap_unit_assert=>assert_equals( exp = 15 act = mo_cut->get_free_seats( 'ABAP101' ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD free_seats_full_course.
|
||||
cl_abap_unit_assert=>assert_equals( exp = 0 act = mo_cut->get_free_seats( 'SQL101' ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD bookable_enough_seats.
|
||||
cl_abap_unit_assert=>assert_true( mo_cut->is_bookable( iv_course_id = 'ABAP101' iv_seats = 10 ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD not_bookable_full.
|
||||
cl_abap_unit_assert=>assert_false( mo_cut->is_bookable( iv_course_id = 'SQL101' iv_seats = 1 ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD list_matching_courses.
|
||||
DATA(lt_result) = mo_cut->list_bookable_courses( iv_category = 'IT' iv_seats = 1 ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_result ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 'ABAP101' act = lt_result[ 1 ]-course_id ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
8
tasks_gen/eval/G0003/seed/course.ddls.abap
Normal file
8
tasks_gen/eval/G0003/seed/course.ddls.abap
Normal file
@@ -0,0 +1,8 @@
|
||||
define table {{P}}COURSE {
|
||||
key mandt : abap.clnt not null;
|
||||
key course_id : abap.char(10) not null;
|
||||
category : abap.char(10);
|
||||
title : abap.char(40);
|
||||
capacity : abap.int4;
|
||||
booked : abap.int4;
|
||||
}
|
||||
9
tasks_gen/eval/G0003/seed/course.ddls.asddls
Normal file
9
tasks_gen/eval/G0003/seed/course.ddls.asddls
Normal file
@@ -0,0 +1,9 @@
|
||||
@EndUserText.label : 'Training courses'
|
||||
define table {{P}}COURSE {
|
||||
key mandt : abap.clnt not null;
|
||||
key course_id : abap.char(10) not null;
|
||||
category : abap.char(10);
|
||||
title : abap.char(40);
|
||||
capacity : abap.int4;
|
||||
booked : abap.int4;
|
||||
}
|
||||
13
tasks_gen/eval/G0003/seed/course.tabl.asddls
Normal file
13
tasks_gen/eval/G0003/seed/course.tabl.asddls
Normal file
@@ -0,0 +1,13 @@
|
||||
@EndUserText.label : 'Training courses'
|
||||
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
|
||||
@AbapCatalog.tableCategory : #TRANSPARENT
|
||||
@AbapCatalog.deliveryClass : #A
|
||||
@AbapCatalog.dataMaintenance : #RESTRICTED
|
||||
define table {{P}}COURSE {
|
||||
key mandt : abap.clnt not null;
|
||||
key course_id : abap.char(10) not null;
|
||||
category : abap.char(10);
|
||||
title : abap.char(40);
|
||||
capacity : abap.int4;
|
||||
booked : abap.int4;
|
||||
}
|
||||
24
tasks_gen/eval/G0003/seed/seed_courses.clas.abap
Normal file
24
tasks_gen/eval/G0003/seed/seed_courses.clas.abap
Normal file
@@ -0,0 +1,24 @@
|
||||
CLASS {{P}}SEED_COURSES DEFINITION PUBLIC FINAL CREATE PUBLIC.
|
||||
PUBLIC SECTION.
|
||||
INTERFACES if_oo_adt_classrun.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{P}}SEED_COURSES IMPLEMENTATION.
|
||||
METHOD if_oo_adt_classrun~main.
|
||||
DELETE FROM {{P}}COURSE.
|
||||
|
||||
DATA lt_course TYPE STANDARD TABLE OF {{P}}COURSE WITH EMPTY KEY.
|
||||
lt_course = VALUE #(
|
||||
( mandt = sy-mandt course_id = 'ABAP101' category = 'IT' title = 'ABAP Basics' capacity = 20 booked = 5 )
|
||||
( mandt = sy-mandt course_id = 'ABAP102' category = 'IT' title = 'ABAP Advanced' capacity = 10 booked = 10 )
|
||||
( mandt = sy-mandt course_id = 'ABAP103' category = 'IT' title = 'ABAP Expert' capacity = 12 booked = 15 )
|
||||
( mandt = sy-mandt course_id = 'SQL101' category = 'DB' title = 'SQL Basics' capacity = 30 booked = 10 )
|
||||
( mandt = sy-mandt course_id = 'SQL102' category = 'DB' title = 'SQL Tuning' capacity = 8 booked = 8 )
|
||||
( mandt = sy-mandt course_id = 'HR101' category = 'HR' title = 'HR Basics' capacity = 6 booked = 1 ) ).
|
||||
|
||||
INSERT {{P}}COURSE FROM TABLE @lt_course.
|
||||
|
||||
out->write( |Courses written: { sy-dbcnt }| ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
68
tasks_gen/eval/G0003/spec.md
Normal file
68
tasks_gen/eval/G0003/spec.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# 1. Goal
|
||||
A training provider sells seats in courses. The booking program needs one service that
|
||||
answers three questions:
|
||||
- How many seats are free in a course?
|
||||
- Can we book a given number of seats in a course?
|
||||
- Which courses of a category still have enough free seats?
|
||||
|
||||
# 2. Open questions
|
||||
None.
|
||||
|
||||
# 3. Context
|
||||
- The database table {{P}}COURSE exists in package $TMP. It has these columns:
|
||||
MANDT (client), COURSE_ID (CHAR 10, key), CATEGORY (CHAR 10), TITLE (CHAR 40),
|
||||
CAPACITY (INT4), BOOKED (INT4).
|
||||
- CAPACITY is the number of seats of the course. BOOKED is the number of seats that
|
||||
are already sold.
|
||||
- The class {{P}}SEED_COURSES fills the table with example data. It is active.
|
||||
|
||||
# 4. Contract
|
||||
- Create the class {{P}}COURSE_BOOKING in package $TMP.
|
||||
- The class is public, final, and has a public constructor without parameters.
|
||||
- The class has these public types:
|
||||
- TY_COURSE_ID, type C, length 10.
|
||||
- TY_CATEGORY, type C, length 10.
|
||||
- TY_COURSE_INFO, a structure with the components COURSE_ID (type TY_COURSE_ID),
|
||||
TITLE (type C, length 40) and FREE_SEATS (type I).
|
||||
- TT_COURSE_INFO, a standard table of TY_COURSE_INFO with an empty key.
|
||||
- The class has these public methods:
|
||||
- GET_FREE_SEATS, importing IV_COURSE_ID type TY_COURSE_ID,
|
||||
returning RV_FREE_SEATS type I.
|
||||
- IS_BOOKABLE, importing IV_COURSE_ID type TY_COURSE_ID and IV_SEATS type I,
|
||||
returning RV_BOOKABLE type ABAP_BOOL.
|
||||
- LIST_BOOKABLE_COURSES, importing IV_CATEGORY type TY_CATEGORY and IV_SEATS type I,
|
||||
returning RT_COURSES type TT_COURSE_INFO.
|
||||
- Do not add other public methods.
|
||||
|
||||
# 5. Business rules
|
||||
Free seats
|
||||
1. Read the course with the course ID.
|
||||
2. If the table has no course with this ID, the free seats are 0.
|
||||
3. The free seats are the capacity minus the booked seats.
|
||||
4. If the capacity minus the booked seats is less than 0, the free seats are 0.
|
||||
|
||||
GET_FREE_SEATS returns the free seats of the course.
|
||||
|
||||
IS_BOOKABLE
|
||||
5. If IV_SEATS is less than 1, the result is false.
|
||||
6. If the table has no course with this ID, the result is false.
|
||||
7. The result is true if IV_SEATS is less than or equal to the free seats of the
|
||||
course. Else the result is false.
|
||||
|
||||
LIST_BOOKABLE_COURSES
|
||||
8. Read all courses with the category IV_CATEGORY.
|
||||
9. Use only the courses whose free seats are greater than or equal to IV_SEATS.
|
||||
10. Sort the result in ascending order by COURSE_ID.
|
||||
11. Each result row has the COURSE_ID, the TITLE and the free seats of the course.
|
||||
12. If no course matches, the result is empty.
|
||||
|
||||
# 6. Constraints
|
||||
- Release target: 8.16.
|
||||
- Coding standards: Clean ABAP. Method length below 40 statements. No global variables.
|
||||
No comment that restates the code.
|
||||
- Out of scope: do not change the table {{P}}COURSE and the class {{P}}SEED_COURSES.
|
||||
|
||||
# 7. Acceptance
|
||||
- The class is active and has no syntax error.
|
||||
- The hidden tests pass.
|
||||
- Write your own ABAP Unit tests for the class.
|
||||
58
tasks_gen/eval/G0003/task.json
Normal file
58
tasks_gen/eval/G0003/task.json
Normal file
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"id": "G0003",
|
||||
"category": "B",
|
||||
"object_type": "CLAS",
|
||||
"difficulty": 2,
|
||||
"release_target": "v816",
|
||||
"expected_outcome": "implement",
|
||||
"budget": {
|
||||
"max_tool_calls": 60,
|
||||
"max_activations": 15
|
||||
},
|
||||
"seed": [
|
||||
{
|
||||
"type": "TABL",
|
||||
"name": "{{P}}COURSE",
|
||||
"file": "seed/course.tabl.asddls",
|
||||
"description": "Training course table with capacity and booked seats"
|
||||
},
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}SEED_COURSES",
|
||||
"file": "seed/seed_courses.clas.abap",
|
||||
"description": "Fills the course table with example data",
|
||||
"run": true
|
||||
}
|
||||
],
|
||||
"contract": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}COURSE_BOOKING"
|
||||
}
|
||||
],
|
||||
"out_of_scope": [
|
||||
"{{P}}COURSE",
|
||||
"{{P}}SEED_COURSES"
|
||||
],
|
||||
"hidden_tests": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}T02_HIDDEN",
|
||||
"file": "hidden/t02_hidden.clas.abap",
|
||||
"description": "T02 hidden tests"
|
||||
}
|
||||
],
|
||||
"reference": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}COURSE_BOOKING",
|
||||
"file": "reference/course_booking.clas.abap",
|
||||
"description": "Course booking service",
|
||||
"testclasses_file": "reference/course_booking.testclasses.abap"
|
||||
}
|
||||
],
|
||||
"craft_checks": [
|
||||
"method_length",
|
||||
"db_operation_in_loop"
|
||||
]
|
||||
}
|
||||
14
tasks_gen/eval/G0004/generation.json
Normal file
14
tasks_gen/eval/G0004/generation.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"id": "G0004",
|
||||
"pool": "eval",
|
||||
"object_type": "CLAS",
|
||||
"category": "C",
|
||||
"attempts": [
|
||||
{
|
||||
"stage": "validate",
|
||||
"oracle": 100.0,
|
||||
"null": 0
|
||||
}
|
||||
],
|
||||
"accepted": true
|
||||
}
|
||||
207
tasks_gen/eval/G0004/hidden/stock_age_hidden.clas.abap
Normal file
207
tasks_gen/eval/G0004/hidden/stock_age_hidden.clas.abap
Normal file
@@ -0,0 +1,207 @@
|
||||
CLASS {{p}}stock_age_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
|
||||
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
|
||||
PRIVATE SECTION.
|
||||
CONSTANTS c_key_date TYPE dats VALUE '20240401'.
|
||||
|
||||
DATA mo_cut TYPE REF TO {{p}}if_stock_age.
|
||||
|
||||
METHODS setup.
|
||||
METHODS gr_date_for_age
|
||||
IMPORTING iv_age TYPE i
|
||||
RETURNING VALUE(rv_date) TYPE dats.
|
||||
|
||||
METHODS empty_input FOR TESTING.
|
||||
METHODS single_batch_bucket_01 FOR TESTING.
|
||||
METHODS bucket_boundaries FOR TESTING.
|
||||
METHODS groups_sum_quantity_and_count FOR TESTING.
|
||||
METHODS result_is_sorted FOR TESTING.
|
||||
METHODS invalid_rows_are_ignored FOR TESTING.
|
||||
METHODS negative_and_zero_quantity FOR TESTING.
|
||||
METHODS total_groups_by_material FOR TESTING.
|
||||
METHODS total_is_sorted FOR TESTING.
|
||||
METHODS total_ignores_invalid_rows FOR TESTING.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}stock_age_hidden IMPLEMENTATION.
|
||||
|
||||
METHOD setup.
|
||||
mo_cut = NEW {{p}}stock_age( ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD gr_date_for_age.
|
||||
rv_date = c_key_date - iv_age.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD empty_input.
|
||||
DATA(lt_result) = mo_cut->analyze(
|
||||
it_batch = VALUE {{p}}if_stock_age=>tt_batch( )
|
||||
iv_key_date = c_key_date ).
|
||||
|
||||
cl_abap_unit_assert=>assert_initial( act = lt_result ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD single_batch_bucket_01.
|
||||
DATA(lt_result) = mo_cut->analyze(
|
||||
it_batch = VALUE {{p}}if_stock_age=>tt_batch(
|
||||
( material = 'MAT-1' batch = 'B1' quantity = 10
|
||||
gr_date = gr_date_for_age( 0 ) ) )
|
||||
iv_key_date = c_key_date ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals( act = lines( lt_result ) exp = 1 ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 1 ]-material
|
||||
exp = 'MAT-1' ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 1 ]-bucket
|
||||
exp = {{p}}if_stock_age=>c_bucket-d0_30 ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 1 ]-quantity exp = 10 ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 1 ]-batch_count exp = 1 ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD bucket_boundaries.
|
||||
DATA(lt_result) = mo_cut->analyze(
|
||||
it_batch = VALUE {{p}}if_stock_age=>tt_batch(
|
||||
( material = 'MAT-B' batch = 'B1' quantity = 1 gr_date = gr_date_for_age( 30 ) )
|
||||
( material = 'MAT-B' batch = 'B2' quantity = 1 gr_date = gr_date_for_age( 31 ) )
|
||||
( material = 'MAT-B' batch = 'B3' quantity = 1 gr_date = gr_date_for_age( 60 ) )
|
||||
( material = 'MAT-B' batch = 'B4' quantity = 1 gr_date = gr_date_for_age( 61 ) )
|
||||
( material = 'MAT-B' batch = 'B5' quantity = 1 gr_date = gr_date_for_age( 90 ) )
|
||||
( material = 'MAT-B' batch = 'B6' quantity = 1 gr_date = gr_date_for_age( 91 ) ) )
|
||||
iv_key_date = c_key_date ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals( act = lines( lt_result ) exp = 4 ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 1 ]-bucket
|
||||
exp = {{p}}if_stock_age=>c_bucket-d0_30 ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 1 ]-batch_count exp = 1 ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 2 ]-bucket
|
||||
exp = {{p}}if_stock_age=>c_bucket-d31_60 ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 2 ]-batch_count exp = 2 ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 3 ]-bucket
|
||||
exp = {{p}}if_stock_age=>c_bucket-d61_90 ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 3 ]-batch_count exp = 2 ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 4 ]-bucket
|
||||
exp = {{p}}if_stock_age=>c_bucket-d91_plus ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 4 ]-batch_count exp = 1 ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD groups_sum_quantity_and_count.
|
||||
DATA(lt_result) = mo_cut->analyze(
|
||||
it_batch = VALUE {{p}}if_stock_age=>tt_batch(
|
||||
( material = 'MAT-A' batch = 'B1' quantity = 10 gr_date = gr_date_for_age( 1 ) )
|
||||
( material = 'MAT-A' batch = 'B2' quantity = 5 gr_date = gr_date_for_age( 2 ) )
|
||||
( material = 'MAT-A' batch = 'B3' quantity = 2 gr_date = gr_date_for_age( 200 ) ) )
|
||||
iv_key_date = c_key_date ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals( act = lines( lt_result ) exp = 2 ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 1 ]-bucket
|
||||
exp = {{p}}if_stock_age=>c_bucket-d0_30 ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 1 ]-quantity exp = 15 ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 1 ]-batch_count exp = 2 ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 2 ]-bucket
|
||||
exp = {{p}}if_stock_age=>c_bucket-d91_plus ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 2 ]-quantity exp = 2 ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 2 ]-batch_count exp = 1 ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD result_is_sorted.
|
||||
DATA(lt_result) = mo_cut->analyze(
|
||||
it_batch = VALUE {{p}}if_stock_age=>tt_batch(
|
||||
( material = 'MAT-C' batch = 'B1' quantity = 1 gr_date = gr_date_for_age( 200 ) )
|
||||
( material = 'MAT-A' batch = 'B2' quantity = 1 gr_date = gr_date_for_age( 40 ) )
|
||||
( material = 'MAT-B' batch = 'B3' quantity = 1 gr_date = gr_date_for_age( 1 ) )
|
||||
( material = 'MAT-A' batch = 'B4' quantity = 1 gr_date = gr_date_for_age( 1 ) )
|
||||
( material = 'MAT-C' batch = 'B5' quantity = 1 gr_date = gr_date_for_age( 1 ) )
|
||||
( material = 'MAT-B' batch = 'B6' quantity = 1 gr_date = gr_date_for_age( 70 ) ) )
|
||||
iv_key_date = c_key_date ).
|
||||
|
||||
DATA(lt_expected) = VALUE {{p}}if_stock_age=>tt_age_row(
|
||||
( material = 'MAT-A' bucket = {{p}}if_stock_age=>c_bucket-d0_30 )
|
||||
( material = 'MAT-A' bucket = {{p}}if_stock_age=>c_bucket-d31_60 )
|
||||
( material = 'MAT-B' bucket = {{p}}if_stock_age=>c_bucket-d0_30 )
|
||||
( material = 'MAT-B' bucket = {{p}}if_stock_age=>c_bucket-d61_90 )
|
||||
( material = 'MAT-C' bucket = {{p}}if_stock_age=>c_bucket-d0_30 )
|
||||
( material = 'MAT-C' bucket = {{p}}if_stock_age=>c_bucket-d91_plus ) ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals( act = lines( lt_result ) exp = 6 ).
|
||||
|
||||
DATA lv_index TYPE i.
|
||||
LOOP AT lt_expected INTO DATA(ls_expected).
|
||||
lv_index = lv_index + 1.
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ lv_index ]-material
|
||||
exp = ls_expected-material ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ lv_index ]-bucket
|
||||
exp = ls_expected-bucket ).
|
||||
ENDLOOP.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD invalid_rows_are_ignored.
|
||||
DATA(lt_result) = mo_cut->analyze(
|
||||
it_batch = VALUE {{p}}if_stock_age=>tt_batch(
|
||||
( material = 'MAT-A' batch = 'B1' quantity = 10 gr_date = gr_date_for_age( 5 ) )
|
||||
( material = 'MAT-A' batch = 'B2' quantity = 99 gr_date = '00000000' )
|
||||
( material = 'MAT-A' batch = 'B3' quantity = 99 gr_date = gr_date_for_age( -5 ) ) )
|
||||
iv_key_date = c_key_date ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals( act = lines( lt_result ) exp = 1 ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 1 ]-quantity exp = 10 ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 1 ]-batch_count exp = 1 ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD negative_and_zero_quantity.
|
||||
DATA(lt_result) = mo_cut->analyze(
|
||||
it_batch = VALUE {{p}}if_stock_age=>tt_batch(
|
||||
( material = 'MAT-A' batch = 'B1' quantity = 10 gr_date = gr_date_for_age( 5 ) )
|
||||
( material = 'MAT-A' batch = 'B2' quantity = -4 gr_date = gr_date_for_age( 6 ) )
|
||||
( material = 'MAT-B' batch = 'B3' quantity = 5 gr_date = gr_date_for_age( 5 ) )
|
||||
( material = 'MAT-B' batch = 'B4' quantity = -5 gr_date = gr_date_for_age( 6 ) ) )
|
||||
iv_key_date = c_key_date ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals( act = lines( lt_result ) exp = 2 ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 1 ]-material exp = 'MAT-A' ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 1 ]-quantity exp = 6 ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 1 ]-batch_count exp = 2 ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 2 ]-material exp = 'MAT-B' ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 2 ]-quantity exp = 0 ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 2 ]-batch_count exp = 2 ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD total_groups_by_material.
|
||||
DATA(lt_result) = mo_cut->total_by_material(
|
||||
it_batch = VALUE {{p}}if_stock_age=>tt_batch(
|
||||
( material = 'MAT-A' batch = 'B1' quantity = 10 gr_date = gr_date_for_age( 5 ) )
|
||||
( material = 'MAT-A' batch = 'B2' quantity = 5 gr_date = gr_date_for_age( 100 ) )
|
||||
( material = 'MAT-B' batch = 'B3' quantity = 7 gr_date = gr_date_for_age( 5 ) ) )
|
||||
iv_key_date = c_key_date ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals( act = lines( lt_result ) exp = 2 ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 1 ]-material exp = 'MAT-A' ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 1 ]-quantity exp = 15 ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 1 ]-batch_count exp = 2 ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 2 ]-material exp = 'MAT-B' ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 2 ]-quantity exp = 7 ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 2 ]-batch_count exp = 1 ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD total_is_sorted.
|
||||
DATA(lt_result) = mo_cut->total_by_material(
|
||||
it_batch = VALUE {{p}}if_stock_age=>tt_batch(
|
||||
( material = 'MAT-Z' batch = 'B1' quantity = 1 gr_date = gr_date_for_age( 5 ) )
|
||||
( material = 'MAT-A' batch = 'B2' quantity = 1 gr_date = gr_date_for_age( 5 ) )
|
||||
( material = 'MAT-M' batch = 'B3' quantity = 1 gr_date = gr_date_for_age( 5 ) ) )
|
||||
iv_key_date = c_key_date ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals( act = lines( lt_result ) exp = 3 ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 1 ]-material exp = 'MAT-A' ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 2 ]-material exp = 'MAT-M' ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 3 ]-material exp = 'MAT-Z' ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD total_ignores_invalid_rows.
|
||||
DATA(lt_result) = mo_cut->total_by_material(
|
||||
it_batch = VALUE {{p}}if_stock_age=>tt_batch(
|
||||
( material = 'MAT-A' batch = 'B1' quantity = 99 gr_date = '00000000' )
|
||||
( material = 'MAT-A' batch = 'B2' quantity = 99 gr_date = gr_date_for_age( -1 ) ) )
|
||||
iv_key_date = c_key_date ).
|
||||
|
||||
cl_abap_unit_assert=>assert_initial( act = lt_result ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
92
tasks_gen/eval/G0004/reference/stock_age.clas.abap
Normal file
92
tasks_gen/eval/G0004/reference/stock_age.clas.abap
Normal file
@@ -0,0 +1,92 @@
|
||||
CLASS {{p}}stock_age DEFINITION PUBLIC FINAL CREATE PUBLIC.
|
||||
PUBLIC SECTION.
|
||||
INTERFACES {{p}}if_stock_age.
|
||||
|
||||
PRIVATE SECTION.
|
||||
TYPES tt_age_group TYPE HASHED TABLE OF {{p}}if_stock_age=>ty_age_row
|
||||
WITH UNIQUE KEY material bucket.
|
||||
TYPES tt_total_group TYPE HASHED TABLE OF {{p}}if_stock_age=>ty_total
|
||||
WITH UNIQUE KEY material.
|
||||
|
||||
METHODS age_in_days
|
||||
IMPORTING is_batch TYPE {{p}}if_stock_age=>ty_batch
|
||||
iv_key_date TYPE dats
|
||||
RETURNING VALUE(rv_age) TYPE i.
|
||||
|
||||
METHODS bucket_of
|
||||
IMPORTING iv_age TYPE i
|
||||
RETURNING VALUE(rv_bucket) TYPE {{p}}if_stock_age=>ty_bucket.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}stock_age IMPLEMENTATION.
|
||||
|
||||
METHOD {{p}}if_stock_age~analyze.
|
||||
DATA lt_group TYPE tt_age_group.
|
||||
|
||||
LOOP AT it_batch INTO DATA(ls_batch).
|
||||
DATA(lv_age) = age_in_days( is_batch = ls_batch iv_key_date = iv_key_date ).
|
||||
IF lv_age < 0.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
DATA(lv_bucket) = bucket_of( lv_age ).
|
||||
ASSIGN lt_group[ material = ls_batch-material
|
||||
bucket = lv_bucket ] TO FIELD-SYMBOL(<ls_group>).
|
||||
IF sy-subrc <> 0.
|
||||
INSERT VALUE #( material = ls_batch-material bucket = lv_bucket )
|
||||
INTO TABLE lt_group.
|
||||
ASSIGN lt_group[ material = ls_batch-material
|
||||
bucket = lv_bucket ] TO <ls_group>.
|
||||
ENDIF.
|
||||
|
||||
<ls_group>-quantity = <ls_group>-quantity + ls_batch-quantity.
|
||||
<ls_group>-batch_count = <ls_group>-batch_count + 1.
|
||||
ENDLOOP.
|
||||
|
||||
rt_age = lt_group.
|
||||
SORT rt_age BY material bucket.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD {{p}}if_stock_age~total_by_material.
|
||||
DATA lt_group TYPE tt_total_group.
|
||||
|
||||
LOOP AT it_batch INTO DATA(ls_batch).
|
||||
IF age_in_days( is_batch = ls_batch iv_key_date = iv_key_date ) < 0.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
|
||||
ASSIGN lt_group[ material = ls_batch-material ] TO FIELD-SYMBOL(<ls_group>).
|
||||
IF sy-subrc <> 0.
|
||||
INSERT VALUE #( material = ls_batch-material ) INTO TABLE lt_group.
|
||||
ASSIGN lt_group[ material = ls_batch-material ] TO <ls_group>.
|
||||
ENDIF.
|
||||
|
||||
<ls_group>-quantity = <ls_group>-quantity + ls_batch-quantity.
|
||||
<ls_group>-batch_count = <ls_group>-batch_count + 1.
|
||||
ENDLOOP.
|
||||
|
||||
rt_total = lt_group.
|
||||
SORT rt_total BY material.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD age_in_days.
|
||||
IF is_batch-gr_date IS INITIAL OR is_batch-gr_date > iv_key_date.
|
||||
rv_age = -1.
|
||||
ELSE.
|
||||
rv_age = iv_key_date - is_batch-gr_date.
|
||||
ENDIF.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD bucket_of.
|
||||
IF iv_age <= 30.
|
||||
rv_bucket = {{p}}if_stock_age=>c_bucket-d0_30.
|
||||
ELSEIF iv_age <= 60.
|
||||
rv_bucket = {{p}}if_stock_age=>c_bucket-d31_60.
|
||||
ELSEIF iv_age <= 90.
|
||||
rv_bucket = {{p}}if_stock_age=>c_bucket-d61_90.
|
||||
ELSE.
|
||||
rv_bucket = {{p}}if_stock_age=>c_bucket-d91_plus.
|
||||
ENDIF.
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
80
tasks_gen/eval/G0004/reference/stock_age.testclasses.abap
Normal file
80
tasks_gen/eval/G0004/reference/stock_age.testclasses.abap
Normal file
@@ -0,0 +1,80 @@
|
||||
CLASS ltc_stock_age DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
|
||||
PRIVATE SECTION.
|
||||
CONSTANTS c_key_date TYPE dats VALUE '20240401'.
|
||||
|
||||
DATA mo_cut TYPE REF TO {{p}}if_stock_age.
|
||||
|
||||
METHODS setup.
|
||||
METHODS gr_date_for_age
|
||||
IMPORTING iv_age TYPE i
|
||||
RETURNING VALUE(rv_date) TYPE dats.
|
||||
|
||||
METHODS empty_input FOR TESTING.
|
||||
METHODS bucket_01 FOR TESTING.
|
||||
METHODS bucket_04 FOR TESTING.
|
||||
METHODS invalid_rows FOR TESTING.
|
||||
METHODS total_by_material FOR TESTING.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS ltc_stock_age IMPLEMENTATION.
|
||||
|
||||
METHOD setup.
|
||||
mo_cut = NEW {{p}}stock_age( ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD gr_date_for_age.
|
||||
rv_date = c_key_date - iv_age.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD empty_input.
|
||||
cl_abap_unit_assert=>assert_initial(
|
||||
act = mo_cut->analyze( it_batch = VALUE {{p}}if_stock_age=>tt_batch( )
|
||||
iv_key_date = c_key_date ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD bucket_01.
|
||||
DATA(lt_result) = mo_cut->analyze(
|
||||
it_batch = VALUE {{p}}if_stock_age=>tt_batch(
|
||||
( material = 'MAT-1' batch = 'B1' quantity = 10
|
||||
gr_date = gr_date_for_age( 30 ) ) )
|
||||
iv_key_date = c_key_date ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 1 ]-bucket
|
||||
exp = {{p}}if_stock_age=>c_bucket-d0_30 ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 1 ]-quantity exp = 10 ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD bucket_04.
|
||||
DATA(lt_result) = mo_cut->analyze(
|
||||
it_batch = VALUE {{p}}if_stock_age=>tt_batch(
|
||||
( material = 'MAT-1' batch = 'B1' quantity = 10
|
||||
gr_date = gr_date_for_age( 91 ) ) )
|
||||
iv_key_date = c_key_date ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 1 ]-bucket
|
||||
exp = {{p}}if_stock_age=>c_bucket-d91_plus ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD invalid_rows.
|
||||
DATA(lt_result) = mo_cut->analyze(
|
||||
it_batch = VALUE {{p}}if_stock_age=>tt_batch(
|
||||
( material = 'MAT-1' batch = 'B1' quantity = 10 gr_date = '00000000' ) )
|
||||
iv_key_date = c_key_date ).
|
||||
|
||||
cl_abap_unit_assert=>assert_initial( act = lt_result ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD total_by_material.
|
||||
DATA(lt_result) = mo_cut->total_by_material(
|
||||
it_batch = VALUE {{p}}if_stock_age=>tt_batch(
|
||||
( material = 'MAT-2' batch = 'B1' quantity = 10 gr_date = gr_date_for_age( 1 ) )
|
||||
( material = 'MAT-1' batch = 'B2' quantity = 5 gr_date = gr_date_for_age( 100 ) ) )
|
||||
iv_key_date = c_key_date ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 1 ]-material exp = 'MAT-1' ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 1 ]-quantity exp = 5 ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 2 ]-material exp = 'MAT-2' ).
|
||||
cl_abap_unit_assert=>assert_equals( act = lt_result[ 2 ]-quantity exp = 10 ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
45
tasks_gen/eval/G0004/seed/if_stock_age.intf.abap
Normal file
45
tasks_gen/eval/G0004/seed/if_stock_age.intf.abap
Normal file
@@ -0,0 +1,45 @@
|
||||
INTERFACE {{p}}if_stock_age PUBLIC.
|
||||
TYPES:
|
||||
ty_material TYPE c LENGTH 10,
|
||||
ty_batch_id TYPE c LENGTH 10,
|
||||
ty_bucket TYPE c LENGTH 2,
|
||||
ty_quantity TYPE p LENGTH 13 DECIMALS 3,
|
||||
BEGIN OF ty_batch,
|
||||
material TYPE ty_material,
|
||||
batch TYPE ty_batch_id,
|
||||
quantity TYPE ty_quantity,
|
||||
gr_date TYPE dats,
|
||||
END OF ty_batch,
|
||||
tt_batch TYPE STANDARD TABLE OF ty_batch WITH EMPTY KEY,
|
||||
BEGIN OF ty_age_row,
|
||||
material TYPE ty_material,
|
||||
bucket TYPE ty_bucket,
|
||||
quantity TYPE ty_quantity,
|
||||
batch_count TYPE i,
|
||||
END OF ty_age_row,
|
||||
tt_age_row TYPE STANDARD TABLE OF ty_age_row WITH EMPTY KEY,
|
||||
BEGIN OF ty_total,
|
||||
material TYPE ty_material,
|
||||
quantity TYPE ty_quantity,
|
||||
batch_count TYPE i,
|
||||
END OF ty_total,
|
||||
tt_total TYPE STANDARD TABLE OF ty_total WITH EMPTY KEY.
|
||||
|
||||
CONSTANTS:
|
||||
BEGIN OF c_bucket,
|
||||
d0_30 TYPE ty_bucket VALUE '01',
|
||||
d31_60 TYPE ty_bucket VALUE '02',
|
||||
d61_90 TYPE ty_bucket VALUE '03',
|
||||
d91_plus TYPE ty_bucket VALUE '04',
|
||||
END OF c_bucket.
|
||||
|
||||
METHODS analyze
|
||||
IMPORTING it_batch TYPE tt_batch
|
||||
iv_key_date TYPE dats
|
||||
RETURNING VALUE(rt_age) TYPE tt_age_row.
|
||||
|
||||
METHODS total_by_material
|
||||
IMPORTING it_batch TYPE tt_batch
|
||||
iv_key_date TYPE dats
|
||||
RETURNING VALUE(rt_total) TYPE tt_total.
|
||||
ENDINTERFACE.
|
||||
80
tasks_gen/eval/G0004/spec.md
Normal file
80
tasks_gen/eval/G0004/spec.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# 1. Goal
|
||||
Analyse the age of stock batches. A warehouse report calls the analysis before it
|
||||
prints the stock aging report. The report needs the grouped quantity and the number
|
||||
of batches for each material and age bucket.
|
||||
|
||||
# 2. Open questions
|
||||
None.
|
||||
|
||||
# 3. Context
|
||||
- The interface {{P}}IF_STOCK_AGE exists in package $TMP. It is active.
|
||||
- The interface defines these types:
|
||||
- ty_material: character, length 10.
|
||||
- ty_batch_id: character, length 10.
|
||||
- ty_bucket: character, length 2.
|
||||
- ty_quantity: packed number, length 13, 3 decimals.
|
||||
- ty_batch: structure with the components material, batch, quantity, gr_date.
|
||||
- tt_batch: table of ty_batch.
|
||||
- ty_age_row: structure with the components material, bucket, quantity, batch_count.
|
||||
- tt_age_row: table of ty_age_row.
|
||||
- ty_total: structure with the components material, quantity, batch_count.
|
||||
- tt_total: table of ty_total.
|
||||
- The interface defines the constant structure C_BUCKET with the components
|
||||
D0_30 = '01', D31_60 = '02', D61_90 = '03', D91_PLUS = '04'.
|
||||
- The interface defines two methods:
|
||||
- analyze: importing it_batch type tt_batch and iv_key_date type dats,
|
||||
returning rt_age type tt_age_row.
|
||||
- total_by_material: importing it_batch type tt_batch and iv_key_date type dats,
|
||||
returning rt_total type tt_total.
|
||||
|
||||
# 4. Contract
|
||||
- Create the class {{P}}STOCK_AGE in package $TMP.
|
||||
- The class is public, final, and has a public constructor without parameters.
|
||||
- The class implements {{P}}IF_STOCK_AGE.
|
||||
- Do not add other public methods.
|
||||
|
||||
# 5. Business rules
|
||||
Both methods use the same validity rules and the same age buckets.
|
||||
|
||||
Validity
|
||||
1. A row of IT_BATCH is valid when its goods receipt date is not initial and is not
|
||||
after IV_KEY_DATE.
|
||||
2. A row that is not valid is ignored. It must not change any result.
|
||||
|
||||
Age and bucket
|
||||
3. The age of a batch is the number of days between its goods receipt date and
|
||||
IV_KEY_DATE.
|
||||
4. The bucket of a batch is:
|
||||
- age 0 to 30 days: bucket 01 (C_BUCKET-D0_30)
|
||||
- age 31 to 60 days: bucket 02 (C_BUCKET-D31_60)
|
||||
- age 61 to 90 days: bucket 03 (C_BUCKET-D61_90)
|
||||
- age more than 90 days: bucket 04 (C_BUCKET-D91_PLUS)
|
||||
|
||||
Method ANALYZE
|
||||
5. Group the valid rows by material and bucket.
|
||||
6. For each group, sum the quantity and count the valid rows.
|
||||
7. Return one row per group. Sort the result by material ascending and then by
|
||||
bucket ascending.
|
||||
8. A group is in the result as soon as one valid row belongs to it, also when the
|
||||
summed quantity is zero.
|
||||
9. If no valid row exists, return an empty table.
|
||||
|
||||
Method TOTAL_BY_MATERIAL
|
||||
10. Group the valid rows by material only.
|
||||
11. For each group, sum the quantity and count the valid rows.
|
||||
12. Return one row per material. Sort the result by material ascending.
|
||||
13. If no valid row exists, return an empty table.
|
||||
|
||||
Quantity
|
||||
14. The quantity of a batch can be negative. Add the quantities as they are.
|
||||
|
||||
# 6. Constraints
|
||||
- Release target: SAP_BASIS 8.16 (ABAP Platform 2025).
|
||||
- Coding standards: Clean ABAP. Method length below 40 statements. No global
|
||||
variables. No comment that restates the code. Pass large parameters by reference.
|
||||
- Out of scope: do not change {{P}}IF_STOCK_AGE.
|
||||
|
||||
# 7. Acceptance
|
||||
- The class is active and has no syntax error.
|
||||
- The hidden tests pass.
|
||||
- Write your own ABAP Unit tests for the class.
|
||||
53
tasks_gen/eval/G0004/task.json
Normal file
53
tasks_gen/eval/G0004/task.json
Normal file
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"id": "G0004",
|
||||
"category": "C",
|
||||
"object_type": "CLAS",
|
||||
"difficulty": 2,
|
||||
"release_target": "v816",
|
||||
"expected_outcome": "implement",
|
||||
"budget": {
|
||||
"max_tool_calls": 60,
|
||||
"max_activations": 12
|
||||
},
|
||||
"seed": [
|
||||
{
|
||||
"type": "INTF",
|
||||
"name": "{{P}}IF_STOCK_AGE",
|
||||
"file": "seed/if_stock_age.intf.abap",
|
||||
"description": "Stock age contract: row types, bucket constants and the two analysis methods"
|
||||
}
|
||||
],
|
||||
"contract": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}STOCK_AGE",
|
||||
"implements": "{{P}}IF_STOCK_AGE"
|
||||
}
|
||||
],
|
||||
"out_of_scope": [
|
||||
"{{P}}IF_STOCK_AGE"
|
||||
],
|
||||
"hidden_tests": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}STOCK_AGE_HIDDEN",
|
||||
"file": "hidden/stock_age_hidden.clas.abap",
|
||||
"description": "Hidden tests for the stock age analysis"
|
||||
}
|
||||
],
|
||||
"reference": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}STOCK_AGE",
|
||||
"file": "reference/stock_age.clas.abap",
|
||||
"description": "Stock age analysis",
|
||||
"testclasses_file": "reference/stock_age.testclasses.abap"
|
||||
}
|
||||
],
|
||||
"craft_checks": [
|
||||
"table_kind",
|
||||
"access_path",
|
||||
"method_length",
|
||||
"no_nested_loops"
|
||||
]
|
||||
}
|
||||
29
tasks_gen/eval/G0005/generation.json
Normal file
29
tasks_gen/eval/G0005/generation.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"id": "G0005",
|
||||
"pool": "eval",
|
||||
"object_type": "CLAS",
|
||||
"category": "D",
|
||||
"attempts": [
|
||||
{
|
||||
"stage": "validate",
|
||||
"oracle": null,
|
||||
"null": null
|
||||
},
|
||||
{
|
||||
"stage": "validate",
|
||||
"oracle": 0,
|
||||
"null": 0
|
||||
},
|
||||
{
|
||||
"stage": "validate",
|
||||
"oracle": 0,
|
||||
"null": 0
|
||||
},
|
||||
{
|
||||
"stage": "validate",
|
||||
"oracle": 0,
|
||||
"null": 0
|
||||
}
|
||||
],
|
||||
"accepted": false
|
||||
}
|
||||
158
tasks_gen/eval/G0005/hidden/t02_hidden.clas.abap
Normal file
158
tasks_gen/eval/G0005/hidden/t02_hidden.clas.abap
Normal file
@@ -0,0 +1,158 @@
|
||||
CLASS {{p}}t02_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
|
||||
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
|
||||
PRIVATE SECTION.
|
||||
TYPES ty_cost TYPE p LENGTH 15 DECIMALS 2.
|
||||
TYPES ty_currency TYPE c LENGTH 5.
|
||||
TYPES ty_zone_code TYPE c LENGTH 4.
|
||||
TYPES ty_weight TYPE p LENGTH 15 DECIMALS 3.
|
||||
|
||||
DATA mo_cut TYPE REF TO {{p}}freight_calc.
|
||||
|
||||
METHODS setup.
|
||||
|
||||
METHODS calculate_result
|
||||
IMPORTING iv_zone_code TYPE ty_zone_code
|
||||
iv_weight_kg TYPE ty_weight
|
||||
iv_express TYPE abap_bool DEFAULT abap_false
|
||||
RETURNING VALUE(rs_result) TYPE {{p}}freight_calc=>ty_result.
|
||||
|
||||
METHODS assert_cost
|
||||
IMPORTING iv_cost TYPE ty_cost
|
||||
iv_currency TYPE ty_currency
|
||||
is_result TYPE {{p}}freight_calc=>ty_result.
|
||||
|
||||
METHODS assert_weight
|
||||
IMPORTING iv_expected TYPE ty_weight
|
||||
iv_actual TYPE ty_weight
|
||||
iv_msg TYPE string.
|
||||
|
||||
METHODS standard_cost FOR TESTING.
|
||||
METHODS express_surcharge FOR TESTING.
|
||||
METHODS express_no_early_rounding FOR TESTING.
|
||||
METHODS minimum_charge FOR TESTING.
|
||||
METHODS rounding FOR TESTING.
|
||||
METHODS zone_code_normalized FOR TESTING.
|
||||
METHODS weight_at_limit FOR TESTING.
|
||||
METHODS unknown_zone FOR TESTING.
|
||||
METHODS invalid_weight FOR TESTING.
|
||||
METHODS weight_limit FOR TESTING.
|
||||
METHODS weight_check_before_zone_lookup FOR TESTING.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}t02_hidden IMPLEMENTATION.
|
||||
METHOD setup.
|
||||
mo_cut = NEW {{p}}freight_calc( ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD calculate_result.
|
||||
TRY.
|
||||
rs_result = mo_cut->calculate( iv_zone_code = iv_zone_code
|
||||
iv_weight_kg = iv_weight_kg
|
||||
iv_express = iv_express ).
|
||||
CATCH {{p}}cx_freight_error INTO DATA(lo_error).
|
||||
cl_abap_unit_assert=>fail( msg = lo_error->get_reason_text( ) ).
|
||||
ENDTRY.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD assert_cost.
|
||||
cl_abap_unit_assert=>assert_equals( exp = iv_cost act = is_result-cost msg = 'cost' ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = iv_currency act = is_result-currency msg = 'currency' ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD assert_weight.
|
||||
cl_abap_unit_assert=>assert_equals( exp = iv_expected act = iv_actual msg = iv_msg ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD standard_cost.
|
||||
DATA(ls_result) = calculate_result( iv_zone_code = 'DE01' iv_weight_kg = '10.000' ).
|
||||
assert_cost( iv_cost = '17.00' iv_currency = 'EUR' is_result = ls_result ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD express_surcharge.
|
||||
DATA(ls_result) = calculate_result( iv_zone_code = 'DE01'
|
||||
iv_weight_kg = '10.000'
|
||||
iv_express = abap_true ).
|
||||
assert_cost( iv_cost = '25.50' iv_currency = 'EUR' is_result = ls_result ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD express_no_early_rounding.
|
||||
DATA(ls_result) = calculate_result( iv_zone_code = 'DE01'
|
||||
iv_weight_kg = '10.004'
|
||||
iv_express = abap_true ).
|
||||
assert_cost( iv_cost = '25.51' iv_currency = 'EUR' is_result = ls_result ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD minimum_charge.
|
||||
DATA(ls_result) = calculate_result( iv_zone_code = 'DE01' iv_weight_kg = '0.500' ).
|
||||
assert_cost( iv_cost = '6.00' iv_currency = 'EUR' is_result = ls_result ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD rounding.
|
||||
DATA(ls_result) = calculate_result( iv_zone_code = 'FR01' iv_weight_kg = '1.234' ).
|
||||
assert_cost( iv_cost = '12.09' iv_currency = 'EUR' is_result = ls_result ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD zone_code_normalized.
|
||||
DATA(ls_result) = calculate_result( iv_zone_code = 'de01' iv_weight_kg = '10.000' ).
|
||||
assert_cost( iv_cost = '17.00' iv_currency = 'EUR' is_result = ls_result ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD weight_at_limit.
|
||||
DATA(ls_result) = calculate_result( iv_zone_code = 'CN01' iv_weight_kg = '20.000' ).
|
||||
assert_cost( iv_cost = '103.00' iv_currency = 'CNY' is_result = ls_result ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD unknown_zone.
|
||||
TRY.
|
||||
mo_cut->calculate( iv_zone_code = 'xx99' iv_weight_kg = '1.000' ).
|
||||
cl_abap_unit_assert=>fail( msg = 'CX_UNKNOWN_ZONE expected' ).
|
||||
CATCH {{p}}cx_unknown_zone INTO DATA(lo_unknown).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 'XX99' act = lo_unknown->mv_zone_code ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `Zone XX99 is not known`
|
||||
act = lo_unknown->get_reason_text( ) ).
|
||||
CATCH {{p}}cx_freight_error INTO DATA(lo_other).
|
||||
cl_abap_unit_assert=>fail( msg = |Wrong exception class: { lo_other->get_reason_text( ) }| ).
|
||||
ENDTRY.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD invalid_weight.
|
||||
TRY.
|
||||
mo_cut->calculate( iv_zone_code = 'DE01' iv_weight_kg = '0.000' ).
|
||||
cl_abap_unit_assert=>fail( msg = 'CX_INVALID_WEIGHT expected' ).
|
||||
CATCH {{p}}cx_invalid_weight INTO DATA(lo_invalid).
|
||||
assert_weight( iv_expected = '0.000' iv_actual = lo_invalid->mv_weight_kg iv_msg = 'weight' ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 'DE01' act = lo_invalid->mv_zone_code ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `Weight must be greater than zero`
|
||||
act = lo_invalid->get_reason_text( ) ).
|
||||
CATCH {{p}}cx_freight_error INTO DATA(lo_other).
|
||||
cl_abap_unit_assert=>fail( msg = |Wrong exception class: { lo_other->get_reason_text( ) }| ).
|
||||
ENDTRY.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD weight_limit.
|
||||
TRY.
|
||||
mo_cut->calculate( iv_zone_code = 'CN01' iv_weight_kg = '20.001' ).
|
||||
cl_abap_unit_assert=>fail( msg = 'CX_WEIGHT_LIMIT expected' ).
|
||||
CATCH {{p}}cx_weight_limit INTO DATA(lo_limit).
|
||||
assert_weight( iv_expected = '20.001' iv_actual = lo_limit->mv_weight_kg iv_msg = 'weight' ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 20 act = lo_limit->mv_max_weight_kg msg = 'max weight' ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 'CN01' act = lo_limit->mv_zone_code ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `Weight exceeds the zone limit`
|
||||
act = lo_limit->get_reason_text( ) ).
|
||||
CATCH {{p}}cx_freight_error INTO DATA(lo_other).
|
||||
cl_abap_unit_assert=>fail( msg = |Wrong exception class: { lo_other->get_reason_text( ) }| ).
|
||||
ENDTRY.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD weight_check_before_zone_lookup.
|
||||
TRY.
|
||||
mo_cut->calculate( iv_zone_code = 'ZZZZ' iv_weight_kg = '0.000' ).
|
||||
cl_abap_unit_assert=>fail( msg = 'CX_INVALID_WEIGHT expected' ).
|
||||
CATCH {{p}}cx_invalid_weight INTO DATA(lo_invalid).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 'ZZZZ' act = lo_invalid->mv_zone_code ).
|
||||
CATCH {{p}}cx_freight_error INTO DATA(lo_other).
|
||||
cl_abap_unit_assert=>fail( msg = |Wrong exception class: { lo_other->get_reason_text( ) }| ).
|
||||
ENDTRY.
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
11
tasks_gen/eval/G0005/reference/cx_freight_error.clas.abap
Normal file
11
tasks_gen/eval/G0005/reference/cx_freight_error.clas.abap
Normal file
@@ -0,0 +1,11 @@
|
||||
CLASS {{p}}cx_freight_error DEFINITION PUBLIC INHERITING FROM cx_static_check ABSTRACT.
|
||||
PUBLIC SECTION.
|
||||
DATA mv_zone_code TYPE c LENGTH 4.
|
||||
|
||||
METHODS get_reason_text ABSTRACT
|
||||
RETURNING VALUE(rv_text) TYPE string.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}cx_freight_error IMPLEMENTATION.
|
||||
ENDCLASS.
|
||||
13
tasks_gen/eval/G0005/reference/cx_invalid_weight.clas.abap
Normal file
13
tasks_gen/eval/G0005/reference/cx_invalid_weight.clas.abap
Normal file
@@ -0,0 +1,13 @@
|
||||
CLASS {{p}}cx_invalid_weight DEFINITION PUBLIC INHERITING FROM {{p}}cx_freight_error FINAL CREATE PUBLIC.
|
||||
PUBLIC SECTION.
|
||||
DATA mv_weight_kg TYPE p LENGTH 15 DECIMALS 3.
|
||||
|
||||
METHODS get_reason_text REDEFINITION.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}cx_invalid_weight IMPLEMENTATION.
|
||||
METHOD get_reason_text.
|
||||
rv_text = 'Weight must be greater than zero'.
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
11
tasks_gen/eval/G0005/reference/cx_unknown_zone.clas.abap
Normal file
11
tasks_gen/eval/G0005/reference/cx_unknown_zone.clas.abap
Normal file
@@ -0,0 +1,11 @@
|
||||
CLASS {{p}}cx_unknown_zone DEFINITION PUBLIC INHERITING FROM {{p}}cx_freight_error FINAL CREATE PUBLIC.
|
||||
PUBLIC SECTION.
|
||||
METHODS get_reason_text REDEFINITION.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}cx_unknown_zone IMPLEMENTATION.
|
||||
METHOD get_reason_text.
|
||||
rv_text = |Zone { condense( mv_zone_code ) } is not known|.
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
14
tasks_gen/eval/G0005/reference/cx_weight_limit.clas.abap
Normal file
14
tasks_gen/eval/G0005/reference/cx_weight_limit.clas.abap
Normal file
@@ -0,0 +1,14 @@
|
||||
CLASS {{p}}cx_weight_limit DEFINITION PUBLIC INHERITING FROM {{p}}cx_freight_error FINAL CREATE PUBLIC.
|
||||
PUBLIC SECTION.
|
||||
DATA mv_weight_kg TYPE p LENGTH 15 DECIMALS 3.
|
||||
DATA mv_max_weight_kg TYPE i.
|
||||
|
||||
METHODS get_reason_text REDEFINITION.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}cx_weight_limit IMPLEMENTATION.
|
||||
METHOD get_reason_text.
|
||||
rv_text = 'Weight exceeds the zone limit'.
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
73
tasks_gen/eval/G0005/reference/freight_calc.clas.abap
Normal file
73
tasks_gen/eval/G0005/reference/freight_calc.clas.abap
Normal file
@@ -0,0 +1,73 @@
|
||||
CLASS {{p}}freight_calc DEFINITION PUBLIC FINAL CREATE PUBLIC.
|
||||
PUBLIC SECTION.
|
||||
TYPES ty_cost TYPE p LENGTH 15 DECIMALS 2.
|
||||
TYPES ty_weight TYPE p LENGTH 15 DECIMALS 3.
|
||||
TYPES: BEGIN OF ty_result,
|
||||
cost TYPE ty_cost,
|
||||
currency TYPE c LENGTH 5,
|
||||
END OF ty_result.
|
||||
|
||||
METHODS calculate
|
||||
IMPORTING iv_zone_code TYPE c LENGTH 4
|
||||
iv_weight_kg TYPE ty_weight
|
||||
iv_express TYPE abap_bool DEFAULT abap_false
|
||||
RETURNING VALUE(rs_result) TYPE ty_result
|
||||
RAISING {{p}}cx_freight_error.
|
||||
|
||||
PRIVATE SECTION.
|
||||
CONSTANTS c_express_factor TYPE p LENGTH 5 DECIMALS 2 VALUE '1.50'.
|
||||
CONSTANTS c_minimum_charge TYPE ty_cost VALUE '6.00'.
|
||||
|
||||
METHODS find_zone
|
||||
IMPORTING iv_zone_code TYPE c LENGTH 4
|
||||
RETURNING VALUE(rs_zone) TYPE {{p}}zone_master=>ty_zone
|
||||
RAISING {{p}}cx_freight_error.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}freight_calc IMPLEMENTATION.
|
||||
METHOD calculate.
|
||||
DATA lv_zone_code TYPE c LENGTH 4.
|
||||
lv_zone_code = to_upper( iv_zone_code ).
|
||||
|
||||
IF iv_weight_kg <= 0.
|
||||
DATA(lo_invalid) = NEW {{p}}cx_invalid_weight( ).
|
||||
lo_invalid->mv_zone_code = lv_zone_code.
|
||||
lo_invalid->mv_weight_kg = iv_weight_kg.
|
||||
RAISE EXCEPTION lo_invalid.
|
||||
ENDIF.
|
||||
|
||||
DATA(ls_zone) = find_zone( lv_zone_code ).
|
||||
|
||||
IF iv_weight_kg > ls_zone-max_weight_kg.
|
||||
DATA(lo_limit) = NEW {{p}}cx_weight_limit( ).
|
||||
lo_limit->mv_zone_code = lv_zone_code.
|
||||
lo_limit->mv_weight_kg = iv_weight_kg.
|
||||
lo_limit->mv_max_weight_kg = ls_zone-max_weight_kg.
|
||||
RAISE EXCEPTION lo_limit.
|
||||
ENDIF.
|
||||
|
||||
DATA lv_cost TYPE p LENGTH 15 DECIMALS 5.
|
||||
lv_cost = ls_zone-base_fee + iv_weight_kg * ls_zone-price_per_kg.
|
||||
IF iv_express = abap_true.
|
||||
lv_cost = lv_cost * c_express_factor.
|
||||
ENDIF.
|
||||
lv_cost = round( val = lv_cost dec = 2 ).
|
||||
IF lv_cost < c_minimum_charge.
|
||||
lv_cost = c_minimum_charge.
|
||||
ENDIF.
|
||||
|
||||
rs_result-cost = lv_cost.
|
||||
rs_result-currency = ls_zone-currency.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD find_zone.
|
||||
DATA(lt_zone) = {{p}}zone_master=>get_all( ).
|
||||
READ TABLE lt_zone INTO rs_zone WITH KEY zone_code = iv_zone_code.
|
||||
IF sy-subrc <> 0.
|
||||
DATA(lo_unknown) = NEW {{p}}cx_unknown_zone( ).
|
||||
lo_unknown->mv_zone_code = iv_zone_code.
|
||||
RAISE EXCEPTION lo_unknown.
|
||||
ENDIF.
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
98
tasks_gen/eval/G0005/reference/freight_calc.testclasses.abap
Normal file
98
tasks_gen/eval/G0005/reference/freight_calc.testclasses.abap
Normal file
@@ -0,0 +1,98 @@
|
||||
CLASS ltc_freight_calc DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
|
||||
PRIVATE SECTION.
|
||||
TYPES ty_cost TYPE p LENGTH 15 DECIMALS 2.
|
||||
TYPES ty_currency TYPE c LENGTH 5.
|
||||
TYPES ty_zone_code TYPE c LENGTH 4.
|
||||
TYPES ty_weight TYPE p LENGTH 15 DECIMALS 3.
|
||||
|
||||
DATA mo_cut TYPE REF TO {{p}}freight_calc.
|
||||
|
||||
METHODS setup.
|
||||
METHODS assert_cost
|
||||
IMPORTING iv_cost TYPE ty_cost
|
||||
iv_currency TYPE ty_currency
|
||||
is_result TYPE {{p}}freight_calc=>ty_result.
|
||||
METHODS calculate_result
|
||||
IMPORTING iv_zone_code TYPE ty_zone_code
|
||||
iv_weight_kg TYPE ty_weight
|
||||
iv_express TYPE abap_bool DEFAULT abap_false
|
||||
RETURNING VALUE(rs_result) TYPE {{p}}freight_calc=>ty_result.
|
||||
METHODS standard_cost FOR TESTING.
|
||||
METHODS express_cost FOR TESTING.
|
||||
METHODS minimum_charge FOR TESTING.
|
||||
METHODS unknown_zone FOR TESTING.
|
||||
METHODS invalid_weight FOR TESTING.
|
||||
METHODS weight_limit FOR TESTING.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS ltc_freight_calc IMPLEMENTATION.
|
||||
METHOD setup.
|
||||
mo_cut = NEW {{p}}freight_calc( ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD assert_cost.
|
||||
cl_abap_unit_assert=>assert_equals( exp = iv_cost act = is_result-cost ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = iv_currency act = is_result-currency ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD calculate_result.
|
||||
TRY.
|
||||
rs_result = mo_cut->calculate( iv_zone_code = iv_zone_code
|
||||
iv_weight_kg = iv_weight_kg
|
||||
iv_express = iv_express ).
|
||||
CATCH {{p}}cx_freight_error INTO DATA(lo_error).
|
||||
cl_abap_unit_assert=>fail( msg = lo_error->get_reason_text( ) ).
|
||||
ENDTRY.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD standard_cost.
|
||||
DATA(ls_result) = calculate_result( iv_zone_code = 'DE01' iv_weight_kg = '10.000' ).
|
||||
assert_cost( iv_cost = '17.00' iv_currency = 'EUR' is_result = ls_result ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD express_cost.
|
||||
DATA(ls_result) = calculate_result( iv_zone_code = 'DE01'
|
||||
iv_weight_kg = '10.000'
|
||||
iv_express = abap_true ).
|
||||
assert_cost( iv_cost = '25.50' iv_currency = 'EUR' is_result = ls_result ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD minimum_charge.
|
||||
DATA(ls_result) = calculate_result( iv_zone_code = 'DE01' iv_weight_kg = '0.500' ).
|
||||
assert_cost( iv_cost = '6.00' iv_currency = 'EUR' is_result = ls_result ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD unknown_zone.
|
||||
TRY.
|
||||
mo_cut->calculate( iv_zone_code = 'XX99' iv_weight_kg = '1.000' ).
|
||||
cl_abap_unit_assert=>fail( msg = 'CX_UNKNOWN_ZONE expected' ).
|
||||
CATCH {{p}}cx_unknown_zone INTO DATA(lo_unknown).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 'XX99' act = lo_unknown->mv_zone_code ).
|
||||
CATCH {{p}}cx_freight_error INTO DATA(lo_other).
|
||||
cl_abap_unit_assert=>fail( msg = |Wrong exception class: { lo_other->get_reason_text( ) }| ).
|
||||
ENDTRY.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD invalid_weight.
|
||||
TRY.
|
||||
mo_cut->calculate( iv_zone_code = 'DE01' iv_weight_kg = '0.000' ).
|
||||
cl_abap_unit_assert=>fail( msg = 'CX_INVALID_WEIGHT expected' ).
|
||||
CATCH {{p}}cx_invalid_weight INTO DATA(lo_invalid).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 'DE01' act = lo_invalid->mv_zone_code ).
|
||||
CATCH {{p}}cx_freight_error INTO DATA(lo_other).
|
||||
cl_abap_unit_assert=>fail( msg = |Wrong exception class: { lo_other->get_reason_text( ) }| ).
|
||||
ENDTRY.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD weight_limit.
|
||||
TRY.
|
||||
mo_cut->calculate( iv_zone_code = 'CN01' iv_weight_kg = '20.001' ).
|
||||
cl_abap_unit_assert=>fail( msg = 'CX_WEIGHT_LIMIT expected' ).
|
||||
CATCH {{p}}cx_weight_limit INTO DATA(lo_limit).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 'CN01' act = lo_limit->mv_zone_code ).
|
||||
CATCH {{p}}cx_freight_error INTO DATA(lo_other).
|
||||
cl_abap_unit_assert=>fail( msg = |Wrong exception class: { lo_other->get_reason_text( ) }| ).
|
||||
ENDTRY.
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
18
tasks_gen/eval/G0005/seed/seed_data.clas.abap
Normal file
18
tasks_gen/eval/G0005/seed/seed_data.clas.abap
Normal file
@@ -0,0 +1,18 @@
|
||||
CLASS {{p}}seed_data DEFINITION PUBLIC FINAL CREATE PUBLIC.
|
||||
PUBLIC SECTION.
|
||||
INTERFACES if_oo_adt_classrun.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}seed_data IMPLEMENTATION.
|
||||
METHOD if_oo_adt_classrun~main.
|
||||
DELETE FROM {{p}}zones.
|
||||
INSERT {{p}}zones FROM TABLE @( VALUE #(
|
||||
( zone_code = 'DE01' country = 'DE' base_fee = '5.00' price_per_kg = '1.20' max_weight_kg = 31 currency = 'EUR' )
|
||||
( zone_code = 'DE02' country = 'DE' base_fee = '8.00' price_per_kg = '1.80' max_weight_kg = 31 currency = 'EUR' )
|
||||
( zone_code = 'FR01' country = 'FR' base_fee = '9.50' price_per_kg = '2.10' max_weight_kg = 30 currency = 'EUR' )
|
||||
( zone_code = 'US01' country = 'US' base_fee = '14.00' price_per_kg = '3.40' max_weight_kg = 25 currency = 'USD' )
|
||||
( zone_code = 'CN01' country = 'CN' base_fee = '18.00' price_per_kg = '4.25' max_weight_kg = 20 currency = 'CNY' ) ) ).
|
||||
out->write( |Zones seeded| ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
27
tasks_gen/eval/G0005/seed/zone_master.clas.abap
Normal file
27
tasks_gen/eval/G0005/seed/zone_master.clas.abap
Normal file
@@ -0,0 +1,27 @@
|
||||
CLASS {{p}}zone_master DEFINITION PUBLIC FINAL CREATE PUBLIC.
|
||||
PUBLIC SECTION.
|
||||
TYPES: BEGIN OF ty_zone,
|
||||
zone_code TYPE c LENGTH 4,
|
||||
country TYPE c LENGTH 2,
|
||||
base_fee TYPE p LENGTH 15 DECIMALS 2,
|
||||
price_per_kg TYPE p LENGTH 15 DECIMALS 2,
|
||||
max_weight_kg TYPE i,
|
||||
currency TYPE c LENGTH 5,
|
||||
END OF ty_zone,
|
||||
tt_zone TYPE SORTED TABLE OF ty_zone WITH UNIQUE KEY zone_code.
|
||||
|
||||
CLASS-METHODS get_all
|
||||
RETURNING VALUE(rt_zone) TYPE tt_zone.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}zone_master IMPLEMENTATION.
|
||||
METHOD get_all.
|
||||
rt_zone = VALUE #(
|
||||
( zone_code = 'DE01' country = 'DE' base_fee = '5.00' price_per_kg = '1.20' max_weight_kg = 31 currency = 'EUR' )
|
||||
( zone_code = 'DE02' country = 'DE' base_fee = '8.00' price_per_kg = '1.80' max_weight_kg = 31 currency = 'EUR' )
|
||||
( zone_code = 'FR01' country = 'FR' base_fee = '9.50' price_per_kg = '2.10' max_weight_kg = 30 currency = 'EUR' )
|
||||
( zone_code = 'US01' country = 'US' base_fee = '14.00' price_per_kg = '3.40' max_weight_kg = 25 currency = 'USD' )
|
||||
( zone_code = 'CN01' country = 'CN' base_fee = '18.00' price_per_kg = '4.25' max_weight_kg = 20 currency = 'CNY' ) ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
10
tasks_gen/eval/G0005/seed/zones.tabl.abap
Normal file
10
tasks_gen/eval/G0005/seed/zones.tabl.abap
Normal file
@@ -0,0 +1,10 @@
|
||||
@EndUserText.label : 'Zone tariff'
|
||||
define table {{p}}zones {
|
||||
key mandt : abap.clnt not null;
|
||||
key zone_code : abap.char(4) not null;
|
||||
country : abap.char(2) not null;
|
||||
base_fee : abap.dec(15,2) not null;
|
||||
price_per_kg : abap.dec(15,2) not null;
|
||||
max_weight_kg : abap.int4 not null;
|
||||
currency : abap.char(5) not null;
|
||||
}
|
||||
103
tasks_gen/eval/G0005/spec.md
Normal file
103
tasks_gen/eval/G0005/spec.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# 1. Goal
|
||||
A parcel service calculates the freight cost of a parcel from a zone code and a
|
||||
weight. Each rejected input must be reported as its own class-based exception, so
|
||||
that the calling program can react to the exact reason.
|
||||
|
||||
# 2. Open questions
|
||||
None.
|
||||
|
||||
# 3. Context
|
||||
- The class {{P}}ZONE_MASTER exists in package $TMP and is active. It provides the
|
||||
zone master data. Do not change it.
|
||||
- {{P}}ZONE_MASTER has these public components:
|
||||
- TYPES TY_ZONE with the components ZONE_CODE (c LENGTH 4), COUNTRY (c LENGTH 2),
|
||||
BASE_FEE (p LENGTH 15 DECIMALS 2), PRICE_PER_KG (p LENGTH 15 DECIMALS 2),
|
||||
MAX_WEIGHT_KG (i), CURRENCY (c LENGTH 5).
|
||||
- TYPES TT_ZONE, a sorted table of TY_ZONE with the unique key ZONE_CODE.
|
||||
- CLASS-METHOD GET_ALL returning the table TT_ZONE.
|
||||
- The zone master data contains these entries:
|
||||
|
||||
| ZONE_CODE | COUNTRY | BASE_FEE | PRICE_PER_KG | MAX_WEIGHT_KG | CURRENCY |
|
||||
| --------- | ------- | -------- | ------------ | ------------- | -------- |
|
||||
| DE01 | DE | 5.00 | 1.20 | 31 | EUR |
|
||||
| DE02 | DE | 8.00 | 1.80 | 31 | EUR |
|
||||
| FR01 | FR | 9.50 | 2.10 | 30 | EUR |
|
||||
| US01 | US | 14.00 | 3.40 | 25 | USD |
|
||||
| CN01 | CN | 18.00 | 4.25 | 20 | CNY |
|
||||
|
||||
# 4. Contract
|
||||
Create these classes in package $TMP.
|
||||
|
||||
{{P}}CX_FREIGHT_ERROR
|
||||
- public, abstract, inherits from CX_STATIC_CHECK.
|
||||
- public attribute MV_ZONE_CODE type c LENGTH 4.
|
||||
- public method GET_REASON_TEXT returning VALUE(rv_text) type string.
|
||||
|
||||
{{P}}CX_UNKNOWN_ZONE
|
||||
- public, inherits from {{P}}CX_FREIGHT_ERROR.
|
||||
|
||||
{{P}}CX_INVALID_WEIGHT
|
||||
- public, inherits from {{P}}CX_FREIGHT_ERROR.
|
||||
- public attribute MV_WEIGHT_KG type p LENGTH 15 DECIMALS 3.
|
||||
|
||||
{{P}}CX_WEIGHT_LIMIT
|
||||
- public, inherits from {{P}}CX_FREIGHT_ERROR.
|
||||
- public attribute MV_WEIGHT_KG type p LENGTH 15 DECIMALS 3.
|
||||
- public attribute MV_MAX_WEIGHT_KG type i.
|
||||
|
||||
GET_REASON_TEXT returns the reason text of the exception. Each of the three
|
||||
concrete exception classes returns its own text, see the business rules.
|
||||
|
||||
{{P}}FREIGHT_CALC
|
||||
- public, final, create public, constructor without parameters.
|
||||
- public type TY_COST (p LENGTH 15 DECIMALS 2).
|
||||
- public type TY_WEIGHT (p LENGTH 15 DECIMALS 3).
|
||||
- public type TY_RESULT with the components COST (type TY_COST) and CURRENCY
|
||||
(c LENGTH 5).
|
||||
- public method CALCULATE:
|
||||
|
||||
IMPORTING iv_zone_code TYPE c LENGTH 4
|
||||
iv_weight_kg TYPE ty_weight
|
||||
iv_express TYPE abap_bool DEFAULT abap_false
|
||||
RETURNING VALUE(rs_result) TYPE ty_result
|
||||
RAISING {{p}}cx_freight_error
|
||||
|
||||
- no other public methods.
|
||||
|
||||
Use the named types of this contract in the method interfaces. Do not write the
|
||||
additions LENGTH or DECIMALS in a method interface.
|
||||
|
||||
# 5. Business rules
|
||||
CALCULATE applies these rules in this sequence.
|
||||
1. Convert the zone code to upper case. Use this value in all further steps and in
|
||||
the attribute MV_ZONE_CODE of every exception.
|
||||
2. If the weight is less than or equal to zero, raise {{P}}CX_INVALID_WEIGHT. Set
|
||||
MV_ZONE_CODE to the zone code and MV_WEIGHT_KG to the given weight.
|
||||
3. Read the zone master data with {{P}}ZONE_MASTER=>GET_ALL and find the entry
|
||||
whose ZONE_CODE equals the zone code. If there is no such entry, raise
|
||||
{{P}}CX_UNKNOWN_ZONE and set MV_ZONE_CODE to the zone code.
|
||||
4. If the weight is greater than MAX_WEIGHT_KG, raise {{P}}CX_WEIGHT_LIMIT. Set
|
||||
MV_ZONE_CODE to the zone code, MV_WEIGHT_KG to the given weight and
|
||||
MV_MAX_WEIGHT_KG to MAX_WEIGHT_KG.
|
||||
5. Calculate the cost as BASE_FEE + weight x PRICE_PER_KG.
|
||||
6. If IV_EXPRESS is ABAP_TRUE, multiply the cost by 1.5.
|
||||
7. Keep the full precision of the cost until this step. Do not round the cost
|
||||
before this step. Round the cost to 2 decimal places with commercial rounding.
|
||||
8. If the rounded cost is less than 6.00, use 6.00.
|
||||
9. Return the cost in COST and the CURRENCY of the zone in CURRENCY.
|
||||
|
||||
GET_REASON_TEXT returns:
|
||||
- in {{P}}CX_UNKNOWN_ZONE: 'Zone ', then the zone code, then ' is not known'.
|
||||
Example: 'Zone XX99 is not known'.
|
||||
- in {{P}}CX_INVALID_WEIGHT: 'Weight must be greater than zero'.
|
||||
- in {{P}}CX_WEIGHT_LIMIT: 'Weight exceeds the zone limit'.
|
||||
|
||||
# 6. Constraints
|
||||
- Release target: SAP_BASIS 816 (ABAP Platform 2025).
|
||||
- Coding standards: Clean ABAP. Methods below 40 statements. No global variables.
|
||||
- Out of scope: do not change {{P}}ZONE_MASTER.
|
||||
|
||||
# 7. Acceptance
|
||||
- All classes are active and have no syntax error.
|
||||
- The hidden tests pass.
|
||||
- Write your own ABAP Unit tests for {{P}}FREIGHT_CALC.
|
||||
90
tasks_gen/eval/G0005/task.json
Normal file
90
tasks_gen/eval/G0005/task.json
Normal file
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"id": "G0005",
|
||||
"category": "D",
|
||||
"object_type": "CLAS",
|
||||
"difficulty": 2,
|
||||
"release_target": "v816",
|
||||
"expected_outcome": "implement",
|
||||
"budget": {
|
||||
"max_tool_calls": 60,
|
||||
"max_activations": 20
|
||||
},
|
||||
"seed": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}ZONE_MASTER",
|
||||
"file": "seed/zone_master.clas.abap",
|
||||
"description": "Zone master data provider"
|
||||
}
|
||||
],
|
||||
"contract": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}CX_FREIGHT_ERROR"
|
||||
},
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}CX_UNKNOWN_ZONE"
|
||||
},
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}CX_INVALID_WEIGHT"
|
||||
},
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}CX_WEIGHT_LIMIT"
|
||||
},
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}FREIGHT_CALC"
|
||||
}
|
||||
],
|
||||
"out_of_scope": [
|
||||
"{{P}}ZONE_MASTER"
|
||||
],
|
||||
"hidden_tests": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}T02_HIDDEN",
|
||||
"file": "hidden/t02_hidden.clas.abap",
|
||||
"description": "T02 hidden tests"
|
||||
}
|
||||
],
|
||||
"reference": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}CX_FREIGHT_ERROR",
|
||||
"file": "reference/cx_freight_error.clas.abap",
|
||||
"description": "Abstract base exception"
|
||||
},
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}CX_UNKNOWN_ZONE",
|
||||
"file": "reference/cx_unknown_zone.clas.abap",
|
||||
"description": "Unknown zone exception"
|
||||
},
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}CX_INVALID_WEIGHT",
|
||||
"file": "reference/cx_invalid_weight.clas.abap",
|
||||
"description": "Invalid weight exception"
|
||||
},
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}CX_WEIGHT_LIMIT",
|
||||
"file": "reference/cx_weight_limit.clas.abap",
|
||||
"description": "Weight limit exception"
|
||||
},
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}FREIGHT_CALC",
|
||||
"file": "reference/freight_calc.clas.abap",
|
||||
"description": "Freight cost calculator",
|
||||
"testclasses_file": "reference/freight_calc.testclasses.abap"
|
||||
}
|
||||
],
|
||||
"craft_checks": [
|
||||
"method_length",
|
||||
"exception_handling"
|
||||
]
|
||||
}
|
||||
30
tasks_gen/eval/G0006/generation.json
Normal file
30
tasks_gen/eval/G0006/generation.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"id": "G0006",
|
||||
"pool": "eval",
|
||||
"object_type": "CLAS",
|
||||
"category": "E",
|
||||
"attempts": [
|
||||
{
|
||||
"stage": "validate",
|
||||
"oracle": null,
|
||||
"null": null
|
||||
},
|
||||
{
|
||||
"stage": "validate",
|
||||
"oracle": null,
|
||||
"null": null
|
||||
},
|
||||
{
|
||||
"stage": "bundle",
|
||||
"errors": [
|
||||
"invalid JSON: Expecting value: line 1 column 1 (char 0)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"stage": "validate",
|
||||
"oracle": null,
|
||||
"null": null
|
||||
}
|
||||
],
|
||||
"accepted": false
|
||||
}
|
||||
154
tasks_gen/eval/G0006/hidden/t02_hidden.clas.abap
Normal file
154
tasks_gen/eval/G0006/hidden/t02_hidden.clas.abap
Normal file
@@ -0,0 +1,154 @@
|
||||
CLASS {{p}}t02_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
|
||||
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
|
||||
|
||||
PRIVATE SECTION.
|
||||
DATA mo_cut TYPE REF TO {{p}}freight_calculator.
|
||||
|
||||
METHODS setup.
|
||||
METHODS assert_calculation
|
||||
IMPORTING iv_weight_kg TYPE p LENGTH 8 DECIMALS 2
|
||||
iv_zone TYPE string
|
||||
iv_express TYPE abap_bool DEFAULT abap_false
|
||||
is_expected TYPE {{p}}freight_calculator=>ty_result.
|
||||
|
||||
METHODS standard_parcel FOR TESTING.
|
||||
METHODS express_parcel FOR TESTING.
|
||||
METHODS zone_normalization FOR TESTING.
|
||||
METHODS rounding_half_up FOR TESTING.
|
||||
METHODS zero_weight FOR TESTING.
|
||||
METHODS negative_weight FOR TESTING.
|
||||
METHODS unknown_zone FOR TESTING.
|
||||
METHODS weight_error_wins FOR TESTING.
|
||||
METHODS supported_zones FOR TESTING.
|
||||
METHODS unsupported_zones FOR TESTING.
|
||||
METHODS all_rates FOR TESTING.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}t02_hidden IMPLEMENTATION.
|
||||
METHOD setup.
|
||||
mo_cut = NEW {{p}}freight_calculator( ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD assert_calculation.
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = is_expected
|
||||
act = mo_cut->calculate( iv_weight_kg = iv_weight_kg
|
||||
iv_zone = iv_zone
|
||||
iv_express = iv_express )
|
||||
msg = |zone { iv_zone }| ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD standard_parcel.
|
||||
assert_calculation(
|
||||
iv_weight_kg = '10.00'
|
||||
iv_zone = `DE`
|
||||
is_expected = VALUE #( status = {{p}}freight_calculator=>c_status-ok
|
||||
base = '45.00'
|
||||
surcharge = '0.00'
|
||||
total = '45.00' ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD express_parcel.
|
||||
assert_calculation(
|
||||
iv_weight_kg = '10.00'
|
||||
iv_zone = `DE`
|
||||
iv_express = abap_true
|
||||
is_expected = VALUE #( status = {{p}}freight_calculator=>c_status-ok
|
||||
base = '45.00'
|
||||
surcharge = '11.25'
|
||||
total = '56.25' ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD zone_normalization.
|
||||
assert_calculation(
|
||||
iv_weight_kg = '5.00'
|
||||
iv_zone = ` ch `
|
||||
is_expected = VALUE #( status = {{p}}freight_calculator=>c_status-ok
|
||||
base = '39.00'
|
||||
total = '39.00' ) ).
|
||||
assert_calculation(
|
||||
iv_weight_kg = '5.00'
|
||||
iv_zone = `de`
|
||||
is_expected = VALUE #( status = {{p}}freight_calculator=>c_status-ok
|
||||
base = '22.50'
|
||||
total = '22.50' ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD rounding_half_up.
|
||||
assert_calculation(
|
||||
iv_weight_kg = '3.33'
|
||||
iv_zone = `DE`
|
||||
iv_express = abap_true
|
||||
is_expected = VALUE #( status = {{p}}freight_calculator=>c_status-ok
|
||||
base = '14.99'
|
||||
surcharge = '3.75'
|
||||
total = '18.74' ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD zero_weight.
|
||||
assert_calculation(
|
||||
iv_weight_kg = '0.00'
|
||||
iv_zone = `DE`
|
||||
is_expected = VALUE #( status = {{p}}freight_calculator=>c_status-weight ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD negative_weight.
|
||||
assert_calculation(
|
||||
iv_weight_kg = '-2.50'
|
||||
iv_zone = `DE`
|
||||
iv_express = abap_true
|
||||
is_expected = VALUE #( status = {{p}}freight_calculator=>c_status-weight ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD unknown_zone.
|
||||
assert_calculation(
|
||||
iv_weight_kg = '5.00'
|
||||
iv_zone = `XX`
|
||||
is_expected = VALUE #( status = {{p}}freight_calculator=>c_status-zone ) ).
|
||||
assert_calculation(
|
||||
iv_weight_kg = '5.00'
|
||||
iv_zone = `DEU`
|
||||
is_expected = VALUE #( status = {{p}}freight_calculator=>c_status-zone ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD weight_error_wins.
|
||||
assert_calculation(
|
||||
iv_weight_kg = '0.00'
|
||||
iv_zone = `XX`
|
||||
is_expected = VALUE #( status = {{p}}freight_calculator=>c_status-weight ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD supported_zones.
|
||||
cl_abap_unit_assert=>assert_equals( exp = abap_true act = mo_cut->is_zone_supported( `de` ) msg = `de` ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = abap_true act = mo_cut->is_zone_supported( ` DE ` ) msg = ` DE ` ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = abap_true act = mo_cut->is_zone_supported( `at` ) msg = `at` ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = abap_true act = mo_cut->is_zone_supported( `es` ) msg = `es` ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD unsupported_zones.
|
||||
DATA lv_empty TYPE string.
|
||||
cl_abap_unit_assert=>assert_equals( exp = abap_false act = mo_cut->is_zone_supported( `XX` ) msg = `XX` ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = abap_false act = mo_cut->is_zone_supported( lv_empty ) msg = `empty` ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = abap_false act = mo_cut->is_zone_supported( ` ` ) msg = `blanks` ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = abap_false act = mo_cut->is_zone_supported( `DEU` ) msg = `DEU` ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = abap_false act = mo_cut->is_zone_supported( `DE1` ) msg = `DE1` ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD all_rates.
|
||||
assert_calculation( iv_weight_kg = '1.00' iv_zone = `DE`
|
||||
is_expected = VALUE #( status = {{p}}freight_calculator=>c_status-ok base = '4.50' total = '4.50' ) ).
|
||||
assert_calculation( iv_weight_kg = '1.00' iv_zone = `AT`
|
||||
is_expected = VALUE #( status = {{p}}freight_calculator=>c_status-ok base = '5.20' total = '5.20' ) ).
|
||||
assert_calculation( iv_weight_kg = '1.00' iv_zone = `CH`
|
||||
is_expected = VALUE #( status = {{p}}freight_calculator=>c_status-ok base = '7.80' total = '7.80' ) ).
|
||||
assert_calculation( iv_weight_kg = '1.00' iv_zone = `FR`
|
||||
is_expected = VALUE #( status = {{p}}freight_calculator=>c_status-ok base = '6.40' total = '6.40' ) ).
|
||||
assert_calculation( iv_weight_kg = '1.00' iv_zone = `NL`
|
||||
is_expected = VALUE #( status = {{p}}freight_calculator=>c_status-ok base = '4.90' total = '4.90' ) ).
|
||||
assert_calculation( iv_weight_kg = '1.00' iv_zone = `PL`
|
||||
is_expected = VALUE #( status = {{p}}freight_calculator=>c_status-ok base = '5.10' total = '5.10' ) ).
|
||||
assert_calculation( iv_weight_kg = '1.00' iv_zone = `ES`
|
||||
is_expected = VALUE #( status = {{p}}freight_calculator=>c_status-ok base = '6.90' total = '6.90' ) ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
130
tasks_gen/eval/G0006/reference/freight_calculator.clas.abap
Normal file
130
tasks_gen/eval/G0006/reference/freight_calculator.clas.abap
Normal file
@@ -0,0 +1,130 @@
|
||||
CLASS {{p}}freight_calculator DEFINITION PUBLIC FINAL CREATE PUBLIC.
|
||||
PUBLIC SECTION.
|
||||
TYPES:
|
||||
BEGIN OF ty_result,
|
||||
status TYPE c LENGTH 10,
|
||||
base TYPE p LENGTH 9 DECIMALS 2,
|
||||
surcharge TYPE p LENGTH 9 DECIMALS 2,
|
||||
total TYPE p LENGTH 9 DECIMALS 2,
|
||||
END OF ty_result.
|
||||
|
||||
CONSTANTS:
|
||||
BEGIN OF c_status,
|
||||
ok TYPE c LENGTH 10 VALUE 'OK',
|
||||
weight TYPE c LENGTH 10 VALUE 'WEIGHT',
|
||||
zone TYPE c LENGTH 10 VALUE 'ZONE',
|
||||
END OF c_status.
|
||||
|
||||
METHODS calculate
|
||||
IMPORTING
|
||||
iv_weight_kg TYPE p LENGTH 8 DECIMALS 2
|
||||
iv_zone TYPE string
|
||||
iv_express TYPE abap_bool DEFAULT abap_false
|
||||
RETURNING
|
||||
VALUE(rs_result) TYPE ty_result.
|
||||
|
||||
METHODS is_zone_supported
|
||||
IMPORTING
|
||||
iv_zone TYPE string
|
||||
RETURNING
|
||||
VALUE(rv_supported) TYPE abap_bool.
|
||||
|
||||
PRIVATE SECTION.
|
||||
TYPES:
|
||||
BEGIN OF ty_rate,
|
||||
zone TYPE c LENGTH 2,
|
||||
rate TYPE p LENGTH 6 DECIMALS 2,
|
||||
END OF ty_rate,
|
||||
tt_rate TYPE HASHED TABLE OF ty_rate WITH UNIQUE KEY zone.
|
||||
|
||||
CONSTANTS c_express_share TYPE p LENGTH 5 DECIMALS 2 VALUE '0.25'.
|
||||
|
||||
METHODS normalize_zone
|
||||
IMPORTING iv_zone TYPE string
|
||||
RETURNING VALUE(rv_zone) TYPE string.
|
||||
METHODS rates
|
||||
RETURNING VALUE(rt_rate) TYPE tt_rate.
|
||||
METHODS rate_for_zone
|
||||
IMPORTING iv_zone TYPE string
|
||||
RETURNING VALUE(rv_rate) TYPE p LENGTH 6 DECIMALS 2.
|
||||
METHODS empty_result
|
||||
IMPORTING iv_status TYPE c LENGTH 10
|
||||
RETURNING VALUE(rs_result) TYPE ty_result.
|
||||
METHODS base_amount
|
||||
IMPORTING iv_rate TYPE p LENGTH 6 DECIMALS 2
|
||||
iv_weight_kg TYPE p LENGTH 8 DECIMALS 2
|
||||
RETURNING VALUE(rv_base) TYPE p LENGTH 9 DECIMALS 2.
|
||||
METHODS surcharge_amount
|
||||
IMPORTING iv_base TYPE p LENGTH 9 DECIMALS 2
|
||||
iv_express TYPE abap_bool
|
||||
RETURNING VALUE(rv_surcharge) TYPE p LENGTH 9 DECIMALS 2.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}freight_calculator IMPLEMENTATION.
|
||||
METHOD calculate.
|
||||
DATA(lv_zone) = normalize_zone( iv_zone ).
|
||||
|
||||
IF iv_weight_kg <= 0.
|
||||
rs_result = empty_result( c_status-weight ).
|
||||
RETURN.
|
||||
ENDIF.
|
||||
|
||||
IF is_zone_supported( lv_zone ) = abap_false.
|
||||
rs_result = empty_result( c_status-zone ).
|
||||
RETURN.
|
||||
ENDIF.
|
||||
|
||||
rs_result-base = base_amount( iv_rate = rate_for_zone( lv_zone )
|
||||
iv_weight_kg = iv_weight_kg ).
|
||||
rs_result-surcharge = surcharge_amount( iv_base = rs_result-base
|
||||
iv_express = iv_express ).
|
||||
rs_result-total = rs_result-base + rs_result-surcharge.
|
||||
rs_result-status = c_status-ok.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD is_zone_supported.
|
||||
DATA(lv_zone) = normalize_zone( iv_zone ).
|
||||
DATA(lt_rate) = rates( ).
|
||||
rv_supported = xsdbool( line_exists( lt_rate[ zone = lv_zone ] ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD normalize_zone.
|
||||
rv_zone = to_upper( replace( val = iv_zone sub = ` ` with = `` occ = 0 ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD rates.
|
||||
rt_rate = VALUE #( ( zone = 'DE' rate = '4.50' )
|
||||
( zone = 'AT' rate = '5.20' )
|
||||
( zone = 'CH' rate = '7.80' )
|
||||
( zone = 'FR' rate = '6.40' )
|
||||
( zone = 'NL' rate = '4.90' )
|
||||
( zone = 'PL' rate = '5.10' )
|
||||
( zone = 'ES' rate = '6.90' ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD rate_for_zone.
|
||||
DATA(lt_rate) = rates( ).
|
||||
READ TABLE lt_rate WITH TABLE KEY zone = iv_zone INTO DATA(ls_rate).
|
||||
rv_rate = ls_rate-rate.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD empty_result.
|
||||
rs_result = VALUE #( status = iv_status ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD base_amount.
|
||||
DATA lv_amount TYPE p LENGTH 13 DECIMALS 4.
|
||||
lv_amount = iv_rate * iv_weight_kg.
|
||||
rv_base = round( val = lv_amount dec = 2 ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD surcharge_amount.
|
||||
IF iv_express = abap_false.
|
||||
RETURN.
|
||||
ENDIF.
|
||||
DATA lv_amount TYPE p LENGTH 13 DECIMALS 4.
|
||||
lv_amount = iv_base * c_express_share.
|
||||
rv_surcharge = round( val = lv_amount dec = 2 ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
@@ -0,0 +1,56 @@
|
||||
CLASS ltc_freight_calculator DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
|
||||
PRIVATE SECTION.
|
||||
DATA mo_cut TYPE REF TO {{p}}freight_calculator.
|
||||
METHODS setup.
|
||||
METHODS base_parcel FOR TESTING.
|
||||
METHODS express_parcel FOR TESTING.
|
||||
METHODS zone_is_normalized FOR TESTING.
|
||||
METHODS weight_error FOR TESTING.
|
||||
METHODS unknown_zone FOR TESTING.
|
||||
METHODS zone_support FOR TESTING.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS ltc_freight_calculator IMPLEMENTATION.
|
||||
METHOD setup.
|
||||
mo_cut = NEW {{p}}freight_calculator( ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD base_parcel.
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = VALUE {{p}}freight_calculator=>ty_result( status = 'OK' base = '45.00' total = '45.00' )
|
||||
act = mo_cut->calculate( iv_weight_kg = '10.00' iv_zone = `DE` ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD express_parcel.
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = VALUE {{p}}freight_calculator=>ty_result( status = 'OK'
|
||||
base = '45.00'
|
||||
surcharge = '11.25'
|
||||
total = '56.25' )
|
||||
act = mo_cut->calculate( iv_weight_kg = '10.00' iv_zone = `DE` iv_express = abap_true ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD zone_is_normalized.
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = VALUE {{p}}freight_calculator=>ty_result( status = 'OK' base = '39.00' total = '39.00' )
|
||||
act = mo_cut->calculate( iv_weight_kg = '5.00' iv_zone = ` ch ` ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD weight_error.
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = VALUE {{p}}freight_calculator=>ty_result( status = 'WEIGHT' )
|
||||
act = mo_cut->calculate( iv_weight_kg = '0.00' iv_zone = `DE` ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD unknown_zone.
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = VALUE {{p}}freight_calculator=>ty_result( status = 'ZONE' )
|
||||
act = mo_cut->calculate( iv_weight_kg = '5.00' iv_zone = `XX` ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD zone_support.
|
||||
cl_abap_unit_assert=>assert_true( mo_cut->is_zone_supported( `de` ) ).
|
||||
cl_abap_unit_assert=>assert_false( mo_cut->is_zone_supported( `XX` ) ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
106
tasks_gen/eval/G0006/seed/freight_calculator.clas.abap
Normal file
106
tasks_gen/eval/G0006/seed/freight_calculator.clas.abap
Normal file
@@ -0,0 +1,106 @@
|
||||
CLASS {{p}}freight_calculator DEFINITION PUBLIC FINAL CREATE PUBLIC.
|
||||
PUBLIC SECTION.
|
||||
TYPES:
|
||||
BEGIN OF ty_result,
|
||||
status TYPE c LENGTH 10,
|
||||
base TYPE p LENGTH 9 DECIMALS 2,
|
||||
surcharge TYPE p LENGTH 9 DECIMALS 2,
|
||||
total TYPE p LENGTH 9 DECIMALS 2,
|
||||
END OF ty_result.
|
||||
|
||||
CONSTANTS:
|
||||
BEGIN OF c_status,
|
||||
ok TYPE c LENGTH 10 VALUE 'OK',
|
||||
weight TYPE c LENGTH 10 VALUE 'WEIGHT',
|
||||
zone TYPE c LENGTH 10 VALUE 'ZONE',
|
||||
END OF c_status.
|
||||
|
||||
METHODS calculate
|
||||
IMPORTING
|
||||
iv_weight_kg TYPE p LENGTH 8 DECIMALS 2
|
||||
iv_zone TYPE string
|
||||
iv_express TYPE abap_bool DEFAULT abap_false
|
||||
RETURNING
|
||||
VALUE(rs_result) TYPE ty_result.
|
||||
|
||||
METHODS is_zone_supported
|
||||
IMPORTING
|
||||
iv_zone TYPE string
|
||||
RETURNING
|
||||
VALUE(rv_supported) TYPE abap_bool.
|
||||
|
||||
PRIVATE SECTION.
|
||||
DATA mv_last_zone TYPE string.
|
||||
CONSTANTS c_express_share TYPE p LENGTH 5 DECIMALS 2 VALUE '0.25'.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}freight_calculator IMPLEMENTATION.
|
||||
METHOD calculate.
|
||||
DATA lv_zone TYPE string.
|
||||
DATA lv_rate TYPE p LENGTH 6 DECIMALS 2.
|
||||
DATA lv_amount TYPE p LENGTH 13 DECIMALS 4.
|
||||
DATA lv_express TYPE abap_bool.
|
||||
|
||||
lv_zone = to_upper( replace( val = iv_zone sub = ` ` with = `` occ = 0 ) ).
|
||||
mv_last_zone = lv_zone.
|
||||
|
||||
IF iv_weight_kg <= 0.
|
||||
rs_result-status = 'WEIGHT'.
|
||||
rs_result-base = 0.
|
||||
rs_result-surcharge = 0.
|
||||
rs_result-total = 0.
|
||||
RETURN.
|
||||
ENDIF.
|
||||
|
||||
* IF lv_zone = 'BE'.
|
||||
* lv_rate = '5.60'.
|
||||
* ENDIF.
|
||||
IF lv_zone = 'DE'.
|
||||
lv_rate = '4.50'.
|
||||
ELSEIF lv_zone = 'AT'.
|
||||
lv_rate = '5.20'.
|
||||
ELSEIF lv_zone = 'CH'.
|
||||
lv_rate = '7.80'.
|
||||
ELSEIF lv_zone = 'FR'.
|
||||
lv_rate = '6.40'.
|
||||
ELSEIF lv_zone = 'NL'.
|
||||
lv_rate = '4.90'.
|
||||
ELSEIF lv_zone = 'PL'.
|
||||
lv_rate = '5.10'.
|
||||
ELSEIF lv_zone = 'ES'.
|
||||
lv_rate = '6.90'.
|
||||
ELSE.
|
||||
rs_result-status = 'ZONE'.
|
||||
rs_result-base = 0.
|
||||
rs_result-surcharge = 0.
|
||||
rs_result-total = 0.
|
||||
RETURN.
|
||||
ENDIF.
|
||||
|
||||
lv_amount = lv_rate * iv_weight_kg.
|
||||
rs_result-base = round( val = lv_amount dec = 2 ).
|
||||
|
||||
lv_express = iv_express.
|
||||
IF lv_express = abap_true.
|
||||
lv_amount = rs_result-base * c_express_share.
|
||||
rs_result-surcharge = round( val = lv_amount dec = 2 ).
|
||||
ELSE.
|
||||
rs_result-surcharge = 0.
|
||||
ENDIF.
|
||||
|
||||
rs_result-total = rs_result-base + rs_result-surcharge.
|
||||
rs_result-status = 'OK'.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD is_zone_supported.
|
||||
DATA lv_zone TYPE string.
|
||||
lv_zone = to_upper( replace( val = iv_zone sub = ` ` with = `` occ = 0 ) ).
|
||||
IF lv_zone = 'DE' OR lv_zone = 'AT' OR lv_zone = 'CH' OR lv_zone = 'FR'
|
||||
OR lv_zone = 'NL' OR lv_zone = 'PL' OR lv_zone = 'ES'.
|
||||
rv_supported = abap_true.
|
||||
ELSE.
|
||||
rv_supported = abap_false.
|
||||
ENDIF.
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
@@ -0,0 +1,25 @@
|
||||
CLASS ltc_legacy_freight DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
|
||||
PRIVATE SECTION.
|
||||
METHODS base_parcel FOR TESTING.
|
||||
METHODS express_parcel FOR TESTING.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS ltc_legacy_freight IMPLEMENTATION.
|
||||
METHOD base_parcel.
|
||||
DATA(lo_cut) = NEW {{p}}freight_calculator( ).
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = VALUE {{p}}freight_calculator=>ty_result( status = 'OK' base = '45.00' total = '45.00' )
|
||||
act = lo_cut->calculate( iv_weight_kg = '10.00' iv_zone = `DE` ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD express_parcel.
|
||||
DATA(lo_cut) = NEW {{p}}freight_calculator( ).
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = VALUE {{p}}freight_calculator=>ty_result( status = 'OK'
|
||||
base = '45.00'
|
||||
surcharge = '11.25'
|
||||
total = '56.25' )
|
||||
act = lo_cut->calculate( iv_weight_kg = '10.00' iv_zone = `DE` iv_express = abap_true ) ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
67
tasks_gen/eval/G0006/spec.md
Normal file
67
tasks_gen/eval/G0006/spec.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# 1. Goal
|
||||
Refactor the class {{P}}FREIGHT_CALCULATOR. The class calculates the freight cost of a
|
||||
parcel. The calculation is correct, but the code is hard to read and hard to maintain.
|
||||
Make the code clean. The behavior and the public API must not change.
|
||||
|
||||
# 2. Open questions
|
||||
None.
|
||||
|
||||
# 3. Context
|
||||
- The class {{P}}FREIGHT_CALCULATOR exists in package $TMP. It is active.
|
||||
- The class contains legacy code: one long method, nested IF blocks, hard-coded
|
||||
numbers, a private attribute that is written but never read, and commented-out code.
|
||||
- A logistics program calls the class. That program must continue to work without a
|
||||
change. Therefore the behavior of the class must stay the same.
|
||||
|
||||
# 4. Contract
|
||||
The public part of the class must stay exactly as it is:
|
||||
- The class {{P}}FREIGHT_CALCULATOR is public, final, and has a public constructor
|
||||
without parameters.
|
||||
- Public type TY_RESULT with these components: STATUS TYPE c LENGTH 10,
|
||||
BASE TYPE p LENGTH 9 DECIMALS 2, SURCHARGE TYPE p LENGTH 9 DECIMALS 2,
|
||||
TOTAL TYPE p LENGTH 9 DECIMALS 2.
|
||||
- Public constant structure C_STATUS with the components OK, WEIGHT and ZONE. Each
|
||||
component has the type c LENGTH 10. The values are 'OK', 'WEIGHT' and 'ZONE'.
|
||||
- Public method CALCULATE:
|
||||
IMPORTING iv_weight_kg TYPE p LENGTH 8 DECIMALS 2
|
||||
iv_zone TYPE string
|
||||
iv_express TYPE abap_bool DEFAULT abap_false
|
||||
RETURNING VALUE(rs_result) TYPE ty_result.
|
||||
- Public method IS_ZONE_SUPPORTED:
|
||||
IMPORTING iv_zone TYPE string
|
||||
RETURNING VALUE(rv_supported) TYPE abap_bool.
|
||||
- Do not add other public components or public methods.
|
||||
|
||||
# 5. Business rules
|
||||
The rules below describe the behavior of the class. The behavior must not change.
|
||||
1. Normalize the zone: remove all blanks and convert all letters to upper case. A
|
||||
zone is known only if the normalized zone is exactly equal to a zone code. Do not
|
||||
shorten the zone and do not extend the zone.
|
||||
2. Check the weight first. If the weight is not greater than zero, return the status
|
||||
WEIGHT with BASE, SURCHARGE and TOTAL equal to zero. This check comes before the
|
||||
zone check.
|
||||
3. If the normalized zone is not known, return the status ZONE with BASE, SURCHARGE
|
||||
and TOTAL equal to zero.
|
||||
4. The rate per kilogram depends on the zone: DE 4.50, AT 5.20, CH 7.80, FR 6.40,
|
||||
NL 4.90, PL 5.10, ES 6.90.
|
||||
5. BASE = rate x weight. Round BASE to 2 decimal places. Round half away from zero.
|
||||
6. If iv_express is abap_true, SURCHARGE = BASE x 25 / 100, rounded to 2 decimal
|
||||
places. Else SURCHARGE is zero.
|
||||
7. TOTAL = BASE + SURCHARGE.
|
||||
8. Return the status OK.
|
||||
9. IS_ZONE_SUPPORTED returns abap_true if the normalized zone is known, else
|
||||
abap_false. A blank zone is not known.
|
||||
|
||||
# 6. Constraints
|
||||
- Release target: SAP_BASIS 816 (ABAP Platform 2025).
|
||||
- Coding standards: Clean ABAP. Every method has less than 40 statements. No global
|
||||
variables. No IF block nested deeper than 2 levels. No hard-coded rate in a
|
||||
statement: use a constant or a table. Remove the private attribute that is never
|
||||
read. Remove the commented-out code. No comment that restates the code.
|
||||
- Out of scope: do not change the public API, do not change the behavior, do not
|
||||
create new global objects, do not change the class name.
|
||||
|
||||
# 7. Acceptance
|
||||
- The class is active and has no syntax error.
|
||||
- The hidden tests pass.
|
||||
- Write your own ABAP Unit tests as local test classes in the class.
|
||||
54
tasks_gen/eval/G0006/task.json
Normal file
54
tasks_gen/eval/G0006/task.json
Normal file
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"id": "G0006",
|
||||
"category": "E",
|
||||
"object_type": "CLAS",
|
||||
"difficulty": 2,
|
||||
"release_target": "v816",
|
||||
"expected_outcome": "implement",
|
||||
"budget": {
|
||||
"max_tool_calls": 60,
|
||||
"max_activations": 15
|
||||
},
|
||||
"seed": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}FREIGHT_CALCULATOR",
|
||||
"file": "seed/freight_calculator.clas.abap",
|
||||
"description": "Legacy freight calculator. Correct behavior, poor structure: one long method, nested IF blocks, hard-coded rates, a private attribute that is written but never read, commented-out code."
|
||||
}
|
||||
],
|
||||
"contract": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}FREIGHT_CALCULATOR"
|
||||
}
|
||||
],
|
||||
"out_of_scope": [
|
||||
"New global objects",
|
||||
"Changes to the public API of {{P}}FREIGHT_CALCULATOR",
|
||||
"Changes to the result of the calculation"
|
||||
],
|
||||
"hidden_tests": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}T02_HIDDEN",
|
||||
"file": "hidden/t02_hidden.clas.abap",
|
||||
"description": "T02 hidden tests for the refactored freight calculator"
|
||||
}
|
||||
],
|
||||
"reference": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}FREIGHT_CALCULATOR",
|
||||
"file": "reference/freight_calculator.clas.abap",
|
||||
"description": "Refactored freight calculator with extracted methods and a rate table",
|
||||
"testclasses_file": "reference/freight_calculator.testclasses.abap"
|
||||
}
|
||||
],
|
||||
"craft_checks": [
|
||||
"method_length",
|
||||
"nesting_depth",
|
||||
"magic_number",
|
||||
"dead_code"
|
||||
]
|
||||
}
|
||||
14
tasks_gen/eval/G0007/generation.json
Normal file
14
tasks_gen/eval/G0007/generation.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"id": "G0007",
|
||||
"pool": "eval",
|
||||
"object_type": "CLAS",
|
||||
"category": "F",
|
||||
"attempts": [
|
||||
{
|
||||
"stage": "validate",
|
||||
"oracle": 100.0,
|
||||
"null": 0
|
||||
}
|
||||
],
|
||||
"accepted": true
|
||||
}
|
||||
103
tasks_gen/eval/G0007/hidden/t02_hidden.clas.abap
Normal file
103
tasks_gen/eval/G0007/hidden/t02_hidden.clas.abap
Normal file
@@ -0,0 +1,103 @@
|
||||
CLASS {{p}}t02_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
|
||||
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
|
||||
PRIVATE SECTION.
|
||||
DATA mo_cut TYPE REF TO {{p}}if_loyalty_rules.
|
||||
METHODS setup.
|
||||
METHODS tier_boundaries FOR TESTING.
|
||||
METHODS tier_negative FOR TESTING.
|
||||
METHODS tier_zero FOR TESTING.
|
||||
METHODS discount_all_tiers FOR TESTING.
|
||||
METHODS discount_unknown_tier FOR TESTING.
|
||||
METHODS next_tier_from_basic FOR TESTING.
|
||||
METHODS next_tier_from_silver FOR TESTING.
|
||||
METHODS next_tier_from_gold FOR TESTING.
|
||||
METHODS next_tier_from_platinum FOR TESTING.
|
||||
METHODS next_tier_negative_points FOR TESTING.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}t02_hidden IMPLEMENTATION.
|
||||
METHOD setup.
|
||||
mo_cut = NEW {{p}}loyalty_evaluator( ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD tier_boundaries.
|
||||
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_loyalty_rules=>c_tier-basic
|
||||
act = mo_cut->get_tier( 999 ) msg = `999` ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_loyalty_rules=>c_tier-silver
|
||||
act = mo_cut->get_tier( 1000 ) msg = `1000` ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_loyalty_rules=>c_tier-silver
|
||||
act = mo_cut->get_tier( 4999 ) msg = `4999` ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_loyalty_rules=>c_tier-gold
|
||||
act = mo_cut->get_tier( 5000 ) msg = `5000` ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_loyalty_rules=>c_tier-gold
|
||||
act = mo_cut->get_tier( 19999 ) msg = `19999` ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_loyalty_rules=>c_tier-platinum
|
||||
act = mo_cut->get_tier( 20000 ) msg = `20000` ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_loyalty_rules=>c_tier-platinum
|
||||
act = mo_cut->get_tier( 500000 ) msg = `500000` ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD tier_negative.
|
||||
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_loyalty_rules=>c_tier-basic
|
||||
act = mo_cut->get_tier( -1 ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_loyalty_rules=>c_tier-basic
|
||||
act = mo_cut->get_tier( -5000 ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD tier_zero.
|
||||
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_loyalty_rules=>c_tier-basic
|
||||
act = mo_cut->get_tier( 0 ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD discount_all_tiers.
|
||||
cl_abap_unit_assert=>assert_equals( exp = 0
|
||||
act = mo_cut->get_discount( {{p}}if_loyalty_rules=>c_tier-basic ) msg = `basic` ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 3
|
||||
act = mo_cut->get_discount( {{p}}if_loyalty_rules=>c_tier-silver ) msg = `silver` ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 7
|
||||
act = mo_cut->get_discount( {{p}}if_loyalty_rules=>c_tier-gold ) msg = `gold` ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 12
|
||||
act = mo_cut->get_discount( {{p}}if_loyalty_rules=>c_tier-platinum ) msg = `platinum` ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD discount_unknown_tier.
|
||||
cl_abap_unit_assert=>assert_equals( exp = 0
|
||||
act = mo_cut->get_discount( 'X' ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 0
|
||||
act = mo_cut->get_discount( ' ' ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD next_tier_from_basic.
|
||||
cl_abap_unit_assert=>assert_equals( exp = 1000
|
||||
act = mo_cut->points_to_next_tier( 0 ) msg = `0` ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 1
|
||||
act = mo_cut->points_to_next_tier( 999 ) msg = `999` ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD next_tier_from_silver.
|
||||
cl_abap_unit_assert=>assert_equals( exp = 4000
|
||||
act = mo_cut->points_to_next_tier( 1000 ) msg = `1000` ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 1
|
||||
act = mo_cut->points_to_next_tier( 4999 ) msg = `4999` ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD next_tier_from_gold.
|
||||
cl_abap_unit_assert=>assert_equals( exp = 15000
|
||||
act = mo_cut->points_to_next_tier( 5000 ) msg = `5000` ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 1
|
||||
act = mo_cut->points_to_next_tier( 19999 ) msg = `19999` ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD next_tier_from_platinum.
|
||||
cl_abap_unit_assert=>assert_equals( exp = 0
|
||||
act = mo_cut->points_to_next_tier( 20000 ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 0
|
||||
act = mo_cut->points_to_next_tier( 999999 ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD next_tier_negative_points.
|
||||
cl_abap_unit_assert=>assert_equals( exp = 1000
|
||||
act = mo_cut->points_to_next_tier( -7 ) ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
79
tasks_gen/eval/G0007/reference/loyalty_evaluator.clas.abap
Normal file
79
tasks_gen/eval/G0007/reference/loyalty_evaluator.clas.abap
Normal file
@@ -0,0 +1,79 @@
|
||||
CLASS {{p}}loyalty_evaluator DEFINITION PUBLIC FINAL CREATE PUBLIC.
|
||||
PUBLIC SECTION.
|
||||
INTERFACES {{p}}if_loyalty_rules.
|
||||
|
||||
PRIVATE SECTION.
|
||||
CONSTANTS:
|
||||
c_silver_threshold TYPE i VALUE 1000,
|
||||
c_gold_threshold TYPE i VALUE 5000,
|
||||
c_platinum_threshold TYPE i VALUE 20000.
|
||||
|
||||
METHODS normalize_points
|
||||
IMPORTING iv_points TYPE i
|
||||
RETURNING VALUE(rv_points) TYPE i.
|
||||
|
||||
METHODS tier_of
|
||||
IMPORTING iv_points TYPE i
|
||||
RETURNING VALUE(rv_tier) TYPE {{p}}if_loyalty_rules=>ty_tier.
|
||||
|
||||
METHODS points_to_tier
|
||||
IMPORTING iv_points TYPE i
|
||||
iv_tier TYPE {{p}}if_loyalty_rules=>ty_tier
|
||||
RETURNING VALUE(rv_points) TYPE i.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}loyalty_evaluator IMPLEMENTATION.
|
||||
METHOD {{p}}if_loyalty_rules~get_tier.
|
||||
rv_tier = tier_of( normalize_points( iv_points ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD {{p}}if_loyalty_rules~get_discount.
|
||||
CASE iv_tier.
|
||||
WHEN {{p}}if_loyalty_rules=>c_tier-silver.
|
||||
rv_percent = 3.
|
||||
WHEN {{p}}if_loyalty_rules=>c_tier-gold.
|
||||
rv_percent = 7.
|
||||
WHEN {{p}}if_loyalty_rules=>c_tier-platinum.
|
||||
rv_percent = 12.
|
||||
WHEN OTHERS.
|
||||
rv_percent = 0.
|
||||
ENDCASE.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD {{p}}if_loyalty_rules~points_to_next_tier.
|
||||
DATA(lv_points) = normalize_points( iv_points ).
|
||||
DATA(lv_tier) = tier_of( lv_points ).
|
||||
rv_points = points_to_tier( iv_points = lv_points
|
||||
iv_tier = lv_tier ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD normalize_points.
|
||||
rv_points = COND #( WHEN iv_points < 0 THEN 0 ELSE iv_points ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD tier_of.
|
||||
IF iv_points >= c_platinum_threshold.
|
||||
rv_tier = {{p}}if_loyalty_rules=>c_tier-platinum.
|
||||
ELSEIF iv_points >= c_gold_threshold.
|
||||
rv_tier = {{p}}if_loyalty_rules=>c_tier-gold.
|
||||
ELSEIF iv_points >= c_silver_threshold.
|
||||
rv_tier = {{p}}if_loyalty_rules=>c_tier-silver.
|
||||
ELSE.
|
||||
rv_tier = {{p}}if_loyalty_rules=>c_tier-basic.
|
||||
ENDIF.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD points_to_tier.
|
||||
CASE iv_tier.
|
||||
WHEN {{p}}if_loyalty_rules=>c_tier-basic.
|
||||
rv_points = c_silver_threshold - iv_points.
|
||||
WHEN {{p}}if_loyalty_rules=>c_tier-silver.
|
||||
rv_points = c_gold_threshold - iv_points.
|
||||
WHEN {{p}}if_loyalty_rules=>c_tier-gold.
|
||||
rv_points = c_platinum_threshold - iv_points.
|
||||
WHEN OTHERS.
|
||||
rv_points = 0.
|
||||
ENDCASE.
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
@@ -0,0 +1,77 @@
|
||||
CLASS ltc_loyalty_evaluator DEFINITION FINAL FOR TESTING
|
||||
DURATION SHORT RISK LEVEL HARMLESS.
|
||||
|
||||
PRIVATE SECTION.
|
||||
DATA mo_cut TYPE REF TO {{p}}if_loyalty_rules.
|
||||
|
||||
METHODS setup.
|
||||
METHODS tier_of_boundary_points FOR TESTING.
|
||||
METHODS negative_points_are_basic FOR TESTING.
|
||||
METHODS discount_of_each_tier FOR TESTING.
|
||||
METHODS discount_of_unknown_tier FOR TESTING.
|
||||
METHODS points_to_silver FOR TESTING.
|
||||
METHODS points_to_gold FOR TESTING.
|
||||
METHODS points_to_platinum FOR TESTING.
|
||||
METHODS platinum_needs_no_points FOR TESTING.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS ltc_loyalty_evaluator IMPLEMENTATION.
|
||||
METHOD setup.
|
||||
mo_cut = NEW {{p}}loyalty_evaluator( ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD tier_of_boundary_points.
|
||||
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_loyalty_rules=>c_tier-basic
|
||||
act = mo_cut->get_tier( 0 ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_loyalty_rules=>c_tier-silver
|
||||
act = mo_cut->get_tier( 1000 ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_loyalty_rules=>c_tier-gold
|
||||
act = mo_cut->get_tier( 5000 ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_loyalty_rules=>c_tier-platinum
|
||||
act = mo_cut->get_tier( 20000 ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD negative_points_are_basic.
|
||||
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_loyalty_rules=>c_tier-basic
|
||||
act = mo_cut->get_tier( -100 ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD discount_of_each_tier.
|
||||
cl_abap_unit_assert=>assert_equals( exp = 0
|
||||
act = mo_cut->get_discount( {{p}}if_loyalty_rules=>c_tier-basic ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 3
|
||||
act = mo_cut->get_discount( {{p}}if_loyalty_rules=>c_tier-silver ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 7
|
||||
act = mo_cut->get_discount( {{p}}if_loyalty_rules=>c_tier-gold ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 12
|
||||
act = mo_cut->get_discount( {{p}}if_loyalty_rules=>c_tier-platinum ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD discount_of_unknown_tier.
|
||||
cl_abap_unit_assert=>assert_equals( exp = 0
|
||||
act = mo_cut->get_discount( 'X' ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD points_to_silver.
|
||||
cl_abap_unit_assert=>assert_equals( exp = 1000
|
||||
act = mo_cut->points_to_next_tier( 0 ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 1
|
||||
act = mo_cut->points_to_next_tier( 999 ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD points_to_gold.
|
||||
cl_abap_unit_assert=>assert_equals( exp = 4000
|
||||
act = mo_cut->points_to_next_tier( 1000 ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD points_to_platinum.
|
||||
cl_abap_unit_assert=>assert_equals( exp = 15000
|
||||
act = mo_cut->points_to_next_tier( 5000 ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD platinum_needs_no_points.
|
||||
cl_abap_unit_assert=>assert_equals( exp = 0
|
||||
act = mo_cut->points_to_next_tier( 20000 ) ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
24
tasks_gen/eval/G0007/seed/if_loyalty_rules.intf.abap
Normal file
24
tasks_gen/eval/G0007/seed/if_loyalty_rules.intf.abap
Normal file
@@ -0,0 +1,24 @@
|
||||
INTERFACE {{p}}if_loyalty_rules PUBLIC.
|
||||
TYPES ty_points TYPE i.
|
||||
TYPES ty_tier TYPE c LENGTH 1.
|
||||
|
||||
CONSTANTS:
|
||||
BEGIN OF c_tier,
|
||||
basic TYPE ty_tier VALUE 'B',
|
||||
silver TYPE ty_tier VALUE 'S',
|
||||
gold TYPE ty_tier VALUE 'G',
|
||||
platinum TYPE ty_tier VALUE 'P',
|
||||
END OF c_tier.
|
||||
|
||||
METHODS get_tier
|
||||
IMPORTING iv_points TYPE ty_points
|
||||
RETURNING VALUE(rv_tier) TYPE ty_tier.
|
||||
|
||||
METHODS get_discount
|
||||
IMPORTING iv_tier TYPE ty_tier
|
||||
RETURNING VALUE(rv_percent) TYPE i.
|
||||
|
||||
METHODS points_to_next_tier
|
||||
IMPORTING iv_points TYPE ty_points
|
||||
RETURNING VALUE(rv_points) TYPE i.
|
||||
ENDINTERFACE.
|
||||
57
tasks_gen/eval/G0007/spec.md
Normal file
57
tasks_gen/eval/G0007/spec.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# 1. Goal
|
||||
A retail company gives loyalty discounts to its customers. A checkout program needs
|
||||
three values: the loyalty tier of a customer, the discount percent of a tier, and
|
||||
the number of points that a customer still needs for the next tier. The program
|
||||
calls one class for these three values.
|
||||
|
||||
# 2. Open questions
|
||||
None.
|
||||
|
||||
# 3. Context
|
||||
- The interface {{P}}IF_LOYALTY_RULES exists in package $TMP. It is active.
|
||||
- The interface declares the type of a point value, the type of a tier, the
|
||||
constants for all tiers, and three methods. This document does not repeat the
|
||||
signature of the interface. Read the interface before you start.
|
||||
- The three methods are:
|
||||
* the method that returns the tier for a point value,
|
||||
* the method that returns the discount percent of a tier,
|
||||
* the method that returns the number of points that are missing for the next tier.
|
||||
|
||||
# 4. Contract
|
||||
- Create the class {{P}}LOYALTY_EVALUATOR in package $TMP.
|
||||
- The class is public and final. It has a public constructor without parameters.
|
||||
- The class implements {{P}}IF_LOYALTY_RULES.
|
||||
- Do not add other public methods.
|
||||
|
||||
# 5. Business rules
|
||||
Tier of a point value:
|
||||
1. A point value below zero counts as zero.
|
||||
2. 0 to 999 points is the basic tier.
|
||||
3. 1000 to 4999 points is the silver tier.
|
||||
4. 5000 to 19999 points is the gold tier.
|
||||
5. 20000 points and more is the platinum tier.
|
||||
|
||||
Discount percent of a tier:
|
||||
6. basic is 0 percent.
|
||||
7. silver is 3 percent.
|
||||
8. gold is 7 percent.
|
||||
9. platinum is 12 percent.
|
||||
10. Any other tier value is 0 percent.
|
||||
|
||||
Points to the next tier:
|
||||
11. A point value below zero counts as zero.
|
||||
12. basic needs 1000 points minus the point value.
|
||||
13. silver needs 5000 points minus the point value.
|
||||
14. gold needs 20000 points minus the point value.
|
||||
15. platinum needs 0 points.
|
||||
|
||||
# 6. Constraints
|
||||
- Release target: 8.16.
|
||||
- Coding standards: Clean ABAP. Methods below 40 statements. No global variables.
|
||||
No comment that restates the code.
|
||||
- Out of scope: do not change {{P}}IF_LOYALTY_RULES.
|
||||
|
||||
# 7. Acceptance
|
||||
- The class is active and has no syntax error.
|
||||
- The hidden tests pass.
|
||||
- Write your own ABAP Unit tests for the class.
|
||||
51
tasks_gen/eval/G0007/task.json
Normal file
51
tasks_gen/eval/G0007/task.json
Normal file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"id": "G0007",
|
||||
"category": "F",
|
||||
"object_type": "CLAS",
|
||||
"difficulty": 2,
|
||||
"release_target": "v816",
|
||||
"expected_outcome": "implement",
|
||||
"budget": {
|
||||
"max_tool_calls": 40,
|
||||
"max_activations": 10
|
||||
},
|
||||
"seed": [
|
||||
{
|
||||
"type": "INTF",
|
||||
"name": "{{P}}IF_LOYALTY_RULES",
|
||||
"file": "seed/if_loyalty_rules.intf.abap",
|
||||
"description": "Loyalty contract: tier type, point type, tier constants and three methods. The spec does not repeat the signature."
|
||||
}
|
||||
],
|
||||
"contract": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}LOYALTY_EVALUATOR",
|
||||
"implements": "{{P}}IF_LOYALTY_RULES"
|
||||
}
|
||||
],
|
||||
"out_of_scope": [
|
||||
"{{P}}IF_LOYALTY_RULES"
|
||||
],
|
||||
"hidden_tests": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}T02_HIDDEN",
|
||||
"file": "hidden/t02_hidden.clas.abap",
|
||||
"description": "T02 hidden tests"
|
||||
}
|
||||
],
|
||||
"reference": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}LOYALTY_EVALUATOR",
|
||||
"file": "reference/loyalty_evaluator.clas.abap",
|
||||
"description": "Loyalty evaluator",
|
||||
"testclasses_file": "reference/loyalty_evaluator.testclasses.abap"
|
||||
}
|
||||
],
|
||||
"craft_checks": [
|
||||
"method_length",
|
||||
"nesting_depth"
|
||||
]
|
||||
}
|
||||
19
tasks_gen/eval/G0008/generation.json
Normal file
19
tasks_gen/eval/G0008/generation.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"id": "G0008",
|
||||
"pool": "eval",
|
||||
"object_type": "CLAS",
|
||||
"category": "G",
|
||||
"attempts": [
|
||||
{
|
||||
"stage": "validate",
|
||||
"oracle": 0,
|
||||
"null": 0
|
||||
},
|
||||
{
|
||||
"stage": "validate",
|
||||
"oracle": 100.0,
|
||||
"null": 0
|
||||
}
|
||||
],
|
||||
"accepted": true
|
||||
}
|
||||
197
tasks_gen/eval/G0008/hidden/t07_hidden.clas.abap
Normal file
197
tasks_gen/eval/G0008/hidden/t07_hidden.clas.abap
Normal file
@@ -0,0 +1,197 @@
|
||||
CLASS {{p}}t07_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
|
||||
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
|
||||
|
||||
PRIVATE SECTION.
|
||||
DATA mo_cut TYPE REF TO {{p}}if_freight_calc.
|
||||
|
||||
METHODS setup.
|
||||
METHODS assert_amount
|
||||
IMPORTING iv_expected TYPE {{p}}if_freight_calc=>ty_amount
|
||||
iv_actual TYPE {{p}}if_freight_calc=>ty_amount.
|
||||
METHODS assert_weight
|
||||
IMPORTING iv_expected TYPE {{p}}if_freight_calc=>ty_weight
|
||||
iv_actual TYPE {{p}}if_freight_calc=>ty_weight.
|
||||
|
||||
METHODS weight_not_positive FOR TESTING.
|
||||
METHODS volume_negative FOR TESTING.
|
||||
METHODS distance_not_positive FOR TESTING.
|
||||
METHODS fuel_index_negative FOR TESTING.
|
||||
METHODS fuel_index_too_high FOR TESTING.
|
||||
METHODS base_at_weight_limit FOR TESTING.
|
||||
METHODS base_above_weight_limit FOR TESTING.
|
||||
METHODS volumetric_weight_wins FOR TESTING.
|
||||
METHODS distance_component FOR TESTING.
|
||||
METHODS fuel_rounds_half_up FOR TESTING.
|
||||
METHODS full_load FOR TESTING.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}t07_hidden IMPLEMENTATION.
|
||||
|
||||
METHOD setup.
|
||||
DATA lo_calc TYPE REF TO {{p}}freight_calc.
|
||||
CREATE OBJECT lo_calc.
|
||||
mo_cut = lo_calc.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD assert_amount.
|
||||
cl_abap_unit_assert=>assert_equals( exp = iv_expected act = iv_actual ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD assert_weight.
|
||||
cl_abap_unit_assert=>assert_equals( exp = iv_expected act = iv_actual ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD weight_not_positive.
|
||||
DATA ls_result TYPE {{p}}if_freight_calc=>ty_result.
|
||||
|
||||
ls_result = mo_cut->calculate( iv_weight_kg = 0
|
||||
iv_volume_m3 = -1
|
||||
iv_distance_km = 0
|
||||
iv_fuel_index = 200 ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_freight_calc=>c_reason-weight
|
||||
act = ls_result-reason ).
|
||||
assert_amount( iv_expected = 0 iv_actual = ls_result-total ).
|
||||
assert_weight( iv_expected = 0 iv_actual = ls_result-chargeable_weight ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD volume_negative.
|
||||
DATA ls_result TYPE {{p}}if_freight_calc=>ty_result.
|
||||
|
||||
ls_result = mo_cut->calculate( iv_weight_kg = 1000
|
||||
iv_volume_m3 = '-0.5'
|
||||
iv_distance_km = 100
|
||||
iv_fuel_index = 50 ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_freight_calc=>c_reason-volume
|
||||
act = ls_result-reason ).
|
||||
assert_amount( iv_expected = 0 iv_actual = ls_result-total ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD distance_not_positive.
|
||||
DATA ls_result TYPE {{p}}if_freight_calc=>ty_result.
|
||||
|
||||
ls_result = mo_cut->calculate( iv_weight_kg = 1000
|
||||
iv_volume_m3 = 0
|
||||
iv_distance_km = 0
|
||||
iv_fuel_index = 50 ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_freight_calc=>c_reason-distance
|
||||
act = ls_result-reason ).
|
||||
assert_amount( iv_expected = 0 iv_actual = ls_result-total ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD fuel_index_negative.
|
||||
DATA ls_result TYPE {{p}}if_freight_calc=>ty_result.
|
||||
|
||||
ls_result = mo_cut->calculate( iv_weight_kg = 1000
|
||||
iv_volume_m3 = 0
|
||||
iv_distance_km = 100
|
||||
iv_fuel_index = '-0.1' ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_freight_calc=>c_reason-fuel
|
||||
act = ls_result-reason ).
|
||||
assert_amount( iv_expected = 0 iv_actual = ls_result-total ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD fuel_index_too_high.
|
||||
DATA ls_result TYPE {{p}}if_freight_calc=>ty_result.
|
||||
|
||||
ls_result = mo_cut->calculate( iv_weight_kg = 1000
|
||||
iv_volume_m3 = 0
|
||||
iv_distance_km = 100
|
||||
iv_fuel_index = '100.1' ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_freight_calc=>c_reason-fuel
|
||||
act = ls_result-reason ).
|
||||
assert_amount( iv_expected = 0 iv_actual = ls_result-total ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD base_at_weight_limit.
|
||||
DATA ls_result TYPE {{p}}if_freight_calc=>ty_result.
|
||||
|
||||
ls_result = mo_cut->calculate( iv_weight_kg = 1000
|
||||
iv_volume_m3 = 0
|
||||
iv_distance_km = 100
|
||||
iv_fuel_index = 0 ).
|
||||
|
||||
assert_weight( iv_expected = 1000 iv_actual = ls_result-chargeable_weight ).
|
||||
assert_amount( iv_expected = 45 iv_actual = ls_result-base ).
|
||||
assert_amount( iv_expected = 0 iv_actual = ls_result-distance ).
|
||||
assert_amount( iv_expected = 0 iv_actual = ls_result-fuel ).
|
||||
assert_amount( iv_expected = 45 iv_actual = ls_result-total ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_freight_calc=>c_reason-ok
|
||||
act = ls_result-reason ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD base_above_weight_limit.
|
||||
DATA ls_result TYPE {{p}}if_freight_calc=>ty_result.
|
||||
|
||||
ls_result = mo_cut->calculate( iv_weight_kg = '1100.5'
|
||||
iv_volume_m3 = 0
|
||||
iv_distance_km = 100
|
||||
iv_fuel_index = 0 ).
|
||||
|
||||
assert_weight( iv_expected = '1100.5' iv_actual = ls_result-chargeable_weight ).
|
||||
assert_amount( iv_expected = 58 iv_actual = ls_result-base ).
|
||||
assert_amount( iv_expected = 58 iv_actual = ls_result-total ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD volumetric_weight_wins.
|
||||
DATA ls_result TYPE {{p}}if_freight_calc=>ty_result.
|
||||
|
||||
ls_result = mo_cut->calculate( iv_weight_kg = 500
|
||||
iv_volume_m3 = '4.5'
|
||||
iv_distance_km = 100
|
||||
iv_fuel_index = 0 ).
|
||||
|
||||
assert_weight( iv_expected = 1125 iv_actual = ls_result-chargeable_weight ).
|
||||
assert_amount( iv_expected = 58 iv_actual = ls_result-base ).
|
||||
assert_amount( iv_expected = 58 iv_actual = ls_result-total ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD distance_component.
|
||||
DATA ls_result TYPE {{p}}if_freight_calc=>ty_result.
|
||||
|
||||
ls_result = mo_cut->calculate( iv_weight_kg = 1000
|
||||
iv_volume_m3 = 0
|
||||
iv_distance_km = 350
|
||||
iv_fuel_index = 0 ).
|
||||
|
||||
assert_amount( iv_expected = 45 iv_actual = ls_result-base ).
|
||||
assert_amount( iv_expected = 27 iv_actual = ls_result-distance ).
|
||||
assert_amount( iv_expected = 72 iv_actual = ls_result-total ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD fuel_rounds_half_up.
|
||||
DATA ls_result TYPE {{p}}if_freight_calc=>ty_result.
|
||||
|
||||
ls_result = mo_cut->calculate( iv_weight_kg = 1000
|
||||
iv_volume_m3 = 0
|
||||
iv_distance_km = 100
|
||||
iv_fuel_index = '12.3' ).
|
||||
|
||||
assert_amount( iv_expected = 45 iv_actual = ls_result-base ).
|
||||
assert_amount( iv_expected = 0 iv_actual = ls_result-distance ).
|
||||
assert_amount( iv_expected = '5.54' iv_actual = ls_result-fuel ).
|
||||
assert_amount( iv_expected = '50.54' iv_actual = ls_result-total ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD full_load.
|
||||
DATA ls_result TYPE {{p}}if_freight_calc=>ty_result.
|
||||
|
||||
ls_result = mo_cut->calculate( iv_weight_kg = 2000
|
||||
iv_volume_m3 = 1
|
||||
iv_distance_km = 500
|
||||
iv_fuel_index = 100 ).
|
||||
|
||||
assert_weight( iv_expected = 2000 iv_actual = ls_result-chargeable_weight ).
|
||||
assert_amount( iv_expected = 110 iv_actual = ls_result-base ).
|
||||
assert_amount( iv_expected = 36 iv_actual = ls_result-distance ).
|
||||
assert_amount( iv_expected = 146 iv_actual = ls_result-fuel ).
|
||||
assert_amount( iv_expected = 292 iv_actual = ls_result-total ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_freight_calc=>c_reason-ok
|
||||
act = ls_result-reason ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
149
tasks_gen/eval/G0008/reference/freight_calc.clas.abap
Normal file
149
tasks_gen/eval/G0008/reference/freight_calc.clas.abap
Normal file
@@ -0,0 +1,149 @@
|
||||
CLASS {{p}}freight_calc DEFINITION PUBLIC FINAL CREATE PUBLIC.
|
||||
PUBLIC SECTION.
|
||||
INTERFACES {{p}}if_freight_calc.
|
||||
|
||||
PRIVATE SECTION.
|
||||
TYPES ty_quantity TYPE p LENGTH 13 DECIMALS 3.
|
||||
|
||||
CONSTANTS:
|
||||
c_base_amount TYPE {{p}}if_freight_calc=>ty_amount VALUE '45.00',
|
||||
c_base_weight TYPE ty_quantity VALUE '1000.000',
|
||||
c_weight_rate TYPE {{p}}if_freight_calc=>ty_amount VALUE '6.50',
|
||||
c_free_km TYPE i VALUE 100,
|
||||
c_km_rate TYPE {{p}}if_freight_calc=>ty_amount VALUE '9.00',
|
||||
c_step TYPE ty_quantity VALUE '100.000',
|
||||
c_volume_factor TYPE i VALUE 250,
|
||||
c_percent TYPE p LENGTH 3 DECIMALS 2 VALUE '0.01'.
|
||||
|
||||
METHODS check_input
|
||||
IMPORTING iv_weight_kg TYPE {{p}}if_freight_calc=>ty_weight
|
||||
iv_volume_m3 TYPE {{p}}if_freight_calc=>ty_volume
|
||||
iv_distance_km TYPE {{p}}if_freight_calc=>ty_distance
|
||||
iv_fuel_index TYPE {{p}}if_freight_calc=>ty_fuel
|
||||
RETURNING VALUE(rv_reason) TYPE {{p}}if_freight_calc=>ty_reason.
|
||||
|
||||
METHODS chargeable_weight
|
||||
IMPORTING iv_weight_kg TYPE {{p}}if_freight_calc=>ty_weight
|
||||
iv_volume_m3 TYPE {{p}}if_freight_calc=>ty_volume
|
||||
RETURNING VALUE(rv_weight) TYPE ty_quantity.
|
||||
|
||||
METHODS base_freight
|
||||
IMPORTING iv_weight_kg TYPE ty_quantity
|
||||
RETURNING VALUE(rv_amount) TYPE {{p}}if_freight_calc=>ty_amount.
|
||||
|
||||
METHODS distance_freight
|
||||
IMPORTING iv_distance_km TYPE {{p}}if_freight_calc=>ty_distance
|
||||
RETURNING VALUE(rv_amount) TYPE {{p}}if_freight_calc=>ty_amount.
|
||||
|
||||
METHODS fuel_freight
|
||||
IMPORTING iv_amount TYPE {{p}}if_freight_calc=>ty_amount
|
||||
iv_fuel_index TYPE {{p}}if_freight_calc=>ty_fuel
|
||||
RETURNING VALUE(rv_amount) TYPE {{p}}if_freight_calc=>ty_amount.
|
||||
|
||||
METHODS started_steps
|
||||
IMPORTING iv_excess TYPE ty_quantity
|
||||
RETURNING VALUE(rv_steps) TYPE i.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}freight_calc IMPLEMENTATION.
|
||||
|
||||
METHOD {{p}}if_freight_calc~calculate.
|
||||
DATA lv_reason TYPE {{p}}if_freight_calc=>ty_reason.
|
||||
DATA lv_weight TYPE ty_quantity.
|
||||
DATA lv_net TYPE {{p}}if_freight_calc=>ty_amount.
|
||||
|
||||
CLEAR rs_result.
|
||||
lv_reason = check_input( iv_weight_kg = iv_weight_kg
|
||||
iv_volume_m3 = iv_volume_m3
|
||||
iv_distance_km = iv_distance_km
|
||||
iv_fuel_index = iv_fuel_index ).
|
||||
IF lv_reason <> {{p}}if_freight_calc=>c_reason-ok.
|
||||
rs_result-reason = lv_reason.
|
||||
RETURN.
|
||||
ENDIF.
|
||||
|
||||
lv_weight = chargeable_weight( iv_weight_kg = iv_weight_kg
|
||||
iv_volume_m3 = iv_volume_m3 ).
|
||||
rs_result-chargeable_weight = lv_weight.
|
||||
rs_result-base = base_freight( lv_weight ).
|
||||
rs_result-distance = distance_freight( iv_distance_km ).
|
||||
lv_net = rs_result-base + rs_result-distance.
|
||||
rs_result-fuel = fuel_freight( iv_amount = lv_net
|
||||
iv_fuel_index = iv_fuel_index ).
|
||||
rs_result-total = rs_result-base + rs_result-distance + rs_result-fuel.
|
||||
rs_result-reason = {{p}}if_freight_calc=>c_reason-ok.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD check_input.
|
||||
IF iv_weight_kg <= 0.
|
||||
rv_reason = {{p}}if_freight_calc=>c_reason-weight.
|
||||
ELSEIF iv_volume_m3 < 0.
|
||||
rv_reason = {{p}}if_freight_calc=>c_reason-volume.
|
||||
ELSEIF iv_distance_km <= 0.
|
||||
rv_reason = {{p}}if_freight_calc=>c_reason-distance.
|
||||
ELSEIF iv_fuel_index < 0 OR iv_fuel_index > 100.
|
||||
rv_reason = {{p}}if_freight_calc=>c_reason-fuel.
|
||||
ELSE.
|
||||
rv_reason = {{p}}if_freight_calc=>c_reason-ok.
|
||||
ENDIF.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD chargeable_weight.
|
||||
DATA lv_volumetric TYPE ty_quantity.
|
||||
|
||||
lv_volumetric = iv_volume_m3 * c_volume_factor.
|
||||
IF lv_volumetric > iv_weight_kg.
|
||||
rv_weight = lv_volumetric.
|
||||
ELSE.
|
||||
rv_weight = iv_weight_kg.
|
||||
ENDIF.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD base_freight.
|
||||
DATA lv_excess TYPE ty_quantity.
|
||||
DATA lv_steps TYPE i.
|
||||
|
||||
lv_excess = iv_weight_kg - c_base_weight.
|
||||
IF lv_excess <= 0.
|
||||
rv_amount = c_base_amount.
|
||||
ELSE.
|
||||
lv_steps = started_steps( lv_excess ).
|
||||
rv_amount = c_base_amount + lv_steps * c_weight_rate.
|
||||
ENDIF.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD distance_freight.
|
||||
DATA lv_excess TYPE ty_quantity.
|
||||
DATA lv_steps TYPE i.
|
||||
|
||||
lv_excess = iv_distance_km - c_free_km.
|
||||
IF lv_excess <= 0.
|
||||
rv_amount = 0.
|
||||
ELSE.
|
||||
lv_steps = started_steps( lv_excess ).
|
||||
rv_amount = lv_steps * c_km_rate.
|
||||
ENDIF.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD fuel_freight.
|
||||
DATA lv_scaled TYPE p LENGTH 15 DECIMALS 3.
|
||||
DATA lv_fuel TYPE p LENGTH 15 DECIMALS 5.
|
||||
|
||||
lv_scaled = iv_amount * iv_fuel_index.
|
||||
lv_fuel = lv_scaled * c_percent.
|
||||
rv_amount = lv_fuel.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD started_steps.
|
||||
DATA lv_excess_scaled TYPE p LENGTH 16 DECIMALS 0.
|
||||
DATA lv_step_scaled TYPE p LENGTH 16 DECIMALS 0.
|
||||
|
||||
lv_excess_scaled = iv_excess * 1000.
|
||||
lv_step_scaled = c_step * 1000.
|
||||
rv_steps = lv_excess_scaled DIV lv_step_scaled.
|
||||
IF lv_excess_scaled MOD lv_step_scaled > 0.
|
||||
rv_steps = rv_steps + 1.
|
||||
ENDIF.
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
114
tasks_gen/eval/G0008/reference/freight_calc.testclasses.abap
Normal file
114
tasks_gen/eval/G0008/reference/freight_calc.testclasses.abap
Normal file
@@ -0,0 +1,114 @@
|
||||
CLASS ltc_freight_calc DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
|
||||
PRIVATE SECTION.
|
||||
DATA mo_cut TYPE REF TO {{p}}if_freight_calc.
|
||||
|
||||
METHODS setup.
|
||||
METHODS assert_amount
|
||||
IMPORTING iv_expected TYPE {{p}}if_freight_calc=>ty_amount
|
||||
iv_actual TYPE {{p}}if_freight_calc=>ty_amount.
|
||||
METHODS assert_weight
|
||||
IMPORTING iv_expected TYPE {{p}}if_freight_calc=>ty_weight
|
||||
iv_actual TYPE {{p}}if_freight_calc=>ty_weight.
|
||||
|
||||
METHODS base_and_distance FOR TESTING.
|
||||
METHODS fuel_is_rounded FOR TESTING.
|
||||
METHODS volume_sets_chargeable_weight FOR TESTING.
|
||||
METHODS weight_zero_is_rejected FOR TESTING.
|
||||
METHODS distance_zero_is_rejected FOR TESTING.
|
||||
METHODS fuel_index_out_of_range FOR TESTING.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS ltc_freight_calc IMPLEMENTATION.
|
||||
|
||||
METHOD setup.
|
||||
DATA lo_calc TYPE REF TO {{p}}freight_calc.
|
||||
CREATE OBJECT lo_calc.
|
||||
mo_cut = lo_calc.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD assert_amount.
|
||||
cl_abap_unit_assert=>assert_equals( exp = iv_expected act = iv_actual ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD assert_weight.
|
||||
cl_abap_unit_assert=>assert_equals( exp = iv_expected act = iv_actual ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD base_and_distance.
|
||||
DATA ls_result TYPE {{p}}if_freight_calc=>ty_result.
|
||||
|
||||
ls_result = mo_cut->calculate( iv_weight_kg = 2000
|
||||
iv_volume_m3 = 1
|
||||
iv_distance_km = 500
|
||||
iv_fuel_index = 100 ).
|
||||
|
||||
assert_amount( iv_expected = 110 iv_actual = ls_result-base ).
|
||||
assert_amount( iv_expected = 36 iv_actual = ls_result-distance ).
|
||||
assert_amount( iv_expected = 146 iv_actual = ls_result-fuel ).
|
||||
assert_amount( iv_expected = 292 iv_actual = ls_result-total ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD fuel_is_rounded.
|
||||
DATA ls_result TYPE {{p}}if_freight_calc=>ty_result.
|
||||
|
||||
ls_result = mo_cut->calculate( iv_weight_kg = 1000
|
||||
iv_volume_m3 = 0
|
||||
iv_distance_km = 100
|
||||
iv_fuel_index = '12.3' ).
|
||||
|
||||
assert_amount( iv_expected = '5.54' iv_actual = ls_result-fuel ).
|
||||
assert_amount( iv_expected = '50.54' iv_actual = ls_result-total ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD volume_sets_chargeable_weight.
|
||||
DATA ls_result TYPE {{p}}if_freight_calc=>ty_result.
|
||||
|
||||
ls_result = mo_cut->calculate( iv_weight_kg = 500
|
||||
iv_volume_m3 = '4.5'
|
||||
iv_distance_km = 100
|
||||
iv_fuel_index = 0 ).
|
||||
|
||||
assert_weight( iv_expected = 1125 iv_actual = ls_result-chargeable_weight ).
|
||||
assert_amount( iv_expected = 58 iv_actual = ls_result-base ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD weight_zero_is_rejected.
|
||||
DATA ls_result TYPE {{p}}if_freight_calc=>ty_result.
|
||||
|
||||
ls_result = mo_cut->calculate( iv_weight_kg = 0
|
||||
iv_volume_m3 = 2
|
||||
iv_distance_km = 300
|
||||
iv_fuel_index = 10 ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_freight_calc=>c_reason-weight
|
||||
act = ls_result-reason ).
|
||||
assert_amount( iv_expected = 0 iv_actual = ls_result-total ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD distance_zero_is_rejected.
|
||||
DATA ls_result TYPE {{p}}if_freight_calc=>ty_result.
|
||||
|
||||
ls_result = mo_cut->calculate( iv_weight_kg = 1500
|
||||
iv_volume_m3 = 0
|
||||
iv_distance_km = 0
|
||||
iv_fuel_index = 10 ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_freight_calc=>c_reason-distance
|
||||
act = ls_result-reason ).
|
||||
assert_amount( iv_expected = 0 iv_actual = ls_result-total ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD fuel_index_out_of_range.
|
||||
DATA ls_result TYPE {{p}}if_freight_calc=>ty_result.
|
||||
|
||||
ls_result = mo_cut->calculate( iv_weight_kg = 1500
|
||||
iv_volume_m3 = 0
|
||||
iv_distance_km = 300
|
||||
iv_fuel_index = 120 ).
|
||||
|
||||
cl_abap_unit_assert=>assert_equals( exp = {{p}}if_freight_calc=>c_reason-fuel
|
||||
act = ls_result-reason ).
|
||||
assert_amount( iv_expected = 0 iv_actual = ls_result-total ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
34
tasks_gen/eval/G0008/seed/if_freight_calc.intf.abap
Normal file
34
tasks_gen/eval/G0008/seed/if_freight_calc.intf.abap
Normal file
@@ -0,0 +1,34 @@
|
||||
INTERFACE {{p}}if_freight_calc PUBLIC.
|
||||
TYPES ty_reason TYPE c LENGTH 10.
|
||||
TYPES ty_amount TYPE p LENGTH 9 DECIMALS 2.
|
||||
TYPES ty_weight TYPE p LENGTH 9 DECIMALS 3.
|
||||
TYPES ty_volume TYPE p LENGTH 9 DECIMALS 3.
|
||||
TYPES ty_distance TYPE i.
|
||||
TYPES ty_fuel TYPE p LENGTH 5 DECIMALS 1.
|
||||
|
||||
CONSTANTS:
|
||||
BEGIN OF c_reason,
|
||||
ok TYPE ty_reason VALUE 'OK',
|
||||
weight TYPE ty_reason VALUE 'WEIGHT',
|
||||
volume TYPE ty_reason VALUE 'VOLUME',
|
||||
distance TYPE ty_reason VALUE 'DISTANCE',
|
||||
fuel TYPE ty_reason VALUE 'FUEL',
|
||||
END OF c_reason.
|
||||
|
||||
TYPES:
|
||||
BEGIN OF ty_result,
|
||||
chargeable_weight TYPE ty_weight,
|
||||
base TYPE ty_amount,
|
||||
distance TYPE ty_amount,
|
||||
fuel TYPE ty_amount,
|
||||
total TYPE ty_amount,
|
||||
reason TYPE ty_reason,
|
||||
END OF ty_result.
|
||||
|
||||
METHODS calculate
|
||||
IMPORTING iv_weight_kg TYPE ty_weight
|
||||
iv_volume_m3 TYPE ty_volume
|
||||
iv_distance_km TYPE ty_distance
|
||||
iv_fuel_index TYPE ty_fuel
|
||||
RETURNING VALUE(rs_result) TYPE ty_result.
|
||||
ENDINTERFACE.
|
||||
61
tasks_gen/eval/G0008/spec.md
Normal file
61
tasks_gen/eval/G0008/spec.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# 1. Goal
|
||||
A freight forwarder calculates the price of an outbound shipment. The
|
||||
calculation service receives the gross weight, the volume, the transport
|
||||
distance, and the current fuel index. It returns the freight components and a
|
||||
reason code.
|
||||
|
||||
# 2. Open questions
|
||||
None.
|
||||
|
||||
# 3. Context
|
||||
- The interface {{P}}IF_FREIGHT_CALC exists in package $TMP. It is active.
|
||||
- The interface defines the types TY_REASON, TY_AMOUNT, TY_WEIGHT, TY_VOLUME,
|
||||
TY_DISTANCE, TY_FUEL, and TY_RESULT.
|
||||
- The interface defines the constant structure C_REASON with the components
|
||||
OK, WEIGHT, VOLUME, DISTANCE, and FUEL.
|
||||
- The interface defines the instance method CALCULATE with the importing
|
||||
parameters IV_WEIGHT_KG, IV_VOLUME_M3, IV_DISTANCE_KM, IV_FUEL_INDEX and the
|
||||
returning parameter RS_RESULT.
|
||||
|
||||
# 4. Contract
|
||||
- Create the class {{P}}FREIGHT_CALC in package $TMP.
|
||||
- The class is public, final, and has a public constructor without parameters.
|
||||
- The class implements {{P}}IF_FREIGHT_CALC.
|
||||
- Do not add other public methods.
|
||||
|
||||
# 5. Business rules
|
||||
All amounts are in euro. Apply the rules in this sequence.
|
||||
1. If IV_WEIGHT_KG is less than or equal to 0, return the reason WEIGHT. Set
|
||||
all amounts and the chargeable weight to 0.
|
||||
2. If IV_VOLUME_M3 is less than 0, return the reason VOLUME. Set all amounts
|
||||
and the chargeable weight to 0.
|
||||
3. If IV_DISTANCE_KM is less than or equal to 0, return the reason DISTANCE.
|
||||
Set all amounts and the chargeable weight to 0.
|
||||
4. If IV_FUEL_INDEX is less than 0 or greater than 100, return the reason FUEL.
|
||||
Set all amounts and the chargeable weight to 0.
|
||||
5. The volumetric weight is IV_VOLUME_M3 multiplied by 250.
|
||||
6. The chargeable weight is the greater of IV_WEIGHT_KG and the volumetric
|
||||
weight.
|
||||
7. The base freight is 45.00. For each full or partial 100 kg by which the
|
||||
chargeable weight is greater than 1000 kg, add 6.50.
|
||||
8. The distance freight is 0.00 for a distance up to and including 100 km. For
|
||||
each full or partial 100 km by which IV_DISTANCE_KM is greater than 100 km,
|
||||
add 9.00.
|
||||
9. The fuel freight is the sum of the base freight and the distance freight,
|
||||
multiplied by IV_FUEL_INDEX, divided by 100. Round the result to 2 decimal
|
||||
places. Round a half away from zero.
|
||||
10. The total is the sum of the base freight, the distance freight, and the
|
||||
fuel freight.
|
||||
11. Return the reason OK.
|
||||
|
||||
# 6. Constraints
|
||||
- Release target: 7.40 SP05. Do not use syntax that is newer than 7.40 SP05.
|
||||
For example, do not use COND, SWITCH, REDUCE, FOR, or LET.
|
||||
- Coding standards: Clean ABAP. Method length below 40 statements. No global
|
||||
variables. No comment that restates the code.
|
||||
- Out of scope: do not change {{P}}IF_FREIGHT_CALC.
|
||||
|
||||
# 7. Acceptance
|
||||
- The class is active and has no syntax error.
|
||||
- The hidden tests pass.
|
||||
- Write your own ABAP Unit tests for the class.
|
||||
51
tasks_gen/eval/G0008/task.json
Normal file
51
tasks_gen/eval/G0008/task.json
Normal file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"id": "G0008",
|
||||
"category": "G",
|
||||
"object_type": "CLAS",
|
||||
"difficulty": 2,
|
||||
"release_target": "v740sp05",
|
||||
"expected_outcome": "implement",
|
||||
"budget": {
|
||||
"max_tool_calls": 45,
|
||||
"max_activations": 12
|
||||
},
|
||||
"seed": [
|
||||
{
|
||||
"type": "INTF",
|
||||
"name": "{{P}}IF_FREIGHT_CALC",
|
||||
"file": "seed/if_freight_calc.intf.abap",
|
||||
"description": "Freight calculation contract with result type and reason codes"
|
||||
}
|
||||
],
|
||||
"contract": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}FREIGHT_CALC",
|
||||
"implements": "{{P}}IF_FREIGHT_CALC"
|
||||
}
|
||||
],
|
||||
"out_of_scope": [
|
||||
"{{P}}IF_FREIGHT_CALC"
|
||||
],
|
||||
"hidden_tests": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}T07_HIDDEN",
|
||||
"file": "hidden/t07_hidden.clas.abap",
|
||||
"description": "T07 hidden tests for the freight calculation"
|
||||
}
|
||||
],
|
||||
"reference": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}FREIGHT_CALC",
|
||||
"file": "reference/freight_calc.clas.abap",
|
||||
"description": "Freight surcharge calculator",
|
||||
"testclasses_file": "reference/freight_calc.testclasses.abap"
|
||||
}
|
||||
],
|
||||
"craft_checks": [
|
||||
"method_length",
|
||||
"nesting_depth"
|
||||
]
|
||||
}
|
||||
19
tasks_gen/eval/G0009/generation.json
Normal file
19
tasks_gen/eval/G0009/generation.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"id": "G0009",
|
||||
"pool": "eval",
|
||||
"object_type": "CLAS",
|
||||
"category": "I",
|
||||
"attempts": [
|
||||
{
|
||||
"stage": "validate",
|
||||
"oracle": 0,
|
||||
"null": 0
|
||||
},
|
||||
{
|
||||
"stage": "validate",
|
||||
"oracle": 100.0,
|
||||
"null": 0
|
||||
}
|
||||
],
|
||||
"accepted": true
|
||||
}
|
||||
111
tasks_gen/eval/G0009/hidden/t02_hidden.clas.abap
Normal file
111
tasks_gen/eval/G0009/hidden/t02_hidden.clas.abap
Normal file
@@ -0,0 +1,111 @@
|
||||
CLASS {{p}}t02_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
|
||||
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
|
||||
|
||||
PRIVATE SECTION.
|
||||
DATA mo_cut TYPE REF TO {{p}}if_shipping_cost.
|
||||
|
||||
METHODS setup.
|
||||
|
||||
METHODS zero_weight_is_free FOR TESTING.
|
||||
METHODS light_parcel_gets_minimum FOR TESTING.
|
||||
METHODS tier_limit_one_kg FOR TESTING.
|
||||
METHODS tier_limit_five_kg FOR TESTING.
|
||||
METHODS tier_limit_ten_kg FOR TESTING.
|
||||
METHODS bulk_weight_limit FOR TESTING.
|
||||
METHODS bulk_weight_started_kg FOR TESTING.
|
||||
METHODS express_surcharge FOR TESTING.
|
||||
METHODS express_below_minimum FOR TESTING.
|
||||
METHODS bulk_express FOR TESTING.
|
||||
|
||||
METHODS assert_cost
|
||||
IMPORTING iv_weight TYPE {{p}}if_shipping_cost=>ty_weight
|
||||
iv_express TYPE abap_bool
|
||||
iv_exp TYPE {{p}}if_shipping_cost=>ty_amount
|
||||
iv_msg TYPE string.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}t02_hidden IMPLEMENTATION.
|
||||
METHOD setup.
|
||||
mo_cut = NEW {{p}}shipping_cost_calc( ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD assert_cost.
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = iv_exp
|
||||
act = mo_cut->calculate( iv_weight = iv_weight iv_express = iv_express )
|
||||
msg = iv_msg ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD zero_weight_is_free.
|
||||
assert_cost( iv_weight = '0.000' iv_express = abap_false
|
||||
iv_exp = '0.00' iv_msg = `zero weight` ).
|
||||
assert_cost( iv_weight = '-2.500' iv_express = abap_true
|
||||
iv_exp = '0.00' iv_msg = `negative weight` ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD light_parcel_gets_minimum.
|
||||
assert_cost( iv_weight = '0.100' iv_express = abap_false
|
||||
iv_exp = '6.00' iv_msg = `0.100 kg` ).
|
||||
assert_cost( iv_weight = '0.500' iv_express = abap_false
|
||||
iv_exp = '6.00' iv_msg = `0.500 kg` ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD tier_limit_one_kg.
|
||||
assert_cost( iv_weight = '1.000' iv_express = abap_false
|
||||
iv_exp = '6.00' iv_msg = `1.000 kg` ).
|
||||
assert_cost( iv_weight = '1.001' iv_express = abap_false
|
||||
iv_exp = '8.50' iv_msg = `1.001 kg` ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD tier_limit_five_kg.
|
||||
assert_cost( iv_weight = '5.000' iv_express = abap_false
|
||||
iv_exp = '8.50' iv_msg = `5.000 kg` ).
|
||||
assert_cost( iv_weight = '5.001' iv_express = abap_false
|
||||
iv_exp = '12.00' iv_msg = `5.001 kg` ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD tier_limit_ten_kg.
|
||||
assert_cost( iv_weight = '10.000' iv_express = abap_false
|
||||
iv_exp = '12.00' iv_msg = `10.000 kg` ).
|
||||
assert_cost( iv_weight = '10.001' iv_express = abap_false
|
||||
iv_exp = '18.75' iv_msg = `10.001 kg` ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD bulk_weight_limit.
|
||||
assert_cost( iv_weight = '31.500' iv_express = abap_false
|
||||
iv_exp = '18.75' iv_msg = `31.500 kg` ).
|
||||
assert_cost( iv_weight = '31.501' iv_express = abap_false
|
||||
iv_exp = '19.40' iv_msg = `31.501 kg` ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD bulk_weight_started_kg.
|
||||
assert_cost( iv_weight = '32.000' iv_express = abap_false
|
||||
iv_exp = '19.40' iv_msg = `32.000 kg` ).
|
||||
assert_cost( iv_weight = '33.000' iv_express = abap_false
|
||||
iv_exp = '20.05' iv_msg = `33.000 kg` ).
|
||||
assert_cost( iv_weight = '100.000' iv_express = abap_false
|
||||
iv_exp = '63.60' iv_msg = `100.000 kg` ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD express_surcharge.
|
||||
assert_cost( iv_weight = '2.000' iv_express = abap_true
|
||||
iv_exp = '11.48' iv_msg = `2.000 kg express` ).
|
||||
assert_cost( iv_weight = '20.000' iv_express = abap_true
|
||||
iv_exp = '25.31' iv_msg = `20.000 kg express` ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD express_below_minimum.
|
||||
assert_cost( iv_weight = '0.500' iv_express = abap_true
|
||||
iv_exp = '6.62' iv_msg = `0.500 kg express` ).
|
||||
assert_cost( iv_weight = '1.000' iv_express = abap_true
|
||||
iv_exp = '6.62' iv_msg = `1.000 kg express` ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD bulk_express.
|
||||
assert_cost( iv_weight = '32.000' iv_express = abap_true
|
||||
iv_exp = '26.19' iv_msg = `32.000 kg express` ).
|
||||
assert_cost( iv_weight = '100.000' iv_express = abap_true
|
||||
iv_exp = '85.86' iv_msg = `100.000 kg express` ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
56
tasks_gen/eval/G0009/reference/shipping_cost_calc.clas.abap
Normal file
56
tasks_gen/eval/G0009/reference/shipping_cost_calc.clas.abap
Normal file
@@ -0,0 +1,56 @@
|
||||
CLASS {{p}}shipping_cost_calc DEFINITION PUBLIC FINAL CREATE PUBLIC.
|
||||
PUBLIC SECTION.
|
||||
INTERFACES {{p}}if_shipping_cost.
|
||||
|
||||
PRIVATE SECTION.
|
||||
METHODS base_rate
|
||||
IMPORTING iv_weight TYPE {{p}}if_shipping_cost=>ty_weight
|
||||
RETURNING VALUE(rv_rate) TYPE {{p}}if_shipping_cost=>ty_amount.
|
||||
|
||||
METHODS express_surcharge
|
||||
IMPORTING iv_rate TYPE {{p}}if_shipping_cost=>ty_amount
|
||||
RETURNING VALUE(rv_surcharge) TYPE {{p}}if_shipping_cost=>ty_amount.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}shipping_cost_calc IMPLEMENTATION.
|
||||
METHOD {{p}}if_shipping_cost~calculate.
|
||||
IF iv_weight <= 0.
|
||||
rv_cost = 0.
|
||||
RETURN.
|
||||
ENDIF.
|
||||
|
||||
DATA(lv_cost) = base_rate( iv_weight ).
|
||||
|
||||
IF iv_express = abap_true.
|
||||
lv_cost = lv_cost + express_surcharge( lv_cost ).
|
||||
ENDIF.
|
||||
|
||||
IF lv_cost < {{p}}if_shipping_cost=>c_rate-min_charge.
|
||||
rv_cost = {{p}}if_shipping_cost=>c_rate-min_charge.
|
||||
ELSE.
|
||||
rv_cost = lv_cost.
|
||||
ENDIF.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD base_rate.
|
||||
IF iv_weight <= 1.
|
||||
rv_rate = '4.90'.
|
||||
ELSEIF iv_weight <= 5.
|
||||
rv_rate = '8.50'.
|
||||
ELSEIF iv_weight <= 10.
|
||||
rv_rate = '12.00'.
|
||||
ELSEIF iv_weight <= {{p}}if_shipping_cost=>c_rate-bulk_weight.
|
||||
rv_rate = '18.75'.
|
||||
ELSE.
|
||||
DATA(lv_started_kg) = CONV i(
|
||||
ceil( iv_weight - {{p}}if_shipping_cost=>c_rate-bulk_weight ) ).
|
||||
rv_rate = '18.75' + lv_started_kg * {{p}}if_shipping_cost=>c_rate-bulk_step.
|
||||
ENDIF.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD express_surcharge.
|
||||
rv_surcharge = round( val = iv_rate * {{p}}if_shipping_cost=>c_rate-express_percent / 100
|
||||
dec = 2 ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
@@ -0,0 +1,68 @@
|
||||
CLASS ltc_shipping_cost_calc DEFINITION FINAL FOR TESTING
|
||||
DURATION SHORT RISK LEVEL HARMLESS.
|
||||
|
||||
PRIVATE SECTION.
|
||||
DATA mo_cut TYPE REF TO {{p}}if_shipping_cost.
|
||||
|
||||
METHODS setup.
|
||||
METHODS zero_weight_is_free FOR TESTING.
|
||||
METHODS minimum_charge FOR TESTING.
|
||||
METHODS tier_limits FOR TESTING.
|
||||
METHODS bulk_weight FOR TESTING.
|
||||
METHODS express_surcharge FOR TESTING.
|
||||
METHODS express_below_minimum FOR TESTING.
|
||||
|
||||
METHODS assert_cost
|
||||
IMPORTING iv_weight TYPE {{p}}if_shipping_cost=>ty_weight
|
||||
iv_express TYPE abap_bool
|
||||
iv_exp TYPE {{p}}if_shipping_cost=>ty_amount
|
||||
iv_msg TYPE string.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS ltc_shipping_cost_calc IMPLEMENTATION.
|
||||
METHOD setup.
|
||||
mo_cut = NEW {{p}}shipping_cost_calc( ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD assert_cost.
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = iv_exp
|
||||
act = mo_cut->calculate( iv_weight = iv_weight iv_express = iv_express )
|
||||
msg = iv_msg ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD zero_weight_is_free.
|
||||
assert_cost( iv_weight = '0.000' iv_express = abap_true
|
||||
iv_exp = '0.00' iv_msg = `zero weight` ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD minimum_charge.
|
||||
assert_cost( iv_weight = '0.500' iv_express = abap_false
|
||||
iv_exp = '6.00' iv_msg = `minimum charge` ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD tier_limits.
|
||||
assert_cost( iv_weight = '1.000' iv_express = abap_false
|
||||
iv_exp = '6.00' iv_msg = `1.000 kg` ).
|
||||
assert_cost( iv_weight = '1.001' iv_express = abap_false
|
||||
iv_exp = '8.50' iv_msg = `1.001 kg` ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD bulk_weight.
|
||||
assert_cost( iv_weight = '31.500' iv_express = abap_false
|
||||
iv_exp = '18.75' iv_msg = `31.500 kg` ).
|
||||
assert_cost( iv_weight = '32.000' iv_express = abap_false
|
||||
iv_exp = '19.40' iv_msg = `32.000 kg` ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD express_surcharge.
|
||||
assert_cost( iv_weight = '2.000' iv_express = abap_true
|
||||
iv_exp = '11.48' iv_msg = `2.000 kg express` ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD express_below_minimum.
|
||||
assert_cost( iv_weight = '0.500' iv_express = abap_true
|
||||
iv_exp = '6.62' iv_msg = `0.500 kg express` ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
17
tasks_gen/eval/G0009/seed/if_shipping_cost.intf.abap
Normal file
17
tasks_gen/eval/G0009/seed/if_shipping_cost.intf.abap
Normal file
@@ -0,0 +1,17 @@
|
||||
INTERFACE {{p}}if_shipping_cost PUBLIC.
|
||||
TYPES ty_weight TYPE p LENGTH 13 DECIMALS 3.
|
||||
TYPES ty_amount TYPE p LENGTH 15 DECIMALS 2.
|
||||
|
||||
CONSTANTS:
|
||||
BEGIN OF c_rate,
|
||||
min_charge TYPE ty_amount VALUE '6.00',
|
||||
express_percent TYPE i VALUE 35,
|
||||
bulk_weight TYPE ty_weight VALUE '31.500',
|
||||
bulk_step TYPE ty_amount VALUE '0.65',
|
||||
END OF c_rate.
|
||||
|
||||
METHODS calculate
|
||||
IMPORTING iv_weight TYPE ty_weight
|
||||
iv_express TYPE abap_bool
|
||||
RETURNING VALUE(rv_cost) TYPE ty_amount.
|
||||
ENDINTERFACE.
|
||||
53
tasks_gen/eval/G0009/seed/shipping_cost_calc.clas.abap
Normal file
53
tasks_gen/eval/G0009/seed/shipping_cost_calc.clas.abap
Normal file
@@ -0,0 +1,53 @@
|
||||
CLASS {{p}}shipping_cost_calc DEFINITION PUBLIC FINAL CREATE PUBLIC.
|
||||
PUBLIC SECTION.
|
||||
INTERFACES {{p}}if_shipping_cost.
|
||||
|
||||
PRIVATE SECTION.
|
||||
METHODS base_rate
|
||||
IMPORTING iv_weight TYPE {{p}}if_shipping_cost=>ty_weight
|
||||
RETURNING VALUE(rv_rate) TYPE {{p}}if_shipping_cost=>ty_amount.
|
||||
|
||||
METHODS express_surcharge
|
||||
IMPORTING iv_rate TYPE {{p}}if_shipping_cost=>ty_amount
|
||||
RETURNING VALUE(rv_surcharge) TYPE {{p}}if_shipping_cost=>ty_amount.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}shipping_cost_calc IMPLEMENTATION.
|
||||
METHOD {{p}}if_shipping_cost~calculate.
|
||||
IF iv_weight <= 0.
|
||||
RETURN.
|
||||
ENDIF.
|
||||
|
||||
rv_cost = base_rate( iv_weight ).
|
||||
|
||||
IF rv_cost < {{p}}if_shipping_cost=>c_rate-min_charge.
|
||||
rv_cost = {{p}}if_shipping_cost=>c_rate-min_charge.
|
||||
ENDIF.
|
||||
|
||||
IF iv_express = abap_true.
|
||||
rv_cost = rv_cost + express_surcharge( rv_cost ).
|
||||
ENDIF.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD base_rate.
|
||||
IF iv_weight < 1.
|
||||
rv_rate = '4.90'.
|
||||
ELSEIF iv_weight < 5.
|
||||
rv_rate = '8.50'.
|
||||
ELSEIF iv_weight < 10.
|
||||
rv_rate = '12.00'.
|
||||
ELSEIF iv_weight < {{p}}if_shipping_cost=>c_rate-bulk_weight.
|
||||
rv_rate = '18.75'.
|
||||
ELSE.
|
||||
DATA lv_started_kg TYPE i.
|
||||
lv_started_kg = iv_weight - {{p}}if_shipping_cost=>c_rate-bulk_weight.
|
||||
rv_rate = '18.75' + lv_started_kg * {{p}}if_shipping_cost=>c_rate-bulk_step.
|
||||
ENDIF.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD express_surcharge.
|
||||
rv_surcharge = round( val = iv_rate * {{p}}if_shipping_cost=>c_rate-express_percent / 100
|
||||
dec = 2 ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
53
tasks_gen/eval/G0009/seed/shipping_cost_legacy.clas.abap
Normal file
53
tasks_gen/eval/G0009/seed/shipping_cost_legacy.clas.abap
Normal file
@@ -0,0 +1,53 @@
|
||||
CLASS {{p}}shipping_cost_legacy DEFINITION PUBLIC FINAL CREATE PUBLIC.
|
||||
PUBLIC SECTION.
|
||||
INTERFACES {{p}}if_shipping_cost.
|
||||
|
||||
PRIVATE SECTION.
|
||||
METHODS base_rate
|
||||
IMPORTING iv_weight TYPE {{p}}if_shipping_cost=>ty_weight
|
||||
RETURNING VALUE(rv_rate) TYPE {{p}}if_shipping_cost=>ty_amount.
|
||||
|
||||
METHODS express_surcharge
|
||||
IMPORTING iv_rate TYPE {{p}}if_shipping_cost=>ty_amount
|
||||
RETURNING VALUE(rv_surcharge) TYPE {{p}}if_shipping_cost=>ty_amount.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}shipping_cost_legacy IMPLEMENTATION.
|
||||
METHOD {{p}}if_shipping_cost~calculate.
|
||||
IF iv_weight <= 0.
|
||||
RETURN.
|
||||
ENDIF.
|
||||
|
||||
rv_cost = base_rate( iv_weight ).
|
||||
|
||||
IF rv_cost < {{p}}if_shipping_cost=>c_rate-min_charge.
|
||||
rv_cost = {{p}}if_shipping_cost=>c_rate-min_charge.
|
||||
ENDIF.
|
||||
|
||||
IF iv_express = abap_true.
|
||||
rv_cost = rv_cost + express_surcharge( rv_cost ).
|
||||
ENDIF.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD base_rate.
|
||||
IF iv_weight < 1.
|
||||
rv_rate = '4.90'.
|
||||
ELSEIF iv_weight < 5.
|
||||
rv_rate = '8.50'.
|
||||
ELSEIF iv_weight < 10.
|
||||
rv_rate = '12.00'.
|
||||
ELSEIF iv_weight < {{p}}if_shipping_cost=>c_rate-bulk_weight.
|
||||
rv_rate = '18.75'.
|
||||
ELSE.
|
||||
DATA lv_started_kg TYPE i.
|
||||
lv_started_kg = iv_weight - {{p}}if_shipping_cost=>c_rate-bulk_weight.
|
||||
rv_rate = '18.75' + lv_started_kg * {{p}}if_shipping_cost=>c_rate-bulk_step.
|
||||
ENDIF.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD express_surcharge.
|
||||
rv_surcharge = round( val = iv_rate * {{p}}if_shipping_cost=>c_rate-express_percent / 100
|
||||
dec = 2 ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
63
tasks_gen/eval/G0009/spec.md
Normal file
63
tasks_gen/eval/G0009/spec.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# 1. Goal
|
||||
Calculate the shipping cost of a parcel. A webshop calls the calculation before
|
||||
it shows the total price to the customer. The cost depends on the weight of the
|
||||
parcel and on an express flag. The class that the webshop uses today returns
|
||||
wrong costs. A corrected class must replace it.
|
||||
|
||||
# 2. Open questions
|
||||
None.
|
||||
|
||||
# 3. Context
|
||||
- The interface {{P}}IF_SHIPPING_COST exists in package $TMP. It is active.
|
||||
- The interface contains the types TY_WEIGHT (packed, 3 decimals) and TY_AMOUNT
|
||||
(packed, 2 decimals), the constant structure C_RATE, and one method:
|
||||
CALCULATE IMPORTING iv_weight TYPE ty_weight, iv_express TYPE abap_bool
|
||||
RETURNING VALUE(rv_cost) TYPE ty_amount.
|
||||
- C_RATE has the components MIN_CHARGE (6.00), EXPRESS_PERCENT (35),
|
||||
BULK_WEIGHT (31.500), and BULK_STEP (0.65).
|
||||
- The class {{P}}SHIPPING_COST_LEGACY exists in package $TMP. It is active and
|
||||
it implements the interface, but the calculated costs are wrong.
|
||||
- Reported symptoms of {{P}}SHIPPING_COST_LEGACY:
|
||||
1. A parcel with a weight that is exactly on a weight limit is charged with
|
||||
the rate of the next weight limit.
|
||||
2. A parcel that is heavier than C_RATE-BULK_WEIGHT is charged as if its
|
||||
weight were exactly C_RATE-BULK_WEIGHT.
|
||||
3. An express parcel that is lighter than the minimum charge gets a total
|
||||
that is too high.
|
||||
|
||||
# 4. Contract
|
||||
- Create the class {{P}}SHIPPING_COST_CALC in package $TMP.
|
||||
- The class is public and final and has a public constructor without parameters.
|
||||
- The class implements {{P}}IF_SHIPPING_COST.
|
||||
- Do not add other public methods.
|
||||
- Do not change {{P}}IF_SHIPPING_COST and {{P}}SHIPPING_COST_LEGACY.
|
||||
|
||||
# 5. Business rules
|
||||
Apply the rules in this sequence.
|
||||
1. If iv_weight is zero or negative, the cost is 0. Stop.
|
||||
2. Else calculate the base rate from the weight:
|
||||
- weight up to and including 1.000 kg: 4.90
|
||||
- weight up to and including 5.000 kg: 8.50
|
||||
- weight up to and including 10.000 kg: 12.00
|
||||
- weight up to and including 31.500 kg: 18.75
|
||||
- weight above 31.500 kg: 18.75 plus 0.65 for each started kilogram above
|
||||
31.500 kg. A started kilogram is a kilogram that is not complete.
|
||||
Example: 31.501 kg is 0.001 kg above 31.500 kg, so there is one started
|
||||
kilogram. 33.000 kg is 1.500 kg above 31.500 kg, so there are two started
|
||||
kilograms.
|
||||
3. If iv_express is abap_true, add 35 percent of the base rate to the base rate.
|
||||
Round this surcharge to 2 decimals. Round a half away from zero.
|
||||
4. If the result is below 6.00, the result is 6.00.
|
||||
5. The result has 2 decimals.
|
||||
|
||||
# 6. Constraints
|
||||
- Release target: 8.16.
|
||||
- Coding standards: Clean ABAP. Methods below 40 statements. No global variables.
|
||||
No comment that restates the code.
|
||||
- Out of scope: do not change {{P}}IF_SHIPPING_COST and
|
||||
{{P}}SHIPPING_COST_LEGACY.
|
||||
|
||||
# 7. Acceptance
|
||||
- The class is active and has no syntax error.
|
||||
- The hidden tests pass.
|
||||
- Write your own ABAP Unit tests for the class.
|
||||
59
tasks_gen/eval/G0009/task.json
Normal file
59
tasks_gen/eval/G0009/task.json
Normal file
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"id": "G0009",
|
||||
"category": "I",
|
||||
"object_type": "CLAS",
|
||||
"difficulty": 2,
|
||||
"release_target": "v816",
|
||||
"expected_outcome": "implement",
|
||||
"budget": {
|
||||
"max_tool_calls": 50,
|
||||
"max_activations": 12
|
||||
},
|
||||
"seed": [
|
||||
{
|
||||
"type": "INTF",
|
||||
"name": "{{P}}IF_SHIPPING_COST",
|
||||
"file": "seed/if_shipping_cost.intf.abap",
|
||||
"description": "Shipping cost contract with the weight and amount types, the rate constants and the CALCULATE method"
|
||||
},
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}SHIPPING_COST_LEGACY",
|
||||
"file": "seed/shipping_cost_legacy.clas.abap",
|
||||
"description": "Active class that implements the interface but calculates wrong costs"
|
||||
}
|
||||
],
|
||||
"contract": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}SHIPPING_COST_CALC",
|
||||
"implements": "{{P}}IF_SHIPPING_COST"
|
||||
}
|
||||
],
|
||||
"out_of_scope": [
|
||||
"{{P}}IF_SHIPPING_COST",
|
||||
"{{P}}SHIPPING_COST_LEGACY"
|
||||
],
|
||||
"hidden_tests": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}T02_HIDDEN",
|
||||
"file": "hidden/t02_hidden.clas.abap",
|
||||
"description": "T02 hidden tests for the shipping cost calculation"
|
||||
}
|
||||
],
|
||||
"reference": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}SHIPPING_COST_CALC",
|
||||
"file": "reference/shipping_cost_calc.clas.abap",
|
||||
"description": "Correct shipping cost calculation",
|
||||
"testclasses_file": "reference/shipping_cost_calc.testclasses.abap"
|
||||
}
|
||||
],
|
||||
"craft_checks": [
|
||||
"method_length",
|
||||
"cyclomatic_complexity",
|
||||
"no_global_variables"
|
||||
]
|
||||
}
|
||||
25
tasks_gen/eval/G0010/generation.json
Normal file
25
tasks_gen/eval/G0010/generation.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"id": "G0010",
|
||||
"pool": "eval",
|
||||
"object_type": "CLAS",
|
||||
"category": "C",
|
||||
"attempts": [
|
||||
{
|
||||
"stage": "validate",
|
||||
"oracle": 0,
|
||||
"null": 0
|
||||
},
|
||||
{
|
||||
"stage": "bundle",
|
||||
"errors": [
|
||||
"invalid JSON: Extra data: line 1 column 24591 (char 24590)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"stage": "validate",
|
||||
"oracle": 100.0,
|
||||
"null": 0
|
||||
}
|
||||
],
|
||||
"accepted": true
|
||||
}
|
||||
173
tasks_gen/eval/G0010/hidden/t02_hidden.clas.abap
Normal file
173
tasks_gen/eval/G0010/hidden/t02_hidden.clas.abap
Normal file
@@ -0,0 +1,173 @@
|
||||
CLASS {{p}}t02_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
|
||||
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
|
||||
PRIVATE SECTION.
|
||||
DATA mo_cut TYPE REF TO {{p}}if_stock_cover.
|
||||
METHODS setup.
|
||||
METHODS all_ok FOR TESTING.
|
||||
METHODS shortage_is_reported FOR TESTING.
|
||||
METHODS stock_used_in_order FOR TESTING.
|
||||
METHODS negative_stock_ignored FOR TESTING.
|
||||
METHODS zero_requirement_invalid FOR TESTING.
|
||||
METHODS negative_req_invalid FOR TESTING.
|
||||
METHODS missing_stock_is_short FOR TESTING.
|
||||
METHODS case_and_blanks_ignored FOR TESTING.
|
||||
METHODS stock_items_are_summed FOR TESTING.
|
||||
METHODS no_requirements FOR TESTING.
|
||||
METHODS shortages_filter_sort FOR TESTING.
|
||||
METHODS shortages_empty_all_ok FOR TESTING.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}t02_hidden IMPLEMENTATION.
|
||||
METHOD setup.
|
||||
mo_cut = NEW {{p}}stock_cover_checker( ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD all_ok.
|
||||
DATA(lt_stock) = VALUE {{p}}if_stock_cover=>tt_stock_item(
|
||||
( material = 'MAT-A' plant = 'P1' quantity = 100 )
|
||||
( material = 'MAT-B' plant = 'P1' quantity = 50 ) ).
|
||||
DATA(lt_req) = VALUE {{p}}if_stock_cover=>tt_requirement(
|
||||
( material = 'MAT-A' plant = 'P1' required = 30 )
|
||||
( material = 'MAT-B' plant = 'P1' required = 50 ) ).
|
||||
DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result(
|
||||
( material = 'MAT-A' plant = 'P1' required = 30 available = 100 shortage = 0 status = 'OK' )
|
||||
( material = 'MAT-B' plant = 'P1' required = 50 available = 50 shortage = 0 status = 'OK' ) ).
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = lt_exp
|
||||
act = mo_cut->check( it_stock = lt_stock it_requirement = lt_req ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD shortage_is_reported.
|
||||
DATA(lt_stock) = VALUE {{p}}if_stock_cover=>tt_stock_item(
|
||||
( material = 'MAT-A' plant = 'P1' quantity = 30 ) ).
|
||||
DATA(lt_req) = VALUE {{p}}if_stock_cover=>tt_requirement(
|
||||
( material = 'MAT-A' plant = 'P1' required = 50 ) ).
|
||||
DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result(
|
||||
( material = 'MAT-A' plant = 'P1' required = 50 available = 30 shortage = 20 status = 'SHORT' ) ).
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = lt_exp
|
||||
act = mo_cut->check( it_stock = lt_stock it_requirement = lt_req ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD stock_used_in_order.
|
||||
DATA(lt_stock) = VALUE {{p}}if_stock_cover=>tt_stock_item(
|
||||
( material = 'MAT-A' plant = 'P1' quantity = 100 ) ).
|
||||
DATA(lt_req) = VALUE {{p}}if_stock_cover=>tt_requirement(
|
||||
( material = 'MAT-A' plant = 'P1' required = 60 )
|
||||
( material = 'MAT-A' plant = 'P1' required = 60 ) ).
|
||||
DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result(
|
||||
( material = 'MAT-A' plant = 'P1' required = 60 available = 100 shortage = 0 status = 'OK' )
|
||||
( material = 'MAT-A' plant = 'P1' required = 60 available = 40 shortage = 20 status = 'SHORT' ) ).
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = lt_exp
|
||||
act = mo_cut->check( it_stock = lt_stock it_requirement = lt_req ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD negative_stock_ignored.
|
||||
DATA(lt_stock) = VALUE {{p}}if_stock_cover=>tt_stock_item(
|
||||
( material = 'MAT-A' plant = 'P1' quantity = 100 )
|
||||
( material = 'MAT-A' plant = 'P1' quantity = -40 ) ).
|
||||
DATA(lt_req) = VALUE {{p}}if_stock_cover=>tt_requirement(
|
||||
( material = 'MAT-A' plant = 'P1' required = 100 ) ).
|
||||
DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result(
|
||||
( material = 'MAT-A' plant = 'P1' required = 100 available = 100 shortage = 0 status = 'OK' ) ).
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = lt_exp
|
||||
act = mo_cut->check( it_stock = lt_stock it_requirement = lt_req ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD zero_requirement_invalid.
|
||||
DATA(lt_stock) = VALUE {{p}}if_stock_cover=>tt_stock_item(
|
||||
( material = 'MAT-A' plant = 'P1' quantity = 50 ) ).
|
||||
DATA(lt_req) = VALUE {{p}}if_stock_cover=>tt_requirement(
|
||||
( material = 'MAT-A' plant = 'P1' required = 0 )
|
||||
( material = 'MAT-A' plant = 'P1' required = 50 ) ).
|
||||
DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result(
|
||||
( material = 'MAT-A' plant = 'P1' required = 0 available = 50 shortage = 0 status = 'INVALID' )
|
||||
( material = 'MAT-A' plant = 'P1' required = 50 available = 50 shortage = 0 status = 'OK' ) ).
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = lt_exp
|
||||
act = mo_cut->check( it_stock = lt_stock it_requirement = lt_req ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD negative_req_invalid.
|
||||
DATA(lt_stock) = VALUE {{p}}if_stock_cover=>tt_stock_item(
|
||||
( material = 'MAT-A' plant = 'P1' quantity = 50 ) ).
|
||||
DATA(lt_req) = VALUE {{p}}if_stock_cover=>tt_requirement(
|
||||
( material = 'MAT-A' plant = 'P1' required = -10 ) ).
|
||||
DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result(
|
||||
( material = 'MAT-A' plant = 'P1' required = -10 available = 50 shortage = 0 status = 'INVALID' ) ).
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = lt_exp
|
||||
act = mo_cut->check( it_stock = lt_stock it_requirement = lt_req ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD missing_stock_is_short.
|
||||
DATA(lt_stock) = VALUE {{p}}if_stock_cover=>tt_stock_item( ).
|
||||
DATA(lt_req) = VALUE {{p}}if_stock_cover=>tt_requirement(
|
||||
( material = 'MAT-X' plant = 'P9' required = 25 ) ).
|
||||
DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result(
|
||||
( material = 'MAT-X' plant = 'P9' required = 25 available = 0 shortage = 25 status = 'SHORT' ) ).
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = lt_exp
|
||||
act = mo_cut->check( it_stock = lt_stock it_requirement = lt_req ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD case_and_blanks_ignored.
|
||||
DATA(lt_stock) = VALUE {{p}}if_stock_cover=>tt_stock_item(
|
||||
( material = 'mat-a' plant = 'p1' quantity = 80 ) ).
|
||||
DATA(lt_req) = VALUE {{p}}if_stock_cover=>tt_requirement(
|
||||
( material = ' MAT-A ' plant = 'P1 ' required = 80 ) ).
|
||||
DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result(
|
||||
( material = ' MAT-A ' plant = 'P1 ' required = 80 available = 80 shortage = 0 status = 'OK' ) ).
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = lt_exp
|
||||
act = mo_cut->check( it_stock = lt_stock it_requirement = lt_req ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD stock_items_are_summed.
|
||||
DATA(lt_stock) = VALUE {{p}}if_stock_cover=>tt_stock_item(
|
||||
( material = 'MAT-A' plant = 'P1' quantity = 10 )
|
||||
( material = 'MAT-A' plant = 'P1' quantity = 20 )
|
||||
( material = 'MAT-A' plant = 'P2' quantity = 5 ) ).
|
||||
DATA(lt_req) = VALUE {{p}}if_stock_cover=>tt_requirement(
|
||||
( material = 'MAT-A' plant = 'P1' required = 30 )
|
||||
( material = 'MAT-A' plant = 'P2' required = 5 ) ).
|
||||
DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result(
|
||||
( material = 'MAT-A' plant = 'P1' required = 30 available = 30 shortage = 0 status = 'OK' )
|
||||
( material = 'MAT-A' plant = 'P2' required = 5 available = 5 shortage = 0 status = 'OK' ) ).
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = lt_exp
|
||||
act = mo_cut->check( it_stock = lt_stock it_requirement = lt_req ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD no_requirements.
|
||||
DATA(lt_stock) = VALUE {{p}}if_stock_cover=>tt_stock_item(
|
||||
( material = 'MAT-A' plant = 'P1' quantity = 10 ) ).
|
||||
DATA(lt_req) = VALUE {{p}}if_stock_cover=>tt_requirement( ).
|
||||
DATA(lt_act) = mo_cut->check( it_stock = lt_stock it_requirement = lt_req ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 0 act = lines( lt_act ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD shortages_filter_sort.
|
||||
DATA(lt_in) = VALUE {{p}}if_stock_cover=>tt_result(
|
||||
( material = 'MAT-C' plant = 'P1' required = 10 available = 0 shortage = 10 status = 'SHORT' )
|
||||
( material = 'MAT-A' plant = 'P2' required = 10 available = 0 shortage = 10 status = 'SHORT' )
|
||||
( material = 'MAT-B' plant = 'P1' required = 10 available = 10 shortage = 0 status = 'OK' )
|
||||
( material = 'MAT-A' plant = 'P1' required = 10 available = 0 shortage = 10 status = 'SHORT' )
|
||||
( material = 'MAT-D' plant = 'P1' required = 10 available = 10 shortage = 0 status = 'INVALID' ) ).
|
||||
DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result(
|
||||
( material = 'MAT-A' plant = 'P1' required = 10 available = 0 shortage = 10 status = 'SHORT' )
|
||||
( material = 'MAT-A' plant = 'P2' required = 10 available = 0 shortage = 10 status = 'SHORT' )
|
||||
( material = 'MAT-C' plant = 'P1' required = 10 available = 0 shortage = 10 status = 'SHORT' ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = lt_exp act = mo_cut->shortages( lt_in ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD shortages_empty_all_ok.
|
||||
DATA(lt_in) = VALUE {{p}}if_stock_cover=>tt_result(
|
||||
( material = 'MAT-A' plant = 'P1' required = 10 available = 10 shortage = 0 status = 'OK' )
|
||||
( material = 'MAT-B' plant = 'P1' required = 10 available = 10 shortage = 0 status = 'INVALID' ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 0 act = lines( mo_cut->shortages( lt_in ) ) ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
128
tasks_gen/eval/G0010/reference/stock_cover_checker.clas.abap
Normal file
128
tasks_gen/eval/G0010/reference/stock_cover_checker.clas.abap
Normal file
@@ -0,0 +1,128 @@
|
||||
CLASS {{p}}stock_cover_checker DEFINITION PUBLIC FINAL CREATE PUBLIC.
|
||||
PUBLIC SECTION.
|
||||
INTERFACES {{p}}if_stock_cover.
|
||||
|
||||
PRIVATE SECTION.
|
||||
TYPES:
|
||||
BEGIN OF ty_stock,
|
||||
material TYPE {{p}}if_stock_cover=>ty_material,
|
||||
plant TYPE {{p}}if_stock_cover=>ty_plant,
|
||||
remaining TYPE {{p}}if_stock_cover=>ty_quantity,
|
||||
END OF ty_stock.
|
||||
TYPES tt_stock TYPE HASHED TABLE OF ty_stock WITH UNIQUE KEY material plant.
|
||||
|
||||
METHODS aggregate
|
||||
IMPORTING it_stock TYPE {{p}}if_stock_cover=>tt_stock_item
|
||||
RETURNING VALUE(rt_stock) TYPE tt_stock.
|
||||
|
||||
METHODS free_quantity
|
||||
IMPORTING it_stock TYPE tt_stock
|
||||
iv_material TYPE {{p}}if_stock_cover=>ty_material
|
||||
iv_plant TYPE {{p}}if_stock_cover=>ty_plant
|
||||
RETURNING VALUE(rv_quantity) TYPE {{p}}if_stock_cover=>ty_quantity.
|
||||
|
||||
METHODS consume
|
||||
IMPORTING iv_material TYPE {{p}}if_stock_cover=>ty_material
|
||||
iv_plant TYPE {{p}}if_stock_cover=>ty_plant
|
||||
iv_quantity TYPE {{p}}if_stock_cover=>ty_quantity
|
||||
CHANGING ct_stock TYPE tt_stock.
|
||||
|
||||
METHODS normalize_material
|
||||
IMPORTING iv_material TYPE {{p}}if_stock_cover=>ty_material
|
||||
RETURNING VALUE(rv_material) TYPE {{p}}if_stock_cover=>ty_material.
|
||||
|
||||
METHODS normalize_plant
|
||||
IMPORTING iv_plant TYPE {{p}}if_stock_cover=>ty_plant
|
||||
RETURNING VALUE(rv_plant) TYPE {{p}}if_stock_cover=>ty_plant.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}stock_cover_checker IMPLEMENTATION.
|
||||
METHOD {{p}}if_stock_cover~check.
|
||||
DATA(lt_stock) = aggregate( it_stock ).
|
||||
|
||||
LOOP AT it_requirement INTO DATA(ls_requirement).
|
||||
DATA(lv_free) = free_quantity( it_stock = lt_stock
|
||||
iv_material = ls_requirement-material
|
||||
iv_plant = ls_requirement-plant ).
|
||||
DATA(ls_result) = VALUE {{p}}if_stock_cover=>ty_result(
|
||||
material = ls_requirement-material
|
||||
plant = ls_requirement-plant
|
||||
required = ls_requirement-required
|
||||
available = lv_free ).
|
||||
|
||||
IF ls_requirement-required <= 0.
|
||||
ls_result-status = {{p}}if_stock_cover=>c_status-invalid.
|
||||
ELSEIF lv_free >= ls_requirement-required.
|
||||
ls_result-status = {{p}}if_stock_cover=>c_status-ok.
|
||||
consume( EXPORTING iv_material = ls_requirement-material
|
||||
iv_plant = ls_requirement-plant
|
||||
iv_quantity = ls_requirement-required
|
||||
CHANGING ct_stock = lt_stock ).
|
||||
ELSE.
|
||||
ls_result-status = {{p}}if_stock_cover=>c_status-short.
|
||||
ls_result-shortage = ls_requirement-required - lv_free.
|
||||
consume( EXPORTING iv_material = ls_requirement-material
|
||||
iv_plant = ls_requirement-plant
|
||||
iv_quantity = lv_free
|
||||
CHANGING ct_stock = lt_stock ).
|
||||
ENDIF.
|
||||
|
||||
APPEND ls_result TO rt_result.
|
||||
ENDLOOP.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD {{p}}if_stock_cover~shortages.
|
||||
rt_shortage = it_result.
|
||||
DELETE rt_shortage WHERE status <> {{p}}if_stock_cover=>c_status-short.
|
||||
SORT rt_shortage BY material plant.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD aggregate.
|
||||
LOOP AT it_stock INTO DATA(ls_stock).
|
||||
IF ls_stock-quantity < 0.
|
||||
CONTINUE.
|
||||
ENDIF.
|
||||
DATA(lv_material) = normalize_material( ls_stock-material ).
|
||||
DATA(lv_plant) = normalize_plant( ls_stock-plant ).
|
||||
ASSIGN rt_stock[ material = lv_material plant = lv_plant ] TO FIELD-SYMBOL(<ls_stock_sum>).
|
||||
IF sy-subrc = 0.
|
||||
<ls_stock_sum>-remaining = <ls_stock_sum>-remaining + ls_stock-quantity.
|
||||
ELSE.
|
||||
INSERT VALUE #( material = lv_material
|
||||
plant = lv_plant
|
||||
remaining = ls_stock-quantity ) INTO TABLE rt_stock.
|
||||
ENDIF.
|
||||
ENDLOOP.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD free_quantity.
|
||||
ASSIGN it_stock[ material = normalize_material( iv_material )
|
||||
plant = normalize_plant( iv_plant ) ] TO FIELD-SYMBOL(<ls_stock>).
|
||||
IF sy-subrc = 0.
|
||||
rv_quantity = <ls_stock>-remaining.
|
||||
ENDIF.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD consume.
|
||||
ASSIGN ct_stock[ material = normalize_material( iv_material )
|
||||
plant = normalize_plant( iv_plant ) ] TO FIELD-SYMBOL(<ls_stock>).
|
||||
IF sy-subrc = 0.
|
||||
<ls_stock>-remaining = <ls_stock>-remaining - iv_quantity.
|
||||
ENDIF.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD normalize_material.
|
||||
DATA lv_text TYPE string.
|
||||
lv_text = iv_material.
|
||||
REPLACE ALL OCCURRENCES OF ` ` IN lv_text WITH ``.
|
||||
rv_material = to_upper( lv_text ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD normalize_plant.
|
||||
DATA lv_text TYPE string.
|
||||
lv_text = iv_plant.
|
||||
REPLACE ALL OCCURRENCES OF ` ` IN lv_text WITH ``.
|
||||
rv_plant = to_upper( lv_text ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
@@ -0,0 +1,93 @@
|
||||
CLASS ltc_stock_cover DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
|
||||
PRIVATE SECTION.
|
||||
DATA mo_cut TYPE REF TO {{p}}if_stock_cover.
|
||||
METHODS setup.
|
||||
METHODS covered_req_is_ok FOR TESTING.
|
||||
METHODS shortage_is_reported FOR TESTING.
|
||||
METHODS stock_shared_in_order FOR TESTING.
|
||||
METHODS invalid_req_keeps_stock FOR TESTING.
|
||||
METHODS blanks_and_case_ignored FOR TESTING.
|
||||
METHODS shortages_are_sorted FOR TESTING.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS ltc_stock_cover IMPLEMENTATION.
|
||||
METHOD setup.
|
||||
mo_cut = NEW {{p}}stock_cover_checker( ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD covered_req_is_ok.
|
||||
DATA(lt_stock) = VALUE {{p}}if_stock_cover=>tt_stock_item(
|
||||
( material = 'MAT-A' plant = 'P1' quantity = 40 ) ).
|
||||
DATA(lt_req) = VALUE {{p}}if_stock_cover=>tt_requirement(
|
||||
( material = 'MAT-A' plant = 'P1' required = 40 ) ).
|
||||
DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result(
|
||||
( material = 'MAT-A' plant = 'P1' required = 40 available = 40 shortage = 0 status = 'OK' ) ).
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = lt_exp
|
||||
act = mo_cut->check( it_stock = lt_stock it_requirement = lt_req ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD shortage_is_reported.
|
||||
DATA(lt_stock) = VALUE {{p}}if_stock_cover=>tt_stock_item(
|
||||
( material = 'MAT-A' plant = 'P1' quantity = 5 ) ).
|
||||
DATA(lt_req) = VALUE {{p}}if_stock_cover=>tt_requirement(
|
||||
( material = 'MAT-A' plant = 'P1' required = 12 ) ).
|
||||
DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result(
|
||||
( material = 'MAT-A' plant = 'P1' required = 12 available = 5 shortage = 7 status = 'SHORT' ) ).
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = lt_exp
|
||||
act = mo_cut->check( it_stock = lt_stock it_requirement = lt_req ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD stock_shared_in_order.
|
||||
DATA(lt_stock) = VALUE {{p}}if_stock_cover=>tt_stock_item(
|
||||
( material = 'MAT-A' plant = 'P1' quantity = 10 ) ).
|
||||
DATA(lt_req) = VALUE {{p}}if_stock_cover=>tt_requirement(
|
||||
( material = 'MAT-A' plant = 'P1' required = 6 )
|
||||
( material = 'MAT-A' plant = 'P1' required = 6 ) ).
|
||||
DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result(
|
||||
( material = 'MAT-A' plant = 'P1' required = 6 available = 10 shortage = 0 status = 'OK' )
|
||||
( material = 'MAT-A' plant = 'P1' required = 6 available = 4 shortage = 2 status = 'SHORT' ) ).
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = lt_exp
|
||||
act = mo_cut->check( it_stock = lt_stock it_requirement = lt_req ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD invalid_req_keeps_stock.
|
||||
DATA(lt_stock) = VALUE {{p}}if_stock_cover=>tt_stock_item(
|
||||
( material = 'MAT-A' plant = 'P1' quantity = 9 ) ).
|
||||
DATA(lt_req) = VALUE {{p}}if_stock_cover=>tt_requirement(
|
||||
( material = 'MAT-A' plant = 'P1' required = 0 )
|
||||
( material = 'MAT-A' plant = 'P1' required = 9 ) ).
|
||||
DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result(
|
||||
( material = 'MAT-A' plant = 'P1' required = 0 available = 9 shortage = 0 status = 'INVALID' )
|
||||
( material = 'MAT-A' plant = 'P1' required = 9 available = 9 shortage = 0 status = 'OK' ) ).
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = lt_exp
|
||||
act = mo_cut->check( it_stock = lt_stock it_requirement = lt_req ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD blanks_and_case_ignored.
|
||||
DATA(lt_stock) = VALUE {{p}}if_stock_cover=>tt_stock_item(
|
||||
( material = 'mat-a' plant = 'p1' quantity = 7 ) ).
|
||||
DATA(lt_req) = VALUE {{p}}if_stock_cover=>tt_requirement(
|
||||
( material = ' MAT-A ' plant = 'P1' required = 7 ) ).
|
||||
DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result(
|
||||
( material = ' MAT-A ' plant = 'P1' required = 7 available = 7 shortage = 0 status = 'OK' ) ).
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = lt_exp
|
||||
act = mo_cut->check( it_stock = lt_stock it_requirement = lt_req ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD shortages_are_sorted.
|
||||
DATA(lt_in) = VALUE {{p}}if_stock_cover=>tt_result(
|
||||
( material = 'MAT-B' plant = 'P1' required = 1 available = 0 shortage = 1 status = 'SHORT' )
|
||||
( material = 'MAT-A' plant = 'P2' required = 1 available = 0 shortage = 1 status = 'SHORT' )
|
||||
( material = 'MAT-A' plant = 'P1' required = 1 available = 1 shortage = 0 status = 'OK' ) ).
|
||||
DATA(lt_exp) = VALUE {{p}}if_stock_cover=>tt_result(
|
||||
( material = 'MAT-A' plant = 'P2' required = 1 available = 0 shortage = 1 status = 'SHORT' )
|
||||
( material = 'MAT-B' plant = 'P1' required = 1 available = 0 shortage = 1 status = 'SHORT' ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = lt_exp act = mo_cut->shortages( lt_in ) ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
46
tasks_gen/eval/G0010/seed/if_stock_cover.intf.abap
Normal file
46
tasks_gen/eval/G0010/seed/if_stock_cover.intf.abap
Normal file
@@ -0,0 +1,46 @@
|
||||
INTERFACE {{p}}if_stock_cover PUBLIC.
|
||||
TYPES ty_material TYPE c LENGTH 18.
|
||||
TYPES ty_plant TYPE c LENGTH 4.
|
||||
TYPES ty_quantity TYPE p LENGTH 13 DECIMALS 3.
|
||||
TYPES ty_status TYPE c LENGTH 10.
|
||||
|
||||
TYPES: BEGIN OF ty_stock_item,
|
||||
material TYPE ty_material,
|
||||
plant TYPE ty_plant,
|
||||
quantity TYPE ty_quantity,
|
||||
END OF ty_stock_item.
|
||||
TYPES tt_stock_item TYPE STANDARD TABLE OF ty_stock_item WITH EMPTY KEY.
|
||||
|
||||
TYPES: BEGIN OF ty_requirement,
|
||||
material TYPE ty_material,
|
||||
plant TYPE ty_plant,
|
||||
required TYPE ty_quantity,
|
||||
END OF ty_requirement.
|
||||
TYPES tt_requirement TYPE STANDARD TABLE OF ty_requirement WITH EMPTY KEY.
|
||||
|
||||
TYPES: BEGIN OF ty_result,
|
||||
material TYPE ty_material,
|
||||
plant TYPE ty_plant,
|
||||
required TYPE ty_quantity,
|
||||
available TYPE ty_quantity,
|
||||
shortage TYPE ty_quantity,
|
||||
status TYPE ty_status,
|
||||
END OF ty_result.
|
||||
TYPES tt_result TYPE STANDARD TABLE OF ty_result WITH EMPTY KEY.
|
||||
|
||||
CONSTANTS:
|
||||
BEGIN OF c_status,
|
||||
ok TYPE ty_status VALUE 'OK',
|
||||
short TYPE ty_status VALUE 'SHORT',
|
||||
invalid TYPE ty_status VALUE 'INVALID',
|
||||
END OF c_status.
|
||||
|
||||
METHODS check
|
||||
IMPORTING it_stock TYPE tt_stock_item
|
||||
it_requirement TYPE tt_requirement
|
||||
RETURNING VALUE(rt_result) TYPE tt_result.
|
||||
|
||||
METHODS shortages
|
||||
IMPORTING it_result TYPE tt_result
|
||||
RETURNING VALUE(rt_shortage) TYPE tt_result.
|
||||
ENDINTERFACE.
|
||||
70
tasks_gen/eval/G0010/spec.md
Normal file
70
tasks_gen/eval/G0010/spec.md
Normal file
@@ -0,0 +1,70 @@
|
||||
# 1. Goal
|
||||
A warehouse planner checks if the free stock covers the requirements of a
|
||||
production run. The planner sends a list of stock items and a list of
|
||||
requirements to a class. The class returns one result row for each requirement.
|
||||
|
||||
# 2. Open questions
|
||||
None.
|
||||
|
||||
# 3. Context
|
||||
- The interface {{P}}IF_STOCK_COVER exists in package $TMP. It is active.
|
||||
- The interface contains the types TY_MATERIAL (CHAR 18), TY_PLANT (CHAR 4),
|
||||
TY_QUANTITY (PACKED 13, 3) and TY_STATUS (CHAR 10).
|
||||
- The interface contains the structures TY_STOCK_ITEM, TY_REQUIREMENT and
|
||||
TY_RESULT and the table types TT_STOCK_ITEM, TT_REQUIREMENT and TT_RESULT.
|
||||
- The interface contains the constant structure C_STATUS with the values OK,
|
||||
SHORT and INVALID.
|
||||
- The interface has the method CHECK. It imports a stock table and a requirement
|
||||
table and returns a result table.
|
||||
- The interface has the method SHORTAGES. It imports a result table and returns a
|
||||
result table.
|
||||
|
||||
# 4. Contract
|
||||
- Create the class {{P}}STOCK_COVER_CHECKER in package $TMP.
|
||||
- The class is public and final.
|
||||
- The class implements {{P}}IF_STOCK_COVER.
|
||||
- Do not add other public methods.
|
||||
- The hidden tests create the class with NEW {{P}}STOCK_COVER_CHECKER( ).
|
||||
|
||||
# 5. Business rules
|
||||
|
||||
## Stock
|
||||
1. Each stock item has a material, a plant and a quantity. Ignore every stock
|
||||
item whose quantity is less than zero.
|
||||
2. Sum the quantities of the remaining stock items for each combination of
|
||||
material and plant. This sum is the free stock of the material and plant.
|
||||
3. Compare material and plant without regard to case. Remove all blanks before
|
||||
you compare them.
|
||||
|
||||
## Requirements
|
||||
4. Process the requirements in the given sequence. The result contains one row
|
||||
for each requirement in the same sequence.
|
||||
5. The available quantity of a requirement is the free stock of its material and
|
||||
plant at the time of the requirement. If no stock exists for the material and
|
||||
plant, the available quantity is 0.
|
||||
6. If the required quantity is less than or equal to 0, the status is INVALID.
|
||||
The requirement does not use free stock. The shortage is 0.
|
||||
7. Else if the available quantity is greater than or equal to the required
|
||||
quantity, the status is OK. The shortage is 0. The requirement uses the
|
||||
required quantity of the free stock.
|
||||
8. Else the status is SHORT. The requirement uses all free stock. The shortage is
|
||||
the required quantity minus the available quantity.
|
||||
|
||||
## Result
|
||||
9. A result row contains the material and the plant of the requirement without a
|
||||
change, the required quantity, the available quantity, the shortage and the
|
||||
status.
|
||||
10. The method SHORTAGES returns all rows of the result table whose status is
|
||||
SHORT. Sort these rows by material in ascending order and then by plant in
|
||||
ascending order. The result can be empty.
|
||||
|
||||
# 6. Constraints
|
||||
- Release target: 8.16 (SAP_BASIS 816).
|
||||
- Coding standards: Clean ABAP. Method length below 40 statements. No global
|
||||
variables. No comment that restates the code.
|
||||
- Out of scope: do not change {{P}}IF_STOCK_COVER.
|
||||
|
||||
# 7. Acceptance
|
||||
- The class is active and has no syntax error.
|
||||
- The hidden tests pass.
|
||||
- Write your own ABAP Unit tests for the class.
|
||||
52
tasks_gen/eval/G0010/task.json
Normal file
52
tasks_gen/eval/G0010/task.json
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"id": "G0010",
|
||||
"category": "C",
|
||||
"object_type": "CLAS",
|
||||
"difficulty": 2,
|
||||
"release_target": "v816",
|
||||
"expected_outcome": "implement",
|
||||
"budget": {
|
||||
"max_tool_calls": 50,
|
||||
"max_activations": 12
|
||||
},
|
||||
"seed": [
|
||||
{
|
||||
"type": "INTF",
|
||||
"name": "{{P}}IF_STOCK_COVER",
|
||||
"file": "seed/if_stock_cover.intf.abap",
|
||||
"description": "Stock cover interface with types, constants and two methods"
|
||||
}
|
||||
],
|
||||
"contract": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}STOCK_COVER_CHECKER",
|
||||
"implements": "{{P}}IF_STOCK_COVER"
|
||||
}
|
||||
],
|
||||
"out_of_scope": [
|
||||
"{{P}}IF_STOCK_COVER"
|
||||
],
|
||||
"hidden_tests": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}T02_HIDDEN",
|
||||
"file": "hidden/t02_hidden.clas.abap",
|
||||
"description": "T02 hidden tests for the stock cover checker"
|
||||
}
|
||||
],
|
||||
"reference": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}STOCK_COVER_CHECKER",
|
||||
"file": "reference/stock_cover_checker.clas.abap",
|
||||
"description": "Stock cover checker with hashed stock table",
|
||||
"testclasses_file": "reference/stock_cover_checker.testclasses.abap"
|
||||
}
|
||||
],
|
||||
"craft_checks": [
|
||||
"table_kind",
|
||||
"access_path",
|
||||
"method_length"
|
||||
]
|
||||
}
|
||||
29
tasks_gen/eval/G0011/generation.json
Normal file
29
tasks_gen/eval/G0011/generation.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"id": "G0011",
|
||||
"pool": "eval",
|
||||
"object_type": "FUNC",
|
||||
"category": "A",
|
||||
"attempts": [
|
||||
{
|
||||
"stage": "validate",
|
||||
"oracle": 0,
|
||||
"null": 0
|
||||
},
|
||||
{
|
||||
"stage": "validate",
|
||||
"oracle": 92.5,
|
||||
"null": 0
|
||||
},
|
||||
{
|
||||
"stage": "validate",
|
||||
"oracle": 0,
|
||||
"null": 0
|
||||
},
|
||||
{
|
||||
"stage": "validate",
|
||||
"oracle": 92.5,
|
||||
"null": 0
|
||||
}
|
||||
],
|
||||
"accepted": false
|
||||
}
|
||||
117
tasks_gen/eval/G0011/hidden/t14_hidden.clas.abap
Normal file
117
tasks_gen/eval/G0011/hidden/t14_hidden.clas.abap
Normal file
@@ -0,0 +1,117 @@
|
||||
CLASS {{p}}t14_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
|
||||
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
|
||||
PRIVATE SECTION.
|
||||
METHODS call
|
||||
IMPORTING
|
||||
iv_stock TYPE decfloat34
|
||||
iv_reorder_point TYPE decfloat34
|
||||
iv_target_stock TYPE decfloat34
|
||||
iv_pack_size TYPE decfloat34
|
||||
iv_min_qty TYPE decfloat34 DEFAULT 0
|
||||
EXPORTING
|
||||
ev_qty TYPE decfloat34
|
||||
ev_subrc TYPE sysubrc.
|
||||
METHODS no_replenishment_when_stock_ok FOR TESTING.
|
||||
METHODS replenish_to_target FOR TESTING.
|
||||
METHODS pack_rounding_up FOR TESTING.
|
||||
METHODS exact_multiple_not_rounded FOR TESTING.
|
||||
METHODS minimum_quantity_applied FOR TESTING.
|
||||
METHODS minimum_quantity_rounded_up FOR TESTING.
|
||||
METHODS negative_minimum_is_zero FOR TESTING.
|
||||
METHODS target_below_stock_is_zero FOR TESTING.
|
||||
METHODS invalid_pack_size FOR TESTING.
|
||||
METHODS class_calculates_directly FOR TESTING.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}t14_hidden IMPLEMENTATION.
|
||||
METHOD call.
|
||||
ev_qty = 0.
|
||||
CALL FUNCTION '{{P}}REPL_CALC'
|
||||
EXPORTING
|
||||
iv_stock = iv_stock
|
||||
iv_reorder_point = iv_reorder_point
|
||||
iv_target_stock = iv_target_stock
|
||||
iv_pack_size = iv_pack_size
|
||||
iv_min_qty = iv_min_qty
|
||||
IMPORTING
|
||||
ev_qty = ev_qty
|
||||
EXCEPTIONS
|
||||
invalid_pack_size = 1
|
||||
OTHERS = 2.
|
||||
ev_subrc = sy-subrc.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD no_replenishment_when_stock_ok.
|
||||
DATA lv_qty TYPE decfloat34.
|
||||
call( EXPORTING iv_stock = 50 iv_reorder_point = 20 iv_target_stock = 100 iv_pack_size = 10
|
||||
IMPORTING ev_qty = lv_qty ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = lv_qty ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD replenish_to_target.
|
||||
DATA lv_qty TYPE decfloat34.
|
||||
call( EXPORTING iv_stock = 10 iv_reorder_point = 20 iv_target_stock = 50 iv_pack_size = 12
|
||||
IMPORTING ev_qty = lv_qty ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 48 ) act = lv_qty ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD pack_rounding_up.
|
||||
DATA lv_qty TYPE decfloat34.
|
||||
call( EXPORTING iv_stock = 0 iv_reorder_point = 10 iv_target_stock = 25 iv_pack_size = 6
|
||||
IMPORTING ev_qty = lv_qty ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 30 ) act = lv_qty ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD exact_multiple_not_rounded.
|
||||
DATA lv_qty TYPE decfloat34.
|
||||
call( EXPORTING iv_stock = 0 iv_reorder_point = 10 iv_target_stock = 24 iv_pack_size = 12
|
||||
IMPORTING ev_qty = lv_qty ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 24 ) act = lv_qty ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD minimum_quantity_applied.
|
||||
DATA lv_qty TYPE decfloat34.
|
||||
call( EXPORTING iv_stock = 10 iv_reorder_point = 20 iv_target_stock = 12 iv_pack_size = 1 iv_min_qty = 7
|
||||
IMPORTING ev_qty = lv_qty ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 7 ) act = lv_qty ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD minimum_quantity_rounded_up.
|
||||
DATA lv_qty TYPE decfloat34.
|
||||
call( EXPORTING iv_stock = 10 iv_reorder_point = 20 iv_target_stock = 12 iv_pack_size = 5 iv_min_qty = 7
|
||||
IMPORTING ev_qty = lv_qty ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 10 ) act = lv_qty ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD negative_minimum_is_zero.
|
||||
DATA lv_qty TYPE decfloat34.
|
||||
call( EXPORTING iv_stock = 0 iv_reorder_point = 10 iv_target_stock = 10 iv_pack_size = 4 iv_min_qty = -5
|
||||
IMPORTING ev_qty = lv_qty ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 12 ) act = lv_qty ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD target_below_stock_is_zero.
|
||||
DATA lv_qty TYPE decfloat34.
|
||||
call( EXPORTING iv_stock = 10 iv_reorder_point = 20 iv_target_stock = 5 iv_pack_size = 4
|
||||
IMPORTING ev_qty = lv_qty ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = lv_qty ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD invalid_pack_size.
|
||||
DATA lv_rc TYPE sysubrc.
|
||||
call( EXPORTING iv_stock = 0 iv_reorder_point = 10 iv_target_stock = 20 iv_pack_size = 0
|
||||
IMPORTING ev_subrc = lv_rc ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_rc ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD class_calculates_directly.
|
||||
DATA(lv_qty) = NEW {{p}}cl_repl( )->calculate(
|
||||
iv_stock = 10
|
||||
iv_reorder_point = 20
|
||||
iv_target_stock = 50
|
||||
iv_pack_size = 12
|
||||
iv_min_qty = 0 ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 48 ) act = lv_qty ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
38
tasks_gen/eval/G0011/reference/cl_repl.clas.abap
Normal file
38
tasks_gen/eval/G0011/reference/cl_repl.clas.abap
Normal file
@@ -0,0 +1,38 @@
|
||||
CLASS {{p}}cl_repl DEFINITION PUBLIC FINAL CREATE PUBLIC.
|
||||
PUBLIC SECTION.
|
||||
METHODS calculate
|
||||
IMPORTING
|
||||
iv_stock TYPE decfloat34
|
||||
iv_reorder_point TYPE decfloat34
|
||||
iv_target_stock TYPE decfloat34
|
||||
iv_pack_size TYPE decfloat34
|
||||
iv_min_qty TYPE decfloat34
|
||||
RETURNING
|
||||
VALUE(rv_qty) TYPE decfloat34.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}cl_repl IMPLEMENTATION.
|
||||
METHOD calculate.
|
||||
IF iv_stock >= iv_reorder_point.
|
||||
rv_qty = 0.
|
||||
RETURN.
|
||||
ENDIF.
|
||||
|
||||
DATA(lv_need) = iv_target_stock - iv_stock.
|
||||
DATA(lv_min_qty) = iv_min_qty.
|
||||
IF lv_min_qty < 0.
|
||||
lv_min_qty = 0.
|
||||
ENDIF.
|
||||
IF lv_need < lv_min_qty.
|
||||
lv_need = lv_min_qty.
|
||||
ENDIF.
|
||||
|
||||
IF lv_need <= 0.
|
||||
rv_qty = 0.
|
||||
RETURN.
|
||||
ENDIF.
|
||||
|
||||
rv_qty = ceil( lv_need / iv_pack_size ) * iv_pack_size.
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
24
tasks_gen/eval/G0011/reference/repl_calc.func.abap
Normal file
24
tasks_gen/eval/G0011/reference/repl_calc.func.abap
Normal file
@@ -0,0 +1,24 @@
|
||||
FUNCTION {{p}}repl_calc
|
||||
IMPORTING
|
||||
iv_stock TYPE decfloat34
|
||||
iv_reorder_point TYPE decfloat34
|
||||
iv_target_stock TYPE decfloat34
|
||||
iv_pack_size TYPE decfloat34
|
||||
iv_min_qty TYPE decfloat34
|
||||
EXPORTING
|
||||
ev_qty TYPE decfloat34
|
||||
EXCEPTIONS
|
||||
invalid_pack_size.
|
||||
|
||||
IF iv_pack_size <= 0.
|
||||
RAISE invalid_pack_size.
|
||||
ENDIF.
|
||||
|
||||
ev_qty = NEW {{p}}cl_repl( )->calculate(
|
||||
iv_stock = iv_stock
|
||||
iv_reorder_point = iv_reorder_point
|
||||
iv_target_stock = iv_target_stock
|
||||
iv_pack_size = iv_pack_size
|
||||
iv_min_qty = iv_min_qty ).
|
||||
|
||||
ENDFUNCTION.
|
||||
100
tasks_gen/eval/G0011/reference/t14_test.clas.abap
Normal file
100
tasks_gen/eval/G0011/reference/t14_test.clas.abap
Normal file
@@ -0,0 +1,100 @@
|
||||
CLASS {{p}}t14_test DEFINITION PUBLIC FINAL CREATE PUBLIC
|
||||
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
|
||||
PRIVATE SECTION.
|
||||
METHODS qty_for
|
||||
IMPORTING
|
||||
iv_stock TYPE decfloat34
|
||||
iv_reorder_point TYPE decfloat34
|
||||
iv_target_stock TYPE decfloat34
|
||||
iv_pack_size TYPE decfloat34
|
||||
iv_min_qty TYPE decfloat34 DEFAULT 0
|
||||
RETURNING
|
||||
VALUE(rv_qty) TYPE decfloat34.
|
||||
METHODS replenish_to_target FOR TESTING.
|
||||
METHODS no_replenishment FOR TESTING.
|
||||
METHODS minimum_quantity FOR TESTING.
|
||||
METHODS pack_rounding FOR TESTING.
|
||||
METHODS invalid_pack_size FOR TESTING.
|
||||
METHODS class_direct_call FOR TESTING.
|
||||
METHODS class_no_replenishment FOR TESTING.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}t14_test IMPLEMENTATION.
|
||||
METHOD qty_for.
|
||||
CALL FUNCTION '{{P}}REPL_CALC'
|
||||
EXPORTING
|
||||
iv_stock = iv_stock
|
||||
iv_reorder_point = iv_reorder_point
|
||||
iv_target_stock = iv_target_stock
|
||||
iv_pack_size = iv_pack_size
|
||||
iv_min_qty = iv_min_qty
|
||||
IMPORTING
|
||||
ev_qty = rv_qty
|
||||
EXCEPTIONS
|
||||
invalid_pack_size = 1
|
||||
OTHERS = 2.
|
||||
cl_abap_unit_assert=>assert_subrc( exp = 0 ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD replenish_to_target.
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = CONV decfloat34( 48 )
|
||||
act = qty_for( iv_stock = 10 iv_reorder_point = 20 iv_target_stock = 50 iv_pack_size = 12 ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD no_replenishment.
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = CONV decfloat34( 0 )
|
||||
act = qty_for( iv_stock = 30 iv_reorder_point = 20 iv_target_stock = 50 iv_pack_size = 12 ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD minimum_quantity.
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = CONV decfloat34( 10 )
|
||||
act = qty_for( iv_stock = 10 iv_reorder_point = 20 iv_target_stock = 12 iv_pack_size = 5 iv_min_qty = 7 ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD pack_rounding.
|
||||
cl_abap_unit_assert=>assert_equals(
|
||||
exp = CONV decfloat34( 30 )
|
||||
act = qty_for( iv_stock = 0 iv_reorder_point = 10 iv_target_stock = 25 iv_pack_size = 6 ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD invalid_pack_size.
|
||||
DATA lv_qty TYPE decfloat34.
|
||||
CALL FUNCTION '{{P}}REPL_CALC'
|
||||
EXPORTING
|
||||
iv_stock = 0
|
||||
iv_reorder_point = 10
|
||||
iv_target_stock = 20
|
||||
iv_pack_size = 0
|
||||
iv_min_qty = 0
|
||||
IMPORTING
|
||||
ev_qty = lv_qty
|
||||
EXCEPTIONS
|
||||
invalid_pack_size = 1
|
||||
OTHERS = 2.
|
||||
cl_abap_unit_assert=>assert_equals( exp = 1 act = sy-subrc ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD class_direct_call.
|
||||
DATA(lv_qty) = NEW {{p}}cl_repl( )->calculate(
|
||||
iv_stock = 0
|
||||
iv_reorder_point = 10
|
||||
iv_target_stock = 24
|
||||
iv_pack_size = 12
|
||||
iv_min_qty = 0 ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 24 ) act = lv_qty ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD class_no_replenishment.
|
||||
DATA(lv_qty) = NEW {{p}}cl_repl( )->calculate(
|
||||
iv_stock = 40
|
||||
iv_reorder_point = 20
|
||||
iv_target_stock = 100
|
||||
iv_pack_size = 10
|
||||
iv_min_qty = 0 ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = lv_qty ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
9
tasks_gen/eval/G0011/seed/repl_sample.func.abap
Normal file
9
tasks_gen/eval/G0011/seed/repl_sample.func.abap
Normal file
@@ -0,0 +1,9 @@
|
||||
FUNCTION {{p}}repl_sample
|
||||
IMPORTING
|
||||
iv_bin TYPE string
|
||||
EXPORTING
|
||||
ev_info TYPE string.
|
||||
|
||||
ev_info = |Storage bin { iv_bin }|.
|
||||
|
||||
ENDFUNCTION.
|
||||
66
tasks_gen/eval/G0011/spec.md
Normal file
66
tasks_gen/eval/G0011/spec.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# 1. Goal
|
||||
A warehouse system needs the quantity for a replenishment order of a storage
|
||||
bin. The calling program calls the function module {{P}}REPL_CALC. The
|
||||
calculation logic must be in the class {{P}}CL_REPL, because other programs
|
||||
also use this logic.
|
||||
|
||||
# 2. Open questions
|
||||
None.
|
||||
|
||||
# 3. Context
|
||||
- Function group {{P}}FG_REPL exists in package $TMP.
|
||||
- Function module {{P}}REPL_SAMPLE exists in this function group. It shows bin
|
||||
information. Do not change it.
|
||||
- The class {{P}}CL_REPL does not exist. Create it first.
|
||||
|
||||
# 4. Contract
|
||||
|
||||
## 4.1 Class {{P}}CL_REPL
|
||||
- Package: $TMP.
|
||||
- The class is instantiable without parameters.
|
||||
- Public instance method calculate:
|
||||
- importing iv_stock, type decfloat34
|
||||
- importing iv_reorder_point, type decfloat34
|
||||
- importing iv_target_stock, type decfloat34
|
||||
- importing iv_pack_size, type decfloat34
|
||||
- importing iv_min_qty, type decfloat34
|
||||
- returning rv_qty, type decfloat34
|
||||
- The method has no exception. Call it only with a positive pack size.
|
||||
|
||||
## 4.2 Function module {{P}}REPL_CALC
|
||||
- Function group: {{P}}FG_REPL.
|
||||
- Importing parameters:
|
||||
- iv_stock, type decfloat34
|
||||
- iv_reorder_point, type decfloat34
|
||||
- iv_target_stock, type decfloat34
|
||||
- iv_pack_size, type decfloat34
|
||||
- iv_min_qty, type decfloat34
|
||||
- Exporting parameters:
|
||||
- ev_qty, type decfloat34
|
||||
- Exceptions: invalid_pack_size.
|
||||
- The function module {{P}}REPL_CALC must call the method calculate of the class
|
||||
{{P}}CL_REPL. Create and activate the class before you activate the function
|
||||
module.
|
||||
|
||||
# 5. Business rules
|
||||
1. If the pack size is not positive, the function module raises the exception
|
||||
INVALID_PACK_SIZE. The class method is not called in this case.
|
||||
2. If the stock is greater than or equal to the reorder point, the
|
||||
replenishment quantity is 0.
|
||||
3. Otherwise, the requirement is the target stock minus the stock.
|
||||
4. If the requirement is less than the minimum quantity, the requirement is the
|
||||
minimum quantity. A minimum quantity below 0 counts as 0.
|
||||
5. If the requirement is not positive, the replenishment quantity is 0.
|
||||
6. Otherwise, round the requirement up to the next full multiple of the pack
|
||||
size. The replenishment quantity is this multiple multiplied by the pack
|
||||
size.
|
||||
|
||||
# 6. Constraints
|
||||
- Release target: 7.58.
|
||||
- Use Clean ABAP. Keep each method below 40 statements.
|
||||
- Out of scope: do not change {{P}}REPL_SAMPLE. Do not create database tables.
|
||||
|
||||
# 7. Acceptance
|
||||
- The function module and the class are active and have no syntax error.
|
||||
- The hidden tests pass.
|
||||
- Write ABAP Unit tests for the function module in a global test class.
|
||||
99
tasks_gen/eval/G0011/task.json
Normal file
99
tasks_gen/eval/G0011/task.json
Normal file
@@ -0,0 +1,99 @@
|
||||
{
|
||||
"id": "G0011",
|
||||
"category": "A",
|
||||
"object_type": "FUNC",
|
||||
"difficulty": 2,
|
||||
"release_target": "v758",
|
||||
"expected_outcome": "implement",
|
||||
"budget": {
|
||||
"max_tool_calls": 40,
|
||||
"max_activations": 10
|
||||
},
|
||||
"seed": [
|
||||
{
|
||||
"type": "FUGR",
|
||||
"name": "{{P}}FG_REPL",
|
||||
"description": "Replenishment function group"
|
||||
},
|
||||
{
|
||||
"type": "FUNC",
|
||||
"name": "{{P}}REPL_SAMPLE",
|
||||
"functionGroup": "{{P}}FG_REPL",
|
||||
"file": "seed/repl_sample.func.abap",
|
||||
"description": "Sample bin information module"
|
||||
}
|
||||
],
|
||||
"contract": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}CL_REPL"
|
||||
},
|
||||
{
|
||||
"type": "FUNC",
|
||||
"name": "{{P}}REPL_CALC",
|
||||
"functionGroup": "{{P}}FG_REPL",
|
||||
"params": [
|
||||
{
|
||||
"name": "iv_stock",
|
||||
"type": "decfloat34"
|
||||
},
|
||||
{
|
||||
"name": "iv_reorder_point",
|
||||
"type": "decfloat34"
|
||||
},
|
||||
{
|
||||
"name": "iv_target_stock",
|
||||
"type": "decfloat34"
|
||||
},
|
||||
{
|
||||
"name": "iv_pack_size",
|
||||
"type": "decfloat34"
|
||||
},
|
||||
{
|
||||
"name": "iv_min_qty",
|
||||
"type": "decfloat34"
|
||||
},
|
||||
{
|
||||
"name": "ev_qty",
|
||||
"type": "decfloat34"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"out_of_scope": [
|
||||
"{{P}}REPL_SAMPLE"
|
||||
],
|
||||
"hidden_tests": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}T14_HIDDEN",
|
||||
"file": "hidden/t14_hidden.clas.abap",
|
||||
"description": "T14 hidden tests"
|
||||
}
|
||||
],
|
||||
"reference": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}CL_REPL",
|
||||
"file": "reference/cl_repl.clas.abap",
|
||||
"description": "Replenishment quantity calculator"
|
||||
},
|
||||
{
|
||||
"type": "FUNC",
|
||||
"name": "{{P}}REPL_CALC",
|
||||
"functionGroup": "{{P}}FG_REPL",
|
||||
"file": "reference/repl_calc.func.abap",
|
||||
"description": "Replenishment function module"
|
||||
},
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}T14_TEST",
|
||||
"file": "reference/t14_test.clas.abap",
|
||||
"description": "T14 own tests"
|
||||
}
|
||||
],
|
||||
"craft_checks": [
|
||||
"method_length",
|
||||
"clean_abap"
|
||||
]
|
||||
}
|
||||
14
tasks_gen/eval/G0012/generation.json
Normal file
14
tasks_gen/eval/G0012/generation.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"id": "G0012",
|
||||
"pool": "eval",
|
||||
"object_type": "FUNC",
|
||||
"category": "F",
|
||||
"attempts": [
|
||||
{
|
||||
"stage": "validate",
|
||||
"oracle": 100.0,
|
||||
"null": 0
|
||||
}
|
||||
],
|
||||
"accepted": true
|
||||
}
|
||||
120
tasks_gen/eval/G0012/hidden/t14_hidden.clas.abap
Normal file
120
tasks_gen/eval/G0012/hidden/t14_hidden.clas.abap
Normal file
@@ -0,0 +1,120 @@
|
||||
CLASS {{p}}t14_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
|
||||
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
|
||||
PRIVATE SECTION.
|
||||
METHODS call
|
||||
IMPORTING iv_quantity TYPE decfloat34
|
||||
iv_scrap TYPE decfloat34
|
||||
iv_rework TYPE decfloat34 DEFAULT 0
|
||||
EXPORTING ev_pct TYPE decfloat34
|
||||
ev_severity TYPE string
|
||||
ev_rework TYPE decfloat34
|
||||
ev_subrc TYPE sysubrc.
|
||||
METHODS percent_rounds_half_up FOR TESTING.
|
||||
METHODS zero_scrap_is_ok FOR TESTING.
|
||||
METHODS low_upper_boundary FOR TESTING.
|
||||
METHODS high_lower_boundary FOR TESTING.
|
||||
METHODS high_upper_boundary FOR TESTING.
|
||||
METHODS critical_above_twenty FOR TESTING.
|
||||
METHODS rework_unchanged_for_low FOR TESTING.
|
||||
METHODS rework_set_for_high FOR TESTING.
|
||||
METHODS quantity_zero_raises FOR TESTING.
|
||||
METHODS scrap_negative_raises FOR TESTING.
|
||||
METHODS scrap_above_quantity_raises FOR TESTING.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}t14_hidden IMPLEMENTATION.
|
||||
METHOD call.
|
||||
ev_pct = 0.
|
||||
ev_severity = ``.
|
||||
ev_rework = iv_rework.
|
||||
CALL FUNCTION '{{P}}PRD_SCRAP'
|
||||
EXPORTING
|
||||
iv_quantity = iv_quantity
|
||||
iv_scrap = iv_scrap
|
||||
IMPORTING
|
||||
ev_scrap_pct = ev_pct
|
||||
ev_severity = ev_severity
|
||||
CHANGING
|
||||
cv_rework_qty = ev_rework
|
||||
EXCEPTIONS
|
||||
invalid_quantity = 1
|
||||
scrap_too_high = 2
|
||||
OTHERS = 3.
|
||||
ev_subrc = sy-subrc.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD percent_rounds_half_up.
|
||||
call( EXPORTING iv_quantity = 800 iv_scrap = 7
|
||||
IMPORTING ev_pct = DATA(lv_pct) ev_severity = DATA(lv_sev) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '0.9' ) act = lv_pct ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `LOW` act = lv_sev ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD zero_scrap_is_ok.
|
||||
call( EXPORTING iv_quantity = 100 iv_scrap = 0
|
||||
IMPORTING ev_pct = DATA(lv_pct) ev_severity = DATA(lv_sev) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = lv_pct ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `OK` act = lv_sev ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD low_upper_boundary.
|
||||
call( EXPORTING iv_quantity = 100 iv_scrap = 5
|
||||
IMPORTING ev_pct = DATA(lv_pct) ev_severity = DATA(lv_sev) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 5 ) act = lv_pct ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `LOW` act = lv_sev ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD high_lower_boundary.
|
||||
call( EXPORTING iv_quantity = 100 iv_scrap = '5.1'
|
||||
IMPORTING ev_pct = DATA(lv_pct) ev_severity = DATA(lv_sev) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '5.1' ) act = lv_pct ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `HIGH` act = lv_sev ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD high_upper_boundary.
|
||||
call( EXPORTING iv_quantity = 100 iv_scrap = 20
|
||||
IMPORTING ev_pct = DATA(lv_pct) ev_severity = DATA(lv_sev) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 20 ) act = lv_pct ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `HIGH` act = lv_sev ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD critical_above_twenty.
|
||||
call( EXPORTING iv_quantity = 100 iv_scrap = '20.1'
|
||||
IMPORTING ev_pct = DATA(lv_pct) ev_severity = DATA(lv_sev) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '20.1' ) act = lv_pct ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `CRITICAL` act = lv_sev ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD rework_unchanged_for_low.
|
||||
call( EXPORTING iv_quantity = 200 iv_scrap = 4 iv_rework = 99
|
||||
IMPORTING ev_rework = DATA(lv_rework) ev_severity = DATA(lv_sev) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `LOW` act = lv_sev ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 99 ) act = lv_rework ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD rework_set_for_high.
|
||||
call( EXPORTING iv_quantity = 100 iv_scrap = 10 iv_rework = 99
|
||||
IMPORTING ev_rework = DATA(lv_rework) ev_severity = DATA(lv_sev) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `HIGH` act = lv_sev ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 10 ) act = lv_rework ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD quantity_zero_raises.
|
||||
call( EXPORTING iv_quantity = 0 iv_scrap = 0
|
||||
IMPORTING ev_subrc = DATA(lv_rc) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_rc ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD scrap_negative_raises.
|
||||
call( EXPORTING iv_quantity = 100 iv_scrap = -1
|
||||
IMPORTING ev_subrc = DATA(lv_rc) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 1 act = lv_rc ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD scrap_above_quantity_raises.
|
||||
call( EXPORTING iv_quantity = 100 iv_scrap = 101
|
||||
IMPORTING ev_subrc = DATA(lv_rc) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 2 act = lv_rc ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
41
tasks_gen/eval/G0012/reference/prd_scrap.func.abap
Normal file
41
tasks_gen/eval/G0012/reference/prd_scrap.func.abap
Normal file
@@ -0,0 +1,41 @@
|
||||
FUNCTION {{p}}prd_scrap
|
||||
IMPORTING
|
||||
iv_quantity TYPE decfloat34
|
||||
iv_scrap TYPE decfloat34
|
||||
EXPORTING
|
||||
ev_scrap_pct TYPE decfloat34
|
||||
ev_severity TYPE string
|
||||
CHANGING
|
||||
cv_rework_qty TYPE decfloat34
|
||||
EXCEPTIONS
|
||||
invalid_quantity
|
||||
scrap_too_high.
|
||||
|
||||
IF iv_quantity <= 0 OR iv_scrap < 0.
|
||||
RAISE invalid_quantity.
|
||||
ENDIF.
|
||||
|
||||
IF iv_scrap > iv_quantity.
|
||||
RAISE scrap_too_high.
|
||||
ENDIF.
|
||||
|
||||
ev_scrap_pct = round( val = iv_scrap / iv_quantity * 100
|
||||
dec = 1
|
||||
mode = cl_abap_math=>round_half_up ).
|
||||
|
||||
IF ev_scrap_pct = 0.
|
||||
ev_severity = 'OK'.
|
||||
ELSEIF ev_scrap_pct <= 5.
|
||||
ev_severity = 'LOW'.
|
||||
ELSEIF ev_scrap_pct <= 20.
|
||||
ev_severity = 'HIGH'.
|
||||
ELSE.
|
||||
ev_severity = 'CRITICAL'.
|
||||
ENDIF.
|
||||
|
||||
CASE ev_severity.
|
||||
WHEN 'HIGH' OR 'CRITICAL'.
|
||||
cv_rework_qty = iv_scrap.
|
||||
ENDCASE.
|
||||
|
||||
ENDFUNCTION.
|
||||
90
tasks_gen/eval/G0012/reference/t14_test.clas.abap
Normal file
90
tasks_gen/eval/G0012/reference/t14_test.clas.abap
Normal file
@@ -0,0 +1,90 @@
|
||||
CLASS {{p}}t14_test DEFINITION PUBLIC FINAL CREATE PUBLIC
|
||||
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
|
||||
PRIVATE SECTION.
|
||||
METHODS result_for
|
||||
IMPORTING iv_quantity TYPE decfloat34
|
||||
iv_scrap TYPE decfloat34
|
||||
iv_rework TYPE decfloat34 DEFAULT 0
|
||||
EXPORTING ev_pct TYPE decfloat34
|
||||
ev_severity TYPE string
|
||||
ev_rework TYPE decfloat34.
|
||||
METHODS percent_and_severity FOR TESTING.
|
||||
METHODS severity_bands FOR TESTING.
|
||||
METHODS rework_quantity FOR TESTING.
|
||||
METHODS invalid_inputs FOR TESTING.
|
||||
METHODS scrap_too_high FOR TESTING.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}t14_test IMPLEMENTATION.
|
||||
METHOD result_for.
|
||||
ev_rework = iv_rework.
|
||||
CALL FUNCTION '{{P}}PRD_SCRAP'
|
||||
EXPORTING
|
||||
iv_quantity = iv_quantity
|
||||
iv_scrap = iv_scrap
|
||||
IMPORTING
|
||||
ev_scrap_pct = ev_pct
|
||||
ev_severity = ev_severity
|
||||
CHANGING
|
||||
cv_rework_qty = ev_rework
|
||||
EXCEPTIONS
|
||||
invalid_quantity = 1
|
||||
scrap_too_high = 2
|
||||
OTHERS = 3.
|
||||
cl_abap_unit_assert=>assert_subrc( exp = 0 ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD percent_and_severity.
|
||||
result_for( EXPORTING iv_quantity = 800 iv_scrap = 7
|
||||
IMPORTING ev_pct = DATA(lv_pct) ev_severity = DATA(lv_sev) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '0.9' ) act = lv_pct ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `LOW` act = lv_sev ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD severity_bands.
|
||||
result_for( EXPORTING iv_quantity = 100 iv_scrap = 0
|
||||
IMPORTING ev_severity = DATA(lv_ok) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `OK` act = lv_ok ).
|
||||
result_for( EXPORTING iv_quantity = 100 iv_scrap = 5
|
||||
IMPORTING ev_severity = DATA(lv_low) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `LOW` act = lv_low ).
|
||||
result_for( EXPORTING iv_quantity = 100 iv_scrap = 20
|
||||
IMPORTING ev_severity = DATA(lv_high) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `HIGH` act = lv_high ).
|
||||
result_for( EXPORTING iv_quantity = 100 iv_scrap = 21
|
||||
IMPORTING ev_severity = DATA(lv_crit) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `CRITICAL` act = lv_crit ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD rework_quantity.
|
||||
result_for( EXPORTING iv_quantity = 100 iv_scrap = 4 iv_rework = 99
|
||||
IMPORTING ev_rework = DATA(lv_keep) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 99 ) act = lv_keep ).
|
||||
result_for( EXPORTING iv_quantity = 100 iv_scrap = 10
|
||||
IMPORTING ev_rework = DATA(lv_set) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 10 ) act = lv_set ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD invalid_inputs.
|
||||
DATA lv_pct TYPE decfloat34.
|
||||
DATA lv_rework TYPE decfloat34.
|
||||
CALL FUNCTION '{{P}}PRD_SCRAP'
|
||||
EXPORTING iv_quantity = 0 iv_scrap = 0
|
||||
IMPORTING ev_scrap_pct = lv_pct
|
||||
CHANGING cv_rework_qty = lv_rework
|
||||
EXCEPTIONS invalid_quantity = 1 OTHERS = 2.
|
||||
cl_abap_unit_assert=>assert_equals( exp = 1 act = sy-subrc ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD scrap_too_high.
|
||||
DATA lv_pct TYPE decfloat34.
|
||||
DATA lv_rework TYPE decfloat34.
|
||||
CALL FUNCTION '{{P}}PRD_SCRAP'
|
||||
EXPORTING iv_quantity = 100 iv_scrap = 101
|
||||
IMPORTING ev_scrap_pct = lv_pct
|
||||
CHANGING cv_rework_qty = lv_rework
|
||||
EXCEPTIONS scrap_too_high = 2 OTHERS = 1.
|
||||
cl_abap_unit_assert=>assert_equals( exp = 2 act = sy-subrc ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
18
tasks_gen/eval/G0012/seed/prd_sample.func.abap
Normal file
18
tasks_gen/eval/G0012/seed/prd_sample.func.abap
Normal file
@@ -0,0 +1,18 @@
|
||||
FUNCTION {{p}}prd_sample
|
||||
IMPORTING
|
||||
iv_quantity TYPE decfloat34
|
||||
iv_scrap TYPE decfloat34
|
||||
EXPORTING
|
||||
ev_scrap_pct TYPE decfloat34
|
||||
ev_severity TYPE string
|
||||
CHANGING
|
||||
cv_rework_qty TYPE decfloat34
|
||||
EXCEPTIONS
|
||||
invalid_quantity
|
||||
scrap_too_high.
|
||||
|
||||
" Sample confirmation module. All confirmation modules use this interface.
|
||||
ev_scrap_pct = 0.
|
||||
ev_severity = 'OK'.
|
||||
|
||||
ENDFUNCTION.
|
||||
46
tasks_gen/eval/G0012/spec.md
Normal file
46
tasks_gen/eval/G0012/spec.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# 1. Goal
|
||||
Evaluate a production confirmation. Calculate the scrap percentage and the
|
||||
severity of the scrap. The confirmation program calls one module for each
|
||||
confirmation. The new module must have the same interface as the sample module,
|
||||
because the confirmation program calls all modules in the same way.
|
||||
|
||||
# 2. Open questions
|
||||
None.
|
||||
|
||||
# 3. Context
|
||||
- Function group {{P}}FG_PROD exists in package $TMP.
|
||||
- Function module {{P}}PRD_SAMPLE exists in this group. It is the sample
|
||||
confirmation module. Its interface is the interface that all confirmation
|
||||
modules must use.
|
||||
|
||||
# 4. Contract
|
||||
- Create the function module {{P}}PRD_SCRAP in function group {{P}}FG_PROD.
|
||||
- Use exactly the interface of {{P}}PRD_SAMPLE: the same parameter names, kinds,
|
||||
types, and exceptions.
|
||||
|
||||
# 5. Business rules
|
||||
1. If the confirmed quantity is less than or equal to 0, raise the exception
|
||||
INVALID_QUANTITY.
|
||||
2. If the scrap quantity is less than 0, raise the exception INVALID_QUANTITY.
|
||||
3. If the scrap quantity is greater than the confirmed quantity, raise the
|
||||
exception SCRAP_TOO_HIGH.
|
||||
4. The scrap percentage is the scrap quantity divided by the confirmed quantity,
|
||||
multiplied by 100. Round the result half up to 1 decimal. Write the result to
|
||||
the scrap percentage parameter.
|
||||
5. Set the severity from the rounded scrap percentage of rule 4:
|
||||
- equal to 0: `OK`
|
||||
- greater than 0 and less than or equal to 5: `LOW`
|
||||
- greater than 5 and less than or equal to 20: `HIGH`
|
||||
- greater than 20: `CRITICAL`
|
||||
6. If the severity is `HIGH` or `CRITICAL`, set the rework quantity to the scrap
|
||||
quantity. In all other cases, do not change the rework quantity.
|
||||
|
||||
# 6. Constraints
|
||||
- Release target: 7.58.
|
||||
- Coding standards: Clean ABAP. Keep every method below 40 statements.
|
||||
- Out of scope: do not change {{P}}PRD_SAMPLE.
|
||||
|
||||
# 7. Acceptance
|
||||
- The function module is active and has no syntax error.
|
||||
- The hidden tests pass.
|
||||
- Write ABAP Unit tests for the function module in a global test class.
|
||||
84
tasks_gen/eval/G0012/task.json
Normal file
84
tasks_gen/eval/G0012/task.json
Normal file
@@ -0,0 +1,84 @@
|
||||
{
|
||||
"id": "G0012",
|
||||
"category": "F",
|
||||
"object_type": "FUNC",
|
||||
"difficulty": 2,
|
||||
"release_target": "v758",
|
||||
"expected_outcome": "implement",
|
||||
"budget": {
|
||||
"max_tool_calls": 40,
|
||||
"max_activations": 10
|
||||
},
|
||||
"seed": [
|
||||
{
|
||||
"type": "FUGR",
|
||||
"name": "{{P}}FG_PROD",
|
||||
"description": "Production confirmation modules"
|
||||
},
|
||||
{
|
||||
"type": "FUNC",
|
||||
"name": "{{P}}PRD_SAMPLE",
|
||||
"functionGroup": "{{P}}FG_PROD",
|
||||
"file": "seed/prd_sample.func.abap",
|
||||
"description": "Sample confirmation module"
|
||||
}
|
||||
],
|
||||
"contract": [
|
||||
{
|
||||
"type": "FUNC",
|
||||
"name": "{{P}}PRD_SCRAP",
|
||||
"functionGroup": "{{P}}FG_PROD",
|
||||
"params": [
|
||||
{
|
||||
"name": "iv_quantity",
|
||||
"type": "decfloat34"
|
||||
},
|
||||
{
|
||||
"name": "iv_scrap",
|
||||
"type": "decfloat34"
|
||||
},
|
||||
{
|
||||
"name": "ev_scrap_pct",
|
||||
"type": "decfloat34"
|
||||
},
|
||||
{
|
||||
"name": "ev_severity",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "cv_rework_qty",
|
||||
"type": "decfloat34"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"out_of_scope": [
|
||||
"{{P}}PRD_SAMPLE"
|
||||
],
|
||||
"hidden_tests": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}T14_HIDDEN",
|
||||
"file": "hidden/t14_hidden.clas.abap",
|
||||
"description": "T14 hidden tests"
|
||||
}
|
||||
],
|
||||
"reference": [
|
||||
{
|
||||
"type": "FUNC",
|
||||
"name": "{{P}}PRD_SCRAP",
|
||||
"functionGroup": "{{P}}FG_PROD",
|
||||
"file": "reference/prd_scrap.func.abap",
|
||||
"description": "Scrap evaluation module"
|
||||
},
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}T14_TEST",
|
||||
"file": "reference/t14_test.clas.abap",
|
||||
"description": "T14 own tests"
|
||||
}
|
||||
],
|
||||
"craft_checks": [
|
||||
"method_length"
|
||||
]
|
||||
}
|
||||
26
tasks_gen/eval/G0013/generation.json
Normal file
26
tasks_gen/eval/G0013/generation.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"id": "G0013",
|
||||
"pool": "eval",
|
||||
"object_type": "FUNC",
|
||||
"category": "I",
|
||||
"attempts": [
|
||||
{
|
||||
"stage": "validate",
|
||||
"oracle": 70.5,
|
||||
"null": 0
|
||||
},
|
||||
{
|
||||
"stage": "validate",
|
||||
"oracle": 100.0,
|
||||
"null": 0
|
||||
},
|
||||
{
|
||||
"stage": "manual_fix",
|
||||
"by": "Claude review 2026-10-03",
|
||||
"change": "Removed own test class REPL_TEST from the contract and from the spec acceptance (own tests are the model's choice). REPL_TEST stays in the reference as own tests.",
|
||||
"oracle": 100.0,
|
||||
"null": 0
|
||||
}
|
||||
],
|
||||
"accepted": true
|
||||
}
|
||||
108
tasks_gen/eval/G0013/hidden/t21_hidden.clas.abap
Normal file
108
tasks_gen/eval/G0013/hidden/t21_hidden.clas.abap
Normal file
@@ -0,0 +1,108 @@
|
||||
CLASS {{p}}t21_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
|
||||
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
|
||||
PRIVATE SECTION.
|
||||
TYPES: BEGIN OF ty_result,
|
||||
qty TYPE decfloat34,
|
||||
action TYPE string,
|
||||
subrc TYPE sysubrc,
|
||||
END OF ty_result.
|
||||
METHODS call
|
||||
IMPORTING iv_stock TYPE decfloat34
|
||||
iv_safety TYPE decfloat34
|
||||
iv_lot_size TYPE decfloat34
|
||||
iv_min_order TYPE decfloat34
|
||||
RETURNING VALUE(rs_result) TYPE ty_result.
|
||||
METHODS exact_multiple_lot FOR TESTING.
|
||||
METHODS exact_multiple_single_lot FOR TESTING.
|
||||
METHODS exact_multiple_with_minimum FOR TESTING.
|
||||
METHODS partial_lot_rounds_up FOR TESTING.
|
||||
METHODS stock_above_safety FOR TESTING.
|
||||
METHODS stock_equals_safety FOR TESTING.
|
||||
METHODS no_lot_size_no_rounding FOR TESTING.
|
||||
METHODS minimum_order_applies FOR TESTING.
|
||||
METHODS minimum_order_keeps_quantity FOR TESTING.
|
||||
METHODS negative_lot_size FOR TESTING.
|
||||
METHODS negative_min_order FOR TESTING.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}t21_hidden IMPLEMENTATION.
|
||||
METHOD call.
|
||||
CALL FUNCTION '{{P}}REPL_QTY'
|
||||
EXPORTING
|
||||
iv_stock = iv_stock
|
||||
iv_safety = iv_safety
|
||||
iv_lot_size = iv_lot_size
|
||||
iv_min_order = iv_min_order
|
||||
IMPORTING
|
||||
ev_order_qty = rs_result-qty
|
||||
ev_action = rs_result-action
|
||||
EXCEPTIONS
|
||||
invalid_input = 1
|
||||
OTHERS = 2.
|
||||
rs_result-subrc = sy-subrc.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD exact_multiple_lot.
|
||||
DATA(ls_result) = call( iv_stock = 0 iv_safety = 100 iv_lot_size = 50 iv_min_order = 0 ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 0 act = ls_result-subrc ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 100 ) act = ls_result-qty ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `ORDER` act = ls_result-action ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD exact_multiple_single_lot.
|
||||
DATA(ls_result) = call( iv_stock = 0 iv_safety = 50 iv_lot_size = 50 iv_min_order = 0 ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 0 act = ls_result-subrc ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 50 ) act = ls_result-qty ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD exact_multiple_with_minimum.
|
||||
DATA(ls_result) = call( iv_stock = 0 iv_safety = 100 iv_lot_size = 50 iv_min_order = 120 ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 120 ) act = ls_result-qty ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `ORDER` act = ls_result-action ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD partial_lot_rounds_up.
|
||||
DATA(ls_result) = call( iv_stock = 0 iv_safety = 110 iv_lot_size = 50 iv_min_order = 0 ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 150 ) act = ls_result-qty ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `ORDER` act = ls_result-action ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD stock_above_safety.
|
||||
DATA(ls_result) = call( iv_stock = 200 iv_safety = 100 iv_lot_size = 50 iv_min_order = 50 ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = ls_result-qty ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `NONE` act = ls_result-action ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD stock_equals_safety.
|
||||
DATA(ls_result) = call( iv_stock = 100 iv_safety = 100 iv_lot_size = 50 iv_min_order = 0 ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = ls_result-qty ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `NONE` act = ls_result-action ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD no_lot_size_no_rounding.
|
||||
DATA(ls_result) = call( iv_stock = 0 iv_safety = '37.5' iv_lot_size = 0 iv_min_order = 0 ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( '37.5' ) act = ls_result-qty ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `ORDER` act = ls_result-action ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD minimum_order_applies.
|
||||
DATA(ls_result) = call( iv_stock = 0 iv_safety = 10 iv_lot_size = 0 iv_min_order = 25 ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 25 ) act = ls_result-qty ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD minimum_order_keeps_quantity.
|
||||
DATA(ls_result) = call( iv_stock = 0 iv_safety = 100 iv_lot_size = 0 iv_min_order = 25 ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 100 ) act = ls_result-qty ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD negative_lot_size.
|
||||
DATA(ls_result) = call( iv_stock = 0 iv_safety = 100 iv_lot_size = -1 iv_min_order = 0 ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 1 act = ls_result-subrc ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD negative_min_order.
|
||||
DATA(ls_result) = call( iv_stock = 0 iv_safety = 100 iv_lot_size = 0 iv_min_order = -1 ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 1 act = ls_result-subrc ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
38
tasks_gen/eval/G0013/reference/repl_qty.func.abap
Normal file
38
tasks_gen/eval/G0013/reference/repl_qty.func.abap
Normal file
@@ -0,0 +1,38 @@
|
||||
FUNCTION {{p}}repl_qty
|
||||
IMPORTING
|
||||
iv_stock TYPE decfloat34
|
||||
iv_safety TYPE decfloat34
|
||||
iv_lot_size TYPE decfloat34
|
||||
iv_min_order TYPE decfloat34
|
||||
EXPORTING
|
||||
ev_order_qty TYPE decfloat34
|
||||
ev_action TYPE string
|
||||
EXCEPTIONS
|
||||
invalid_input.
|
||||
|
||||
IF iv_lot_size < 0 OR iv_min_order < 0.
|
||||
RAISE invalid_input.
|
||||
ENDIF.
|
||||
|
||||
DATA lv_required TYPE decfloat34.
|
||||
lv_required = iv_safety - iv_stock.
|
||||
|
||||
IF lv_required <= 0.
|
||||
ev_order_qty = 0.
|
||||
ev_action = 'NONE'.
|
||||
RETURN.
|
||||
ENDIF.
|
||||
|
||||
IF iv_lot_size > 0.
|
||||
ev_order_qty = ceil( lv_required / iv_lot_size ) * iv_lot_size.
|
||||
ELSE.
|
||||
ev_order_qty = lv_required.
|
||||
ENDIF.
|
||||
|
||||
IF ev_order_qty < iv_min_order.
|
||||
ev_order_qty = iv_min_order.
|
||||
ENDIF.
|
||||
|
||||
ev_action = 'ORDER'.
|
||||
|
||||
ENDFUNCTION.
|
||||
65
tasks_gen/eval/G0013/reference/t21_test.clas.abap
Normal file
65
tasks_gen/eval/G0013/reference/t21_test.clas.abap
Normal file
@@ -0,0 +1,65 @@
|
||||
CLASS {{p}}repl_test DEFINITION PUBLIC FINAL CREATE PUBLIC
|
||||
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
|
||||
PRIVATE SECTION.
|
||||
TYPES: BEGIN OF ty_result,
|
||||
qty TYPE decfloat34,
|
||||
action TYPE string,
|
||||
subrc TYPE sysubrc,
|
||||
END OF ty_result.
|
||||
METHODS call
|
||||
IMPORTING iv_stock TYPE decfloat34
|
||||
iv_safety TYPE decfloat34
|
||||
iv_lot_size TYPE decfloat34
|
||||
iv_min_order TYPE decfloat34
|
||||
RETURNING VALUE(rs_result) TYPE ty_result.
|
||||
METHODS exact_multiple FOR TESTING.
|
||||
METHODS partial_lot FOR TESTING.
|
||||
METHODS no_order FOR TESTING.
|
||||
METHODS minimum_order FOR TESTING.
|
||||
METHODS invalid_input FOR TESTING.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}repl_test IMPLEMENTATION.
|
||||
METHOD call.
|
||||
CALL FUNCTION '{{P}}REPL_QTY'
|
||||
EXPORTING
|
||||
iv_stock = iv_stock
|
||||
iv_safety = iv_safety
|
||||
iv_lot_size = iv_lot_size
|
||||
iv_min_order = iv_min_order
|
||||
IMPORTING
|
||||
ev_order_qty = rs_result-qty
|
||||
ev_action = rs_result-action
|
||||
EXCEPTIONS
|
||||
invalid_input = 1
|
||||
OTHERS = 2.
|
||||
rs_result-subrc = sy-subrc.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD exact_multiple.
|
||||
DATA(ls_result) = call( iv_stock = 0 iv_safety = 100 iv_lot_size = 50 iv_min_order = 0 ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 100 ) act = ls_result-qty ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD partial_lot.
|
||||
DATA(ls_result) = call( iv_stock = 0 iv_safety = 101 iv_lot_size = 50 iv_min_order = 0 ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 150 ) act = ls_result-qty ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD no_order.
|
||||
DATA(ls_result) = call( iv_stock = 300 iv_safety = 100 iv_lot_size = 50 iv_min_order = 0 ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 0 ) act = ls_result-qty ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `NONE` act = ls_result-action ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD minimum_order.
|
||||
DATA(ls_result) = call( iv_stock = 0 iv_safety = 5 iv_lot_size = 0 iv_min_order = 20 ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = CONV decfloat34( 20 ) act = ls_result-qty ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD invalid_input.
|
||||
DATA(ls_result) = call( iv_stock = 0 iv_safety = 100 iv_lot_size = -5 iv_min_order = 0 ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 1 act = ls_result-subrc ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
38
tasks_gen/eval/G0013/seed/repl_qty.func.abap
Normal file
38
tasks_gen/eval/G0013/seed/repl_qty.func.abap
Normal file
@@ -0,0 +1,38 @@
|
||||
FUNCTION {{p}}repl_qty
|
||||
IMPORTING
|
||||
iv_stock TYPE decfloat34
|
||||
iv_safety TYPE decfloat34
|
||||
iv_lot_size TYPE decfloat34
|
||||
iv_min_order TYPE decfloat34
|
||||
EXPORTING
|
||||
ev_order_qty TYPE decfloat34
|
||||
ev_action TYPE string
|
||||
EXCEPTIONS
|
||||
invalid_input.
|
||||
|
||||
IF iv_lot_size < 0.
|
||||
RAISE invalid_input.
|
||||
ENDIF.
|
||||
|
||||
DATA lv_required TYPE decfloat34.
|
||||
lv_required = iv_safety - iv_stock.
|
||||
|
||||
IF lv_required <= 0.
|
||||
ev_order_qty = 0.
|
||||
ev_action = 'NONE'.
|
||||
RETURN.
|
||||
ENDIF.
|
||||
|
||||
IF iv_lot_size > 0.
|
||||
ev_order_qty = ( floor( lv_required / iv_lot_size ) + 1 ) * iv_lot_size.
|
||||
ELSE.
|
||||
ev_order_qty = lv_required.
|
||||
ENDIF.
|
||||
|
||||
IF ev_order_qty < iv_min_order.
|
||||
ev_order_qty = iv_min_order.
|
||||
ENDIF.
|
||||
|
||||
ev_action = 'ORDER'.
|
||||
|
||||
ENDFUNCTION.
|
||||
38
tasks_gen/eval/G0013/seed/repl_qty_old.func.abap
Normal file
38
tasks_gen/eval/G0013/seed/repl_qty_old.func.abap
Normal file
@@ -0,0 +1,38 @@
|
||||
FUNCTION {{p}}repl_qty_old
|
||||
IMPORTING
|
||||
iv_stock TYPE decfloat34
|
||||
iv_safety TYPE decfloat34
|
||||
iv_lot_size TYPE decfloat34
|
||||
iv_min_order TYPE decfloat34
|
||||
EXPORTING
|
||||
ev_order_qty TYPE decfloat34
|
||||
ev_action TYPE string
|
||||
EXCEPTIONS
|
||||
invalid_input.
|
||||
|
||||
IF iv_lot_size < 0.
|
||||
RAISE invalid_input.
|
||||
ENDIF.
|
||||
|
||||
DATA lv_required TYPE decfloat34.
|
||||
lv_required = iv_safety - iv_stock.
|
||||
|
||||
IF lv_required <= 0.
|
||||
ev_order_qty = 0.
|
||||
ev_action = 'NONE'.
|
||||
RETURN.
|
||||
ENDIF.
|
||||
|
||||
IF iv_lot_size > 0.
|
||||
ev_order_qty = ( floor( lv_required / iv_lot_size ) + 1 ) * iv_lot_size.
|
||||
ELSE.
|
||||
ev_order_qty = lv_required.
|
||||
ENDIF.
|
||||
|
||||
IF ev_order_qty < iv_min_order.
|
||||
ev_order_qty = iv_min_order.
|
||||
ENDIF.
|
||||
|
||||
ev_action = 'ORDER'.
|
||||
|
||||
ENDFUNCTION.
|
||||
48
tasks_gen/eval/G0013/spec.md
Normal file
48
tasks_gen/eval/G0013/spec.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# 1. Goal
|
||||
The function module {{P}}REPL_QTY_OLD calculates the replenishment order quantity for a material. Users report two defects:
|
||||
- When the required quantity is exactly a multiple of the lot size, the module orders one lot too many.
|
||||
- The module accepts a negative minimum order quantity. It must report an error instead.
|
||||
The module {{P}}REPL_QTY_OLD is used by a released interface and must not change. Deliver the corrected calculation in the new function module {{P}}REPL_QTY.
|
||||
|
||||
# 2. Open questions
|
||||
None.
|
||||
|
||||
# 3. Context
|
||||
- Function group {{P}}FG_REPL exists in package $TMP.
|
||||
- Function module {{P}}REPL_QTY_OLD exists in this group. It is the module in production. It has the two defects above.
|
||||
- The replenishment program will call {{P}}REPL_QTY.
|
||||
|
||||
# 4. Contract
|
||||
Create the function module {{P}}REPL_QTY in function group {{P}}FG_REPL with this interface:
|
||||
|
||||
IMPORTING
|
||||
iv_stock TYPE decfloat34
|
||||
iv_safety TYPE decfloat34
|
||||
iv_lot_size TYPE decfloat34
|
||||
iv_min_order TYPE decfloat34
|
||||
EXPORTING
|
||||
ev_order_qty TYPE decfloat34
|
||||
ev_action TYPE string
|
||||
EXCEPTIONS
|
||||
invalid_input
|
||||
|
||||
ev_action contains the value 'ORDER' or the value 'NONE'.
|
||||
|
||||
# 5. Business rules
|
||||
1. If iv_lot_size is less than 0, or if iv_min_order is less than 0, raise the exception INVALID_INPUT.
|
||||
2. The required quantity is iv_safety minus iv_stock.
|
||||
3. If the required quantity is less than or equal to 0, ev_order_qty is 0 and ev_action is 'NONE'. Rules 4 to 6 do not apply then.
|
||||
4. If iv_lot_size is greater than 0, round the required quantity up to the next multiple of iv_lot_size. A required quantity that is already a multiple of iv_lot_size does not change.
|
||||
5. If iv_lot_size is 0, do not round.
|
||||
6. If ev_order_qty is less than iv_min_order, set ev_order_qty to iv_min_order.
|
||||
7. If ev_order_qty is greater than 0, ev_action is 'ORDER'. Otherwise ev_action is 'NONE'.
|
||||
|
||||
# 6. Constraints
|
||||
- Release target: 8.16.
|
||||
- Coding standards: Clean ABAP. Keep methods below 40 statements.
|
||||
- Out of scope: do not change the function group {{P}}FG_REPL. Do not change {{P}}REPL_QTY_OLD.
|
||||
|
||||
# 7. Acceptance
|
||||
- The function module {{P}}REPL_QTY is active and has no syntax error.
|
||||
- The hidden tests pass.
|
||||
- Write ABAP Unit tests for the function module in a global test class.
|
||||
89
tasks_gen/eval/G0013/task.json
Normal file
89
tasks_gen/eval/G0013/task.json
Normal file
@@ -0,0 +1,89 @@
|
||||
{
|
||||
"id": "G0013",
|
||||
"category": "I",
|
||||
"object_type": "FUNC",
|
||||
"difficulty": 2,
|
||||
"release_target": "v816",
|
||||
"expected_outcome": "implement",
|
||||
"budget": {
|
||||
"max_tool_calls": 40,
|
||||
"max_activations": 10
|
||||
},
|
||||
"seed": [
|
||||
{
|
||||
"type": "FUGR",
|
||||
"name": "{{P}}FG_REPL",
|
||||
"description": "Replenishment function group"
|
||||
},
|
||||
{
|
||||
"type": "FUNC",
|
||||
"name": "{{P}}REPL_QTY_OLD",
|
||||
"functionGroup": "{{P}}FG_REPL",
|
||||
"file": "seed/repl_qty_old.func.abap",
|
||||
"description": "Faulty replenishment order quantity module"
|
||||
}
|
||||
],
|
||||
"contract": [
|
||||
{
|
||||
"type": "FUNC",
|
||||
"name": "{{P}}REPL_QTY",
|
||||
"functionGroup": "{{P}}FG_REPL",
|
||||
"params": [
|
||||
{
|
||||
"name": "iv_stock",
|
||||
"type": "decfloat34"
|
||||
},
|
||||
{
|
||||
"name": "iv_safety",
|
||||
"type": "decfloat34"
|
||||
},
|
||||
{
|
||||
"name": "iv_lot_size",
|
||||
"type": "decfloat34"
|
||||
},
|
||||
{
|
||||
"name": "iv_min_order",
|
||||
"type": "decfloat34"
|
||||
},
|
||||
{
|
||||
"name": "ev_order_qty",
|
||||
"type": "decfloat34"
|
||||
},
|
||||
{
|
||||
"name": "ev_action",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"out_of_scope": [
|
||||
"{{P}}FG_REPL",
|
||||
"{{P}}REPL_QTY_OLD"
|
||||
],
|
||||
"hidden_tests": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}T21_HIDDEN",
|
||||
"file": "hidden/t21_hidden.clas.abap",
|
||||
"description": "T21 hidden tests"
|
||||
}
|
||||
],
|
||||
"reference": [
|
||||
{
|
||||
"type": "FUNC",
|
||||
"name": "{{P}}REPL_QTY",
|
||||
"functionGroup": "{{P}}FG_REPL",
|
||||
"file": "reference/repl_qty.func.abap",
|
||||
"description": "Corrected replenishment order quantity module"
|
||||
},
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}REPL_TEST",
|
||||
"file": "reference/t21_test.clas.abap",
|
||||
"description": "Own tests of the reference (not contract)"
|
||||
}
|
||||
],
|
||||
"craft_checks": [
|
||||
"method_length"
|
||||
]
|
||||
}
|
||||
19
tasks_gen/eval/G0014/generation.json
Normal file
19
tasks_gen/eval/G0014/generation.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"id": "G0014",
|
||||
"pool": "eval",
|
||||
"object_type": "PROG",
|
||||
"category": "B",
|
||||
"attempts": [
|
||||
{
|
||||
"stage": "validate",
|
||||
"oracle": 93.3,
|
||||
"null": 0
|
||||
},
|
||||
{
|
||||
"stage": "validate",
|
||||
"oracle": 100.0,
|
||||
"null": 0
|
||||
}
|
||||
],
|
||||
"accepted": true
|
||||
}
|
||||
112
tasks_gen/eval/G0014/hidden/t15_hidden.clas.abap
Normal file
112
tasks_gen/eval/G0014/hidden/t15_hidden.clas.abap
Normal file
@@ -0,0 +1,112 @@
|
||||
CLASS {{p}}t15_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
|
||||
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
|
||||
PRIVATE SECTION.
|
||||
TYPES tt_plant TYPE RANGE OF {{p}}movmt-plant.
|
||||
METHODS run
|
||||
IMPORTING iv_from TYPE d
|
||||
iv_to TYPE d
|
||||
it_plant TYPE tt_plant 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 all_materials_in_range FOR TESTING.
|
||||
METHODS receipt_and_issue_split FOR TESTING.
|
||||
METHODS sorted_by_balance FOR TESTING.
|
||||
METHODS plant_filter FOR TESTING.
|
||||
METHODS date_range_filter FOR TESTING.
|
||||
METHODS ignored_move_types FOR TESTING.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}t15_hidden IMPLEMENTATION.
|
||||
METHOD run.
|
||||
cl_salv_bs_runtime_info=>set( display = abap_false metadata = abap_false data = abap_true ).
|
||||
SUBMIT {{p}}stock_bal
|
||||
WITH p_from = iv_from
|
||||
WITH p_to = iv_to
|
||||
WITH s_plant IN it_plant
|
||||
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> ) ).
|
||||
" The ALV data can show a negative number with a trailing sign.
|
||||
DATA(lv_length) = strlen( rv_value ).
|
||||
IF lv_length > 1 AND substring( val = rv_value off = lv_length - 1 len = 1 ) = '-'.
|
||||
rv_value = '-' && substring( val = rv_value off = 0 len = lv_length - 1 ).
|
||||
ENDIF.
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD all_materials_in_range.
|
||||
DATA(lr_data) = run( iv_from = '20260101' iv_to = '20260131' ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines_of( lr_data ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `MAT-001` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `MATERIAL` ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `120` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `BALANCE` ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `MAT-002` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `MATERIAL` ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `-20` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `BALANCE` ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD receipt_and_issue_split.
|
||||
DATA(lr_data) = run( iv_from = '20260101' iv_to = '20260131' ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `150` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `RECEIPT_QTY` ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `30` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `ISSUE_QTY` ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `40` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `RECEIPT_QTY` ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `60` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `ISSUE_QTY` ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD sorted_by_balance.
|
||||
DATA(lr_data) = run( iv_from = '20251201' iv_to = '20260131' ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 3 act = lines_of( lr_data ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `MAT-001` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `MATERIAL` ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `MAT-004` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `MATERIAL` ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `MAT-002` act = value_of( ir_data = lr_data iv_row = 3 iv_col = `MATERIAL` ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD plant_filter.
|
||||
DATA(lr_data) = run( iv_from = '20260101' iv_to = '20260131'
|
||||
it_plant = VALUE #( ( sign = 'I' option = 'EQ' low = '1000' ) ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines_of( lr_data ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `MAT-001` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `MATERIAL` ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `70` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `BALANCE` ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD date_range_filter.
|
||||
DATA(lr_data) = run( iv_from = '20260101' iv_to = '20260109' ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines_of( lr_data ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `100` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `BALANCE` ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `40` act = value_of( ir_data = lr_data iv_row = 2 iv_col = `BALANCE` ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD ignored_move_types.
|
||||
DATA(lr_data) = run( iv_from = '20260101' iv_to = '20260131'
|
||||
it_plant = VALUE #( ( sign = 'I' option = 'EQ' low = '2000' ) ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines_of( lr_data ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `MAT-001` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `MATERIAL` ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `50` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `RECEIPT_QTY` ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `0` act = value_of( ir_data = lr_data iv_row = 1 iv_col = `ISSUE_QTY` ) ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
127
tasks_gen/eval/G0014/reference/stock_bal.prog.abap
Normal file
127
tasks_gen/eval/G0014/reference/stock_bal.prog.abap
Normal file
@@ -0,0 +1,127 @@
|
||||
REPORT {{p}}stock_bal.
|
||||
|
||||
DATA gv_plant TYPE {{p}}movmt-plant.
|
||||
|
||||
PARAMETERS p_from TYPE d OBLIGATORY.
|
||||
PARAMETERS p_to TYPE d OBLIGATORY.
|
||||
SELECT-OPTIONS s_plant FOR gv_plant.
|
||||
|
||||
CLASS lcl_report DEFINITION FINAL.
|
||||
PUBLIC SECTION.
|
||||
TYPES:
|
||||
BEGIN OF ty_line,
|
||||
material TYPE {{p}}movmt-material,
|
||||
receipt_qty TYPE i,
|
||||
issue_qty TYPE i,
|
||||
balance TYPE i,
|
||||
END OF ty_line,
|
||||
tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY,
|
||||
tt_plant TYPE RANGE OF {{p}}movmt-plant.
|
||||
METHODS select_balances
|
||||
IMPORTING iv_from TYPE d
|
||||
iv_to TYPE d
|
||||
it_plant TYPE tt_plant
|
||||
RETURNING VALUE(rt_lines) TYPE tt_line.
|
||||
METHODS display
|
||||
CHANGING ct_lines TYPE tt_line.
|
||||
ENDCLASS.
|
||||
|
||||
CLASS lcl_report IMPLEMENTATION.
|
||||
METHOD select_balances.
|
||||
SELECT material,
|
||||
SUM( CASE WHEN move_type = '101' OR move_type = '201'
|
||||
THEN quantity
|
||||
ELSE 0 END ) AS receipt_qty,
|
||||
SUM( CASE WHEN move_type = '261' OR move_type = '262'
|
||||
THEN quantity
|
||||
ELSE 0 END ) AS issue_qty
|
||||
FROM {{p}}movmt
|
||||
WHERE move_date >= @iv_from
|
||||
AND move_date <= @iv_to
|
||||
AND plant IN @it_plant
|
||||
AND move_type IN ( '101', '201', '261', '262' )
|
||||
GROUP BY material
|
||||
INTO CORRESPONDING FIELDS OF TABLE @rt_lines.
|
||||
|
||||
LOOP AT rt_lines ASSIGNING FIELD-SYMBOL(<ls_line>).
|
||||
<ls_line>-balance = <ls_line>-receipt_qty - <ls_line>-issue_qty.
|
||||
ENDLOOP.
|
||||
|
||||
SORT rt_lines BY balance DESCENDING.
|
||||
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_balances( iv_from = p_from
|
||||
iv_to = p_to
|
||||
it_plant = s_plant[] ).
|
||||
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 balances_per_material FOR TESTING.
|
||||
METHODS plant_filter FOR TESTING.
|
||||
METHODS negative_balance FOR TESTING.
|
||||
ENDCLASS.
|
||||
|
||||
CLASS ltc_report IMPLEMENTATION.
|
||||
METHOD class_setup.
|
||||
go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( '{{P}}MOVMT' ) ) ).
|
||||
DATA lt_movmt TYPE STANDARD TABLE OF {{p}}movmt WITH EMPTY KEY.
|
||||
lt_movmt = VALUE #(
|
||||
( move_id = 1 material = 'MAT-A' plant = '1000' move_date = '20260105' move_type = '101' quantity = 100 )
|
||||
( move_id = 2 material = 'MAT-A' plant = '1000' move_date = '20260110' move_type = '261' quantity = 30 )
|
||||
( move_id = 3 material = 'MAT-B' plant = '2000' move_date = '20260112' move_type = '201' quantity = 40 )
|
||||
( move_id = 4 material = 'MAT-B' plant = '2000' move_date = '20260113' move_type = '262' quantity = 90 )
|
||||
( move_id = 5 material = 'MAT-C' plant = '2000' move_date = '20260112' move_type = '999' quantity = 500 ) ).
|
||||
go_env->insert_test_data( lt_movmt ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD class_teardown.
|
||||
go_env->destroy( ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD balances_per_material.
|
||||
DATA(lt_lines) = NEW lcl_report( )->select_balances(
|
||||
iv_from = '20260101' iv_to = '20260131' it_plant = VALUE #( ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_lines ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 'MAT-A' act = lt_lines[ 1 ]-material ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 70 act = lt_lines[ 1 ]-balance ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 'MAT-B' act = lt_lines[ 2 ]-material ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = -50 act = lt_lines[ 2 ]-balance ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD plant_filter.
|
||||
DATA(lt_lines) = NEW lcl_report( )->select_balances(
|
||||
iv_from = '20260101'
|
||||
iv_to = '20260131'
|
||||
it_plant = VALUE #( ( sign = 'I' option = 'EQ' low = '1000' ) ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_lines ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 'MAT-A' act = lt_lines[ 1 ]-material ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 30 act = lt_lines[ 1 ]-issue_qty ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD negative_balance.
|
||||
DATA(lt_lines) = NEW lcl_report( )->select_balances(
|
||||
iv_from = '20260101'
|
||||
iv_to = '20260131'
|
||||
it_plant = VALUE #( ( sign = 'I' option = 'EQ' low = '2000' ) ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_lines ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 'MAT-B' act = lt_lines[ 1 ]-material ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = -50 act = lt_lines[ 1 ]-balance ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
14
tasks_gen/eval/G0014/seed/movmt.tabl.asabap
Normal file
14
tasks_gen/eval/G0014/seed/movmt.tabl.asabap
Normal file
@@ -0,0 +1,14 @@
|
||||
@EndUserText.label : 'Stock movements'
|
||||
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
|
||||
@AbapCatalog.tableCategory : #TRANSPARENT
|
||||
@AbapCatalog.deliveryClass : #A
|
||||
@AbapCatalog.dataMaintenance : #RESTRICTED
|
||||
define table {{p}}movmt {
|
||||
key client : abap.clnt not null;
|
||||
key move_id : abap.int4 not null;
|
||||
material : abap.char(10);
|
||||
plant : abap.char(4);
|
||||
move_date : abap.dats;
|
||||
move_type : abap.char(3);
|
||||
quantity : abap.int4;
|
||||
}
|
||||
19
tasks_gen/eval/G0014/seed/t15_seed.clas.abap
Normal file
19
tasks_gen/eval/G0014/seed/t15_seed.clas.abap
Normal file
@@ -0,0 +1,19 @@
|
||||
CLASS {{p}}t15_seed DEFINITION PUBLIC FINAL CREATE PUBLIC.
|
||||
PUBLIC SECTION.
|
||||
INTERFACES if_oo_adt_classrun.
|
||||
ENDCLASS.
|
||||
|
||||
CLASS {{p}}t15_seed IMPLEMENTATION.
|
||||
METHOD if_oo_adt_classrun~main.
|
||||
DELETE FROM {{p}}movmt.
|
||||
INSERT {{p}}movmt FROM TABLE @( VALUE #(
|
||||
( move_id = 1 material = 'MAT-001' plant = '1000' move_date = '20260105' move_type = '101' quantity = 100 )
|
||||
( move_id = 2 material = 'MAT-001' plant = '1000' move_date = '20260110' move_type = '261' quantity = 30 )
|
||||
( move_id = 3 material = 'MAT-001' plant = '2000' move_date = '20260120' move_type = '101' quantity = 50 )
|
||||
( move_id = 4 material = 'MAT-002' plant = '1000' move_date = '20260108' move_type = '201' quantity = 40 )
|
||||
( move_id = 5 material = 'MAT-002' plant = '1000' move_date = '20260115' move_type = '262' quantity = 60 )
|
||||
( move_id = 6 material = 'MAT-003' plant = '2000' move_date = '20260112' move_type = '999' quantity = 500 )
|
||||
( move_id = 7 material = 'MAT-004' plant = '1000' move_date = '20251220' move_type = '101' quantity = 70 ) ) ).
|
||||
out->write( sy-dbcnt ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
43
tasks_gen/eval/G0014/spec.md
Normal file
43
tasks_gen/eval/G0014/spec.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# 1. Goal
|
||||
Show the stock balance for each material in a warehouse. The warehouse team uses
|
||||
the list to compare the receipts and the issues of a period.
|
||||
|
||||
# 2. Open questions
|
||||
None.
|
||||
|
||||
# 3. Context
|
||||
- Table {{P}}MOVMT exists in package $TMP. It contains data.
|
||||
Fields: MOVE_ID (INT4, key), MATERIAL (CHAR 10), PLANT (CHAR 4),
|
||||
MOVE_DATE (DATS), MOVE_TYPE (CHAR 3), QUANTITY (INT4).
|
||||
|
||||
# 4. Contract
|
||||
- Create the executable program {{P}}STOCK_BAL in package $TMP.
|
||||
- Selection screen:
|
||||
- Parameter P_FROM, type DATS, mandatory: the first movement date to include.
|
||||
- Parameter P_TO, type DATS, mandatory: the last movement date to include.
|
||||
- Select-option S_PLANT for the plant.
|
||||
- Show the result with CL_SALV_TABLE. The output table has these columns, with
|
||||
these names: MATERIAL, RECEIPT_QTY, ISSUE_QTY, BALANCE.
|
||||
|
||||
# 5. Business rules
|
||||
1. A movement is in scope if MOVE_DATE is on or after P_FROM and on or before
|
||||
P_TO, and PLANT is in S_PLANT.
|
||||
2. An in-scope movement is a receipt if MOVE_TYPE is '101' or '201'. It is an
|
||||
issue if MOVE_TYPE is '261' or '262'. All other in-scope movements are
|
||||
ignored.
|
||||
3. RECEIPT_QTY is the sum of QUANTITY of all receipts of the material.
|
||||
ISSUE_QTY is the sum of QUANTITY of all issues of the material.
|
||||
BALANCE is RECEIPT_QTY minus ISSUE_QTY.
|
||||
4. Show one line for each material that has at least one receipt or issue. A
|
||||
material with only ignored movements does not appear.
|
||||
5. Sort the lines by BALANCE, the highest balance first.
|
||||
|
||||
# 6. Constraints
|
||||
- Release target: 7.58.
|
||||
- Coding standards: Clean ABAP. Read the movement data with one database access.
|
||||
- Out of scope: do not change {{P}}MOVMT.
|
||||
|
||||
# 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.
|
||||
61
tasks_gen/eval/G0014/task.json
Normal file
61
tasks_gen/eval/G0014/task.json
Normal file
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"id": "G0014",
|
||||
"category": "B",
|
||||
"object_type": "PROG",
|
||||
"difficulty": 2,
|
||||
"release_target": "v758",
|
||||
"expected_outcome": "implement",
|
||||
"budget": {
|
||||
"max_tool_calls": 40,
|
||||
"max_activations": 10
|
||||
},
|
||||
"seed": [
|
||||
{
|
||||
"type": "TABL",
|
||||
"name": "{{P}}MOVMT",
|
||||
"file": "seed/movmt.tabl.asabap",
|
||||
"description": "Stock movements"
|
||||
},
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}T15_SEED",
|
||||
"file": "seed/t15_seed.clas.abap",
|
||||
"description": "T15 seed data",
|
||||
"run": true
|
||||
}
|
||||
],
|
||||
"contract": [
|
||||
{
|
||||
"type": "PROG",
|
||||
"name": "{{P}}STOCK_BAL",
|
||||
"parameters": [
|
||||
"p_from",
|
||||
"p_to",
|
||||
"s_plant"
|
||||
]
|
||||
}
|
||||
],
|
||||
"out_of_scope": [
|
||||
"{{P}}MOVMT"
|
||||
],
|
||||
"hidden_tests": [
|
||||
{
|
||||
"type": "CLAS",
|
||||
"name": "{{P}}T15_HIDDEN",
|
||||
"file": "hidden/t15_hidden.clas.abap",
|
||||
"description": "T15 hidden tests"
|
||||
}
|
||||
],
|
||||
"reference": [
|
||||
{
|
||||
"type": "PROG",
|
||||
"name": "{{P}}STOCK_BAL",
|
||||
"file": "reference/stock_bal.prog.abap",
|
||||
"description": "Stock balance per material"
|
||||
}
|
||||
],
|
||||
"craft_checks": [
|
||||
"db_operation_in_loop",
|
||||
"method_length"
|
||||
]
|
||||
}
|
||||
19
tasks_gen/eval/G0015/generation.json
Normal file
19
tasks_gen/eval/G0015/generation.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"id": "G0015",
|
||||
"pool": "eval",
|
||||
"object_type": "PROG",
|
||||
"category": "B",
|
||||
"attempts": [
|
||||
{
|
||||
"stage": "validate",
|
||||
"oracle": 0,
|
||||
"null": 0
|
||||
},
|
||||
{
|
||||
"stage": "validate",
|
||||
"oracle": 100.0,
|
||||
"null": 0
|
||||
}
|
||||
],
|
||||
"accepted": true
|
||||
}
|
||||
120
tasks_gen/eval/G0015/hidden/bill_age_test.clas.abap
Normal file
120
tasks_gen/eval/G0015/hidden/bill_age_test.clas.abap
Normal file
@@ -0,0 +1,120 @@
|
||||
CLASS {{p}}bill_age_test DEFINITION PUBLIC FINAL CREATE PUBLIC
|
||||
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
|
||||
PRIVATE SECTION.
|
||||
TYPES tt_customer TYPE RANGE OF {{p}}bill-customer.
|
||||
METHODS run
|
||||
IMPORTING iv_date TYPE d
|
||||
it_customer TYPE tt_customer 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 only_open_invoices FOR TESTING.
|
||||
METHODS paid_invoices_excluded FOR TESTING.
|
||||
METHODS sorted_by_open_amount FOR TESTING.
|
||||
METHODS count_and_amount FOR TESTING.
|
||||
METHODS overdue_amount FOR TESTING.
|
||||
METHODS no_overdue_amount FOR TESTING.
|
||||
METHODS customer_filter FOR TESTING.
|
||||
METHODS customer_filter_multiple FOR TESTING.
|
||||
ENDCLASS.
|
||||
|
||||
|
||||
CLASS {{p}}bill_age_test IMPLEMENTATION.
|
||||
METHOD run.
|
||||
cl_salv_bs_runtime_info=>set( display = abap_false metadata = abap_false data = abap_true ).
|
||||
SUBMIT {{p}}bill_age WITH p_date = iv_date WITH s_cust IN it_customer 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 } is missing| ).
|
||||
rv_value = condense( CONV string( <lv_value> ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD only_open_invoices.
|
||||
cl_abap_unit_assert=>assert_equals( exp = 4 act = lines_of( run( '20260101' ) ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD paid_invoices_excluded.
|
||||
DATA(lr_data) = run( '20260101' ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `C002`
|
||||
act = value_of( ir_data = lr_data iv_row = 2 iv_col = `CUSTOMER` ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `300.00`
|
||||
act = value_of( ir_data = lr_data iv_row = 2 iv_col = `OPEN_AMOUNT` ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD sorted_by_open_amount.
|
||||
DATA(lr_data) = run( '20260101' ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `C004`
|
||||
act = value_of( ir_data = lr_data iv_row = 1 iv_col = `CUSTOMER` ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `C003`
|
||||
act = value_of( ir_data = lr_data iv_row = 4 iv_col = `CUSTOMER` ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD count_and_amount.
|
||||
DATA(lr_data) = run( '20260101' ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `C001`
|
||||
act = value_of( ir_data = lr_data iv_row = 3 iv_col = `CUSTOMER` ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `2`
|
||||
act = value_of( ir_data = lr_data iv_row = 3 iv_col = `OPEN_COUNT` ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `150.00`
|
||||
act = value_of( ir_data = lr_data iv_row = 3 iv_col = `OPEN_AMOUNT` ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD overdue_amount.
|
||||
DATA(lr_data) = run( '20260301' ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `100.00`
|
||||
act = value_of( ir_data = lr_data iv_row = 3 iv_col = `OVERDUE_AMOUNT` ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `300.00`
|
||||
act = value_of( ir_data = lr_data iv_row = 2 iv_col = `OVERDUE_AMOUNT` ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD no_overdue_amount.
|
||||
DATA(lr_data) = run( '20260101' ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `0.00`
|
||||
act = value_of( ir_data = lr_data iv_row = 1 iv_col = `OVERDUE_AMOUNT` ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `0.00`
|
||||
act = value_of( ir_data = lr_data iv_row = 3 iv_col = `OVERDUE_AMOUNT` ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD customer_filter.
|
||||
DATA(lr_data) = run( iv_date = '20260101'
|
||||
it_customer = VALUE #( ( sign = 'I' option = 'EQ' low = 'C001' ) ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 1 act = lines_of( lr_data ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `150.00`
|
||||
act = value_of( ir_data = lr_data iv_row = 1 iv_col = `OPEN_AMOUNT` ) ).
|
||||
ENDMETHOD.
|
||||
|
||||
METHOD customer_filter_multiple.
|
||||
DATA(lr_data) = run( iv_date = '20260101'
|
||||
it_customer = VALUE #( ( sign = 'I' option = 'EQ' low = 'C001' )
|
||||
( sign = 'I' option = 'EQ' low = 'C002' ) ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = 2 act = lines_of( lr_data ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `C002`
|
||||
act = value_of( ir_data = lr_data iv_row = 1 iv_col = `CUSTOMER` ) ).
|
||||
cl_abap_unit_assert=>assert_equals( exp = `C001`
|
||||
act = value_of( ir_data = lr_data iv_row = 2 iv_col = `CUSTOMER` ) ).
|
||||
ENDMETHOD.
|
||||
ENDCLASS.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user