Pipeline controller: plan 2 (hard +, error +50 %), backlog throttle, 2 trajectory workers, stop rules, summaries every 50; budget reserve

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Kral
2026-10-05 13:35:54 +02:00
parent 1c4667a0fc
commit 13360292dd
781 changed files with 50211 additions and 22 deletions

View File

@@ -0,0 +1,108 @@
CLASS {{p}}storage_pricer DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2.
TYPES ty_sqm TYPE i.
TYPES ty_months TYPE i.
TYPES:
BEGIN OF ty_booking,
size_sqm TYPE ty_sqm,
months TYPE ty_months,
climate TYPE abap_bool,
insurance TYPE abap_bool,
END OF ty_booking.
METHODS calculate_price
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_price) TYPE ty_amount.
PRIVATE SECTION.
CONSTANTS:
c_rate_small TYPE ty_amount VALUE '14.00',
c_rate_medium TYPE ty_amount VALUE '11.50',
c_rate_large TYPE ty_amount VALUE '9.00',
c_climate_addon TYPE ty_amount VALUE '4.50',
c_insurance_rate TYPE ty_amount VALUE '0.90',
c_admin_fee TYPE ty_amount VALUE '19.00',
c_percent TYPE i VALUE 100,
c_size_small_max TYPE ty_sqm VALUE 5,
c_size_medium_max TYPE ty_sqm VALUE 15,
c_months_short TYPE ty_months VALUE 6,
c_months_medium TYPE ty_months VALUE 12,
c_months_long TYPE ty_months VALUE 24,
c_disc_short TYPE i VALUE 5,
c_disc_medium TYPE i VALUE 10,
c_disc_long TYPE i VALUE 15.
METHODS is_valid
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_valid) TYPE abap_bool.
METHODS monthly_rate
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_rate) TYPE ty_amount.
METHODS discount_percent
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_percent) TYPE i.
METHODS insurance_fee
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_fee) TYPE ty_amount.
ENDCLASS.
CLASS {{p}}storage_pricer IMPLEMENTATION.
METHOD calculate_price.
IF is_valid( is_booking ) <> abap_false.
RETURN.
ENDIF.
DATA lv_rent TYPE ty_amount.
DATA lv_discount TYPE ty_amount.
DATA lv_total TYPE ty_amount.
lv_rent = is_booking-size_sqm * is_booking-months * monthly_rate( is_booking ).
lv_discount = lv_rent * discount_percent( is_booking ) / c_percent.
lv_total = lv_rent - lv_discount + insurance_fee( is_booking ) + c_admin_fee.
rv_price = lv_total.
ENDMETHOD.
METHOD is_valid.
rv_valid = xsdbool( is_booking-size_sqm > 0 AND is_booking-months > 0 ).
ENDMETHOD.
METHOD monthly_rate.
IF is_booking-size_sqm <= c_size_small_max.
rv_rate = c_rate_small.
ELSEIF is_booking-size_sqm <= c_size_medium_max.
rv_rate = c_rate_medium.
ELSE.
rv_rate = c_rate_large.
ENDIF.
IF is_booking-climate = abap_true.
rv_rate = rv_rate + c_climate_addon.
ENDIF.
ENDMETHOD.
METHOD discount_percent.
IF is_booking-months >= c_months_long.
rv_percent = c_disc_long.
ELSEIF is_booking-months >= c_months_medium.
rv_percent = c_disc_medium.
ELSEIF is_booking-months >= c_months_short.
rv_percent = c_disc_short.
ENDIF.
ENDMETHOD.
METHOD insurance_fee.
IF is_booking-insurance = abap_true.
rv_fee = is_booking-size_sqm * is_booking-months * c_insurance_rate.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,108 @@
CLASS {{p}}storage_pricer DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2.
TYPES ty_sqm TYPE i.
TYPES ty_months TYPE i.
TYPES:
BEGIN OF ty_booking,
size_sqm TYPE ty_sqm,
months TYPE ty_months,
climate TYPE abap_bool,
insurance TYPE abap_bool,
END OF ty_booking.
METHODS calculate_price
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_price) TYPE ty_amount.
PRIVATE SECTION.
CONSTANTS:
c_rate_small TYPE ty_amount VALUE '14.00',
c_rate_medium TYPE ty_amount VALUE '11.50',
c_rate_large TYPE ty_amount VALUE '9.00',
c_climate_addon TYPE ty_amount VALUE '4.50',
c_insurance_rate TYPE ty_amount VALUE '0.90',
c_admin_fee TYPE ty_amount VALUE '19.00',
c_percent TYPE i VALUE 100,
c_size_small_max TYPE ty_sqm VALUE 5,
c_size_medium_max TYPE ty_sqm VALUE 15,
c_months_short TYPE ty_months VALUE 6,
c_months_medium TYPE ty_months VALUE 12,
c_months_long TYPE ty_months VALUE 24,
c_disc_short TYPE i VALUE 5,
c_disc_medium TYPE i VALUE 10,
c_disc_long TYPE i VALUE 15.
METHODS is_valid
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_valid) TYPE abap_bool.
METHODS monthly_rate
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_rate) TYPE ty_amount.
METHODS discount_percent
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_percent) TYPE i.
METHODS insurance_fee
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_fee) TYPE ty_amount.
ENDCLASS.
CLASS {{p}}storage_pricer IMPLEMENTATION.
METHOD calculate_price.
IF is_valid( is_booking ) = abap_false.
RETURN.
ENDIF.
DATA lv_rent TYPE ty_amount.
DATA lv_discount TYPE ty_amount.
DATA lv_total TYPE ty_amount.
lv_rent = is_booking-size_sqm * is_booking-months * monthly_rate( is_booking ).
lv_discount = lv_rent * discount_percent( is_booking ) / c_percent.
lv_total = lv_rent - lv_discount + insurance_fee( is_booking ) + c_admin_fee.
rv_price = lv_total.
ENDMETHOD.
METHOD is_valid.
rv_valid = xsdbool( is_booking-size_sqm > 0 AND is_booking-months <= 0 ).
ENDMETHOD.
METHOD monthly_rate.
IF is_booking-size_sqm <= c_size_small_max.
rv_rate = c_rate_small.
ELSEIF is_booking-size_sqm <= c_size_medium_max.
rv_rate = c_rate_medium.
ELSE.
rv_rate = c_rate_large.
ENDIF.
IF is_booking-climate = abap_true.
rv_rate = rv_rate + c_climate_addon.
ENDIF.
ENDMETHOD.
METHOD discount_percent.
IF is_booking-months >= c_months_long.
rv_percent = c_disc_long.
ELSEIF is_booking-months >= c_months_medium.
rv_percent = c_disc_medium.
ELSEIF is_booking-months >= c_months_short.
rv_percent = c_disc_short.
ENDIF.
ENDMETHOD.
METHOD insurance_fee.
IF is_booking-insurance = abap_true.
rv_fee = is_booking-size_sqm * is_booking-months * c_insurance_rate.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,108 @@
CLASS {{p}}storage_pricer DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2.
TYPES ty_sqm TYPE i.
TYPES ty_months TYPE i.
TYPES:
BEGIN OF ty_booking,
size_sqm TYPE ty_sqm,
months TYPE ty_months,
climate TYPE abap_bool,
insurance TYPE abap_bool,
END OF ty_booking.
METHODS calculate_price
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_price) TYPE ty_amount.
PRIVATE SECTION.
CONSTANTS:
c_rate_small TYPE ty_amount VALUE '14.00',
c_rate_medium TYPE ty_amount VALUE '11.50',
c_rate_large TYPE ty_amount VALUE '9.00',
c_climate_addon TYPE ty_amount VALUE '4.50',
c_insurance_rate TYPE ty_amount VALUE '0.90',
c_admin_fee TYPE ty_amount VALUE '19.00',
c_percent TYPE i VALUE 100,
c_size_small_max TYPE ty_sqm VALUE 5,
c_size_medium_max TYPE ty_sqm VALUE 15,
c_months_short TYPE ty_months VALUE 6,
c_months_medium TYPE ty_months VALUE 12,
c_months_long TYPE ty_months VALUE 24,
c_disc_short TYPE i VALUE 5,
c_disc_medium TYPE i VALUE 10,
c_disc_long TYPE i VALUE 15.
METHODS is_valid
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_valid) TYPE abap_bool.
METHODS monthly_rate
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_rate) TYPE ty_amount.
METHODS discount_percent
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_percent) TYPE i.
METHODS insurance_fee
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_fee) TYPE ty_amount.
ENDCLASS.
CLASS {{p}}storage_pricer IMPLEMENTATION.
METHOD calculate_price.
IF is_valid( is_booking ) = abap_false.
RETURN.
ENDIF.
DATA lv_rent TYPE ty_amount.
DATA lv_discount TYPE ty_amount.
DATA lv_total TYPE ty_amount.
lv_rent = is_booking-size_sqm * is_booking-months * monthly_rate( is_booking ).
lv_discount = lv_rent * discount_percent( is_booking ) / c_percent.
lv_total = lv_rent - lv_discount + insurance_fee( is_booking ) + c_admin_fee.
rv_price = lv_total.
ENDMETHOD.
METHOD is_valid.
rv_valid = xsdbool( is_booking-size_sqm > 0 AND is_booking-months > 0 ).
ENDMETHOD.
METHOD monthly_rate.
IF is_booking-size_sqm <= c_size_small_max.
rv_rate = c_rate_small.
ELSEIF is_booking-size_sqm <= c_size_medium_max.
rv_rate = c_rate_medium.
ELSE.
rv_rate = c_rate_large.
ENDIF.
IF is_booking-climate = abap_true.
rv_rate = rv_rate - c_climate_addon.
ENDIF.
ENDMETHOD.
METHOD discount_percent.
IF is_booking-months >= c_months_long.
rv_percent = c_disc_long.
ELSEIF is_booking-months >= c_months_medium.
rv_percent = c_disc_medium.
ELSEIF is_booking-months >= c_months_short.
rv_percent = c_disc_short.
ENDIF.
ENDMETHOD.
METHOD insurance_fee.
IF is_booking-insurance = abap_true.
rv_fee = is_booking-size_sqm * is_booking-months * c_insurance_rate.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,108 @@
CLASS {{p}}storage_pricer DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2.
TYPES ty_sqm TYPE i.
TYPES ty_months TYPE i.
TYPES:
BEGIN OF ty_booking,
size_sqm TYPE ty_sqm,
months TYPE ty_months,
climate TYPE abap_bool,
insurance TYPE abap_bool,
END OF ty_booking.
METHODS calculate_price
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_price) TYPE ty_amount.
PRIVATE SECTION.
CONSTANTS:
c_rate_small TYPE ty_amount VALUE '14.00',
c_rate_medium TYPE ty_amount VALUE '11.50',
c_rate_large TYPE ty_amount VALUE '9.00',
c_climate_addon TYPE ty_amount VALUE '4.50',
c_insurance_rate TYPE ty_amount VALUE '0.90',
c_admin_fee TYPE ty_amount VALUE '19.00',
c_percent TYPE i VALUE 100,
c_size_small_max TYPE ty_sqm VALUE 5,
c_size_medium_max TYPE ty_sqm VALUE 15,
c_months_short TYPE ty_months VALUE 6,
c_months_medium TYPE ty_months VALUE 12,
c_months_long TYPE ty_months VALUE 24,
c_disc_short TYPE i VALUE 5,
c_disc_medium TYPE i VALUE 10,
c_disc_long TYPE i VALUE 15.
METHODS is_valid
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_valid) TYPE abap_bool.
METHODS monthly_rate
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_rate) TYPE ty_amount.
METHODS discount_percent
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_percent) TYPE i.
METHODS insurance_fee
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_fee) TYPE ty_amount.
ENDCLASS.
CLASS {{p}}storage_pricer IMPLEMENTATION.
METHOD calculate_price.
IF is_valid( is_booking ) = abap_false.
RETURN.
ENDIF.
DATA lv_rent TYPE ty_amount.
DATA lv_discount TYPE ty_amount.
DATA lv_total TYPE ty_amount.
lv_rent = is_booking-size_sqm * is_booking-months * monthly_rate( is_booking ).
lv_discount = lv_rent * discount_percent( is_booking ) / c_percent.
lv_total = lv_rent - lv_discount + insurance_fee( is_booking ) + c_admin_fee.
rv_price = lv_total.
ENDMETHOD.
METHOD is_valid.
rv_valid = xsdbool( is_booking-size_sqm > 0 AND is_booking-months > 0 ).
ENDMETHOD.
METHOD monthly_rate.
IF is_booking-size_sqm <= c_size_small_max.
rv_rate = c_rate_small.
ELSEIF is_booking-size_sqm <= c_size_medium_max.
rv_rate = c_rate_medium.
ELSE.
rv_rate = c_rate_large.
ENDIF.
IF is_booking-climate = abap_true.
rv_rate = rv_rate + c_climate_addon.
ENDIF.
ENDMETHOD.
METHOD discount_percent.
IF is_booking-months < c_months_long.
rv_percent = c_disc_long.
ELSEIF is_booking-months >= c_months_medium.
rv_percent = c_disc_medium.
ELSEIF is_booking-months >= c_months_short.
rv_percent = c_disc_short.
ENDIF.
ENDMETHOD.
METHOD insurance_fee.
IF is_booking-insurance = abap_true.
rv_fee = is_booking-size_sqm * is_booking-months * c_insurance_rate.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,108 @@
CLASS {{p}}storage_pricer DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2.
TYPES ty_sqm TYPE i.
TYPES ty_months TYPE i.
TYPES:
BEGIN OF ty_booking,
size_sqm TYPE ty_sqm,
months TYPE ty_months,
climate TYPE abap_bool,
insurance TYPE abap_bool,
END OF ty_booking.
METHODS calculate_price
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_price) TYPE ty_amount.
PRIVATE SECTION.
CONSTANTS:
c_rate_small TYPE ty_amount VALUE '14.00',
c_rate_medium TYPE ty_amount VALUE '11.50',
c_rate_large TYPE ty_amount VALUE '9.00',
c_climate_addon TYPE ty_amount VALUE '4.50',
c_insurance_rate TYPE ty_amount VALUE '0.90',
c_admin_fee TYPE ty_amount VALUE '19.00',
c_percent TYPE i VALUE 100,
c_size_small_max TYPE ty_sqm VALUE 5,
c_size_medium_max TYPE ty_sqm VALUE 15,
c_months_short TYPE ty_months VALUE 6,
c_months_medium TYPE ty_months VALUE 12,
c_months_long TYPE ty_months VALUE 24,
c_disc_short TYPE i VALUE 5,
c_disc_medium TYPE i VALUE 10,
c_disc_long TYPE i VALUE 15.
METHODS is_valid
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_valid) TYPE abap_bool.
METHODS monthly_rate
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_rate) TYPE ty_amount.
METHODS discount_percent
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_percent) TYPE i.
METHODS insurance_fee
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_fee) TYPE ty_amount.
ENDCLASS.
CLASS {{p}}storage_pricer IMPLEMENTATION.
METHOD calculate_price.
IF is_valid( is_booking ) = abap_false.
RETURN.
ENDIF.
DATA lv_rent TYPE ty_amount.
DATA lv_discount TYPE ty_amount.
DATA lv_total TYPE ty_amount.
lv_rent = is_booking-size_sqm * is_booking-months * monthly_rate( is_booking ).
lv_discount = lv_rent * discount_percent( is_booking ) / c_percent.
lv_total = lv_rent - lv_discount + insurance_fee( is_booking ) + c_admin_fee.
rv_price = lv_total.
ENDMETHOD.
METHOD is_valid.
rv_valid = xsdbool( is_booking-size_sqm > 0 AND is_booking-months > 0 ).
ENDMETHOD.
METHOD monthly_rate.
IF is_booking-size_sqm <= c_size_small_max.
rv_rate = c_rate_small.
ELSEIF is_booking-size_sqm <= c_size_medium_max.
rv_rate = c_rate_medium.
ELSE.
rv_rate = c_rate_large.
ENDIF.
IF is_booking-climate = abap_true.
rv_rate = rv_rate + c_climate_addon.
ENDIF.
ENDMETHOD.
METHOD discount_percent.
IF is_booking-months >= c_months_long.
rv_percent = c_disc_long.
ELSEIF is_booking-months >= c_months_medium.
rv_percent = c_disc_medium.
ELSEIF is_booking-months >= c_months_short.
rv_percent = c_disc_short.
ENDIF.
ENDMETHOD.
METHOD insurance_fee.
IF is_booking-insurance = abap_false.
rv_fee = is_booking-size_sqm * is_booking-months * c_insurance_rate.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,19 @@
{
"id": "G1034",
"pool": "train",
"object_type": "CLAS",
"category": "E",
"attempts": [
{
"stage": "validate",
"oracle": 100.0,
"null": 0,
"mutation": {
"valid": 5,
"killed": 5,
"ok": true
}
}
],
"accepted": true
}

