fix(payments): expand discount coupons on cached invoices and subscriptions - #21008
Open
david1alvarez wants to merge 1 commit into
Open
fix(payments): expand discount coupons on cached invoices and subscriptions#21008david1alvarez wants to merge 1 commit into
david1alvarez wants to merge 1 commit into
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes Stripe discount/coupon handling after the SDK 22 upgrade by consistently expanding discounts.source.coupon on reads/cached objects and by hardening downstream formatting/DTO code paths so unexpanded discounts don’t crash /v1/account.
Changes:
- Expand
discounts.source.couponin Stripe reads and Firestore invoice fetch/write paths (and related preview invoice calls). - Add logic to detect when discounts/coupons are not expanded and re-fetch from Stripe rather than dropping promotion details.
- Make formatter/DTO consumers resilient to unexpanded discount/coupon fields by returning null coupon fields while preserving the discount amount.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/fxa-shared/payments/stripe.ts | Adds discountsNeedExpansion and uses it to decide when cached invoices need a Stripe re-fetch with discounts.source.coupon expanded. |
| packages/fxa-shared/payments/stripe-firestore.ts | Expands discounts.source.coupon when fetching invoices to insert into Firestore. |
| packages/fxa-auth-server/lib/payments/stripe.ts | Ensures invoice/subscription discount coupon expansion and adds subscription re-fetch path when discount data is unexpanded. |
| packages/fxa-auth-server/lib/payments/stripe.spec.ts | Updates expectations for expanded fields and adds test coverage for re-fetch behavior when cached discounts/coupons are unexpanded. |
| packages/fxa-auth-server/lib/payments/stripe-formatter.ts | Makes invoice preview discount formatting tolerant of unexpanded discount/coupon fields while keeping the amount. |
| packages/fxa-auth-server/lib/payments/stripe-formatter.spec.ts | Adds tests for preserving discount amount when discount or coupon is an unexpanded id. |
| packages/fxa-auth-server/lib/payments/stripe-firestore.spec.ts | Updates invoice retrieve expectations to include discounts.source.coupon expansion. |
| libs/payments/stripe/src/lib/stripe.client.types.ts | Updates StripeDiscount typing so source.coupon is expanded or null (never an id). |
| libs/payments/stripe/src/lib/stripe.client.ts | Updates invoice retrieve/preview calls to expand discounts.source.coupon. |
| libs/payments/stripe/src/lib/stripe.client.spec.ts | Updates tests to expect discounts.source.coupon expansion and adds preview expansion coverage. |
| libs/payments/metrics-aggregator/src/lib/payments-metrics-aggregator.service.ts | Makes coupon id access nullable-safe (coupon?.id). |
| libs/payments/management/src/lib/subscriptionManagement.service.ts | Makes promotion name access nullable-safe (coupon?.name). |
| libs/payments/customer/src/lib/util/stripeInvoiceToFirstInvoicePreviewDTO.ts | Makes discount coupon duration/name access nullable-safe (coupon?.duration / coupon?.name). |
| libs/payments/customer/src/lib/subscription.manager.ts | Makes coupon id comparisons nullable-safe (coupon?.id). |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
621
to
630
| const invoice = await this.stripeFirestore.retrieveInvoice(resource); | ||
| if (!discountsNeedExpansion(invoice.discounts)) { | ||
| // @ts-ignore | ||
| return invoice; | ||
| } | ||
| // @ts-ignore | ||
| return invoice; | ||
| return this.stripe.invoices.retrieve(resource, { | ||
| expand: ['discounts.source.coupon'], | ||
| }); | ||
| } catch (err) { |
Contributor
Author
There was a problem hiding this comment.
Current plan is for this to live in a followup ticket (to be filed, pending review)
david1alvarez
force-pushed
the
PAY-3893
branch
from
August 12, 2026 14:50
be9a02a to
e97d7f5
Compare
…ptions Because: * The SDK 22 upgrade rewrote discount reads to `discounts[0].source.coupon` without requesting the expansion, so a cached invoice holding a discount id threw `Cannot read properties of undefined (reading 'coupon')` on `/v1/account`. * Expanding `discounts` does not expand the coupon under it, so reads asking only for `discounts` dropped promotion details. This commit: * Requests `discounts.source.coupon` on the reads and Firestore writes that asked only for `discounts`. * Adds discountsNeedExpansion, and re-fetches a discount that arrives as an id rather than dropping it. * Reports the discount amount with null coupon fields when a coupon is still unreadable. * Types `source.coupon` as expanded or null, never an id. Closes PAY-3893
david1alvarez
force-pushed
the
PAY-3893
branch
from
August 12, 2026 15:56
e97d7f5 to
76606e5
Compare
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.
Because:
discounts[0].source.couponwithout requesting the expansion, so a cached invoice holding a discount id threwCannot read properties of undefined (reading 'coupon')on/v1/account.discountsdoes not expand the coupon under it, so reads asking only fordiscountsdropped promotion details.This commit:
discounts.source.couponon the reads and Firestore writes that asked only fordiscounts.source.couponas expanded or null, never an id.Closes PAY-3893
Checklist
Put an
xin the boxes that apply