drawings: VISUAL's rev is the source of truth; attach it when M-Files holds it Effective or Retired
When M-Files' Effective rev differs from the rev VISUAL calls, the drawing job looks that rev up (MFilesKit DrawingLookup.revision). If M-Files has it as Effective or Retired, the job copies it into drawing_revisions and attaches it to the draft with no flag and no Clerical approval, so the draft can auto-release. Past draft, already attached or with a hand drawing: unchanged, no flag and no change order. Any other status, or no document at that rev, still flags rev_mismatch with a note saying why. Packet Station only ever attaches Effective or Retired drawings. rev_approve stays for that case only. This replaces the "Use rev V as VISUAL calls it" choice from #46: the use=called path in rev-approve and its button are removed. A packet that already kept the rev that way keeps it, since that rev is now used anyway. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
"""The drawing decision table. Pure: no database, no M-Files.
|
||||
|
||||
`decide(target, found, same_file=...)` says what the drawing job does to one packet for one lookup. Note texts are
|
||||
`decide(target, found, same_file=..., called=...)` says what the drawing job does to one packet for one lookup.
|
||||
VISUAL is the source of truth for the rev: when M-Files' Effective rev differs from the rev VISUAL calls but M-Files
|
||||
still holds that rev as Effective or Retired, the rev VISUAL calls is used, with no flag and no Clerical approval.
|
||||
The job passes `called` only for those two statuses; no drawing at any other status is ever attached. Note texts are
|
||||
the app's own (from the old revMismatch and draftLine in visual.js, "-" in place of the em-dash), never M-Files'
|
||||
note passed through, except inside the lookup_failed text.
|
||||
|
||||
@@ -9,14 +12,15 @@ Rows, in the order they are tried:
|
||||
2. past draft, a pending feed change order waits for this drawing at the released rev -> stage_for_co.
|
||||
Past draft, the pending change order already stages this drawing at the released rev -> unchanged, or
|
||||
stage_for_co again when M-Files has a different file for that rev.
|
||||
2a. M-Files' Effective rev is not the rev VISUAL calls (or there is none), no approved rev equals it, and M-Files
|
||||
holds the rev VISUAL calls as Effective or Retired (`called`) -> on a draft, attach_called (unchanged when that very
|
||||
file is attached, or a hand drawing is); past draft, unchanged. No flag. Note "Rev V is Retired in M-Files;
|
||||
VISUAL calls it (M-Files has rev N)".
|
||||
3. no released rev, a draft rev or a drafting assignment -> flag not_released with the drafting status.
|
||||
4. no released rev otherwise -> flag not_found.
|
||||
5. VISUAL rev not a number (and no approved rev equal to M-Files') -> flag bad_rev, not attached.
|
||||
6. revs differ (and no approved rev equal to M-Files') -> flag rev_mismatch. The job stages the M-Files copy
|
||||
for Clerical Supervisor approval on drafts only, and on a draft also copies the rev VISUAL calls when M-Files
|
||||
still holds it (Retired, say), so Clerical can choose either.
|
||||
Revs differ, but Clerical chose to keep the rev VISUAL calls while M-Files' Effective rev was this one ->
|
||||
unchanged (no flag, no change order). A newer Effective rev flags the packet again.
|
||||
6. revs differ (and no approved rev equal to M-Files', and M-Files has no document at the rev VISUAL calls) ->
|
||||
flag rev_mismatch. The job stages the M-Files copy for Clerical Supervisor approval on drafts only.
|
||||
7. revs match, draft with a hand drawing -> unchanged (the feed already took the hand drawing off on a rev move).
|
||||
8. revs match, draft with this very file attached at this rev -> unchanged.
|
||||
9. revs match, draft -> attach ("sheet of drawing <base>" for an H sheet).
|
||||
@@ -41,11 +45,23 @@ NOT_FOUND = "not_found"
|
||||
BAD_REV = "bad_rev"
|
||||
REV_MISMATCH = "rev_mismatch"
|
||||
ATTACH = "attach"
|
||||
ATTACH_CALLED = "attach_called"
|
||||
UNCHANGED = "unchanged"
|
||||
OPEN_CO = "open_co"
|
||||
STAGE_FOR_CO = "stage_for_co"
|
||||
|
||||
KINDS = (ATTACH, UNCHANGED, REV_MISMATCH, NOT_RELEASED, NOT_FOUND, LOOKUP_FAILED, BAD_REV, OPEN_CO, STAGE_FOR_CO)
|
||||
KINDS = (
|
||||
ATTACH,
|
||||
ATTACH_CALLED,
|
||||
UNCHANGED,
|
||||
REV_MISMATCH,
|
||||
NOT_RELEASED,
|
||||
NOT_FOUND,
|
||||
LOOKUP_FAILED,
|
||||
BAD_REV,
|
||||
OPEN_CO,
|
||||
STAGE_FOR_CO,
|
||||
)
|
||||
FLAG_KINDS = (LOOKUP_FAILED, NOT_RELEASED, NOT_FOUND, BAD_REV, REV_MISMATCH)
|
||||
|
||||
# drawing_state enum values (0003). bad_rev has no state of its own: it is a rev mismatch Clerical can approve.
|
||||
@@ -72,8 +88,15 @@ class Target:
|
||||
co_pending: bool = False
|
||||
co_staged_sha: bytes | None = None # sha256 of the file the pending CO already stages
|
||||
rejected_sha: bytes | None = None # sha256 staged on the last drawing-origin CO Clerical rejected
|
||||
# Clerical chose the rev VISUAL calls (a Retired rev) over M-Files' Effective rev; this is that Effective rev.
|
||||
kept_latest: str | None = None
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Called:
|
||||
"""The rev VISUAL calls, as M-Files holds it (Effective or Retired), with Packet Station's copy."""
|
||||
|
||||
rev: int
|
||||
controlled: str # M-Files' Controlled Status, e.g. "Retired"
|
||||
same_file: bool # this copy is the drawing attached to the packet
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -111,25 +134,33 @@ def failed_note(f: Found) -> str:
|
||||
return f"{_FAILED_PREFIX}{detail or 'no detail'}"
|
||||
|
||||
|
||||
def kept_called(t: Target, f: Found) -> bool:
|
||||
"""Clerical kept the rev VISUAL calls, and M-Files' Effective rev is still the one they chose against."""
|
||||
return f.ok and f.rev is not None and t.kept_latest is not None and str(t.kept_latest).strip() == str(f.rev)
|
||||
def uses_called(t: Target, f: Found, called: Called | None) -> bool:
|
||||
"""The rev VISUAL calls is used from M-Files at another status: it differs from M-Files' Effective rev (or there
|
||||
is none), Clerical approved no other rev, and M-Files holds it."""
|
||||
if not f.ok or called is None:
|
||||
return False
|
||||
v = _int(t.visual_rev)
|
||||
if v is None or v != called.rev or v == f.rev:
|
||||
return False
|
||||
return not (f.rev is not None and t.rev_ok is not None and str(t.rev_ok).strip() == str(f.rev))
|
||||
|
||||
|
||||
def rev_confirmed(t: Target, f: Found) -> bool:
|
||||
"""The old revConfirmed: M-Files' released rev is the rev VISUAL calls, or Clerical approved that rev, or Clerical
|
||||
kept the rev VISUAL calls over that rev."""
|
||||
def rev_confirmed(t: Target, f: Found, called: Called | None = None) -> bool:
|
||||
"""The old revConfirmed: M-Files' released rev is the rev VISUAL calls, or Clerical approved that rev, or M-Files
|
||||
holds the rev VISUAL calls at another status."""
|
||||
if uses_called(t, f, called):
|
||||
return True
|
||||
if not f.ok or f.rev is None:
|
||||
return False
|
||||
v = _int(t.visual_rev)
|
||||
if v is not None and v == f.rev:
|
||||
return True
|
||||
if kept_called(t, f):
|
||||
return True
|
||||
return t.rev_ok is not None and str(t.rev_ok).strip() == str(f.rev)
|
||||
|
||||
|
||||
def decide(t: Target, f: Found, *, same_file: bool, fetched_sha: bytes | None = None) -> Decision:
|
||||
def decide(
|
||||
t: Target, f: Found, *, same_file: bool, fetched_sha: bytes | None = None, called: Called | None = None
|
||||
) -> Decision:
|
||||
"""What to do to one packet.
|
||||
|
||||
`same_file`: the M-Files file has the sha256 of the attached drawing asset. `fetched_sha`: the sha256 of the
|
||||
@@ -163,6 +194,15 @@ def decide(t: Target, f: Found, *, same_file: bool, fetched_sha: bytes | None =
|
||||
if fetched_sha is not None and t.co_staged_sha is not None and fetched_sha != t.co_staged_sha:
|
||||
return keep(STAGE_FOR_CO, f"New file for rev {f.rev} in M-Files; staged again for the change order")
|
||||
return keep(UNCHANGED, f"Rev {f.rev} is staged on the pending change order")
|
||||
# 2a
|
||||
if called is not None and uses_called(t, f, called):
|
||||
has = f"M-Files has rev {f.rev}" if f.rev is not None else "no Effective rev in M-Files"
|
||||
note = f"Rev {called.rev} is {called.controlled} in M-Files; VISUAL calls it ({has})"
|
||||
if not draft or t.has_hand_drawing:
|
||||
return keep(UNCHANGED, note)
|
||||
if t.drawing_state == "attached" and called.same_file and t.attached_rev == str(called.rev):
|
||||
return keep(UNCHANGED, note)
|
||||
return Decision(ATTACH_CALLED, None, "attached", note)
|
||||
# 3, 4
|
||||
if f.rev is None:
|
||||
d = draft_line(f)
|
||||
@@ -173,8 +213,6 @@ def decide(t: Target, f: Found, *, same_file: bool, fetched_sha: bytes | None =
|
||||
approved = t.rev_ok is not None and str(t.rev_ok).strip() == str(f.rev)
|
||||
vrev = (t.visual_rev or "").strip()
|
||||
v = _int(vrev)
|
||||
if not approved and kept_called(t, f):
|
||||
return keep(UNCHANGED, f"Rev {vrev} kept by Clerical; M-Files has rev {f.rev}")
|
||||
if not approved:
|
||||
# 5
|
||||
if v is None:
|
||||
|
||||
Reference in New Issue
Block a user