swedish org number validation and storage v.0.102.5 - v.2.23.019.1209
This commit is contained in:
parent
c2a9fa0210
commit
cc00d397a9
7 changed files with 103 additions and 28 deletions
|
@ -14,6 +14,9 @@
|
|||
//
|
||||
|
||||
using System.Globalization;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Wonky.Client.Helpers;
|
||||
|
||||
|
@ -29,11 +32,11 @@ public class VatUtils
|
|||
/// <returns></returns>
|
||||
public static bool ValidateFormat(string countryCode, string vatNumber)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(vatNumber) || string.IsNullOrWhiteSpace(countryCode) || !IsDigitsOnly(vatNumber))
|
||||
if (string.IsNullOrWhiteSpace(vatNumber) || string.IsNullOrWhiteSpace(countryCode))
|
||||
return false;
|
||||
|
||||
|
||||
var sanitisedVat = SanitizeVatNumber(vatNumber);
|
||||
|
||||
|
||||
return countryCode.ToUpperInvariant() switch
|
||||
{
|
||||
"DK" => ValidateFormatDk(sanitisedVat),
|
||||
|
@ -104,23 +107,74 @@ public class VatUtils
|
|||
// 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)
|
||||
|
||||
var vatToCheck = vatNumber;
|
||||
if (vatToCheck.Length < 10 || long.Parse(vatToCheck) == 0)
|
||||
if (long.Parse(vatToCheck) == 0)
|
||||
return false;
|
||||
|
||||
switch (vatToCheck.Length)
|
||||
{
|
||||
// if less than 10 chars validate as SSI
|
||||
case 6:
|
||||
return ValidateFormatSeExt(vatToCheck);
|
||||
case < 10:
|
||||
return false;
|
||||
}
|
||||
|
||||
// check digit calculation
|
||||
var r = new[] { 0, 2, 4, 6, 8 }
|
||||
.Sum(m => (int)char.GetNumericValue(vatToCheck[m]) / 5 +
|
||||
(int)char.GetNumericValue(vatToCheck[m]) * 2 % 10);
|
||||
var c1 = new[] { 1, 3, 5, 7 }.Sum(m => (int)char.GetNumericValue(vatToCheck[m]));
|
||||
var c10 = (10 - (r + c1) % 10) % 10;
|
||||
if (vatToCheck.Length == 10)
|
||||
{
|
||||
return $"{vatToCheck[..9]}{c10}" == vatNumber;
|
||||
}
|
||||
|
||||
return $"{vatToCheck[..9]}{c10}01" == vatNumber;
|
||||
// end check digit calculation
|
||||
// return validation check - depending on with or with or without EU extension `01`
|
||||
return vatToCheck.Length == 10
|
||||
? $"{vatToCheck[..9]}{c10}" == vatNumber
|
||||
: $"{vatToCheck[..9]}{c10}01" == vatNumber;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
private static bool ValidateFormatSeExt(string data)
|
||||
{
|
||||
// Swedish personally held companies uses SSN number
|
||||
// a relaxed validation is required as only first 6 digits is supplied
|
||||
// birthday format e.g. 991231 yyMMdd
|
||||
|
||||
var y = int.Parse(data[..2]);
|
||||
var m = int.Parse(data[2..4]);
|
||||
var d = int.Parse(data[4..6]);
|
||||
// this calculation is only valid within 21st century
|
||||
var leap = y % 4 == 0; // 2000 was a leap year;
|
||||
// day
|
||||
if(d is < 1 or > 31)
|
||||
return false;
|
||||
// month
|
||||
switch (m)
|
||||
{
|
||||
// feb
|
||||
case 2:
|
||||
{
|
||||
if (leap)
|
||||
return d <= 29;
|
||||
return d <= 28;
|
||||
}
|
||||
// apr, jun, sep, nov
|
||||
case 4 or 6 or 9 or 11:
|
||||
return d <= 30;
|
||||
// jan, mar, may, july, aug, oct, dec
|
||||
case 1 or 3 or 5 or 7 or 8 or 10 or 12:
|
||||
return true;
|
||||
// does not exist
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Modulus11 validator
|
||||
/// </summary>
|
||||
|
@ -147,11 +201,9 @@ public class VatUtils
|
|||
/// <returns></returns>
|
||||
private static string SanitizeVatNumber(string vatNumber)
|
||||
{
|
||||
return vatNumber.Replace(" ", "")
|
||||
.Replace("-", "")
|
||||
.Replace("DK", "")
|
||||
.Replace("NO", "")
|
||||
.Replace("SE", "")
|
||||
.Replace("MVA", "");
|
||||
if (string.IsNullOrWhiteSpace(vatNumber))
|
||||
return "";
|
||||
var regexObj = new Regex(@"[^\d]");
|
||||
return regexObj.Replace(vatNumber, "");
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
using System.Net;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Blazored.LocalStorage;
|
||||
using Blazored.Toast.Services;
|
||||
|
@ -86,7 +87,7 @@ namespace Wonky.Client.HttpInterceptors
|
|||
if (e.Response == null || e.Response.IsSuccessStatusCode)
|
||||
return;
|
||||
|
||||
var message = $"En fejl er opstået \n {e.Response.Content }";
|
||||
var message = $"En fejl er opstået \n {JsonSerializer.Serialize(e)}";
|
||||
var currDoc = _navigation.ToBaseRelativePath(_navigation.Uri);
|
||||
if (currDoc.Contains("login/"))
|
||||
currDoc = "";
|
||||
|
|
|
@ -189,6 +189,8 @@ public class AdvisorCustomerRepository : IAdvisorCustomerRepository
|
|||
};
|
||||
var response = await _client.PutAsJsonAsync($"{_conf.CrmCustomers}/{companyId}/vat", model, _options);
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
return JsonSerializer.Deserialize<CompanyDto>(content);
|
||||
return response.IsSuccessStatusCode
|
||||
? JsonSerializer.Deserialize<CompanyDto>(content)
|
||||
: new CompanyDto{Name = "ERROR", VatNumber = vatNumber, CrmNotes = $"FEJL: {content}"};
|
||||
}
|
||||
}
|
|
@ -99,6 +99,7 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
|||
if (Company.HasFolded == 1)
|
||||
// Company has shutdown activities
|
||||
Activity.OrderMessage = "BEMÆRK: CVR nummer er ophørt.";
|
||||
|
||||
// variable to validate if customer needs phone number update
|
||||
OldPhone = Company.Phone;
|
||||
if (string.IsNullOrWhiteSpace(Company.Phone)
|
||||
|
@ -173,6 +174,8 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
|||
// fetch pDate from storage
|
||||
var pDate = await Storage.GetItemAsync<string>($"{CompanyId}-pDate");
|
||||
Logger.LogDebug("pDate => {}", pDate);
|
||||
if (string.IsNullOrWhiteSpace(pStorage))
|
||||
await Task.Delay(1000);
|
||||
// check if product data is valid and updated today
|
||||
if (string.IsNullOrWhiteSpace(pStorage) || pDate.Replace("\"", "") != $"{DateTime.Now:yyyy-MM-dd}")
|
||||
{
|
||||
|
@ -325,6 +328,7 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
|||
if (OldPhone != Activity.Phone)
|
||||
{
|
||||
Company.Phone = Activity.Phone;
|
||||
Activity.OrderMessage = $"Telefonnr. opdateret.\n{Activity.OrderMessage}";
|
||||
await Companies.UpdateErpData(Company.CompanyId, Company);
|
||||
}
|
||||
// begin assembling activity
|
||||
|
|
|
@ -92,10 +92,10 @@
|
|||
<ValidationMessage For="@(() => Company.Email)"></ValidationMessage>
|
||||
</div>
|
||||
<div class="col-sm-2 d-grid mx-auto">
|
||||
<button type="button" class="btn btn-primary d-block" disabled="@(Company.HasFolded == 0)" onclick="@ForceActivity">Aktiver besøg</button>
|
||||
<button type="button" class="btn btn-primary d-block" disabled="@(Company.HasFolded == 0 || Company.Name == "ERROR")" onclick="@ForceActivity">Aktiver besøg</button>
|
||||
</div>
|
||||
<div class="col-sm-2 d-grid mx-auto">
|
||||
<button type="button" class="btn btn-primary d-block" onclick="@UpdateErpData" disabled="@(Working)"><i class="bi-save"></i> STAM data </button>
|
||||
<button type="button" class="btn btn-primary d-block" onclick="@UpdateErpData" disabled="@(Working || Company.Name == "ERROR")"><i class="bi-save"></i> STAM data </button>
|
||||
</div>
|
||||
|
||||
@* account *@
|
||||
|
@ -116,7 +116,18 @@
|
|||
</div>
|
||||
@* vat lookup *@
|
||||
<div class="col-sm-2 d-grid mx-auto">
|
||||
<button type="button" class="btn btn-info" @onclick="OpenVatLookupModal">Firma opslag</button>
|
||||
@switch (CountryCode)
|
||||
{
|
||||
case "dk":
|
||||
<button type="button" class="btn btn-info" @onclick="OpenVatLookupModal"><i class="bi-search"></i> Firma opslag</button>
|
||||
break;
|
||||
case "no":
|
||||
<a class="btn btn-info" href="https://brreg.no/" target="_blank"><i class="bi-search"></i> Firma opslag</a>
|
||||
break;
|
||||
case "se":
|
||||
<a class="btn btn-info" href="https://www.allabolag.se/what/@Company.Name" target="_blank"><i class="bi-search"></i> Firma opslag</a>
|
||||
break;
|
||||
}
|
||||
</div>
|
||||
@* save vat number *@
|
||||
<div class="col-sm-2 d-grid mx-auto">
|
||||
|
@ -162,7 +173,7 @@
|
|||
</div>
|
||||
@* Save CRM data button *@
|
||||
<div class="col-sm-2 d-grid mx-auto">
|
||||
<button type="button" class="btn btn-primary" @onclick="UpdateCrmData"><i class="bi-save"></i> CRM data</button>
|
||||
<button type="button" class="btn btn-primary" disabled="@(Company.Name == "ERROR")" @onclick="UpdateCrmData"><i class="bi-save"></i> CRM data</button>
|
||||
</div>
|
||||
</div>
|
||||
@* crm context - contacts *@
|
||||
|
|
|
@ -265,11 +265,13 @@ public partial class AdvisorCustomerViewPage : IDisposable
|
|||
Company.NextVisit = $"{NextVisit:yyyy-MM-dd}";
|
||||
Company.IsHidden = 0;
|
||||
var result = await CompanyRepo.UpdateCrmData(CompanyId, Company);
|
||||
if (!string.IsNullOrWhiteSpace(result.Name))
|
||||
if (!string.IsNullOrWhiteSpace(result.CompanyId))
|
||||
{
|
||||
Company = result;
|
||||
StateHasChanged();
|
||||
}
|
||||
Working = false;
|
||||
Toaster.ClearAll();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -283,11 +285,13 @@ public partial class AdvisorCustomerViewPage : IDisposable
|
|||
Working = true;
|
||||
Toaster.ShowInfo("Vent venligst ...", "OPDATERER STAM DATA");
|
||||
var result = await CompanyRepo.UpdateErpData(CompanyId, Company);
|
||||
if (!string.IsNullOrWhiteSpace(result.Name))
|
||||
if (!string.IsNullOrWhiteSpace(result.CompanyId))
|
||||
{
|
||||
Company = result;
|
||||
StateHasChanged();
|
||||
}
|
||||
Working = false;
|
||||
Toaster.ClearAll();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -307,11 +311,12 @@ public partial class AdvisorCustomerViewPage : IDisposable
|
|||
Working = true;
|
||||
Toaster.ShowInfo("Vent venligst ...", "OPDATERER MOMS NUMMER");
|
||||
var result = await CompanyRepo.UpdateCompanyVat(CompanyId, Company.VatNumber);
|
||||
if (!string.IsNullOrWhiteSpace(result.Name))
|
||||
if (!string.IsNullOrWhiteSpace(result.CompanyId))
|
||||
{
|
||||
Company = result;
|
||||
StateHasChanged();
|
||||
}
|
||||
Toaster.ClearAll();
|
||||
Working = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
{
|
||||
"appInfo": {
|
||||
"name": "Wonky Online",
|
||||
"version": "0.101.x",
|
||||
"version": "0.102.5",
|
||||
"rc": true,
|
||||
"sandBox": false,
|
||||
"image": "grumpy-coder.png"
|
||||
},
|
||||
"apiConfig": {
|
||||
"baseUrl": "https://dev.innotec.dk",
|
||||
"baseUrl": "https://zeta.innotec.dk",
|
||||
"catalog": "api/v2/catalog/country",
|
||||
"crmCustomers": "api/v2/crm/companies",
|
||||
"crmInventoryExt": "history/inventory",
|
||||
|
@ -36,7 +36,7 @@
|
|||
},
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Default": "Debug",
|
||||
"System": "Information",
|
||||
"Microsoft": "Information"
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue