ADT fallback: Accept headers for FUNC; G0189 accepted; regen2 results

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014aUaQeLnwbb1zTpN7kHeat
This commit is contained in:
Kral
2026-10-03 16:31:03 +02:00
parent 428b3565b2
commit 7510131a7d
335 changed files with 12047 additions and 5545 deletions

View File

@@ -0,0 +1,115 @@
CLASS {{p}}provision_calc DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES:
ty_material TYPE c LENGTH 18,
ty_quantity TYPE p LENGTH 13 DECIMALS 3,
ty_price TYPE p LENGTH 11 DECIMALS 2,
ty_amount TYPE p LENGTH 13 DECIMALS 2,
ty_reason TYPE c LENGTH 20.
TYPES:
BEGIN OF ty_line,
material TYPE ty_material,
quantity TYPE ty_quantity,
price TYPE ty_price,
END OF ty_line.
TYPES tt_lines TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY.
CONSTANTS:
c_max_lines TYPE i VALUE 999,
c_value_limit TYPE ty_amount VALUE '100000.00',
c_empty_order TYPE ty_reason VALUE 'EMPTY_ORDER',
c_too_many_lines TYPE ty_reason VALUE 'TOO_MANY_LINES',
c_material_missing TYPE ty_reason VALUE 'MATERIAL_MISSING',
c_quantity_invalid TYPE ty_reason VALUE 'QUANTITY_INVALID',
c_price_negative TYPE ty_reason VALUE 'PRICE_NEGATIVE',
c_duplicate_material TYPE ty_reason VALUE 'DUPLICATE_MATERIAL',
c_limit_exceeded TYPE ty_reason VALUE 'LIMIT_EXCEEDED'.
METHODS constructor.
METHODS check_order
IMPORTING it_lines TYPE tt_lines
RAISING {{p}}cx_prov_error.
METHODS calculate_value
IMPORTING it_lines TYPE tt_lines
RETURNING VALUE(rv_value) TYPE ty_amount
RAISING {{p}}cx_prov_error.
PRIVATE SECTION.
TYPES tt_materials TYPE HASHED TABLE OF ty_material WITH UNIQUE KEY table_line.
METHODS check_lines
IMPORTING it_lines TYPE tt_lines
RAISING {{p}}cx_prov_error.
METHODS total_value
IMPORTING it_lines TYPE tt_lines
RETURNING VALUE(rv_value) TYPE ty_amount.
METHODS raise_error
IMPORTING iv_reason TYPE ty_reason
RAISING {{p}}cx_prov_error.
ENDCLASS.
CLASS {{p}}provision_calc IMPLEMENTATION.
METHOD constructor.
ENDMETHOD.
METHOD check_order.
IF it_lines IS INITIAL.
raise_error( c_empty_order ).
ENDIF.
IF lines( it_lines ) <= c_max_lines.
raise_error( c_too_many_lines ).
ENDIF.
check_lines( it_lines ).
IF total_value( it_lines ) > c_value_limit.
raise_error( c_limit_exceeded ).
ENDIF.
ENDMETHOD.
METHOD calculate_value.
check_order( it_lines ).
rv_value = total_value( it_lines ).
ENDMETHOD.
METHOD check_lines.
DATA lt_seen TYPE tt_materials.
LOOP AT it_lines INTO DATA(ls_line).
IF ls_line-material IS INITIAL.
raise_error( c_material_missing ).
ENDIF.
IF ls_line-quantity <= 0.
raise_error( c_quantity_invalid ).
ENDIF.
IF ls_line-price < 0.
raise_error( c_price_negative ).
ENDIF.
IF line_exists( lt_seen[ table_line = ls_line-material ] ).
raise_error( c_duplicate_material ).
ENDIF.
INSERT ls_line-material INTO TABLE lt_seen.
ENDLOOP.
ENDMETHOD.
METHOD total_value.
DATA lv_total TYPE p LENGTH 16 DECIMALS 5.
LOOP AT it_lines INTO DATA(ls_line).
lv_total = lv_total + ls_line-quantity * ls_line-price.
ENDLOOP.
rv_value = round( val = lv_total dec = 2 ).
ENDMETHOD.
METHOD raise_error.
RAISE EXCEPTION TYPE {{p}}cx_prov_error
EXPORTING
iv_reason = iv_reason.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,115 @@
CLASS {{p}}provision_calc DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES:
ty_material TYPE c LENGTH 18,
ty_quantity TYPE p LENGTH 13 DECIMALS 3,
ty_price TYPE p LENGTH 11 DECIMALS 2,
ty_amount TYPE p LENGTH 13 DECIMALS 2,
ty_reason TYPE c LENGTH 20.
TYPES:
BEGIN OF ty_line,
material TYPE ty_material,
quantity TYPE ty_quantity,
price TYPE ty_price,
END OF ty_line.
TYPES tt_lines TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY.
CONSTANTS:
c_max_lines TYPE i VALUE 999,
c_value_limit TYPE ty_amount VALUE '100000.00',
c_empty_order TYPE ty_reason VALUE 'EMPTY_ORDER',
c_too_many_lines TYPE ty_reason VALUE 'TOO_MANY_LINES',
c_material_missing TYPE ty_reason VALUE 'MATERIAL_MISSING',
c_quantity_invalid TYPE ty_reason VALUE 'QUANTITY_INVALID',
c_price_negative TYPE ty_reason VALUE 'PRICE_NEGATIVE',
c_duplicate_material TYPE ty_reason VALUE 'DUPLICATE_MATERIAL',
c_limit_exceeded TYPE ty_reason VALUE 'LIMIT_EXCEEDED'.
METHODS constructor.
METHODS check_order
IMPORTING it_lines TYPE tt_lines
RAISING {{p}}cx_prov_error.
METHODS calculate_value
IMPORTING it_lines TYPE tt_lines
RETURNING VALUE(rv_value) TYPE ty_amount
RAISING {{p}}cx_prov_error.
PRIVATE SECTION.
TYPES tt_materials TYPE HASHED TABLE OF ty_material WITH UNIQUE KEY table_line.
METHODS check_lines
IMPORTING it_lines TYPE tt_lines
RAISING {{p}}cx_prov_error.
METHODS total_value
IMPORTING it_lines TYPE tt_lines
RETURNING VALUE(rv_value) TYPE ty_amount.
METHODS raise_error
IMPORTING iv_reason TYPE ty_reason
RAISING {{p}}cx_prov_error.
ENDCLASS.
CLASS {{p}}provision_calc IMPLEMENTATION.
METHOD constructor.
ENDMETHOD.
METHOD check_order.
IF it_lines IS INITIAL.
raise_error( c_empty_order ).
ENDIF.
IF lines( it_lines ) > c_max_lines.
raise_error( c_too_many_lines ).
ENDIF.
check_lines( it_lines ).
IF total_value( it_lines ) <= c_value_limit.
raise_error( c_limit_exceeded ).
ENDIF.
ENDMETHOD.
METHOD calculate_value.
check_order( it_lines ).
rv_value = total_value( it_lines ).
ENDMETHOD.
METHOD check_lines.
DATA lt_seen TYPE tt_materials.
LOOP AT it_lines INTO DATA(ls_line).
IF ls_line-material IS INITIAL.
raise_error( c_material_missing ).
ENDIF.
IF ls_line-quantity <= 0.
raise_error( c_quantity_invalid ).
ENDIF.
IF ls_line-price < 0.
raise_error( c_price_negative ).
ENDIF.
IF line_exists( lt_seen[ table_line = ls_line-material ] ).
raise_error( c_duplicate_material ).
ENDIF.
INSERT ls_line-material INTO TABLE lt_seen.
ENDLOOP.
ENDMETHOD.
METHOD total_value.
DATA lv_total TYPE p LENGTH 16 DECIMALS 5.
LOOP AT it_lines INTO DATA(ls_line).
lv_total = lv_total + ls_line-quantity * ls_line-price.
ENDLOOP.
rv_value = round( val = lv_total dec = 2 ).
ENDMETHOD.
METHOD raise_error.
RAISE EXCEPTION TYPE {{p}}cx_prov_error
EXPORTING
iv_reason = iv_reason.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,115 @@
CLASS {{p}}provision_calc DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES:
ty_material TYPE c LENGTH 18,
ty_quantity TYPE p LENGTH 13 DECIMALS 3,
ty_price TYPE p LENGTH 11 DECIMALS 2,
ty_amount TYPE p LENGTH 13 DECIMALS 2,
ty_reason TYPE c LENGTH 20.
TYPES:
BEGIN OF ty_line,
material TYPE ty_material,
quantity TYPE ty_quantity,
price TYPE ty_price,
END OF ty_line.
TYPES tt_lines TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY.
CONSTANTS:
c_max_lines TYPE i VALUE 999,
c_value_limit TYPE ty_amount VALUE '100000.00',
c_empty_order TYPE ty_reason VALUE 'EMPTY_ORDER',
c_too_many_lines TYPE ty_reason VALUE 'TOO_MANY_LINES',
c_material_missing TYPE ty_reason VALUE 'MATERIAL_MISSING',
c_quantity_invalid TYPE ty_reason VALUE 'QUANTITY_INVALID',
c_price_negative TYPE ty_reason VALUE 'PRICE_NEGATIVE',
c_duplicate_material TYPE ty_reason VALUE 'DUPLICATE_MATERIAL',
c_limit_exceeded TYPE ty_reason VALUE 'LIMIT_EXCEEDED'.
METHODS constructor.
METHODS check_order
IMPORTING it_lines TYPE tt_lines
RAISING {{p}}cx_prov_error.
METHODS calculate_value
IMPORTING it_lines TYPE tt_lines
RETURNING VALUE(rv_value) TYPE ty_amount
RAISING {{p}}cx_prov_error.
PRIVATE SECTION.
TYPES tt_materials TYPE HASHED TABLE OF ty_material WITH UNIQUE KEY table_line.
METHODS check_lines
IMPORTING it_lines TYPE tt_lines
RAISING {{p}}cx_prov_error.
METHODS total_value
IMPORTING it_lines TYPE tt_lines
RETURNING VALUE(rv_value) TYPE ty_amount.
METHODS raise_error
IMPORTING iv_reason TYPE ty_reason
RAISING {{p}}cx_prov_error.
ENDCLASS.
CLASS {{p}}provision_calc IMPLEMENTATION.
METHOD constructor.
ENDMETHOD.
METHOD check_order.
IF it_lines IS INITIAL.
raise_error( c_empty_order ).
ENDIF.
IF lines( it_lines ) > c_max_lines.
raise_error( c_too_many_lines ).
ENDIF.
check_lines( it_lines ).
IF total_value( it_lines ) > c_value_limit.
raise_error( c_limit_exceeded ).
ENDIF.
ENDMETHOD.
METHOD calculate_value.
check_order( it_lines ).
rv_value = total_value( it_lines ).
ENDMETHOD.
METHOD check_lines.
DATA lt_seen TYPE tt_materials.
LOOP AT it_lines INTO DATA(ls_line).
IF ls_line-material IS INITIAL.
raise_error( c_material_missing ).
ENDIF.
IF ls_line-quantity <= 0.
raise_error( c_quantity_invalid ).
ENDIF.
IF ls_line-price < 0.
raise_error( c_price_negative ).
ENDIF.
IF line_exists( lt_seen[ table_line = ls_line-material ] ).
raise_error( c_duplicate_material ).
ENDIF.
INSERT ls_line-material INTO TABLE lt_seen.
ENDLOOP.
ENDMETHOD.
METHOD total_value.
DATA lv_total TYPE p LENGTH 16 DECIMALS 5.
LOOP AT it_lines INTO DATA(ls_line).
lv_total = lv_total - ls_line-quantity * ls_line-price.
ENDLOOP.
rv_value = round( val = lv_total dec = 2 ).
ENDMETHOD.
METHOD raise_error.
RAISE EXCEPTION TYPE {{p}}cx_prov_error
EXPORTING
iv_reason = iv_reason.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,29 @@
{
"id": "G0130",
"pool": "eval",
"object_type": "CLAS",
"category": "D",
"attempts": [
{
"stage": "validate",
"oracle": null,
"null": null
},
{
"stage": "validate",
"oracle": 0,
"null": 0
},
{
"stage": "validate",
"oracle": 100.0,
"null": 0,
"mutation": {
"valid": 4,
"killed": 3,
"ok": true
}
}
],
"accepted": true
}

