Build Seth's changes C1 to C11 (Gitea issues 1, 8, 18, 23, 24, 25, 27, 31, 32, 33, 36)
- C1 (issue 1): over target follows VISUAL ticket hours, not the timer. - C2 (issue 24): a Q.C. reject always needs a reason; accept needs an NCR number after a reject without one. - C3 (issue 25): an incomplete unit ITP blocks filing. - C4 (issue 27): prints open the print dialog on the page, no new tab. - C5 (issue 31): filing is blocked while VISUAL shows a work order open; the feed sets vclosed on VISUAL packets. - C6 (issue 8): the data book leaves out the history pages. - C7 (issue 18): the supervisor approves each received short; accept and filing wait for it. - C8 (issue 23): per-department checklists, edited by the department supervisor or Admin, frozen at START. - C9 (issue 32): Q.C. and Clerical may run the stamp check. - C10 (issue 33): the PM screen and reports are for PS-ProjectMgmt and Admin only. - C11 (issue 36): the Stall screen lists the packets assigned to the welder, at the supervisor's stall. Migration 0011. Docs: PLAN (also issue 9 confirmed, issue 4 asked), POLICY, SECURITY, SCHEMA, FEED, README, CHANGELOG. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
"""Change C5 (Gitea issue 31): filing is blocked, not warned, while VISUAL still shows a work order open, on both
|
||||
routes. On a VISUAL packet the feed is the one writer of `vclosed`: it sets it when it sees every work order closed
|
||||
(the Clerical board then shows the packet under "Ready for data book") and clears it when one shows open again.
|
||||
|
||||
The feed's observe step runs here on legs written by SQL. Nothing here reads VISUAL or M-Files."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Iterator, Mapping
|
||||
from datetime import date
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
from closehelpers import at_complete, file_packet, leg, q1, set_feed_legs
|
||||
from fakedir import FakeDirectory
|
||||
from pshelpers import app_conn, needs_pg
|
||||
from shophelpers import Shop, find_log, fresh, ok, open_shop, refused
|
||||
|
||||
from packetstation.feed import apply
|
||||
from packetstation.feed.types import WoKey
|
||||
from packetstation.settings import Settings
|
||||
|
||||
pytestmark = needs_pg
|
||||
|
||||
W1 = WoKey("L670001", "001", "0", "0")
|
||||
W2 = WoKey("L670002", "001", "0", "0")
|
||||
OPEN_W2 = "VISUAL still shows work orders open on this packet: L670002/001. Filing waits until VISUAL closes them."
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def shop(pg_settings: Settings, fake_dir: FakeDirectory, dev_visual: None) -> Iterator[Shop]:
|
||||
yield from open_shop(pg_settings, fake_dir)
|
||||
|
||||
|
||||
def observe(settings: Settings, seen: Mapping[WoKey, str]) -> dict[str, Any]:
|
||||
"""The feed's observe step for the given leg statuses. Returns the run's counts."""
|
||||
with app_conn(settings) as conn:
|
||||
run = apply._Run(conn, None, None, None, date.today())
|
||||
apply._observe(run, seen, None)
|
||||
return dict(run.counts)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("route", ["databook", "shipping"])
|
||||
def test_feed_closes_and_opens_a_visual_packet(shop: Shop, route: str) -> None:
|
||||
pkt = at_complete(shop, route=route)
|
||||
pid = pkt["id"]
|
||||
set_feed_legs(shop.settings, pid, [leg("L670001", st="R"), leg("L670002", st="R")])
|
||||
c = shop("clerk.clara")
|
||||
|
||||
# one leg closed: still open in VISUAL, nothing set
|
||||
counts = observe(shop.settings, {W1: "C", W2: "R"})
|
||||
assert counts["closed_observed"] == 0 and counts["errors"] == 0, counts
|
||||
view = fresh(c, pid)
|
||||
assert view["vclosed"] is None and view["blocked"]["file"] == [OPEN_W2]
|
||||
|
||||
# every leg closed: the feed sets vclosed (no person) and the file opens
|
||||
counts = observe(shop.settings, {W1: "C", W2: "C"})
|
||||
assert counts["closed_observed"] == 1 and counts["errors"] == 0, counts
|
||||
view = fresh(c, pid)
|
||||
assert view["vclosed"]["at"] is not None and view["vclosed"]["by"] is None
|
||||
assert view["vclose_check"]["closed_at"] is not None and view["vclose_check"]["agrees"] is True
|
||||
assert "file" in view["can"]
|
||||
assert find_log(c, pid, "Closed in VISUAL (observed)")
|
||||
assert observe(shop.settings, {W1: "C", W2: "C"})["closed_observed"] == 0 # nothing changed: no write
|
||||
|
||||
# a leg open again: the feed clears it and the file waits
|
||||
observe(shop.settings, {W1: "C", W2: "R"})
|
||||
view = fresh(c, pid)
|
||||
assert view["vclosed"] is None and view["vclose_check"]["closed_at"] is None
|
||||
assert view["blocked"]["file"] == [OPEN_W2]
|
||||
assert find_log(c, pid, "Open again in VISUAL (observed)")["note"] == "L670002/001"
|
||||
refused(file_packet(shop, view), 403, "precondition", OPEN_W2)
|
||||
|
||||
# closed and cancelled count as done
|
||||
assert observe(shop.settings, {W1: "C", W2: "X"})["closed_observed"] == 1
|
||||
out = ok(file_packet(shop, fresh(c, pid)))
|
||||
assert out["status"] == "filed" and out["vclosed"]["by"] is None
|
||||
# the feed leaves a filed packet alone
|
||||
observe(shop.settings, {W1: "R", W2: "R"})
|
||||
assert q1(shop.settings, "SELECT vclosed_at IS NOT NULL FROM packets WHERE id = %s", (pid,))[0] is True
|
||||
Reference in New Issue
Block a user