feat(OUT-4005): reconcile payouts via webhook + resync [3/4] - #275
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Greptile SummaryThis PR wires payout reconciliation into webhook handling and failed-record resync.
Confidence Score: 5/5The PR appears safe to merge, with no concrete changed-code defect identified. The payout webhook and resync paths preserve stored deposit identifiers, use database-backed claims to prevent concurrent reconciliation, and exercise the principal recovery and idempotency cases in integration tests. Important Files Changed
Sequence DiagramsequenceDiagram
participant Stripe as Payout webhook
participant Webhook as WebhookService
participant DB as Sync tables
participant Payout as PayoutService
participant QBO as QuickBooks
participant Resync as SyncService
Stripe->>Webhook: payout settled
Webhook->>DB: Upsert payout context
Webhook->>DB: Claim webhook event
alt Claim acquired
Webhook->>Payout: Reconcile payout
Payout->>QBO: Create or locate deposit
Payout->>DB: Save deposit ID
Webhook->>DB: Mark log SUCCESS
else Reconciliation fails
Webhook->>DB: Mark log FAILED and retryable
Resync->>DB: Claim FAILED to PENDING
Resync->>Payout: Reconcile with idempotency check
Payout->>QBO: Locate or create deposit
Resync->>DB: Mark log SUCCESS or FAILED
end
Reviews (1): Last reviewed commit: "feat(OUT-4005): reconcile payouts into b..." | Re-trigger Greptile |
SandipBajracharya
force-pushed
the
OUT-4005-split-3
branch
from
July 31, 2026 10:35
38979a4 to
5987f9c
Compare
SandipBajracharya
force-pushed
the
OUT-4005-split-3
branch
from
July 31, 2026 11:40
5987f9c to
65f07cc
Compare
priosshrsth
approved these changes
Aug 3, 2026
priosshrsth
left a comment
Collaborator
There was a problem hiding this comment.
lgtm except for minor nitpick
Comment on lines
+239
to
+259
| await db.insert(QBPayoutSync).values({ | ||
| portalId: TEST_PORTAL_ID, | ||
| payoutId: opts.payoutId, | ||
| lineItems: opts.lineItems, | ||
| netAmount: opts.netAmount, | ||
| feeAmount: opts.feeCents, | ||
| arrivalDate: opts.arrivalDate, | ||
| qbDepositId: opts.qbDepositId ?? null, | ||
| }) | ||
| await db.insert(QBSyncLog).values({ | ||
| portalId: TEST_PORTAL_ID, | ||
| entityType: EntityType.PAYOUT, | ||
| eventType: EventType.SETTLED, | ||
| status: LogStatus.FAILED, | ||
| copilotId: opts.payoutId, | ||
| // Cents-as-string, matching what the webhook writes for a payout log. | ||
| amount: opts.netAmount.toFixed(2), | ||
| feeAmount: opts.feeCents.toFixed(2), | ||
| errorMessage: opts.errorMessage ?? 'QuickBooks timed out', | ||
| shouldRetry: true, | ||
| }) |
Collaborator
There was a problem hiding this comment.
Minor nitpick. But this can happen in parallel right?
…nd resync Webhook delegates to PayoutService (saving the payout row before claiming). Resync claims the row FAILED->PENDING before work so overlapping runs can't double-deposit, and skips the absorbed-fee expense for batched invoices. Routes token-exchange resync through afterIfAvailable to keep next/server out of the service graph. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
SandipBajracharya
force-pushed
the
OUT-4005-split-3
branch
from
August 3, 2026 08:32
65f07cc to
535bab7
Compare
…ledPayout The qb_payout_sync and qb_sync_logs inserts are independent (no FK), so run them together with Promise.all instead of sequentially. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
SandipBajracharya
merged commit Aug 3, 2026
f1bf9d1
into
feature/payout-reconciliation
4 checks passed
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.
Stack 3/4 — base:
OUT-4005-split-2Webhook delegates payout handling to
PayoutService(saving the payout row before claiming). Resync claims the rowFAILED→PENDINGbefore work so overlapping runs can't double-deposit, and skips the absorbed-fee expense for batched invoices. Routes token-exchange resync throughafterIfAvailableto keepnext/serverout of the service graph. Includes the payout integration + resync tests.Part of the OUT-4005 payout-reconciliation stack:
🤖 Generated with Claude Code