View File

@@ -1,156 +0,0 @@
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}}prescription_check.
METHODS setup.
METHODS empty_prescription FOR TESTING.
METHODS expired_prescription FOR TESTING.
METHODS valid_on_last_day FOR TESTING.
METHODS unknown_drug FOR TESTING.
METHODS zero_quantity FOR TESTING.
METHODS zero_daily_dose FOR TESTING.
METHODS dose_above_max FOR TESTING.
METHODS duplicate_drug FOR TESTING.
METHODS expired_before_quantity FOR TESTING.
METHODS dose_before_duplicate FOR TESTING.
METHODS valid_prescription FOR TESTING.
METHODS message_texts FOR TESTING.
METHODS valid_item
RETURNING VALUE(rt_item) TYPE {{p}}prescription_check=>tt_item.
METHODS expect_reason
IMPORTING iv_reason TYPE {{p}}cx_presc_error=>ty_reason
it_item TYPE {{p}}prescription_check=>tt_item
iv_as_of TYPE d DEFAULT '20240110'.
METHODS expect_no_error
IMPORTING it_item TYPE {{p}}prescription_check=>tt_item
iv_as_of TYPE d DEFAULT '20240110'.
ENDCLASS.
CLASS {{p}}t02_hidden IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}prescription_check( ).
ENDMETHOD.
METHOD valid_item.
rt_item = VALUE #( ( drug_id = 'PARA500' quantity = 20 daily_dose = 1000 ) ).
ENDMETHOD.
METHOD expect_reason.
DATA lv_raised TYPE abap_bool.
TRY.
mo_cut->validate( iv_issue_date = '20240101'
iv_valid_days = 30
iv_as_of_date = iv_as_of
it_item = it_item ).
CATCH {{p}}cx_presc_error INTO DATA(lx_error).
lv_raised = abap_true.
cl_abap_unit_assert=>assert_equals( exp = iv_reason
act = lx_error->get_reason( ) ).
ENDTRY.
cl_abap_unit_assert=>assert_true( act = lv_raised
msg = |No exception with reason { iv_reason }| ).
ENDMETHOD.
METHOD expect_no_error.
DATA lv_raised TYPE abap_bool.
TRY.
mo_cut->validate( iv_issue_date = '20240101'
iv_valid_days = 30
iv_as_of_date = iv_as_of
it_item = it_item ).
CATCH {{p}}cx_presc_error.
lv_raised = abap_true.
ENDTRY.
cl_abap_unit_assert=>assert_false( act = lv_raised ).
ENDMETHOD.
METHOD empty_prescription.
expect_reason( iv_reason = {{p}}cx_presc_error=>c_reason-empty
it_item = VALUE {{p}}prescription_check=>tt_item( ) ).
ENDMETHOD.
METHOD expired_prescription.
expect_reason( iv_reason = {{p}}cx_presc_error=>c_reason-expired
it_item = valid_item( )
iv_as_of = '20240201' ).
ENDMETHOD.
METHOD valid_on_last_day.
expect_no_error( it_item = valid_item( )
iv_as_of = '20240131' ).
ENDMETHOD.
METHOD unknown_drug.
expect_reason( iv_reason = {{p}}cx_presc_error=>c_reason-unknown
it_item = VALUE #( ( drug_id = 'XXXXXX' quantity = 5 daily_dose = 10 ) ) ).
ENDMETHOD.
METHOD zero_quantity.
expect_reason( iv_reason = {{p}}cx_presc_error=>c_reason-quantity
it_item = VALUE #( ( drug_id = 'PARA500' quantity = 0 daily_dose = 1000 ) ) ).
ENDMETHOD.
METHOD zero_daily_dose.
expect_reason( iv_reason = {{p}}cx_presc_error=>c_reason-dose
it_item = VALUE #( ( drug_id = 'PARA500' quantity = 5 daily_dose = 0 ) ) ).
ENDMETHOD.
METHOD dose_above_max.
expect_reason( iv_reason = {{p}}cx_presc_error=>c_reason-dose
it_item = VALUE #( ( drug_id = 'META50' quantity = 5 daily_dose = 250 ) ) ).
ENDMETHOD.
METHOD duplicate_drug.
expect_reason( iv_reason = {{p}}cx_presc_error=>c_reason-duplicate
it_item = VALUE #( ( drug_id = 'PARA500' quantity = 5 daily_dose = 1000 )
( drug_id = 'PARA500' quantity = 5 daily_dose = 1000 ) ) ).
ENDMETHOD.
METHOD expired_before_quantity.
expect_reason( iv_reason = {{p}}cx_presc_error=>c_reason-expired
it_item = VALUE #( ( drug_id = 'PARA500' quantity = 0 daily_dose = 1000 ) )
iv_as_of = '20240201' ).
ENDMETHOD.
METHOD dose_before_duplicate.
expect_reason( iv_reason = {{p}}cx_presc_error=>c_reason-dose
it_item = VALUE #( ( drug_id = 'META50' quantity = 5 daily_dose = 250 )
( drug_id = 'META50' quantity = 5 daily_dose = 100 ) ) ).
ENDMETHOD.
METHOD valid_prescription.
expect_no_error( it_item = VALUE #( ( drug_id = 'PARA500' quantity = 20 daily_dose = 4000 )
( drug_id = 'IBU400' quantity = 10 daily_dose = 1200 ) ) ).
ENDMETHOD.
METHOD message_texts.
DATA lo_error TYPE REF TO {{p}}cx_presc_error.
lo_error = NEW #( iv_reason = {{p}}cx_presc_error=>c_reason-empty ).
cl_abap_unit_assert=>assert_equals( exp = 'The prescription has no items'
act = lo_error->get_message_text( ) ).
lo_error = NEW #( iv_reason = {{p}}cx_presc_error=>c_reason-expired ).
cl_abap_unit_assert=>assert_equals( exp = 'The prescription is expired'
act = lo_error->get_message_text( ) ).
lo_error = NEW #( iv_reason = {{p}}cx_presc_error=>c_reason-quantity ).
cl_abap_unit_assert=>assert_equals( exp = 'The quantity is not positive'
act = lo_error->get_message_text( ) ).
lo_error = NEW #( iv_reason = {{p}}cx_presc_error=>c_reason-unknown ).
cl_abap_unit_assert=>assert_equals( exp = 'The drug is not in the drug master'
act = lo_error->get_message_text( ) ).
lo_error = NEW #( iv_reason = {{p}}cx_presc_error=>c_reason-dose ).
cl_abap_unit_assert=>assert_equals( exp = 'The daily dose is not allowed'
act = lo_error->get_message_text( ) ).
lo_error = NEW #( iv_reason = {{p}}cx_presc_error=>c_reason-duplicate ).
cl_abap_unit_assert=>assert_equals( exp = 'The drug appears more than once'
act = lo_error->get_message_text( ) ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,157 @@
CLASS {{p}}t_prov_hidden DEFINITION PUBLIC FINAL CREATE PUBLIC
FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO {{p}}provision_calc.
METHODS setup.
METHODS empty_order_raises FOR TESTING.
METHODS too_many_lines_raises FOR TESTING.
METHODS material_missing_raises FOR TESTING.
METHODS quantity_invalid_raises FOR TESTING.
METHODS price_negative_raises FOR TESTING.
METHODS duplicate_material_raises FOR TESTING.
METHODS limit_exceeded_raises FOR TESTING.
METHODS limit_boundary_is_ok FOR TESTING.
METHODS valid_order_is_ok FOR TESTING.
METHODS value_is_sum FOR TESTING.
METHODS value_rounds_total FOR TESTING.
METHODS invalid_order_propagates FOR TESTING.
METHODS expect_reason
IMPORTING it_lines TYPE {{p}}provision_calc=>tt_lines
iv_reason TYPE {{p}}provision_calc=>ty_reason.
ENDCLASS.
CLASS {{p}}t_prov_hidden IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}provision_calc( ).
ENDMETHOD.
METHOD expect_reason.
TRY.
mo_cut->check_order( it_lines ).
cl_abap_unit_assert=>fail( msg = |Expected reason { iv_reason }| ).
CATCH {{p}}cx_prov_error INTO DATA(lx_error).
cl_abap_unit_assert=>assert_equals( exp = iv_reason act = lx_error->reason ).
ENDTRY.
ENDMETHOD.
METHOD empty_order_raises.
DATA lt_lines TYPE {{p}}provision_calc=>tt_lines.
expect_reason( it_lines = lt_lines
iv_reason = {{p}}provision_calc=>c_empty_order ).
ENDMETHOD.
METHOD too_many_lines_raises.
DATA lt_lines TYPE {{p}}provision_calc=>tt_lines.
DATA ls_line TYPE {{p}}provision_calc=>ty_line.
DO 1000 TIMES.
ls_line = VALUE #( material = |M{ sy-index }| quantity = 1 price = 1 ).
INSERT ls_line INTO TABLE lt_lines.
ENDDO.
expect_reason( it_lines = lt_lines
iv_reason = {{p}}provision_calc=>c_too_many_lines ).
ENDMETHOD.
METHOD material_missing_raises.
DATA lt_lines TYPE {{p}}provision_calc=>tt_lines.
lt_lines = VALUE #( ( material = ` ` quantity = 1 price = 1 ) ).
expect_reason( it_lines = lt_lines
iv_reason = {{p}}provision_calc=>c_material_missing ).
ENDMETHOD.
METHOD quantity_invalid_raises.
DATA lt_lines TYPE {{p}}provision_calc=>tt_lines.
lt_lines = VALUE #( ( material = 'ROPE' quantity = 0 price = 1 ) ).
expect_reason( it_lines = lt_lines
iv_reason = {{p}}provision_calc=>c_quantity_invalid ).
lt_lines = VALUE #( ( material = 'ROPE' quantity = -1 price = 1 ) ).
expect_reason( it_lines = lt_lines
iv_reason = {{p}}provision_calc=>c_quantity_invalid ).
ENDMETHOD.
METHOD price_negative_raises.
DATA lt_lines TYPE {{p}}provision_calc=>tt_lines.
lt_lines = VALUE #( ( material = 'ROPE' quantity = 1 price = -1 ) ).
expect_reason( it_lines = lt_lines
iv_reason = {{p}}provision_calc=>c_price_negative ).
ENDMETHOD.
METHOD duplicate_material_raises.
DATA lt_lines TYPE {{p}}provision_calc=>tt_lines.
lt_lines = VALUE #( ( material = 'ROPE' quantity = 1 price = 1 )
( material = 'ROPE' quantity = 2 price = 1 ) ).
expect_reason( it_lines = lt_lines
iv_reason = {{p}}provision_calc=>c_duplicate_material ).
ENDMETHOD.
METHOD limit_exceeded_raises.
DATA lt_lines TYPE {{p}}provision_calc=>tt_lines.
lt_lines = VALUE #( ( material = 'ENGINE' quantity = 1 price = '100000.01' ) ).
expect_reason( it_lines = lt_lines
iv_reason = {{p}}provision_calc=>c_limit_exceeded ).
ENDMETHOD.
METHOD limit_boundary_is_ok.
DATA lt_lines TYPE {{p}}provision_calc=>tt_lines.
lt_lines = VALUE #( ( material = 'ENGINE' quantity = 1 price = '100000.00' ) ).
TRY.
mo_cut->check_order( lt_lines ).
CATCH {{p}}cx_prov_error INTO DATA(lx_error).
cl_abap_unit_assert=>fail( msg = |Unexpected reason { lx_error->reason }| ).
ENDTRY.
ENDMETHOD.
METHOD valid_order_is_ok.
DATA lt_lines TYPE {{p}}provision_calc=>tt_lines.
lt_lines = VALUE #( ( material = 'ROPE' quantity = 2 price = '3.50' )
( material = 'BOLT' quantity = 3 price = '1.25' ) ).
TRY.
mo_cut->check_order( lt_lines ).
CATCH {{p}}cx_prov_error INTO DATA(lx_error).
cl_abap_unit_assert=>fail( msg = |Unexpected reason { lx_error->reason }| ).
ENDTRY.
ENDMETHOD.
METHOD value_is_sum.
DATA lt_lines TYPE {{p}}provision_calc=>tt_lines.
lt_lines = VALUE #( ( material = 'ROPE' quantity = 2 price = '3.50' )
( material = 'BOLT' quantity = 3 price = '1.25' ) ).
DATA lv_expected TYPE {{p}}provision_calc=>ty_amount VALUE '10.75'.
DATA lv_value TYPE {{p}}provision_calc=>ty_amount.
TRY.
lv_value = mo_cut->calculate_value( lt_lines ).
CATCH {{p}}cx_prov_error INTO DATA(lx_error).
cl_abap_unit_assert=>fail( msg = |Unexpected reason { lx_error->reason }| ).
ENDTRY.
cl_abap_unit_assert=>assert_equals( exp = lv_expected act = lv_value ).
ENDMETHOD.
METHOD value_rounds_total.
DATA lt_lines TYPE {{p}}provision_calc=>tt_lines.
lt_lines = VALUE #( ( material = 'ROPE' quantity = '1.005' price = '1.00' )
( material = 'BOLT' quantity = '1.005' price = '1.00' ) ).
DATA lv_expected TYPE {{p}}provision_calc=>ty_amount VALUE '2.01'.
DATA lv_value TYPE {{p}}provision_calc=>ty_amount.
TRY.
lv_value = mo_cut->calculate_value( lt_lines ).
CATCH {{p}}cx_prov_error INTO DATA(lx_error).
cl_abap_unit_assert=>fail( msg = |Unexpected reason { lx_error->reason }| ).
ENDTRY.
cl_abap_unit_assert=>assert_equals( exp = lv_expected act = lv_value ).
ENDMETHOD.
METHOD invalid_order_propagates.
DATA lt_lines TYPE {{p}}provision_calc=>tt_lines.
lt_lines = VALUE #( ( material = '' quantity = 1 price = 1 ) ).
TRY.
mo_cut->calculate_value( lt_lines ).
cl_abap_unit_assert=>fail( msg = 'Expected reason MATERIAL_MISSING' ).
CATCH {{p}}cx_prov_error INTO DATA(lx_error).
cl_abap_unit_assert=>assert_equals( exp = {{p}}provision_calc=>c_material_missing
act = lx_error->reason ).
ENDTRY.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,66 @@
{
"task": "G0130",
"mutants": [
{
"object": "{{P}}PROVISION_CALC",
"mutant": "line 67: > -> <= (rel)",
"status": "killed",
"hidden": "1/12",
"failed_tests": [
"DUPLICATE_MATERIAL_RAISES",
"INVALID_ORDER_PROPAGATES",
"LIMIT_BOUNDARY_IS_OK",
"LIMIT_EXCEEDED_RAISES",
"MATERIAL_MISSING_RAISES",
"PRICE_NEGATIVE_RAISES",
"QUANTITY_INVALID_RAISES",
"TOO_MANY_LINES_RAISES",
"VALID_ORDER_IS_OK",
"VALUE_IS_SUM",
"VALUE_ROUNDS_TOTAL"
]
},
{
"object": "{{P}}PROVISION_CALC",
"mutant": "line 73: > -> <= (rel)",
"status": "killed",
"hidden": "7/12",
"failed_tests": [
"LIMIT_BOUNDARY_IS_OK",
"LIMIT_EXCEEDED_RAISES",
"VALID_ORDER_IS_OK",
"VALUE_IS_SUM",
"VALUE_ROUNDS_TOTAL"
]
},
{
"object": "{{P}}PROVISION_CALC",
"mutant": "line 95: = -> <> (eq)",
"status": "invalid",
"hidden": "0/0",
"failed_tests": []
},
{
"object": "{{P}}PROVISION_CALC",
"mutant": "line 105: + -> - (arith)",
"status": "killed",
"hidden": "9/12",
"failed_tests": [
"LIMIT_EXCEEDED_RAISES",
"VALUE_IS_SUM",
"VALUE_ROUNDS_TOTAL"
]
},
{
"object": "{{P}}PROVISION_CALC",
"mutant": "line 107: 2 -> 3 (const)",
"status": "survived",
"hidden": "12/12",
"failed_tests": []
}
],
"valid": 4,
"killed": 3,
"kill_rate": 0.75,
"ok": true
}

