dodil/erp-brick-inventory

DODIL ERP brick: inventory

tests/test_returns.py

"""Customer returns against an RMA: INV-14 (receive at the cost they left at, inspect every unit, tell sales-order once)."""
from decimal import Decimal

import fakes
import world
from conftest import MANAGER, OPERATOR, SYSTEM, api, must, refused
from test_deliveries import BOTTLES, stocked

RMA = {"rma_ref": "so:RE-2026-0001", "bp_id": 7311, "warehouse_id": "WH1", "lines": [
    {"line_no": 1, "product_id": "COLA-075", "unit_code": "C62", "quantity": "6", "original_delivery_ref": "WH1/OUT/00001", "inspect": True}]}


def delivered_and_authorised():
    stocked(pallets="2", order_qty="24")
    must(api("POST", "/locations", MANAGER, {"location_id": "WH1/QC", "kind": "internal", "stock_status": "quality"}))
    doc = must(api("POST", "/deliveries", OPERATOR, {"sales_order_id": "SO-2026-0012", "warehouse_id": "WH1"}))["document_id"]
    must(api("POST", f"/deliveries/{doc}/validate", OPERATOR, {"picks": [{"line_no": 1, "location_id": "WH1/A/01", "quantity": "24", "unit_code": "C62"}]}))
    fakes.add_order("RE-2026-0001", {1: {**BOTTLES, "quantity": "6"}})
    return must(api("POST", "/expected-returns", SYSTEM, RMA))


def receive(qty="6", **kw):
    return api("POST", "/returns", OPERATOR, {"bp_id": 7311, "warehouse_id": "WH1", "rma_ref": "so:RE-2026-0001",
                                              "lines": [{"line_no": 1, "quantity": qty, "unit_code": "C62"}], **kw})


def test_inv14_an_rma_is_idempotent_cancellable_until_something_is_received():
    delivered_and_authorised()
    again = must(api("POST", "/expected-returns", SYSTEM, RMA))
    assert again["replay"] is True and again["expected"] == [{"line_no": 1, "quantity_base": "4.5"}]
    assert api("POST", "/expected-returns", MANAGER, RMA)[0] == 403                                  # a machine grant
    assert must(api("POST", "/expected-returns/so:RE-2026-0001/cancel", SYSTEM, {}))["status"] == "cancelled"
    s, b = receive()
    assert s == 409 and b["detail"]["gate"] == "rma_open" and "no open RMA of 7311" in b["detail"]["reason"]      # a cancelled RMA lets nothing be received
    assert must(api("POST", "/expected-returns/so:RE-2026-0001/cancel", SYSTEM, {}))["status"] == "cancelled"     # a repeat answers the same
    refused(api("POST", "/expected-returns/so:NOPE/cancel", SYSTEM, {}), 422, "no RMA so:NOPE")
    fakes.add_order("RE-2026-0002", {1: {**BOTTLES, "quantity": "6"}})
    must(api("POST", "/expected-returns", SYSTEM, {**RMA, "rma_ref": "so:RE-2026-0002"}))
    must(receive(rma_ref="so:RE-2026-0002"))
    s, b = api("POST", "/expected-returns/so:RE-2026-0002/cancel", SYSTEM, {})
    assert s == 422 and b["detail"]["gate"] == "rma_received" and b["detail"]["reason"] == "so:RE-2026-0002 is partly received: it can no longer be cancelled"


