drawings: on a rev mismatch, Clerical can keep the retired rev VISUAL calls (#41)
ci / server (pull_request) Failing after 17s
ci / frontend (pull_request) Successful in 42s
ci / image (pull_request) Skipped
ci / e2e (pull_request) Skipped

When VISUAL calls a rev that M-Files has retired, the draft is still
flagged rev_mismatch, but the drawing job now also copies the rev VISUAL
calls (MFilesKit 0.1.3 DrawingLookup.revision) into drawing_revisions and
visual.called. A Clerical Supervisor picks either rev on the packet:
"Use latest rev N" as before, or "Use rev V as VISUAL calls it"
(rev-approve with use=called), with a reason and a signature.

The kept rev holds while M-Files' Effective rev stays the one chosen
against: no flag, no change order. A newer Effective rev flags the
packet again; a new VISUAL rev clears the choice.

Migration 0009 adds drawing_revisions. Needs mfileskit 0.1.3.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-19 13:39:14 -06:00
co-authored by Claude Opus 5.5
parent 4c0cba4da5
commit bb8eb17748
21 changed files with 547 additions and 55 deletions
+2 -1
View File
@@ -68,7 +68,8 @@ export const packetsApi = {
databook: (id: number) => api.post<PacketRead>(`${base(id)}/databook`, {}),
/* Phase 3: VISUAL packets. */
revApprove: (id: number, body: { reason: string } & Guarded) => api.post<PacketRead>(`${base(id)}/rev-approve`, body),
revApprove: (id: number, body: { reason: string; use?: "latest" | "called" } & Guarded) =>
api.post<PacketRead>(`${base(id)}/rev-approve`, body),
handDrawing: (id: number, body: { asset_id: string; reason: string } & Guarded) =>
api.post<PacketRead>(`${base(id)}/hand/drawing`, body),
/** Multipart cannot carry JSON, so the signature rides as sign_factor and sign_secret. */
+25 -2
View File
@@ -905,16 +905,39 @@ export interface FoldedOp {
tgt?: number | string;
}
/** The rev VISUAL calls, as M-Files holds it at another status (Retired, say). Set by the drawing job on a draft flagged
* rev_mismatch. `missing` when M-Files has no document at that rev. */
export interface CalledRev {
rev: string;
missing?: boolean;
controlled?: string;
state?: string | null;
name?: string | null;
asset_id?: string;
pages?: number;
}
/** The packet's `visual` jsonb. Every key is optional; hand drafts have {}. */
export interface VisualInfo {
appr?: VisualAppr;
/** Set by the read model from drawing_lookups when M-Files has a staged copy. */
staged_rev?: { rev: number | string; name: string | null };
staged_rev?: { rev: number | string; name: string | null; asset_id?: string };
called?: CalledRev | null;
partspecs?: string[];
folded?: FoldedOp[];
manual_dwg?: HandUpload;
manual_bom?: HandUpload;
rev_ok?: { rev: string | number; vis_rev?: string | null; by?: WhoRef | string | null; at?: string | null; reason?: string | null };
rev_ok?: {
rev: string | number;
vis_rev?: string | null;
by?: WhoRef | string | null;
at?: string | null;
reason?: string | null;
/** "called": Clerical kept the rev VISUAL calls over M-Files' Effective rev (`latest`). */
use?: "latest" | "called";
latest?: string | null;
controlled?: string | null;
};
rev_confirmed?: boolean;
[key: string]: unknown;
}