mirror of
https://github.com/bitwarden/server
synced 2025-12-22 19:23:45 +00:00
[PM-14894] Drop Tax Rate tables - Stage 1 (#5236)
This commit is contained in:
@@ -16,7 +16,6 @@ using Bit.Core.Settings;
|
||||
using Bit.Core.Utilities;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using TaxRate = Bit.Core.Entities.TaxRate;
|
||||
|
||||
namespace Bit.Admin.Controllers;
|
||||
|
||||
@@ -33,7 +32,6 @@ public class ToolsController : Controller
|
||||
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||
private readonly IProviderUserRepository _providerUserRepository;
|
||||
private readonly IPaymentService _paymentService;
|
||||
private readonly ITaxRateRepository _taxRateRepository;
|
||||
private readonly IStripeAdapter _stripeAdapter;
|
||||
private readonly IWebHostEnvironment _environment;
|
||||
|
||||
@@ -46,7 +44,6 @@ public class ToolsController : Controller
|
||||
IInstallationRepository installationRepository,
|
||||
IOrganizationUserRepository organizationUserRepository,
|
||||
IProviderUserRepository providerUserRepository,
|
||||
ITaxRateRepository taxRateRepository,
|
||||
IPaymentService paymentService,
|
||||
IStripeAdapter stripeAdapter,
|
||||
IWebHostEnvironment environment)
|
||||
@@ -59,7 +56,6 @@ public class ToolsController : Controller
|
||||
_installationRepository = installationRepository;
|
||||
_organizationUserRepository = organizationUserRepository;
|
||||
_providerUserRepository = providerUserRepository;
|
||||
_taxRateRepository = taxRateRepository;
|
||||
_paymentService = paymentService;
|
||||
_stripeAdapter = stripeAdapter;
|
||||
_environment = environment;
|
||||
@@ -346,165 +342,6 @@ public class ToolsController : Controller
|
||||
}
|
||||
}
|
||||
|
||||
[RequirePermission(Permission.Tools_ManageTaxRates)]
|
||||
public async Task<IActionResult> TaxRate(int page = 1, int count = 25)
|
||||
{
|
||||
if (page < 1)
|
||||
{
|
||||
page = 1;
|
||||
}
|
||||
|
||||
if (count < 1)
|
||||
{
|
||||
count = 1;
|
||||
}
|
||||
|
||||
var skip = (page - 1) * count;
|
||||
var rates = await _taxRateRepository.SearchAsync(skip, count);
|
||||
return View(new TaxRatesModel
|
||||
{
|
||||
Items = rates.ToList(),
|
||||
Page = page,
|
||||
Count = count
|
||||
});
|
||||
}
|
||||
|
||||
[RequirePermission(Permission.Tools_ManageTaxRates)]
|
||||
public async Task<IActionResult> TaxRateAddEdit(string stripeTaxRateId = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(stripeTaxRateId))
|
||||
{
|
||||
return View(new TaxRateAddEditModel());
|
||||
}
|
||||
|
||||
var rate = await _taxRateRepository.GetByIdAsync(stripeTaxRateId);
|
||||
var model = new TaxRateAddEditModel()
|
||||
{
|
||||
StripeTaxRateId = stripeTaxRateId,
|
||||
Country = rate.Country,
|
||||
State = rate.State,
|
||||
PostalCode = rate.PostalCode,
|
||||
Rate = rate.Rate
|
||||
};
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
[ValidateAntiForgeryToken]
|
||||
[RequirePermission(Permission.Tools_ManageTaxRates)]
|
||||
public async Task<IActionResult> TaxRateUpload(IFormFile file)
|
||||
{
|
||||
if (file == null || file.Length == 0)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(file));
|
||||
}
|
||||
|
||||
// Build rates and validate them first before updating DB & Stripe
|
||||
var taxRateUpdates = new List<TaxRate>();
|
||||
var currentTaxRates = await _taxRateRepository.GetAllActiveAsync();
|
||||
using var reader = new StreamReader(file.OpenReadStream());
|
||||
while (!reader.EndOfStream)
|
||||
{
|
||||
var line = await reader.ReadLineAsync();
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var taxParts = line.Split(',');
|
||||
if (taxParts.Length < 2)
|
||||
{
|
||||
throw new Exception($"This line is not in the format of <postal code>,<rate>,<state code>,<country code>: {line}");
|
||||
}
|
||||
var postalCode = taxParts[0].Trim();
|
||||
if (string.IsNullOrWhiteSpace(postalCode))
|
||||
{
|
||||
throw new Exception($"'{line}' is not valid, the first element must contain a postal code.");
|
||||
}
|
||||
if (!decimal.TryParse(taxParts[1], out var rate) || rate <= 0M || rate > 100)
|
||||
{
|
||||
throw new Exception($"{taxParts[1]} is not a valid rate/decimal for {postalCode}");
|
||||
}
|
||||
var state = taxParts.Length > 2 ? taxParts[2] : null;
|
||||
var country = (taxParts.Length > 3 ? taxParts[3] : null);
|
||||
if (string.IsNullOrWhiteSpace(country))
|
||||
{
|
||||
country = "US";
|
||||
}
|
||||
var taxRate = currentTaxRates.FirstOrDefault(r => r.Country == country && r.PostalCode == postalCode) ??
|
||||
new TaxRate
|
||||
{
|
||||
Country = country,
|
||||
PostalCode = postalCode,
|
||||
Active = true,
|
||||
};
|
||||
taxRate.Rate = rate;
|
||||
taxRate.State = state ?? taxRate.State;
|
||||
taxRateUpdates.Add(taxRate);
|
||||
}
|
||||
|
||||
foreach (var taxRate in taxRateUpdates)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(taxRate.Id))
|
||||
{
|
||||
await _paymentService.UpdateTaxRateAsync(taxRate);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _paymentService.CreateTaxRateAsync(taxRate);
|
||||
}
|
||||
}
|
||||
|
||||
return RedirectToAction("TaxRate");
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
[RequirePermission(Permission.Tools_ManageTaxRates)]
|
||||
public async Task<IActionResult> TaxRateAddEdit(TaxRateAddEditModel model)
|
||||
{
|
||||
var existingRateCheck = await _taxRateRepository.GetByLocationAsync(new TaxRate() { Country = model.Country, PostalCode = model.PostalCode });
|
||||
if (existingRateCheck.Any())
|
||||
{
|
||||
ModelState.AddModelError(nameof(model.PostalCode), "A tax rate already exists for this Country/Postal Code combination.");
|
||||
}
|
||||
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
|
||||
var taxRate = new TaxRate()
|
||||
{
|
||||
Id = model.StripeTaxRateId,
|
||||
Country = model.Country,
|
||||
State = model.State,
|
||||
PostalCode = model.PostalCode,
|
||||
Rate = model.Rate
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(model.StripeTaxRateId))
|
||||
{
|
||||
await _paymentService.UpdateTaxRateAsync(taxRate);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _paymentService.CreateTaxRateAsync(taxRate);
|
||||
}
|
||||
|
||||
return RedirectToAction("TaxRate");
|
||||
}
|
||||
|
||||
[RequirePermission(Permission.Tools_ManageTaxRates)]
|
||||
public async Task<IActionResult> TaxRateArchive(string stripeTaxRateId)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(stripeTaxRateId))
|
||||
{
|
||||
await _paymentService.ArchiveTaxRateAsync(new TaxRate() { Id = stripeTaxRateId });
|
||||
}
|
||||
|
||||
return RedirectToAction("TaxRate");
|
||||
}
|
||||
|
||||
[RequirePermission(Permission.Tools_ManageStripeSubscriptions)]
|
||||
public async Task<IActionResult> StripeSubscriptions(StripeSubscriptionListOptions options)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user