[PM-38830] fix: Surface fixed-amount and time-bounded discounts in billing API#7814
Conversation
🤖 Bitwarden Claude Code ReviewOverall Assessment: APPROVE Reviewed the server-side billing contract changes that surface fixed-amount ( Code Review DetailsNo findings. The change is well-scoped, additive, and thoroughly tested:
The earlier suggestion to reuse |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7814 +/- ##
==========================================
+ Coverage 61.26% 61.28% +0.02%
==========================================
Files 2194 2194
Lines 97313 97325 +12
Branches 8768 8769 +1
==========================================
+ Hits 59615 59646 +31
+ Misses 35584 35565 -19
Partials 2114 2114 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…lling API Fixed-amount (Stripe amount_off) churn coupons and repeating/time-bounded discounts are billed correctly but were never rendered in the billing UI because the server contracts dropped the underlying values. Add AmountOff to the churn offer result (Stripe minor units converted to dollars) and End/DurationInMonths to both the domain and API customer-discount models so clients can format and apply them. The existing Active flag keeps its perpetual-only meaning and is intentionally left unchanged.
3ee5444 to
41bdf1d
Compare
…rn-coupons-are-not-displayed
…rn-coupons-are-not-displayed
|



🎟️ Tracking
https://bitwarden.atlassian.net/browse/PM-38830
📔 Objective
Fixed-amount (Stripe
amount_off) churn-mitigation coupons — andrepeating/ time-bounded discounts — are billed correctly in Stripe but were never rendered in the Web Vault billing UI, because the server's billing contracts dropped the underlying values. This PR adds the missing data so the clients can format and display them. It is the server-side portion; a companion client PR consumes the new fields.Churn offer (
amount_off)AmountOff(decimal?, USD dollars) toChurnMitigationOfferResultand map it from StripeCoupon.AmountOff(minor units → dollars via/ 100M) inGetChurnMitigationOfferQuery.nullfor percentage coupons.Customer discount (time-bounded)
End(DateTime?) andDurationInMonths(long?) to both the domainSubscriptionInfo.BillingCustomerDiscountand the APIBillingCustomerDiscountresponse model, populated in both theDiscountandCouponconstructors. These let the subscription page apply/showrepeatingdiscounts (e.g. the 10% × 12-month monthly-plan churn case) instead of suppressing them.All new fields are additive and nullable — safe for the V±2 client matrix. The existing
Activeflag is intentionally left unchanged (it keeps its "perpetual / no end date" meaning; other consumers such assm-subscribe.component.tsstill depend on it). No feature-flag, DI, or migration changes. Unit tests cover the cents→dollars conversion, amount + duration coexistence, and an explicitActive-unchanged regression guard.