1
0
mirror of https://github.com/bitwarden/server.git synced 2025-03-12 13:29:14 +01:00

Added ability to bulk-upload tax rates (#1139)

This commit is contained in:
Chad Scharf 2021-02-11 16:39:27 -05:00 committed by GitHub
parent 7065bba56f
commit f3bff938c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 103 additions and 3 deletions

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@ -10,6 +11,7 @@ using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Utilities;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
@ -282,7 +284,7 @@ namespace Bit.Admin.Controllers
{
count = 1;
}
var skip = (page - 1) * count;
var rates = await _taxRateRepository.SearchAsync(skip, count);
return View(new TaxRatesModel
@ -293,13 +295,13 @@ namespace Bit.Admin.Controllers
});
}
public async Task<IActionResult> TaxRateAddEdit(string stripeTaxRateId = null)
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()
{
@ -313,6 +315,71 @@ namespace Bit.Admin.Controllers
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]
public async Task<IActionResult> TaxRateAddEdit(TaxRateAddEditModel model)
{

View File

@ -7,6 +7,39 @@
<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 &amp; Manage Tax Rates</h2>
<a class="btn btn-primary mb-2" asp-controller="Tools" asp-action="TaxRateAddEdit">Add a Rate</a>
<div class="table-responsive">
<table class="table table-striped table-hover">