1
0
mirror of https://github.com/bitwarden/server.git synced 2024-11-21 12:05:42 +01:00

Remove provider discount for CB (#4277)

This commit is contained in:
Alex Morask 2024-06-26 09:33:22 -04:00 committed by GitHub
parent 750321afaa
commit 26575856e6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 50 additions and 31 deletions

View File

@ -79,7 +79,7 @@ public class ProviderBillingService(
if (string.IsNullOrEmpty(taxInfo.BillingAddressCountry) || if (string.IsNullOrEmpty(taxInfo.BillingAddressCountry) ||
string.IsNullOrEmpty(taxInfo.BillingAddressPostalCode)) string.IsNullOrEmpty(taxInfo.BillingAddressPostalCode))
{ {
logger.LogError("Cannot create Stripe customer for provider ({ID}) - Both the provider's country and postal code are required", provider.Id); logger.LogError("Cannot create customer for provider ({ProviderID}) without both a country and postal code", provider.Id);
throw ContactSupport(); throw ContactSupport();
} }
@ -97,7 +97,6 @@ public class ProviderBillingService(
City = taxInfo.BillingAddressCity, City = taxInfo.BillingAddressCity,
State = taxInfo.BillingAddressState State = taxInfo.BillingAddressState
}, },
Coupon = "msp-discount-35",
Description = provider.DisplayBusinessName(), Description = provider.DisplayBusinessName(),
Email = provider.BillingEmail, Email = provider.BillingEmail,
InvoiceSettings = new CustomerInvoiceSettingsOptions InvoiceSettings = new CustomerInvoiceSettingsOptions
@ -399,20 +398,13 @@ public class ProviderBillingService(
{ {
ArgumentNullException.ThrowIfNull(provider); ArgumentNullException.ThrowIfNull(provider);
if (!string.IsNullOrEmpty(provider.GatewaySubscriptionId))
{
logger.LogWarning("Cannot start Provider subscription - Provider ({ID}) already has a {FieldName}", provider.Id, nameof(provider.GatewaySubscriptionId));
throw ContactSupport();
}
var customer = await subscriberService.GetCustomerOrThrow(provider); var customer = await subscriberService.GetCustomerOrThrow(provider);
var providerPlans = await providerPlanRepository.GetByProviderId(provider.Id); var providerPlans = await providerPlanRepository.GetByProviderId(provider.Id);
if (providerPlans == null || providerPlans.Count == 0) if (providerPlans == null || providerPlans.Count == 0)
{ {
logger.LogError("Cannot start Provider subscription - Provider ({ID}) has no configured plans", provider.Id); logger.LogError("Cannot start subscription for provider ({ProviderID}) that has no configured plans", provider.Id);
throw ContactSupport(); throw ContactSupport();
} }
@ -422,9 +414,9 @@ public class ProviderBillingService(
var teamsProviderPlan = var teamsProviderPlan =
providerPlans.SingleOrDefault(providerPlan => providerPlan.PlanType == PlanType.TeamsMonthly); providerPlans.SingleOrDefault(providerPlan => providerPlan.PlanType == PlanType.TeamsMonthly);
if (teamsProviderPlan == null) if (teamsProviderPlan == null || !teamsProviderPlan.IsConfigured())
{ {
logger.LogError("Cannot start Provider subscription - Provider ({ID}) has no configured Teams Monthly plan", provider.Id); logger.LogError("Cannot start subscription for provider ({ProviderID}) that has no configured Teams plan", provider.Id);
throw ContactSupport(); throw ContactSupport();
} }
@ -440,9 +432,9 @@ public class ProviderBillingService(
var enterpriseProviderPlan = var enterpriseProviderPlan =
providerPlans.SingleOrDefault(providerPlan => providerPlan.PlanType == PlanType.EnterpriseMonthly); providerPlans.SingleOrDefault(providerPlan => providerPlan.PlanType == PlanType.EnterpriseMonthly);
if (enterpriseProviderPlan == null) if (enterpriseProviderPlan == null || !enterpriseProviderPlan.IsConfigured())
{ {
logger.LogError("Cannot start Provider subscription - Provider ({ID}) has no configured Enterprise Monthly plan", provider.Id); logger.LogError("Cannot start subscription for provider ({ProviderID}) that has no configured Enterprise plan", provider.Id);
throw ContactSupport(); throw ContactSupport();
} }
@ -481,7 +473,7 @@ public class ProviderBillingService(
{ {
await providerRepository.ReplaceAsync(provider); await providerRepository.ReplaceAsync(provider);
logger.LogError("Started incomplete Provider ({ProviderID}) subscription ({SubscriptionID})", provider.Id, subscription.Id); logger.LogError("Started incomplete provider ({ProviderID}) subscription ({SubscriptionID})", provider.Id, subscription.Id);
throw ContactSupport(); throw ContactSupport();
} }

View File

@ -556,7 +556,6 @@ public class ProviderBillingServiceTests
o.Address.Line2 == taxInfo.BillingAddressLine2 && o.Address.Line2 == taxInfo.BillingAddressLine2 &&
o.Address.City == taxInfo.BillingAddressCity && o.Address.City == taxInfo.BillingAddressCity &&
o.Address.State == taxInfo.BillingAddressState && o.Address.State == taxInfo.BillingAddressState &&
o.Coupon == "msp-discount-35" &&
o.Description == WebUtility.HtmlDecode(provider.BusinessName) && o.Description == WebUtility.HtmlDecode(provider.BusinessName) &&
o.Email == provider.BillingEmail && o.Email == provider.BillingEmail &&
o.InvoiceSettings.CustomFields.FirstOrDefault().Name == "Provider" && o.InvoiceSettings.CustomFields.FirstOrDefault().Name == "Provider" &&
@ -579,7 +578,6 @@ public class ProviderBillingServiceTests
o.Address.Line2 == taxInfo.BillingAddressLine2 && o.Address.Line2 == taxInfo.BillingAddressLine2 &&
o.Address.City == taxInfo.BillingAddressCity && o.Address.City == taxInfo.BillingAddressCity &&
o.Address.State == taxInfo.BillingAddressState && o.Address.State == taxInfo.BillingAddressState &&
o.Coupon == "msp-discount-35" &&
o.Description == WebUtility.HtmlDecode(provider.BusinessName) && o.Description == WebUtility.HtmlDecode(provider.BusinessName) &&
o.Email == provider.BillingEmail && o.Email == provider.BillingEmail &&
o.InvoiceSettings.CustomFields.FirstOrDefault().Name == "Provider" && o.InvoiceSettings.CustomFields.FirstOrDefault().Name == "Provider" &&
@ -1023,16 +1021,6 @@ public class ProviderBillingServiceTests
SutProvider<ProviderBillingService> sutProvider) => SutProvider<ProviderBillingService> sutProvider) =>
await Assert.ThrowsAsync<ArgumentNullException>(() => sutProvider.Sut.StartSubscription(null)); await Assert.ThrowsAsync<ArgumentNullException>(() => sutProvider.Sut.StartSubscription(null));
[Theory, BitAutoData]
public async Task StartSubscription_AlreadyHasGatewaySubscriptionId_ContactSupport(
SutProvider<ProviderBillingService> sutProvider,
Provider provider)
{
provider.GatewaySubscriptionId = "subscription_id";
await ThrowsContactSupportAsync(() => sutProvider.Sut.StartSubscription(provider));
}
[Theory, BitAutoData] [Theory, BitAutoData]
public async Task StartSubscription_NoProviderPlans_ContactSupport( public async Task StartSubscription_NoProviderPlans_ContactSupport(
SutProvider<ProviderBillingService> sutProvider, SutProvider<ProviderBillingService> sutProvider,
@ -1121,8 +1109,24 @@ public class ProviderBillingServiceTests
var providerPlans = new List<ProviderPlan> var providerPlans = new List<ProviderPlan>
{ {
new() { PlanType = PlanType.TeamsMonthly, SeatMinimum = 100 }, new()
new() { PlanType = PlanType.EnterpriseMonthly, SeatMinimum = 100 } {
Id = Guid.NewGuid(),
ProviderId = provider.Id,
PlanType = PlanType.TeamsMonthly,
SeatMinimum = 100,
PurchasedSeats = 0,
AllocatedSeats = 0
},
new()
{
Id = Guid.NewGuid(),
ProviderId = provider.Id,
PlanType = PlanType.EnterpriseMonthly,
SeatMinimum = 100,
PurchasedSeats = 0,
AllocatedSeats = 0
}
}; };
sutProvider.GetDependency<IProviderPlanRepository>().GetByProviderId(provider.Id) sutProvider.GetDependency<IProviderPlanRepository>().GetByProviderId(provider.Id)
@ -1153,8 +1157,24 @@ public class ProviderBillingServiceTests
var providerPlans = new List<ProviderPlan> var providerPlans = new List<ProviderPlan>
{ {
new() { PlanType = PlanType.TeamsMonthly, SeatMinimum = 100 }, new()
new() { PlanType = PlanType.EnterpriseMonthly, SeatMinimum = 100 } {
Id = Guid.NewGuid(),
ProviderId = provider.Id,
PlanType = PlanType.TeamsMonthly,
SeatMinimum = 100,
PurchasedSeats = 0,
AllocatedSeats = 0
},
new()
{
Id = Guid.NewGuid(),
ProviderId = provider.Id,
PlanType = PlanType.EnterpriseMonthly,
SeatMinimum = 100,
PurchasedSeats = 0,
AllocatedSeats = 0
}
}; };
sutProvider.GetDependency<IProviderPlanRepository>().GetByProviderId(provider.Id) sutProvider.GetDependency<IProviderPlanRepository>().GetByProviderId(provider.Id)

View File

@ -1,6 +1,7 @@
using Bit.Core.AdminConsole.Entities; using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Entities.Provider; using Bit.Core.AdminConsole.Entities.Provider;
using Bit.Core.AdminConsole.Enums.Provider; using Bit.Core.AdminConsole.Enums.Provider;
using Bit.Core.Billing.Entities;
using Bit.Core.Billing.Enums; using Bit.Core.Billing.Enums;
using Bit.Core.Billing.Models; using Bit.Core.Billing.Models;
using Bit.Core.Models.Business; using Bit.Core.Models.Business;
@ -43,6 +44,12 @@ public interface IProviderBillingService
Provider provider, Provider provider,
Organization organization); Organization organization);
/// <summary>
/// Generate a provider's client invoice report in CSV format for the specified <paramref name="invoiceId"/>. Utilizes the <see cref="ProviderInvoiceItem"/>
/// records saved for the <paramref name="invoiceId"/> as part of our webhook processing for the <b>"invoice.created"</b> and <b>"invoice.finalized"</b> Stripe events.
/// </summary>
/// <param name="invoiceId">The ID of the Stripe <see cref="Stripe.Invoice"/> to generate the report for.</param>
/// <returns>The provider's client invoice report as a byte array.</returns>
Task<byte[]> GenerateClientInvoiceReport( Task<byte[]> GenerateClientInvoiceReport(
string invoiceId); string invoiceId);