using ClosedXML.Excel; using RhSolutions.Api.Models; namespace RhSolutions.Api.Services { public class ClosedXMLParser : IPricelistParser { public async IAsyncEnumerable GetProducts(HttpContext context) { using (var memoryStream = new MemoryStream()) { if (context == null) { yield break; } await context.Request.Body.CopyToAsync(memoryStream); using (var wb = new XLWorkbook(memoryStream)) { var table = GetTable(wb); var rows = table.DataRange.Rows(); var enumerator = rows.GetEnumerator(); while (enumerator.MoveNext()) { if (Sku.TryParse(enumerator.Current.Field("Актуальный материал") .GetString(), out IEnumerable skus)) { yield return ParseRow(enumerator.Current); } } yield break; } } } 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(); Sku.TryParse(row.Field("Актуальный материал") .GetString(), out IEnumerable productSkus); Sku.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 = null; break; } string priceField = row.Field("Цена брутто \nЕВРО\nбез НДС") .GetString(); if (!decimal.TryParse(priceField, out decimal price)) { price = 0.0M; } return new Product { ProductLine = productLine, Name = productName, ProductSku = productSkus.First().Id, DeprecatedSkus = deprecatedSkus.Select(s => s.Id).ToList(), ProductMeasure = productMeasure, DeliveryMakeUp = productWarehouseCount, IsOnWarehouse = IsOnWarehouse, Price = price }; } } }