139 lines
3.3 KiB
C#
139 lines
3.3 KiB
C#
using ClosedXML.Excel;
|
||
using RhSolutions.Api.Models;
|
||
|
||
namespace RhSolutions.Api.Services
|
||
{
|
||
public class ClosedXMLParser : IPricelistParser
|
||
{
|
||
public async IAsyncEnumerable<Product> 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<Sku> 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<Sku> productSkus);
|
||
Sku.TryParse(row.Field("Прежний материал")
|
||
.GetString(), out IEnumerable<Sku> 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
|
||
};
|
||
}
|
||
}
|
||
} |