aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSerghei Cebotari <serghei@cebotari.ru>2025-01-14 14:01:01 +0000
committerSerghei Cebotari <serghei@cebotari.ru>2025-01-14 14:01:01 +0000
commita542bfb7f4ceee8b49cf8fcadf64ffb72cc97da5 (patch)
tree5e9563638eb09a4c3a1c717a6f238139fc66dc53
parente2ac0c46c1a1085ab7e7597e463e73f371ce2791 (diff)
Common Parsing Method
-rw-r--r--RhSolutions.SkuParser.Api/Abstractions/ISkuParser.cs8
-rw-r--r--RhSolutions.SkuParser.Api/Controllers/CommonParseController.cs (renamed from RhSolutions.SkuParser.Api/Controllers/ProductsController.cs)18
-rw-r--r--RhSolutions.SkuParser.Api/Program.cs7
-rw-r--r--RhSolutions.SkuParser.Api/Services/CommonCsvParser.cs (renamed from RhSolutions.SkuParser.Api/Services/CsvParser.cs)10
-rw-r--r--RhSolutions.SkuParser.Api/Services/CommonExcelParser.cs (renamed from RhSolutions.SkuParser.Api/Services/ExcelParser.cs)28
-rw-r--r--RhSolutions.SkuParser.Api/Services/ISkuParser.cs7
-rw-r--r--RhSolutions.SkuParser.Tests/ExcelParserTests.cs28
7 files changed, 56 insertions, 50 deletions
diff --git a/RhSolutions.SkuParser.Api/Abstractions/ISkuParser.cs b/RhSolutions.SkuParser.Api/Abstractions/ISkuParser.cs
new file mode 100644
index 0000000..a1b2fbf
--- /dev/null
+++ b/RhSolutions.SkuParser.Api/Abstractions/ISkuParser.cs
@@ -0,0 +1,8 @@
+using RhSolutions.SkuParser.Models;
+
+namespace RhSolutions.SkuParser.Abstractions;
+
+public interface ISkuParser
+{
+ public Dictionary<Product, double> ParseProducts(IFormFile file);
+}
diff --git a/RhSolutions.SkuParser.Api/Controllers/ProductsController.cs b/RhSolutions.SkuParser.Api/Controllers/CommonParseController.cs
index 77b277b..c819851 100644
--- a/RhSolutions.SkuParser.Api/Controllers/ProductsController.cs
+++ b/RhSolutions.SkuParser.Api/Controllers/CommonParseController.cs
@@ -1,16 +1,16 @@
using Microsoft.AspNetCore.Mvc;
using RhSolutions.SkuParser.Models;
-using RhSolutions.SkuParser.Services;
+using RhSolutions.SkuParser.Abstractions;
namespace RhSolutions.SkuParser.Controllers;
[ApiController]
[Route("/api/[controller]")]
-public class ProductsController : ControllerBase
+public class CommonParseController : ControllerBase
{
private IServiceProvider _provider;
private Dictionary<Product, double> _result;
- public ProductsController(IServiceProvider provider)
+ public CommonParseController(IServiceProvider provider)
{
_provider = provider;
_result = new();
@@ -25,16 +25,16 @@ public class ProductsController : ControllerBase
foreach (var file in files)
{
ISkuParser parser = _provider.GetRequiredKeyedService<ISkuParser>(file.ContentType);
- IEnumerable<ProductQuantity> productQuantities = parser.ParseProducts(file);
- foreach (ProductQuantity pq in productQuantities)
+ var dict = parser.ParseProducts(file);
+ foreach (var kvp in dict)
{
- if (_result.ContainsKey(pq.Product))
+ if (_result.ContainsKey(kvp.Key))
{
- _result[pq.Product] += pq.Quantity;
+ _result[kvp.Key] += kvp.Value;
}
else
{
- _result.Add(pq.Product, pq.Quantity);
+ _result.Add(kvp.Key, kvp.Value);
}
}
}
@@ -43,6 +43,6 @@ public class ProductsController : ControllerBase
{
return BadRequest(error: $"{ex.Message}\n\n{ex.Source}\n{ex.StackTrace}");
}
- return new JsonResult(_result.Select(x => new { Sku = x.Key.ToString(), Quantity = x.Value }));
+ return new JsonResult(_result.Select(x => new { x.Key.Sku, x.Value }));
}
} \ No newline at end of file
diff --git a/RhSolutions.SkuParser.Api/Program.cs b/RhSolutions.SkuParser.Api/Program.cs
index e0acec8..13e0b90 100644
--- a/RhSolutions.SkuParser.Api/Program.cs
+++ b/RhSolutions.SkuParser.Api/Program.cs
@@ -1,10 +1,11 @@
+using RhSolutions.SkuParser.Abstractions;
using RhSolutions.SkuParser.Services;
var builder = WebApplication.CreateBuilder(args);
builder.Services
- .AddKeyedScoped<ISkuParser, CsvParser>("text/csv")
- .AddKeyedScoped<ISkuParser, ExcelParser>("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
- .AddKeyedScoped<ISkuParser, ExcelParser>("application/vnd.ms-excel.sheet.macroenabled.12");
+ .AddKeyedScoped<ISkuParser, CommonCsvParser>("text/csv")
+ .AddKeyedScoped<ISkuParser, CommonExcelParser>("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
+ .AddKeyedScoped<ISkuParser, CommonExcelParser>("application/vnd.ms-excel.sheet.macroenabled.12");
builder.Services.AddControllers();
var app = builder.Build();
diff --git a/RhSolutions.SkuParser.Api/Services/CsvParser.cs b/RhSolutions.SkuParser.Api/Services/CommonCsvParser.cs
index 2776721..e88ba25 100644
--- a/RhSolutions.SkuParser.Api/Services/CsvParser.cs
+++ b/RhSolutions.SkuParser.Api/Services/CommonCsvParser.cs
@@ -1,6 +1,7 @@
using System.Globalization;
using CsvHelper;
using CsvHelper.Configuration;
+using RhSolutions.SkuParser.Abstractions;
using RhSolutions.SkuParser.Models;
namespace RhSolutions.SkuParser.Services;
@@ -8,9 +9,9 @@ namespace RhSolutions.SkuParser.Services;
/// <summary>
/// Парсер артикулов и их количества из файлов *.csv
/// </summary>
-public class CsvParser : ISkuParser
+public class CommonCsvParser : ISkuParser
{
- public IEnumerable<ProductQuantity> ParseProducts(IFormFile file)
+ public Dictionary<Product, double> ParseProducts(IFormFile file)
{
using StreamReader reader = new(file.OpenReadStream());
var config = new CsvConfiguration(CultureInfo.GetCultureInfo("ru-RU"))
@@ -18,7 +19,8 @@ public class CsvParser : ISkuParser
HasHeaderRecord = false,
};
using CsvReader csvReader = new(reader, config);
-
- return csvReader.GetRecords<ProductQuantity>().ToList();
+
+ return csvReader.GetRecords<ProductQuantity>()
+ .ToDictionary(pq => new Product() { Sku = pq.Product.Sku }, pq => pq.Quantity);
}
}
diff --git a/RhSolutions.SkuParser.Api/Services/ExcelParser.cs b/RhSolutions.SkuParser.Api/Services/CommonExcelParser.cs
index fec3885..206200d 100644
--- a/RhSolutions.SkuParser.Api/Services/ExcelParser.cs
+++ b/RhSolutions.SkuParser.Api/Services/CommonExcelParser.cs
@@ -1,11 +1,12 @@
using ClosedXML.Excel;
+using RhSolutions.SkuParser.Abstractions;
using RhSolutions.SkuParser.Models;
namespace RhSolutions.SkuParser.Services;
-public class ExcelParser : ISkuParser
+public class CommonExcelParser : ISkuParser
{
- public IEnumerable<ProductQuantity> ParseProducts(IFormFile file)
+ public Dictionary<Product, double> ParseProducts(IFormFile file)
{
using XLWorkbook workbook = new(file.OpenReadStream());
IXLWorksheet ws = workbook.Worksheet(1);
@@ -51,23 +52,26 @@ public class ExcelParser : ISkuParser
throw new ArgumentException($"Столбец с количеством не определен: {file.FileName}");
}
- List<ProductQuantity> result = new();
+ Dictionary<Product, double> result = new();
var rows = quantityColumn.CellsUsed().Select(x => x.Address.RowNumber);
-
+
foreach (var row in rows)
{
var quantity = quantityColumn.Cell(row).Value;
var sku = skuColumn.Cell(row).Value;
-
- if (quantity.IsNumber
- && Product.TryParse(sku.ToString(), out Product? p))
+
+ if (quantity.IsNumber
+ && Product.TryParse(sku.ToString(), out Product? p)
+ && p != null)
{
- ProductQuantity pq = new()
+ if (result.ContainsKey(p))
+ {
+ result[p] += (double)quantity;
+ }
+ else
{
- Product = p!,
- Quantity = quantity.GetNumber()
- };
- result.Add(pq);
+ result.Add(p, (double)quantity);
+ }
}
}
diff --git a/RhSolutions.SkuParser.Api/Services/ISkuParser.cs b/RhSolutions.SkuParser.Api/Services/ISkuParser.cs
deleted file mode 100644
index 4329135..0000000
--- a/RhSolutions.SkuParser.Api/Services/ISkuParser.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-using RhSolutions.SkuParser.Models;
-
-namespace RhSolutions.SkuParser.Services;
-public interface ISkuParser
-{
- public IEnumerable<ProductQuantity> ParseProducts(IFormFile file);
-}
diff --git a/RhSolutions.SkuParser.Tests/ExcelParserTests.cs b/RhSolutions.SkuParser.Tests/ExcelParserTests.cs
index 60e1e7b..781ea56 100644
--- a/RhSolutions.SkuParser.Tests/ExcelParserTests.cs
+++ b/RhSolutions.SkuParser.Tests/ExcelParserTests.cs
@@ -4,18 +4,18 @@ namespace RhSolutions.SkuParser.Tests;
public class ExcelParserTests
{
- private static readonly List<ProductQuantity> _expected = new()
+ private static readonly Dictionary<Product, double> _expected = new()
{
- new ProductQuantity() {Product= new Product() {Sku = "11303703100"}, Quantity = 2129.5},
- new ProductQuantity() {Product= new Product() {Sku = "11303803100"}, Quantity = 503},
- new ProductQuantity() {Product= new Product() {Sku = "11303903050"}, Quantity = 52},
- new ProductQuantity() {Product= new Product() {Sku = "11080011001"}, Quantity = 2154},
- new ProductQuantity() {Product= new Product() {Sku = "11080021001"}, Quantity = 134},
- new ProductQuantity() {Product= new Product() {Sku = "11080031001"}, Quantity = 6},
- new ProductQuantity() {Product= new Product() {Sku = "11080311001"}, Quantity = 462},
- new ProductQuantity() {Product= new Product() {Sku = "11080611001"}, Quantity = 38},
- new ProductQuantity() {Product= new Product() {Sku = "11080811001"}, Quantity = 24},
- new ProductQuantity() {Product= new Product() {Sku = "11080831001"}, Quantity = 2},
+ [new Product() {Sku = "11303703100"}] = 2129.5,
+ [new Product() {Sku = "11303803100"}] = 503,
+ [new Product() {Sku = "11303903050"}] = 52,
+ [new Product() {Sku = "11080011001"}] = 2154,
+ [new Product() {Sku = "11080021001"}] = 134,
+ [new Product() {Sku = "11080031001"}] = 6,
+ [new Product() {Sku = "11080311001"}] = 462,
+ [new Product() {Sku = "11080611001"}] = 38,
+ [new Product() {Sku = "11080811001"}] = 24,
+ [new Product() {Sku = "11080831001"}] = 2,
};
[TestCase("simple.xlsx")]
@@ -28,10 +28,9 @@ public class ExcelParserTests
public void XlsxTests(string filename)
{
var mockFile = FormFileUtil.GetMockFormFile(filename);
- var parser = new ExcelParser();
+ var parser = new CommonExcelParser();
var actual = parser.ParseProducts(mockFile.Object);
Assert.That(actual.Count, Is.EqualTo(_expected.Count()));
- CollectionAssert.AllItemsAreInstancesOfType(actual, typeof(ProductQuantity));
CollectionAssert.AreEqual(_expected, actual);
}
@@ -39,10 +38,9 @@ public class ExcelParserTests
public void CsvTests(string filename)
{
var mockFile = FormFileUtil.GetMockFormFile(filename);
- var parser = new CsvParser();
+ var parser = new CommonCsvParser();
var actual = parser.ParseProducts(mockFile.Object);
Assert.That(actual.Count, Is.EqualTo(_expected.Count()));
- CollectionAssert.AllItemsAreInstancesOfType(actual, typeof(ProductQuantity));
CollectionAssert.AreEqual(_expected, actual);
}
}