Implement BS parser
This commit is contained in:
parent
a542bfb7f4
commit
be127319e2
@ -1,48 +1,57 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using RhSolutions.SkuParser.Models;
|
||||
using RhSolutions.SkuParser.Abstractions;
|
||||
|
||||
namespace RhSolutions.SkuParser.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("/api/[controller]")]
|
||||
public class CommonParseController : ControllerBase
|
||||
{
|
||||
private IServiceProvider _provider;
|
||||
private Dictionary<Product, double> _result;
|
||||
public CommonParseController(IServiceProvider provider)
|
||||
{
|
||||
_provider = provider;
|
||||
_result = new();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public IActionResult PostFiles()
|
||||
{
|
||||
IFormFileCollection files = Request.Form.Files;
|
||||
try
|
||||
{
|
||||
foreach (var file in files)
|
||||
{
|
||||
ISkuParser parser = _provider.GetRequiredKeyedService<ISkuParser>(file.ContentType);
|
||||
var dict = parser.ParseProducts(file);
|
||||
foreach (var kvp in dict)
|
||||
{
|
||||
if (_result.ContainsKey(kvp.Key))
|
||||
{
|
||||
_result[kvp.Key] += kvp.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
_result.Add(kvp.Key, kvp.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return BadRequest(error: $"{ex.Message}\n\n{ex.Source}\n{ex.StackTrace}");
|
||||
}
|
||||
return new JsonResult(_result.Select(x => new { x.Key.Sku, x.Value }));
|
||||
}
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using RhSolutions.SkuParser.Models;
|
||||
using RhSolutions.SkuParser.Abstractions;
|
||||
|
||||
namespace RhSolutions.SkuParser.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("/api/[controller]")]
|
||||
public class ParseController : ControllerBase
|
||||
{
|
||||
private IServiceProvider _provider;
|
||||
private Dictionary<Product, double> _result;
|
||||
public ParseController(IServiceProvider provider)
|
||||
{
|
||||
_provider = provider;
|
||||
_result = new();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public IActionResult PostFiles([FromQuery] bool bs = false)
|
||||
{
|
||||
IFormFileCollection files = Request.Form.Files;
|
||||
try
|
||||
{
|
||||
foreach (var file in files)
|
||||
{
|
||||
ISkuParser parser = bs ? _provider.GetRequiredKeyedService<ISkuParser>("BS")
|
||||
: _provider.GetRequiredKeyedService<ISkuParser>(file.ContentType);
|
||||
var dict = parser.ParseProducts(file);
|
||||
|
||||
foreach (var kvp in dict)
|
||||
{
|
||||
if (_result.ContainsKey(kvp.Key))
|
||||
{
|
||||
_result[kvp.Key] += kvp.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
_result.Add(kvp.Key, kvp.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return BadRequest(error: $"{ex.Message}\n\n{ex.Source}\n{ex.StackTrace}");
|
||||
}
|
||||
return new JsonResult(_result.Select(x => new
|
||||
{
|
||||
x.Key.Sku,
|
||||
x.Key.ProductLine,
|
||||
x.Key.Name,
|
||||
x.Key.Price,
|
||||
quantity = x.Value
|
||||
}));
|
||||
}
|
||||
}
|
@ -4,6 +4,10 @@ namespace RhSolutions.SkuParser.Models;
|
||||
|
||||
public record Product
|
||||
{
|
||||
private string _sku = string.Empty;
|
||||
private const string _parsePattern = @"(?<Lead>[1\s]|^|\b)(?<Article>\d{6})(?<Delimiter>[\s13-])(?<Variant>\d{3})(\b|$)";
|
||||
private const string _validnessPattern = @"^1\d{6}[1|3]\d{3}$";
|
||||
|
||||
/// <summary>
|
||||
/// Артикул РЕХАУ в заданном формате
|
||||
/// </summary>
|
||||
@ -17,9 +21,9 @@ public record Product
|
||||
: throw new ArgumentException("$Неверный артикул: {value}");
|
||||
}
|
||||
}
|
||||
private string _sku = string.Empty;
|
||||
private const string _parsePattern = @"(?<Lead>[1\s]|^|\b)(?<Article>\d{6})(?<Delimiter>[\s13-])(?<Variant>\d{3})(\b|$)";
|
||||
private const string _validnessPattern = @"^1\d{6}[1|3]\d{3}$";
|
||||
public ProductLine? ProductLine { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public decimal? Price { get; set; }
|
||||
|
||||
private static bool IsValudSku(string value)
|
||||
{
|
||||
@ -62,4 +66,4 @@ public record Product
|
||||
}
|
||||
public override int GetHashCode() => Sku.GetHashCode();
|
||||
public override string ToString() => Sku;
|
||||
}
|
||||
}
|
||||
|
7
RhSolutions.SkuParser.Api/Models/ProductLine.cs
Normal file
7
RhSolutions.SkuParser.Api/Models/ProductLine.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace RhSolutions.SkuParser.Models;
|
||||
|
||||
public enum ProductLine
|
||||
{
|
||||
RAUTITAN,
|
||||
RAUTHERMS
|
||||
}
|
@ -1,11 +1,15 @@
|
||||
using RhSolutions.SkuParser.Abstractions;
|
||||
using RhSolutions.SkuParser.Api.Services;
|
||||
using RhSolutions.SkuParser.Services;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
builder.Configuration
|
||||
.AddJsonFile("appsettings.json");
|
||||
builder.Services
|
||||
.AddKeyedScoped<ISkuParser, CommonCsvParser>("text/csv")
|
||||
.AddKeyedScoped<ISkuParser, CommonExcelParser>("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
||||
.AddKeyedScoped<ISkuParser, CommonExcelParser>("application/vnd.ms-excel.sheet.macroenabled.12");
|
||||
.AddKeyedScoped<ISkuParser, CommonExcelParser>("application/vnd.ms-excel.sheet.macroenabled.12")
|
||||
.AddKeyedScoped<ISkuParser, BsExcelParser>("BS");
|
||||
builder.Services.AddControllers();
|
||||
|
||||
var app = builder.Build();
|
||||
|
72
RhSolutions.SkuParser.Api/Services/BsExcelParser.cs
Normal file
72
RhSolutions.SkuParser.Api/Services/BsExcelParser.cs
Normal file
@ -0,0 +1,72 @@
|
||||
using System.Data;
|
||||
using ClosedXML.Excel;
|
||||
using RhSolutions.SkuParser.Abstractions;
|
||||
using RhSolutions.SkuParser.Models;
|
||||
|
||||
namespace RhSolutions.SkuParser.Api.Services;
|
||||
|
||||
public class BsExcelParser : ISkuParser
|
||||
{
|
||||
private IConfiguration configuration;
|
||||
// private Dictionary<Product, double> result;
|
||||
private const int rowsLookupCount = 20;
|
||||
private const decimal vat = 1.2M;
|
||||
public BsExcelParser(IConfiguration configuration)
|
||||
{
|
||||
this.configuration = configuration;
|
||||
// result = new();
|
||||
}
|
||||
|
||||
public Dictionary<Product, double> ParseProducts(IFormFile file)
|
||||
{
|
||||
using XLWorkbook workbook = new(file.OpenReadStream());
|
||||
IXLWorksheet ws = workbook.Worksheet(1);
|
||||
var headers = configuration.GetSection("Headers");
|
||||
ws.AutoFilter.Clear();
|
||||
var cells = configuration.GetSection("Headers")
|
||||
.GetChildren()
|
||||
.ToDictionary(x => x.Path, x => ws.Range(1, 1, rowsLookupCount, ws.LastCellUsed().Address.ColumnNumber)
|
||||
.Search(x.Value)
|
||||
.FirstOrDefault())
|
||||
.OrderBy(x => x.Value?.Address.ColumnNumber ?? int.MaxValue);
|
||||
if (cells == null || cells.Any(x => x.Value == null))
|
||||
{
|
||||
throw new DataException($"В рабочей книге отсуствует таблица с необходимыми заголовками: {file.Name}");
|
||||
}
|
||||
|
||||
var firstCell = cells.First().Value;
|
||||
var lastCell = cells.Last().Value?.WorksheetColumn().LastCellUsed();
|
||||
var table = ws.Range(firstCell, lastCell).AsTable();
|
||||
var rows = table.DataRange.Rows();
|
||||
Dictionary<Product, double> result = new();
|
||||
|
||||
foreach (var row in rows.Where(r => r.Field(headers["Quantity"]).Value.IsNumber))
|
||||
{
|
||||
Product product = new()
|
||||
{
|
||||
Sku = row.Field(headers["Sku"]).GetString(),
|
||||
ProductLine = row.Field(headers["ProductLine"]).GetString() switch
|
||||
{
|
||||
"RAUTITAN" => ProductLine.RAUTITAN,
|
||||
"RAUTHERM S" => ProductLine.RAUTHERMS,
|
||||
_ => null
|
||||
},
|
||||
Name = row.Field(headers["Name"]).GetString(),
|
||||
Price = decimal.TryParse(row.Field(headers["Price"]).GetString(), out decimal value)
|
||||
? Math.Round(value * vat, 2)
|
||||
: null
|
||||
};
|
||||
|
||||
double quantity = double.TryParse(row.Field(headers["Quantity"]).GetString(), out double q) ? q : 0;
|
||||
if (result.ContainsKey(product))
|
||||
{
|
||||
result[product] += quantity;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Add(product, quantity);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
@ -5,5 +5,12 @@
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
"AllowedHosts": "*",
|
||||
"Headers": {
|
||||
"ProductLine": "Программа",
|
||||
"Sku": "Актуальный материал",
|
||||
"Name": "Наименование",
|
||||
"Quantity": "Кол-во",
|
||||
"Price": "Цена брутто \nЕВРО\nбез НДС"
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user