View File

@@ -1,60 +0,0 @@
CLASS {{p}}cx_presc_error DEFINITION
PUBLIC
INHERITING FROM cx_root
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_reason TYPE c LENGTH 12.
CONSTANTS:
BEGIN OF c_reason,
empty TYPE ty_reason VALUE 'EMPTY',
expired TYPE ty_reason VALUE 'EXPIRED',
quantity TYPE ty_reason VALUE 'QUANTITY',
unknown TYPE ty_reason VALUE 'UNKNOWN',
dose TYPE ty_reason VALUE 'DOSE',
duplicate TYPE ty_reason VALUE 'DUPLICATE',
END OF c_reason.
METHODS constructor
IMPORTING iv_reason TYPE ty_reason.
METHODS get_reason
RETURNING VALUE(rv_reason) TYPE ty_reason.
METHODS get_message_text
RETURNING VALUE(rv_text) TYPE string.
PRIVATE SECTION.
DATA mv_reason TYPE ty_reason.
ENDCLASS.
CLASS {{p}}cx_presc_error IMPLEMENTATION.
METHOD constructor.
super->constructor( ).
mv_reason = iv_reason.
ENDMETHOD.
METHOD get_reason.
rv_reason = mv_reason.
ENDMETHOD.
METHOD get_message_text.
CASE mv_reason.
WHEN c_reason-empty.
rv_text = 'The prescription has no items'.
WHEN c_reason-expired.
rv_text = 'The prescription is expired'.
WHEN c_reason-quantity.
rv_text = 'The quantity is not positive'.
WHEN c_reason-unknown.
rv_text = 'The drug is not in the drug master'.
WHEN c_reason-dose.
rv_text = 'The daily dose is not allowed'.
WHEN c_reason-duplicate.
rv_text = 'The drug appears more than once'.
ENDCASE.
ENDMETHOD.
ENDCLASS.

