mirror of
https://github.com/bitwarden/server.git
synced 2025-04-18 19:48:12 -05:00
Added ability to bulk-upload tax rates (#1139)
This commit is contained in:
parent
7065bba56f
commit
f3bff938c4
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -10,6 +11,7 @@ using Bit.Core.Repositories;
|
|||||||
using Bit.Core.Services;
|
using Bit.Core.Services;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
@ -313,6 +315,71 @@ namespace Bit.Admin.Controllers
|
|||||||
return View(model);
|
return View(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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]
|
[HttpPost]
|
||||||
public async Task<IActionResult> TaxRateAddEdit(TaxRateAddEditModel model)
|
public async Task<IActionResult> TaxRateAddEdit(TaxRateAddEditModel model)
|
||||||
{
|
{
|
||||||
|
@ -7,6 +7,39 @@
|
|||||||
|
|
||||||
<h1>Manage Tax Rates</h1>
|
<h1>Manage Tax Rates</h1>
|
||||||
|
|
||||||
|
<h2>Bulk Upload Tax Rates</h2>
|
||||||
|
<section>
|
||||||
|
<p>
|
||||||
|
Upload a CSV file containing multiple tax rates in bulk in order to update existing rates by country
|
||||||
|
and postal code OR to create new rates where a currently active rate is not found already.
|
||||||
|
</p>
|
||||||
|
<p>CSV Upload Format</p>
|
||||||
|
<ul>
|
||||||
|
<li><b>Postal Code</b> (required) - The postal code for the tax rate.</li>
|
||||||
|
<li><b>Rate</b> (required) - The effective tax rate for this postal code.</li>
|
||||||
|
<li><b>State</b> (<i>optional</i>) - The ISO-2 character code for the state. Optional but recommended.</li>
|
||||||
|
<li><b>Country</b> (<i>optional</i>) - The ISO-2 character country code, defaults to "US" if not provided.</li>
|
||||||
|
</ul>
|
||||||
|
<p>Example (white-space is ignored):</p>
|
||||||
|
<div class="card mb-2">
|
||||||
|
<div class="card-body">
|
||||||
|
<pre class="mb-0">87654,8.25,FL,US
|
||||||
|
22334,8.5,CA
|
||||||
|
11223,7</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<form method="post" enctype="multipart/form-data" asp-action="TaxRateUpload">
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="file" name="file" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="submit" value="Upload" class="btn btn-primary mb-2" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
<h2>View & Manage Tax Rates</h2>
|
||||||
<a class="btn btn-primary mb-2" asp-controller="Tools" asp-action="TaxRateAddEdit">Add a Rate</a>
|
<a class="btn btn-primary mb-2" asp-controller="Tools" asp-action="TaxRateAddEdit">Add a Rate</a>
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-striped table-hover">
|
<table class="table table-striped table-hover">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user