2023-06-20 07:25:44 +03:00
|
|
|
|
using System.Text.RegularExpressions;
|
|
|
|
|
|
|
|
|
|
namespace RhSolutions.Services
|
|
|
|
|
{
|
|
|
|
|
public abstract class ExcelWriterBase
|
|
|
|
|
{
|
|
|
|
|
protected Application _application;
|
|
|
|
|
protected Dictionary<string, string> _headers;
|
|
|
|
|
protected ResultBar _resultBar;
|
|
|
|
|
protected ProgressBar _progressBar;
|
|
|
|
|
|
2023-06-20 08:14:01 +03:00
|
|
|
|
protected Worksheet _worksheet;
|
2023-06-20 07:25:44 +03:00
|
|
|
|
protected Range _amountCell;
|
|
|
|
|
protected Range _nameCell;
|
|
|
|
|
protected Range _oldSkuCell;
|
|
|
|
|
protected Range _programLineCell;
|
|
|
|
|
protected Range _skuCell;
|
2023-06-20 08:14:01 +03:00
|
|
|
|
|
|
|
|
|
protected bool _appendValues = true;
|
2023-06-20 07:25:44 +03:00
|
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
|
|
|
|
_progressBar?.Dispose();
|
|
|
|
|
_resultBar?.Dispose();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void WriteProducts(Dictionary<Product, double> products)
|
|
|
|
|
{
|
|
|
|
|
WriteProducts(new[] { (string.Empty, products) });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void WriteProducts(IEnumerable<(string, Dictionary<Product, double>)> products)
|
|
|
|
|
{
|
2023-10-17 21:22:42 +03:00
|
|
|
|
if (!_worksheet.IsValidSource())
|
2023-06-20 07:25:44 +03:00
|
|
|
|
{
|
|
|
|
|
_application.ActiveWorkbook.Close();
|
|
|
|
|
throw new ArgumentException(
|
|
|
|
|
$"Целевой файл {_application.ActiveWorkbook.Name} не является прайс-листом.");
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-20 09:51:25 +03:00
|
|
|
|
ShowFilteredData();
|
|
|
|
|
|
2023-10-17 21:22:42 +03:00
|
|
|
|
_amountCell = _worksheet.Cells.Find(_headers["Amount"]);
|
|
|
|
|
_skuCell = _worksheet.Cells.Find(_headers["Sku"]);
|
|
|
|
|
_programLineCell = _worksheet.Cells.Find(_headers["ProductLine"]);
|
|
|
|
|
_nameCell = _worksheet.Cells.Find(_headers["Name"]);
|
|
|
|
|
_oldSkuCell = _worksheet.Cells.Find(_headers["OldSku"]);
|
2023-06-20 07:25:44 +03:00
|
|
|
|
|
|
|
|
|
_progressBar = new("Заполняю строки...", products
|
|
|
|
|
.Select(p => p.Item2)
|
|
|
|
|
.Sum(set => set.Count));
|
|
|
|
|
|
|
|
|
|
if (products.Count() == 1)
|
|
|
|
|
{
|
|
|
|
|
foreach (var kvp in products.First().Item2)
|
|
|
|
|
{
|
2023-06-20 08:14:01 +03:00
|
|
|
|
FillAmounts(kvp, _amountCell.Column);
|
2023-06-20 07:25:44 +03:00
|
|
|
|
_progressBar.Update();
|
|
|
|
|
}
|
|
|
|
|
FilterByAmount();
|
|
|
|
|
_resultBar.Update();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
foreach (var product in products)
|
|
|
|
|
{
|
|
|
|
|
_worksheet.Columns[_amountCell.Column]
|
|
|
|
|
.EntireColumn
|
|
|
|
|
.Insert(XlInsertShiftDirection.xlShiftToRight, XlInsertFormatOrigin.xlFormatFromRightOrBelow);
|
|
|
|
|
|
|
|
|
|
Range newColumnHeader = _worksheet.Cells[_amountCell.Row, _amountCell.Column - 1];
|
2024-05-27 23:44:59 +03:00
|
|
|
|
newColumnHeader.NumberFormat = "@";
|
2023-06-20 07:25:44 +03:00
|
|
|
|
newColumnHeader.Value2 = $"{product.Item1}";
|
|
|
|
|
newColumnHeader.WrapText = true;
|
|
|
|
|
|
|
|
|
|
foreach (var kvp in product.Item2)
|
|
|
|
|
{
|
2023-06-20 08:14:01 +03:00
|
|
|
|
FillAmounts(kvp, _amountCell.Column - 1, _amountCell.Column);
|
2023-06-20 07:25:44 +03:00
|
|
|
|
_progressBar.Update();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FilterByAmount();
|
|
|
|
|
_resultBar.Update();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-20 08:14:01 +03:00
|
|
|
|
private void WriteOutMissing(KeyValuePair<Product, double> productAmount, params int[] columns)
|
2023-06-20 07:25:44 +03:00
|
|
|
|
{
|
|
|
|
|
Range worksheetCells = _worksheet.Cells;
|
|
|
|
|
Range worksheetRows = _worksheet.Rows;
|
|
|
|
|
int skuColumn = _skuCell.Column;
|
|
|
|
|
int groupColumn = _programLineCell.Column;
|
|
|
|
|
int nameColumn = _nameCell.Column;
|
2023-06-20 08:14:01 +03:00
|
|
|
|
Product product = productAmount.Key;
|
2023-06-20 07:25:44 +03:00
|
|
|
|
|
|
|
|
|
int row = worksheetCells[worksheetRows.Count, skuColumn]
|
|
|
|
|
.End[XlDirection.xlUp]
|
|
|
|
|
.Row + 1;
|
|
|
|
|
|
|
|
|
|
worksheetRows[row]
|
|
|
|
|
.EntireRow
|
|
|
|
|
.Insert(XlInsertShiftDirection.xlShiftDown, XlInsertFormatOrigin.xlFormatFromLeftOrAbove);
|
|
|
|
|
|
|
|
|
|
Range previous = worksheetRows[row - 1];
|
|
|
|
|
Range current = worksheetRows[row];
|
|
|
|
|
|
|
|
|
|
previous.Copy(current);
|
|
|
|
|
current.ClearContents();
|
|
|
|
|
|
|
|
|
|
worksheetCells[row, groupColumn].Value2 = product.ProductLines.FirstOrDefault() ?? string.Empty;
|
|
|
|
|
worksheetCells[row, nameColumn].Value2 = $"{product.Name} (не найден арт. {product.ProductSku})";
|
|
|
|
|
worksheetCells[row, skuColumn].Value2 = "???";
|
|
|
|
|
if (_oldSkuCell != null)
|
|
|
|
|
{
|
|
|
|
|
worksheetCells[row, _oldSkuCell.Column].Value2 = product.ProductSku;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (int column in columns)
|
|
|
|
|
{
|
|
|
|
|
Range cell = worksheetCells[row, column];
|
2023-06-20 08:14:01 +03:00
|
|
|
|
cell.AddValue(productAmount.Value);
|
2023-06-20 07:25:44 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-20 08:14:01 +03:00
|
|
|
|
private void FillCells(double amount, int row, int[] columns)
|
2023-06-20 07:25:44 +03:00
|
|
|
|
{
|
2023-06-20 08:14:01 +03:00
|
|
|
|
foreach (int column in columns)
|
2023-06-20 07:25:44 +03:00
|
|
|
|
{
|
2023-06-20 08:14:01 +03:00
|
|
|
|
Range cell = _worksheet.Cells[row, column];
|
|
|
|
|
if (_appendValues)
|
|
|
|
|
{
|
|
|
|
|
cell.AddValue(amount);
|
|
|
|
|
}
|
|
|
|
|
else
|
2023-06-20 07:25:44 +03:00
|
|
|
|
{
|
2023-06-21 16:45:38 +03:00
|
|
|
|
if (amount == 0)
|
|
|
|
|
{
|
|
|
|
|
cell.Value2 = null;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cell.Value2 = amount;
|
|
|
|
|
}
|
2023-06-20 07:25:44 +03:00
|
|
|
|
}
|
2023-06-20 08:14:01 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void FillAmounts(KeyValuePair<Product, double> positionAmount, params int[] columns)
|
|
|
|
|
{
|
|
|
|
|
Range range = _skuCell.EntireColumn;
|
|
|
|
|
ProductSku sku = positionAmount.Key.ProductSku;
|
|
|
|
|
string productLine = positionAmount.Key.ProductLines.FirstOrDefault();
|
2023-06-20 07:25:44 +03:00
|
|
|
|
|
2023-06-20 08:14:01 +03:00
|
|
|
|
int? row = GetPositionRow(range, sku, productLine);
|
|
|
|
|
|
|
|
|
|
if (row != null)
|
|
|
|
|
{
|
|
|
|
|
FillCells(positionAmount.Value, row.Value, columns);
|
2023-06-20 07:25:44 +03:00
|
|
|
|
_resultBar.IncrementSuccess();
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-20 08:14:01 +03:00
|
|
|
|
else
|
2023-06-20 07:25:44 +03:00
|
|
|
|
{
|
2023-06-20 08:14:01 +03:00
|
|
|
|
if (_oldSkuCell != null)
|
|
|
|
|
{
|
|
|
|
|
range = _oldSkuCell.EntireColumn;
|
|
|
|
|
row = GetPositionRow(range, sku, productLine);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (row == null)
|
|
|
|
|
{
|
|
|
|
|
range = _skuCell.EntireColumn;
|
|
|
|
|
row = GetPositionRow(range, sku, productLine, true);
|
|
|
|
|
}
|
2023-06-20 07:25:44 +03:00
|
|
|
|
|
|
|
|
|
if (row != null)
|
|
|
|
|
{
|
2023-06-20 08:14:01 +03:00
|
|
|
|
Range nameCell = _worksheet.Cells[row, _nameCell.Column];
|
2023-06-20 07:25:44 +03:00
|
|
|
|
if (!Regex.IsMatch(nameCell.Value2, @"арт. \d{11}"))
|
|
|
|
|
{
|
2023-06-20 08:14:01 +03:00
|
|
|
|
nameCell.AddValue($"(замена арт. {sku})");
|
2023-06-20 07:25:44 +03:00
|
|
|
|
}
|
|
|
|
|
|
2023-06-20 08:14:01 +03:00
|
|
|
|
FillCells(positionAmount.Value, row.Value, columns);
|
2023-06-20 07:25:44 +03:00
|
|
|
|
_resultBar.IncrementReplaced();
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-20 08:14:01 +03:00
|
|
|
|
else
|
2023-06-20 07:25:44 +03:00
|
|
|
|
{
|
2023-06-20 08:14:01 +03:00
|
|
|
|
WriteOutMissing(positionAmount, columns);
|
|
|
|
|
_resultBar.IncrementNotFound();
|
2023-06-20 07:25:44 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void FilterByAmount()
|
|
|
|
|
{
|
2023-06-20 09:51:25 +03:00
|
|
|
|
if (_worksheet.AutoFilterMode)
|
|
|
|
|
{
|
2023-06-20 07:25:44 +03:00
|
|
|
|
AutoFilter filter = _worksheet.AutoFilter;
|
|
|
|
|
int startColumn = filter.Range.Column;
|
|
|
|
|
|
|
|
|
|
filter.Range.AutoFilter(_amountCell.Column - startColumn + 1, "<>0", XlAutoFilterOperator.xlAnd, "<>");
|
|
|
|
|
_worksheet.Range["A1"].Activate();
|
|
|
|
|
}
|
2023-06-20 09:51:25 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ShowFilteredData()
|
|
|
|
|
{
|
|
|
|
|
if (_worksheet.AutoFilterMode)
|
|
|
|
|
{
|
|
|
|
|
AutoFilter filter = _worksheet.AutoFilter;
|
|
|
|
|
filter.ShowAllData();
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-06-20 07:25:44 +03:00
|
|
|
|
|
|
|
|
|
private int? GetPositionRow(Range range, ProductSku sku, string productLine, bool justArticle = false)
|
|
|
|
|
{
|
|
|
|
|
string lookupString = justArticle ? sku.Article : sku.ToString();
|
|
|
|
|
Range found = range.Find(lookupString);
|
|
|
|
|
string foundGroupValue;
|
|
|
|
|
string foundSkuValue;
|
|
|
|
|
|
|
|
|
|
if (found == null)
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int firstFoundRow = found.Row;
|
|
|
|
|
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
|
|
|
|
foundSkuValue = _worksheet.Cells[found.Row, range.Column].Value2.ToString();
|
|
|
|
|
foundGroupValue = _worksheet.Cells[found.Row, _programLineCell.Column].Value2.ToString();
|
|
|
|
|
|
|
|
|
|
if (ProductSku.TryParse(foundSkuValue, out var skus))
|
|
|
|
|
{
|
|
|
|
|
if (skus.Any(s => s.Article == sku.Article) &&
|
|
|
|
|
(string.IsNullOrEmpty(productLine) || productLine.Equals(foundGroupValue)))
|
|
|
|
|
{
|
|
|
|
|
return found.Row;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
found = range.FindNext(found);
|
|
|
|
|
|
|
|
|
|
if (found.Row == firstFoundRow)
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
found = range.FindNext(found);
|
|
|
|
|
|
|
|
|
|
if (found.Row == firstFoundRow)
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|