View File

@@ -1,103 +0,0 @@
CLASS {{p}}prescription_check DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_drug_id TYPE c LENGTH 10.
TYPES:
BEGIN OF ty_item,
drug_id TYPE ty_drug_id,
quantity TYPE i,
daily_dose TYPE i,
END OF ty_item,
tt_item TYPE STANDARD TABLE OF ty_item WITH EMPTY KEY.
METHODS constructor.
METHODS validate
IMPORTING iv_issue_date TYPE d
iv_valid_days TYPE i
iv_as_of_date TYPE d
it_item TYPE tt_item
RAISING {{p}}cx_presc_error.
PRIVATE SECTION.
DATA mo_drug_master TYPE REF TO {{p}}drug_master.
METHODS expiry_date
IMPORTING iv_issue_date TYPE d
iv_valid_days TYPE i
RETURNING VALUE(rv_expiry) TYPE d.
METHODS check_items
IMPORTING it_item TYPE tt_item
RAISING {{p}}cx_presc_error.
METHODS check_item
IMPORTING is_item TYPE ty_item
RAISING {{p}}cx_presc_error.
METHODS check_duplicates
IMPORTING it_item TYPE tt_item
RAISING {{p}}cx_presc_error.
ENDCLASS.
CLASS {{p}}prescription_check IMPLEMENTATION.
METHOD constructor.
mo_drug_master = NEW {{p}}drug_master( ).
ENDMETHOD.
METHOD validate.
IF it_item IS INITIAL.
RAISE EXCEPTION TYPE {{p}}cx_presc_error
EXPORTING iv_reason = {{p}}cx_presc_error=>c_reason-empty.
ENDIF.
IF iv_as_of_date > expiry_date( iv_issue_date = iv_issue_date
iv_valid_days = iv_valid_days ).
RAISE EXCEPTION TYPE {{p}}cx_presc_error
EXPORTING iv_reason = {{p}}cx_presc_error=>c_reason-expired.
ENDIF.
check_items( it_item ).
check_duplicates( it_item ).
ENDMETHOD.
METHOD expiry_date.
rv_expiry = iv_issue_date + iv_valid_days.
ENDMETHOD.
METHOD check_items.
LOOP AT it_item INTO DATA(ls_item).
check_item( ls_item ).
ENDLOOP.
ENDMETHOD.
METHOD check_item.
IF is_item-quantity < 1.
RAISE EXCEPTION TYPE {{p}}cx_presc_error
EXPORTING iv_reason = {{p}}cx_presc_error=>c_reason-quantity.
ENDIF.
DATA(ls_drug) = mo_drug_master->get_drug( is_item-drug_id ).
IF ls_drug IS INITIAL.
RAISE EXCEPTION TYPE {{p}}cx_presc_error
EXPORTING iv_reason = {{p}}cx_presc_error=>c_reason-unknown.
ENDIF.
IF is_item-daily_dose < 1 OR is_item-daily_dose > ls_drug-max_daily_dose.
RAISE EXCEPTION TYPE {{p}}cx_presc_error
EXPORTING iv_reason = {{p}}cx_presc_error=>c_reason-dose.
ENDIF.
ENDMETHOD.
METHOD check_duplicates.
DATA lt_seen TYPE HASHED TABLE OF ty_item WITH UNIQUE KEY drug_id.
LOOP AT it_item INTO DATA(ls_item).
INSERT ls_item INTO TABLE lt_seen.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE {{p}}cx_presc_error
EXPORTING iv_reason = {{p}}cx_presc_error=>c_reason-duplicate.
ENDIF.
ENDLOOP.
ENDMETHOD.
ENDCLASS.

