1
0
mirror of https://github.com/bitwarden/server.git synced 2025-06-30 07:36:14 -05:00

[AC-2795] Add account credit & tax information to provider subscription (#4276)

* Add account credit, suspension and tax information to subscription response

* Run dotnet format'
This commit is contained in:
Alex Morask
2024-06-26 09:08:18 -04:00
committed by GitHub
parent 6646d11074
commit e8e725c389
7 changed files with 220 additions and 61 deletions

View File

@ -8,11 +8,11 @@ public record ConsolidatedBillingSubscriptionResponse(
DateTime CurrentPeriodEndDate,
decimal? DiscountPercentage,
string CollectionMethod,
DateTime? UnpaidPeriodEndDate,
int? GracePeriod,
DateTime? SuspensionDate,
IEnumerable<ProviderPlanResponse> Plans,
long AccountCredit,
TaxInformationDTO TaxInformation,
DateTime? CancelAt,
IEnumerable<ProviderPlanResponse> Plans)
SubscriptionSuspensionDTO Suspension)
{
private const string _annualCadence = "Annual";
private const string _monthlyCadence = "Monthly";
@ -20,9 +20,9 @@ public record ConsolidatedBillingSubscriptionResponse(
public static ConsolidatedBillingSubscriptionResponse From(
ConsolidatedBillingSubscriptionDTO consolidatedBillingSubscription)
{
var (providerPlans, subscription, suspensionDate, unpaidPeriodEndDate) = consolidatedBillingSubscription;
var (providerPlans, subscription, taxInformation, suspension) = consolidatedBillingSubscription;
var providerPlansDTO = providerPlans
var providerPlanResponses = providerPlans
.Select(providerPlan =>
{
var plan = StaticStore.GetPlan(providerPlan.PlanType);
@ -37,18 +37,16 @@ public record ConsolidatedBillingSubscriptionResponse(
cadence);
});
var gracePeriod = subscription.CollectionMethod == "charge_automatically" ? 14 : 30;
return new ConsolidatedBillingSubscriptionResponse(
subscription.Status,
subscription.CurrentPeriodEnd,
subscription.Customer?.Discount?.Coupon?.PercentOff,
subscription.CollectionMethod,
unpaidPeriodEndDate,
gracePeriod,
suspensionDate,
providerPlanResponses,
subscription.Customer?.Balance ?? 0,
taxInformation,
subscription.CancelAt,
providerPlansDTO);
suspension);
}
}

View File

@ -5,5 +5,5 @@ namespace Bit.Core.Billing.Models;
public record ConsolidatedBillingSubscriptionDTO(
List<ConfiguredProviderPlanDTO> ProviderPlans,
Subscription Subscription,
DateTime? SuspensionDate,
DateTime? UnpaidPeriodEndDate);
TaxInformationDTO TaxInformation,
SubscriptionSuspensionDTO Suspension);

View File

@ -0,0 +1,6 @@
namespace Bit.Core.Billing.Models;
public record SubscriptionSuspensionDTO(
DateTime SuspensionDate,
DateTime UnpaidPeriodEndDate,
int GracePeriod);

View File

@ -1,4 +1,8 @@
namespace Bit.Core.Billing;
using Bit.Core.Billing.Models;
using Bit.Core.Services;
using Stripe;
namespace Bit.Core.Billing;
public static class Utilities
{
@ -8,4 +12,67 @@ public static class Utilities
string internalMessage = null,
Exception innerException = null) => new("Something went wrong with your request. Please contact support.",
internalMessage, innerException);
public static async Task<SubscriptionSuspensionDTO> GetSuspensionAsync(
IStripeAdapter stripeAdapter,
Subscription subscription)
{
if (subscription.Status is not "past_due" && subscription.Status is not "unpaid")
{
return null;
}
var openInvoices = await stripeAdapter.InvoiceSearchAsync(new InvoiceSearchOptions
{
Query = $"subscription:'{subscription.Id}' status:'open'"
});
if (openInvoices.Count == 0)
{
return null;
}
var currentDate = subscription.TestClock?.FrozenTime ?? DateTime.UtcNow;
switch (subscription.CollectionMethod)
{
case "charge_automatically":
{
var firstOverdueInvoice = openInvoices
.Where(invoice => invoice.PeriodEnd < currentDate && invoice.Attempted)
.MinBy(invoice => invoice.Created);
if (firstOverdueInvoice == null)
{
return null;
}
const int gracePeriod = 14;
return new SubscriptionSuspensionDTO(
firstOverdueInvoice.Created.AddDays(gracePeriod),
firstOverdueInvoice.PeriodEnd,
gracePeriod);
}
case "send_invoice":
{
var firstOverdueInvoice = openInvoices
.Where(invoice => invoice.DueDate < currentDate)
.MinBy(invoice => invoice.Created);
if (firstOverdueInvoice?.DueDate == null)
{
return null;
}
const int gracePeriod = 30;
return new SubscriptionSuspensionDTO(
firstOverdueInvoice.DueDate.Value.AddDays(gracePeriod),
firstOverdueInvoice.PeriodEnd,
gracePeriod);
}
default: return null;
}
}
}