dodil/erp-brick-ar
DODIL ERP brick: accounts receivable
tests/test_doors.py
"""The same outcome through the API and through MCP: tools are use cases, the doors are generated from one declaration."""
import json
from conftest import BILLER, BP, OWNER, SYSTEM, api, billing, issued, line, must, person, tool, tools
from brick_ar.application.use_cases import AR
def test_every_use_case_is_a_route_and_a_tool_except_the_process_view():
names = tools(person("all@x", ["*:*:*"]))
expected = sorted(uc.name for uc in AR.use_cases if uc.tool)
assert names == expected and len(expected) >= 50
def test_a_draft_is_raised_issued_and_read_the_same_way_through_both_doors(world):
billing()
s, d1 = tool(BILLER, "draft_invoice", {"bp_id": str(BP), "currency": "GBP", "lines": [line()]})
assert s == "ok" and d1["total"] == "240.00" and d1["lifecycle"] == "draft"
s, gates = tool(BILLER, "invoice_readiness", {"invoice_id": d1["invoice_id"]})
assert s == "ok" and gates["ready"] is True and {"gate", "met", "reason", "fix"} == set(gates["gates"][0])
s, issued_ = tool(BILLER, "issue_invoice", {"invoice_id": d1["invoice_id"]})
assert s == "ok" and issued_["invoice_no"] == "INV-2026-0001"
via_api = must(api("GET", f"/invoices/{d1['invoice_id']}", BILLER))
s, via_tool = tool(BILLER, "get_invoice", {"invoice_id": d1["invoice_id"]})
assert s == "ok" and json.loads(json.dumps(via_api)) == via_tool
s, why = tool(BILLER, "edit_draft", {"invoice_id": d1["invoice_id"], "customer_po_ref": "PO-1"})
assert s == "refused" and "credit it instead" in why
def test_a_source_asks_through_the_machine_tool_and_asking_twice_returns_the_same_invoice(world):
billing()
args = {"source_kind": "sales_order", "source_id": "so:SO-1:1", "bp_id": str(BP), "currency": "GBP",
"lines": [line(sales_order_id="SO-1", so_line_no=1)]}
s, a = tool(SYSTEM, "raise_draft", args)
s2, b = tool(SYSTEM, "raise_draft", args)
assert (s, s2) == ("ok", "ok") and a["version"] == b["version"] and a["invoice_id"] == "so:SO-1:1"
s, why = tool(BILLER, "raise_draft", args) # a machine permission: refused to a person
assert s == "refused"
def test_a_money_amount_leaves_as_an_exact_string_and_an_id_as_a_string(world):
inv = issued(world)
out = must(api("GET", f"/invoices/{inv['invoice_id']}", BILLER))
assert out["total"] == "240.00" and out["bp_id"] == str(BP) and isinstance(out["lines"][0]["unit_price"], str)
s, body = tool(BILLER, "get_invoice", {"invoice_id": inv["invoice_id"]})
assert body["bp_id"] == str(BP) and body["subtotal"] == "200.00"
def test_the_process_is_served_as_bpmn():
s, body = api("GET", "/process/bpmn", OWNER)
assert s == 200 and "bpmn" in json.dumps(body).lower() and "Task_issue" in json.dumps(body)
def test_a_command_that_makes_something_new_takes_an_idempotency_key(world):
billing()
body = {"bp_id": str(BP), "currency": "GBP", "lines": [line()]}
h = {**BILLER, "Idempotency-Key": "k-1"}
a = must(api("POST", "/invoices", h, body))
b = must(api("POST", "/invoices", h, body))
assert a["invoice_id"] == b["invoice_id"] and len(must(api("GET", "/invoices", BILLER))["invoices"]) == 1