View File

@@ -1,104 +0,0 @@
CLASS ltc_presc_check DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO {{p}}prescription_check.
METHODS setup.
METHODS valid_prescription FOR TESTING.
METHODS empty_prescription FOR TESTING.
METHODS expired_prescription FOR TESTING.
METHODS unknown_drug FOR TESTING.
METHODS bad_quantity FOR TESTING.
METHODS bad_dose FOR TESTING.
METHODS duplicate_drug FOR TESTING.
METHODS message_of_empty FOR TESTING.
METHODS valid_item
RETURNING VALUE(rt_item) TYPE {{p}}prescription_check=>tt_item.
METHODS expect_reason
IMPORTING iv_reason TYPE {{p}}cx_presc_error=>ty_reason
it_item TYPE {{p}}prescription_check=>tt_item.
ENDCLASS.
CLASS ltc_presc_check IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}prescription_check( ).
ENDMETHOD.
METHOD valid_item.
rt_item = VALUE #( ( drug_id = 'IBU400' quantity = 10 daily_dose = 1200 ) ).
ENDMETHOD.
METHOD expect_reason.
DATA lv_raised TYPE abap_bool.
TRY.
mo_cut->validate( iv_issue_date = '20240101'
iv_valid_days = 30
iv_as_of_date = '20240110'
it_item = it_item ).
CATCH {{p}}cx_presc_error INTO DATA(lx_error).
lv_raised = abap_true.
cl_abap_unit_assert=>assert_equals( exp = iv_reason
act = lx_error->get_reason( ) ).
ENDTRY.
cl_abap_unit_assert=>assert_true( act = lv_raised ).
ENDMETHOD.
METHOD valid_prescription.
TRY.
mo_cut->validate( iv_issue_date = '20240101'
iv_valid_days = 30
iv_as_of_date = '20240110'
it_item = valid_item( ) ).
CATCH {{p}}cx_presc_error.
cl_abap_unit_assert=>fail( msg = 'Unexpected exception' ).
ENDTRY.
ENDMETHOD.
METHOD empty_prescription.
expect_reason( iv_reason = {{p}}cx_presc_error=>c_reason-empty
it_item = VALUE {{p}}prescription_check=>tt_item( ) ).
ENDMETHOD.
METHOD expired_prescription.
DATA lv_raised TYPE abap_bool.
TRY.
mo_cut->validate( iv_issue_date = '20240101'
iv_valid_days = 30
iv_as_of_date = '20240201'
it_item = valid_item( ) ).
CATCH {{p}}cx_presc_error INTO DATA(lx_error).
lv_raised = abap_true.
cl_abap_unit_assert=>assert_equals( exp = {{p}}cx_presc_error=>c_reason-expired
act = lx_error->get_reason( ) ).
ENDTRY.
cl_abap_unit_assert=>assert_true( act = lv_raised ).
ENDMETHOD.
METHOD unknown_drug.
expect_reason( iv_reason = {{p}}cx_presc_error=>c_reason-unknown
it_item = VALUE #( ( drug_id = 'NODRUG' quantity = 5 daily_dose = 10 ) ) ).
ENDMETHOD.
METHOD bad_quantity.
expect_reason( iv_reason = {{p}}cx_presc_error=>c_reason-quantity
it_item = VALUE #( ( drug_id = 'IBU400' quantity = 0 daily_dose = 1200 ) ) ).
ENDMETHOD.
METHOD bad_dose.
expect_reason( iv_reason = {{p}}cx_presc_error=>c_reason-dose
it_item = VALUE #( ( drug_id = 'META50' quantity = 5 daily_dose = 500 ) ) ).
ENDMETHOD.
METHOD duplicate_drug.
expect_reason( iv_reason = {{p}}cx_presc_error=>c_reason-duplicate
it_item = VALUE #( ( drug_id = 'IBU400' quantity = 10 daily_dose = 1200 )
( drug_id = 'IBU400' quantity = 10 daily_dose = 1200 ) ) ).
ENDMETHOD.
METHOD message_of_empty.
DATA(lo_error) = NEW {{p}}cx_presc_error( iv_reason = {{p}}cx_presc_error=>c_reason-empty ).
cl_abap_unit_assert=>assert_equals( exp = 'The prescription has no items'
act = lo_error->get_message_text( ) ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,115 @@
CLASS {{p}}provision_calc DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES:
ty_material TYPE c LENGTH 18,
ty_quantity TYPE p LENGTH 13 DECIMALS 3,
ty_price TYPE p LENGTH 11 DECIMALS 2,
ty_amount TYPE p LENGTH 13 DECIMALS 2,
ty_reason TYPE c LENGTH 20.
TYPES:
BEGIN OF ty_line,
material TYPE ty_material,
quantity TYPE ty_quantity,
price TYPE ty_price,
END OF ty_line.
TYPES tt_lines TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY.
CONSTANTS:
c_max_lines TYPE i VALUE 999,
c_value_limit TYPE ty_amount VALUE '100000.00',
c_empty_order TYPE ty_reason VALUE 'EMPTY_ORDER',
c_too_many_lines TYPE ty_reason VALUE 'TOO_MANY_LINES',
c_material_missing TYPE ty_reason VALUE 'MATERIAL_MISSING',
c_quantity_invalid TYPE ty_reason VALUE 'QUANTITY_INVALID',
c_price_negative TYPE ty_reason VALUE 'PRICE_NEGATIVE',
c_duplicate_material TYPE ty_reason VALUE 'DUPLICATE_MATERIAL',
c_limit_exceeded TYPE ty_reason VALUE 'LIMIT_EXCEEDED'.
METHODS constructor.
METHODS check_order
IMPORTING it_lines TYPE tt_lines
RAISING {{p}}cx_prov_error.
METHODS calculate_value
IMPORTING it_lines TYPE tt_lines
RETURNING VALUE(rv_value) TYPE ty_amount
RAISING {{p}}cx_prov_error.
PRIVATE SECTION.
TYPES tt_materials TYPE HASHED TABLE OF ty_material WITH UNIQUE KEY table_line.
METHODS check_lines
IMPORTING it_lines TYPE tt_lines
RAISING {{p}}cx_prov_error.
METHODS total_value
IMPORTING it_lines TYPE tt_lines
RETURNING VALUE(rv_value) TYPE ty_amount.
METHODS raise_error
IMPORTING iv_reason TYPE ty_reason
RAISING {{p}}cx_prov_error.
ENDCLASS.
CLASS {{p}}provision_calc IMPLEMENTATION.
METHOD constructor.
ENDMETHOD.
METHOD check_order.
IF it_lines IS INITIAL.
raise_error( c_empty_order ).
ENDIF.
IF lines( it_lines ) > c_max_lines.
raise_error( c_too_many_lines ).
ENDIF.
check_lines( it_lines ).
IF total_value( it_lines ) > c_value_limit.
raise_error( c_limit_exceeded ).
ENDIF.
ENDMETHOD.
METHOD calculate_value.
check_order( it_lines ).
rv_value = total_value( it_lines ).
ENDMETHOD.
METHOD check_lines.
DATA lt_seen TYPE tt_materials.
LOOP AT it_lines INTO DATA(ls_line).
IF ls_line-material IS INITIAL.
raise_error( c_material_missing ).
ENDIF.
IF ls_line-quantity <= 0.
raise_error( c_quantity_invalid ).
ENDIF.
IF ls_line-price < 0.
raise_error( c_price_negative ).
ENDIF.
IF line_exists( lt_seen[ table_line = ls_line-material ] ).
raise_error( c_duplicate_material ).
ENDIF.
INSERT ls_line-material INTO TABLE lt_seen.
ENDLOOP.
ENDMETHOD.
METHOD total_value.
DATA lv_total TYPE p LENGTH 16 DECIMALS 5.
LOOP AT it_lines INTO DATA(ls_line).
lv_total = lv_total + ls_line-quantity * ls_line-price.
ENDLOOP.
rv_value = round( val = lv_total dec = 2 ).
ENDMETHOD.
METHOD raise_error.
RAISE EXCEPTION TYPE {{p}}cx_prov_error
EXPORTING
iv_reason = iv_reason.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,95 @@
CLASS ltc_provision_calc DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO {{p}}provision_calc.
METHODS setup.
METHODS empty_order FOR TESTING.
METHODS material_missing FOR TESTING.
METHODS duplicate_material FOR TESTING.
METHODS value_of_valid_order FOR TESTING.
METHODS limit_exceeded FOR TESTING.
METHODS rounds_total FOR TESTING.
ENDCLASS.
CLASS ltc_provision_calc IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}provision_calc( ).
ENDMETHOD.
METHOD empty_order.
DATA lt_lines TYPE {{p}}provision_calc=>tt_lines.
TRY.
mo_cut->check_order( lt_lines ).
cl_abap_unit_assert=>fail( ).
CATCH {{p}}cx_prov_error INTO DATA(lx_error).
cl_abap_unit_assert=>assert_equals( exp = {{p}}provision_calc=>c_empty_order
act = lx_error->reason ).
ENDTRY.
ENDMETHOD.
METHOD material_missing.
DATA lt_lines TYPE {{p}}provision_calc=>tt_lines.
lt_lines = VALUE #( ( material = ` ` quantity = 1 price = 1 ) ).
TRY.
mo_cut->check_order( lt_lines ).
cl_abap_unit_assert=>fail( ).
CATCH {{p}}cx_prov_error INTO DATA(lx_error).
cl_abap_unit_assert=>assert_equals( exp = {{p}}provision_calc=>c_material_missing
act = lx_error->reason ).
ENDTRY.
ENDMETHOD.
METHOD duplicate_material.
DATA lt_lines TYPE {{p}}provision_calc=>tt_lines.
lt_lines = VALUE #( ( material = 'ROPE' quantity = 1 price = 1 )
( material = 'ROPE' quantity = 2 price = 1 ) ).
TRY.
mo_cut->check_order( lt_lines ).
cl_abap_unit_assert=>fail( ).
CATCH {{p}}cx_prov_error INTO DATA(lx_error).
cl_abap_unit_assert=>assert_equals( exp = {{p}}provision_calc=>c_duplicate_material
act = lx_error->reason ).
ENDTRY.
ENDMETHOD.
METHOD value_of_valid_order.
DATA lt_lines TYPE {{p}}provision_calc=>tt_lines.
lt_lines = VALUE #( ( material = 'ROPE' quantity = 2 price = '3.50' )
( material = 'BOLT' quantity = 3 price = '1.25' ) ).
DATA lv_expected TYPE {{p}}provision_calc=>ty_amount VALUE '10.75'.
DATA lv_value TYPE {{p}}provision_calc=>ty_amount.
TRY.
lv_value = mo_cut->calculate_value( lt_lines ).
CATCH {{p}}cx_prov_error INTO DATA(lx_error).
cl_abap_unit_assert=>fail( msg = |Unexpected reason { lx_error->reason }| ).
ENDTRY.
cl_abap_unit_assert=>assert_equals( exp = lv_expected act = lv_value ).
ENDMETHOD.
METHOD limit_exceeded.
DATA lt_lines TYPE {{p}}provision_calc=>tt_lines.
lt_lines = VALUE #( ( material = 'ENGINE' quantity = 1 price = '100000.01' ) ).
TRY.
mo_cut->check_order( lt_lines ).
cl_abap_unit_assert=>fail( ).
CATCH {{p}}cx_prov_error INTO DATA(lx_error).
cl_abap_unit_assert=>assert_equals( exp = {{p}}provision_calc=>c_limit_exceeded
act = lx_error->reason ).
ENDTRY.
ENDMETHOD.
METHOD rounds_total.
DATA lt_lines TYPE {{p}}provision_calc=>tt_lines.
lt_lines = VALUE #( ( material = 'ROPE' quantity = '1.005' price = '1.00' )
( material = 'BOLT' quantity = '1.005' price = '1.00' ) ).
DATA lv_expected TYPE {{p}}provision_calc=>ty_amount VALUE '2.01'.
DATA lv_value TYPE {{p}}provision_calc=>ty_amount.
TRY.
lv_value = mo_cut->calculate_value( lt_lines ).
CATCH {{p}}cx_prov_error INTO DATA(lx_error).
cl_abap_unit_assert=>fail( msg = |Unexpected reason { lx_error->reason }| ).
ENDTRY.
cl_abap_unit_assert=>assert_equals( exp = lv_expected act = lv_value ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,19 @@
CLASS {{p}}cx_prov_error DEFINITION PUBLIC INHERITING FROM cx_static_check FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_reason TYPE c LENGTH 20.
DATA reason TYPE ty_reason READ-ONLY.
METHODS constructor
IMPORTING iv_reason TYPE ty_reason.
PRIVATE SECTION.
ENDCLASS.
CLASS {{p}}cx_prov_error IMPLEMENTATION.
METHOD constructor.
super->constructor( ).
reason = iv_reason.
ENDMETHOD.
ENDCLASS.

View File

@@ -1,38 +0,0 @@
CLASS {{p}}drug_master DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_drug_id TYPE c LENGTH 10.
TYPES:
BEGIN OF ty_drug,
drug_id TYPE ty_drug_id,
max_daily_dose TYPE i,
END OF ty_drug,
tt_drug TYPE STANDARD TABLE OF ty_drug WITH EMPTY KEY.
METHODS get_drug
IMPORTING iv_drug_id TYPE ty_drug_id
RETURNING VALUE(rs_drug) TYPE ty_drug.
PRIVATE SECTION.
METHODS get_all_drugs
RETURNING VALUE(rt_drug) TYPE tt_drug.
ENDCLASS.
CLASS {{p}}drug_master IMPLEMENTATION.
METHOD get_drug.
DATA(lt_drug) = get_all_drugs( ).
READ TABLE lt_drug INTO rs_drug WITH KEY drug_id = iv_drug_id.
IF sy-subrc <> 0.
CLEAR rs_drug.
ENDIF.
ENDMETHOD.
METHOD get_all_drugs.
rt_drug = VALUE #( ( drug_id = 'PARA500' max_daily_dose = 4000 )
( drug_id = 'IBU400' max_daily_dose = 1200 )
( drug_id = 'AMOX500' max_daily_dose = 1500 )
( drug_id = 'META50' max_daily_dose = 200 )
( drug_id = 'SALB100' max_daily_dose = 800 ) ).
ENDMETHOD.
ENDCLASS.

