diff --git a/lib/services/pax8-sync-service.ts b/lib/services/pax8-sync-service.ts index a8ea89d..89bd71d 100644 --- a/lib/services/pax8-sync-service.ts +++ b/lib/services/pax8-sync-service.ts @@ -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 { + 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 {