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,148 @@
CLASS {{p}}photo_pricer DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES ty_session TYPE c LENGTH 7.
TYPES ty_reason TYPE c LENGTH 8.
TYPES ty_amount TYPE p LENGTH 8 DECIMALS 2.
TYPES: BEGIN OF ty_request,
session TYPE ty_session,
minutes TYPE i,
persons TYPE i,
photos TYPE i,
distance_km TYPE i,
END OF ty_request.
TYPES: BEGIN OF ty_quote,
time_fee TYPE ty_amount,
person_fee TYPE ty_amount,
photo_fee TYPE ty_amount,
travel_fee TYPE ty_amount,
crew_fee TYPE ty_amount,
total TYPE ty_amount,
reason TYPE ty_reason,
END OF ty_quote.
CONSTANTS:
BEGIN OF c_session,
studio TYPE ty_session VALUE 'STUDIO',
outdoor TYPE ty_session VALUE 'OUTDOOR',
END OF c_session,
BEGIN OF c_reason,
ok TYPE ty_reason VALUE 'OK',
session TYPE ty_reason VALUE 'SESSION',
minutes TYPE ty_reason VALUE 'MINUTES',
persons TYPE ty_reason VALUE 'PERSONS',
photos TYPE ty_reason VALUE 'PHOTOS',
distance TYPE ty_reason VALUE 'DISTANCE',
END OF c_reason.
METHODS calculate
IMPORTING is_request TYPE ty_request
RETURNING VALUE(rs_quote) TYPE ty_quote.
PRIVATE SECTION.
CONSTANTS:
c_min_minutes TYPE i VALUE 30,
c_max_minutes TYPE i VALUE 480,
c_min_persons TYPE i VALUE 1,
c_max_persons TYPE i VALUE 20,
c_min_photos TYPE i VALUE 0,
c_max_photos TYPE i VALUE 200,
c_min_distance TYPE i VALUE 1,
c_slot_minutes TYPE i VALUE 15,
c_slot_fee TYPE ty_amount VALUE 20,
c_free_persons TYPE i VALUE 2,
c_person_fee TYPE ty_amount VALUE 10,
c_bulk_limit TYPE i VALUE 50,
c_photo_std TYPE ty_amount VALUE 5,
c_photo_bulk TYPE ty_amount VALUE 4,
c_travel_base TYPE ty_amount VALUE 15,
c_travel_km TYPE ty_amount VALUE 2,
c_crew_limit TYPE i VALUE 8,
c_crew_fee TYPE ty_amount VALUE 40.
METHODS check_request
IMPORTING is_request TYPE ty_request
RETURNING VALUE(rv_reason) TYPE ty_reason.
METHODS time_fee
IMPORTING iv_minutes TYPE i
RETURNING VALUE(rv_fee) TYPE ty_amount.
METHODS person_fee
IMPORTING iv_persons TYPE i
RETURNING VALUE(rv_fee) TYPE ty_amount.
METHODS photo_fee
IMPORTING iv_photos TYPE i
RETURNING VALUE(rv_fee) TYPE ty_amount.
METHODS travel_fee
IMPORTING is_request TYPE ty_request
RETURNING VALUE(rv_fee) TYPE ty_amount.
METHODS crew_fee
IMPORTING iv_persons TYPE i
RETURNING VALUE(rv_fee) TYPE ty_amount.
ENDCLASS.
CLASS {{p}}photo_pricer IMPLEMENTATION.
METHOD calculate.
rs_quote-reason = check_request( is_request ).
IF rs_quote-reason <> c_reason-ok.
RETURN.
ENDIF.
rs_quote-time_fee = time_fee( is_request-minutes ).
rs_quote-person_fee = person_fee( is_request-persons ).
rs_quote-photo_fee = photo_fee( is_request-photos ).
rs_quote-travel_fee = travel_fee( is_request ).
rs_quote-crew_fee = crew_fee( is_request-persons ).
rs_quote-total = rs_quote-time_fee + rs_quote-person_fee + rs_quote-photo_fee
+ rs_quote-travel_fee + rs_quote-crew_fee.
ENDMETHOD.
METHOD check_request.
IF is_request-session <> c_session-studio AND is_request-session <> c_session-outdoor.
rv_reason = c_reason-session.
ELSEIF is_request-minutes < c_min_minutes OR is_request-minutes > c_max_minutes.
rv_reason = c_reason-minutes.
ELSEIF is_request-persons < c_min_persons OR is_request-persons > c_max_persons.
rv_reason = c_reason-persons.
ELSEIF is_request-photos < c_min_photos OR is_request-photos > c_max_photos.
rv_reason = c_reason-photos.
ELSEIF is_request-session = c_session-outdoor AND is_request-distance_km < c_min_distance.
rv_reason = c_reason-distance.
ELSE.
rv_reason = c_reason-ok.
ENDIF.
ENDMETHOD.
METHOD time_fee.
DATA(lv_slots) = ( iv_minutes + c_slot_minutes - 1 ) DIV c_slot_minutes.
rv_fee = lv_slots * c_slot_fee.
ENDMETHOD.
METHOD person_fee.
DATA(lv_extra) = iv_persons - c_free_persons.
IF lv_extra > 0.
rv_fee = lv_extra * c_person_fee.
ENDIF.
ENDMETHOD.
METHOD photo_fee.
IF iv_photos >= c_bulk_limit.
rv_fee = iv_photos * c_photo_bulk.
ELSE.
rv_fee = iv_photos * c_photo_std.
ENDIF.
ENDMETHOD.
METHOD travel_fee.
IF is_request-session <> c_session-outdoor.
RETURN.
ENDIF.
rv_fee = c_travel_base + is_request-distance_km * c_travel_km.
ENDMETHOD.
METHOD crew_fee.
IF iv_persons > c_crew_limit.
rv_fee = c_crew_fee.
ENDIF.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,121 @@
CLASS ltc_photo_pricer DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO {{p}}photo_pricer.
METHODS setup.
METHODS studio_quote FOR TESTING.
METHODS outdoor_quote FOR TESTING.
METHODS studio_ignores_distance FOR TESTING.
METHODS rounds_up_minutes FOR TESTING.
METHODS rejects_unknown_session FOR TESTING.
METHODS rejects_bad_minutes FOR TESTING.
METHODS rejects_outdoor_no_distance FOR TESTING.
METHODS build_request
IMPORTING iv_session TYPE {{p}}photo_pricer=>ty_session
iv_minutes TYPE i
iv_persons TYPE i
iv_photos TYPE i
iv_distance_km TYPE i
RETURNING VALUE(rs_request) TYPE {{p}}photo_pricer=>ty_request.
ENDCLASS.
CLASS ltc_photo_pricer IMPLEMENTATION.
METHOD setup.
mo_cut = NEW {{p}}photo_pricer( ).
ENDMETHOD.
METHOD build_request.
rs_request = VALUE #( session = iv_session
minutes = iv_minutes
persons = iv_persons
photos = iv_photos
distance_km = iv_distance_km ).
ENDMETHOD.
METHOD studio_quote.
DATA(ls_request) = build_request( iv_session = {{p}}photo_pricer=>c_session-studio
iv_minutes = 90
iv_persons = 3
iv_photos = 10
iv_distance_km = 0 ).
DATA(ls_quote) = mo_cut->calculate( ls_request ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}photo_pricer=>c_reason-ok
act = ls_quote-reason ).
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}photo_pricer=>ty_amount( 180 )
act = ls_quote-total ).
ENDMETHOD.
METHOD outdoor_quote.
DATA(ls_request) = build_request( iv_session = {{p}}photo_pricer=>c_session-outdoor
iv_minutes = 45
iv_persons = 10
iv_photos = 50
iv_distance_km = 20 ).
DATA(ls_quote) = mo_cut->calculate( ls_request ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}photo_pricer=>c_reason-ok
act = ls_quote-reason ).
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}photo_pricer=>ty_amount( 435 )
act = ls_quote-total ).
ENDMETHOD.
METHOD studio_ignores_distance.
DATA(ls_request) = build_request( iv_session = {{p}}photo_pricer=>c_session-studio
iv_minutes = 30
iv_persons = 1
iv_photos = 0
iv_distance_km = 25 ).
DATA(ls_quote) = mo_cut->calculate( ls_request ).
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}photo_pricer=>ty_amount( 0 )
act = ls_quote-travel_fee ).
ENDMETHOD.
METHOD rounds_up_minutes.
DATA(ls_request) = build_request( iv_session = {{p}}photo_pricer=>c_session-studio
iv_minutes = 31
iv_persons = 1
iv_photos = 0
iv_distance_km = 0 ).
DATA(ls_quote) = mo_cut->calculate( ls_request ).
cl_abap_unit_assert=>assert_equals(
exp = CONV {{p}}photo_pricer=>ty_amount( 60 )
act = ls_quote-time_fee ).
ENDMETHOD.
METHOD rejects_unknown_session.
DATA(ls_request) = build_request( iv_session = 'WEDDING'
iv_minutes = 60
iv_persons = 2
iv_photos = 0
iv_distance_km = 0 ).
DATA(ls_quote) = mo_cut->calculate( ls_request ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}photo_pricer=>c_reason-session
act = ls_quote-reason ).
ENDMETHOD.
METHOD rejects_bad_minutes.
DATA(ls_request) = build_request( iv_session = {{p}}photo_pricer=>c_session-studio
iv_minutes = 29
iv_persons = 2
iv_photos = 0
iv_distance_km = 0 ).
DATA(ls_quote) = mo_cut->calculate( ls_request ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}photo_pricer=>c_reason-minutes
act = ls_quote-reason ).
ENDMETHOD.
METHOD rejects_outdoor_no_distance.
DATA(ls_request) = build_request( iv_session = {{p}}photo_pricer=>c_session-outdoor
iv_minutes = 60
iv_persons = 2
iv_photos = 0
iv_distance_km = 0 ).
DATA(ls_quote) = mo_cut->calculate( ls_request ).
cl_abap_unit_assert=>assert_equals( exp = {{p}}photo_pricer=>c_reason-distance
act = ls_quote-reason ).
ENDMETHOD.
ENDCLASS.