You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(payments): time-slice revenue split so plan changes don't reprice historical payouts (#496)
computeOwedBalances() applied one CURRENT school_percentage to the entire
all-time sum of a tenant's platform-settled transactions. Every plan change
rewrites revenue_splits, so the next payout calculation silently repriced
every historical transaction at the new percentage, not just new sales
(e.g. a school doing $10k at 0% platform fee, then auto-downgraded to free's
10% fee, would show ~$1k less owed on that already-settled $10k than agreed
at the time of sale).
Adds transactions.school_percentage_snapshot, populated at transaction
creation time (app/api/payments/checkout/route.ts — the single insert site
that matters for payout math, since Stripe/manual/binance_personal don't
settle to the platform account and mock-checkout transactions never carry a
payment_provider that matches the payout filter). computeOwedBalances now
sums amount * that transaction's own snapshotted split, falling back to the
tenant's current split only for transactions with no snapshot (pre-#496
rows) — old data isn't retroactively wrong either way.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
/** Sum over transactions of amount × (that transaction's snapshotted split, or the tenant's current split if unsnapshotted) — the school's all-time share. */
39
54
grossOwed: number
40
55
/** Sum of manual payouts already recorded as paid for this tenant. */
41
56
alreadyPaid: number
@@ -50,10 +65,17 @@ export function computeOwedBalances(
-- #496: revenue_splits.school_percentage isn't time-sliced today — the
2
+
-- payouts-owed computation applies the tenant's CURRENT split to the
3
+
-- entire all-time sum of platform-settled transactions, so any plan change
4
+
-- (which rewrites revenue_splits) silently reprices every historical
5
+
-- transaction, not just new ones.
6
+
--
7
+
-- Snapshot the split percentage in effect at the moment each transaction is
8
+
-- created (app/api/payments/checkout/route.ts), so a later plan change only
9
+
-- affects future transactions. NULL for transactions created before this
10
+
-- column existed; lib/payments/payouts-owed.ts falls back to the tenant's
11
+
-- current split for those, matching the pre-#496 behavior for old data.
12
+
13
+
ALTERTABLE transactions
14
+
ADD COLUMN school_percentage_snapshot numeric;
15
+
16
+
COMMENT ON COLUMN transactions.school_percentage_snapshot IS
17
+
'revenue_splits.school_percentage in effect for this tenant when this transaction was created. NULL for transactions predating this column (#496) — payout computation falls back to the tenant''s current split for those.';
0 commit comments