dodil/erp-brick-purchasing

DODIL ERP brick: purchasing

tests/test_stories_readside.py

"""The read side other bricks use (expected receipts, open bills, receiving locations) and release levels (PUR-38)."""
from conftest import (
    ALICE,
    APPROVER,
    APPROVER2,
    BUYER,
    CLERK,
    INVENTORY,
    OWNER,
    RECEIVER,
    SUPPLIER_A,
    api,
    bill,
    confirmed,
    draft,
    must,
    receive,
    set_limit,
    supplier_price,
    world,
)


def test_expected_receipts_are_derived_from_confirmed_lines_less_receipts_and_need_the_expected_permission():
    world()
    supplier_price()
    o = confirmed(lines=[{"product_id": "COLA-075", "quantity": "10"}])
    got = must(api("GET", "/expected-receipts", INVENTORY, {"product_id": "COLA-075"}))
    assert len(got) == 1 and str(got[0]["quantity_base_outstanding"]).startswith("240")
    receive(o, quantity="4")
    assert str(must(api("GET", "/expected-receipts", INVENTORY, {}))[0]["quantity_base_outstanding"]).startswith("144")
    one = must(api("GET", f"/purchase-orders/{o['purchase_order_id']}/expected", INVENTORY))
    assert str(one["lines"][0]["outstanding"]).startswith("6") and str(one["lines"][0]["received"]).startswith("4")
    assert api("GET", "/expected-receipts", CLERK, {})[0] == 403


def test_open_bills_are_the_approved_bills_less_allocations_as_of_a_date():
    world()
    supplier_price()
    o = confirmed(lines=[{"product_id": "COLA-075", "quantity": "10"}])
    receive(o)
    s, b = bill(o)
    assert must(api("GET", "/bills/open", ALICE, {"as_of": "2026-11-20"}))["items"] == []                         # a bill nobody approved is not open
    must(api("POST", f"/bills/{b['bill_id']}/approve", as_approver(), {}))
    items = must(api("GET", "/bills/open", ALICE, {"as_of": "2026-11-20"}))["items"]
    assert len(items) == 1 and items[0]["bp_id"] == str(SUPPLIER_A) and str(items[0]["outstanding"]) == "216.00"


def as_approver():
    from conftest import PAYAPPROVER
    return PAYAPPROVER


def test_receiving_locations_come_from_inventory_for_a_receiver(neighbours):
    got = must(api("GET", "/receiving-locations", RECEIVER, {}))
    assert got and api("GET", "/receiving-locations", CLERK, {})[0] == 403


def test_pur38_two_release_levels_need_two_different_approvers_and_the_final_limit_to_cover():
    world(threshold="0", limits=False)
    set_limit("approver@shop.example", "5000", start="2026-11-20")
    set_limit("approver2@shop.example", "500000", start="2026-11-20")
    must(api("POST", "/release-strategies", OWNER, {"levels": 2, "level_thresholds": ["1000", "50000"], "min_amount": "0", "valid_from": "2026-11-20"}))
    supplier_price(product="LAPTOP", unit="C62", price="900.0000")
    o = draft(lines=[{"product_id": "LAPTOP", "quantity": "10"}])
    oid = o["purchase_order_id"]
    must(api("POST", f"/purchase-orders/{oid}/submit", BUYER, {}))
    s, b = api("POST", f"/purchase-orders/{oid}/approve", APPROVER2, {})                       # the final level before level 1
    assert s == 409
    lvl = must(api("POST", f"/purchase-orders/{oid}/approve-level", APPROVER, {}))
    assert lvl["status"] == "to_approve" and "level 2 of 2" in str(lvl["waiting"])
    s, b = api("POST", f"/purchase-orders/{oid}/approve", APPROVER, {})                        # the same person cannot give the second level
    assert s == 409 and "second_person" in str(b)
    done = must(api("POST", f"/purchase-orders/{oid}/approve", APPROVER2, {}))
    assert done["status"] == "approved" and done["approved_levels"] == 2
    assert api("POST", f"/purchase-orders/{oid}/confirm", BUYER, {})[0] == 200