chore(scripts): one-off repair of 3 part-invoiced short pickups
Applied 2026-10-22 against live PB: 6632, MSP18104, ZA10PO26012735. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
2e55d21937
commit
7fceb47005
1 changed files with 77 additions and 0 deletions
77
scripts/2026-10-22-repair-short-splits.ts
Normal file
77
scripts/2026-10-22-repair-short-splits.ts
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/**
|
||||
* One-off repair for the short pickups that were part-invoiced before
|
||||
* Collection Confirm learned to split them (commit 2e55d21).
|
||||
*
|
||||
* Each line was invoiced for what was collected, then bounced back to
|
||||
* `ready_invoice` with the rest still owed and never re-ordered. This does
|
||||
* what the new split does, after the fact:
|
||||
* - the original is cut to the invoiced qty and closed as `invoiced`;
|
||||
* - the rest becomes a new `pending` line on the same order (New tab),
|
||||
* with the `shortCollection` marker and its original PO for Back order.
|
||||
*
|
||||
* Guarded per line: still `ready_invoice`, `qty_invoiced > 0`,
|
||||
* `qty_invoiced == qty_collected < quantity`. Dry run unless `--apply`.
|
||||
*
|
||||
* npx tsx scripts/2026-10-22-repair-short-splits.ts [--apply]
|
||||
*/
|
||||
import "./_env";
|
||||
import { getAdminPocketBase } from "../src/lib/server/pocketbase-admin";
|
||||
import { runWithAuditActor } from "../src/lib/server/audit-context";
|
||||
import { appendNote } from "../src/lib/note-feed";
|
||||
import { buildShortCollectionSplit, newRecordId } from "../src/lib/short-collection";
|
||||
|
||||
const IDS = [
|
||||
"3sipxowwqkfw9x3", // 6632 U BOLT M24(400) HDG — 549 of 770
|
||||
"4juzxtt2yj3tsyl", // MSP18104 Insertion rubber — 5 of 8
|
||||
"9gojrwwszua8sgy", // ZA10PO26012735 Welding rod 2.5mm — 3 of 42
|
||||
];
|
||||
const APPLY = process.argv.includes("--apply");
|
||||
const actor = { id: "claude-short-split-repair", name: "Claude (short-collection repair)" };
|
||||
|
||||
async function main() {
|
||||
const pb = await getAdminPocketBase();
|
||||
const at = new Date().toISOString();
|
||||
for (const id of IDS) {
|
||||
const row = (await pb.collection("order_items").getOne(id, { expand: "purchase_order" })) as Record<string, unknown> & {
|
||||
expand?: { purchase_order?: { po_number?: string } };
|
||||
};
|
||||
const quantity = Number(row.quantity);
|
||||
const collected = Number(row.qty_collected);
|
||||
const invoiced = Number(row.qty_invoiced);
|
||||
const label = `${id} ${String(row.description)} (${collected}/${quantity}, invoiced ${invoiced})`;
|
||||
if (row.item_status !== "ready_invoice" || !(invoiced > 0) || invoiced !== collected || collected >= quantity) {
|
||||
console.log(`SKIP ${label}: status ${String(row.item_status)} — no longer the stuck shape`);
|
||||
continue;
|
||||
}
|
||||
const split = buildShortCollectionSplit(row as Parameters<typeof buildShortCollectionSplit>[0], {
|
||||
remainderId: newRecordId(),
|
||||
poNumber: row.expand?.purchase_order?.po_number ?? "",
|
||||
at,
|
||||
});
|
||||
if (!split) {
|
||||
console.log(`SKIP ${label}: nothing to split`);
|
||||
continue;
|
||||
}
|
||||
const originalPatch = {
|
||||
...split.originalPatch,
|
||||
item_status: "invoiced",
|
||||
notes: appendNote(row.notes as string | null, {
|
||||
ts: at,
|
||||
actor,
|
||||
category: "quantity",
|
||||
body: `Short collection repaired: ${collected} of ${quantity} collected and invoiced on ${String(row.customer_invoice_number ?? "")}. The ${split.remainderQty} still owed moved to a new line in New on this order.`,
|
||||
}),
|
||||
};
|
||||
console.log(`${APPLY ? "APPLY" : "DRY "} ${label} → original qty ${collected} invoiced; new line ${split.remainder.id} qty ${split.remainderQty} pending (PO ${row.expand?.purchase_order?.po_number ?? "?"})`);
|
||||
if (!APPLY) continue;
|
||||
const batch = pb.createBatch();
|
||||
batch.collection("order_items").create(split.remainder);
|
||||
batch.collection("order_items").update(id, originalPatch);
|
||||
await batch.send();
|
||||
}
|
||||
}
|
||||
|
||||
runWithAuditActor({ ...actor, source: "server", ignoreRequestUser: true }, main).catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
Loading…
Reference in a new issue