diff --git a/src/Core/Billing/Migration/Services/Implementations/ProviderMigrator.cs b/src/Core/Billing/Migration/Services/Implementations/ProviderMigrator.cs index 0da384ae2..46c014cdb 100644 --- a/src/Core/Billing/Migration/Services/Implementations/ProviderMigrator.cs +++ b/src/Core/Billing/Migration/Services/Implementations/ProviderMigrator.cs @@ -306,21 +306,36 @@ public class ProviderMigrator( var organizationCancellationCredit = organizationCustomers.Sum(customer => customer.Balance); - var legacyOrganizations = organizations.Where(organization => - organization.PlanType is + await stripeAdapter.CustomerBalanceTransactionCreate(provider.GatewayCustomerId, + new CustomerBalanceTransactionCreateOptions + { + Amount = organizationCancellationCredit, + Currency = "USD", + Description = "Unused, prorated time for client organization subscriptions." + }); + + var migrationRecords = await Task.WhenAll(organizations.Select(organization => + clientOrganizationMigrationRecordRepository.GetByOrganizationId(organization.Id))); + + var legacyOrganizationMigrationRecords = migrationRecords.Where(migrationRecord => + migrationRecord.PlanType is PlanType.EnterpriseAnnually2020 or - PlanType.EnterpriseMonthly2020 or - PlanType.TeamsAnnually2020 or - PlanType.TeamsMonthly2020); + PlanType.TeamsAnnually2020); - var legacyOrganizationCredit = legacyOrganizations.Sum(organization => organization.Seats ?? 0); + var legacyOrganizationCredit = legacyOrganizationMigrationRecords.Sum(migrationRecord => migrationRecord.Seats) * 12 * -100; - await stripeAdapter.CustomerUpdateAsync(provider.GatewayCustomerId, new CustomerUpdateOptions + if (legacyOrganizationCredit < 0) { - Balance = organizationCancellationCredit + legacyOrganizationCredit - }); + await stripeAdapter.CustomerBalanceTransactionCreate(provider.GatewayCustomerId, + new CustomerBalanceTransactionCreateOptions + { + Amount = legacyOrganizationCredit, + Currency = "USD", + Description = "1 year rebate for legacy client organizations." + }); + } - logger.LogInformation("CB: Applied {Credit} credit to provider ({ProviderID})", organizationCancellationCredit, provider.Id); + logger.LogInformation("CB: Applied {Credit} credit to provider ({ProviderID})", organizationCancellationCredit + legacyOrganizationCredit, provider.Id); await migrationTrackerCache.UpdateTrackingStatus(provider.Id, ProviderMigrationProgress.CreditApplied); } diff --git a/src/Core/Services/IStripeAdapter.cs b/src/Core/Services/IStripeAdapter.cs index bb57f1cd0..a288e1cbe 100644 --- a/src/Core/Services/IStripeAdapter.cs +++ b/src/Core/Services/IStripeAdapter.cs @@ -10,6 +10,8 @@ public interface IStripeAdapter Task CustomerUpdateAsync(string id, Stripe.CustomerUpdateOptions options = null); Task CustomerDeleteAsync(string id); Task> CustomerListPaymentMethods(string id, CustomerListPaymentMethodsOptions options = null); + Task CustomerBalanceTransactionCreate(string customerId, + CustomerBalanceTransactionCreateOptions options); Task SubscriptionCreateAsync(Stripe.SubscriptionCreateOptions subscriptionCreateOptions); Task SubscriptionGetAsync(string id, Stripe.SubscriptionGetOptions options = null); Task> SubscriptionListAsync(StripeSubscriptionListOptions subscriptionSearchOptions); diff --git a/src/Core/Services/Implementations/StripeAdapter.cs b/src/Core/Services/Implementations/StripeAdapter.cs index 100a47f75..e5fee63b9 100644 --- a/src/Core/Services/Implementations/StripeAdapter.cs +++ b/src/Core/Services/Implementations/StripeAdapter.cs @@ -18,6 +18,7 @@ public class StripeAdapter : IStripeAdapter private readonly Stripe.PriceService _priceService; private readonly Stripe.SetupIntentService _setupIntentService; private readonly Stripe.TestHelpers.TestClockService _testClockService; + private readonly CustomerBalanceTransactionService _customerBalanceTransactionService; public StripeAdapter() { @@ -34,6 +35,7 @@ public class StripeAdapter : IStripeAdapter _priceService = new Stripe.PriceService(); _setupIntentService = new SetupIntentService(); _testClockService = new Stripe.TestHelpers.TestClockService(); + _customerBalanceTransactionService = new CustomerBalanceTransactionService(); } public Task CustomerCreateAsync(Stripe.CustomerCreateOptions options) @@ -63,6 +65,10 @@ public class StripeAdapter : IStripeAdapter return paymentMethods.Data; } + public async Task CustomerBalanceTransactionCreate(string customerId, + CustomerBalanceTransactionCreateOptions options) + => await _customerBalanceTransactionService.CreateAsync(customerId, options); + public Task SubscriptionCreateAsync(Stripe.SubscriptionCreateOptions options) { return _subscriptionService.CreateAsync(options);