From 21fb58744cac0f37bb3ab9d6a69e402ebbcd5565 Mon Sep 17 00:00:00 2001 From: Sergey Chebotar Date: Mon, 22 May 2023 10:24:18 +0300 Subject: [PATCH] Implement Magic Reader --- RhSolutions.AddIn/Services/MagicReader.cs | 190 ++++++++++++++++++++ RhSolutions.AddIn/Services/ReaderFactory.cs | 1 + RhSolutions.Tests/CanDoMagic.cs | 6 +- 3 files changed, 194 insertions(+), 3 deletions(-) create mode 100644 RhSolutions.AddIn/Services/MagicReader.cs diff --git a/RhSolutions.AddIn/Services/MagicReader.cs b/RhSolutions.AddIn/Services/MagicReader.cs new file mode 100644 index 0000000..d0021cb --- /dev/null +++ b/RhSolutions.AddIn/Services/MagicReader.cs @@ -0,0 +1,190 @@ +using System.IO; + +namespace RhSolutions.Services; + +public class MagicReader : IReader +{ + private readonly Application _application; + private ProgressBar _progressBar; + + public MagicReader(Application application) + { + _application = application; + } + + public Dictionary ReadProducts(Range range) + { + _progressBar = new("Ищу колонки со значениями", range.Columns.Count); + int? productColumnIndex = null; + List<(int, double)> amountColumnIndeces = new(); + + for (int column = 1; column < range.Columns.Count + 1; column++) + { + _progressBar.Update(); + if (productColumnIndex == null && IsProductColumn(range.Columns[column])) + { + productColumnIndex = column; + } + else if (IsAmountColumn(range.Columns[column], out double average)) + { + amountColumnIndeces.Add((column, average)); + } + } + + if (productColumnIndex == null || amountColumnIndeces.Count == 0) + { + throw new ArgumentException("Колонка с артикулом или количеством не определена"); + } + + else if (amountColumnIndeces.Count == 1) + { + return GetDictionaryFromColumns(range.Columns[productColumnIndex], + range.Columns[amountColumnIndeces.First().Item1]); + } + + else + { + int amountColumnIndex = amountColumnIndeces + .Where(i => i.Item2 < 30000 && i.Item2 > 0) + .OrderByDescending(i => i.Item2).First().Item1; + return GetDictionaryFromColumns(range.Columns[productColumnIndex], + range.Columns[amountColumnIndex]); + } + } + + private bool IsProductColumn(Range column) + { + int successCounter = 0; + for (int row = 1; row < column.Rows.Count + 1; row++) + { + if (ProductSku.TryParse(column.Cells[row, 1].Value2.ToString(), out IEnumerable skus)) + { + successCounter++; + } + + if (successCounter > 2) + { + return true; + } + } + + return successCounter > 0; + } + + private bool IsAmountColumn(Range column, out double average) + { + object[,] cells = column.Value2; + int successCounter = 0; + average = 0.0; + + for (int row = 1; row < column.Rows.Count + 1; row++) + { + object currentCell = cells[row, 1]; + if (currentCell == null) + { + continue; + } + double value = 0.0; + + if (currentCell.GetType() == typeof(double)) + { + value = (double)currentCell; + } + else if (currentCell.GetType() == typeof(string)) + { + double.TryParse((string)currentCell, out value); + } + + if (value != 0.0) + { + successCounter++; + average += value; + } + } + if (successCounter > 0) + { + average /= successCounter; + } + + return successCounter > 0; + } + + private Dictionary GetDictionaryFromColumns(Range productColumn, Range amountColumn) + { + Dictionary result = new(); + + for (int row = 1; row < productColumn.Rows.Count + 1; row++) + { + object[,] cells = amountColumn.Value2; + object currentCell = cells[row, 1]; + double amountValue = 0.0; + if (ProductSku.TryParse(productColumn.Cells[row, 1].Value2.ToString(), out IEnumerable skus) && + currentCell != null) + { + Product p = new(skus.First()) + { + Name = "Распознанный артикул" + }; + + if (currentCell.GetType() == typeof(double)) + { + amountValue = (double)currentCell; + } + else if (currentCell.GetType() == typeof(string)) + { + double.TryParse((string)currentCell, out amountValue); + } + + if (result.ContainsKey(p)) + { + result[p] += amountValue; + } + else + { + result.Add(p, amountValue); + } + } + } + return result; + } + + public List<(string, Dictionary)> ReadProducts(IEnumerable worksheets) + { + List<(string, Dictionary)> result = new(); + foreach (Worksheet worksheet in worksheets) + { + string wbName = Path.GetFileNameWithoutExtension( + worksheet.Parent.Name); + Range range = worksheet.UsedRange; + var productsDict = ReadProducts(range); + result.Add((wbName, productsDict)); + } + return result; + } + + public List<(string, Dictionary)> ReadProducts(string[] files) + { + _progressBar = new("Открываю исходные файлы...", files.Length); + List worksheets = new(); + + _application.ScreenUpdating = false; + foreach (string file in files) + { + Workbook wb = _application.Workbooks.Open(file); + worksheets.Add(wb.ActiveSheet); + _progressBar.Update(); + } + _application.ScreenUpdating = true; + var result = ReadProducts(worksheets); + foreach (var ws in worksheets) + { + ws.Parent.Close(); + } + return result; + } + + public void Dispose() + { + _progressBar?.Dispose(); + } +} \ No newline at end of file diff --git a/RhSolutions.AddIn/Services/ReaderFactory.cs b/RhSolutions.AddIn/Services/ReaderFactory.cs index 390ccd0..d2a4b63 100644 --- a/RhSolutions.AddIn/Services/ReaderFactory.cs +++ b/RhSolutions.AddIn/Services/ReaderFactory.cs @@ -13,6 +13,7 @@ public class ReaderFactory { return readerName switch { + "Magic" => (IReader)_serviceProvider.GetService(typeof(MagicReader)), "Excel" => (IReader)_serviceProvider.GetService(typeof(ExcelReader)), _ => (IReader)_serviceProvider.GetService(typeof(ExcelReader)) }; diff --git a/RhSolutions.Tests/CanDoMagic.cs b/RhSolutions.Tests/CanDoMagic.cs index 7988724..d3a0bf9 100644 --- a/RhSolutions.Tests/CanDoMagic.cs +++ b/RhSolutions.Tests/CanDoMagic.cs @@ -8,15 +8,15 @@ namespace RhSolutions.Tests; public class CanDoMagic : IDisposable { private RhSolutionsAddIn _addIn; - private ReaderFactory _readerFactory; + //private ReaderFactory _readerFactory; private IReader _reader; public CanDoMagic() { _addIn = new(); _addIn.AutoOpen(); - _readerFactory = RhSolutionsAddIn.ServiceProvider.GetRequiredService(); - _reader = _readerFactory.GetReader("Magic"); + //_readerFactory = RhSolutionsAddIn.ServiceProvider.GetRequiredService(); + _reader = new MagicReader(Util.Application); } [ExcelFact(Workbook = @"..\..\..\TestWorkbooks\TestSpecificationMagic.xlsx")]