View File

@@ -1,84 +1,73 @@
# 1. Goal
A pharmacy dispenses prescription items. Before the pharmacy dispenses a
prescription, it validates the prescription. The validation raises a class-based
exception with one reason and one message for each problem. The pharmacy program
needs the validation class and the exception class.
A ship chandler supplies provisions to vessels. The ordering program of the
chandler calls one service for each provisioning order. The service checks the
lines of the order and calculates the net value of the order. The service
reports each violation as a class-based exception with one reason code.
# 2. Open questions
None.
# 3. Context
- The class {{P}}DRUG_MASTER is in package $TMP. It is active. It is the drug
master data of the pharmacy. Do not change it.
- Public type TY_DRUG_ID: character, length 10.
- Public structure TY_DRUG with the components DRUG_ID (TY_DRUG_ID) and
MAX_DAILY_DOSE (integer, milligram).
- Public method GET_DRUG with the importing parameter IV_DRUG_ID (TY_DRUG_ID)
and the returning parameter RS_DRUG (TY_DRUG). If the drug is not in the
master data, RS_DRUG is initial.
- The drug master data contains these drugs and maximum daily doses:
PARA500 4000, IBU400 1200, AMOX500 1500, META50 200, SALB100 800.
- A prescription has an issue date, a number of valid days and items. Each item
has a drug, a quantity and a daily dose.
- The exception class {{P}}CX_PROV_ERROR exists in package $TMP. It is active.
- The class inherits from CX_STATIC_CHECK. It has the type TY_REASON (CHAR 20),
the read-only attribute REASON, and a constructor with the importing
parameter IV_REASON of type TY_REASON.
- The ordering program catches the exception and shows the reason code.
# 4. Contract
## 4.1 Exception class {{P}}CX_PRESC_ERROR
- Create the class in package $TMP.
- The class inherits from CX_ROOT.
- Public type TY_REASON: character, length 12.
- Public constant structure C_REASON with the components EMPTY, EXPIRED,
QUANTITY, UNKNOWN, DOSE and DUPLICATE. Each component has the type TY_REASON
and the value of its own name.
- Public constructor with the importing parameter IV_REASON (TY_REASON).
- Public method GET_REASON with the returning parameter RV_REASON (TY_REASON).
- Public method GET_MESSAGE_TEXT with the returning parameter RV_TEXT (string).
GET_MESSAGE_TEXT returns the message of the reason:
- EMPTY: The prescription has no items
- EXPIRED: The prescription is expired
- QUANTITY: The quantity is not positive
- UNKNOWN: The drug is not in the drug master
- DOSE: The daily dose is not allowed
- DUPLICATE: The drug appears more than once
## 4.2 Check class {{P}}PRESCRIPTION_CHECK
- Create the class in package $TMP.
- Create the class {{P}}PROVISION_CALC in package $TMP.
- The class is public and final. It has a public constructor without parameters.
- Public type TY_DRUG_ID: character, length 10.
- Public structure TY_ITEM with the components DRUG_ID (TY_DRUG_ID), QUANTITY
(integer) and DAILY_DOSE (integer).
- Public table type TT_ITEM: standard table of TY_ITEM with empty key.
- Public method VALIDATE with these importing parameters:
- IV_ISSUE_DATE (type d)
- IV_VALID_DAYS (integer)
- IV_AS_OF_DATE (type d)
- IT_ITEM (TT_ITEM)
and the addition RAISING {{P}}CX_PRESC_ERROR.
- Public types of the class:
- TY_MATERIAL (CHAR 18), TY_QUANTITY (packed, length 13, 3 decimals),
TY_PRICE (packed, length 11, 2 decimals), TY_AMOUNT (packed, length 13,
2 decimals), TY_REASON (CHAR 20).
- TY_LINE with the components MATERIAL, QUANTITY and PRICE.
- TT_LINES, a standard table of TY_LINE with an empty key.
- Public constants of the class:
- C_MAX_LINES (type I) with the value 999.
- C_VALUE_LIMIT (type TY_AMOUNT) with the value 100000.00.
- C_EMPTY_ORDER, C_TOO_MANY_LINES, C_MATERIAL_MISSING, C_QUANTITY_INVALID,
C_PRICE_NEGATIVE, C_DUPLICATE_MATERIAL and C_LIMIT_EXCEEDED, all of type
TY_REASON, with the values EMPTY_ORDER, TOO_MANY_LINES, MATERIAL_MISSING,
QUANTITY_INVALID, PRICE_NEGATIVE, DUPLICATE_MATERIAL and LIMIT_EXCEEDED.
- Public methods of the class:
- CHECK_ORDER, importing IT_LINES of type TT_LINES, raising
{{P}}CX_PROV_ERROR.
- CALCULATE_VALUE, importing IT_LINES of type TT_LINES, returning RV_VALUE
of type TY_AMOUNT, raising {{P}}CX_PROV_ERROR.
- Do not add other public methods.
# 5. Business rules
VALIDATE applies the rules in this sequence. It raises {{P}}CX_PRESC_ERROR with
the reason of the first rule that fails.
1. If IT_ITEM is empty, the reason is EMPTY.
2. If IV_AS_OF_DATE is later than IV_ISSUE_DATE plus IV_VALID_DAYS days, the
reason is EXPIRED.
3. Process the items in the sequence of the table. For each item:
3.1 If QUANTITY is less than 1, the reason is QUANTITY.
3.2 If DRUG_ID is not in the drug master data, the reason is UNKNOWN.
3.3 If DAILY_DOSE is less than 1, or if DAILY_DOSE is greater than the
maximum daily dose of the drug, the reason is DOSE.
4. If one DRUG_ID occurs in more than one item, the reason is DUPLICATE.
5. Else VALIDATE returns without an exception.
The dates are always valid dates.
The value of a line is the quantity multiplied by the price. The net value of
the order is the sum of the exact line values. Round only the net value, and
only once, to 2 decimals. Half values round away from zero.
CHECK_ORDER applies these rules in this sequence. It raises {{P}}CX_PROV_ERROR
with the reason of the first rule that fails.
1. If the order has no line, the reason is C_EMPTY_ORDER.
2. If the order has more than C_MAX_LINES lines, the reason is
C_TOO_MANY_LINES.
3. Check the lines in the given order. For each line apply these rules in this
sequence:
a. If the material is empty or contains only spaces, the reason is
C_MATERIAL_MISSING.
b. If the quantity is not greater than zero, the reason is
C_QUANTITY_INVALID.
c. If the price is less than zero, the reason is C_PRICE_NEGATIVE.
d. If the material occurs in an earlier line, the reason is
C_DUPLICATE_MATERIAL.
4. If the net value of the order is greater than C_VALUE_LIMIT, the reason is
C_LIMIT_EXCEEDED.
CALCULATE_VALUE applies the same checks and returns the net value.
# 6. Constraints
- Release target: SAP_BASIS 816 (ABAP Platform 2025).
- Package: $TMP. Do not use a transport request.
- Coding standards: Clean ABAP. Methods below 40 statements. No global
variables. Pass large parameters by reference. No comment that restates the
code.
- Out of scope: do not change {{P}}DRUG_MASTER.
- Release target: SAP_BASIS 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 {{P}}CX_PROV_ERROR.
# 7. Acceptance
- Both classes are active and have no syntax error.
- The class is active and has no syntax error.
- The hidden tests pass.
- Write your own ABAP Unit tests for {{P}}PRESCRIPTION_CHECK.
- Write your own ABAP Unit tests for the class.

