From 111ef56e450a406e8e42a849f0d1540c7af56399 Mon Sep 17 00:00:00 2001 From: lorentz Date: Fri, 10 Jul 2026 22:40:03 -0400 Subject: [PATCH] feat(12-01): add migration 093 for pax8 orders + company matching schema - Enable pg_trgm extension for fuzzy company-name matching - Add per-company id, billing period, and dual-cost columns to pax8_order_items - Add auto-match columns (autotask_company_id, match_confidence, match_method, matched_at) to pax8_companies - Applied to dev DB and verified idempotent --- .../093_pax8_orders_company_matching.sql | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 migrations/093_pax8_orders_company_matching.sql diff --git a/migrations/093_pax8_orders_company_matching.sql b/migrations/093_pax8_orders_company_matching.sql new file mode 100644 index 0000000..b94a2b4 --- /dev/null +++ b/migrations/093_pax8_orders_company_matching.sql @@ -0,0 +1,64 @@ +-- PAX8 orders/invoices + company matching — schema foundation (Phase 12). +-- +-- Enables pg_trgm (fuzzy-name company matching, PAX8-10/PAX8-11) and closes +-- two schema gaps discovered by live PAX8 verification (12-RESEARCH.md): +-- +-- 1. Invoice headers (pax8_orders) carry no per-customer data — PAX8's +-- /invoices response always returns companyId=NULL on the header; the +-- real per-company + billing-period cost data lives on each invoice +-- item instead (12-RESEARCH.md Pitfall 1). pax8_order_items therefore +-- needs its own company/period/cost columns. pax8_orders.pax8_company_id +-- will intentionally stay NULL for every real synced row — this is +-- expected PAX8 API behavior, not a sync bug. +-- 2. pax8_companies has nowhere to persist a confident auto-match against +-- an Autotask company (PAX8-10/PAX8-11). +-- +-- Additive-only: every new column and index below is guarded (IF NOT EXISTS). +-- Does not edit migration 091 and does not touch pax8_orders or +-- pax8_company_match_review, which are already correctly shaped. + +-- --------------------------------------------------------------------------- +-- 1. pg_trgm — trigram similarity for fuzzy company-name matching +-- --------------------------------------------------------------------------- + +CREATE EXTENSION IF NOT EXISTS pg_trgm; + +-- --------------------------------------------------------------------------- +-- 2. pax8_order_items — per-company id, billing period, dual-cost columns +-- --------------------------------------------------------------------------- +-- pax8_company_id / subscription_id are soft refs (plain indexed columns, no +-- hard FK) matching the pax8_subscriptions.pax8_company_id convention — sync +-- insert order across items/companies/subscriptions is not guaranteed within +-- a single pass. item_type has no CHECK constraint (free-form, matching +-- pax8_subscriptions.status) since the full set of PAX8 invoice item types +-- ('subscription' | 'prorate' | 'one-time' and possibly others) isn't fully +-- enumerated yet. + +ALTER TABLE pax8_order_items ADD COLUMN IF NOT EXISTS pax8_company_id UUID; -- soft ref -> pax8_companies(id) +ALTER TABLE pax8_order_items ADD COLUMN IF NOT EXISTS subscription_id UUID; -- soft ref -> pax8_subscriptions(id) +ALTER TABLE pax8_order_items ADD COLUMN IF NOT EXISTS item_type TEXT; +ALTER TABLE pax8_order_items ADD COLUMN IF NOT EXISTS sku TEXT; +ALTER TABLE pax8_order_items ADD COLUMN IF NOT EXISTS description TEXT; +ALTER TABLE pax8_order_items ADD COLUMN IF NOT EXISTS start_period TIMESTAMPTZ; +ALTER TABLE pax8_order_items ADD COLUMN IF NOT EXISTS end_period TIMESTAMPTZ; +ALTER TABLE pax8_order_items ADD COLUMN IF NOT EXISTS partner_cost NUMERIC(12,2); +ALTER TABLE pax8_order_items ADD COLUMN IF NOT EXISTS partner_cost_total NUMERIC(12,2); + +CREATE INDEX IF NOT EXISTS idx_pax8_order_items_company ON pax8_order_items(pax8_company_id); +CREATE INDEX IF NOT EXISTS idx_pax8_order_items_period ON pax8_order_items(start_period, end_period); + +-- --------------------------------------------------------------------------- +-- 3. pax8_companies — auto-match columns +-- --------------------------------------------------------------------------- +-- autotask_company_id is a soft ref (no hard FK) matching the soft-ref +-- convention used elsewhere in this schema. match_confidence stores the raw +-- pg_trgm similarity score (0.000-1.000); match_method distinguishes an +-- automated pg_trgm match from a manual admin resolution recorded via +-- pax8_company_match_review. + +ALTER TABLE pax8_companies ADD COLUMN IF NOT EXISTS autotask_company_id BIGINT; -- soft ref -> companies(id) +ALTER TABLE pax8_companies ADD COLUMN IF NOT EXISTS match_confidence NUMERIC(4,3); +ALTER TABLE pax8_companies ADD COLUMN IF NOT EXISTS match_method TEXT; -- 'pg_trgm' | 'manual' +ALTER TABLE pax8_companies ADD COLUMN IF NOT EXISTS matched_at TIMESTAMPTZ; + +CREATE INDEX IF NOT EXISTS idx_pax8_companies_autotask ON pax8_companies(autotask_company_id);