diff --git a/RhSolutions.AddIn/AddIn/RhSolutionsAddIn.cs b/RhSolutions.AddIn/AddIn/RhSolutionsAddIn.cs index dcb0f7d..f2bdd6f 100644 --- a/RhSolutions.AddIn/AddIn/RhSolutionsAddIn.cs +++ b/RhSolutions.AddIn/AddIn/RhSolutionsAddIn.cs @@ -63,7 +63,7 @@ public sealed class RhSolutionsAddIn : IExcelAddIn }; if (!isTesting) { - IntelliSenseServer.Install(); + //IntelliSenseServer.Install(); } ServicePointManager.SecurityProtocol = @@ -82,7 +82,7 @@ public sealed class RhSolutionsAddIn : IExcelAddIn }; if (!isTesting) { - IntelliSenseServer.Uninstall(); + //IntelliSenseServer.Uninstall(); } } } diff --git a/RhSolutions.AddIn/RhSolutions.AddIn.csproj b/RhSolutions.AddIn/RhSolutions.AddIn.csproj index d73b404..a08a8f2 100644 --- a/RhSolutions.AddIn/RhSolutions.AddIn.csproj +++ b/RhSolutions.AddIn/RhSolutions.AddIn.csproj @@ -39,8 +39,10 @@ - + + + \ No newline at end of file diff --git a/RhSolutions.ProductSku/Measure.cs b/RhSolutions.ProductSku/Measure.cs new file mode 100644 index 0000000..d7911ab --- /dev/null +++ b/RhSolutions.ProductSku/Measure.cs @@ -0,0 +1,3 @@ +namespace RhSolutions.Models; + +public enum Measure { Kg, M, M2, P } diff --git a/RhSolutions.ProductSku/Product.cs b/RhSolutions.ProductSku/Product.cs new file mode 100644 index 0000000..5a6f5fa --- /dev/null +++ b/RhSolutions.ProductSku/Product.cs @@ -0,0 +1,91 @@ +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 DeprecatedSkus { get; set; } = new(); + public List 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.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() + { + + } +} diff --git a/RhSolutions.ProductSku/ProductSku.cs b/RhSolutions.ProductSku/ProductSku.cs new file mode 100644 index 0000000..7e3e763 --- /dev/null +++ b/RhSolutions.ProductSku/ProductSku.cs @@ -0,0 +1,194 @@ +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 = @"(?[1\s]|^|\b)(?
\d{6})(?[\s13-])(?\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 Parse(string line) + { + MatchCollection matches = GetMatches(line); + if (matches.Count == 0) + { + return Enumerable.Empty(); + } + else + { + return GetProducts(matches); + } + } + + public static bool TryParse(string line, out IEnumerable skus) + { + MatchCollection matches = GetMatches(line); + if (matches.Count == 0) + { + skus = Enumerable.Empty(); + return false; + } + + else + { + skus = GetProducts(matches); + return true; + } + } + + private static MatchCollection GetMatches(string line) + { + return Regex.Matches(line, matchPattern); + } + + private static IEnumerable 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(); + } +} diff --git a/RhSolutions.ProductSku/RhSolutions.ProductSku.csproj b/RhSolutions.ProductSku/RhSolutions.ProductSku.csproj new file mode 100644 index 0000000..ecf5130 --- /dev/null +++ b/RhSolutions.ProductSku/RhSolutions.ProductSku.csproj @@ -0,0 +1,20 @@ + + + + net472;net6.0;net7.0;net8.0 + 10.0 + enable + enable + 1.0.3 + Serghei Cebotari + RhSolutions Sku + Библиотека с классами моделей артикулов для плагинов и приложений RhSolutions + + + + + + + + + diff --git a/RhSolutions.Tests/RhSolutions.Tests.csproj b/RhSolutions.Tests/RhSolutions.Tests.csproj index 8c6b442..b1491cb 100644 --- a/RhSolutions.Tests/RhSolutions.Tests.csproj +++ b/RhSolutions.Tests/RhSolutions.Tests.csproj @@ -15,6 +15,7 @@ + diff --git a/RhSolutions.Tests/SkuTests.cs b/RhSolutions.Tests/SkuTests.cs new file mode 100644 index 0000000..ab9a1c2 --- /dev/null +++ b/RhSolutions.Tests/SkuTests.cs @@ -0,0 +1,171 @@ +using RhSolutions.Models; + +namespace RhSolutions.Tests; + +public class SkuTests +{ + [Fact] + public void EqualityTest() + { + Product p1 = new("11600011001") + { + Name = "Test", + ProductLines = new List + { + "TestLine" + }, + IsOnWarehouse = true, + ProductMeasure = Measure.Kg, + DeliveryMakeUp = 100.0, + Price = 1000 + }; + + Product p2 = new("11600011001") + { + Name = "Test", + ProductLines = new List + { + "TestLine" + }, + IsOnWarehouse = true, + ProductMeasure = Measure.Kg, + DeliveryMakeUp = 100.0, + Price = 1000 + }; + + Product p3 = new("11600013001") + { + Name = "Test", + ProductLines = new List + { + "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 + { + "TestLine" + }, + IsOnWarehouse = true, + ProductMeasure = Measure.Kg, + DeliveryMakeUp = 100.0, + Price = 1000 + }; + + Product p2 = new("11600011001") + { + Name = "Test", + ProductLines = new List + { + "TestLine" + }, + IsOnWarehouse = true, + ProductMeasure = Measure.Kg, + DeliveryMakeUp = 100.0, + Price = 1000 + }; + + Product p3 = new("11600013001") + { + Name = "Test", + ProductLines = new List + { + "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 _)); + } +} \ No newline at end of file diff --git a/RhSolutions.sln b/RhSolutions.sln index 8d94b9b..610e085 100644 --- a/RhSolutions.sln +++ b/RhSolutions.sln @@ -7,6 +7,8 @@ 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 @@ -21,6 +23,10 @@ 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