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