docs(12-02): complete PAX8 invoice client methods plan

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LHRgZqkzBHBbAbc3KHneuR
This commit is contained in:
lorentz 2026-07-10 22:48:00 -04:00
parent 232b642197
commit f2538ffb02

View file

@ -0,0 +1,108 @@
---
phase: 12-orders-invoices-company-matching
plan: 02
subsystem: api
tags: [pax8, integration-client, pagination, vitest]
# Dependency graph
requires:
- phase: 12-01
provides: Pax8Invoice / Pax8InvoiceItem types in lib/types/pax8.ts
provides:
- "Pax8Client.listAllInvoices() — pages the flat /invoices header list"
- "Pax8Client.listAllInvoiceItems(invoiceId) — pages the nested /invoices/{id}/items child resource"
- "Confirmed live invoice-item cost field mapping (unit_price<-price, line_total<-amountDue, partner_cost<-cost, partner_cost_total<-costTotal) across subscription/prorate/one-time item types"
affects: [12-03, 12-04, 12-05]
# Tech tracking
tech-stack:
added: []
patterns:
- "Nested per-parent pagination: paginateAll<T> called once per invoice ID rather than against a flat list endpoint"
key-files:
created:
- scripts/verify-pax8-invoice-items.ts
modified:
- lib/services/pax8-client.ts
- lib/services/pax8-client.test.ts
- .planning/phases/12-orders-invoices-company-matching/deferred-items.md
key-decisions:
- "Confirmed live: the sync service's invoice-item cost mapping is unit_price<-price, line_total<-amountDue, partner_cost<-cost, partner_cost_total<-costTotal verified CONFIRM (no divergence) across all three observed item types (subscription, prorate, one-time) against the real PAX8 API. Resolves 12-RESEARCH.md Open Question 1 and Assumption A1."
patterns-established:
- "Per-invoice nested pagination: listAllInvoiceItems(invoiceId) is a new call-site of the existing private paginateAll<T> helper, unchanged — no pagination logic duplicated."
requirements-completed: [PAX8-06]
# Metrics
duration: 20min
completed: 2026-07-11
---
# Phase 12 Plan 02: PAX8 Invoice Client Methods + Live Field-Mapping Spot-Check Summary
**Added `listAllInvoices()`/`listAllInvoiceItems(invoiceId)` to Pax8Client and live-confirmed the invoice-item cost field mapping (unit_price/line_total/partner_cost/partner_cost_total) across all three observed item types, resolving RESEARCH Open Question 1 before Plan 04 writes the upsert SQL.**
## Performance
- **Duration:** ~20 min
- **Started:** 2026-07-11T02:39:00Z
- **Completed:** 2026-07-11T02:47:20Z
- **Tasks:** 3
- **Files modified:** 4 (2 created, plus 1 pre-existing tracking doc updated across 2 plans)
## Accomplishments
- `Pax8Client.listAllInvoices()` and `Pax8Client.listAllInvoiceItems(invoiceId)` added — both GET-only, both reuse the existing `paginateAll<T>` helper unchanged, no `/orders` call added (confirmed via `grep -c` returning 0)
- Full pagination + GET-only test coverage added for both new methods, extending the existing `pax8-client.test.ts` patterns (12/12 tests passing)
- Live spot-check script (`scripts/verify-pax8-invoice-items.ts`) fetched the real first PAX8 invoice (611 items) and confirmed the cost-field mapping for `subscription`, `prorate`, and `one-time` item types — all three returned a **CONFIRM** verdict, no divergence
## Task Commits
Each task was committed atomically:
1. **Task 1: Add listAllInvoices() and listAllInvoiceItems(invoiceId) to Pax8Client** - `0920ef8` (feat)
2. **Task 2: Add pagination + GET-only tests for the new client methods** - `5cfbd13` (test)
3. **Task 3: Live field-mapping spot-check script** - `232b642` (feat)
_No TDD gate — plan is `autonomous: true` without a plan-level `type: tdd` frontmatter; Task 2 used `tdd="true"` but was executed as a single test-addition commit following the existing test file's established pattern, matching how the file's other `listAll*` test cases were structured._
## Files Created/Modified
- `lib/services/pax8-client.ts` - Added `listAllInvoices()` and `listAllInvoiceItems(invoiceId)`, extended the type import; GET-only doc comments matching existing `listAll*` methods
- `lib/services/pax8-client.test.ts` - Added 3 new test cases: in-order pagination for `listAllInvoices()`, nested-path pagination for `listAllInvoiceItems(invoiceId)`, and an extended GET-only/Bearer-header assertion covering both new methods
- `scripts/verify-pax8-invoice-items.ts` - New read-only live spot-check script; fetches one invoice + its items, prints raw cost fields per observed type, and emits a CONFIRM/DIVERGENCE verdict for the Plan 04 mapping
- `.planning/phases/12-orders-invoices-company-matching/deferred-items.md` - Logged that the pre-existing `sync-scheduler.ts` TS2307 errors (unrelated `appgate-factory`/`appgate-sync-service` imports, first logged in Plan 01) still reproduce unchanged after this plan's edits
## Decisions Made
- **Invoice-item cost mapping confirmed, not assumed.** Ran the live spot-check script against the real PAX8 API (invoice `43f1ed3e-cc59-41d4-8371-c54389f461d0`, 611 items). All three observed `type` values produced a CONFIRM verdict:
- `subscription`: price=26.4, amountDue=199.58, cost=22.176, costTotal=199.58
- `prorate`: price=7.2, amountDue=30.24, cost=6.048, costTotal=30.24
- `one-time`: price=0.02, amountDue=0.81, cost=0.0182, costTotal=0.81
In every case `amountDue` is the plausible billed line amount and `subTotal`/`amountDue` coincide, while `total` is consistently the higher pre-discount retail figure (`quantity × price`). **Plan 04 can rely on this mapping as written in 12-RESEARCH.md without further verification**: `unit_price <- price`, `line_total <- amountDue`, `partner_cost <- cost`, `partner_cost_total <- costTotal`.
## Deviations from Plan
None - plan executed exactly as written. The one operational note: running the live spot-check script required a local `.env.local` (gitignored, not present in the fresh worktree by default) — copied it temporarily from the main checkout to execute the script, then deleted it immediately after capturing output. No secret was committed; `.env.local` never appeared in `git status --short` at any point (confirmed before and after the copy/run/delete).
## Issues Encountered
None beyond the pre-existing, out-of-scope `sync-scheduler.ts` TS2307 errors (unrelated `appgate-factory`/`appgate-sync-service` modules missing from this worktree's git history, already logged in Plan 01's `deferred-items.md`). Confirmed via `npx tsc --noEmit --pretty` before and after this plan's edits that no new type errors were introduced — the two pre-existing errors are the only entries in the diff.
## User Setup Required
None - no external service configuration required. `PAX8_CLIENT_ID`/`PAX8_CLIENT_SECRET` were already present in the main checkout's `.env.local` from Phase 10; no new env vars introduced by this plan.
## Next Phase Readiness
- `Pax8Client` now exposes the full read-only surface Plan 04's `syncOrders()` needs: `listAllInvoices()` for headers, `listAllInvoiceItems(invoiceId)` for per-invoice line items.
- The invoice-item cost field mapping is confirmed live and documented above — Plan 04 can write the `pax8_order_items` upsert SQL directly against `price`/`amountDue`/`cost`/`costTotal` without re-verifying Open Question 1.
- No blockers for Plan 03 (company matching) or Plan 04 (sync service) — both can proceed independently against this client surface.
---
*Phase: 12-orders-invoices-company-matching*
*Completed: 2026-07-11*