fix: preserve terminal staged candidates

This commit is contained in:
DEls 2026-09-19 12:20:30 +02:00
parent 66bf2a0876
commit 05eaa1fa3e
2 changed files with 39 additions and 2 deletions

View file

@ -348,4 +348,39 @@ describe("runStagedBatch", () => {
expect(fixture.candidates.get("old-b")).toEqual(expect.objectContaining({ pages: [9], delivery_note_number: "dn 1", stage: "needs_review" }));
expect(fixture.candidates.size).toBe(3);
});
it("does not rewrite an unmatched legacy promoted candidate", async () => {
const fixture = stagedPb();
fixture.candidates.set("promoted", {
id: "promoted", batch: BATCH_ID, candidate_key: "promoted-key", note_index: 7, pages: [99],
delivery_note_number: "DN-HISTORIC", doc_number: "DN-HISTORIC", status: "promoted",
});
normaliseSourceMock.mockResolvedValue([{ sourcePage: 1, png: Buffer.from("one"), mime: "image/png", width: 100, height: 200, rotation: 0 }]);
extractPageMock.mockResolvedValue(read(1, "DN-CURRENT", "PO-1"));
await runStagedBatch(fixture.pb as never, BATCH_ID);
expect(fixture.candidates.get("promoted")).toEqual(expect.objectContaining({
status: "promoted", note_index: 7,
}));
expect(fixture.candidates.get("promoted")).not.toHaveProperty("stage");
});
it("does not rewrite an unmatched candidate already related to a delivery note", async () => {
const fixture = stagedPb();
fixture.candidates.set("posted-relation", {
id: "posted-relation", batch: BATCH_ID, candidate_key: "posted-relation-key", note_index: 8, pages: [98],
delivery_note_number: "DN-POSTED", doc_number: "DN-POSTED", delivery_note: "delivery-note-1",
});
normaliseSourceMock.mockResolvedValue([{ sourcePage: 1, png: Buffer.from("one"), mime: "image/png", width: 100, height: 200, rotation: 0 }]);
extractPageMock.mockResolvedValue(read(1, "DN-CURRENT", "PO-1"));
await runStagedBatch(fixture.pb as never, BATCH_ID);
expect(fixture.candidates.get("posted-relation")).toEqual(expect.objectContaining({
delivery_note: "delivery-note-1", note_index: 8,
}));
expect(fixture.candidates.get("posted-relation")).not.toHaveProperty("status");
expect(fixture.candidates.get("posted-relation")).not.toHaveProperty("stage");
});
});

View file

@ -34,6 +34,7 @@ type ExistingCandidate = {
pages?: unknown;
delivery_note_number?: string;
doc_number?: string;
delivery_note?: string;
status?: string;
stage?: string;
posted_at?: string;
@ -271,7 +272,7 @@ async function upsertCandidate(
async function loadCandidates(pb: PocketBase, batchId: string): Promise<ExistingCandidate[]> {
const records = (await pb.collection("dn_batch_notes").getFullList({
filter: batchFilter(pb, batchId),
fields: "id,candidate_key,note_index,pages,delivery_note_number,doc_number,status,stage,posted_at",
fields: "id,candidate_key,note_index,pages,delivery_note_number,doc_number,delivery_note,status,stage,posted_at",
})) as unknown as ExistingCandidate[];
return records;
}
@ -332,7 +333,8 @@ function legacyNumberCompatible(candidate: ExistingCandidate, documentNumber: st
}
function isTerminalCandidate(candidate: ExistingCandidate): boolean {
return candidate.status === "dismissed" || candidate.stage === "dismissed" || candidate.stage === "posted" || Boolean(candidate.posted_at);
return candidate.status === "dismissed" || candidate.status === "promoted" || candidate.status === "posted" ||
candidate.stage === "dismissed" || candidate.stage === "posted" || Boolean(candidate.posted_at) || Boolean(candidate.delivery_note);
}
async function markSurplusCandidatesForReview(