"""Change C2 (Gitea issue 24): a Q.C. reject always needs a detailed reason, and a packet rejected without an NCR number cannot be accepted until the NCR number is given with the accept (QC_ACCEPT and QC_ACCEPT_AND_ROUTE). The packet read says `ncr_required`; can() does not block on it (the NCR comes with the step); the server refuses the step without it, 422 ncr_required. The accept stores the NCR on its inspection and in the log.""" from __future__ import annotations from collections.abc import Iterator import pytest from fakedir import FakeDirectory from pkthelpers import step from pshelpers import needs_pg from qchelpers import NCR, accept, at_qc, finish_inspection, reject, to_qc from shophelpers import SIGN, Shop, fresh, last_log, ok, one, open_shop, refused from packetstation.settings import Settings pytestmark = needs_pg REASON = "Weld 2 undercut too deep" MSG = "Enter the NCR number of the reject first." @pytest.fixture def shop(pg_settings: Settings, fake_dir: FakeDirectory, dev_visual: None) -> Iterator[Shop]: yield from open_shop(pg_settings, fake_dir) def test_accept_after_a_reject_without_ncr_needs_one(shop: Shop) -> None: pkt = at_qc(shop) assert pkt["ncr_required"] is False out = ok(reject(shop, pkt, REASON)) assert out["ncr_required"] is True and out["qc_last"]["ncr"] is None pkt = finish_inspection(shop, to_qc(shop, fresh(shop("sup.wes"), pkt["id"]))) assert pkt["ncr_required"] is True # can() does not block on it: the NCR is input with the step assert {"qc_accept", "qc_accept_and_route"} <= set(pkt["can"]) and "qc_accept" not in pkt["blocked"] refused(accept(shop, pkt), 422, "ncr_required", MSG) refused(step(shop("qc.quinn"), pkt, "qc_accept_and_route", dept="09", sign=SIGN), 422, "ncr_required", MSG) refused(step(shop("qc.quinn"), pkt, "qc_accept", routed_to="databook", ncr=" ", sign=SIGN), 422, "ncr_required") refused( step(shop("qc.quinn"), pkt, "qc_accept", routed_to="databook", ncr="NCR-26-1", sign=SIGN), 422, "invalid_ncr" ) assert fresh(shop("qc.quinn"), pkt["id"])["status"] == "qc" out = ok(step(shop("qc.quinn"), pkt, "qc_accept", routed_to="databook", ncr=" ncr-2026-0021 ", sign=SIGN)) assert out["status"] == "complete" and out["ncr_required"] is False assert out["qc_last"]["result"] == "accepted" and out["qc_last"]["ncr"] == NCR row = one( shop.settings, "SELECT ncr, result FROM qc_inspections WHERE packet_id = %s ORDER BY id DESC LIMIT 1", (pkt["id"],), ) assert tuple(row) == (NCR, "accepted") log = last_log(shop("qc.quinn"), pkt["id"]) assert log["action"] == "Q.C. accepted → Clerical – Data Book" assert log["note"] == f"Quinn QC [Q1] · 2 welds VT accepted · {NCR}", log def test_accept_and_route_carries_the_ncr(shop: Shop) -> None: pkt = at_qc(shop) ok(reject(shop, pkt, REASON)) pkt = finish_inspection(shop, to_qc(shop, fresh(shop("sup.wes"), pkt["id"]))) out = ok(step(shop("qc.quinn"), pkt, "qc_accept_and_route", dept="09", ncr=NCR, sign=SIGN)) assert out["status"] == "ready" and out["ncr_required"] is False and out["qc_last"]["ncr"] == NCR log = last_log(shop("qc.quinn"), pkt["id"]) assert log["note"] == f"Quinn QC [Q1] · from 03 Weld Parts · {NCR}", log def test_a_reject_with_its_ncr_needs_none_at_accept(shop: Shop) -> None: pkt = at_qc(shop) out = ok(reject(shop, pkt, REASON, ncr=NCR)) assert out["ncr_required"] is False and out["return_note"] == f"{NCR} · {REASON}" pkt = finish_inspection(shop, to_qc(shop, fresh(shop("sup.wes"), pkt["id"]))) out = ok(accept(shop, pkt)) assert out["status"] == "complete" and out["qc_last"]["ncr"] is None