Compare commits
No commits in common. "master" and "v1.6.3.0" have entirely different histories.
27
.vscode/launch.json
vendored
27
.vscode/launch.json
vendored
@ -1,27 +0,0 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": ".NET Core Launch (console)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
"program": "C:\\Program Files\\Microsoft Office\\root\\Office16\\EXCEL.EXE",
|
||||
"args": [
|
||||
"${workspaceFolder}\\RhSolutions.AddIn\\bin\\Debug\\net6.0-windows\\RhSolutions-AddIn64.xll"
|
||||
],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"console": "internalConsole",
|
||||
"stopAtEntry": false,
|
||||
"requireExactSource": false
|
||||
},
|
||||
{
|
||||
"name": ".NET Core Attach",
|
||||
"type": "coreclr",
|
||||
"request": "attach"
|
||||
}
|
||||
]
|
||||
}
|
12
.vscode/tasks.json
vendored
12
.vscode/tasks.json
vendored
@ -1,12 +0,0 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "dotnet",
|
||||
"task": "build ${workspaceFolder}\\RhSolutions.AddIn\\RhSolutions.AddIn.csproj",
|
||||
"group": "build",
|
||||
"problemMatcher": [],
|
||||
"label": "build"
|
||||
},
|
||||
]
|
||||
}
|
15
README.md
15
README.md
@ -3,24 +3,15 @@
|
||||
Помощь в обработке клиентских заявок путем поиска продукции РЕХАУ по запросу, выраженному в свободной форме, и в работе с прайс-листом BS РЕХАУ
|
||||
|
||||
## Реализованные функции
|
||||
- Поиск артикула с помощью `=RHSOLUTIONS()`
|
||||
- Экспорт массива ячеек вида "Артикул - Количество" в прайс-лист
|
||||
- Актуализация прайс-листа до последней версии
|
||||
- Объединение нескольких прайс-листов в один файл
|
||||
- Поиск пар артикул-количество в любой сторонней таблице и экспорт в таблицу заказов
|
||||
- Подбор монтажных гильз для фитингов RAUTITAN
|
||||
- Подбор ремонтных муфт по количеству трубы
|
||||
- Экспорт таблицы заказов в девятиграфку по ГОСТ
|
||||
- Сложением всех позиций по артикулам
|
||||
- С разнесением данных по колонкам в конечном файле
|
||||
|
||||
*Для работы функций "Экспорт", "Актуализация" и "Объединение" требуется указать путь к файлу пустого прайс-листа РЕХАУ*
|
||||
|
||||
## Реализованные формулы для работы с артикулами
|
||||
- ```=РЕХАУ()``` - поиск артикула РЕХАУ по произвольному запросу в сервисе [RhSolutions-Api](https://gitea.cebotari.ru/chebser/RhSolutions-Api)
|
||||
- ```=РЕХАУАРТИКУЛ()``` - экстракция артикула РЕХАУ из любой строки по регулярному выражению
|
||||
- ```=РЕХАУИМЯ()``` - поиск названия артикула по номеру
|
||||
- ```=РЕХАУЦЕНА()``` - поиск цены в евро по номеру артикула
|
||||
- ```=РЕХАУЦЕНАРУБ()``` - поиск цены в рублях по номеру артикула и курсу ЦБ на любую дату
|
||||
- ```=КУРСЕВРО()``` - курс евро ЦБ на дату
|
||||
|
||||
## Установка
|
||||
1. Скопировать файл плагина в папку
|
||||
```
|
||||
|
@ -1,27 +0,0 @@
|
||||
namespace RhSolutions.AddIn;
|
||||
|
||||
public static class CurrencyFunctions
|
||||
{
|
||||
private static readonly ICurrencyClient currencyClient =
|
||||
RhSolutionsAddIn.ServiceProvider.GetRequiredService<ICurrencyClient>();
|
||||
|
||||
[ExcelFunction(Name = "КУРСЕВРО")]
|
||||
public static object GetEuroCurrencyRate(double dateField)
|
||||
{
|
||||
DateTime date = dateField == 0 ? DateTime.Today : DateTime.FromOADate(dateField);
|
||||
var functionName = nameof(GetEuroCurrencyRate);
|
||||
var parameters = new object[] { date };
|
||||
|
||||
var exchangeRate = ExcelAsyncUtil.RunTask(functionName, parameters, async () =>
|
||||
{
|
||||
var requestResult = await currencyClient.GetExchangeRate(date); return requestResult ?? -1m;
|
||||
});
|
||||
|
||||
if (exchangeRate is not decimal)
|
||||
{
|
||||
return "Загрузка...";
|
||||
}
|
||||
|
||||
return (decimal)exchangeRate < 0 ? ExcelError.ExcelErrorNA : exchangeRate;
|
||||
}
|
||||
}
|
16
RhSolutions.AddIn/AddIn/ResetBarFunction.cs
Normal file
16
RhSolutions.AddIn/AddIn/ResetBarFunction.cs
Normal file
@ -0,0 +1,16 @@
|
||||
#if !NET472
|
||||
using System.Runtime.Versioning;
|
||||
#endif
|
||||
|
||||
namespace RhSolutions.AddIn;
|
||||
#if !NET472
|
||||
[SupportedOSPlatform("windows")]
|
||||
#endif
|
||||
public static class ResetBarFunction
|
||||
{
|
||||
[ExcelFunction]
|
||||
public static void StatusBarReset()
|
||||
{
|
||||
RhSolutionsAddIn.Excel.StatusBar = false;
|
||||
}
|
||||
}
|
@ -1,7 +1,13 @@
|
||||
using System.Net;
|
||||
#if !NET472
|
||||
using System.Runtime.Versioning;
|
||||
#endif
|
||||
|
||||
namespace RhSolutions.AddIn;
|
||||
|
||||
#if !NET472
|
||||
[SupportedOSPlatform("windows")]
|
||||
#endif
|
||||
public sealed class RhSolutionsAddIn : IExcelAddIn
|
||||
{
|
||||
public static Application Excel { get; private set; }
|
||||
@ -13,32 +19,18 @@ public sealed class RhSolutionsAddIn : IExcelAddIn
|
||||
IServiceCollection Services = new ServiceCollection();
|
||||
|
||||
Services.AddHttpClient()
|
||||
.AddMemoryCache()
|
||||
.AddSingleton((Application)ExcelDnaUtil.Application)
|
||||
.AddSingleton<IAddInConfiguration, AddInConfiguration>()
|
||||
.AddSingleton<IDatabaseClient, DatabaseClient>()
|
||||
.AddSingleton<ICurrencyClient, CurrencyClient>()
|
||||
.AddTransient<IFileDialog, FileDialog>();
|
||||
.AddTransient<ICurrencyClient, CurrencyClient>()
|
||||
.AddTransient<IFileDialog, FileDialog>()
|
||||
.AddTransient<IReader, ExcelReader>();
|
||||
|
||||
Services.AddSingleton<WriterFactory>();
|
||||
Services.AddTransient<NewPriceWriter>()
|
||||
.AddTransient<IWriter, NewPriceWriter>(s => s.GetService<NewPriceWriter>());
|
||||
Services.AddTransient<ExcelWriter>()
|
||||
.AddTransient<IWriter, ExcelWriter>(s => s.GetService<ExcelWriter>());
|
||||
Services.AddTransient<DxfWriter>()
|
||||
.AddTransient<IWriter, DxfWriter>(s => s.GetService<DxfWriter>());
|
||||
Services.AddTransient<CurrentPriceWriter>()
|
||||
.AddTransient<IWriter, CurrentPriceWriter>(s => s.GetService<CurrentPriceWriter>());
|
||||
|
||||
Services.AddSingleton<ReaderFactory>();
|
||||
Services.AddTransient<ExcelReader>()
|
||||
.AddTransient<IReader, ExcelReader>(s => s.GetService<ExcelReader>());
|
||||
Services.AddTransient<GuessReader>()
|
||||
.AddTransient<IReader, GuessReader>(s => s.GetService<GuessReader>());
|
||||
|
||||
Services.AddSingleton<FittingsCalculatorFactory>();
|
||||
Services.AddTransient<CouplingsCalculator>()
|
||||
.AddTransient<IFittingsCalculator, CouplingsCalculator>(s => s.GetService<CouplingsCalculator>());
|
||||
Services.AddTransient<SleevesCalculator>()
|
||||
.AddTransient<IFittingsCalculator, SleevesCalculator>(s => s.GetService<SleevesCalculator>());
|
||||
|
||||
Services.AddSingleton<ToolFactory>();
|
||||
|
||||
@ -47,10 +39,8 @@ public sealed class RhSolutionsAddIn : IExcelAddIn
|
||||
Excel = ServiceProvider.GetService<Application>();
|
||||
|
||||
EventsUtil.Initialize();
|
||||
|
||||
ServicePointManager.SecurityProtocol =
|
||||
SecurityProtocolType.Tls12;
|
||||
ServicePointManager.DefaultConnectionLimit = 50;
|
||||
}
|
||||
|
||||
public void AutoClose()
|
||||
|
186
RhSolutions.AddIn/AddIn/RhSolutionsFunction.cs
Normal file
186
RhSolutions.AddIn/AddIn/RhSolutionsFunction.cs
Normal file
@ -0,0 +1,186 @@
|
||||
#if !NET472
|
||||
using System.Runtime.Versioning;
|
||||
#endif
|
||||
|
||||
namespace RhSolutions.AddIn;
|
||||
|
||||
#if !NET472
|
||||
[SupportedOSPlatform("windows")]
|
||||
#endif
|
||||
public class RhSolutionsFunction
|
||||
{
|
||||
[ExcelFunction(Description = "Распознать артикул и попробовать найти его в прайс-листе")]
|
||||
public static object RHSOLUTIONS([ExcelArgument(Name = "\"Строка с названием материала\"")] string line)
|
||||
{
|
||||
IDatabaseClient databaseClient = RhSolutionsAddIn.ServiceProvider.GetService<IDatabaseClient>();
|
||||
|
||||
ProductSku.TryParse(line, out var skus);
|
||||
|
||||
if (ExcelAsyncUtil.Run("Database request", line, delegate
|
||||
{
|
||||
return databaseClient.GetProducts(line)
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
}) is not IEnumerable<Product> requestResult)
|
||||
{
|
||||
if (skus.Any())
|
||||
{
|
||||
return $"{skus.First()} ...";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "Загрузка...";
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (!requestResult.Any() && !skus.Any())
|
||||
{
|
||||
return ExcelError.ExcelErrorNA;
|
||||
}
|
||||
else if (!requestResult.Any())
|
||||
{
|
||||
return $"{skus.First()}";
|
||||
}
|
||||
else
|
||||
{
|
||||
var firstProduct = requestResult.First();
|
||||
return $"{firstProduct.ProductSku} {firstProduct.Name}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ExcelFunction]
|
||||
public static object РЕХАУ(string line) => RHSOLUTIONS(line);
|
||||
|
||||
[ExcelFunction]
|
||||
public static object РЕХАУАРТИКУЛ(string line)
|
||||
{
|
||||
if (ProductSku.TryParse(line, out var skus))
|
||||
{
|
||||
return skus.First().Id;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ExcelError.ExcelErrorNA;
|
||||
}
|
||||
}
|
||||
|
||||
[ExcelFunction]
|
||||
public static object РЕХАУИМЯ(string line)
|
||||
{
|
||||
if (!ProductSku.TryParse(line, out var skus))
|
||||
{
|
||||
return ExcelError.ExcelErrorNA;
|
||||
}
|
||||
else
|
||||
{
|
||||
var article = skus.First().Id;
|
||||
IDatabaseClient databaseClient = RhSolutionsAddIn.ServiceProvider.GetService<IDatabaseClient>();
|
||||
|
||||
if (ExcelAsyncUtil.Run("Database request", line, delegate
|
||||
{
|
||||
return databaseClient.GetProducts(article)
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
}) is not IEnumerable<Product> requestResult)
|
||||
{
|
||||
return "Загрузка...";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!requestResult.Any())
|
||||
{
|
||||
return ExcelError.ExcelErrorNA;
|
||||
}
|
||||
else
|
||||
{
|
||||
var firstProduct = requestResult.First();
|
||||
return firstProduct.Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ExcelFunction]
|
||||
public static object РЕХАУЦЕНА(string line)
|
||||
{
|
||||
if (!ProductSku.TryParse(line, out var skus))
|
||||
{
|
||||
return ExcelError.ExcelErrorNA;
|
||||
}
|
||||
else
|
||||
{
|
||||
var article = skus.First().Id;
|
||||
IDatabaseClient databaseClient = RhSolutionsAddIn.ServiceProvider.GetService<IDatabaseClient>();
|
||||
|
||||
if (ExcelAsyncUtil.Run("Database request", line, delegate
|
||||
{
|
||||
return databaseClient.GetProducts(article)
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
}) is not IEnumerable<Product> requestResult)
|
||||
{
|
||||
return "Загрузка...";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!requestResult.Any())
|
||||
{
|
||||
return ExcelError.ExcelErrorNA;
|
||||
}
|
||||
else
|
||||
{
|
||||
var firstProduct = requestResult.First();
|
||||
return Math.Round(firstProduct.Price * 1.2m, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ExcelFunction]
|
||||
public static object РЕХАУЦЕНАРУБ(string line, double dateField)
|
||||
{
|
||||
if (!ProductSku.TryParse(line, out var skus))
|
||||
{
|
||||
return ExcelError.ExcelErrorNA;
|
||||
}
|
||||
else
|
||||
{
|
||||
var article = skus.First().Id;
|
||||
IDatabaseClient databaseClient = RhSolutionsAddIn.ServiceProvider.GetService<IDatabaseClient>();
|
||||
ICurrencyClient currencyClient = RhSolutionsAddIn.ServiceProvider.GetRequiredService<ICurrencyClient>();
|
||||
|
||||
if (ExcelAsyncUtil.Run("Database request", line, delegate
|
||||
{
|
||||
var product = databaseClient.GetProducts(article)
|
||||
.GetAwaiter()
|
||||
.GetResult()
|
||||
.FirstOrDefault();
|
||||
|
||||
DateTime date = dateField == 0 ? DateTime.Now : DateTime.FromOADate(dateField);
|
||||
var exchangeRate = currencyClient.GetCurrencyCourse(date)
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
|
||||
return product == null ? -1m :
|
||||
product.Price * exchangeRate * 1.2m;
|
||||
}) is not decimal requestResult)
|
||||
{
|
||||
return "Загрузка...";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (requestResult < 0)
|
||||
{
|
||||
return ExcelError.ExcelErrorNA;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Math.Round(requestResult, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,156 +0,0 @@
|
||||
namespace RhSolutions.AddIn;
|
||||
|
||||
public static class RhSolutionsFunctions
|
||||
{
|
||||
private static readonly IDatabaseClient databaseClient =
|
||||
RhSolutionsAddIn.ServiceProvider.GetService<IDatabaseClient>();
|
||||
private static readonly ICurrencyClient currencyClient =
|
||||
RhSolutionsAddIn.ServiceProvider.GetRequiredService<ICurrencyClient>();
|
||||
|
||||
[ExcelFunction(Name = "РЕХАУ")]
|
||||
public static object ProductSearch(object[,] values)
|
||||
{
|
||||
List<string> strings = new();
|
||||
int rows = values.GetLength(0);
|
||||
int columns = values.GetLength(1);
|
||||
for (int row = 0; row < rows; row++)
|
||||
{
|
||||
for (int column = 0; column < columns; column++)
|
||||
{
|
||||
object value = values[row, column];
|
||||
strings.Add(value.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
string query = string.Join(" ", strings.ToArray());
|
||||
var functionName = nameof(ProductSearch);
|
||||
var parameters = new object[] { query };
|
||||
if (ExcelAsyncUtil.RunTask(functionName, parameters, async () =>
|
||||
{
|
||||
return await databaseClient.GetProducts(query);
|
||||
}) is not IEnumerable<Product> products)
|
||||
{
|
||||
return "Загрузка...";
|
||||
}
|
||||
else if (!products.Any())
|
||||
{
|
||||
return ExcelError.ExcelErrorNA;
|
||||
}
|
||||
else
|
||||
{
|
||||
var product = products.First();
|
||||
return $"{product.Id} {product.Name}";
|
||||
}
|
||||
}
|
||||
|
||||
[ExcelFunction(Name = "РЕХАУАРТИКУЛ")]
|
||||
public static object SkuSearch(string query)
|
||||
{
|
||||
if (ProductSku.TryParse(query, out var skus))
|
||||
{
|
||||
return skus.First().Id;
|
||||
}
|
||||
return ExcelError.ExcelErrorNA;
|
||||
}
|
||||
|
||||
[ExcelFunction(Name = "РЕХАУИМЯ")]
|
||||
public static object GetProductName(string query)
|
||||
{
|
||||
if (!ProductSku.TryParse(query, out var skus))
|
||||
{
|
||||
return ExcelError.ExcelErrorNA;
|
||||
}
|
||||
var article = skus.First().Id;
|
||||
var functionName = nameof(GetProductName);
|
||||
var parameters = new object[] { query };
|
||||
if (ExcelAsyncUtil.RunTask(functionName, parameters, async () =>
|
||||
{
|
||||
return await databaseClient.GetProducts(article);
|
||||
}) is not IEnumerable<Product> requestResult)
|
||||
{
|
||||
return "Загрузка...";
|
||||
}
|
||||
else if (!requestResult.Any())
|
||||
{
|
||||
return ExcelError.ExcelErrorNA;
|
||||
}
|
||||
else
|
||||
{
|
||||
var firstProduct = requestResult.First();
|
||||
return firstProduct.Name;
|
||||
}
|
||||
}
|
||||
|
||||
[ExcelFunction(Name = "РЕХАУЦЕНА")]
|
||||
public static object GetProductPrice(string query)
|
||||
{
|
||||
if (!ProductSku.TryParse(query, out var skus))
|
||||
{
|
||||
return ExcelError.ExcelErrorNA;
|
||||
}
|
||||
var article = skus.First().Id;
|
||||
var functionName = nameof(GetProductPrice);
|
||||
var parameters = new object[] { article };
|
||||
|
||||
if (ExcelAsyncUtil.RunTask(functionName, parameters, async () =>
|
||||
{
|
||||
return await databaseClient.GetProducts(article);
|
||||
}) is not IEnumerable<Product> requestResult)
|
||||
{
|
||||
return "Загрузка...";
|
||||
}
|
||||
else if (!requestResult.Any())
|
||||
{
|
||||
return ExcelError.ExcelErrorNA;
|
||||
}
|
||||
else
|
||||
{
|
||||
var firstProduct = requestResult.First();
|
||||
return Math.Round(firstProduct.Price * 1.2m, 2);
|
||||
}
|
||||
}
|
||||
|
||||
[ExcelFunction(Name = "РЕХАУЦЕНАРУБ")]
|
||||
public static object GetProductPriceRub(string query, double dateField)
|
||||
{
|
||||
if (!ProductSku.TryParse(query, out var skus))
|
||||
{
|
||||
return ExcelError.ExcelErrorNA;
|
||||
}
|
||||
var article = skus.First().Id;
|
||||
DateTime date = dateField == 0 ? DateTime.Today : DateTime.FromOADate(dateField);
|
||||
|
||||
|
||||
var functionName = nameof(GetProductPriceRub);
|
||||
var parameters = new object[] { date };
|
||||
|
||||
if (ExcelAsyncUtil.RunTask(functionName, parameters, async () =>
|
||||
{
|
||||
var requestResult = await currencyClient.GetExchangeRate(date);
|
||||
return requestResult ?? -1m;
|
||||
}) is not decimal exchangeRate)
|
||||
{
|
||||
return "Загрузка...";
|
||||
}
|
||||
|
||||
parameters = new object[] { query };
|
||||
if (ExcelAsyncUtil.RunTask(functionName, parameters, async () =>
|
||||
{
|
||||
var products = await databaseClient.GetProducts(article);
|
||||
var product = products.FirstOrDefault();
|
||||
return product == null ? -1m :
|
||||
product.Price * (decimal)exchangeRate * 1.2m;
|
||||
}) is not decimal requestResult)
|
||||
{
|
||||
return "Загрузка...";
|
||||
}
|
||||
else if (requestResult < 0 || exchangeRate < 0)
|
||||
{
|
||||
return ExcelError.ExcelErrorNA;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Math.Round(requestResult, 2);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,39 +1,36 @@
|
||||
using ExcelDna.Integration.CustomUI;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
#if! NET472
|
||||
using System.Runtime.Versioning;
|
||||
#endif
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace RhSolutions.Controllers;
|
||||
|
||||
#if !NET472
|
||||
[SupportedOSPlatform("windows")]
|
||||
#endif
|
||||
[ComVisible(true)]
|
||||
public class RibbonController : ExcelRibbon
|
||||
{
|
||||
private static IRibbonUI ribbonUi;
|
||||
private static bool _workbookIsValid;
|
||||
|
||||
public override string GetCustomUI(string RibbonID)
|
||||
{
|
||||
return @"
|
||||
<customUI onLoad='RibbonLoad' xmlns='http://schemas.microsoft.com/office/2006/01/customui' loadImage='LoadImage'>
|
||||
<customUI onLoad='RibbonLoad' xmlns='http://schemas.microsoft.com/office/2006/01/customui'>
|
||||
<ribbon>
|
||||
<tabs>
|
||||
<tab id='rau' label='RhSolutions'>
|
||||
<group id='priceList' label='Прайс-лист'>
|
||||
<button id='export' getEnabled='GetExportEnabled' label='Экспорт в новый файл' size='normal' image='RhSolutions' onAction='OnToolPressed'/>
|
||||
<button id='export' getEnabled='GetExportEnabled' label='Экспорт в новый файл' size='normal' imageMso='PivotExportToExcel' onAction='OnToolPressed'/>
|
||||
<button id='convert' getEnabled='GetConvertEnabled' label='Актуализировать' size='normal' imageMso='FileUpdate' onAction='OnToolPressed'/>
|
||||
<button id='merge' label='Объединить' size='normal' imageMso='Copy' onAction='OnToolPressed'/>
|
||||
<button id='guess' getEnabled='GetGuessEnabled' label='Найти и экспортировать' size='large' imageMso='ControlWizards' onAction='OnToolPressed'/>
|
||||
<button id='dxfexport' getEnabled='GetDxfEnabled' label='Экспортировать в DXF' size='normal' imageMso='ExportExcel' onAction='OnToolPressed'/>
|
||||
</group>
|
||||
<group id='fittingsCalc' label='Расчет фитингов'>
|
||||
<button id='fillsleeves' getEnabled='GetFittingsCalcEnabled' label='Гильзы' size='large' image='Sleeve' onAction='OnToolPressed'/>
|
||||
<button id='fillcouplings' getEnabled='GetFittingsCalcEnabled' label='Муфты' size='large' image='Coupling' onAction='OnToolPressed'/>
|
||||
</group>
|
||||
<group id='exportTab' label='Экспорт'>
|
||||
<button id='dxfexport' getEnabled='GetDxfEnabled' label='DXF' size='large' image='DXF' onAction='OnToolPressed'/>
|
||||
</group>
|
||||
<group id='settings' getLabel='GetVersionLabel'>
|
||||
<button id='setPriceList' getLabel='GetPriceListPathLabel' size='large' image='RhSolutions' onAction='OnSetPricePressed'/>
|
||||
<group id='rausettings' getLabel='GetVersionLabel'>
|
||||
<button id='setPriceList' getLabel='GetPriceListPathLabel' size='large' imageMso='TableExcelSpreadsheetInsert' onAction='OnSetPricePressed'/>
|
||||
</group>
|
||||
</tab>
|
||||
</tabs>
|
||||
@ -83,10 +80,17 @@ public class RibbonController : ExcelRibbon
|
||||
}
|
||||
}
|
||||
|
||||
public bool GetConvertEnabled(IRibbonControl control) => _workbookIsValid;
|
||||
public bool GetDxfEnabled(IRibbonControl control) => _workbookIsValid;
|
||||
public bool GetFittingsCalcEnabled(IRibbonControl control) => _workbookIsValid;
|
||||
public bool GetGuessEnabled(IRibbonControl control) => RhSolutionsAddIn.Excel.ActiveWorkbook != null && !_workbookIsValid;
|
||||
public bool GetConvertEnabled(IRibbonControl control)
|
||||
{
|
||||
if (RhSolutionsAddIn.Excel.ActiveWorkbook == null)
|
||||
return false;
|
||||
|
||||
else
|
||||
{
|
||||
Worksheet worksheet = RhSolutionsAddIn.Excel.ActiveWorkbook.ActiveSheet;
|
||||
return worksheet.IsValidSource();
|
||||
}
|
||||
}
|
||||
|
||||
public bool GetExportEnabled(IRibbonControl control)
|
||||
{
|
||||
@ -100,6 +104,18 @@ public class RibbonController : ExcelRibbon
|
||||
}
|
||||
}
|
||||
|
||||
public bool GetDxfEnabled(IRibbonControl control)
|
||||
{
|
||||
if (RhSolutionsAddIn.Excel.ActiveWorkbook == null)
|
||||
return false;
|
||||
|
||||
else
|
||||
{
|
||||
Worksheet worksheet = RhSolutionsAddIn.Excel.ActiveWorkbook.ActiveSheet;
|
||||
return worksheet.IsValidSource();
|
||||
}
|
||||
}
|
||||
|
||||
public string GetVersionLabel(IRibbonControl control)
|
||||
{
|
||||
string version = Assembly.GetExecutingAssembly().GetName().Version.ToString();
|
||||
@ -109,27 +125,6 @@ public class RibbonController : ExcelRibbon
|
||||
public string GetPriceListPathLabel(IRibbonControl control)
|
||||
{
|
||||
string name = RhSolutionsAddIn.Configuration.GetPriceListFileName();
|
||||
return string.IsNullOrEmpty(name) ? "Указать шаблонный файл" : name;
|
||||
}
|
||||
|
||||
public static void UpdateWorkbookValidation()
|
||||
{
|
||||
if (RhSolutionsAddIn.Excel.ActiveWorkbook == null)
|
||||
_workbookIsValid = false;
|
||||
|
||||
else
|
||||
{
|
||||
Worksheet worksheet = RhSolutionsAddIn.Excel.ActiveWorkbook.ActiveSheet;
|
||||
_workbookIsValid = worksheet.IsValidSource();
|
||||
}
|
||||
}
|
||||
|
||||
public static void EnsurePriseListExists()
|
||||
{
|
||||
string pricelistPath = RhSolutionsAddIn.Configuration.GetPriceListPath();
|
||||
if (!File.Exists(pricelistPath))
|
||||
{
|
||||
RhSolutionsAddIn.Configuration.SetPriceListPath(string.Empty);
|
||||
}
|
||||
return string.IsNullOrEmpty(name) ? "Шаблонный файл" : name;
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 4.4 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
Before Width: | Height: | Size: 900 B |
Binary file not shown.
Before Width: | Height: | Size: 7.3 KiB |
@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.9.5.1")]
|
||||
[assembly: AssemblyFileVersion("1.9.5.1")]
|
||||
[assembly: AssemblyVersion("1.6.3.0")]
|
||||
[assembly: AssemblyFileVersion("1.6.3.0")]
|
||||
|
@ -3,7 +3,7 @@
|
||||
"Excel": {
|
||||
"commandName": "Executable",
|
||||
"executablePath": "C:\\Program Files\\Microsoft Office\\root\\Office16\\EXCEL.EXE",
|
||||
"commandLineArgs": "/x \"RhSolutions-AddIn64.xll\""
|
||||
"commandLineArgs": "RhSolutions-AddIn64.xll"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<DnaLibrary Name="RhSolutions Add-In" RuntimeVersion="v4.0" xmlns="http://schemas.excel-dna.net/addin/2020/07/dnalibrary">
|
||||
<ExternalLibrary Path="RhSolutions.AddIn.dll" ExplicitExports="false" LoadFromBytes="true" Pack="true" IncludePdb="false" />
|
||||
<Reference Path="ExcelDna.Registration.dll" Pack="true" />
|
||||
<Reference Path="Microsoft.Bcl.AsyncInterfaces.dll" Pack="true" />
|
||||
<Reference Path="Microsoft.Bcl.HashCode.dll" Pack="true" />
|
||||
<Reference Path="Microsoft.Extensions.Caching.Abstractions.dll" Pack="true" />
|
||||
<Reference Path="Microsoft.Extensions.Caching.Memory.dll" Pack="true" />
|
||||
<Reference Path="Microsoft.Extensions.DependencyInjection.Abstractions.dll" Pack="true" />
|
||||
<Reference Path="Microsoft.Extensions.DependencyInjection.dll" Pack="true" />
|
||||
<Reference Path="Microsoft.Extensions.Http.dll" Pack="true" />
|
||||
@ -22,9 +19,5 @@
|
||||
<Reference Path="System.Numerics.Vectors.dll" Pack="true" />
|
||||
<Reference Path="System.Runtime.CompilerServices.Unsafe.dll" Pack="true" />
|
||||
<Reference Path="System.Threading.Tasks.Extensions.dll" Pack="true" />
|
||||
<Reference Path="System.ValueTuple.dll" Pack="true" />
|
||||
<Image Name='RhSolutions' Path='Images\RhSolutions.png' Pack='true' />
|
||||
<Image Name='DXF' Path='Images\DXF.png' Pack='true' />
|
||||
<Image Name='Sleeve' Path='Images\Sleeve.png' Pack='true' />
|
||||
<Image Name='Coupling' Path='Images\Coupling.png' Pack='true' />
|
||||
<Reference Path="System.ValueTuple.dll" Pack="true" />
|
||||
</DnaLibrary>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;net6.0-windows</TargetFrameworks>
|
||||
<TargetFrameworks>net472</TargetFrameworks>
|
||||
<LangVersion>10</LangVersion>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>RhSolutions</RootNamespace>
|
||||
@ -9,36 +9,35 @@
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<ImportWindowsDesktopTargets>true</ImportWindowsDesktopTargets>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<StartupObject />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net472|AnyCPU'">
|
||||
<NoWarn>1701;1702</NoWarn>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net472|AnyCPU'">
|
||||
<NoWarn>1701;1702</NoWarn>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net6.0-windows7.0|AnyCPU'">
|
||||
<NoWarn>1701;1702</NoWarn>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net6.0-windows7.0|AnyCPU'">
|
||||
<NoWarn>1701;1702</NoWarn>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ExcelDna.AddIn" Version="1.8.0" />
|
||||
<PackageReference Include="ExcelDna.Integration" Version="1.8.0" />
|
||||
<PackageReference Include="ExcelDna.AddIn" Version="1.6.0">
|
||||
<TreatAsUsed>true</TreatAsUsed>
|
||||
</PackageReference>
|
||||
<PackageReference Include="ExcelDna.Integration" Version="1.6.0" />
|
||||
<PackageReference Include="ExcelDna.Interop" Version="15.0.1" />
|
||||
<PackageReference Include="ExcelDna.Registration" Version="1.8.0" />
|
||||
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Bcl.HashCode" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
|
||||
<PackageReference Include="netDxf" Version="2022.11.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="RhSolutions.ProductSku" Version="1.0.2" />
|
||||
<PackageReference Include="System.Buffers" Version="4.5.1" />
|
||||
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\RhSolutions.ProductSku\RhSolutions.ProductSku.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="Images\Coupling.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Images\DXF.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Images\RhSolutions.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Images\Sleeve.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -1,43 +1,114 @@
|
||||
using Microsoft.Win32;
|
||||
using System.Configuration;
|
||||
using System.IO;
|
||||
|
||||
namespace RhSolutions.Services;
|
||||
|
||||
public class AddInConfiguration : IAddInConfiguration
|
||||
public class AddInConfiguration : ApplicationSettingsBase, IAddInConfiguration
|
||||
{
|
||||
private RegistryKey _rootKey;
|
||||
private string _priceListPath;
|
||||
private Dictionary<string, string> _priceListHeaders;
|
||||
|
||||
public event IAddInConfiguration.SettingsHandler OnSettingsChange;
|
||||
private readonly Dictionary<string, string> _priceListHeaders;
|
||||
|
||||
public AddInConfiguration()
|
||||
{
|
||||
_rootKey = Registry.CurrentUser.CreateSubKey(@"SOFTWARE\RhSolutions\RhSolutions-AddIn");
|
||||
_priceListPath = (string)_rootKey.GetValue("PriceListPath");
|
||||
_priceListHeaders = new()
|
||||
_priceListHeaders = new Dictionary<string, string>()
|
||||
{
|
||||
["Amount"] = "Кол-во",
|
||||
["OldSku"] = "Прежний материал",
|
||||
["Sku"] = "Актуальный материал",
|
||||
["ProductLine"] = "Программа",
|
||||
["Name"] = "Наименование",
|
||||
["Measure"] = "Ед. изм."
|
||||
["Amount"] = AmountHeader,
|
||||
["OldSku"] = OldSkuHeader,
|
||||
["Sku"] = SkuHeader,
|
||||
["ProductLine"] = ProductLineHeader,
|
||||
["Name"] = NameHeader,
|
||||
["Measure"] = MeasureHeader
|
||||
};
|
||||
}
|
||||
|
||||
public string GetPriceListFileName() => Path.GetFileName(_priceListPath);
|
||||
[UserScopedSetting]
|
||||
[DefaultSettingValue("Кол-во")]
|
||||
public string AmountHeader
|
||||
{
|
||||
get
|
||||
{
|
||||
return (string)this[nameof(AmountHeader)];
|
||||
}
|
||||
}
|
||||
|
||||
[UserScopedSetting]
|
||||
[DefaultSettingValue("Прежний материал")]
|
||||
public string OldSkuHeader
|
||||
{
|
||||
get
|
||||
{
|
||||
return (string)this[nameof(OldSkuHeader)];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[UserScopedSetting]
|
||||
[DefaultSettingValue("Актуальный материал")]
|
||||
public string SkuHeader
|
||||
{
|
||||
get
|
||||
{
|
||||
return (string)this[nameof(SkuHeader)];
|
||||
}
|
||||
}
|
||||
|
||||
[UserScopedSetting]
|
||||
[DefaultSettingValue("Программа")]
|
||||
public string ProductLineHeader
|
||||
{
|
||||
get
|
||||
{
|
||||
return (string)this[nameof(ProductLineHeader)];
|
||||
}
|
||||
}
|
||||
|
||||
[UserScopedSetting]
|
||||
[DefaultSettingValue("Наименование")]
|
||||
public string NameHeader
|
||||
{
|
||||
get
|
||||
{
|
||||
return (string)this[nameof(NameHeader)];
|
||||
}
|
||||
}
|
||||
|
||||
[UserScopedSetting]
|
||||
[DefaultSettingValue("Ед. изм.")]
|
||||
public string MeasureHeader
|
||||
{
|
||||
get
|
||||
{
|
||||
return (string)this[nameof(MeasureHeader)];
|
||||
}
|
||||
}
|
||||
|
||||
[UserScopedSetting]
|
||||
public string PriceListPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return (string)this[nameof(PriceListPath)];
|
||||
}
|
||||
set
|
||||
{
|
||||
this[nameof(PriceListPath)] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public event SettingChangingEventHandler OnSettingsChange
|
||||
{
|
||||
add
|
||||
{
|
||||
base.SettingChanging += value;
|
||||
}
|
||||
remove
|
||||
{
|
||||
base.SettingChanging -= value;
|
||||
}
|
||||
}
|
||||
|
||||
public string GetPriceListFileName() => Path.GetFileName(PriceListPath);
|
||||
public string GetPriceListPath() => PriceListPath;
|
||||
public void SetPriceListPath(string value) => PriceListPath = value;
|
||||
public void SaveSettings() => base.Save();
|
||||
public Dictionary<string, string> GetPriceListHeaders() => _priceListHeaders;
|
||||
public string GetPriceListPath() => _priceListPath;
|
||||
|
||||
public void SaveSettings()
|
||||
{
|
||||
_rootKey.SetValue("PriceListPath", _priceListPath);
|
||||
OnSettingsChange.Invoke();
|
||||
}
|
||||
|
||||
public void SetPriceListPath(string value)
|
||||
{
|
||||
_priceListPath = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,67 +0,0 @@
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace RhSolutions.Services;
|
||||
|
||||
public class CouplingsCalculator : IFittingsCalculator
|
||||
{
|
||||
private static readonly string pattern =
|
||||
@"(^|\W)труба.*(?'Diameter'16|20|25|32|40|50|63).*(отрезки|бухт[ае])\D*(?'Length'\d{1,3})(\D|$)";
|
||||
|
||||
public Dictionary<Product, double> Calculate(Dictionary<Product, double> products)
|
||||
{
|
||||
Dictionary<string, double> result = new()
|
||||
{
|
||||
["16"] = 0,
|
||||
["20"] = 0,
|
||||
["25"] = 0,
|
||||
["32"] = 0,
|
||||
["40"] = 0,
|
||||
["50"] = 0,
|
||||
["63"] = 0,
|
||||
};
|
||||
|
||||
var rautitanProducts = products.Where(kvp => kvp.Key.ProductLines.Contains("RAUTITAN"));
|
||||
Regex regex = new(pattern, RegexOptions.Multiline | RegexOptions.IgnoreCase);
|
||||
|
||||
foreach (var kvp in rautitanProducts)
|
||||
{
|
||||
var match = regex.Match(kvp.Key.Name);
|
||||
if (match.Success)
|
||||
{
|
||||
string diameter = match.Groups["Diameter"].Value;
|
||||
int packingLength = int.Parse(match.Groups["Length"].Value);
|
||||
result[diameter] += GetCouplesCount(kvp.Value, packingLength);
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
.ToDictionary(kvp =>
|
||||
kvp.Key switch
|
||||
{
|
||||
"16" => new Product("11080111001"),
|
||||
"20" => new Product("11080121001"),
|
||||
"25" => new Product("11080131001"),
|
||||
"32" => new Product("11080141001"),
|
||||
"40" => new Product("11080151001"),
|
||||
"50" => new Product("14563021001"),
|
||||
"63" => new Product("14563031001"),
|
||||
_ => throw new Exception($"Неизвестный диаметр {kvp.Key}")
|
||||
}, kvp => kvp.Value);
|
||||
}
|
||||
|
||||
private int GetCouplesCount(double amount, int packingLength)
|
||||
{
|
||||
if (amount < packingLength)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (amount % packingLength == 0)
|
||||
{
|
||||
return (int)amount / packingLength - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (int)amount / packingLength;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using System.Net;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
@ -8,43 +7,35 @@ namespace RhSolutions.Services;
|
||||
|
||||
public class CurrencyClient : ICurrencyClient
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly IMemoryCache _memoryCache;
|
||||
private const string _requestAddress = @"https://www.cbr.ru/scripts/XML_daily.asp?date_req=";
|
||||
private readonly HttpClient _httpClient;
|
||||
public HttpStatusCode StatusCode { get; private set; }
|
||||
|
||||
public CurrencyClient(HttpClient httpClient, IMemoryCache memoryCache)
|
||||
public CurrencyClient(IServiceProvider serviceProvider)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_memoryCache = memoryCache;
|
||||
_httpClient = serviceProvider.GetRequiredService<HttpClient>();
|
||||
}
|
||||
|
||||
public async Task<decimal?> GetExchangeRate(DateTime date)
|
||||
public async Task<decimal?> GetCurrencyCourse(DateTime date)
|
||||
{
|
||||
if (!_memoryCache.TryGetValue(date, out decimal exchangeRate))
|
||||
string request = $"https://www.cbr.ru/scripts/XML_daily.asp?date_req={date.Date.ToString("dd/MM/yyyy")}";
|
||||
var response = await _httpClient.GetAsync(request);
|
||||
|
||||
try
|
||||
{
|
||||
string request = $"{_requestAddress}{date.Date:dd/MM/yyyy}";
|
||||
HttpResponseMessage response = await _httpClient.GetAsync(request);
|
||||
try
|
||||
{
|
||||
response.EnsureSuccessStatusCode();
|
||||
string xml = await response.Content.ReadAsStringAsync();
|
||||
XElement valCourses = XElement.Parse(xml);
|
||||
exchangeRate = decimal.Parse(valCourses.Elements("Valute")
|
||||
.Where(e => e.Element("Name").Value == "Евро")
|
||||
.FirstOrDefault()
|
||||
.Element("Value").Value);
|
||||
var cacheEntryOptions = new MemoryCacheEntryOptions()
|
||||
.SetSlidingExpiration(TimeSpan.FromHours(1));
|
||||
_memoryCache.Set(date, exchangeRate, cacheEntryOptions);
|
||||
return exchangeRate;
|
||||
}
|
||||
catch
|
||||
{
|
||||
StatusCode = response.StatusCode;
|
||||
return null;
|
||||
}
|
||||
response.EnsureSuccessStatusCode();
|
||||
string xml = await response.Content.ReadAsStringAsync();
|
||||
XElement valCourses = XElement.Parse(xml);
|
||||
var course = decimal.Parse(valCourses.Elements("Valute")
|
||||
.Where(e => e.Element("Name").Value == "Евро")
|
||||
.FirstOrDefault()
|
||||
.Element("Value").Value);
|
||||
return course;
|
||||
}
|
||||
return exchangeRate;
|
||||
catch
|
||||
{
|
||||
StatusCode = response.StatusCode;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
#if !NET472
|
||||
using System.Runtime.Versioning;
|
||||
using RhSolutions.Tools;
|
||||
#endif
|
||||
|
||||
|
||||
namespace RhSolutions.Services;
|
||||
|
||||
public class CurrentPriceWriter : ExcelWriterBase, IWriter, IDisposable
|
||||
{
|
||||
public CurrentPriceWriter(Application application, IAddInConfiguration configuration)
|
||||
{
|
||||
_application = application;
|
||||
_resultBar = new();
|
||||
_headers = configuration.GetPriceListHeaders();
|
||||
_worksheet = _application.ActiveSheet;
|
||||
_appendValues = false;
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
@ -8,87 +7,42 @@ namespace RhSolutions.Services;
|
||||
|
||||
public class DatabaseClient : IDatabaseClient
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly IMemoryCache _memoryCache;
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
public HttpStatusCode StatusCode { get; private set; }
|
||||
|
||||
public DatabaseClient(HttpClient httpClient, IMemoryCache memoryCache)
|
||||
public DatabaseClient(IServiceProvider provider)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_memoryCache = memoryCache;
|
||||
this.serviceProvider = provider;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Product>> GetProducts(string line)
|
||||
{
|
||||
string request;
|
||||
|
||||
if (ProductSku.TryParse(line, out var skus))
|
||||
{
|
||||
ProductSku sku = skus.FirstOrDefault();
|
||||
string request = @"https://rh.cebotari.ru/api/products/" + sku.ToString();
|
||||
|
||||
if (!_memoryCache.TryGetValue(sku, out IEnumerable<Product> products))
|
||||
{
|
||||
var response = await _httpClient.GetAsync(request);
|
||||
|
||||
try
|
||||
{
|
||||
response.EnsureSuccessStatusCode();
|
||||
string json = await response.Content.ReadAsStringAsync();
|
||||
products = JsonConvert.DeserializeObject<IEnumerable<Product>>(json) ?? Enumerable.Empty<Product>();
|
||||
}
|
||||
catch
|
||||
{
|
||||
StatusCode = response.StatusCode;
|
||||
return Enumerable.Empty<Product>();
|
||||
}
|
||||
|
||||
var cacheEntryOptions = new MemoryCacheEntryOptions()
|
||||
.SetSlidingExpiration(TimeSpan.FromHours(1));
|
||||
_memoryCache.Set(sku, products, cacheEntryOptions);
|
||||
return products;
|
||||
}
|
||||
else
|
||||
{
|
||||
return products;
|
||||
}
|
||||
request = @"https://rh.cebotari.ru/api/products/" + skus.FirstOrDefault().ToString();
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
UriBuilder builder = new(@"https://rh.cebotari.ru/api/search")
|
||||
{
|
||||
Query = $"query={line.Replace("&", "%26")}"
|
||||
};
|
||||
string request = builder.Uri.AbsoluteUri;
|
||||
|
||||
if (!_memoryCache.TryGetValue(line, out IEnumerable<Product> products))
|
||||
{
|
||||
var response = await _httpClient.GetAsync(request);
|
||||
request = @"https://rh.cebotari.ru/api/search?query=" + line;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
response.EnsureSuccessStatusCode();
|
||||
string json = await response.Content.ReadAsStringAsync();
|
||||
products = JsonConvert.DeserializeObject<IEnumerable<Product>>(json) ?? Enumerable.Empty<Product>();
|
||||
}
|
||||
catch
|
||||
{
|
||||
StatusCode = response.StatusCode;
|
||||
return Enumerable.Empty<Product>();
|
||||
}
|
||||
var client = serviceProvider.GetRequiredService<HttpClient>();
|
||||
var response = await client.GetAsync(request);
|
||||
|
||||
var cacheEntryOptions = new MemoryCacheEntryOptions()
|
||||
.SetSlidingExpiration(TimeSpan.FromHours(1));
|
||||
_memoryCache.Set(line, products, cacheEntryOptions);
|
||||
if (products.Any())
|
||||
{
|
||||
_memoryCache.Set(products.First(), products, cacheEntryOptions);
|
||||
}
|
||||
return products;
|
||||
}
|
||||
else
|
||||
{
|
||||
return products;
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
response.EnsureSuccessStatusCode();
|
||||
string json = await response.Content.ReadAsStringAsync();
|
||||
return JsonConvert.DeserializeObject<IEnumerable<Product>>(json) ?? Enumerable.Empty<Product>();
|
||||
}
|
||||
catch
|
||||
{
|
||||
StatusCode = response.StatusCode;
|
||||
}
|
||||
|
||||
return Enumerable.Empty<Product>();
|
||||
}
|
||||
}
|
@ -60,10 +60,7 @@ public class ExcelReader : IReader, IDisposable
|
||||
continue;
|
||||
}
|
||||
|
||||
Product product = new(currentSku)
|
||||
{
|
||||
Name = $"Распознанный артикул"
|
||||
};
|
||||
Product product = new(currentSku);
|
||||
|
||||
if (readResult.ContainsKey(product))
|
||||
{
|
||||
@ -79,7 +76,7 @@ public class ExcelReader : IReader, IDisposable
|
||||
return readResult;
|
||||
}
|
||||
|
||||
public IEnumerable<(string, Dictionary<Product, double>)>
|
||||
public List<(string, Dictionary<Product, double>)>
|
||||
ReadProducts(IEnumerable<Worksheet> worksheets)
|
||||
{
|
||||
List<(string, Dictionary<Product, double>)> result = new();
|
||||
@ -93,29 +90,27 @@ public class ExcelReader : IReader, IDisposable
|
||||
string wbName = Path.GetFileNameWithoutExtension(
|
||||
worksheet.Parent.Name);
|
||||
|
||||
Range amountCell = worksheet.Cells.Find(headers["Amount"]);
|
||||
Range headerRow = amountCell.EntireRow;
|
||||
Range skuCell = headerRow.Find(headers["Sku"]),
|
||||
productLineCell = headerRow.Find(headers["ProductLine"]),
|
||||
nameCell = headerRow.Find(headers["Name"]),
|
||||
measureCell = headerRow.Find(headers["Measure"]);
|
||||
|
||||
var lastRowIndex = worksheet.Cells[worksheet.Rows.Count, skuCell.Column]
|
||||
Range AmountCell = worksheet.Cells.Find(headers["Amount"]),
|
||||
SkuCell = worksheet.Cells.Find(headers["Sku"]),
|
||||
ProductLineCell = worksheet.Cells.Find(headers["ProductLine"]),
|
||||
NameCell = worksheet.Cells.Find(headers["Name"]),
|
||||
MeasureCell = worksheet.Cells.Find(headers["Measure"]);
|
||||
var lastRowIndex = worksheet.Cells[worksheet.Rows.Count, AmountCell.Column]
|
||||
.End[XlDirection.xlUp].Row;
|
||||
|
||||
Dictionary<Product, double> readResult = new();
|
||||
|
||||
for (int row = amountCell.Row + 1; row <= lastRowIndex; row++)
|
||||
for (int row = AmountCell.Row + 1; row <= lastRowIndex; row++)
|
||||
{
|
||||
double? amount = worksheet.Cells[row, amountCell.Column].Value2 as double?;
|
||||
double? amount = worksheet.Cells[row, AmountCell.Column].Value2 as double?;
|
||||
|
||||
if (amount != null && amount.Value != 0)
|
||||
{
|
||||
object productLine = worksheet.Cells[row, productLineCell.Column].Value2;
|
||||
object name = worksheet.Cells[row, nameCell.Column].Value2;
|
||||
object sku = worksheet.Cells[row, skuCell.Column].Value2;
|
||||
object measure = worksheet.Cells[row, measureCell.Column].Value2;
|
||||
var productMeasure = measure?.ToString() switch
|
||||
object productLine = worksheet.Cells[row, ProductLineCell.Column].Value2;
|
||||
object name = worksheet.Cells[row, NameCell.Column].Value2;
|
||||
object sku = worksheet.Cells[row, SkuCell.Column].Value2;
|
||||
object measure = worksheet.Cells[row, MeasureCell.Column].Value2;
|
||||
var productMeasure = measure.ToString() switch
|
||||
{
|
||||
"м" => Measure.M,
|
||||
"шт" => Measure.P,
|
||||
@ -132,7 +127,7 @@ public class ExcelReader : IReader, IDisposable
|
||||
Product p = new(sku.ToString())
|
||||
{
|
||||
ProductLines = new List<string>() { productLine.ToString() },
|
||||
Name = name.ToString().Split('\n').First(),
|
||||
Name = name.ToString(),
|
||||
ProductMeasure = productMeasure
|
||||
};
|
||||
|
||||
@ -151,15 +146,11 @@ public class ExcelReader : IReader, IDisposable
|
||||
|
||||
result.Add((wbName, readResult));
|
||||
}
|
||||
return result.OrderBy(x => x.Item1);
|
||||
return result;
|
||||
}
|
||||
|
||||
public IEnumerable<(string, Dictionary<Product, double>)> ReadProducts(string[] files)
|
||||
public List<(string, Dictionary<Product, double>)> ReadProducts(string[] files)
|
||||
{
|
||||
HashSet<string> openedFiles = RhSolutionsAddIn.Excel.Workbooks
|
||||
.Cast<Workbook>()
|
||||
.Select(wb => wb.FullName)
|
||||
.ToHashSet();
|
||||
_progressBar = new("Открываю исходные файлы...", files.Length);
|
||||
List<Worksheet> worksheets = new();
|
||||
|
||||
@ -174,11 +165,7 @@ public class ExcelReader : IReader, IDisposable
|
||||
var result = ReadProducts(worksheets);
|
||||
foreach (var ws in worksheets)
|
||||
{
|
||||
string file = (string)ws.Parent.FullName;
|
||||
if (!openedFiles.Contains(file))
|
||||
{
|
||||
ws.Parent.Close(SaveChanges: false);
|
||||
}
|
||||
ws.Parent.Close();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
255
RhSolutions.AddIn/Services/ExcelWriter.cs
Normal file
255
RhSolutions.AddIn/Services/ExcelWriter.cs
Normal file
@ -0,0 +1,255 @@
|
||||
#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.FirstOrDefault());
|
||||
|
||||
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.FirstOrDefault());
|
||||
|
||||
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.FirstOrDefault());
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
@ -1,267 +0,0 @@
|
||||
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;
|
||||
|
||||
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<Product, double> products)
|
||||
{
|
||||
WriteProducts(new[] { (string.Empty, products) });
|
||||
}
|
||||
|
||||
public void WriteProducts(IEnumerable<(string, Dictionary<Product, double>)> 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.NumberFormat = "@";
|
||||
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<Product, double> 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<Product, double> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
namespace RhSolutions.Services;
|
||||
|
||||
public class FittingsCalculatorFactory
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public FittingsCalculatorFactory(IServiceProvider serviceProvider)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public IFittingsCalculator GetFittingsCalculator(string calculatorName)
|
||||
{
|
||||
return calculatorName switch
|
||||
{
|
||||
"Sleeves" => (IFittingsCalculator)_serviceProvider.GetService(typeof(SleevesCalculator)),
|
||||
"Couplings" => (IFittingsCalculator)_serviceProvider.GetService(typeof(CouplingsCalculator)),
|
||||
_ => throw new ArgumentException($"Незвестный интерфейс {nameof(IFittingsCalculator)}: {calculatorName}")
|
||||
};
|
||||
}
|
||||
}
|
@ -1,234 +0,0 @@
|
||||
using System.IO;
|
||||
|
||||
namespace RhSolutions.Services;
|
||||
|
||||
public class GuessReader : IReader
|
||||
{
|
||||
private readonly Application _application;
|
||||
private ProgressBar _progressBar;
|
||||
|
||||
public GuessReader(Application application)
|
||||
{
|
||||
_application = application;
|
||||
}
|
||||
|
||||
public Dictionary<Product, double> ReadProducts(Range range)
|
||||
{
|
||||
_progressBar = new("Ищу колонку с артикулами...", range.Columns.Count);
|
||||
int? productColumnIndex = null;
|
||||
|
||||
for (int column = 1; column < range.Columns.Count + 1; column++)
|
||||
{
|
||||
_progressBar.Update();
|
||||
if (IsProductColumn(range.Columns[column]))
|
||||
{
|
||||
productColumnIndex = column;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (productColumnIndex == null)
|
||||
{
|
||||
throw new ArgumentException("Колонка с артикулом не определена");
|
||||
}
|
||||
|
||||
int? amountColumnIndex = null;
|
||||
int currentIndex = productColumnIndex.Value + 1;
|
||||
_progressBar = new("Ищу колонку с количеством...", range.Columns.Count);
|
||||
|
||||
while (currentIndex > 0)
|
||||
{
|
||||
_progressBar.Update();
|
||||
if (currentIndex > range.Columns.Count + 1)
|
||||
{
|
||||
currentIndex = productColumnIndex.Value - 1;
|
||||
continue;
|
||||
}
|
||||
if (currentIndex > productColumnIndex)
|
||||
{
|
||||
if (IsAmountColumn(range.Columns[currentIndex]))
|
||||
{
|
||||
amountColumnIndex = currentIndex;
|
||||
break;
|
||||
}
|
||||
else currentIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsAmountColumn(range.Columns[currentIndex]))
|
||||
{
|
||||
amountColumnIndex = currentIndex;
|
||||
break;
|
||||
}
|
||||
else currentIndex--;
|
||||
}
|
||||
}
|
||||
|
||||
if (amountColumnIndex == null)
|
||||
{
|
||||
throw new ArgumentException("Колонка с количеством не определена");
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
return GetDictionaryFromColumns(range.Columns[productColumnIndex],
|
||||
range.Columns[amountColumnIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsProductColumn(Range column)
|
||||
{
|
||||
int successCounter = 0;
|
||||
var cells = column.Value2;
|
||||
|
||||
if (cells == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int row = 1; row < column.Rows.Count + 1; row++)
|
||||
{
|
||||
object currentCell = column.Rows.Count == 1 ? cells : cells[row, 1];
|
||||
if (currentCell == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ProductSku.TryParse(currentCell.ToString(), out _))
|
||||
{
|
||||
successCounter++;
|
||||
}
|
||||
|
||||
if (successCounter > 2)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return successCounter > 0;
|
||||
}
|
||||
|
||||
private bool IsAmountColumn(Range column)
|
||||
{
|
||||
int successCounter = 0;
|
||||
var cells = column.Value2;
|
||||
double maxValue = 30000;
|
||||
|
||||
if (cells == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (column.Rows.Count == 1)
|
||||
{
|
||||
double? value = cells as double?;
|
||||
|
||||
return value != null
|
||||
&& value != 0
|
||||
&& value < maxValue;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
for (int row = 1; row < column.Rows.Count + 1; row++)
|
||||
{
|
||||
object currentCell = cells[row, 1];
|
||||
double? value = currentCell as double?;
|
||||
|
||||
if (value == null
|
||||
|| value == 0
|
||||
|| value > maxValue)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (++successCounter > 3)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return successCounter > 1;
|
||||
}
|
||||
|
||||
private Dictionary<Product, double> GetDictionaryFromColumns(Range productColumn, Range amountColumn)
|
||||
{
|
||||
Dictionary<Product, double> result = new();
|
||||
var firstRowIndex = 1;
|
||||
var lastRowIndex = amountColumn.Worksheet
|
||||
.Cells[amountColumn.Worksheet.Rows.Count, amountColumn.Column]
|
||||
.End[XlDirection.xlUp].Row;
|
||||
_progressBar = new("Заполняю словарь значений...", lastRowIndex);
|
||||
Worksheet worksheet = amountColumn.Worksheet;
|
||||
|
||||
for (int row = firstRowIndex; row < lastRowIndex + 1; row++)
|
||||
{
|
||||
_progressBar.Update();
|
||||
object currentAmountCell = worksheet.Cells[row, amountColumn.Column].Value2;
|
||||
object currentProductCell = worksheet.Cells[row, productColumn.Column].Value2;
|
||||
double? amountValue = currentAmountCell as double?;
|
||||
|
||||
if (amountValue == null || amountValue == 0 || currentProductCell == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ProductSku.TryParse(currentProductCell.ToString(), out IEnumerable<ProductSku> skus))
|
||||
{
|
||||
Product p = new(skus.First())
|
||||
{
|
||||
Name = "Распознанный артикул"
|
||||
};
|
||||
if (result.ContainsKey(p))
|
||||
{
|
||||
result[p] += amountValue.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Add(p, amountValue.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public IEnumerable<(string, Dictionary<Product, double>)> ReadProducts(IEnumerable<Worksheet> worksheets)
|
||||
{
|
||||
List<(string, Dictionary<Product, double>)> 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 IEnumerable<(string, Dictionary<Product, double>)> ReadProducts(string[] files)
|
||||
{
|
||||
_progressBar = new("Открываю исходные файлы...", files.Length);
|
||||
List<Worksheet> 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();
|
||||
}
|
||||
}
|
@ -1,12 +1,13 @@
|
||||
namespace RhSolutions.Services;
|
||||
using System.Configuration;
|
||||
|
||||
namespace RhSolutions.Services;
|
||||
|
||||
public interface IAddInConfiguration
|
||||
{
|
||||
public string GetPriceListPath();
|
||||
public void SetPriceListPath(string value);
|
||||
public string GetPriceListFileName();
|
||||
public Dictionary<string, string> GetPriceListHeaders();
|
||||
public delegate void SettingsHandler();
|
||||
public event SettingsHandler OnSettingsChange;
|
||||
public event SettingChangingEventHandler OnSettingsChange;
|
||||
public void SetPriceListPath(string value);
|
||||
public void SaveSettings();
|
||||
}
|
@ -5,5 +5,5 @@ namespace RhSolutions.Services;
|
||||
|
||||
public interface ICurrencyClient
|
||||
{
|
||||
public Task<decimal?> GetExchangeRate(DateTime date);
|
||||
public Task<decimal?> GetCurrencyCourse(DateTime date);
|
||||
}
|
||||
|
@ -1,6 +0,0 @@
|
||||
namespace RhSolutions.Services;
|
||||
|
||||
public interface IFittingsCalculator
|
||||
{
|
||||
public Dictionary<Product, double> Calculate(Dictionary<Product, double> products);
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
public interface IReader : IDisposable
|
||||
{
|
||||
public Dictionary<Product, double> ReadProducts(Range range);
|
||||
public IEnumerable<(string, Dictionary<Product, double>)> ReadProducts(IEnumerable<Worksheet> worksheets);
|
||||
public IEnumerable<(string, Dictionary<Product, double>)> ReadProducts(string[] files);
|
||||
public List<(string, Dictionary<Product, double>)> ReadProducts(IEnumerable<Worksheet> worksheets);
|
||||
public List<(string, Dictionary<Product, double>)> ReadProducts(string[] files);
|
||||
new void Dispose();
|
||||
}
|
||||
|
@ -1,34 +0,0 @@
|
||||
#if !NET472
|
||||
using System.Runtime.Versioning;
|
||||
using RhSolutions.Tools;
|
||||
#endif
|
||||
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace RhSolutions.Services;
|
||||
|
||||
#if !NET472
|
||||
[SupportedOSPlatform("windows")]
|
||||
#endif
|
||||
public class NewPriceWriter : ExcelWriterBase, IWriter, IDisposable
|
||||
{
|
||||
public NewPriceWriter(Application application, IAddInConfiguration configuration)
|
||||
{
|
||||
_application = application;
|
||||
_resultBar = new();
|
||||
_headers = configuration.GetPriceListHeaders();
|
||||
_worksheet = OpenNewPrice(configuration.GetPriceListPath());
|
||||
}
|
||||
|
||||
private Worksheet OpenNewPrice(string pricelistPath)
|
||||
{
|
||||
if (_application.Workbooks
|
||||
.Cast<Workbook>()
|
||||
.FirstOrDefault(w => w.FullName == pricelistPath) != null)
|
||||
{
|
||||
throw new ArgumentException("Шаблонный файл редактируется в другом месте");
|
||||
}
|
||||
|
||||
return _application.Workbooks.Open(pricelistPath, null, true).ActiveSheet;
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
namespace RhSolutions.Services;
|
||||
|
||||
public class ReaderFactory
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public ReaderFactory(IServiceProvider serviceProvider)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public IReader GetReader(string readerName)
|
||||
{
|
||||
return readerName switch
|
||||
{
|
||||
"Guess" => (IReader)_serviceProvider.GetService(typeof(GuessReader)),
|
||||
"Excel" => (IReader)_serviceProvider.GetService(typeof(ExcelReader)),
|
||||
_ => throw new ArgumentException($"Незвестный интерфейс {nameof(IReader)}: {readerName}")
|
||||
};
|
||||
}
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace RhSolutions.Services;
|
||||
|
||||
public class SleevesCalculator : IFittingsCalculator
|
||||
{
|
||||
private const string doublePattern =
|
||||
@"((?i)равнопроходная|угольник\s+90|угольник\s+45|Т-образная|Комплект\s+трубок(?i))(.+?\b(?<Sleeve>16|20|25|32|40|50|63)\b)+";
|
||||
private const string singlePattern =
|
||||
@"((?i)муфта|тройник|переходник|угольник|штуцер|Г-образная|заглушка(?i))(.+?\b(?<Sleeve>16|20|25|32|40|50|63)\b)+";
|
||||
|
||||
public Dictionary<Product, double> Calculate(Dictionary<Product, double> products)
|
||||
{
|
||||
Dictionary<string, double> result = new()
|
||||
{
|
||||
["16"] = 0,
|
||||
["20"] = 0,
|
||||
["25"] = 0,
|
||||
["32"] = 0,
|
||||
["40"] = 0,
|
||||
["50"] = 0,
|
||||
["63"] = 0,
|
||||
["16PX"] = 0,
|
||||
["20PX"] = 0,
|
||||
["25PX"] = 0,
|
||||
["32PX"] = 0,
|
||||
["40PX"] = 0
|
||||
};
|
||||
var rautitanProducts = products.Where(kvp => kvp.Key.ProductLines.Contains("RAUTITAN"));
|
||||
|
||||
foreach (var kvp in rautitanProducts)
|
||||
{
|
||||
var doubleCollection = Regex.Matches(kvp.Key.Name, doublePattern);
|
||||
if (doubleCollection.Count != 0)
|
||||
{
|
||||
CaptureCollection collection = doubleCollection[0].Groups["Sleeve"].Captures;
|
||||
foreach (Capture sleeve in collection)
|
||||
{
|
||||
if (kvp.Key.Name.Contains("PX"))
|
||||
{
|
||||
result[$"{sleeve.Value}PX"] += kvp.Value * 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
result[sleeve.Value] += kvp.Value * 2;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
var singleCollection = Regex.Matches(kvp.Key.Name, singlePattern);
|
||||
if (singleCollection.Count != 0)
|
||||
{
|
||||
CaptureCollection collection = singleCollection[0].Groups["Sleeve"].Captures;
|
||||
foreach (Capture sleeve in collection)
|
||||
{
|
||||
if (kvp.Key.Name.Contains("PX"))
|
||||
{
|
||||
result[$"{sleeve.Value}PX"] += kvp.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
result[sleeve.Value] += kvp.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
.ToDictionary(kvp =>
|
||||
kvp.Key switch
|
||||
{
|
||||
"16" => new Product("11080011001"),
|
||||
"20" => new Product("11080021001"),
|
||||
"25" => new Product("11080031001"),
|
||||
"32" => new Product("11080041001"),
|
||||
"40" => new Product("11080051001"),
|
||||
"50" => new Product("11397713002"),
|
||||
"63" => new Product("11397813002"),
|
||||
"16PX" => new Product("11600011001"),
|
||||
"20PX" => new Product("11600021001"),
|
||||
"25PX" => new Product("11600031001"),
|
||||
"32PX" => new Product("11600041001"),
|
||||
"40PX" => new Product("11600051001"),
|
||||
_ => throw new Exception($"Неизвестный диаметр {kvp.Key}")
|
||||
}, kvp => kvp.Value);
|
||||
}
|
||||
}
|
@ -11,12 +11,14 @@ public class WriterFactory
|
||||
|
||||
public IWriter GetWriter(string writerName)
|
||||
{
|
||||
return writerName switch
|
||||
if (writerName.Equals("Dxf"))
|
||||
{
|
||||
"NewPrice" => (IWriter)_serviceProvider.GetService(typeof(NewPriceWriter)),
|
||||
"CurrentPrice" => (IWriter)_serviceProvider.GetService(typeof(CurrentPriceWriter)),
|
||||
"Dxf" => (IWriter)_serviceProvider.GetService(typeof(DxfWriter)),
|
||||
_ => throw new ArgumentException($"Незвестный интерфейс {nameof(IWriter)}: {writerName}")
|
||||
};
|
||||
return (IWriter)_serviceProvider.GetService(typeof(DxfWriter));
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
return (IWriter)_serviceProvider.GetService(typeof(ExcelWriter));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ namespace RhSolutions.Tools;
|
||||
#endif
|
||||
internal class ConvertTool : Tool
|
||||
{
|
||||
public ConvertTool(ReaderFactory readerFactory, WriterFactory writerFactory) : base(readerFactory, writerFactory)
|
||||
public ConvertTool(IServiceProvider provider) : base(provider)
|
||||
{
|
||||
}
|
||||
|
||||
@ -18,9 +18,8 @@ internal class ConvertTool : Tool
|
||||
{
|
||||
Application app = RhSolutionsAddIn.Excel.Application;
|
||||
Worksheet worksheet = app.ActiveWorkbook.ActiveSheet;
|
||||
_reader = _readerFactory.GetReader("Excel");
|
||||
var products = _reader.ReadProducts(new[] { worksheet });
|
||||
_writer = _writerFactory.GetWriter("NewPrice");
|
||||
_writer = _writerFactory.GetWriter("Excel");
|
||||
_writer.WriteProducts(products);
|
||||
}
|
||||
}
|
@ -9,7 +9,7 @@ namespace RhSolutions.Tools;
|
||||
#endif
|
||||
internal class DxfTool : Tool
|
||||
{
|
||||
public DxfTool(ReaderFactory readerFactory, WriterFactory writerFactory) : base(readerFactory, writerFactory)
|
||||
public DxfTool(IServiceProvider provider) : base(provider)
|
||||
{
|
||||
}
|
||||
|
||||
@ -17,7 +17,6 @@ internal class DxfTool : Tool
|
||||
{
|
||||
Application app = RhSolutionsAddIn.Excel.Application;
|
||||
Worksheet worksheet = app.ActiveWorkbook.ActiveSheet;
|
||||
_reader = _readerFactory.GetReader("Excel");
|
||||
var products = _reader.ReadProducts(new[] { worksheet });
|
||||
_writer = _writerFactory.GetWriter("Dxf");
|
||||
_writer.WriteProducts(products);
|
||||
|
@ -1,43 +1,56 @@
|
||||
using RhSolutions.Controllers;
|
||||
using Microsoft.Office.Interop.Excel;
|
||||
using RhSolutions.AddIn;
|
||||
using RhSolutions.Controllers;
|
||||
using System.Configuration;
|
||||
#if !NET472
|
||||
using System.Runtime.Versioning;
|
||||
#endif
|
||||
|
||||
namespace RhSolutions.Tools;
|
||||
|
||||
internal static class EventsUtil
|
||||
namespace RhSolutions.Tools
|
||||
{
|
||||
public static void Initialize()
|
||||
#if !NET472
|
||||
[SupportedOSPlatform("windows")]
|
||||
#endif
|
||||
internal static class EventsUtil
|
||||
{
|
||||
RibbonController.EnsurePriseListExists();
|
||||
RhSolutionsAddIn.Excel.SheetSelectionChange += RefreshExportButton;
|
||||
RhSolutionsAddIn.Excel.SheetActivate += RefreshButtons;
|
||||
RhSolutionsAddIn.Excel.WorkbookActivate += RefreshButtons;
|
||||
RhSolutionsAddIn.Configuration.OnSettingsChange += RefreshSettingTitle;
|
||||
}
|
||||
public static void Initialize()
|
||||
{
|
||||
RhSolutionsAddIn.Excel.SheetSelectionChange += RefreshExportButton;
|
||||
RhSolutionsAddIn.Excel.SheetActivate += RefreshConvertButton;
|
||||
RhSolutionsAddIn.Excel.SheetActivate += RefreshDxfButton;
|
||||
RhSolutionsAddIn.Excel.WorkbookActivate += RefreshConvertButton;
|
||||
RhSolutionsAddIn.Excel.WorkbookActivate += RefreshDxfButton;
|
||||
RhSolutionsAddIn.Configuration.OnSettingsChange += RefreshSettingTitle;
|
||||
}
|
||||
|
||||
public static void Uninitialize()
|
||||
{
|
||||
RhSolutionsAddIn.Excel.SheetSelectionChange -= RefreshExportButton;
|
||||
RhSolutionsAddIn.Excel.SheetActivate -= RefreshButtons;
|
||||
RhSolutionsAddIn.Excel.WorkbookActivate -= RefreshButtons;
|
||||
RhSolutionsAddIn.Configuration.OnSettingsChange -= RefreshSettingTitle;
|
||||
}
|
||||
public static void Uninitialize()
|
||||
{
|
||||
RhSolutionsAddIn.Excel.SheetSelectionChange -= RefreshExportButton;
|
||||
RhSolutionsAddIn.Excel.SheetActivate -= RefreshConvertButton;
|
||||
RhSolutionsAddIn.Excel.SheetActivate -= RefreshDxfButton;
|
||||
RhSolutionsAddIn.Excel.WorkbookActivate -= RefreshConvertButton;
|
||||
RhSolutionsAddIn.Excel.WorkbookActivate -= RefreshDxfButton;
|
||||
RhSolutionsAddIn.Configuration.OnSettingsChange -= RefreshSettingTitle;
|
||||
}
|
||||
|
||||
private static void RefreshButtons(object sh)
|
||||
{
|
||||
RibbonController.UpdateWorkbookValidation();
|
||||
RibbonController.RefreshControl("convert");
|
||||
RibbonController.RefreshControl("dxfexport");
|
||||
RibbonController.RefreshControl("guess");
|
||||
RibbonController.RefreshControl("fillsleeves");
|
||||
RibbonController.RefreshControl("fillcouplings");
|
||||
}
|
||||
private static void RefreshConvertButton(object sh)
|
||||
{
|
||||
RibbonController.RefreshControl("convert");
|
||||
}
|
||||
|
||||
private static void RefreshExportButton(object sh, Range target)
|
||||
{
|
||||
RibbonController.RefreshControl("export");
|
||||
}
|
||||
private static void RefreshDxfButton(object sh)
|
||||
{
|
||||
RibbonController.RefreshControl("dxfexport");
|
||||
}
|
||||
|
||||
private static void RefreshSettingTitle()
|
||||
{
|
||||
RibbonController.RefreshControl("setPriceList");
|
||||
private static void RefreshExportButton(object sh, Range target)
|
||||
{
|
||||
RibbonController.RefreshControl("export");
|
||||
}
|
||||
|
||||
private static void RefreshSettingTitle(object sender, SettingChangingEventArgs e)
|
||||
{
|
||||
RibbonController.RefreshControl("setPriceList");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
#if !NET472
|
||||
using RhSolutions.AddIn;
|
||||
#if !NET472
|
||||
using System.Runtime.Versioning;
|
||||
#endif
|
||||
|
||||
@ -9,16 +10,15 @@ namespace RhSolutions.Tools;
|
||||
#endif
|
||||
internal class ExportTool : Tool
|
||||
{
|
||||
public ExportTool(ReaderFactory readerFactory, WriterFactory writerFactory) : base(readerFactory, writerFactory)
|
||||
public ExportTool(IServiceProvider provider) : base(provider)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Execute()
|
||||
{
|
||||
Application app = RhSolutionsAddIn.Excel.Application;
|
||||
_reader = _readerFactory.GetReader("Excel");
|
||||
var products = _reader.ReadProducts(app.Selection);
|
||||
_writer = _writerFactory.GetWriter("NewPrice");
|
||||
_writer = _writerFactory.GetWriter("Excel");
|
||||
_writer.WriteProducts(products);
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +0,0 @@
|
||||
namespace RhSolutions.Tools;
|
||||
|
||||
internal class FittingsTool : Tool
|
||||
{
|
||||
private readonly FittingsCalculatorFactory _factory;
|
||||
private string _calculatorName;
|
||||
|
||||
public FittingsTool(ReaderFactory readerFactory, WriterFactory writerFactory, FittingsCalculatorFactory calculatorFactory, string calculatorName) : base(readerFactory, writerFactory)
|
||||
{
|
||||
_factory = calculatorFactory;
|
||||
_calculatorName = calculatorName;
|
||||
}
|
||||
|
||||
public override void Execute()
|
||||
{
|
||||
Application app = RhSolutionsAddIn.Excel.Application;
|
||||
Worksheet worksheet = app.ActiveWorkbook.ActiveSheet;
|
||||
_reader = _readerFactory.GetReader("Excel");
|
||||
var products = _reader.ReadProducts(new[] { worksheet });
|
||||
var calculator = _factory.GetFittingsCalculator(_calculatorName);
|
||||
var fittings = calculator.Calculate(products.Select(p => p.Item2).First());
|
||||
_writer = _writerFactory.GetWriter("CurrentPrice");
|
||||
_writer.WriteProducts(fittings);
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
#if !NET472
|
||||
using System.Runtime.Versioning;
|
||||
#endif
|
||||
|
||||
namespace RhSolutions.Tools;
|
||||
|
||||
internal class GuessTool : Tool
|
||||
{
|
||||
public GuessTool(ReaderFactory readerFactory, WriterFactory writerFactory) : base(readerFactory, writerFactory)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Execute()
|
||||
{
|
||||
Application app = RhSolutionsAddIn.Excel.Application;
|
||||
Worksheet worksheet = app.ActiveWorkbook.ActiveSheet;
|
||||
_reader = _readerFactory.GetReader("Guess");
|
||||
var products = _reader.ReadProducts(new[] { worksheet });
|
||||
_writer = _writerFactory.GetWriter("NewPrice");
|
||||
_writer.WriteProducts(products);
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ namespace RhSolutions.Tools;
|
||||
#endif
|
||||
internal class MergeTool : Tool
|
||||
{
|
||||
public MergeTool(ReaderFactory readerFactory, WriterFactory writerFactory) : base(readerFactory, writerFactory)
|
||||
public MergeTool(IServiceProvider provider) : base(provider)
|
||||
{
|
||||
}
|
||||
|
||||
@ -17,12 +17,8 @@ internal class MergeTool : Tool
|
||||
{
|
||||
IFileDialog dialog = RhSolutionsAddIn.ServiceProvider.GetRequiredService<IFileDialog>();
|
||||
string[] files = dialog.GetFiles();
|
||||
if (files.Length > 0)
|
||||
{
|
||||
_reader = _readerFactory.GetReader("Excel");
|
||||
var products = _reader.ReadProducts(files);
|
||||
_writer = _writerFactory.GetWriter("NewPrice");
|
||||
_writer.WriteProducts(products);
|
||||
}
|
||||
var products = _reader.ReadProducts(files);
|
||||
_writer = _writerFactory.GetWriter("Excel");
|
||||
_writer.WriteProducts(products);
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ namespace RhSolutions.Tools;
|
||||
#if !NET472
|
||||
[SupportedOSPlatform("windows")]
|
||||
#endif
|
||||
public class ProgressBar : StatusbarBase
|
||||
internal class ProgressBar : StatusbarBase
|
||||
{
|
||||
private double CurrentProgress { get; set; }
|
||||
private readonly double TaskWeight;
|
||||
|
@ -8,7 +8,7 @@ namespace RhSolutions.Tools;
|
||||
#if !NET472
|
||||
[SupportedOSPlatform("windows")]
|
||||
#endif
|
||||
public class ResultBar : StatusbarBase
|
||||
internal class ResultBar : StatusbarBase
|
||||
{
|
||||
private int Success { get; set; }
|
||||
private int Replaced { get; set; }
|
||||
|
@ -11,16 +11,10 @@ namespace RhSolutions.Tools;
|
||||
#if !NET472
|
||||
[SupportedOSPlatform("windows")]
|
||||
#endif
|
||||
public abstract class StatusbarBase : IDisposable
|
||||
internal abstract class StatusbarBase : IDisposable
|
||||
{
|
||||
protected Application Excel = RhSolutionsAddIn.Excel;
|
||||
|
||||
[ExcelFunction(IsHidden = true)]
|
||||
public static void StatusBarReset()
|
||||
{
|
||||
RhSolutionsAddIn.Excel.StatusBar = false;
|
||||
}
|
||||
|
||||
public abstract void Update();
|
||||
|
||||
public void Dispose()
|
||||
|
@ -9,21 +9,20 @@ namespace RhSolutions.Tools;
|
||||
#endif
|
||||
internal abstract class Tool : IDisposable
|
||||
{
|
||||
protected readonly ReaderFactory _readerFactory;
|
||||
protected readonly IReader _reader;
|
||||
protected readonly WriterFactory _writerFactory;
|
||||
protected IReader _reader;
|
||||
protected IWriter _writer;
|
||||
|
||||
public Tool(ReaderFactory readerFactory, WriterFactory writerFactory)
|
||||
public Tool(IServiceProvider provider)
|
||||
{
|
||||
_readerFactory = readerFactory;
|
||||
_writerFactory = writerFactory;
|
||||
_reader = provider.GetRequiredService<IReader>();
|
||||
_writerFactory = provider.GetRequiredService<WriterFactory>();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_reader?.Dispose();
|
||||
_writer?.Dispose();
|
||||
_reader.Dispose();
|
||||
_writer.Dispose();
|
||||
}
|
||||
|
||||
public abstract void Execute();
|
||||
|
@ -2,22 +2,15 @@
|
||||
|
||||
internal class ToolFactory
|
||||
{
|
||||
static ReaderFactory readerFactory = RhSolutionsAddIn.ServiceProvider.GetService<ReaderFactory>();
|
||||
static WriterFactory writerFactory = RhSolutionsAddIn.ServiceProvider.GetService<WriterFactory>();
|
||||
static FittingsCalculatorFactory fittingsCalculatorFactory = RhSolutionsAddIn.ServiceProvider.GetService<FittingsCalculatorFactory>();
|
||||
|
||||
public Tool GetTool(string toolName)
|
||||
{
|
||||
Tool tool = toolName switch
|
||||
{
|
||||
"export" => new ExportTool(readerFactory, writerFactory),
|
||||
"convert" => new ConvertTool(readerFactory, writerFactory),
|
||||
"merge" => new MergeTool(readerFactory, writerFactory),
|
||||
"dxfexport" => new DxfTool(readerFactory, writerFactory),
|
||||
"guess" => new GuessTool(readerFactory, writerFactory),
|
||||
"fillsleeves" => new FittingsTool(readerFactory, writerFactory, fittingsCalculatorFactory, "Sleeves"),
|
||||
"fillcouplings" => new FittingsTool(readerFactory, writerFactory, fittingsCalculatorFactory, "Couplings"),
|
||||
_ => throw new Exception($"Неизвестный инструмент {toolName}"),
|
||||
"export" => new ExportTool(RhSolutionsAddIn.ServiceProvider),
|
||||
"convert" => new ConvertTool(RhSolutionsAddIn.ServiceProvider),
|
||||
"merge" => new MergeTool(RhSolutionsAddIn.ServiceProvider),
|
||||
"dxfexport" => new DxfTool(RhSolutionsAddIn.ServiceProvider),
|
||||
_ => throw new Exception("Неизвестный инструмент"),
|
||||
};
|
||||
return tool;
|
||||
}
|
||||
|
@ -14,32 +14,22 @@ public static class WorksheetExtensions
|
||||
|
||||
public static bool IsValidSource(this Worksheet worksheet)
|
||||
{
|
||||
Range headerRow;
|
||||
Range amountCell;
|
||||
Range skuCell;
|
||||
Range programLineCell;
|
||||
Range nameCell;
|
||||
Range measureCell;
|
||||
|
||||
string[] fields = pricelistParameters.Values
|
||||
.Where(v => v != "Прежний материал")
|
||||
.ToArray();
|
||||
|
||||
var value = worksheet.Cells.Find(fields[0]);
|
||||
|
||||
if (value == null)
|
||||
Range[] cells = new[]
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
headerRow = value.EntireRow;
|
||||
}
|
||||
amountCell = worksheet.Cells.Find(pricelistParameters["Amount"]),
|
||||
skuCell = worksheet.Cells.Find(pricelistParameters["Sku"]),
|
||||
programLineCell = worksheet.Cells.Find(pricelistParameters["ProductLine"]),
|
||||
nameCell = worksheet.Cells.Find(pricelistParameters["Name"]),
|
||||
measureCell = worksheet.Cells.Find(pricelistParameters["Measure"])
|
||||
};
|
||||
|
||||
for (int i = 1; i < fields.Length; i++)
|
||||
{
|
||||
if (headerRow.Find(fields[i]) == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return cells.All(x => x != null);
|
||||
}
|
||||
|
||||
public static void AddValue(this Range range, double value)
|
||||
@ -54,18 +44,5 @@ public static class WorksheetExtensions
|
||||
range.Value2 += value;
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddValue(this Range range, string value)
|
||||
{
|
||||
if (range.Value2 == null)
|
||||
{
|
||||
range.Value2 = value;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
range.Value2 = $"{range.Value2} {value}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,3 +0,0 @@
|
||||
namespace RhSolutions.Models;
|
||||
|
||||
public enum Measure { Kg, M, M2, P }
|
@ -1,91 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace RhSolutions.Models;
|
||||
public class Product : IDisposable
|
||||
{
|
||||
[JsonIgnore]
|
||||
public string Id
|
||||
{
|
||||
get => ProductSku.Id;
|
||||
set
|
||||
{
|
||||
ProductSku = new(value);
|
||||
}
|
||||
}
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public ProductSku ProductSku { get; set; }
|
||||
public List<ProductSku> DeprecatedSkus { get; set; } = new();
|
||||
public List<string> ProductLines { get; set; } = new();
|
||||
public bool IsOnWarehouse { get; set; } = false;
|
||||
public Measure ProductMeasure { get; set; }
|
||||
public double? DeliveryMakeUp { get; set; }
|
||||
public decimal Price { get; set; }
|
||||
|
||||
[JsonConstructor]
|
||||
public Product(string id,
|
||||
string name,
|
||||
ProductSku productSku,
|
||||
ProductSku[] deprecatedSkus,
|
||||
string[] productLines,
|
||||
bool isOnWarehouse,
|
||||
int productMeasure,
|
||||
int deliveryMakeUp,
|
||||
decimal price)
|
||||
{
|
||||
Id = id;
|
||||
Name = name;
|
||||
ProductSku = productSku;
|
||||
DeprecatedSkus = deprecatedSkus.ToList();
|
||||
ProductLines = productLines.ToList();
|
||||
IsOnWarehouse = isOnWarehouse;
|
||||
ProductMeasure = (Measure)productMeasure;
|
||||
DeliveryMakeUp = deliveryMakeUp;
|
||||
Price = price;
|
||||
}
|
||||
public Product(string sku)
|
||||
{
|
||||
ProductSku = new(sku);
|
||||
}
|
||||
|
||||
public Product(ProductSku productSku)
|
||||
{
|
||||
ProductSku = productSku;
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is Product product &&
|
||||
Name == product.Name &&
|
||||
EqualityComparer<ProductSku>.Default.Equals(ProductSku, product.ProductSku) &&
|
||||
DeprecatedSkus.SequenceEqual(product.DeprecatedSkus) &&
|
||||
ProductLines.SequenceEqual(product.ProductLines) &&
|
||||
IsOnWarehouse == product.IsOnWarehouse &&
|
||||
ProductMeasure == product.ProductMeasure &&
|
||||
DeliveryMakeUp == product.DeliveryMakeUp &&
|
||||
Price == product.Price;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
HashCode hash = new HashCode();
|
||||
hash.Add(Name);
|
||||
hash.Add(ProductSku);
|
||||
DeprecatedSkus.ForEach(x => hash.Add(x));
|
||||
ProductLines.ForEach(x => hash.Add(x));
|
||||
hash.Add(IsOnWarehouse);
|
||||
hash.Add(ProductMeasure);
|
||||
hash.Add(DeliveryMakeUp);
|
||||
hash.Add(Price);
|
||||
return hash.ToHashCode();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"({ProductSku}) {Name}";
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -1,194 +0,0 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace RhSolutions.Models;
|
||||
public class ProductSku
|
||||
{
|
||||
[JsonIgnore]
|
||||
public string Id
|
||||
{
|
||||
get
|
||||
{
|
||||
return $"1{Article}{Delimiter}{Variant}";
|
||||
}
|
||||
set
|
||||
{
|
||||
var matches = GetMatches(value);
|
||||
if (matches.Count == 0)
|
||||
{
|
||||
throw new ArgumentException($"Wrong Id: {value}");
|
||||
}
|
||||
else
|
||||
{
|
||||
var p = GetProducts(matches).First();
|
||||
_article = p.Article;
|
||||
_delimiter = p.Delimiter;
|
||||
_variant = p.Variant;
|
||||
}
|
||||
}
|
||||
}
|
||||
private const string matchPattern = @"(?<Lead>[1\s]|^|\b)(?<Article>\d{6})(?<Delimiter>[\s13-])(?<Variant>\d{3})(\b|$)";
|
||||
private string _article;
|
||||
private string _variant;
|
||||
private char _delimiter = '1';
|
||||
|
||||
[JsonConstructor]
|
||||
public ProductSku(string article, string delimiter, string variant)
|
||||
{
|
||||
_article = article;
|
||||
_delimiter = delimiter[0];
|
||||
_variant = variant;
|
||||
}
|
||||
|
||||
public ProductSku(string article, string variant)
|
||||
{
|
||||
_article = IsCorrectArticle(article) ? article
|
||||
: throw new ArgumentException($"Wrong Article: {article}");
|
||||
_variant = IsCorrectVariant(variant) ? variant
|
||||
: throw new ArgumentException($"Wrong Variant: {variant}");
|
||||
}
|
||||
public ProductSku(string line)
|
||||
{
|
||||
var matches = GetMatches(line);
|
||||
if (matches.Count == 0)
|
||||
{
|
||||
throw new ArgumentException($"Wrong new Sku input {line}");
|
||||
}
|
||||
else
|
||||
{
|
||||
var p = GetProducts(matches).First();
|
||||
_article = p.Article;
|
||||
_delimiter = p.Delimiter;
|
||||
_variant = p.Variant;
|
||||
}
|
||||
}
|
||||
|
||||
private ProductSku(Match match)
|
||||
{
|
||||
_article = match.Groups["Article"].Value;
|
||||
_delimiter = match.Groups["Delimiter"].Value switch
|
||||
{
|
||||
"3" => '3',
|
||||
_ => '1'
|
||||
};
|
||||
_variant = match.Groups["Variant"].Value;
|
||||
}
|
||||
public string Article
|
||||
{
|
||||
get => _article;
|
||||
set
|
||||
{
|
||||
_article = IsCorrectArticle(value) ? value
|
||||
: throw new ArgumentException($"Wrong Article: {value}");
|
||||
}
|
||||
}
|
||||
public string Variant
|
||||
{
|
||||
get => _variant;
|
||||
set
|
||||
{
|
||||
_variant = IsCorrectVariant(value) ? value
|
||||
: throw new ArgumentException($"Wrong Variant: {value}");
|
||||
}
|
||||
}
|
||||
|
||||
public char Delimiter
|
||||
{
|
||||
get => _delimiter;
|
||||
set
|
||||
{
|
||||
if (value != '1' || value != '3')
|
||||
{
|
||||
throw new ArgumentException($"Wrong Delimiter: {value}");
|
||||
}
|
||||
else
|
||||
{
|
||||
_delimiter = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<ProductSku> Parse(string line)
|
||||
{
|
||||
MatchCollection matches = GetMatches(line);
|
||||
if (matches.Count == 0)
|
||||
{
|
||||
return Enumerable.Empty<ProductSku>();
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetProducts(matches);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryParse(string line, out IEnumerable<ProductSku> skus)
|
||||
{
|
||||
MatchCollection matches = GetMatches(line);
|
||||
if (matches.Count == 0)
|
||||
{
|
||||
skus = Enumerable.Empty<ProductSku>();
|
||||
return false;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
skus = GetProducts(matches);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static MatchCollection GetMatches(string line)
|
||||
{
|
||||
return Regex.Matches(line, matchPattern);
|
||||
}
|
||||
|
||||
private static IEnumerable<ProductSku> GetProducts(MatchCollection matches)
|
||||
{
|
||||
foreach (Match match in matches)
|
||||
{
|
||||
yield return new ProductSku(match);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsCorrectArticle(string line)
|
||||
{
|
||||
return line != null
|
||||
&& line.Length == 6
|
||||
&& line.All(c => char.IsDigit(c));
|
||||
}
|
||||
|
||||
private static bool IsCorrectVariant(string line)
|
||||
{
|
||||
return line != null
|
||||
&& line.Length == 3
|
||||
&& line.All(c => char.IsDigit(c));
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Id;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null || GetType() != obj.GetType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ProductSku other = (ProductSku)obj;
|
||||
|
||||
return this.Article == other.Article &&
|
||||
this.Delimiter == other.Delimiter &&
|
||||
this.Variant == other.Variant;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
HashCode hash = new();
|
||||
hash.Add(_article);
|
||||
hash.Add(_variant);
|
||||
hash.Add(_delimiter);
|
||||
return hash.ToHashCode();
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<LangVersion>10.0</LangVersion>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>1.0.3</Version>
|
||||
<Authors>Serghei Cebotari</Authors>
|
||||
<Product>RhSolutions Sku</Product>
|
||||
<Description>Библиотека с классами моделей артикулов для плагинов и приложений RhSolutions</Description>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Bcl.HashCode" Version="1.1.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -1,62 +0,0 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using RhSolutions.AddIn;
|
||||
using System.IO;
|
||||
|
||||
namespace RhSolutions.Tests;
|
||||
|
||||
[ExcelTestSettings(OutOfProcess = true)]
|
||||
public class CanDoGuess : IDisposable
|
||||
{
|
||||
private RhSolutionsAddIn _addIn;
|
||||
private IReader _guessReader;
|
||||
private IReader _reader;
|
||||
|
||||
public CanDoGuess()
|
||||
{
|
||||
Environment.SetEnvironmentVariable("ISTESTING", "true");
|
||||
_addIn = new();
|
||||
_addIn.AutoOpen();
|
||||
_guessReader = new GuessReader(Util.Application);
|
||||
_reader = new ExcelReader(Util.Application, RhSolutionsAddIn.Configuration);
|
||||
}
|
||||
|
||||
[ExcelFact(Workbook = @"..\..\..\TestWorkbooks\TestSpecificationGuess.xlsx")]
|
||||
public void CanWriteMultiplyRows()
|
||||
{
|
||||
Worksheet sourceSheet = Util.Workbook.Worksheets[1];
|
||||
RhSolutionsAddIn.Configuration.SetPriceListPath(Path.GetFullPath(@"..\..\..\TestWorkbooks\TargetSpecificationGuess.xlsx"));
|
||||
var products = _guessReader.ReadProducts(new[] { sourceSheet });
|
||||
var _writer = new NewPriceWriter(Util.Application, RhSolutionsAddIn.Configuration);
|
||||
_writer.WriteProducts(products);
|
||||
Worksheet targetSheet = Util.Application.ActiveWindow.ActiveSheet;
|
||||
var targetProducts = _reader.ReadProducts(new[] { targetSheet });
|
||||
|
||||
Assert.Equal("TestSpecificationGuess", products.First().Item1);
|
||||
Assert.Equal("TargetSpecificationGuess", targetProducts.First().Item1);
|
||||
Assert.Equal(products.First().Item2.Count(), targetProducts.First().Item2.Count());
|
||||
Assert.Equal(products.First().Item2.Values.Sum(), targetProducts.First().Item2.Values.Sum());
|
||||
}
|
||||
|
||||
[ExcelFact(Workbook = @"..\..\..\TestWorkbooks\TestSpecificationGuessOneRow.xlsx")]
|
||||
public void CanWriteOneRow()
|
||||
{
|
||||
Worksheet sourceSheet = Util.Workbook.Worksheets[1];
|
||||
RhSolutionsAddIn.Configuration.SetPriceListPath(Path.GetFullPath(@"..\..\..\TestWorkbooks\TargetSpecificationGuessOneRow.xlsx"));
|
||||
var products = _guessReader.ReadProducts(new[] { sourceSheet });
|
||||
var _writer = new NewPriceWriter(Util.Application, RhSolutionsAddIn.Configuration);
|
||||
_writer.WriteProducts(products);
|
||||
Worksheet targetSheet = Util.Application.ActiveWindow.ActiveSheet;
|
||||
var targetProducts = _reader.ReadProducts(new[] { targetSheet });
|
||||
|
||||
Assert.Equal("TestSpecificationGuessOneRow", products.First().Item1);
|
||||
Assert.Equal("TargetSpecificationGuessOneRow", targetProducts.First().Item1);
|
||||
Assert.Equal(products.First().Item2.Count(), targetProducts.First().Item2.Count());
|
||||
Assert.Equal(products.First().Item2.Values.Sum(), targetProducts.First().Item2.Values.Sum());
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_addIn.AutoClose();
|
||||
Util.Application.ActiveWindow.Close(SaveChanges: false);
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
using RhSolutions.AddIn;
|
||||
|
||||
namespace RhSolutions.Tests;
|
||||
|
||||
[ExcelTestSettings(OutOfProcess = true)]
|
||||
public class CanFillCouplings : IDisposable
|
||||
{
|
||||
private RhSolutionsAddIn _addIn;
|
||||
private IFittingsCalculator _calculator;
|
||||
private IReader _reader;
|
||||
private IWriter _writer;
|
||||
private Worksheet _worksheet;
|
||||
|
||||
public CanFillCouplings()
|
||||
{
|
||||
Environment.SetEnvironmentVariable("ISTESTING", "true");
|
||||
_addIn = new();
|
||||
_addIn.AutoOpen();
|
||||
_calculator = new CouplingsCalculator();
|
||||
_reader = new ExcelReader(Util.Application, RhSolutionsAddIn.Configuration);
|
||||
_writer = new CurrentPriceWriter(Util.Application, RhSolutionsAddIn.Configuration);
|
||||
_worksheet = Util.Workbook.Worksheets[1];
|
||||
}
|
||||
|
||||
[ExcelFact(Workbook = @"..\..\..\TestWorkbooks\TestSpecificationCouplings.xlsx")]
|
||||
public void CanCalculateSleeves()
|
||||
{
|
||||
var products = _reader.ReadProducts(new[] { _worksheet });
|
||||
var couplings = _calculator.Calculate(products.First().Item2);
|
||||
_writer.WriteProducts(couplings);
|
||||
for (int i = 2; i < 14; i++)
|
||||
{
|
||||
Assert.Equal(_worksheet.Range[$"F{i}"].Value, _worksheet.Range[$"E{i}"].Value);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_addIn.AutoClose();
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
using RhSolutions.AddIn;
|
||||
|
||||
namespace RhSolutions.Tests;
|
||||
|
||||
[ExcelTestSettings(OutOfProcess = true)]
|
||||
public class CanFillSleeves : IDisposable
|
||||
{
|
||||
private RhSolutionsAddIn _addIn;
|
||||
private IFittingsCalculator _calculator;
|
||||
private IReader _reader;
|
||||
private IWriter _writer;
|
||||
private Worksheet _worksheet;
|
||||
|
||||
public CanFillSleeves()
|
||||
{
|
||||
Environment.SetEnvironmentVariable("ISTESTING", "true");
|
||||
_addIn = new();
|
||||
_addIn.AutoOpen();
|
||||
_calculator = new SleevesCalculator();
|
||||
_reader = new ExcelReader(Util.Application, RhSolutionsAddIn.Configuration);
|
||||
_writer = new CurrentPriceWriter(Util.Application, RhSolutionsAddIn.Configuration);
|
||||
_worksheet = Util.Workbook.Worksheets[1];
|
||||
}
|
||||
|
||||
[ExcelFact(Workbook = @"..\..\..\TestWorkbooks\TestSpecificationSleeves.xlsx")]
|
||||
public void CanCalculateSleeves()
|
||||
{
|
||||
var products = _reader.ReadProducts(new[] { _worksheet });
|
||||
var sleeves = _calculator.Calculate(products.First().Item2);
|
||||
_writer.WriteProducts(sleeves);
|
||||
for (int i = 2; i < 14; i++)
|
||||
{
|
||||
Assert.Equal(_worksheet.Range[$"F{i}"].Value, _worksheet.Range[$"E{i}"].Value);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_addIn.AutoClose();
|
||||
}
|
||||
}
|
@ -12,11 +12,10 @@ public class CanReadProducts : IDisposable
|
||||
|
||||
public CanReadProducts()
|
||||
{
|
||||
Environment.SetEnvironmentVariable("ISTESTING", "true");
|
||||
_addIn = new();
|
||||
_testWorkbook = Util.Application.Workbooks.Add();
|
||||
_addIn.AutoOpen();
|
||||
_reader = new ExcelReader(Util.Application, RhSolutionsAddIn.Configuration);
|
||||
_reader = RhSolutionsAddIn.ServiceProvider.GetRequiredService<IReader>();
|
||||
}
|
||||
|
||||
[ExcelFact]
|
||||
@ -46,17 +45,14 @@ public class CanReadProducts : IDisposable
|
||||
Assert.Equal(3, products.Count());
|
||||
}
|
||||
|
||||
[ExcelFact(Workbook = @"..\..\..\TestWorkbooks\TestSpecification.xlsx")]
|
||||
[ExcelFact(Workbook = @"TestWorkbooks\Specifications\HeatingFloor.xlsx")]
|
||||
public void CanReadWorkbook()
|
||||
{
|
||||
Worksheet worksheet = Util.Workbook.Worksheets[1];
|
||||
var result = _reader.ReadProducts(new[] { worksheet });
|
||||
Assert.NotNull(result);
|
||||
Assert.NotEmpty(result);
|
||||
Assert.Equal("TestSpecification", result.First().Item1);
|
||||
var products = result.First().Item2;
|
||||
Assert.Equal(46, products.Count());
|
||||
Assert.Equal(29266, products.Sum(p => p.Value));
|
||||
var products = _reader.ReadProducts(new[] { worksheet });
|
||||
|
||||
Assert.NotNull(products);
|
||||
Assert.NotEmpty(products);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
@ -1,116 +0,0 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using RhSolutions.AddIn;
|
||||
using System.IO;
|
||||
|
||||
namespace RhSolutions.Tests;
|
||||
|
||||
[ExcelTestSettings(OutOfProcess = true)]
|
||||
public class CanWriteProducts : IDisposable
|
||||
{
|
||||
private RhSolutionsAddIn _addIn;
|
||||
private IReader _reader;
|
||||
|
||||
public CanWriteProducts()
|
||||
{
|
||||
Environment.SetEnvironmentVariable("ISTESTING", "true");
|
||||
_addIn = new();
|
||||
_addIn.AutoOpen();
|
||||
_reader = new ExcelReader(Util.Application, RhSolutionsAddIn.Configuration);
|
||||
}
|
||||
|
||||
[ExcelFact(Workbook = @"..\..\..\TestWorkbooks\TestSpecification.xlsx")]
|
||||
public void CanWriteSingle()
|
||||
{
|
||||
Worksheet sourceSheet = Util.Workbook.Worksheets[1];
|
||||
RhSolutionsAddIn.Configuration.SetPriceListPath(Path.GetFullPath(@"..\..\..\TestWorkbooks\TargetSpecification.xlsx"));
|
||||
var products = _reader.ReadProducts(new[] { sourceSheet });
|
||||
var _writer = new NewPriceWriter(Util.Application, RhSolutionsAddIn.Configuration);
|
||||
_writer.WriteProducts(products);
|
||||
Worksheet targetSheet = Util.Application.ActiveWindow.ActiveSheet;
|
||||
var targetProducts = _reader.ReadProducts(new[] { targetSheet });
|
||||
|
||||
Assert.Equal("TestSpecification", products.First().Item1);
|
||||
Assert.Equal("TargetSpecification", targetProducts.First().Item1);
|
||||
Assert.Equal(products.First().Item2.Count(), targetProducts.First().Item2.Count());
|
||||
Assert.Equal(products.First().Item2.Values.Sum(), targetProducts.First().Item2.Values.Sum());
|
||||
}
|
||||
|
||||
[ExcelFact(Workbook = @"..\..\..\TestWorkbooks\TestSpecificationMultipleProductLines.xlsx")]
|
||||
public void CanWriteMultipleProductLines()
|
||||
{
|
||||
Worksheet sourceSheet = Util.Workbook.Worksheets[1];
|
||||
RhSolutionsAddIn.Configuration.SetPriceListPath(Path.GetFullPath(@"..\..\..\TestWorkbooks\TargetSpecificationMultipleProductLines.xlsx"));
|
||||
var products = _reader.ReadProducts(new[] { sourceSheet });
|
||||
var _writer = new NewPriceWriter(Util.Application, RhSolutionsAddIn.Configuration);
|
||||
_writer.WriteProducts(products);
|
||||
Worksheet targetSheet = Util.Application.ActiveWindow.ActiveSheet;
|
||||
var targetProducts = _reader.ReadProducts(new[] { targetSheet });
|
||||
|
||||
Assert.Equal("TestSpecificationMultipleProductLines", products.First().Item1);
|
||||
Assert.Equal("TargetSpecificationMultipleProductLines", targetProducts.First().Item1);
|
||||
Assert.Equal(2, targetProducts.First().Item2.Count());
|
||||
Assert.True(Enumerable.SequenceEqual(products.First().Item2, targetProducts.First().Item2));
|
||||
}
|
||||
|
||||
[ExcelFact(Workbook = @"..\..\..\TestWorkbooks\TestSpecificationNotFound.xlsx")]
|
||||
public void CanWriteNotFound()
|
||||
{
|
||||
Worksheet sourceSheet = Util.Workbook.Worksheets[1];
|
||||
RhSolutionsAddIn.Configuration.SetPriceListPath(Path.GetFullPath(@"..\..\..\TestWorkbooks\TargetSpecificationNotFound.xlsx"));
|
||||
var products = _reader.ReadProducts(new[] { sourceSheet });
|
||||
var _writer = new NewPriceWriter(Util.Application, RhSolutionsAddIn.Configuration);
|
||||
_writer.WriteProducts(products);
|
||||
Worksheet targetSheet = Util.Application.ActiveWindow.ActiveSheet;
|
||||
|
||||
Assert.Equal("???", targetSheet.Range["B4"].Value2);
|
||||
Assert.Contains("Молот Тора", targetSheet.Range["C4"].Value2);
|
||||
Assert.Contains("15555551555", targetSheet.Range["C4"].Value2);
|
||||
}
|
||||
|
||||
[ExcelFact(Workbook = @"..\..\..\TestWorkbooks\TestSpecificationReplaced.xlsx")]
|
||||
public void CanWriteReplaced()
|
||||
{
|
||||
Worksheet sourceSheet = Util.Workbook.Worksheets[1];
|
||||
RhSolutionsAddIn.Configuration.SetPriceListPath(Path.GetFullPath(@"..\..\..\TestWorkbooks\TargetSpecificationReplaced.xlsx"));
|
||||
var products = _reader.ReadProducts(new[] { sourceSheet });
|
||||
var _writer = new NewPriceWriter(Util.Application, RhSolutionsAddIn.Configuration);
|
||||
_writer.WriteProducts(products);
|
||||
Worksheet targetSheet = Util.Application.ActiveWindow.ActiveSheet;
|
||||
var targetProducts = _reader.ReadProducts(new[] { targetSheet });
|
||||
|
||||
Assert.Equal("TestSpecificationReplaced", products.First().Item1);
|
||||
Assert.Equal("TargetSpecificationReplaced", targetProducts.First().Item1);
|
||||
var result = targetProducts.First().Item2.ToArray();
|
||||
Assert.Contains("Молот Тора", result[0].Key.Name);
|
||||
Assert.Contains("15555551555", result[0].Key.Name);
|
||||
Assert.Equal(1, result[0].Value);
|
||||
Assert.Contains("Нога Вирта", result[1].Key.Name);
|
||||
Assert.Contains("17777771777", result[1].Key.Name);
|
||||
Assert.Equal(1, result[1].Value);
|
||||
}
|
||||
|
||||
[ExcelFact(Workbook = @"..\..\..\TestWorkbooks\TestSpecificationNewVariant.xlsx")]
|
||||
public void CanWriteNewVariant()
|
||||
{
|
||||
Worksheet sourceSheet = Util.Workbook.Worksheets[1];
|
||||
RhSolutionsAddIn.Configuration.SetPriceListPath(Path.GetFullPath(@"..\..\..\TestWorkbooks\TargetSpecificationNewVariant.xlsx"));
|
||||
var products = _reader.ReadProducts(new[] { sourceSheet });
|
||||
var _writer = new NewPriceWriter(Util.Application, RhSolutionsAddIn.Configuration);
|
||||
_writer.WriteProducts(products);
|
||||
Worksheet targetSheet = Util.Application.ActiveWindow.ActiveSheet;
|
||||
var targetProducts = _reader.ReadProducts(new[] { targetSheet });
|
||||
|
||||
Assert.Equal("TestSpecificationNewVariant", products.First().Item1);
|
||||
Assert.Equal("TargetSpecificationNewVariant", targetProducts.First().Item1);
|
||||
var result = targetProducts.First().Item2.ToArray();
|
||||
Assert.Contains("Молот Тора", result[0].Key.Name);
|
||||
Assert.Contains("11201111555", result[0].Key.Name);
|
||||
Assert.Equal(1, result[0].Value);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_addIn.AutoClose();
|
||||
Util.Application.ActiveWindow.Close(SaveChanges: false);
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using RhSolutions.AddIn;
|
||||
using System.IO;
|
||||
|
||||
namespace RhSolutions.Tests;
|
||||
|
||||
[ExcelTestSettings(OutOfProcess = true)]
|
||||
public class RealPricelistTest : IDisposable
|
||||
{
|
||||
private RhSolutionsAddIn _addIn;
|
||||
private IReader _reader;
|
||||
|
||||
public RealPricelistTest()
|
||||
{
|
||||
Environment.SetEnvironmentVariable("ISTESTING", "true");
|
||||
_addIn = new();
|
||||
_addIn.AutoOpen();
|
||||
_reader = new ExcelReader(Util.Application, RhSolutionsAddIn.Configuration);
|
||||
}
|
||||
|
||||
[ExcelFact(Workbook = @"..\..\..\TestWorkbooks\RealTestSpecification.xlsm")]
|
||||
public void CanWrite()
|
||||
{
|
||||
Worksheet sourceSheet = Util.Workbook.Worksheets[1];
|
||||
RhSolutionsAddIn.Configuration.SetPriceListPath(Path.GetFullPath(@"..\..\..\TestWorkbooks\RealTargetSpecification.xlsx"));
|
||||
var products = _reader.ReadProducts(new[] { sourceSheet });
|
||||
var _writer = new NewPriceWriter(Util.Application, RhSolutionsAddIn.Configuration);
|
||||
_writer.WriteProducts(products);
|
||||
Worksheet targetSheet = Util.Application.ActiveWindow.ActiveSheet;
|
||||
targetSheet.Range["A1"].Formula = "=SUM(H:H)";
|
||||
|
||||
Assert.Equal("RealTestSpecification", products.First().Item1);
|
||||
Assert.Equal("RealTargetSpecification.xlsx", Util.Application.ActiveWorkbook.Name);
|
||||
Assert.Equal(1188.0, targetSheet.Range["A1"].Value);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_addIn.AutoClose();
|
||||
Util.Application.ActiveWindow.Close(SaveChanges: false);
|
||||
}
|
||||
}
|
@ -10,12 +10,26 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ExcelDna.Interop" Version="15.0.1" />
|
||||
<PackageReference Include="ExcelDna.Testing" Version="1.8.0" />
|
||||
<PackageReference Include="ExcelDna.Testing" Version="1.6.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\RhSolutions.AddIn\RhSolutions.AddIn.csproj" />
|
||||
<ProjectReference Include="..\RhSolutions.ProductSku\RhSolutions.ProductSku.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="TestWorkbooks\EmptyTestTable.xlsx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="TestWorkbooks\EmptyWorkbook.xlsx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="TestWorkbooks\ExcelTableTest.xlsx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="TestWorkbooks\Specifications\HeatingFloor.xlsx">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -1,171 +0,0 @@
|
||||
using RhSolutions.Models;
|
||||
|
||||
namespace RhSolutions.Tests;
|
||||
|
||||
public class SkuTests
|
||||
{
|
||||
[Fact]
|
||||
public void EqualityTest()
|
||||
{
|
||||
Product p1 = new("11600011001")
|
||||
{
|
||||
Name = "Test",
|
||||
ProductLines = new List<string>
|
||||
{
|
||||
"TestLine"
|
||||
},
|
||||
IsOnWarehouse = true,
|
||||
ProductMeasure = Measure.Kg,
|
||||
DeliveryMakeUp = 100.0,
|
||||
Price = 1000
|
||||
};
|
||||
|
||||
Product p2 = new("11600011001")
|
||||
{
|
||||
Name = "Test",
|
||||
ProductLines = new List<string>
|
||||
{
|
||||
"TestLine"
|
||||
},
|
||||
IsOnWarehouse = true,
|
||||
ProductMeasure = Measure.Kg,
|
||||
DeliveryMakeUp = 100.0,
|
||||
Price = 1000
|
||||
};
|
||||
|
||||
Product p3 = new("11600013001")
|
||||
{
|
||||
Name = "Test",
|
||||
ProductLines = new List<string>
|
||||
{
|
||||
"TestLine"
|
||||
},
|
||||
IsOnWarehouse = true,
|
||||
ProductMeasure = Measure.Kg,
|
||||
DeliveryMakeUp = 100.0,
|
||||
Price = 1000
|
||||
};
|
||||
|
||||
Assert.True(p1.Equals(p2));
|
||||
Assert.False(p1.Equals(p3));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProductHashCodeTest()
|
||||
{
|
||||
Product p1 = new("11600011001")
|
||||
{
|
||||
Name = "Test",
|
||||
ProductLines = new List<string>
|
||||
{
|
||||
"TestLine"
|
||||
},
|
||||
IsOnWarehouse = true,
|
||||
ProductMeasure = Measure.Kg,
|
||||
DeliveryMakeUp = 100.0,
|
||||
Price = 1000
|
||||
};
|
||||
|
||||
Product p2 = new("11600011001")
|
||||
{
|
||||
Name = "Test",
|
||||
ProductLines = new List<string>
|
||||
{
|
||||
"TestLine"
|
||||
},
|
||||
IsOnWarehouse = true,
|
||||
ProductMeasure = Measure.Kg,
|
||||
DeliveryMakeUp = 100.0,
|
||||
Price = 1000
|
||||
};
|
||||
|
||||
Product p3 = new("11600013001")
|
||||
{
|
||||
Name = "Test",
|
||||
ProductLines = new List<string>
|
||||
{
|
||||
"TestLine"
|
||||
},
|
||||
IsOnWarehouse = true,
|
||||
ProductMeasure = Measure.Kg,
|
||||
DeliveryMakeUp = 100.0,
|
||||
Price = 1000
|
||||
};
|
||||
|
||||
int hash1 = p1.GetHashCode();
|
||||
int hash2 = p2.GetHashCode();
|
||||
int hash3 = p3.GetHashCode();
|
||||
Assert.True(hash1 == hash2);
|
||||
Assert.False(hash1 == hash3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SkuEqualityTest()
|
||||
{
|
||||
ProductSku sku1 = new("160001", "001");
|
||||
ProductSku sku2 = new("11600011001");
|
||||
Assert.True(sku1.Equals(sku2));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SkuHashCodeTest()
|
||||
{
|
||||
ProductSku sku1 = new("160001", "001");
|
||||
ProductSku sku2 = new("11600011001");
|
||||
int hash1 = sku1.GetHashCode();
|
||||
int hash2 = sku2.GetHashCode();
|
||||
Assert.True(hash1 == hash2);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("12222221333")]
|
||||
[InlineData("222222-333")]
|
||||
[InlineData("222222 333")]
|
||||
[InlineData("string 12222221333")]
|
||||
[InlineData("12222221333 string")]
|
||||
[InlineData("string 12222221333 string")]
|
||||
[InlineData("string 222222-333")]
|
||||
[InlineData("222222-333 string")]
|
||||
[InlineData("string 222222-333 string")]
|
||||
[InlineData("string 222222 333")]
|
||||
[InlineData("222222 333 string")]
|
||||
[InlineData("string 222222 333 string")]
|
||||
public void StandardSkuParseTest(string line)
|
||||
{
|
||||
Assert.True(ProductSku.TryParse(line, out var skus));
|
||||
Assert.True(skus.First().Article == "222222"
|
||||
&& skus.First().Variant == "333"
|
||||
&& skus.First().Delimiter == '1');
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("12222223444")]
|
||||
[InlineData("string 12222223444")]
|
||||
[InlineData("12222223444 string")]
|
||||
[InlineData("string 12222223444 string")]
|
||||
public void NewSkuParseTest(string line)
|
||||
{
|
||||
Assert.True(ProductSku.TryParse(line, out var skus));
|
||||
Assert.True(skus.First().Article == "222222"
|
||||
&& skus.First().Variant == "444"
|
||||
&& skus.First().Delimiter == '3');
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("160001-001 11384611001 160002 002 11600033003")]
|
||||
public void MultipleParseTest(string line)
|
||||
{
|
||||
Assert.True(ProductSku.TryParse(line, out var skus));
|
||||
Assert.Equal(4, skus.Count());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("160001 001")]
|
||||
[InlineData("160001*001")]
|
||||
[InlineData("160001001")]
|
||||
[InlineData("31600011001")]
|
||||
public void DoesntParse(string line)
|
||||
{
|
||||
Assert.False(ProductSku.TryParse(line, out _));
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -10,20 +10,19 @@ public class WorkbookValidationTests : IDisposable
|
||||
|
||||
public WorkbookValidationTests()
|
||||
{
|
||||
Environment.SetEnvironmentVariable("ISTESTING", "true");
|
||||
_addIn = new RhSolutionsAddIn();
|
||||
_addIn.AutoOpen();
|
||||
Util.Application.Workbooks.Add();
|
||||
}
|
||||
|
||||
[ExcelFact(Workbook = @"..\..\..\TestWorkbooks\EmptyTestTable.xlsx")]
|
||||
[ExcelFact(Workbook = @"TestWorkbooks\EmptyTestTable.xlsx")]
|
||||
public void WorksheetIsCorrect()
|
||||
{
|
||||
Worksheet worksheet = Util.Workbook.Sheets[1];
|
||||
Assert.True(worksheet.IsValidSource());
|
||||
}
|
||||
|
||||
[ExcelFact(Workbook = @"..\..\..\TestWorkbooks\EmptyWorkbook.xlsx")]
|
||||
[ExcelFact(Workbook = @"TestWorkbooks\EmptyWorkbook.xlsx")]
|
||||
public void EmptyWorkbookIsNotCorrect()
|
||||
{
|
||||
Worksheet worksheet = Util.Workbook.Sheets[1];
|
||||
|
@ -7,8 +7,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RhSolutions.AddIn", "RhSolu
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RhSolutions.Tests", "RhSolutions.Tests\RhSolutions.Tests.csproj", "{6EECCDDB-741C-404A-874F-BB8656265162}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RhSolutions.ProductSku", "RhSolutions.ProductSku\RhSolutions.ProductSku.csproj", "{59CD05D0-71E0-4027-968A-8BE89A6FDCEF}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -23,10 +21,6 @@ Global
|
||||
{6EECCDDB-741C-404A-874F-BB8656265162}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6EECCDDB-741C-404A-874F-BB8656265162}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6EECCDDB-741C-404A-874F-BB8656265162}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{59CD05D0-71E0-4027-968A-8BE89A6FDCEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{59CD05D0-71E0-4027-968A-8BE89A6FDCEF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{59CD05D0-71E0-4027-968A-8BE89A6FDCEF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{59CD05D0-71E0-4027-968A-8BE89A6FDCEF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
Loading…
Reference in New Issue
Block a user