From efefe4744b275abce5ac60cfca5c53620b5b5b9c Mon Sep 17 00:00:00 2001 From: Alex Morask Date: Thu, 2 Apr 2026 09:09:32 -0500 Subject: [PATCH] fix(billing): scope schedule discount to seats item instead of cart --- .../Queries/GetBitwardenSubscriptionQuery.cs | 8 ++++--- .../GetBitwardenSubscriptionQueryTests.cs | 22 ++++++++++++------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/Core/Billing/Subscriptions/Queries/GetBitwardenSubscriptionQuery.cs b/src/Core/Billing/Subscriptions/Queries/GetBitwardenSubscriptionQuery.cs index 28192b668070..485b9c04a17b 100644 --- a/src/Core/Billing/Subscriptions/Queries/GetBitwardenSubscriptionQuery.cs +++ b/src/Core/Billing/Subscriptions/Queries/GetBitwardenSubscriptionQuery.cs @@ -109,7 +109,9 @@ private async Task GetPremiumCartAsync( var (cartLevelDiscount, productLevelDiscounts) = GetStripeDiscounts(subscription); - var cartDiscount = cartLevelDiscount ?? await GetSchedulePhase2DiscountAsync(subscription); + var scheduleDiscount = cartLevelDiscount == null + ? await GetSchedulePhase2DiscountAsync(subscription) + : null; var availablePlan = plans.First(plan => plan.Available); var onCurrentPricing = passwordManagerSeatsItem.Price.Id == availablePlan.Seat.StripePriceId; @@ -133,7 +135,7 @@ private async Task GetPremiumCartAsync( TranslationKey = "premiumMembership", Quantity = passwordManagerSeatsItem.Quantity, Cost = seatCost, - Discount = productLevelDiscounts.FirstOrDefault(discount => discount.AppliesTo(passwordManagerSeatsItem)) + Discount = productLevelDiscounts.FirstOrDefault(discount => discount.AppliesTo(passwordManagerSeatsItem)) ?? scheduleDiscount }; var additionalStorage = additionalStorageItem != null @@ -154,7 +156,7 @@ private async Task GetPremiumCartAsync( AdditionalStorage = additionalStorage }, Cadence = PlanCadenceType.Annually, - Discount = cartDiscount, + Discount = cartLevelDiscount, EstimatedTax = estimatedTax }; } diff --git a/test/Core.Test/Billing/Subscriptions/Queries/GetBitwardenSubscriptionQueryTests.cs b/test/Core.Test/Billing/Subscriptions/Queries/GetBitwardenSubscriptionQueryTests.cs index 7f35cbfdbe51..d7242aca6087 100644 --- a/test/Core.Test/Billing/Subscriptions/Queries/GetBitwardenSubscriptionQueryTests.cs +++ b/test/Core.Test/Billing/Subscriptions/Queries/GetBitwardenSubscriptionQueryTests.cs @@ -581,7 +581,7 @@ public async Task Run_UserOnCurrentPricing_ReturnsCostFromSubscriptionItem() } [Fact] - public async Task Run_WithSchedulePhase2Discount_IncludesDiscountInCart() + public async Task Run_WithSchedulePhase2Discount_IncludesDiscountOnSeats() { var user = CreateUser(); var subscription = CreateSubscription(SubscriptionStatus.Active); @@ -600,9 +600,10 @@ public async Task Run_WithSchedulePhase2Discount_IncludesDiscountInCart() var result = await _query.Run(user); Assert.NotNull(result); - Assert.NotNull(result.Cart.Discount); - Assert.Equal(BitwardenDiscountType.PercentOff, result.Cart.Discount.Type); - Assert.Equal(30, result.Cart.Discount.Value); + Assert.Null(result.Cart.Discount); + Assert.NotNull(result.Cart.PasswordManager.Seats.Discount); + Assert.Equal(BitwardenDiscountType.PercentOff, result.Cart.PasswordManager.Seats.Discount.Type); + Assert.Equal(30, result.Cart.PasswordManager.Seats.Discount.Value); } [Fact] @@ -650,6 +651,7 @@ public async Task Run_WithScheduleButNoPhase2Discount_ReturnsNoDiscount() Assert.NotNull(result); Assert.Null(result.Cart.Discount); + Assert.Null(result.Cart.PasswordManager.Seats.Discount); } [Fact] @@ -672,10 +674,11 @@ public async Task Run_WithScheduleStripeException_ReturnsNoDiscount() Assert.NotNull(result); Assert.Null(result.Cart.Discount); + Assert.Null(result.Cart.PasswordManager.Seats.Discount); } [Fact] - public async Task Run_WithSchedulePhase2AmountOffDiscount_IncludesAmountOffDiscountInCart() + public async Task Run_WithSchedulePhase2AmountOffDiscount_IncludesAmountOffDiscountOnSeats() { var user = CreateUser(); var subscription = CreateSubscription(SubscriptionStatus.Active); @@ -694,9 +697,10 @@ public async Task Run_WithSchedulePhase2AmountOffDiscount_IncludesAmountOffDisco var result = await _query.Run(user); Assert.NotNull(result); - Assert.NotNull(result.Cart.Discount); - Assert.Equal(BitwardenDiscountType.AmountOff, result.Cart.Discount.Type); - Assert.Equal(500, result.Cart.Discount.Value); + Assert.Null(result.Cart.Discount); + Assert.NotNull(result.Cart.PasswordManager.Seats.Discount); + Assert.Equal(BitwardenDiscountType.AmountOff, result.Cart.PasswordManager.Seats.Discount.Type); + Assert.Equal(500, result.Cart.PasswordManager.Seats.Discount.Value); } [Fact] @@ -720,6 +724,7 @@ public async Task Run_WithCompletedSchedule_ReturnsNoDiscount() Assert.NotNull(result); Assert.Null(result.Cart.Discount); + Assert.Null(result.Cart.PasswordManager.Seats.Discount); } [Fact] @@ -743,6 +748,7 @@ public async Task Run_WithSchedulePhase2InvalidCoupon_ReturnsNoDiscount() Assert.NotNull(result); Assert.Null(result.Cart.Discount); + Assert.Null(result.Cart.PasswordManager.Seats.Discount); } #region Helper Methods