using System.Text.RegularExpressions; namespace RhSolutions.Services { public abstract class ExcelWriterBase { protected Application _application; protected Dictionary _headers; protected ResultBar _resultBar; protected ProgressBar _progressBar; protected Worksheet _worksheet; protected Range _amountCell; protected Range _nameCell; protected Range _oldSkuCell; protected Range _programLineCell; protected Range _skuCell; protected bool _appendValues = true; public void Dispose() { _progressBar?.Dispose(); _resultBar?.Dispose(); } public void WriteProducts(Dictionary products) { WriteProducts(new[] { (string.Empty, products) }); } public void WriteProducts(IEnumerable<(string, Dictionary)> products) { if (!_worksheet.IsValidSource()) { _application.ActiveWorkbook.Close(); throw new ArgumentException( $"Целевой файл {_application.ActiveWorkbook.Name} не является прайс-листом."); } ShowFilteredData(); _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) { FillAmounts(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) { FillAmounts(kvp, _amountCell.Column - 1, _amountCell.Column); _progressBar.Update(); } } FilterByAmount(); _resultBar.Update(); } } private void WriteOutMissing(KeyValuePair productAmount, params int[] columns) { Range worksheetCells = _worksheet.Cells; Range worksheetRows = _worksheet.Rows; int skuColumn = _skuCell.Column; int groupColumn = _programLineCell.Column; int nameColumn = _nameCell.Column; Product product = productAmount.Key; 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]; cell.AddValue(productAmount.Value); } } private void FillCells(double amount, int row, int[] columns) { foreach (int column in columns) { Range cell = _worksheet.Cells[row, column]; if (_appendValues) { cell.AddValue(amount); } else { if (amount == 0) { cell.Value2 = null; } else { cell.Value2 = amount; } } } } private void FillAmounts(KeyValuePair positionAmount, params int[] columns) { Range range = _skuCell.EntireColumn; ProductSku sku = positionAmount.Key.ProductSku; string productLine = positionAmount.Key.ProductLines.FirstOrDefault(); int? row = GetPositionRow(range, sku, productLine); if (row != null) { FillCells(positionAmount.Value, row.Value, columns); _resultBar.IncrementSuccess(); } else { if (_oldSkuCell != null) { range = _oldSkuCell.EntireColumn; row = GetPositionRow(range, sku, productLine); } if (row == null) { range = _skuCell.EntireColumn; row = GetPositionRow(range, sku, productLine, true); } if (row != null) { Range nameCell = _worksheet.Cells[row, _nameCell.Column]; if (!Regex.IsMatch(nameCell.Value2, @"арт. \d{11}")) { nameCell.AddValue($"(замена арт. {sku})"); } FillCells(positionAmount.Value, row.Value, columns); _resultBar.IncrementReplaced(); } else { WriteOutMissing(positionAmount, columns); _resultBar.IncrementNotFound(); } } } private void FilterByAmount() { if (_worksheet.AutoFilterMode) { AutoFilter filter = _worksheet.AutoFilter; int startColumn = filter.Range.Column; filter.Range.AutoFilter(_amountCell.Column - startColumn + 1, "<>0", XlAutoFilterOperator.xlAnd, "<>"); _worksheet.Range["A1"].Activate(); } } private void ShowFilteredData() { if (_worksheet.AutoFilterMode) { AutoFilter filter = _worksheet.AutoFilter; filter.ShowAllData(); } } 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; } } } } } }