mirror of
https://github.com/bitwarden/server
synced 2025-12-26 05:03:18 +00:00
[PM 19727] Update InvoiceUpcoming email content (#6168)
* changes to implement the email * Refactoring and fix the unit testing * refactor the code and remove used method * Fix the failing test * Update the email templates * remove the extra space here * Refactor the descriptions * Fix the wrong subject header * Add the in the hyperlink rather than just Help center
This commit is contained in:
76
src/Core/Billing/Extensions/InvoiceExtensions.cs
Normal file
76
src/Core/Billing/Extensions/InvoiceExtensions.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using Stripe;
|
||||
|
||||
namespace Bit.Core.Billing.Extensions;
|
||||
|
||||
public static class InvoiceExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Formats invoice line items specifically for provider invoices, standardizing product descriptions
|
||||
/// and ensuring consistent tax representation.
|
||||
/// </summary>
|
||||
/// <param name="invoice">The Stripe invoice containing line items</param>
|
||||
/// <param name="subscription">The associated subscription (for future extensibility)</param>
|
||||
/// <returns>A list of formatted invoice item descriptions</returns>
|
||||
public static List<string> FormatForProvider(this Invoice invoice, Subscription subscription)
|
||||
{
|
||||
var items = new List<string>();
|
||||
|
||||
// Return empty list if no line items
|
||||
if (invoice.Lines == null)
|
||||
{
|
||||
return items;
|
||||
}
|
||||
|
||||
foreach (var line in invoice.Lines.Data ?? new List<InvoiceLineItem>())
|
||||
{
|
||||
// Skip null lines or lines without description
|
||||
if (line?.Description == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var description = line.Description;
|
||||
|
||||
// Handle Provider Portal and Business Unit Portal service lines
|
||||
if (description.Contains("Provider Portal") || description.Contains("Business Unit"))
|
||||
{
|
||||
var priceMatch = Regex.Match(description, @"\(at \$[\d,]+\.?\d* / month\)");
|
||||
var priceInfo = priceMatch.Success ? priceMatch.Value : "";
|
||||
|
||||
var standardizedDescription = $"{line.Quantity} × Manage service provider {priceInfo}";
|
||||
items.Add(standardizedDescription);
|
||||
}
|
||||
// Handle tax lines
|
||||
else if (description.ToLower().Contains("tax"))
|
||||
{
|
||||
var priceMatch = Regex.Match(description, @"\(at \$[\d,]+\.?\d* / month\)");
|
||||
var priceInfo = priceMatch.Success ? priceMatch.Value : "";
|
||||
|
||||
// If no price info found in description, calculate from amount
|
||||
if (string.IsNullOrEmpty(priceInfo) && line.Quantity > 0)
|
||||
{
|
||||
var pricePerItem = (line.Amount / 100m) / line.Quantity;
|
||||
priceInfo = $"(at ${pricePerItem:F2} / month)";
|
||||
}
|
||||
|
||||
var taxDescription = $"{line.Quantity} × Tax {priceInfo}";
|
||||
items.Add(taxDescription);
|
||||
}
|
||||
// Handle other line items as-is
|
||||
else
|
||||
{
|
||||
items.Add(description);
|
||||
}
|
||||
}
|
||||
|
||||
// Add fallback tax from invoice-level tax if present and not already included
|
||||
if (invoice.Tax.HasValue && invoice.Tax.Value > 0)
|
||||
{
|
||||
var taxAmount = invoice.Tax.Value / 100m;
|
||||
items.Add($"1 × Tax (at ${taxAmount:F2} / month)");
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user