feat(12-04): wire syncOrders + syncCompanyMatches into fullSync

- syncCompanyMatches() delegates to matchPax8Companies() (Plan 03),
  shaping its result into the standard Pax8EntitySyncResult
- fullSync() now pushes ordersResult then matchResult after products,
  so pax8_companies is fully populated before matching runs
- Both steps roll up into the existing success/status/totals reducer
  and sync_history record unchanged
This commit is contained in:
lorentz 2026-07-10 22:52:30 -04:00
parent a06c1d314b
commit 5f960601e3

View file

@ -12,6 +12,7 @@
import postgresClient from './postgres-client';
import { Pax8Client } from './pax8-client';
import { getPax8Client } from './pax8-factory';
import { matchPax8Companies } from './pax8-company-matcher';
import type {
Pax8Company,
Pax8Subscription,
@ -94,6 +95,14 @@ export class Pax8SyncService {
const productsResult = await this.syncProducts(referencedProductIds);
entities.push(productsResult);
const ordersResult = await this.syncOrders();
entities.push(ordersResult);
// Matching runs after companies + orders so pax8_companies is fully
// populated first (PAX8-10, PAX8-11).
const matchResult = await this.syncCompanyMatches();
entities.push(matchResult);
const completedAt = new Date();
const success = entities.every(e => e.success);
const status: 'completed' | 'failed' = success ? 'completed' : 'failed';
@ -500,6 +509,41 @@ export class Pax8SyncService {
}
}
/**
* PAX8 <-> Autotask company fuzzy-name matching (PAX8-10, PAX8-11).
* Delegates entirely to matchPax8Companies() (Plan 03) this wrapper just
* shapes the result into the standard Pax8EntitySyncResult so it rolls up
* into fullSync()'s totals and sync_history the same way every other
* entity step does.
*/
private async syncCompanyMatches(): Promise<Pax8EntitySyncResult> {
const start = Date.now();
try {
const result = await matchPax8Companies();
return {
entity: 'company_matches',
success: true,
upserted: result.autoLinked,
// Repurposed: not a soft-delete tombstone count — the number of
// pax8_companies rows flagged for manual review this run (ambiguous
// + no-candidate), surfaced through the same rollup field.
tombstoned: result.flaggedAmbiguous + result.flaggedNoCandidate,
durationMs: result.durationMs,
};
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
console.error(`[Pax8Sync] Company match failed:`, msg);
return {
entity: 'company_matches',
success: false,
upserted: 0,
tombstoned: 0,
durationMs: Date.now() - start,
error: msg,
};
}
}
// ─── Helpers ────────────────────────────────────────────────────────────
private async insertHistoryStarted(triggeredBy: string, startedAt: Date): Promise<void> {