Skip to content

[PM-38830] fix: Surface fixed-amount and time-bounded discounts in billing API#7814

Merged
amorask-bitwarden merged 3 commits into
mainfrom
billing/PM-38830/fixed-amount-amount-off-churn-coupons-are-not-displayed
Jun 16, 2026
Merged

[PM-38830] fix: Surface fixed-amount and time-bounded discounts in billing API#7814
amorask-bitwarden merged 3 commits into
mainfrom
billing/PM-38830/fixed-amount-amount-off-churn-coupons-are-not-displayed

Conversation

@amorask-bitwarden

@amorask-bitwarden amorask-bitwarden commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

🎟️ Tracking

https://bitwarden.atlassian.net/browse/PM-38830

📔 Objective

Fixed-amount (Stripe amount_off) churn-mitigation coupons — and repeating / 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)

  • Add AmountOff (decimal?, USD dollars) to ChurnMitigationOfferResult and map it from Stripe Coupon.AmountOff (minor units → dollars via / 100M) in GetChurnMitigationOfferQuery. null for percentage coupons.

Customer discount (time-bounded)

  • Add End (DateTime?) and DurationInMonths (long?) to both the domain SubscriptionInfo.BillingCustomerDiscount and the API BillingCustomerDiscount response model, populated in both the Discount and Coupon constructors. These let the subscription page apply/show repeating discounts (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 Active flag is intentionally left unchanged (it keeps its "perpetual / no end date" meaning; other consumers such as sm-subscribe.component.ts still depend on it). No feature-flag, DI, or migration changes. Unit tests cover the cents→dollars conversion, amount + duration coexistence, and an explicit Active-unchanged regression guard.

@amorask-bitwarden amorask-bitwarden added the ai-review Request a Claude code review label Jun 15, 2026
@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

🤖 Bitwarden Claude Code Review

Overall Assessment: APPROVE

Reviewed the server-side billing contract changes that surface fixed-amount (amount_off) churn-mitigation coupons and time-bounded (repeating) discounts. The change adds AmountOff to ChurnMitigationOfferResult and End / DurationInMonths to both the domain SubscriptionInfo.BillingCustomerDiscount and the API response model. All new fields are additive and nullable, the cents→dollars conversions are correct and consistent with existing helpers, and the intentionally-unchanged Active semantics are documented and guarded by regression tests.

Code Review Details

No findings. The change is well-scoped, additive, and thoroughly tested:

  • Conversions verified: coupon.AmountOff.ToMajor() (1500 → 15.00) is functionally equivalent to the existing ConvertFromStripeMinorUnits divisor.
  • No breaking changes — new fields are nullable and safe for the V±2 client matrix; the single production construction site uses named arguments.
  • No security or zero-knowledge concerns — only Stripe billing metadata, no PII or vault data.
  • Test coverage spans cents→dollars mapping, amount/duration coexistence, and explicit Active-unchanged guards in both the domain and API layers.

The earlier suggestion to reuse CurrencyExtensions.ToMajor() was already addressed in commit 41bdf1d.

@codecov

codecov Bot commented Jun 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 61.28%. Comparing base (2f56f5d) to head (2d0b759).
⚠️ Report is 1 commits behind head on main.

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.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…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.
@amorask-bitwarden amorask-bitwarden force-pushed the billing/PM-38830/fixed-amount-amount-off-churn-coupons-are-not-displayed branch from 3ee5444 to 41bdf1d Compare June 16, 2026 13:52
@amorask-bitwarden amorask-bitwarden marked this pull request as ready for review June 16, 2026 14:11
@amorask-bitwarden amorask-bitwarden requested a review from a team as a code owner June 16, 2026 14:11
@sonarqubecloud

Copy link
Copy Markdown

@cyprain-okeke cyprain-okeke left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice Work

@amorask-bitwarden amorask-bitwarden merged commit 3c0b1ec into main Jun 16, 2026
49 of 51 checks passed
@amorask-bitwarden amorask-bitwarden deleted the billing/PM-38830/fixed-amount-amount-off-churn-coupons-are-not-displayed branch June 16, 2026 16:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-review Request a Claude code review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants