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
|
|||
|
};
|
|||
|
}
|
|||
|
}
|
|||
|
}
|