using ClosedXML.Excel; using RhSolutions.Models; namespace RhSolutions.Api.Services { public class ClosedXMLParser : IPricelistParser { public List GetProducts(HttpContext context) { using (var memoryStream = new MemoryStream()) { if (context == null) { return new List(); } context.Request.Body.CopyToAsync(memoryStream).GetAwaiter().GetResult(); List products = new(); using (var wb = new XLWorkbook(memoryStream)) { var table = GetTable(wb); var rows = table.DataRange.Rows(); foreach (var row in rows) { if (ProductSku.TryParse(row.Field("Актуальный материал") .GetString(), out _)) { products.Add(ParseRow(row)); } } } return products; } } private IXLTable GetTable(XLWorkbook wb) { var ws = wb.Worksheets.First(); ws.AutoFilter.IsEnabled = false; try { var firstCellAddress = ws.Search("Программа", System.Globalization.CompareOptions.IgnoreCase) .First() .Address; var lastCellAddress = ws.LastCellUsed().Address; return ws.Range(firstCellAddress, lastCellAddress).AsTable(); } catch (Exception ex) { throw new Exception($"Exception on parsing {ws.Name}:\n{ex.Message}"); } } private Product ParseRow(IXLTableRow row) { string productLine = row.Field("Программа") .GetString(); string productName = row.Field("Наименование") .GetString() .Split('\n') .First(); ProductSku.TryParse(row.Field("Актуальный материал") .GetString(), out IEnumerable productSkus); ProductSku.TryParse(row.Field("Прежний материал") .GetString(), out IEnumerable deprecatedSkus); string measureField = new string(row.Field("Ед. изм.") .GetString() .ToLower() .Where(c => char.IsLetterOrDigit(c)) .ToArray()); Measure productMeasure; switch (measureField) { case "кг": productMeasure = Measure.Kg; break; case "м": productMeasure = Measure.M; break; case "м2": productMeasure = Measure.M2; break; case "шт": productMeasure = Measure.P; break; default: throw new ArgumentException(); } string shippingSizeField = row.Field("Единица поставки") .GetString(); if (!double.TryParse(shippingSizeField, out double productWarehouseCount)) { productWarehouseCount = 0.0; } string onWarehouseField = row.Field("Складская программа") .GetString(); bool IsOnWarehouse; switch (onWarehouseField) { case "x": IsOnWarehouse = true; break; case "под заказ": IsOnWarehouse = false; break; default: IsOnWarehouse = false; break; } string priceField = row.Field("Цена брутто \nЕВРО\nбез НДС") .GetString(); if (!decimal.TryParse(priceField, out decimal price)) { price = 0.0M; } return new Product(productSkus.First()) { ProductLines = new List() { productLine }, Name = productName, DeprecatedSkus = deprecatedSkus.ToList(), ProductMeasure = productMeasure, DeliveryMakeUp = productWarehouseCount, IsOnWarehouse = IsOnWarehouse, Price = price }; } } }