dodil/erp-brick-purchasing

DODIL ERP brick: purchasing

tests/test_v7.py

"""Spec v7 (PUR-65, seam-gap PR 2): sales-order cancels a request it raised."""
from conftest import ALICE, APPROVER, BUYER, INVENTORY, SUPPLIER_A, as_role, api, must, world

SO_CLIENT = as_role("sales_order_client", "sales-order@shop.example")
LINE = {"product_id": "COLA-075", "quantity": "40", "unit_code": "PK24", "sales_order_id": "SO-7", "so_line_no": 1}


def from_so(ref="so:SO-7:1@r1"):
    return api("POST", "/purchase-requests/from-sales-order", SO_CLIENT, {"request_ref": ref, **LINE})


def test_pur65_sales_order_cancels_its_request_which_leaves_the_queue_and_a_repeat_answers_the_same():
    world()
    r = must(from_so())
    rid = r["request_id"]
    assert r == {"request_ref": "so:SO-7:1@r1", "request_id": rid, "status": "awaiting_approval"} and must(from_so()) == r   # PUR-65's shape: no _status
    out = must(api("POST", f"/purchase-requests/{rid}/cancel", SO_CLIENT, {"reason": "the customer cancelled the line"}))
    assert out == {"request_id": rid, "status": "cancelled"}
    assert must(api("POST", f"/purchase-requests/{rid}/cancel", SO_CLIENT, {"reason": "again"})) == {"request_id": rid, "status": "cancelled"}
    got = must(api("GET", f"/purchase-requests/{rid}", ALICE))
    assert got["status"] == "cancelled" and got["closed_reason"] == "the customer cancelled the line"
    assert rid not in [x["purchase_request_id"] for x in must(api("GET", "/purchase-requests?status=awaiting_approval", ALICE))["requests"]]
    s, b = api("POST", f"/purchase-requests/{rid}/approve", APPROVER, {})
    assert s == 409 and "cancelled" in b["detail"]                                     # nothing more can come of it


def test_pur65_a_request_sales_order_did_not_raise_is_403_and_a_request_needs_a_reason():
    world()
    body = {"request_ref": "inv:repl:WH1:COLA-075:2026-11-03", "warehouse_id": "WH1", "location_id": "WH1/IN", "product_id": "COLA-075", "quantity": "40",
            "unit_code": "PK24"}
    rid = must(api("POST", "/purchase-requests/from-replenishment", INVENTORY, body))["request_id"]
    assert api("POST", f"/purchase-requests/{rid}/cancel", SO_CLIENT, {"reason": "x"})[0] == 403
    assert api("POST", f"/purchase-requests/{rid}/cancel", BUYER, {"reason": "x"})[0] == 403
    mine = must(from_so("so:SO-7:2@r1"))["request_id"]
    assert api("POST", f"/purchase-requests/{mine}/cancel", SO_CLIENT, {"reason": "  "})[0] in (409, 422)
    assert api("POST", "/purchase-requests/NOPE/cancel", SO_CLIENT, {"reason": "x"})[0] == 404


def test_pur65_once_ordered_the_refusal_names_the_order_and_the_supplier_and_cancels_nothing():
    world()
    rid = must(from_so("so:SO-7:3@r1"))["request_id"]
    must(api("POST", f"/purchase-requests/{rid}/approve", APPROVER, {}))
    order = must(api("POST", f"/purchase-requests/{rid}/raise-order", BUYER, {"bp_id": SUPPLIER_A, "lines": [
        {"product_id": "COLA-075", "quantity": "40", "unit_code": "PK24", "unit_price": "10.0000"}]}))
    s, b = api("POST", f"/purchase-requests/{rid}/cancel", SO_CLIENT, {"reason": "late"})
    assert s == 422 and b["gate"] == "not_cancellable" and str(SUPPLIER_A) in b["reason"] and "order" in b["reason"] and b["fix"]
    assert must(api("GET", f"/purchase-requests/{rid}", ALICE))["status"] == "ordered" and order["purchase_order_id"]