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): group payouts-owed by currency instead of summing across them (#497) (#505)
transactions.currency is a real, populated currency_type enum column, but
computeOwedBalances() dropped it and summed raw amount across currencies —
a tenant with both USD and EUR PayPal sales got one meaningless combined
total. markPayoutPaid() then hardcoded currency: 'usd' on every inserted
payouts row regardless of what was actually collected.
TenantOwed.balances is now an array of per-currency CurrencyBalance entries
(grossCollected/grossOwed/alreadyPaid/netOwed/byProvider), never summed
together. The payouts page renders one table row per (tenant, currency)
pair and shows metric cards as one figure per currency (e.g. "$80.00 ·
€40.00"), and markPayoutPaid takes an explicit currency argument threaded
from the row being paid instead of assuming USD.
Live-verified locally: seeded a $100 USD PayPal sale and a €50 EUR Lemon
Squeezy sale for the same tenant, confirmed the payouts page showed two
separate rows with correct 80% splits, recorded a EUR payout, and confirmed
the inserted payouts row has currency='eur' (not 'usd') while the USD
row's owed amount was unaffected.
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
/** Successful transaction amount, major units. */
41
+
/** Successful transaction amount, major units, in `currency`. */
37
42
amount: number
43
+
/** transactions.currency (e.g. 'usd', 'eur'). */
44
+
currency: string
38
45
/** revenue_splits.school_percentage in effect when this transaction was created (0–100), or null for pre-#496 rows. */
39
46
schoolPercentageSnapshot: number|null
40
47
}
41
48
42
49
exportinterfaceManualPayoutRecord{
43
50
tenantId: string
44
51
amount: number
52
+
/** payouts.currency — the currency this payout was actually recorded in. */
53
+
currency: string
45
54
}
46
55
47
-
exportinterfaceTenantOwed{
48
-
tenantId: string
49
-
tenantName: string
50
-
schoolPercentage: number
51
-
/** Sum of platform-settled transaction amounts (100% of what was collected). */
56
+
exportinterfaceCurrencyBalance{
57
+
currency: string
58
+
/** Sum of platform-settled transaction amounts in this currency (100% of what was collected). */
52
59
grossCollected: number
53
-
/** Sum over transactions of amount × (that transaction's snapshotted split, or the tenant's current split if unsnapshotted) — the school's all-time share. */
60
+
/** Sum over this currency's transactions of amount × (that transaction's snapshotted split, or the tenant's current split if unsnapshotted). */
54
61
grossOwed: number
55
-
/** Sum of manual payouts already recorded as paid for this tenant. */
62
+
/** Sum of manual payouts already recorded as paid in this currency. */
56
63
alreadyPaid: number
57
-
/** max(grossOwed - alreadyPaid, 0) — what's currently owed. */
64
+
/** max(grossOwed - alreadyPaid, 0) — what's currently owed in this currency. */
58
65
netOwed: number
59
-
/** Per-provider breakdown of grossCollected. */
66
+
/** Per-provider breakdown of grossCollected in this currency. */
60
67
byProvider: Record<string,number>
61
68
}
62
69
70
+
exportinterfaceTenantOwed{
71
+
tenantId: string
72
+
tenantName: string
73
+
schoolPercentage: number
74
+
/** One entry per currency this tenant has platform-settled activity or payouts in. Never summed across currencies. */
0 commit comments