256 lines
7.6 KiB
C#
256 lines
7.6 KiB
C#
#if !NET472
|
||
using System.Runtime.Versioning;
|
||
using RhSolutions.Tools;
|
||
#endif
|
||
|
||
|
||
namespace RhSolutions.Services;
|
||
|
||
#if !NET472
|
||
[SupportedOSPlatform("windows")]
|
||
#endif
|
||
public class ExcelWriter : IWriter, IDisposable
|
||
{
|
||
private readonly Application _application;
|
||
private Worksheet _worksheet;
|
||
private readonly ResultBar _resultBar;
|
||
private readonly Dictionary<string, string> _headers;
|
||
private readonly string _pricelistPath;
|
||
private ProgressBar _progressBar;
|
||
|
||
private Range _amountCell,
|
||
_skuCell,
|
||
_programLineCell,
|
||
_nameCell,
|
||
_oldSkuCell;
|
||
|
||
public ExcelWriter(Application application, IAddInConfiguration configuration)
|
||
{
|
||
_application = application;
|
||
_pricelistPath = configuration.GetPriceListPath();
|
||
_resultBar = new();
|
||
_headers = configuration.GetPriceListHeaders();
|
||
}
|
||
|
||
public void WriteProducts(Dictionary<Product, double> products)
|
||
{
|
||
WriteProducts(new[] { (string.Empty, products) });
|
||
}
|
||
|
||
public void WriteProducts(IEnumerable<(string, Dictionary<Product, double>)> products)
|
||
{
|
||
_worksheet = OpenNewPrice();
|
||
|
||
if (!_worksheet.IsValidSource())
|
||
{
|
||
_application.ActiveWorkbook.Close();
|
||
throw new ArgumentException(
|
||
$"Целевой файл {_application.ActiveWorkbook.Name} не является прайс-листом.");
|
||
}
|
||
|
||
_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"]);
|
||
|
||
_progressBar = new("Заполняю строки...", products
|
||
.Select(p => p.Item2)
|
||
.Sum(set => set.Count));
|
||
|
||
if (products.Count() == 1)
|
||
{
|
||
foreach (var kvp in products.First().Item2)
|
||
{
|
||
FillPositionAmountToColumns(kvp, _amountCell.Column);
|
||
_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];
|
||
newColumnHeader.Value2 = $"{product.Item1}";
|
||
newColumnHeader.WrapText = true;
|
||
|
||
foreach (var kvp in product.Item2)
|
||
{
|
||
FillPositionAmountToColumns(kvp, _amountCell.Column - 1, _amountCell.Column);
|
||
_progressBar.Update();
|
||
}
|
||
}
|
||
|
||
FilterByAmount();
|
||
_resultBar.Update();
|
||
}
|
||
}
|
||
|
||
private Worksheet OpenNewPrice()
|
||
{
|
||
if (_application.Workbooks
|
||
.Cast<Workbook>()
|
||
.FirstOrDefault(w => w.FullName == _pricelistPath) != null)
|
||
{
|
||
throw new ArgumentException("Шаблонный файл редактируется в другом месте");
|
||
}
|
||
|
||
return _application.Workbooks.Open(_pricelistPath, null, true).ActiveSheet;
|
||
}
|
||
|
||
private void FillPositionAmountToColumns(KeyValuePair<Product, double> positionAmount, params int[] columns)
|
||
{
|
||
Range worksheetCells = _worksheet.Cells;
|
||
Range skuColumn = _skuCell.EntireColumn;
|
||
|
||
int? row = GetPositionRow(skuColumn, positionAmount.Key.ProductSku.ToString(), positionAmount.Key.ProductLines.First());
|
||
|
||
if (row != null)
|
||
{
|
||
foreach (int column in columns)
|
||
{
|
||
Range cell = worksheetCells[row, column];
|
||
cell.AddValue(positionAmount.Value);
|
||
}
|
||
|
||
_resultBar.IncrementSuccess();
|
||
return;
|
||
}
|
||
|
||
if (_oldSkuCell != null)
|
||
{
|
||
row = GetPositionRow(_oldSkuCell.EntireColumn, positionAmount.Key.ProductSku.ToString(), positionAmount.Key.ProductLines.First());
|
||
|
||
if (row != null)
|
||
{
|
||
foreach (int column in columns)
|
||
{
|
||
Range cell = worksheetCells[row, column];
|
||
cell.AddValue(positionAmount.Value);
|
||
}
|
||
|
||
_resultBar.IncrementReplaced();
|
||
return;
|
||
}
|
||
}
|
||
|
||
string sku = positionAmount.Key.ProductSku.Article;
|
||
row = GetPositionRow(skuColumn, sku, positionAmount.Key.ProductLines.First());
|
||
|
||
if (row != null)
|
||
{
|
||
foreach (int column in columns)
|
||
{
|
||
Range cell = worksheetCells[row, column];
|
||
cell.AddValue(positionAmount.Value);
|
||
}
|
||
|
||
_resultBar.IncrementReplaced();
|
||
return;
|
||
}
|
||
|
||
FillMissing(positionAmount, columns);
|
||
_resultBar.IncrementNotFound();
|
||
}
|
||
|
||
private void FillMissing(KeyValuePair<Product, double> positionAmount, params int[] columns)
|
||
{
|
||
Range worksheetCells = _worksheet.Cells;
|
||
Range worksheetRows = _worksheet.Rows;
|
||
int skuColumn = _skuCell.Column;
|
||
int groupColumn = _programLineCell.Column;
|
||
int nameColumn = _nameCell.Column;
|
||
|
||
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 = positionAmount.Key.ProductLines.First();
|
||
worksheetCells[row, nameColumn].Value2 = positionAmount.Key.Name;
|
||
|
||
if (_oldSkuCell != null)
|
||
{
|
||
worksheetCells[row, skuColumn].Value2 = "Не найден";
|
||
worksheetCells[row, _oldSkuCell.Column].Value2 = positionAmount.Key.ProductSku;
|
||
}
|
||
|
||
else
|
||
{
|
||
worksheetCells[row, skuColumn].Value2 = positionAmount.Key.ProductSku;
|
||
}
|
||
|
||
foreach (int column in columns)
|
||
{
|
||
Range cell = worksheetCells[row, column];
|
||
cell.AddValue(positionAmount.Value);
|
||
}
|
||
}
|
||
|
||
private int? GetPositionRow(Range range, string sku, string group)
|
||
{
|
||
Range found = range.Find(sku);
|
||
string foundGroupValue;
|
||
|
||
if (found == null)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
int firstFoundRow = found.Row;
|
||
|
||
if (string.IsNullOrEmpty(group))
|
||
{
|
||
return found.Row;
|
||
}
|
||
|
||
while (true)
|
||
{
|
||
foundGroupValue = _worksheet.Cells[found.Row, _programLineCell.Column].Value2.ToString();
|
||
|
||
if (group.Equals(foundGroupValue))
|
||
{
|
||
return found.Row;
|
||
}
|
||
|
||
found = range.FindNext(found);
|
||
|
||
if (found.Row == firstFoundRow)
|
||
{
|
||
return null;
|
||
}
|
||
}
|
||
}
|
||
|
||
private void FilterByAmount()
|
||
{
|
||
AutoFilter filter = _worksheet.AutoFilter;
|
||
int startColumn = filter.Range.Column;
|
||
|
||
filter.Range.AutoFilter(_amountCell.Column - startColumn + 1, "<>0", XlAutoFilterOperator.xlAnd, "<>");
|
||
_worksheet.Range["A1"].Activate();
|
||
}
|
||
|
||
public void Dispose()
|
||
{
|
||
_progressBar?.Dispose();
|
||
_resultBar?.Dispose();
|
||
}
|
||
}
|