aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSergey Chebotar <s.chebotar@gmail.com>2021-12-26 18:22:32 +0300
committerSergey Chebotar <s.chebotar@gmail.com>2021-12-26 18:22:32 +0300
commit54fc3320e7d64d7903b4d091fe0d5c15df01fd78 (patch)
treeac8b9aa1e883a85339a594b2797ab319cca73c4e /src
parent20cfbfcca3a779c04aecdca5e4b465651e2be42a (diff)
Move to /src
Diffstat (limited to 'src')
-rw-r--r--src/AddIn/AddIn.cs47
-rw-r--r--src/AddIn/Functions.cs56
-rw-r--r--src/AddIn/MemoryCacheUtil.cs37
-rw-r--r--src/AddIn/RegistryUtil.cs76
-rw-r--r--src/Assistant/HttpClientUtil.cs53
-rw-r--r--src/Assistant/IProduct.cs9
-rw-r--r--src/Assistant/ParseUtil.cs44
-rw-r--r--src/Assistant/RequestModifier.cs67
-rw-r--r--src/Assistant/SkuAssist.cs22
-rw-r--r--src/Assistant/SkuExtensions.cs12
-rw-r--r--src/Assistant/StoreResponse.cs21
-rw-r--r--src/Forms/Dialog.cs46
-rw-r--r--src/Forms/SettingsForm.Designer.cs46
-rw-r--r--src/Forms/SettingsForm.cs21
-rw-r--r--src/Forms/SettingsForm.resx120
-rw-r--r--src/PriceListTools/ExportTool.cs115
-rw-r--r--src/PriceListTools/MergeTool.cs88
-rw-r--r--src/PriceListTools/PriceList.cs87
-rw-r--r--src/PriceListTools/PriceListUtil.cs41
-rw-r--r--src/Properties/AssemblyInfo.cs36
-rw-r--r--src/Properties/ExcelDna.Build.props77
-rw-r--r--src/RehauSku.Assist-AddIn.dna13
-rw-r--r--src/RehauSku.Assist.csproj143
-rw-r--r--src/RehauSku.Assist.sln25
-rw-r--r--src/Ribbon/RibbonController.cs69
-rw-r--r--src/app.config15
-rw-r--r--src/packages.config15
27 files changed, 1401 insertions, 0 deletions
diff --git a/src/AddIn/AddIn.cs b/src/AddIn/AddIn.cs
new file mode 100644
index 0000000..67cdcc8
--- /dev/null
+++ b/src/AddIn/AddIn.cs
@@ -0,0 +1,47 @@
+using ExcelDna.Integration;
+using ExcelDna.IntelliSense;
+using ExcelDna.Registration;
+using System.Net.Http;
+using System.Runtime.Caching;
+
+
+namespace RehauSku
+{
+ public enum ResponseOrder
+ {
+ Default,
+ Relevance,
+ Name,
+ Price,
+ Series
+ }
+
+ public class AddIn : IExcelAddIn
+ {
+ public static HttpClient httpClient;
+ public static MemoryCache memoryCache;
+
+ public void AutoOpen()
+ {
+ httpClient = new HttpClient();
+ memoryCache = new MemoryCache("RehauSku");
+ RegisterFunctions();
+ IntelliSenseServer.Install();
+ RegistryUtil.Initialize();
+ }
+
+ public void AutoClose()
+ {
+ IntelliSenseServer.Uninstall();
+ RegistryUtil.Uninitialize();
+ memoryCache.Dispose();
+ }
+
+ void RegisterFunctions()
+ {
+ ExcelRegistration.GetExcelFunctions()
+ .ProcessAsyncRegistrations(nativeAsyncIfAvailable: false)
+ .RegisterFunctions();
+ }
+ }
+}
diff --git a/src/AddIn/Functions.cs b/src/AddIn/Functions.cs
new file mode 100644
index 0000000..618d17d
--- /dev/null
+++ b/src/AddIn/Functions.cs
@@ -0,0 +1,56 @@
+using ExcelDna.Integration;
+using RehauSku.Assistant;
+
+namespace RehauSku
+{
+ public class Functions
+ {
+ [ExcelFunction(description: "Получение названия первого продукта в поиске")]
+ public static object RAUNAME([ExcelArgument(Name = "\"Запрос\"", Description = "в свободной форме или ячейка с запросом")] string request)
+ => MakeRequest(request, ProductField.Name);
+
+ [ExcelFunction(Description = "Получение артикула первого продукта в поиске")]
+ public static object RAUSKU([ExcelArgument(Name = "\"Запрос\"", Description = "в свободной форме или ячейка с запросом")] string request)
+ => MakeRequest(request, ProductField.Id);
+
+ [ExcelFunction(Description = "Получение цены первого продукта в поиске")]
+ public static object RAUPRICE([ExcelArgument(Name = "\"Запрос\"", Description = "в свободной форме или ячейка с запросом")] string request)
+ => MakeRequest(request, ProductField.Price);
+
+ private static object MakeRequest(string request, ProductField field)
+ {
+ object result;
+
+ if (request.IsCached())
+ result = request.GetFromCache();
+
+ else
+ {
+ result = ExcelAsyncUtil.Run("Request", request, delegate
+ {
+ return request.RequestAndCache().GetAwaiter().GetResult();
+ });
+ }
+
+ if (result == null)
+ return "Не найдено :(";
+
+ if (result.Equals(ExcelError.ExcelErrorNA))
+ return "Загрузка...";
+
+ IProduct product = result as IProduct;
+
+ switch (field)
+ {
+ case ProductField.Name:
+ return product.Name;
+ case ProductField.Id:
+ return product.Id;
+ case ProductField.Price:
+ return double.Parse(product.Price, System.Globalization.CultureInfo.InvariantCulture);
+ default:
+ return null;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/AddIn/MemoryCacheUtil.cs b/src/AddIn/MemoryCacheUtil.cs
new file mode 100644
index 0000000..1d42e14
--- /dev/null
+++ b/src/AddIn/MemoryCacheUtil.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Runtime.Caching;
+using System.Threading.Tasks;
+using RehauSku.Assistant;
+
+namespace RehauSku
+{
+ static class MemoryCacheUtil
+ {
+ public static bool IsCached(this string request)
+ {
+ return AddIn.memoryCache.Contains(request);
+ }
+
+ public static IProduct GetFromCache(this string request)
+ {
+ return AddIn.memoryCache[request] as IProduct;
+ }
+
+ public static async Task<IProduct> RequestAndCache(this string request)
+ {
+ IProduct product = await SkuAssist.GetProductAsync(request);
+
+ if (product == null)
+ return null;
+
+ AddIn.memoryCache.Add(request, product, DateTime.Now.AddMinutes(10));
+ return product;
+ }
+
+ public static void ClearCache()
+ {
+ AddIn.memoryCache.Dispose();
+ AddIn.memoryCache = new MemoryCache("RehauSku");
+ }
+ }
+} \ No newline at end of file
diff --git a/src/AddIn/RegistryUtil.cs b/src/AddIn/RegistryUtil.cs
new file mode 100644
index 0000000..40d0ec2
--- /dev/null
+++ b/src/AddIn/RegistryUtil.cs
@@ -0,0 +1,76 @@
+using Microsoft.Win32;
+using System.IO;
+using RehauSku.Forms;
+using System.Windows.Forms;
+
+namespace RehauSku
+{
+ static class RegistryUtil
+ {
+ private static string _priceListPath;
+ private static int? _storeResponseOrder;
+ private static RegistryKey _RootKey { get; set; }
+
+ public static void Initialize()
+ {
+ _RootKey = Registry.CurrentUser.CreateSubKey(@"SOFTWARE\REHAU\SkuAssist");
+ _priceListPath = _RootKey.GetValue("PriceListPath") as string;
+ _storeResponseOrder = _RootKey.GetValue("StoreResponseOrder") as int?;
+ }
+
+ public static void Uninitialize()
+ {
+ _RootKey.Close();
+
+ }
+
+ public static bool IsPriceListPathEmpty()
+ {
+ return string.IsNullOrEmpty(_priceListPath);
+ }
+
+ public static string PriceListPath
+ {
+ get
+ {
+ if (IsPriceListPathEmpty() || !File.Exists(_priceListPath))
+ {
+ MessageBox.Show("Прайс-лист отсутствует или неверный файл прайс-листа", "Укажите файл прайс-листа", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ string fileName = Dialog.GetFilePath();
+ _priceListPath = fileName;
+ _RootKey.SetValue("PriceListPath", fileName);
+ return _priceListPath;
+ }
+
+ else
+ {
+ return _priceListPath;
+ }
+ }
+
+ set
+ {
+ _priceListPath = value;
+ _RootKey.SetValue("PriceListPath", value);
+ }
+ }
+
+ public static ResponseOrder StoreResponseOrder
+ {
+ get
+ {
+ if (_storeResponseOrder == null)
+ {
+ _RootKey.SetValue("StoreResponseOrder", (int)ResponseOrder.Default);
+ _storeResponseOrder = (int)ResponseOrder.Default;
+ return (ResponseOrder)_storeResponseOrder.Value;
+ }
+
+ else
+ {
+ return (ResponseOrder)_storeResponseOrder.Value;
+ }
+ }
+ }
+ }
+}
diff --git a/src/Assistant/HttpClientUtil.cs b/src/Assistant/HttpClientUtil.cs
new file mode 100644
index 0000000..316ea07
--- /dev/null
+++ b/src/Assistant/HttpClientUtil.cs
@@ -0,0 +1,53 @@
+using System;
+using System.Net;
+using System.Net.Http;
+using System.Threading.Tasks;
+
+namespace RehauSku.Assistant
+{
+ static class HttpClientUtil
+ {
+ private static HttpClient _httpClient = AddIn.httpClient;
+
+ public async static Task<string> GetContentByRequest(string request)
+ {
+ Uri uri = request.ConvertToUri();
+
+ ServicePointManager.SecurityProtocol =
+ SecurityProtocolType.Tls12 |
+ SecurityProtocolType.Tls11 |
+ SecurityProtocolType.Tls;
+
+ return await _httpClient.GetStringAsync(uri);
+ }
+
+ private static Uri ConvertToUri(this string request)
+ {
+ UriBuilder baseUri = new UriBuilder("https", "shop-rehau.ru");
+
+ baseUri.Path = "/catalogsearch/result/index/";
+ string cleanedRequest = request.CleanRequest();
+
+ switch (RegistryUtil.StoreResponseOrder)
+ {
+ case ResponseOrder.Relevance:
+ baseUri.Query = "dir=asc&order=relevance&q=" + cleanedRequest;
+ break;
+ case ResponseOrder.Name:
+ baseUri.Query = "dir=asc&order=name&q=" + cleanedRequest;
+ break;
+ case ResponseOrder.Price:
+ baseUri.Query = "dir=asc&order=price&q=" + cleanedRequest;
+ break;
+ case ResponseOrder.Series:
+ baseUri.Query = "dir=asc&order=sch_product_series&q=" + cleanedRequest;
+ break;
+ default:
+ baseUri.Query = "q=" + cleanedRequest;
+ break;
+ }
+
+ return baseUri.Uri;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Assistant/IProduct.cs b/src/Assistant/IProduct.cs
new file mode 100644
index 0000000..9494eeb
--- /dev/null
+++ b/src/Assistant/IProduct.cs
@@ -0,0 +1,9 @@
+namespace RehauSku.Assistant
+{
+ interface IProduct
+ {
+ string Id { get; }
+ string Name { get; }
+ string Price { get; }
+ }
+}
diff --git a/src/Assistant/ParseUtil.cs b/src/Assistant/ParseUtil.cs
new file mode 100644
index 0000000..a93c658
--- /dev/null
+++ b/src/Assistant/ParseUtil.cs
@@ -0,0 +1,44 @@
+using AngleSharp;
+using AngleSharp.Dom;
+using Newtonsoft.Json;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace RehauSku.Assistant
+{
+ static class ParseUtil
+ {
+ public async static Task<IDocument> ContentToDocAsync(string content)
+ {
+ IConfiguration config = Configuration.Default;
+ IBrowsingContext context = BrowsingContext.New(config);
+
+ return await context.OpenAsync(req => req.Content(content));
+ }
+
+ public static IProduct GetProduct(IDocument document)
+ {
+ string script = document
+ .Scripts
+ .Where(s => s.InnerHtml.Contains("dataLayer"))
+ .FirstOrDefault()
+ .InnerHtml;
+
+ string json = script
+ .Substring(script.IndexOf("push(") + 5)
+ .TrimEnd(new[] { ')', ';', '\n', ' ' });
+
+ if (!json.Contains("impressions"))
+ return null;
+
+ StoreResponce storeResponse = JsonConvert.DeserializeObject<StoreResponce>(json);
+ IProduct product = storeResponse
+ .Ecommerce
+ .Impressions
+ .Where(p => p.Id.IsRehauSku())
+ .FirstOrDefault();
+
+ return product;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Assistant/RequestModifier.cs b/src/Assistant/RequestModifier.cs
new file mode 100644
index 0000000..9f42e71
--- /dev/null
+++ b/src/Assistant/RequestModifier.cs
@@ -0,0 +1,67 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace RehauSku.Assistant
+{
+ public static class RequestModifier
+ {
+ public static string CleanRequest(this string input)
+ {
+ string replace = new StringBuilder(input)
+ .Replace("+", " plus ")
+ .Replace("РХ", "")
+ .Replace("º", " ")
+ .Replace(".", " ")
+ .Replace("Ø", " ")
+ .ToString();
+
+ return replace._tPieceNormalize();
+ }
+
+ private static string _tPieceNormalize(this string line)
+ {
+ Regex regex = new Regex(@"\d{2}.\d{2}.\d{2}");
+
+ if (!regex.IsMatch(line))
+ return line;
+
+ string match = regex.Match(line).Value;
+
+ int side = int.Parse($"{match[3]}{match[4]}");
+ int[] endFaces = new int[]
+ {
+ int.Parse($"{match[0]}{match[1]}"),
+ int.Parse($"{match[6]}{match[7]}")
+ };
+
+ if (new[] { endFaces[0], endFaces[1], side }.Any(x => x == 45 || x == 90 || x == 87))
+ return line;
+
+ List<string> additions = new List<string>();
+
+ if (endFaces.All(x => x < side))
+ additions.Add("увеличенный боковой");
+
+ else
+ {
+ if (new[] { endFaces[0], endFaces[1], side }.Distinct().Count() == 1)
+ additions.Add("равнопроходной");
+ else
+ additions.Add("уменьшенный");
+
+ if (endFaces.Any(x => x > side))
+ additions.Add("боковой");
+
+ if (endFaces[0] != endFaces[1])
+ additions.Add("торцевой");
+ }
+
+ string piece = $" {endFaces.Max()}-{side}-{endFaces.Min()} ";
+ string modifiedMatch = string.Join(" ", additions) + piece;
+
+ return line.Replace(match, modifiedMatch);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Assistant/SkuAssist.cs b/src/Assistant/SkuAssist.cs
new file mode 100644
index 0000000..6c68288
--- /dev/null
+++ b/src/Assistant/SkuAssist.cs
@@ -0,0 +1,22 @@
+using System.Threading.Tasks;
+
+namespace RehauSku.Assistant
+{
+ public enum ProductField
+ {
+ Name,
+ Id,
+ Price
+ }
+
+ static class SkuAssist
+ {
+ public static async Task<IProduct> GetProductAsync(string request)
+ {
+ var content = await HttpClientUtil.GetContentByRequest(request);
+ var document = await ParseUtil.ContentToDocAsync(content);
+
+ return ParseUtil.GetProduct(document);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Assistant/SkuExtensions.cs b/src/Assistant/SkuExtensions.cs
new file mode 100644
index 0000000..e39807b
--- /dev/null
+++ b/src/Assistant/SkuExtensions.cs
@@ -0,0 +1,12 @@
+using System.Text.RegularExpressions;
+
+namespace RehauSku.Assistant
+{
+ static class SkuExtensions
+ {
+ public static bool IsRehauSku(this string line)
+ {
+ return Regex.IsMatch(line, @"^[1]\d{6}[1]\d{3}$");
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Assistant/StoreResponse.cs b/src/Assistant/StoreResponse.cs
new file mode 100644
index 0000000..8e1759d
--- /dev/null
+++ b/src/Assistant/StoreResponse.cs
@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+
+namespace RehauSku.Assistant
+{
+ public class StoreResponce
+ {
+ public Ecommerce Ecommerce { get; set; }
+ }
+
+ public class Ecommerce
+ {
+ public List<Product> Impressions { get; set; }
+ }
+
+ public class Product : IProduct
+ {
+ public string Id { get; set; }
+ public string Name { get; set; }
+ public string Price { get; set; }
+ }
+} \ No newline at end of file
diff --git a/src/Forms/Dialog.cs b/src/Forms/Dialog.cs
new file mode 100644
index 0000000..170cc81
--- /dev/null
+++ b/src/Forms/Dialog.cs
@@ -0,0 +1,46 @@
+using System.Collections.Generic;
+using System.Windows.Forms;
+
+namespace RehauSku.Forms
+{
+ static class Dialog
+ {
+ public static string GetFilePath()
+ {
+ string filePath = string.Empty;
+
+ using (OpenFileDialog dialog = new OpenFileDialog())
+ {
+ dialog.Filter = "Файлы Excel (*.xls;*.xlsx;*.xlsm)|*.xls;*.xlsx;*.xlsm";
+
+ if (dialog.ShowDialog() == DialogResult.OK)
+ {
+ filePath = dialog.FileName;
+ }
+ }
+
+ return filePath;
+ }
+
+ public static string[] GetMultiplyFiles()
+ {
+ List<string> fileNames = new List<string>();
+
+ using (OpenFileDialog dialog = new OpenFileDialog())
+ {
+ dialog.Filter = "Файлы Excel (*.xls;*.xlsx;*.xlsm)|*.xls;*.xlsx;*.xlsm";
+ dialog.Multiselect = true;
+
+ if (dialog.ShowDialog() == DialogResult.OK)
+ {
+ foreach (string file in dialog.FileNames)
+ {
+ fileNames.Add(file);
+ }
+ }
+ }
+
+ return fileNames.ToArray();
+ }
+ }
+}
diff --git a/src/Forms/SettingsForm.Designer.cs b/src/Forms/SettingsForm.Designer.cs
new file mode 100644
index 0000000..669406e
--- /dev/null
+++ b/src/Forms/SettingsForm.Designer.cs
@@ -0,0 +1,46 @@
+namespace RehauSku.Forms
+{
+ partial class SettingsForm
+ {
+ /// <summary>
+ /// Required designer variable.
+ /// </summary>
+ private System.ComponentModel.IContainer components = null;
+
+ /// <summary>
+ /// Clean up any resources being used.
+ /// </summary>
+ /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ /// <summary>
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ /// </summary>
+ private void InitializeComponent()
+ {
+ this.SuspendLayout();
+ //
+ // SettingsForm
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(800, 450);
+ this.Name = "SettingsForm";
+ this.Text = "SettingsForm";
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+ }
+} \ No newline at end of file
diff --git a/src/Forms/SettingsForm.cs b/src/Forms/SettingsForm.cs
new file mode 100644
index 0000000..4dffadb
--- /dev/null
+++ b/src/Forms/SettingsForm.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace RehauSku.Forms
+{
+ public partial class SettingsForm : Form
+ {
+ public SettingsForm()
+ {
+ InitializeComponent();
+ }
+
+ }
+}
diff --git a/src/Forms/SettingsForm.resx b/src/Forms/SettingsForm.resx
new file mode 100644
index 0000000..1af7de1
--- /dev/null
+++ b/src/Forms/SettingsForm.resx
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+</root> \ No newline at end of file
diff --git a/src/PriceListTools/ExportTool.cs b/src/PriceListTools/ExportTool.cs
new file mode 100644
index 0000000..61f6f0f
--- /dev/null
+++ b/src/PriceListTools/ExportTool.cs
@@ -0,0 +1,115 @@
+using ExcelDna.Integration;
+using Microsoft.Office.Interop.Excel;
+using RehauSku.Assistant;
+using System;
+using System.Collections.Generic;
+
+namespace RehauSku.PriceListTools
+{
+ class ExportTool : IDisposable
+ {
+ private Application ExcelApp;
+ private Dictionary<string, double> SkuAmount { get; set; }
+ private Range Selection { get; set; }
+
+ public ExportTool()
+ {
+ this.ExcelApp = (Application)ExcelDnaUtil.Application;
+ Selection = ExcelApp.Selection;
+
+ if (IsRangeValid())
+ _FillSkuAmountDict();
+ }
+
+ public bool IsRangeValid()
+ {
+ return Selection != null &&
+ Selection.Columns.Count == 2;
+ }
+
+ private void _FillSkuAmountDict()
+ {
+ object[,] cells = Selection.Value2;
+ SkuAmount = new Dictionary<string, double>();
+ int rowsCount = Selection.Rows.Count;
+
+ for (int row = 1; row <= rowsCount; row++)
+ {
+ if (cells[row, 1] == null || cells[row, 2] == null)
+ continue;
+
+ string sku = null;
+ double? amount = null;
+
+ for (int column = 1; column <= 2; column++)
+ {
+ object current = cells[row, column];
+
+ if (current.ToString().IsRehauSku())
+ {
+ sku = current.ToString();
+ }
+
+ else if (current.GetType() == typeof(string)
+ && double.TryParse(current.ToString(), out _))
+ {
+ amount = double.Parse((string)current);
+ }
+
+ else if (current.GetType() == typeof(double))
+ {
+ amount = (double)current;
+ }
+ }
+
+ if (sku == null || amount == null)
+ continue;
+
+ if (SkuAmount.ContainsKey(sku))
+ SkuAmount[sku] += amount.Value;
+ else
+ SkuAmount.Add(sku, amount.Value);
+ }
+ }
+
+ public void ExportToNewFile()
+ {
+ if (SkuAmount.Count < 1)
+ {
+ return;
+ }
+
+ string exportFile = PriceListUtil.CreateNewExportFile();
+ Workbook wb = ExcelApp.Workbooks.Open(exportFile);
+
+ try
+ {
+ PriceList priceList = new PriceList(wb);
+ priceList.Fill(SkuAmount);
+ }
+
+ catch(Exception ex)
+ {
+ System.Windows.Forms.MessageBox.Show
+ ($"{RegistryUtil.PriceListPath} не является файлом прайс-листа \n\n {ex.Message}",
+ "Неверный файл прайс-листа!",
+ System.Windows.Forms.MessageBoxButtons.OK,
+ System.Windows.Forms.MessageBoxIcon.Error);
+
+ wb.Close();
+ }
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+
+ }
+ }
+}
+
diff --git a/src/PriceListTools/MergeTool.cs b/src/PriceListTools/MergeTool.cs
new file mode 100644
index 0000000..ddf74d2
--- /dev/null
+++ b/src/PriceListTools/MergeTool.cs
@@ -0,0 +1,88 @@
+using ExcelDna.Integration;
+using Microsoft.Office.Interop.Excel;
+using System;
+using System.Collections.Generic;
+
+namespace RehauSku.PriceListTools
+{
+ class MergeTool : IDisposable
+ {
+ private Application ExcelApp;
+ private Dictionary<string, double> SkuAmount { get; set; }
+
+ public MergeTool()
+ {
+ this.ExcelApp = (Application)ExcelDnaUtil.Application;
+ this.SkuAmount = new Dictionary<string, double>();
+ }
+
+ public void AddSkuAmountToDict(string[] files)
+ {
+ ExcelApp.ScreenUpdating = false;
+ foreach (string file in files)
+ {
+ Workbook wb = ExcelApp.Workbooks.Open(file);
+
+ try
+ {
+ PriceList priceList = new PriceList(wb);
+ SkuAmount.AddValues(priceList);
+ }
+
+ catch (Exception ex)
+ {
+ System.Windows.Forms.MessageBox.Show
+ ( $"{wb.Name} не является файлом прайс-листа \n\n {ex.Message}",
+ "Неверный файл прайс-листа!",
+ System.Windows.Forms.MessageBoxButtons.OK,
+ System.Windows.Forms.MessageBoxIcon.Error);
+ }
+
+ finally
+ {
+ wb.Close();
+ }
+ }
+ ExcelApp.ScreenUpdating = true;
+ }
+
+ public void ExportToNewFile(string exportFile)
+ {
+ if (SkuAmount.Count < 1)
+ {
+ return;
+ }
+
+ Workbook wb = ExcelApp.Workbooks.Open(exportFile);
+ PriceList priceList;
+
+ try
+ {
+ priceList = new PriceList(wb);
+ priceList.Fill(SkuAmount);
+ }
+
+ catch (Exception ex)
+ {
+ System.Windows.Forms.MessageBox.Show
+ ($"{RegistryUtil.PriceListPath} не является файлом прайс-листа \n\n {ex.Message}",
+ "Неверный файл прайс-листа!",
+ System.Windows.Forms.MessageBoxButtons.OK,
+ System.Windows.Forms.MessageBoxIcon.Error);
+
+ wb.Close();
+ }
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+
+ }
+ }
+}
diff --git a/src/PriceListTools/PriceList.cs b/src/PriceListTools/PriceList.cs
new file mode 100644
index 0000000..1460c07
--- /dev/null
+++ b/src/PriceListTools/PriceList.cs
@@ -0,0 +1,87 @@
+using Microsoft.Office.Interop.Excel;
+using System.Collections.Generic;
+
+namespace RehauSku.PriceListTools
+{
+ class PriceList
+ {
+ public readonly Workbook Workbook;
+ public readonly PriceListSheet OfferSheet;
+ public readonly PriceListSheet ActiveSheet;
+
+ private const string _amountHeader = "Кол-во";
+ private const string _skuHeader = "Актуальный материал";
+ private const string _offerSheetHeader = "КП";
+
+ public PriceList(Workbook workbook)
+ {
+ Workbook = workbook;
+ OfferSheet = new PriceListSheet(workbook.Sheets[_offerSheetHeader]);
+
+ Worksheet active = workbook.ActiveSheet;
+
+ if (active.Name == _offerSheetHeader)
+ ActiveSheet = OfferSheet;
+
+ else
+ ActiveSheet = new PriceListSheet(active);
+ }
+
+ public bool IsValid()
+ {
+ return OfferSheet.IsValid() &&
+ ActiveSheet.IsValid();
+ }
+
+ public void Fill(Dictionary<string, double> values)
+ {
+ Worksheet ws = OfferSheet.sheet;
+ ws.Activate();
+
+ int amountColumn = OfferSheet.amountColumn.Value;
+ int skuColumn = OfferSheet.skuColumn.Value;
+
+ foreach (KeyValuePair<string, double> kvp in values)
+ {
+ Range cell = ws.Columns[skuColumn].Find(kvp.Key);
+ ws.Cells[cell.Row, amountColumn].Value = kvp.Value;
+ }
+
+ AutoFilter filter = ws.AutoFilter;
+ int firstFilterColumn = filter.Range.Column;
+
+ filter.Range.AutoFilter(amountColumn - firstFilterColumn + 1, "<>");
+ ws.Range["A1"].Activate();
+ }
+
+ public class PriceListSheet
+ {
+ public readonly Worksheet sheet;
+ public readonly int? headerRow;
+ public readonly int? amountColumn;
+ public readonly int? skuColumn;
+ public object[,] amountCells;
+ public object[,] skuCells;
+
+ public PriceListSheet(Worksheet sheet)
+ {
+ this.sheet = sheet;
+ headerRow = sheet.Cells.Find(_amountHeader).Row;
+ amountColumn = sheet.Cells.Find(_amountHeader).Column;
+ skuColumn = sheet.Cells.Find(_skuHeader).Column;
+
+ amountCells = sheet.Columns[amountColumn].Value2;
+ skuCells = sheet.Columns[skuColumn].Value2;
+ }
+
+ public bool IsValid()
+ {
+ return sheet != null &&
+ headerRow != null &&
+ amountColumn != null &&
+ skuColumn != null;
+ }
+ }
+ }
+}
+
diff --git a/src/PriceListTools/PriceListUtil.cs b/src/PriceListTools/PriceListUtil.cs
new file mode 100644
index 0000000..14797d9
--- /dev/null
+++ b/src/PriceListTools/PriceListUtil.cs
@@ -0,0 +1,41 @@
+using System.Collections.Generic;
+using System.IO;
+
+namespace RehauSku.PriceListTools
+{
+ static class PriceListUtil
+ {
+ public static string CreateNewExportFile()
+ {
+ string fileExtension = Path.GetExtension(RegistryUtil.PriceListPath);
+ string path = Path.GetTempFileName() + fileExtension;
+
+ File.Copy(RegistryUtil.PriceListPath, path);
+ return path;
+ }
+
+ public static void AddValues(this Dictionary<string, double> SkuAmount, PriceList priceList)
+ {
+ object[,] amountCells = priceList.ActiveSheet.amountCells;
+ object[,] skuCells = priceList.ActiveSheet.skuCells;
+
+ for (int row = priceList.ActiveSheet.headerRow.Value + 1; row < amountCells.GetLength(0); row++)
+ {
+ object amount = amountCells[row, 1];
+ object sku = skuCells[row, 1];
+
+ if (amount != null && (double)amount != 0)
+ {
+ if (SkuAmount.ContainsKey(sku.ToString()))
+ {
+ SkuAmount[sku.ToString()] += (double)amount;
+ }
+
+ else
+ SkuAmount.Add(sku.ToString(), (double)amount);
+ }
+ }
+ }
+ }
+}
+
diff --git a/src/Properties/AssemblyInfo.cs b/src/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..b0cc560
--- /dev/null
+++ b/src/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("RehauSku.Assist")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("RehauSku.Assist")]
+[assembly: AssemblyCopyright("Copyright © 2021")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("18a2ff67-0e46-4a86-b872-29f2b3f23adf")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// 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.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/src/Properties/ExcelDna.Build.props b/src/Properties/ExcelDna.Build.props
new file mode 100644
index 0000000..1fed993
--- /dev/null
+++ b/src/Properties/ExcelDna.Build.props
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="ExcelDnaProps">
+<!--
+ If you change properties in this file, they may not come into effect until you:
+ * Rebuild the solution/project
+
+ or
+
+ * Close Visual Studio
+ * Delete .vs folder, if exists
+ * Delete ProjectName.csproj.user (or equivalent for VB, F#, etc.), if exists
+ * Delete SolutionName.suo, if exists
+ * Open your solution/project again in Visual Studio
+ -->
+
+ <!--
+ Configuration properties for debugging Excel-DNA add-ins
+ -->
+ <PropertyGroup>
+ <!--
+ Enable/Disable setting the debug options when building the project
+ -->
+ <RunExcelDnaSetDebuggerOptions Condition="'$(RunExcelDnaSetDebuggerOptions)' == ''">true</RunExcelDnaSetDebuggerOptions>
+
+ <!--
+ Override the path of EXCEL.EXE used for debugging the project, if you need
+ By default, it will use the latest version of Excel it can find on the machine
+ -->
+ <ExcelDnaExcelExePath Condition="'$(ExcelDnaExcelExePath)' == ''"></ExcelDnaExcelExePath>
+
+ <!--
+ Override the name of the .XLL add-in to use when debugging the project, if you need
+ By default, it will use the first unpacked .xll add-in that matches the bitness of EXCEL.EXE
+ -->
+ <ExcelDnaAddInForDebugging Condition="'$(ExcelDnaAddInForDebugging)' == ''"></ExcelDnaAddInForDebugging>
+ </PropertyGroup>
+
+ <!--
+ Configuration properties for building .dna files
+ -->
+ <PropertyGroup>
+ <!--
+ Enable/Disable automatic generation of platform-specific versions of .dna files
+ -->
+ <ExcelDnaCreate32BitAddIn Condition="'$(ExcelDnaCreate32BitAddIn)' == ''">true</ExcelDnaCreate32BitAddIn>
+ <ExcelDnaCreate64BitAddIn Condition="'$(ExcelDnaCreate64BitAddIn)' == ''">true</ExcelDnaCreate64BitAddIn>
+
+ <!--
+ Define the suffix used for each platform-specific file e.g. MyAddIn64.dna
+ -->
+ <ExcelDna32BitAddInSuffix Condition="'$(ExcelDna32BitAddInSuffix)' == ''"></ExcelDna32BitAddInSuffix>
+ <ExcelDna64BitAddInSuffix Condition="'$(ExcelDna64BitAddInSuffix)' == ''">64</ExcelDna64BitAddInSuffix>
+ </PropertyGroup>
+
+ <PropertyGroup>
+ <!--
+ Enable/Disable using Excel-DNA with PackageReference projects (not officially supported)
+ -->
+ <ExcelDnaAllowPackageReferenceProjectStyle Condition="'$(ExcelDnaAllowPackageReferenceProjectStyle)' == ''">false</ExcelDnaAllowPackageReferenceProjectStyle>
+ </PropertyGroup>
+
+ <!--
+ Configuration properties for packing .dna files
+ -->
+ <PropertyGroup>
+ <!--
+ Enable/Disable packing of .dna files
+ -->
+ <RunExcelDnaPack Condition="'$(RunExcelDnaPack)' == ''">true</RunExcelDnaPack>
+
+ <!--
+ Suffix used for packed .xll files e.g. MyAddIn-packed.xll
+ -->
+ <ExcelDnaPackXllSuffix Condition="'$(ExcelDnaPackXllSuffix)' == ''">-packed</ExcelDnaPackXllSuffix>
+ </PropertyGroup>
+</Project>
+
diff --git a/src/RehauSku.Assist-AddIn.dna b/src/RehauSku.Assist-AddIn.dna
new file mode 100644
index 0000000..1bef6e1
--- /dev/null
+++ b/src/RehauSku.Assist-AddIn.dna
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<DnaLibrary Name="RehauSku.Assist Add-In" RuntimeVersion="v4.0" xmlns="http://schemas.excel-dna.net/addin/2020/07/dnalibrary">
+ <ExternalLibrary Path="RehauSku.Assist.dll" ExplicitRegistration="true" LoadFromBytes="true" Pack="true" IncludePdb="false" />
+ <Reference Path="AngleSharp.dll" Pack="true" />
+ <Reference Path="ExcelDna.Registration.dll" Pack="true" />
+ <Reference Path="Newtonsoft.Json.dll" Pack="true" />
+ <Reference Path="System.Buffers.dll" Pack="true" />
+ <Reference Path="System.Memory.dll" Pack="true" />
+ <Reference Path="System.Numerics.Vectors.dll" Pack="true" />
+ <Reference Path="System.Runtime.CompilerServices.Unsafe.dll" Pack="true" />
+ <Reference Path="System.Text.Encoding.CodePages.dll" Pack="true" />
+ <Reference Path="ExcelDna.IntelliSense.dll" Pack="true" />
+</DnaLibrary> \ No newline at end of file
diff --git a/src/RehauSku.Assist.csproj b/src/RehauSku.Assist.csproj
new file mode 100644
index 0000000..a977125
--- /dev/null
+++ b/src/RehauSku.Assist.csproj
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{18A2FF67-0E46-4A86-B872-29F2B3F23ADF}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>RehauSku.Assist</RootNamespace>
+ <AssemblyName>RehauSku.Assist</AssemblyName>
+ <TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <Deterministic>true</Deterministic>
+ <NuGetPackageImportStamp>
+ </NuGetPackageImportStamp>
+ <TargetFrameworkProfile />
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="AngleSharp, Version=0.16.1.0, Culture=neutral, PublicKeyToken=e83494dcdc6d31ea, processorArchitecture=MSIL">
+ <HintPath>packages\AngleSharp.0.16.1\lib\net472\AngleSharp.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="ExcelDna.Integration, Version=1.1.0.0, Culture=neutral, PublicKeyToken=f225e9659857edbe, processorArchitecture=MSIL">
+ <HintPath>packages\ExcelDna.Integration.1.5.0\lib\net452\ExcelDna.Integration.dll</HintPath>
+ <Private>False</Private>
+ </Reference>
+ <Reference Include="ExcelDna.IntelliSense, Version=1.4.4.0, Culture=neutral, PublicKeyToken=f225e9659857edbe, processorArchitecture=MSIL">
+ <HintPath>packages\ExcelDna.IntelliSense.1.5.0\lib\net452\ExcelDna.IntelliSense.dll</HintPath>
+ </Reference>
+ <Reference Include="ExcelDna.Registration, Version=1.1.0.0, Culture=neutral, PublicKeyToken=f225e9659857edbe, processorArchitecture=MSIL">
+ <HintPath>packages\ExcelDna.Registration.1.5.0\lib\net452\ExcelDna.Registration.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="Microsoft.Office.Interop.Excel, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c, processorArchitecture=MSIL">
+ <HintPath>packages\ExcelDna.Interop.14.0.1\lib\Microsoft.Office.Interop.Excel.dll</HintPath>
+ <EmbedInteropTypes>True</EmbedInteropTypes>
+ </Reference>
+ <Reference Include="Microsoft.Vbe.Interop, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c, processorArchitecture=MSIL">
+ <HintPath>packages\ExcelDna.Interop.14.0.1\lib\Microsoft.Vbe.Interop.dll</HintPath>
+ <EmbedInteropTypes>True</EmbedInteropTypes>
+ </Reference>
+ <Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+ <HintPath>packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
+ </Reference>
+ <Reference Include="Office, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c, processorArchitecture=MSIL">
+ <HintPath>packages\ExcelDna.Interop.14.0.1\lib\Office.dll</HintPath>
+ <EmbedInteropTypes>True</EmbedInteropTypes>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+ <HintPath>packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Configuration" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Data.OracleClient" />
+ <Reference Include="System.Drawing" />
+ <Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+ <HintPath>packages\System.Memory.4.5.4\lib\net461\System.Memory.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Net" />
+ <Reference Include="System.Numerics" />
+ <Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Runtime.Caching" />
+ <Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Security" />
+ <Reference Include="System.ServiceProcess" />
+ <Reference Include="System.Text.Encoding.CodePages, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>packages\System.Text.Encoding.CodePages.6.0.0\lib\net461\System.Text.Encoding.CodePages.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Transactions" />
+ <Reference Include="System.Windows.Forms" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Xml" />
+ <Reference Include="WindowsBase" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Forms\Dialog.cs" />
+ <Compile Include="AddIn\RegistryUtil.cs" />
+ <Compile Include="AddIn\MemoryCacheUtil.cs" />
+ <Compile Include="Assistant\ParseUtil.cs" />
+ <Compile Include="Assistant\RequestModifier.cs" />
+ <Compile Include="Assistant\SkuExtensions.cs" />
+ <Compile Include="PriceListTools\MergeTool.cs" />
+ <Compile Include="PriceListTools\PriceList.cs" />
+ <Compile Include="PriceListTools\PriceListUtil.cs" />
+ <Compile Include="Ribbon\RibbonController.cs" />
+ <Compile Include="Assistant\HttpClientUtil.cs" />
+ <Compile Include="Assistant\StoreResponse.cs" />
+ <Compile Include="PriceListTools\ExportTool.cs" />
+ <Compile Include="AddIn\AddIn.cs" />
+ <Compile Include="Assistant\IProduct.cs" />
+ <Compile Include="AddIn\Functions.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="Assistant\SkuAssist.cs" />
+ <Compile Include="Forms\SettingsForm.cs">
+ <SubType>Form</SubType>
+ </Compile>
+ <Compile Include="Forms\SettingsForm.Designer.cs">
+ <DependentUpon>SettingsForm.cs</DependentUpon>
+ </Compile>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="app.config" />
+ <None Include="RehauSku.Assist-AddIn.dna" />
+ <None Include="packages.config" />
+ <None Include="Properties\ExcelDna.Build.props" />
+ </ItemGroup>
+ <ItemGroup />
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <Import Project="packages\ExcelDna.AddIn.1.5.0\build\ExcelDna.AddIn.targets" Condition="Exists('packages\ExcelDna.AddIn.1.5.0\build\ExcelDna.AddIn.targets')" />
+ <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+ <PropertyGroup>
+ <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+ </PropertyGroup>
+ <Error Condition="!Exists('packages\ExcelDna.AddIn.1.5.0\build\ExcelDna.AddIn.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\ExcelDna.AddIn.1.5.0\build\ExcelDna.AddIn.targets'))" />
+ </Target>
+</Project> \ No newline at end of file
diff --git a/src/RehauSku.Assist.sln b/src/RehauSku.Assist.sln
new file mode 100644
index 0000000..1fe96c1
--- /dev/null
+++ b/src/RehauSku.Assist.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.32014.148
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RehauSku.Assist", "RehauSku.Assist.csproj", "{18A2FF67-0E46-4A86-B872-29F2B3F23ADF}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {18A2FF67-0E46-4A86-B872-29F2B3F23ADF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {18A2FF67-0E46-4A86-B872-29F2B3F23ADF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {18A2FF67-0E46-4A86-B872-29F2B3F23ADF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {18A2FF67-0E46-4A86-B872-29F2B3F23ADF}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {3CF61093-14A6-4A2D-AC13-53EBA2253BAA}
+ EndGlobalSection
+EndGlobal
diff --git a/src/Ribbon/RibbonController.cs b/src/Ribbon/RibbonController.cs
new file mode 100644
index 0000000..df6f327
--- /dev/null
+++ b/src/Ribbon/RibbonController.cs
@@ -0,0 +1,69 @@
+using System.Runtime.InteropServices;
+using System.Windows.Forms;
+using ExcelDna.Integration.CustomUI;
+using RehauSku.PriceListTools;
+using RehauSku.Forms;
+
+namespace RehauSku.Ribbon
+{
+ [ComVisible(true)]
+ public class RibbonController : ExcelRibbon
+ {
+ public override string GetCustomUI(string RibbonID)
+ {
+ return @"
+ <customUI xmlns='http://schemas.microsoft.com/office/2006/01/customui'>
+ <ribbon>
+ <tabs>
+ <tab id='rau' label='REHAU'>
+ <group id='priceList' label='Прайс-лист'>
+ <button id='exportToPrice' label='Экспорт в новый файл' size='normal' imageMso='PivotExportToExcel' onAction='OnExportPressed'/>
+ <button id='mergeFiles' label='Объединить' size='normal' imageMso='Copy' onAction='OnMergePressed'/>
+ </group>
+ <group id='rausettings' label='Настройки'>
+ <button id='setPriceList' label='Файл прайс-листа' size='normal' imageMso='CurrentViewSettings' onAction='OnSetPricePressed'/>
+ </group>
+ </tab>
+ </tabs>
+ </ribbon>
+ </customUI>";
+ }
+
+ public void OnMergePressed(IRibbonControl control)
+ {
+ using (MergeTool mergeTool = new MergeTool())
+ {
+ string[] files = Dialog.GetMultiplyFiles();
+ mergeTool.AddSkuAmountToDict(files);
+ string exportFile = PriceListUtil.CreateNewExportFile();
+ mergeTool.ExportToNewFile(exportFile);
+ }
+ }
+
+ public void OnExportPressed(IRibbonControl control)
+ {
+ using (ExportTool exportTool = new ExportTool())
+ {
+ if (!exportTool.IsRangeValid())
+ {
+ MessageBox.Show("Выделен неверный диапазон!",
+ "Неверный диапазон",
+ MessageBoxButtons.OK,
+ MessageBoxIcon.Information);
+ return;
+ }
+
+ else
+ {
+ exportTool.ExportToNewFile();
+ }
+ }
+ }
+
+ public void OnSetPricePressed(IRibbonControl control)
+ {
+ string path = Dialog.GetFilePath();
+ RegistryUtil.PriceListPath = path;
+ }
+ }
+}
diff --git a/src/app.config b/src/app.config
new file mode 100644
index 0000000..3f5b7b7
--- /dev/null
+++ b/src/app.config
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+ <runtime>
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <dependentAssembly>
+ <assemblyIdentity name="System.Text.Encoding.CodePages" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
+ </dependentAssembly>
+ </assemblyBinding>
+ </runtime>
+<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" /></startup></configuration>
diff --git a/src/packages.config b/src/packages.config
new file mode 100644
index 0000000..6e8f1d1
--- /dev/null
+++ b/src/packages.config
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="AngleSharp" version="0.16.1" targetFramework="net48" />
+ <package id="ExcelDna.AddIn" version="1.5.0" targetFramework="net480" />
+ <package id="ExcelDna.Integration" version="1.5.0" targetFramework="net480" />
+ <package id="ExcelDna.IntelliSense" version="1.5.0" targetFramework="net48" />
+ <package id="ExcelDna.Interop" version="14.0.1" targetFramework="net48" />
+ <package id="ExcelDna.Registration" version="1.5.0" targetFramework="net480" />
+ <package id="Newtonsoft.Json" version="13.0.1" targetFramework="net48" />
+ <package id="System.Buffers" version="4.5.1" targetFramework="net48" />
+ <package id="System.Memory" version="4.5.4" targetFramework="net48" />
+ <package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net48" />
+ <package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" targetFramework="net48" />
+ <package id="System.Text.Encoding.CodePages" version="6.0.0" targetFramework="net48" />
+</packages> \ No newline at end of file