View File

@@ -12,49 +12,39 @@
"seed": [
{
"type": "CLAS",
"name": "{{P}}DRUG_MASTER",
"file": "seed/drug_master.clas.abap",
"description": "Drug master data of the pharmacy"
"name": "{{P}}CX_PROV_ERROR",
"file": "seed/cx_prov_error.clas.abap",
"description": "Class-based exception that carries one provisioning reason code"
}
],
"contract": [
{
"type": "CLAS",
"name": "{{P}}CX_PRESC_ERROR"
},
{
"type": "CLAS",
"name": "{{P}}PRESCRIPTION_CHECK"
"name": "{{P}}PROVISION_CALC"
}
],
"out_of_scope": [
"{{P}}DRUG_MASTER"
"{{P}}CX_PROV_ERROR"
],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}T02_HIDDEN",
"file": "hidden/t02_hidden.clas.abap",
"description": "T02 hidden tests"
"name": "{{P}}T_PROV_HIDDEN",
"file": "hidden/t_prov_hidden.clas.abap",
"description": "Hidden tests for the provisioning order service"
}
],
"reference": [
{
"type": "CLAS",
"name": "{{P}}CX_PRESC_ERROR",
"file": "reference/cx_presc_error.clas.abap",
"description": "Prescription exception with reason and message"
},
{
"type": "CLAS",
"name": "{{P}}PRESCRIPTION_CHECK",
"file": "reference/prescription_check.clas.abap",
"description": "Prescription check",
"testclasses_file": "reference/prescription_check.testclasses.abap"
"name": "{{P}}PROVISION_CALC",
"file": "reference/provision_calc.clas.abap",
"description": "Provisioning order check and net value calculation",
"testclasses_file": "reference/provision_calc.testclasses.abap"
}
],
"craft_checks": [
"method_length",
"db_operation_in_loop"
"exception_handling"
]
}