Commit 0693e49
authored
* fix(billing): resolve plan via priceId map, not price.metadata.planId (#3742)
Port trawl's #1250 fix upstream: `customer.subscription.updated` was reading
`price.metadata.planId` which is empty in real Stripe webhook payloads (planId
lives on the Product, not the Price). Every paid org's plan was silently reset
to `free` on every Stripe subscription update event.
Fix:
- Add `buildPriceIdToPlanMap()` — builds `Map<priceId, planName>` from
`config.stripe.prices` at boot (monthly + annual per plan)
- Rewrite `resolvePlan()` — looks up plan via priceId map first; falls back to
`price.metadata.planId` for legacy test fixtures; final fallback `free` + warn
- Sync `cancelAt`/`cancelAtPeriodEnd` on `customer.subscription.updated` — writes
the fields added by #3741 so the UI can show pending cancellation dates
- Use priceId map in `previousPlan` detection (plan change block in updated handler)
- Strip trawl-specific `analytics.capture('subscription_changed')` calls (not ported)
Also ports `retryWithBackoff` + `isNonTransientStripeError` patterns (already
in devkit from a prior PR — kept identical to trawl).
Adds 20 unit tests covering: priceId map resolution, annual/monthly variants,
unknown priceId fallback to free, legacy metadata fallback, priority of map over
metadata, cancelAt unix→Date conversion, null cancel clear, absent field guard,
handleSubscriptionCreated race safety (E11000 idempotency), and Dashboard
subscription creation path.
Closes #3742
* docs(billing): add ERRORS.md entry for price.metadata.planId empty in Stripe webhooks
1 parent 889626a commit 0693e49
3 files changed
Lines changed: 549 additions & 5 deletions
File tree
- modules/billing
- services
- tests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
27 | 27 | | |
28 | 28 | | |
29 | 29 | | |
| 30 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
57 | 57 | | |
58 | 58 | | |
59 | 59 | | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
60 | 80 | | |
61 | 81 | | |
62 | | - | |
63 | | - | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
64 | 87 | | |
65 | 88 | | |
66 | 89 | | |
67 | 90 | | |
68 | 91 | | |
69 | | - | |
70 | | - | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
71 | 99 | | |
72 | 100 | | |
73 | 101 | | |
| |||
386 | 414 | | |
387 | 415 | | |
388 | 416 | | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
389 | 429 | | |
390 | 430 | | |
391 | 431 | | |
| |||
423 | 463 | | |
424 | 464 | | |
425 | 465 | | |
426 | | - | |
| 466 | + | |
| 467 | + | |
| 468 | + | |
427 | 469 | | |
428 | 470 | | |
429 | 471 | | |
| |||
0 commit comments