View File

@@ -0,0 +1,205 @@
CLASS {{p}}t_stor_hidden DEFINITION
PUBLIC
FINAL
CREATE PUBLIC
FOR TESTING
DURATION SHORT
RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO {{p}}storage_pricer.
METHODS setup.
METHODS booking
IMPORTING iv_size TYPE i
iv_months TYPE i
iv_climate TYPE abap_bool
iv_insurance TYPE abap_bool
RETURNING VALUE(rs_booking) TYPE {{p}}storage_pricer=>ty_booking.
METHODS assert_price
IMPORTING iv_size TYPE i
iv_months TYPE i
iv_climate TYPE abap_bool
iv_insurance TYPE abap_bool
iv_expected TYPE {{p}}storage_pricer=>ty_amount
iv_msg TYPE string OPTIONAL.
METHODS rejects_zero_size FOR TESTING.
METHODS rejects_zero_months FOR TESTING.
METHODS rejects_negative FOR TESTING.
METHODS small_unit_short FOR TESTING.
METHODS size_band_limits FOR TESTING.
METHODS climate_surcharge FOR TESTING.
METHODS insurance_surcharge FOR TESTING.
METHODS discount_tiers FOR TESTING.
METHODS discount_thresholds FOR TESTING.
METHODS all_extras FOR TESTING.
ENDCLASS.
CLASS {{p}}t_stor_hidden IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}storage_pricer( ).
ENDMETHOD.
METHOD booking.
rs_booking-size_sqm = iv_size.
rs_booking-months = iv_months.
rs_booking-climate = iv_climate.
rs_booking-insurance = iv_insurance.
ENDMETHOD.
METHOD assert_price.
cl_abap_unit_assert=>assert_equals(
exp = iv_expected
act = mo_cut->calculate_price(
booking( iv_size = iv_size
iv_months = iv_months
iv_climate = iv_climate
iv_insurance = iv_insurance ) )
msg = iv_msg ).
ENDMETHOD.
METHOD rejects_zero_size.
assert_price( iv_size = 0
iv_months = 6
iv_climate = abap_false
iv_insurance = abap_false
iv_expected = '0.00'
iv_msg = `zero size` ).
ENDMETHOD.
METHOD rejects_zero_months.
assert_price( iv_size = 5
iv_months = 0
iv_climate = abap_false
iv_insurance = abap_false
iv_expected = '0.00'
iv_msg = `zero months` ).
ENDMETHOD.
METHOD rejects_negative.
assert_price( iv_size = -3
iv_months = 4
iv_climate = abap_true
iv_insurance = abap_true
iv_expected = '0.00'
iv_msg = `negative size` ).
assert_price( iv_size = 4
iv_months = -1
iv_climate = abap_false
iv_insurance = abap_false
iv_expected = '0.00'
iv_msg = `negative months` ).
ENDMETHOD.
METHOD small_unit_short.
assert_price( iv_size = 3
iv_months = 1
iv_climate = abap_false
iv_insurance = abap_false
iv_expected = '61.00' ).
ENDMETHOD.
METHOD size_band_limits.
assert_price( iv_size = 5
iv_months = 2
iv_climate = abap_false
iv_insurance = abap_false
iv_expected = '159.00'
iv_msg = `size 5` ).
assert_price( iv_size = 6
iv_months = 2
iv_climate = abap_false
iv_insurance = abap_false
iv_expected = '157.00'
iv_msg = `size 6` ).
assert_price( iv_size = 15
iv_months = 2
iv_climate = abap_false
iv_insurance = abap_false
iv_expected = '364.00'
iv_msg = `size 15` ).
assert_price( iv_size = 16
iv_months = 2
iv_climate = abap_false
iv_insurance = abap_false
iv_expected = '307.00'
iv_msg = `size 16` ).
ENDMETHOD.
METHOD climate_surcharge.
assert_price( iv_size = 4
iv_months = 3
iv_climate = abap_true
iv_insurance = abap_false
iv_expected = '241.00' ).
ENDMETHOD.
METHOD insurance_surcharge.
assert_price( iv_size = 6
iv_months = 5
iv_climate = abap_false
iv_insurance = abap_true
iv_expected = '391.00' ).
ENDMETHOD.
METHOD discount_tiers.
assert_price( iv_size = 10
iv_months = 6
iv_climate = abap_false
iv_insurance = abap_false
iv_expected = '674.50'
iv_msg = `6 months` ).
assert_price( iv_size = 20
iv_months = 12
iv_climate = abap_false
iv_insurance = abap_false
iv_expected = '1963.00'
iv_msg = `12 months` ).
assert_price( iv_size = 20
iv_months = 24
iv_climate = abap_false
iv_insurance = abap_false
iv_expected = '3691.00'
iv_msg = `24 months` ).
ENDMETHOD.
METHOD discount_thresholds.
assert_price( iv_size = 10
iv_months = 5
iv_climate = abap_false
iv_insurance = abap_false
iv_expected = '594.00'
iv_msg = `5 months` ).
assert_price( iv_size = 10
iv_months = 11
iv_climate = abap_false
iv_insurance = abap_false
iv_expected = '1220.75'
iv_msg = `11 months` ).
assert_price( iv_size = 10
iv_months = 23
iv_climate = abap_false
iv_insurance = abap_false
iv_expected = '2399.50'
iv_msg = `23 months` ).
ENDMETHOD.
METHOD all_extras.
assert_price( iv_size = 5
iv_months = 6
iv_climate = abap_true
iv_insurance = abap_true
iv_expected = '573.25'
iv_msg = `medium unit` ).
assert_price( iv_size = 16
iv_months = 12
iv_climate = abap_true
iv_insurance = abap_true
iv_expected = '2524.60'
iv_msg = `large unit` ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,84 @@
{
"task": "G1034",
"mutants": [
{
"object": "{{P}}STORAGE_PRICER",
"mutant": "line 61: = -> <> (eq)",
"status": "killed",
"hidden": "0/10",
"failed_tests": [
"ALL_EXTRAS",
"CLIMATE_SURCHARGE",
"DISCOUNT_THRESHOLDS",
"DISCOUNT_TIERS",
"INSURANCE_SURCHARGE",
"REJECTS_NEGATIVE",
"REJECTS_ZERO_MONTHS",
"REJECTS_ZERO_SIZE",
"SIZE_BAND_LIMITS",
"SMALL_UNIT_SHORT"
]
},
{
"object": "{{P}}STORAGE_PRICER",
"mutant": "line 76: > -> <= (rel)",
"status": "killed",
"hidden": "1/10",
"failed_tests": [
"ALL_EXTRAS",
"CLIMATE_SURCHARGE",
"DISCOUNT_THRESHOLDS",
"DISCOUNT_TIERS",
"INSURANCE_SURCHARGE",
"REJECTS_NEGATIVE",
"REJECTS_ZERO_MONTHS",
"SIZE_BAND_LIMITS",
"SMALL_UNIT_SHORT"
]
},
{
"object": "{{P}}STORAGE_PRICER",
"mutant": "line 89: + -> - (arith)",
"status": "killed",
"hidden": "8/10",
"failed_tests": [
"ALL_EXTRAS",
"CLIMATE_SURCHARGE"
]
},
{
"object": "{{P}}STORAGE_PRICER",
"mutant": "line 94: >= -> < (rel)",
"status": "killed",
"hidden": "3/10",
"failed_tests": [
"ALL_EXTRAS",
"CLIMATE_SURCHARGE",
"DISCOUNT_THRESHOLDS",
"DISCOUNT_TIERS",
"INSURANCE_SURCHARGE",
"SIZE_BAND_LIMITS",
"SMALL_UNIT_SHORT"
]
},
{
"object": "{{P}}STORAGE_PRICER",
"mutant": "line 104: abap_true -> abap_false (bool)",
"status": "killed",
"hidden": "3/10",
"failed_tests": [
"ALL_EXTRAS",
"CLIMATE_SURCHARGE",
"DISCOUNT_THRESHOLDS",
"DISCOUNT_TIERS",
"INSURANCE_SURCHARGE",
"SIZE_BAND_LIMITS",
"SMALL_UNIT_SHORT"
]
}
],
"valid": 5,
"killed": 5,
"kill_rate": 1.0,
"ok": true
}

View File

@@ -0,0 +1,108 @@
CLASS {{p}}storage_pricer DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2.
TYPES ty_sqm TYPE i.
TYPES ty_months TYPE i.
TYPES:
BEGIN OF ty_booking,
size_sqm TYPE ty_sqm,
months TYPE ty_months,
climate TYPE abap_bool,
insurance TYPE abap_bool,
END OF ty_booking.
METHODS calculate_price
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_price) TYPE ty_amount.
PRIVATE SECTION.
CONSTANTS:
c_rate_small TYPE ty_amount VALUE '14.00',
c_rate_medium TYPE ty_amount VALUE '11.50',
c_rate_large TYPE ty_amount VALUE '9.00',
c_climate_addon TYPE ty_amount VALUE '4.50',
c_insurance_rate TYPE ty_amount VALUE '0.90',
c_admin_fee TYPE ty_amount VALUE '19.00',
c_percent TYPE i VALUE 100,
c_size_small_max TYPE ty_sqm VALUE 5,
c_size_medium_max TYPE ty_sqm VALUE 15,
c_months_short TYPE ty_months VALUE 6,
c_months_medium TYPE ty_months VALUE 12,
c_months_long TYPE ty_months VALUE 24,
c_disc_short TYPE i VALUE 5,
c_disc_medium TYPE i VALUE 10,
c_disc_long TYPE i VALUE 15.
METHODS is_valid
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_valid) TYPE abap_bool.
METHODS monthly_rate
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_rate) TYPE ty_amount.
METHODS discount_percent
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_percent) TYPE i.
METHODS insurance_fee
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_fee) TYPE ty_amount.
ENDCLASS.
CLASS {{p}}storage_pricer IMPLEMENTATION.
METHOD calculate_price.
IF is_valid( is_booking ) = abap_false.
RETURN.
ENDIF.
DATA lv_rent TYPE ty_amount.
DATA lv_discount TYPE ty_amount.
DATA lv_total TYPE ty_amount.
lv_rent = is_booking-size_sqm * is_booking-months * monthly_rate( is_booking ).
lv_discount = lv_rent * discount_percent( is_booking ) / c_percent.
lv_total = lv_rent - lv_discount + insurance_fee( is_booking ) + c_admin_fee.
rv_price = lv_total.
ENDMETHOD.
METHOD is_valid.
rv_valid = xsdbool( is_booking-size_sqm > 0 AND is_booking-months > 0 ).
ENDMETHOD.
METHOD monthly_rate.
IF is_booking-size_sqm <= c_size_small_max.
rv_rate = c_rate_small.
ELSEIF is_booking-size_sqm <= c_size_medium_max.
rv_rate = c_rate_medium.
ELSE.
rv_rate = c_rate_large.
ENDIF.
IF is_booking-climate = abap_true.
rv_rate = rv_rate + c_climate_addon.
ENDIF.
ENDMETHOD.
METHOD discount_percent.
IF is_booking-months >= c_months_long.
rv_percent = c_disc_long.
ELSEIF is_booking-months >= c_months_medium.
rv_percent = c_disc_medium.
ELSEIF is_booking-months >= c_months_short.
rv_percent = c_disc_short.
ENDIF.
ENDMETHOD.
METHOD insurance_fee.
IF is_booking-insurance = abap_true.
rv_fee = is_booking-size_sqm * is_booking-months * c_insurance_rate.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,92 @@
CLASS ltc_storage_pricer DEFINITION
FINAL
FOR TESTING
DURATION SHORT
RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO {{p}}storage_pricer.
METHODS setup.
METHODS assert_price
IMPORTING iv_size TYPE i
iv_months TYPE i
iv_climate TYPE abap_bool
iv_insurance TYPE abap_bool
iv_expected TYPE {{p}}storage_pricer=>ty_amount.
METHODS small_unit_no_extras FOR TESTING.
METHODS medium_unit_climate FOR TESTING.
METHODS large_unit_all_extras FOR TESTING.
METHODS long_term_discount FOR TESTING.
METHODS size_band_change FOR TESTING.
METHODS invalid_booking FOR TESTING.
ENDCLASS.
CLASS ltc_storage_pricer IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}storage_pricer( ).
ENDMETHOD.
METHOD assert_price.
DATA(ls_booking) = VALUE {{p}}storage_pricer=>ty_booking(
size_sqm = iv_size
months = iv_months
climate = iv_climate
insurance = iv_insurance ).
cl_abap_unit_assert=>assert_equals(
exp = iv_expected
act = mo_cut->calculate_price( ls_booking ) ).
ENDMETHOD.
METHOD small_unit_no_extras.
assert_price( iv_size = 3
iv_months = 1
iv_climate = abap_false
iv_insurance = abap_false
iv_expected = '61.00' ).
ENDMETHOD.
METHOD medium_unit_climate.
assert_price( iv_size = 4
iv_months = 3
iv_climate = abap_true
iv_insurance = abap_false
iv_expected = '241.00' ).
ENDMETHOD.
METHOD large_unit_all_extras.
assert_price( iv_size = 16
iv_months = 12
iv_climate = abap_true
iv_insurance = abap_true
iv_expected = '2524.60' ).
ENDMETHOD.
METHOD long_term_discount.
assert_price( iv_size = 20
iv_months = 24
iv_climate = abap_false
iv_insurance = abap_false
iv_expected = '3691.00' ).
ENDMETHOD.
METHOD size_band_change.
assert_price( iv_size = 6
iv_months = 2
iv_climate = abap_false
iv_insurance = abap_false
iv_expected = '157.00' ).
ENDMETHOD.
METHOD invalid_booking.
assert_price( iv_size = 0
iv_months = 6
iv_climate = abap_false
iv_insurance = abap_false
iv_expected = '0.00' ).
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,75 @@
CLASS {{p}}storage_pricer DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2.
TYPES ty_sqm TYPE i.
TYPES ty_months TYPE i.
TYPES:
BEGIN OF ty_booking,
size_sqm TYPE ty_sqm,
months TYPE ty_months,
climate TYPE abap_bool,
insurance TYPE abap_bool,
END OF ty_booking.
METHODS calculate_price
IMPORTING is_booking TYPE ty_booking
RETURNING VALUE(rv_price) TYPE ty_amount.
ENDCLASS.
CLASS {{p}}storage_pricer IMPLEMENTATION.
METHOD calculate_price.
" price of the booking
DATA lv_rate TYPE p LENGTH 8 DECIMALS 2.
DATA lv_rent TYPE p LENGTH 12 DECIMALS 2.
DATA lv_disc TYPE p LENGTH 12 DECIMALS 2.
DATA lv_ins TYPE p LENGTH 12 DECIMALS 2.
DATA lv_sum TYPE p LENGTH 12 DECIMALS 2.
DATA lv_tmp TYPE p LENGTH 12 DECIMALS 2.
rv_price = 0.
IF is_booking-size_sqm > 0.
IF is_booking-months > 0.
IF is_booking-size_sqm <= 5.
lv_rate = '14.00'.
ELSE.
IF is_booking-size_sqm <= 15.
lv_rate = '11.50'.
ELSE.
lv_rate = '9.00'.
ENDIF.
ENDIF.
IF is_booking-climate = 'X'.
lv_rate = lv_rate + '4.50'.
ENDIF.
lv_rent = is_booking-size_sqm * is_booking-months * lv_rate.
lv_disc = 0.
IF is_booking-months >= 24.
lv_disc = lv_rent * 15 / 100.
ELSE.
IF is_booking-months >= 12.
lv_disc = lv_rent * 10 / 100.
ELSE.
IF is_booking-months >= 6.
lv_disc = lv_rent * 5 / 100.
ENDIF.
ENDIF.
ENDIF.
lv_ins = 0.
IF is_booking-insurance = 'X'.
lv_ins = is_booking-size_sqm * is_booking-months * '0.90'.
ENDIF.
lv_tmp = lv_rent - lv_disc.
lv_sum = lv_tmp + lv_ins + '19.00'.
rv_price = lv_sum.
ENDIF.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,46 @@
# 1. Goal
A self-storage company rents storage units to private and business customers.
The class {{P}}STORAGE_PRICER calculates the price of one storage unit
booking. The class is legacy code. It works, but it is hard to read and hard
to change. Refactor the class. The behavior stays exactly the same. The class
name and the public interface stay the same.
# 2. Open questions
None.
# 3. Context
- The class {{P}}STORAGE_PRICER exists in package $TMP and is active.
- A checkout program calls the method CALCULATE_PRICE for each booking.
- The class is the only object of this task.
# 4. Contract
Keep the class {{P}}STORAGE_PRICER in package $TMP. Keep the class name and
the public interface. The public interface is:
- The class is public, final, and has a public constructor without parameters.
- Public type TY_AMOUNT: packed number, length 8, 2 decimals.
- Public type TY_SQM: integer.
- Public type TY_MONTHS: integer.
- Public type TY_BOOKING with the components SIZE_SQM (TYPE TY_SQM), MONTHS
(TYPE TY_MONTHS), CLIMATE (TYPE ABAP_BOOL) and INSURANCE (TYPE ABAP_BOOL).
- Public method CALCULATE_PRICE with the importing parameter IS_BOOKING
(TYPE TY_BOOKING) and the returning parameter RV_PRICE (TYPE TY_AMOUNT).
Do not add public methods or public components. Do not remove a public method
or a public component.
# 5. Business rules
The legacy code in {{P}}STORAGE_PRICER contains all business rules. Read the
legacy code. The behavior must stay exactly the same for every input. Do not
add a rule and do not remove a rule.
# 6. Constraints
- Release target: 8.16.
- Coding standards: Clean ABAP. Methods below 40 statements. No deep nesting.
No magic numbers; use constants. No global variables. No comment that
restates the code.
- Out of scope: no other object.
# 7. Acceptance
- The class {{P}}STORAGE_PRICER is active and has no syntax error.
- The public interface is unchanged.
- The hidden tests pass.
- Write your own ABAP Unit tests for the class.