def test_inv14_receive_into_quality_at_the_cost_it_left_at_then_inspect_every_unit_and_tell_the_order_once():
    delivered_and_authorised()
    # today's average differs from the delivery's cost: a second receipt at a higher price
    world.receive("COLA-075", "1", "PK24", price="36.00", location="WH1/A/02")
    got = must(receive())
    assert got["number"] == "WH1/RET/00001" and got["delivery_ref"] == "inv:WH1/RET/00001"
    (mv,) = got["moves"]
    assert (mv["from_location_id"], mv["to_location_id"], mv["quantity_base"]) == ("UK1:CUSTOMER", "WH1/QC", "4.5")
    assert mv["value_amount"] == "5.40"                                               # the cost it left at (24 bottles = 21.60), not today's average
    assert fakes.ORDERS["RE-2026-0001"]["lines"][1]["delivered"] == Decimal(6)
    assert must(api("POST", "/returns", OPERATOR, {"bp_id": 7311, "warehouse_id": "WH1", "request_id": got["document_id"].split(":")[-1], "lines": []}))["replay"] is True
    doc = got["document_id"]
    refused(api("POST", f"/returns/{doc}/inspect", OPERATOR, {"decisions": [{"line_no": 1, "decision": "restock", "quantity": "4", "unit_code": "C62"}]}),
            409, "every_unit_decided")
    done = must(api("POST", f"/returns/{doc}/inspect", OPERATOR, {"decisions": [
        {"line_no": 1, "decision": "restock", "quantity": "4", "unit_code": "C62"},
        {"line_no": 1, "decision": "scrap", "quantity": "1", "unit_code": "C62", "reason": "damaged by us"},
        {"line_no": 1, "decision": "back_to_customer", "quantity": "1", "unit_code": "C62", "reason": "damaged by the customer"}]}))
    by = {m["decision"]: m for m in done["moves"]}
    assert (by["restock"]["to_location_id"], by["restock"]["quantity_base"], by["restock"]["value_amount"]) == ("WH1/A/01", "3", "0.00")
    assert (by["scrap"]["to_location_id"], by["scrap"]["quantity_base"]) == ("UK1:LOSS", "0.75")
    assert by["back_to_customer"]["to_location_id"] == "UK1:CUSTOMER" and by["back_to_customer"]["value_amount"] == "-0.90"
    assert by["scrap"]["value_amount"] == "-0.90"                                      # the value it came in
    (insp,) = fakes.RETURN_INSPECTIONS.values()
    assert (insp["received_quantity"], insp["accepted_quantity"], insp["rejected_quantity"]) == ("6", "5", "1")
    assert insp["inspection_ref"] == "inv:WH1/RET/00001:1"
    again = must(api("POST", f"/returns/{doc}/inspect", OPERATOR, {"decisions": []}))
    assert again["replay"] is True and len(fakes.RETURN_INSPECTIONS) == 1               # once
    assert [i["reported_to_order"] for i in must(api("GET", f"/returns/{doc}", OPERATOR))["inspections"]] == [True, True, True]
    assert {j["event"] for j in fakes.JOURNALS.values()} >= {"return", "return_inspection"}


def test_inv14_a_parcel_with_no_rma_more_than_expected_or_a_serial_never_delivered_is_refused():
    delivered_and_authorised()
    body = {"bp_id": 7311, "warehouse_id": "WH1", "lines": [{"line_no": 1, "product_id": "SCREW-M4", "quantity": "1", "unit_code": "C62"}]}
    refused(api("POST", "/returns", OPERATOR, body), 409, "no open RMA of 7311 names SCREW-M4")
    refused(api("POST", "/returns", OPERATOR, {**body, "bp_id": 9999, "lines": [{**body["lines"][0], "product_id": "COLA-075"}]}), 409, "no open RMA of 9999 names COLA-075")
    refused(receive("7"), 409, "expects 4.5 LTR more, 5.25 came")
    s, got = api("POST", "/returns", OPERATOR, {"bp_id": 7311, "warehouse_id": "WH1", "rma_ref": "so:RE-2026-0001",
                                                 "lines": [{"line_no": 1, "quantity": "2", "unit_code": "C62", "serials": ["S-1", "S-2"]}]})
    assert s == 409 and got["detail"]["gate"] == "serial_was_delivered" and "never delivered to customer 7311" in got["detail"]["reason"]
    assert must(api("GET", "/stock/COLA-075", OPERATOR))["on_hand"] == "18"          # nothing was written