From 22f39b0099ffc38c8e8bd5baeb032da00f352c93 Mon Sep 17 00:00:00 2001 From: FH Date: Wed, 6 Apr 2022 12:02:25 +0200 Subject: [PATCH] added vat number length check --- FCS.Lib.Utility.csproj | 2 +- Properties/AssemblyInfo.cs | 4 +- VatFormatValidator.cs | 173 +++++++++++++++++++++++++++++++++++++ VatUtils.cs | 160 ---------------------------------- 4 files changed, 176 insertions(+), 163 deletions(-) create mode 100644 VatFormatValidator.cs delete mode 100644 VatUtils.cs diff --git a/FCS.Lib.Utility.csproj b/FCS.Lib.Utility.csproj index eb430e7..69fde39 100644 --- a/FCS.Lib.Utility.csproj +++ b/FCS.Lib.Utility.csproj @@ -56,7 +56,7 @@ - + diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index 9010617..fe4f9a5 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -16,5 +16,5 @@ using System.Runtime.InteropServices; [assembly: ComVisible(false)] [assembly: Guid("aaf08873-14e5-411d-8ec8-629782ac8f03")] -[assembly: AssemblyVersion("2.1.22093.1132")] -[assembly: AssemblyFileVersion("2.1.22093.1132")] \ No newline at end of file +[assembly: AssemblyVersion("2.1.22095.1512")] +[assembly: AssemblyFileVersion("2.1.22095.1512")] \ No newline at end of file diff --git a/VatFormatValidator.cs b/VatFormatValidator.cs new file mode 100644 index 0000000..1a071c4 --- /dev/null +++ b/VatFormatValidator.cs @@ -0,0 +1,173 @@ +using System.Linq; + +namespace FCS.Lib.Utility +{ + public static class VatFormatValidator + { + // https://ec.europa.eu/taxation_customs/vies/faqvies.do#item_11 + // https://ec.europa.eu/taxation_customs/vies/ + + public static bool CheckVat(string countryCode, string vatNumber) + { + return countryCode.ToUpperInvariant() switch + { + "DK" => ValidateFormatDk(vatNumber), + "NO" => ValidateFormatNo(vatNumber), + "SE" => ValidateFormatSe(vatNumber), + _ => false + }; + } + + private static bool ValidateFormatDk(string vatNumber) + { + // https://wiki.scn.sap.com/wiki/display/CRM/Denmark + // 8 digits 0 to 9 + // C1..C7 + // C8 check-digit MOD11 + // C1 > 0 + // R = (2*C1 + 7*C2 + 6*C3 + 5*C4 + 4*C5 + 3*C6 + 2*C7 + C8) + return (int)char.GetNumericValue(vatNumber[0]) == 1 && vatNumber.Length == 8 && ValidateMod11(vatNumber); + } + + private static bool ValidateFormatNo(string vatNumber) + { + // https://wiki.scn.sap.com/wiki/display/CRM/Norway + // 12 digits + // C1..C8 random 0 to 9 + // C9 check-digit MOD11 + // C10 C11 C12 chars == MVA + return vatNumber.Length >= 9 && ValidateMod11(vatNumber.Substring(0, 8)); + } + + private static bool ValidateFormatSe(string vatNumber) + { + // https://wiki.scn.sap.com/wiki/display/CRM/Sweden + // 12 digits 0 to 9 + // C10 = (10 – (18 + 5 + 1 + 8 + 4)MOD10 10) MOD10 + // R = S1 + S3 + S5 + S7 + S9 + // Si = int(Ci/5) + (Ci*2)MOD10) + // https://www.skatteverket.se/skatter/mervardesskattmoms/momsregistreringsnummer.4.18e1b10334ebe8bc80002649.html + // C11 C12 == 01 (De två sista siffrorna är alltid 01) + if (vatNumber.Length != 12 || vatNumber.Substring(10) != "01" || long.Parse(vatNumber) == 0) + return false; + + var r = new[] { 0, 2, 4, 5, 8 } + .Sum(m => (int)char.GetNumericValue(vatNumber[m]) / 5 + + (int)char.GetNumericValue(vatNumber[m]) * 2 % 10); + var c1 = new[] { 1, 3, 5, 7 }.Sum(m => (int)char.GetNumericValue(vatNumber[m])); + var c10 = (10 - (r + c1) % 10) % 10; + return $"{vatNumber.Substring(0,9)}{c10}{vatNumber.Substring(9,1)}" == vatNumber; + } + + private static bool ValidateMod11(string number) + { + if (long.Parse(number) == 0) + return false; + var sum = 0; + for (int i = number.Length - 1, multiplier = 1; i >= 0; i--) + { + // Console.WriteLine($"char: {number[i]} multiplier: {multiplier}"); + sum += (int)char.GetNumericValue(number[i]) * multiplier; + if (++multiplier > 7) multiplier = 2; + } + + return sum % 11 == 0; + } + + //private static string SanitizeVatNumber(string vatNumber) + //{ + // var washing = vatNumber.Replace(" ", "").Replace("-", "").ToUpperInvariant(); + // var result = washing.Replace("DK", "").Replace("NO", "").Replace("SE","") ; + // if (result.Contains("MVA")) + // result = result.Replace("MVA", ""); + // return result.Length switch + // { + // >= 10 => vatNumber[..10], + // < 10 => result + // }; + //} + //private static bool ValidateMod10(string number) + //{ + // if (long.Parse(number) == 0) + // return false; + + // var nDigits = number.Length; + // var nSum = 0; + // var isSecond = false; + // for (var i = nDigits - 1; i >= 0; i--) + // { + // var d = (int)char.GetNumericValue(number[i]) - '0'; + // if (isSecond) + // d *= 2; + // nSum += d / 10; + // nSum += d % 10; + // isSecond = !isSecond; + // } + // return nSum % 10 == 0; + //} + + //private static string GetMod10CheckDigit(string number) + //{ + // var sum = 0; + // var alt = true; + // var digits = number.ToCharArray(); + // for (var i = digits.Length - 1; i >= 0; i--) + // { + // var curDigit = digits[i] - 48; + // if (alt) + // { + // curDigit *= 2; + // if (curDigit > 9) + // curDigit -= 9; + // } + + // sum += curDigit; + // alt = !alt; + // } + // return sum % 10 == 0 ? "0" : (10 - sum % 10).ToString(); + //} + + //private string AddMod11CheckDigit(string number) + //{ + // return number + GetMod11CheckDigit(number); + //} + + //private static string GetMod11CheckDigit(string number) + //{ + // var sum = 0; + // for (int i = number.Length - 1, multiplier = 2; i >= 0; i--) + // { + // sum += (int)char.GetNumericValue(number[i]) * multiplier; + // if (++multiplier > 7) multiplier = 2; + // } + + // var modulo = sum % 11; + // return modulo is 0 or 1 ? "0" : (11 - modulo).ToString(); + //} + + //private static bool CheckLuhn(string vatNumber) + //{ + // // https://www.geeksforgeeks.org/luhn-algorithm/ + + // var nDigits = vatNumber.Length; + // var nSum = 0; + // var isSecond = false; + // for (var i = nDigits - 1; i >= 0; i--) + // { + // var d = (int)char.GetNumericValue(vatNumber[i]) - '0'; + // if (isSecond) + // d *= 2; + // // We add two digits to handle + // // cases that make two digits + // // after doubling + // nSum += d / 10; + // nSum += d % 10; + + // isSecond = !isSecond; + // } + + // return nSum % 10 == 0; + //} + + } +} \ No newline at end of file diff --git a/VatUtils.cs b/VatUtils.cs deleted file mode 100644 index a96ef9e..0000000 --- a/VatUtils.cs +++ /dev/null @@ -1,160 +0,0 @@ -using System.Linq; - -namespace FCS.Lib.Utility -{ - public static class VatUtils - { - public static bool CheckVat(string countryCode, string vatNumber) - { - return countryCode.ToUpperInvariant() switch - { - "DK" => CheckVatNumberDenmark(vatNumber), - "NO" => CheckVatNumberNorway(vatNumber), - "SE" => CheckVatNumberSweden(vatNumber), - _ => false - }; - } - - public static bool CheckVatNumberDenmark(string vatNumber) - { - // https://wiki.scn.sap.com/wiki/display/CRM/Denmark - // 8 digits 0 to 9 - // C1..C7 - // C8 Modulo 11 check digit - // C1 > 0 - // R = (2*C1 + 7*C2 + 6*C3 + 5*C4 + 4*C5 + 3*C6 + 2*C7 + C8) - return (int)char.GetNumericValue(vatNumber[0]) == 1 && vatNumber.Length == 8 && ValidateMod11(vatNumber); - } - - public static bool CheckVatNumberNorway(string vatNumber) - { - // https://wiki.scn.sap.com/wiki/display/CRM/Norway - // 12 digits - // C1..C8 random 0 to 9 - // C9 Check MOD11 - // C10 C11 C12 chars == MVA - return vatNumber.Length >= 9 && ValidateMod11(vatNumber.Substring(0, 8)); - } - - public static bool CheckVatNumberSweden(string vatNumber) - { - // https://wiki.scn.sap.com/wiki/display/CRM/Sweden - // 12 digits 0 to 9 - // C1 = (10 - (R + C2 + C4 + C6 + C8) modulo 10) modulo 10 - // R = S1 + S3 + S5 + S7 + S9 - // Si = int(Ci/5) + (Ci*2) modulo 10) - // C11 C12 >= 01 <= 94 - // - // Validate full string using Luhn algoritm - // 12 chars - if (vatNumber.Length != 12 || vatNumber.Substring(10) != "01" || long.Parse(vatNumber) == 0) - return false; - - var r = new[] { 0, 2, 4, 5, 8 } - .Sum(m => (int)char.GetNumericValue(vatNumber[m]) / 5 + - (int)char.GetNumericValue(vatNumber[m]) * 2 % 10); - var c1 = new[] { 1, 3, 5, 7 }.Sum(m => (int)char.GetNumericValue(vatNumber[m])); - var c10 = (10 - (r + c1) % 10) % 10; - return $"{vatNumber.Substring(0,9)}{c10}{vatNumber.Substring(9,1)}" == vatNumber; - } - - public static bool ValidateMod11(string number) - { - if (long.Parse(number) == 0) - return false; - var sum = 0; - for (int i = number.Length - 1, multiplier = 1; i >= 0; i--) - { - // Console.WriteLine($"char: {number[i]} multiplier: {multiplier}"); - sum += (int)char.GetNumericValue(number[i]) * multiplier; - if (++multiplier > 7) multiplier = 2; - } - - return sum % 11 == 0; - } - - public static bool ValidateMod10(string number) - { - if (long.Parse(number) == 0) - return false; - - var nDigits = number.Length; - var nSum = 0; - var isSecond = false; - for (var i = nDigits - 1; i >= 0; i--) - { - var d = (int)char.GetNumericValue(number[i]) - '0'; - if (isSecond) - d *= 2; - nSum += d / 10; - nSum += d % 10; - isSecond = !isSecond; - } - return nSum % 10 == 0; - } - - public static string GetMod10CheckDigit(string number) - { - var sum = 0; - var alt = true; - var digits = number.ToCharArray(); - for (var i = digits.Length - 1; i >= 0; i--) - { - var curDigit = digits[i] - 48; - if (alt) - { - curDigit *= 2; - if (curDigit > 9) - curDigit -= 9; - } - - sum += curDigit; - alt = !alt; - } - return sum % 10 == 0 ? "0" : (10 - sum % 10).ToString(); - } - - public static string AddMod11CheckDigit(string number) - { - return number + GetMod11CheckDigit(number); - } - - public static string GetMod11CheckDigit(string number) - { - var sum = 0; - for (int i = number.Length - 1, multiplier = 2; i >= 0; i--) - { - sum += (int)char.GetNumericValue(number[i]) * multiplier; - if (++multiplier > 7) multiplier = 2; - } - - var modulo = sum % 11; - return modulo is 0 or 1 ? "0" : (11 - modulo).ToString(); - } - - private static bool CheckLuhn(string vatNumber) - { - // https://www.geeksforgeeks.org/luhn-algorithm/ - - var nDigits = vatNumber.Length; - var nSum = 0; - var isSecond = false; - for (var i = nDigits - 1; i >= 0; i--) - { - var d = (int)char.GetNumericValue(vatNumber[i]) - '0'; - if (isSecond) - d *= 2; - // We add two digits to handle - // cases that make two digits - // after doubling - nSum += d / 10; - nSum += d % 10; - - isSecond = !isSecond; - } - - return nSum % 10 == 0; - } - - } -} \ No newline at end of file