OUT-3951: integration tests for the invoice.paid webhook - #67
Merged
Conversation
…and AU Extend the webhook test harness for the invoice.paid flow: getInvoiceById and markInvoicePaid mock defaults, a paidInvoice webhook fixture, and seedSyncedPayment / seedSyncLog helpers. The happy path is parametrized over US and AU and asserts the region sales code and invoice total flow into markInvoicePaid, a synced_payments row is written, and a paid success log is recorded. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A success invoice with an existing synced_payments row short-circuits before markInvoicePaid, adds no new payment row, and writes no new paid sync log. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
When isSyncEnabled is false the controller returns 200 without invoking the handler, so no Xero call is made and no payment row is written. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…cePaid failure When markInvoicePaid throws, the flow writes a failed paid sync log and a failed_syncs row, returns 500, and leaves the invoice row untouched with no payment recorded. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…then pays When the synced row has no xeroInvoiceId, the flow re-fetches the Copilot invoice, creates it in Xero, then marks it paid: the row ends mapped and success, with a payment row and a paid success log. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… is missing When getInvoiceById returns undefined the flow throws NOT_FOUND before any payment work: no payment row, no paid sync log, but a failed_syncs row is recorded and 404 is surfaced. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
Seed a prior invoice.created success log and assert the failed paid log propagates invoiceNumber, customerName, and customerEmail via the failedSyncLogPayload spread, so a regression dropping those fields is caught. Matches the real scenario where a payment failure follows a successful create. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Collaborator
Author
|
@greptileai re-reivew the changes |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds integration tests for the
invoice.paidwebhook flow on the testcontainers harness (parent OUT-3949, follows theinvoice.createdsuite from OUT-3950). Drives the real/api/webhookroute end to end with mocked Copilot + Xero clients. Test-only — no production changes.Linear: OUT-3951
Coverage (7 tests)
happyPath(US & AU)synced_payments, writes apaidsuccess log; asserts the region sales code + invoice total flow intomarkInvoicePaididempotencysuccess+ existing payment → skipsmarkInvoicePaid, no new payment/logsyncDisabledisSyncEnabled=false→ controller 200, handler never runsxeroMarkPaidFailsmarkInvoicePaidthrows → failedsync_log+failed_syncs+ 500, invoice row untouchedmissingXeroInvoicexeroInvoiceId→ creates the Xero invoice first, then paysinvoiceNotFoundgetInvoiceById→ undefined →NOT_FOUND(404),failed_syncsrecorded, no payment/logHarness additions:
getInvoiceById/markInvoicePaidmock defaults,paidInvoicefixture,seedSyncedPayment/seedSyncLog(all additive — existing suites unaffected).Verification
invoice.paidsuite: 7/7 green; full suite 26/26pnpm lintandpnpm typecheck: cleanFollow-ups found during this work (not in this PR)
createMissingXeroInvoice(duplicate Xero contact risk on the recovery path).syncPaidInvoiceToXerobuilds its success sync log via{ ...prevSyncLog }and relies on the spread for the NOT-NULLentityType. If no priorinvoice.createdsuccess log exists, the transaction rolls back aftermarkInvoicePaidalready committed in Xero → a duplicate payment can be created on each retry. Worth a production ticket (fix: hardcodeentityType/eventTypein the success branch like the catch block does).🤖 Generated with Claude Code