dodil/erp-brick-pos
DODIL ERP brick: point of sale
tests/test_statement_budget.py
"""Statement count is flat: a receipt of 20 lines, or a session of 20 receipts, costs the engine the same number of statements as
one of 2 (a statement per line is how a shop's busiest minute becomes a timeout). Counted with the engine's own cursor hook."""
from contextlib import contextmanager
from conftest import CASHIER, api, finalise, make_shop, must, open_till, pay, ring
from sqlalchemy import event
@contextmanager
def counting(engine):
seen: list = []
def hook(conn, cursor, statement, parameters, context, executemany):
seen.append(statement)
event.listen(engine, "before_cursor_execute", hook)
try:
yield seen
finally:
event.remove(engine, "before_cursor_execute", hook)
def many_products(nb, n=20):
for i in range(1, n + 1):
nb.price_lists["LIST-UK-SHOP"]["prices"].append((f"P{i:02d}", "C62", "1", f"{i}.50"))
nb.product_row(f"P{i:02d}", "hot_drink")
def lines(n):
return [{"product_id": f"P{i:02d}", "quantity": "1"} for i in range(1, n + 1)]
def test_ringing_paying_and_finalising_cost_the_same_statements_for_2_lines_or_20(engine, nb):
many_products(nb)
make_shop()
sid = open_till()["session_id"]
costs = {}
for n in (2, 20):
with counting(engine) as ring_stmts:
r = must(api("POST", "/receipts", CASHIER, {"session_id": sid, "lines": lines(n)}))
with counting(engine) as pay_stmts:
r = must(api("POST", f"/receipts/{r['receipt_id']}/payments", CASHIER, {"method": "cash", "amount": r["remaining"], "version": r["version"]}))
with counting(engine) as fin_stmts:
r = must(api("POST", f"/receipts/{r['receipt_id']}/finalise", CASHIER, {"version": r["version"]}))
assert len(r["lines"]) == n and r["status"] == "finalised"
costs[n] = (len(ring_stmts), len(pay_stmts), len(fin_stmts))
assert costs[2] == costs[20], costs
def test_counting_and_reading_a_session_cost_the_same_statements_for_2_receipts_or_20(engine, nb):
make_shop()
a, b = open_till(register="R1"), open_till(register="R2", who=CASHIER)
for sid, n in ((a["session_id"], 2), (b["session_id"], 20)):
for _ in range(n):
r = ring(sid, [("LATTE-REG", 1)])
finalise(pay(r, "cash", "3.60"))
costs = {}
for label, s in (("two", a), ("twenty", b)):
with counting(engine) as read:
view = must(api("GET", f"/sessions/{s['session_id']}", CASHIER))
with counting(engine) as counted:
must(api("POST", f"/sessions/{s['session_id']}/count", CASHIER, {"counted_cash": "0.00"}))
costs[label] = (len(read), len(counted))
assert view["summary"]["receipts"] in (2, 20)
assert costs["two"] == costs["twenty"], costs