@arcforgelabs/flow 2026.11.8 → 2026.11.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arcforgelabs/flow",
|
|
3
|
-
"version": "2026.11.
|
|
3
|
+
"version": "2026.11.9",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@arcforgelabs/flow",
|
|
9
|
-
"version": "2026.11.
|
|
9
|
+
"version": "2026.11.9",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@clerk/backend": "3.25.0",
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { and, asc, eq, gt, gte, inArray, isNull, like, lt, or, sql } from 'drizzle-orm';
|
|
1
|
+
import { and, asc, desc, eq, gt, gte, inArray, isNotNull, isNull, like, lt, or, sql } from 'drizzle-orm';
|
|
2
2
|
import {
|
|
3
3
|
clientListSignature,
|
|
4
4
|
invoiceListSignature,
|
|
@@ -492,6 +492,61 @@ async function readHighWater(db, laneStates, sync, nowMs) {
|
|
|
492
492
|
|
|
493
493
|
// The sweep lane's run. `helpers` come from lanes.js: readOrder (issue #12
|
|
494
494
|
// for each order read), isLaneLevel, describeReadFailure, emptyResponse and
|
|
495
|
+
// Orders whose invoice Flow's copy does not hold. The invoice lane reads
|
|
496
|
+
// invoices changed since its first run, so an invoice last changed before
|
|
497
|
+
// that was never read, and its job took the order's products alone: no
|
|
498
|
+
// Shipping/Handling or Rush, which are service lines on the invoice. Seazona
|
|
499
|
+
// gives an order's invoice the order's own id. The sweep reads it and keeps it
|
|
500
|
+
// when its number is the order's; the feed then gives the job the invoice's
|
|
501
|
+
// lines and totals. An order Seazona answers 404 for, or with another number,
|
|
502
|
+
// is noted (`no_invoice`) and not asked again.
|
|
503
|
+
export const ORDER_INVOICE_KIND = 'no_invoice';
|
|
504
|
+
async function readOrderInvoices(ctx, helpers, found) {
|
|
505
|
+
const { db, client, sync, at } = ctx;
|
|
506
|
+
const rows = await db.select({ id: seazonaOrders.id, invoiceNumber: seazonaOrders.invoiceNumber })
|
|
507
|
+
.from(seazonaOrders)
|
|
508
|
+
.leftJoin(seazonaInvoices, eq(seazonaInvoices.invoiceNumber, seazonaOrders.invoiceNumber))
|
|
509
|
+
.leftJoin(seazonaSweepFindings, and(
|
|
510
|
+
eq(seazonaSweepFindings.resource, 'orders'),
|
|
511
|
+
eq(seazonaSweepFindings.recordKey, seazonaOrders.id),
|
|
512
|
+
eq(seazonaSweepFindings.kind, ORDER_INVOICE_KIND),
|
|
513
|
+
))
|
|
514
|
+
.where(and(
|
|
515
|
+
isNull(seazonaOrders.deletedInSourceAt),
|
|
516
|
+
isNotNull(seazonaOrders.invoiceNumber),
|
|
517
|
+
isNull(seazonaInvoices.invoiceNumber),
|
|
518
|
+
isNull(seazonaSweepFindings.recordKey),
|
|
519
|
+
))
|
|
520
|
+
.orderBy(desc(seazonaOrders.lastChangedAt), seazonaOrders.id)
|
|
521
|
+
.limit(CONFIRM_BATCH);
|
|
522
|
+
for (const row of rows) {
|
|
523
|
+
if (!client.hasCall()) throw new SweepBudgetSpent();
|
|
524
|
+
let detail;
|
|
525
|
+
try {
|
|
526
|
+
detail = await client.get(`invoices/${encodeURIComponent(row.id)}`);
|
|
527
|
+
} catch (error) {
|
|
528
|
+
if (error instanceof SweepBudgetSpent || helpers.isLaneLevel(error)) throw error;
|
|
529
|
+
if (error?.statusCode === 404) {
|
|
530
|
+
await recordFinding(db, 'orders', row.id, ORDER_INVOICE_KIND, { at, detail: { status: 404 } });
|
|
531
|
+
continue;
|
|
532
|
+
}
|
|
533
|
+
// Any other failure: try again on a later run.
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
const invoice = detail && typeof detail === 'object' && !Array.isArray(detail)
|
|
537
|
+
? mapInvoice({}, detail, { keepPatientReference: sync.keepPatientReference }) : null;
|
|
538
|
+
if (!invoice || invoice.invoiceNumber !== row.invoiceNumber) {
|
|
539
|
+
await recordFinding(db, 'orders', row.id, ORDER_INVOICE_KIND, { at, detail: { otherNumber: Boolean(invoice?.invoiceNumber) } });
|
|
540
|
+
continue;
|
|
541
|
+
}
|
|
542
|
+
const summary = await upsertRecords(db, 'invoices', [invoice], { at });
|
|
543
|
+
if (summary.created) {
|
|
544
|
+
found.created += 1;
|
|
545
|
+
await recordFinding(db, 'invoices', invoice.invoiceNumber, 'created', { at, detail: { lastModified: invoice.lastModifiedText } });
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
495
550
|
// LaneError.
|
|
496
551
|
export async function runSweep(ctx, helpers) {
|
|
497
552
|
const { db, sync, at, state } = ctx;
|
|
@@ -506,6 +561,7 @@ export async function runSweep(ctx, helpers) {
|
|
|
506
561
|
const save = () => ({ ...cursor, budget: { day: today, calls: spentToday + budget.spent } });
|
|
507
562
|
|
|
508
563
|
try {
|
|
564
|
+
await readOrderInvoices(sweepCtx, helpers, found);
|
|
509
565
|
for (const kind of SWEEP_KINDS) {
|
|
510
566
|
if (budget.left <= 0) break;
|
|
511
567
|
if (!isDue(cursor[kind], at, sync, kind)) continue;
|
|
@@ -557,7 +613,7 @@ export async function readSweepHealth(db, settings, { now = Date.now } = {}) {
|
|
|
557
613
|
.groupBy(seazonaSweepFindings.resource, seazonaSweepFindings.kind);
|
|
558
614
|
const foundLastWeek = {};
|
|
559
615
|
for (const row of counts) {
|
|
560
|
-
if (row.kind === 'missing') continue;
|
|
616
|
+
if (row.kind === 'missing' || row.kind === ORDER_INVOICE_KIND) continue;
|
|
561
617
|
foundLastWeek[row.resource] = { ...foundLastWeek[row.resource], [row.kind]: row.records };
|
|
562
618
|
}
|
|
563
619
|
const missingRows = await db.select({ resource: seazonaSweepFindings.resource, key: seazonaSweepFindings.recordKey })
|