View File

@@ -0,0 +1,49 @@
{
"id": "G1034",
"category": "E",
"object_type": "CLAS",
"difficulty": 2,
"release_target": "v816",
"expected_outcome": "implement",
"budget": {
"max_tool_calls": 80,
"max_activations": 20
},
"seed": [
{
"type": "CLAS",
"name": "{{P}}STORAGE_PRICER",
"file": "seed/storage_pricer.clas.abap",
"description": "Legacy storage unit rental pricer with deep nesting and magic numbers"
}
],
"contract": [
{
"type": "CLAS",
"name": "{{P}}STORAGE_PRICER"
}
],
"out_of_scope": [],
"hidden_tests": [
{
"type": "CLAS",
"name": "{{P}}T_STOR_HIDDEN",
"file": "hidden/t_stor_hidden.clas.abap",
"description": "Hidden tests for the unchanged behavior of {{P}}STORAGE_PRICER"
}
],
"reference": [
{
"type": "CLAS",
"name": "{{P}}STORAGE_PRICER",
"file": "reference/storage_pricer.clas.abap",
"description": "Refactored storage unit rental pricer with the same public interface",
"testclasses_file": "reference/storage_pricer.testclasses.abap"
}
],
"craft_checks": [
"method_length",
"nesting_depth",
"magic_numbers"
]
}