mirror of
https://github.com/bitwarden/server.git
synced 2025-05-22 20:11:04 -05:00

* [NO LOGIC] Organize Billing provider code * Run dotnet format * Run dotnet format' * Fixed using after merge * Fixed test usings after merge
135 lines
5.3 KiB
C#
135 lines
5.3 KiB
C#
using Bit.Billing.Constants;
|
|
using Bit.Core.AdminConsole.Repositories;
|
|
using Bit.Core.Billing.Pricing;
|
|
using Bit.Core.Billing.Providers.Entities;
|
|
using Bit.Core.Billing.Providers.Repositories;
|
|
using Bit.Core.Enums;
|
|
using Bit.Core.Repositories;
|
|
using Stripe;
|
|
|
|
namespace Bit.Billing.Services.Implementations;
|
|
|
|
public class ProviderEventService(
|
|
IOrganizationRepository organizationRepository,
|
|
IPricingClient pricingClient,
|
|
IProviderInvoiceItemRepository providerInvoiceItemRepository,
|
|
IProviderOrganizationRepository providerOrganizationRepository,
|
|
IProviderPlanRepository providerPlanRepository,
|
|
IStripeEventService stripeEventService,
|
|
IStripeFacade stripeFacade) : IProviderEventService
|
|
{
|
|
public async Task TryRecordInvoiceLineItems(Event parsedEvent)
|
|
{
|
|
if (parsedEvent.Type is not HandledStripeWebhook.InvoiceCreated and not HandledStripeWebhook.InvoiceFinalized)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var invoice = await stripeEventService.GetInvoice(parsedEvent);
|
|
|
|
var metadata = (await stripeFacade.GetSubscription(invoice.SubscriptionId)).Metadata ?? new Dictionary<string, string>();
|
|
|
|
var hasProviderId = metadata.TryGetValue("providerId", out var providerId);
|
|
|
|
if (!hasProviderId)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var parsedProviderId = Guid.Parse(providerId);
|
|
|
|
switch (parsedEvent.Type)
|
|
{
|
|
case HandledStripeWebhook.InvoiceCreated:
|
|
{
|
|
var clients =
|
|
await providerOrganizationRepository.GetManyDetailsByProviderAsync(parsedProviderId);
|
|
|
|
var providerPlans = await providerPlanRepository.GetByProviderId(parsedProviderId);
|
|
|
|
var invoiceItems = new List<ProviderInvoiceItem>();
|
|
|
|
foreach (var client in clients)
|
|
{
|
|
if (client.Status != OrganizationStatusType.Managed)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var organization = await organizationRepository.GetByIdAsync(client.OrganizationId);
|
|
|
|
if (organization == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var plan = await pricingClient.GetPlanOrThrow(organization.PlanType);
|
|
|
|
var discountedPercentage = (100 - (invoice.Discount?.Coupon?.PercentOff ?? 0)) / 100;
|
|
|
|
var discountedSeatPrice = plan.PasswordManager.ProviderPortalSeatPrice * discountedPercentage;
|
|
|
|
invoiceItems.Add(new ProviderInvoiceItem
|
|
{
|
|
ProviderId = parsedProviderId,
|
|
InvoiceId = invoice.Id,
|
|
InvoiceNumber = invoice.Number,
|
|
ClientId = client.OrganizationId,
|
|
ClientName = client.OrganizationName,
|
|
PlanName = client.Plan,
|
|
AssignedSeats = client.Seats ?? 0,
|
|
UsedSeats = client.OccupiedSeats ?? 0,
|
|
Total = (client.Seats ?? 0) * discountedSeatPrice
|
|
});
|
|
}
|
|
|
|
foreach (var providerPlan in providerPlans.Where(x => x.PurchasedSeats is null or 0))
|
|
{
|
|
var plan = await pricingClient.GetPlanOrThrow(providerPlan.PlanType);
|
|
|
|
var clientSeats = invoiceItems
|
|
.Where(item => item.PlanName == plan.Name)
|
|
.Sum(item => item.AssignedSeats);
|
|
|
|
var unassignedSeats = providerPlan.SeatMinimum - clientSeats ?? 0;
|
|
|
|
var discountedPercentage = (100 - (invoice.Discount?.Coupon?.PercentOff ?? 0)) / 100;
|
|
|
|
var discountedSeatPrice = plan.PasswordManager.ProviderPortalSeatPrice * discountedPercentage;
|
|
|
|
invoiceItems.Add(new ProviderInvoiceItem
|
|
{
|
|
ProviderId = parsedProviderId,
|
|
InvoiceId = invoice.Id,
|
|
InvoiceNumber = invoice.Number,
|
|
ClientName = "Unassigned seats",
|
|
PlanName = plan.Name,
|
|
AssignedSeats = unassignedSeats,
|
|
UsedSeats = 0,
|
|
Total = unassignedSeats * discountedSeatPrice
|
|
});
|
|
}
|
|
|
|
await Task.WhenAll(invoiceItems.Select(providerInvoiceItemRepository.CreateAsync));
|
|
|
|
break;
|
|
}
|
|
case HandledStripeWebhook.InvoiceFinalized:
|
|
{
|
|
var invoiceItems = await providerInvoiceItemRepository.GetByInvoiceId(invoice.Id);
|
|
|
|
if (invoiceItems.Count != 0)
|
|
{
|
|
await Task.WhenAll(invoiceItems.Select(invoiceItem =>
|
|
{
|
|
invoiceItem.InvoiceNumber = invoice.Number;
|
|
return providerInvoiceItemRepository.ReplaceAsync(invoiceItem);
|
|
}));
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|