Skip to content

Conversation

@kdenney
Copy link
Contributor

@kdenney kdenney commented Jan 16, 2026

🎟️ Tracking

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

📔 Objective

Implements a new endpoint to preview the prorated cost when upgrading from a Premium individual subscription to an Organization plan. Also refactors billing preview endpoints by renaming TaxController to PreviewInvoiceController.

Notable Changes:

Controller Refactoring

  • Renamed TaxController to PreviewInvoiceController
  • Updated route prefix from /billing/tax/* to /billing/preview-invoice/*
  • Affects 4 existing endpoints:
    • POST /billing/preview-invoice/organizations/subscriptions/purchase
    • POST /billing/preview-invoice/organizations/{organizationId}/subscription/plan-change
    • PUT /billing/preview-invoice/organizations/{organizationId}/subscription/update
    • POST /billing/preview-invoice/premium/subscriptions/purchase

New Endpoint

  • POST /billing/preview-invoice/premium/subscriptions/upgrade
  • Returns proration amounts:
    • Tax
    • Total
    • Credit: Proration credit from unused Premium time

Updated Upgrade Endpoint

  • POST /account/billing/vnext/upgrade
  • Now accepts ProductTierType and minimal billing address in the request dto to be consistent with the preview endpoint

Commands

  • PreviewPremiumUpgradeProrationCommand: New; Calculates proration preview
  • UpgradePremiumToOrganizationCommand: Modified to set a trial based on the product chosen, per business rules

Breaking Changes

  • Route changes for all billing preview endpoints require frontend coordination (ticket here)

⏰ Reminders before review

  • Contributor guidelines followed
  • All formatters and local linters executed and passed
  • Written new unit and / or integration tests where applicable
  • Protected functional changes with optionality (feature flags)
  • Used internationalization (i18n) for all UI strings
  • CI builds passed
  • Communicated to DevOps any deployment requirements
  • Updated any necessary documentation (Confluence, contributing docs) or informed the documentation team

🦮 Reviewer guidelines

  • 👍 (:+1:) or similar for great changes
  • 📝 (:memo:) or ℹ️ (:information_source:) for notes or general info
  • ❓ (:question:) for questions
  • 🤔 (:thinking:) or 💭 (:thought_balloon:) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion
  • 🎨 (:art:) for suggestions / improvements
  • ❌ (:x:) or ⚠️ (:warning:) for more significant problems or concerns needing attention
  • 🌱 (:seedling:) or ♻️ (:recycle:) for future improvements or indications of technical debt
  • ⛏ (:pick:) for minor or nitpick changes

@kdenney kdenney added the ai-review Request a Claude code review label Jan 16, 2026
@claude
Copy link
Contributor

claude bot commented Jan 16, 2026

Claude finished @kdenney's task in 1m 48s —— View job


Code Review: PM-29599 Create Proration Preview Endpoint

Summary

This PR implements a new endpoint (POST /billing/preview-invoice/premium/subscriptions/upgrade) to preview proration costs when upgrading from a Premium individual subscription to an Organization plan. The PR also refactors billing preview endpoints by renaming TaxController to PreviewInvoiceController with updated routes.


Review Status: Approved

This PR is well-implemented with comprehensive test coverage and follows established billing patterns in the codebase.


Strengths

  1. Solid command implementation: PreviewPremiumUpgradeProrationCommand follows the established BaseBillingCommand pattern with proper error handling via BillingCommandResult<T>.

  2. Excellent test coverage: Both the new preview command (567 lines) and updated upgrade command (826 lines) have thorough test coverage including:

    • User validation (non-premium, null/empty subscription ID)
    • Proration credit extraction from negative Stripe line items
    • Seat-based vs non-seat-based plan handling
    • Storage item deletion
    • Trial period handling
    • Billing address updates
    • Metadata preservation for subscription history
  3. Consistent API design: Both the preview and upgrade request DTOs use the same TargetProductTierType approach with identical validation logic.

  4. Proper authorization: Endpoints use [Authorize("Application")] with [InjectUser] to securely identify the authenticated user.

  5. Previous feedback addressed: The error message inconsistency mentioned in the earlier review has been fixed - both commands now consistently return "Premium subscription password manager item not found." when the subscription item cannot be located.


Breaking Changes (Documented)

The PR description correctly documents these breaking changes with a frontend coordination ticket (PM-29600):

Change Impact
Route prefix changed from /billing/tax/* to /billing/preview-invoice/* 4 existing endpoints affected
UpgradePremiumToOrganizationRequest now requires BillingAddress Upgrade endpoint requires additional field
Tier renamed to TargetProductTierType, Cadence removed Request body schema changed
Proration behavior changed from None to CreateProrations Billing behavior change for upgrades

Minor Observations (Non-blocking)

  1. Code duplication: The PlanType getter logic is identical between PreviewPremiumUpgradeProrationRequest and UpgradePremiumToOrganizationRequest. This could be extracted to a shared utility, but is acceptable as-is for two usages.

  2. Test gap: The preview command tests cover null for GatewaySubscriptionId but not empty string (the upgrade command tests both). The code handles both cases correctly via the pattern match not null and not "", so this is a minor test coverage gap only.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 16, 2026

Logo
Checkmarx One – Scan Summary & Detailsfba594f4-a8be-4900-a84b-a43700ae6813

Fixed Issues (3)

Great job! The following issues were fixed in this Pull Request

Severity Issue Source File / Package
MEDIUM CSRF /src/Api/Billing/Controllers/VNext/AccountBillingVNextController.cs: 122
MEDIUM CSRF /src/Api/Billing/Controllers/VNext/AccountBillingVNextController.cs: 80
MEDIUM CSRF /src/Api/Billing/Controllers/VNext/AccountBillingVNextController.cs: 69

@codecov
Copy link

codecov bot commented Jan 16, 2026

Codecov Report

❌ Patch coverage is 84.56790% with 25 lines in your changes missing coverage. Please review.
✅ Project coverage is 56.09%. Comparing base (ebb0712) to head (9eaa6a3).
⚠️ Report is 8 commits behind head on main.

Files with missing lines Patch % Lines
...pi/Billing/Controllers/PreviewInvoiceController.cs 0.00% 15 Missing ⚠️
...ewInvoice/PreviewPremiumUpgradeProrationRequest.cs 81.25% 2 Missing and 1 partial ⚠️
.../Commands/PreviewPremiumUpgradeProrationCommand.cs 96.84% 2 Missing and 1 partial ⚠️
...Controllers/VNext/AccountBillingVNextController.cs 0.00% 2 Missing ⚠️
...sts/Premium/UpgradePremiumToOrganizationRequest.cs 85.71% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6858      +/-   ##
==========================================
- Coverage   59.90%   56.09%   -3.82%     
==========================================
  Files        1966     1968       +2     
  Lines       86883    86997     +114     
  Branches     7741     7739       -2     
==========================================
- Hits        52046    48797    -3249     
- Misses      32954    36397    +3443     
+ Partials     1883     1803      -80     

☔ View full report in Codecov by Sentry.
📢 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.

also using the correct proration behavior and making the upgrade flow start a trial
@kdenney kdenney marked this pull request as ready for review January 21, 2026 23:34
@kdenney kdenney requested a review from a team as a code owner January 21, 2026 23:34
Copy link
Collaborator

@sbrown-livefront sbrown-livefront left a comment

Choose a reason for hiding this comment

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

Clean ✅. Thanks for the in depth tests and the additions to the upgrade logic and parameters. 🦸‍♂️

planType,
billingAddress);

return Handle(result.Map(pair => new { pair.Tax, pair.Total, pair.Credit }));
Copy link
Collaborator

Choose a reason for hiding this comment

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

⚠️ I just took a look back at the figma design while building out the workflow, and I see we may need the amount of prorated months from this response also. For reference: https://www.figma.com/design/nuFrzHsgEoEk2Sm8fWOGuS/Premium---business-upgrade-flows?node-id=3053-118405&m=dev

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.

3 participants