dodil/erp-brick-pos
DODIL ERP brick: point of sale
tests/scenarios/catalogue.py
"""pos's scenario catalogue (module.yaml tests.scenarios), each mapped to its stories and written ONCE over
the composition's doors — routes, MCP tools, public links — never a table. A skeleton: each scenario says its
Given/When/Then and is skipped until its steps are written.
erp-scenarios list tests/scenarios/catalogue.py
erp-scenarios run tests/scenarios/catalogue.py
"""
import pathlib
from erp_platform.scenarios import Catalogue, Skip
HERE = pathlib.Path(__file__).resolve().parent
CAT = Catalogue("pos", compose=HERE / "compose.yaml", roles=HERE / "roles.yaml")
# Generated over the composition's doors, both HTTP and MCP (erp_platform.scenarios.probes): every role ×
# every use case — 401 with no identity, 403 without the permission, served with it. The finer ones (state guards,
# separation of duties, row visibility, seams) are tests/test_invariants.py and test_stories.py.
CAT.permission_matrix()
@CAT.scenario("SC-POS-01", "an ordinary day in a London shop", stories=["POS-03", "POS-08", "POS-09", "POS-05", "POS-06", "POS-17", "POS-20"])
def sc_sc_pos_01(s):
s.given("LON-SOHO R1 opens with 150.00 on 2026-11-14")
s.when("214 receipts are sold, a 6.50 difference counted and approved by another person, and the day posts")
s.then("the Z report and the day journal of POS-17 and POS-20, balanced at 1,543.40, one journal")
raise Skip("TODO(scenario): write the steps over the doors (routes, tools, links)")
@CAT.scenario("SC-POS-02", "offline for two hours, a register dies, receipts arrive the next day", stories=["POS-12", "POS-07", "POS-21"])
def sc_sc_pos_02(s):
s.given("R2 offline 10:02 to 11:47, dead at 15:10 with 7 receipts unsynced")
s.when("the sync repeats, the session is force-closed, the day posts, and the 7 receipts arrive on 2026-11-15")
s.then("no receipt twice; one supplement journal for 41.20; the original day journal untouched")
raise Skip("TODO(scenario): write the steps over the doors (routes, tools, links)")
@CAT.scenario("SC-POS-03", "refund twice at once", stories=["POS-11"])
def sc_sc_pos_03(s):
s.given("one oat latte on receipt 0057")
s.when("two registers refund it at the same second")
s.then("one refund succeeds, the other is refused; the money and the claim agree")
raise Skip("TODO(scenario): write the steps over the doors (routes, tools, links)")
@CAT.scenario("SC-POS-04", "a German shop under KassenSichV with a TSE outage", stories=["POS-24", "POS-25"])
def sc_sc_pos_04(s):
s.given("BER-MITTE R1 with its TSE")
s.when("the TSE fails for 20 minutes during trading")
s.then("receipts print marked as sold without the TSE, the outage is recorded, the DSFinV-K export for the day contains every receipt with its signature or the outage marker")
raise Skip("TODO(scenario): write the steps over the doors (routes, tools, links)")
@CAT.scenario("SC-POS-05", "card settlement and the cash bag clear in payments", stories=["POS-19", "POS-26"])
def sc_sc_pos_05(s):
s.given("card clearing 890.10 and bag B-00451 of 600.00")
s.when("the statement shows 876.75 and 600.00")
s.then("payments matches both; card_clearing and cash_in_transit for the day are zero; fees 13.35 posted by payments")
raise Skip("TODO(scenario): write the steps over the doors (routes, tools, links)")