This commit is contained in:
Frede Hundewadt 2022-04-06 12:25:21 +02:00
parent 18058a4230
commit 38b247f048
16 changed files with 209 additions and 229 deletions

View file

@ -28,7 +28,7 @@
<td>@company.Name</td>
<td>@company.Account</td>
<td>@company.City</td>
<td><a class="btn btn-primary mb-1" href="/company/account/@company.Account">Vis</a></td>
<td><a class="btn btn-primary mb-1" href="/company/@company.CompanyId">Vis</a></td>
</tr>
}
</tbody>

View file

@ -30,15 +30,6 @@ namespace Wonky.Client.Components
private Confirmation _confirmation = new ();
private string _companyId = string.Empty;
private static string VisitState(string nextVisit)
{
var theUgly = DateTime.Parse(nextVisit);
var theBad = theUgly.AddDays(-14);
if (DateTime.Now >= theUgly)
return "the-ugly";
return DateTime.Now >= theBad ? "the-bad" : "the-good";
}
private void CallConfirmationModal(string companyId)
{
_companyId = companyId;

View file

@ -22,7 +22,7 @@ namespace Wonky.Client.Components;
public partial class RegInfoCompany
{
[Inject] public VirkRegistryService VirkRegistryService { get; set; } = null!;
[Inject] public VatOwnerLookupService VatOwnerLookupService { get; set; } = null!;
[Parameter] public string VatNumber { get; set; } = "";
private VirkRegInfo VirkRegInfo { get; set; } = new();
private bool _hideMe = true;
@ -34,7 +34,7 @@ public partial class RegInfoCompany
_virkParams.VatNumber = VatNumber;
if (string.IsNullOrWhiteSpace(VirkRegInfo.VatNumber))
{
var result = await VirkRegistryService.QueryVirkRegistry(_virkParams);
var result = await VatOwnerLookupService.QueryVirkRegistry(_virkParams);
if (result.Any())
{
_currentState = VirkRegInfo.States[^1].State;

View file

@ -1,128 +1,99 @@
namespace Wonky.Client.Helpers;
public class VatUtils
public static class VatUtils
{
public static bool CheckVat(string countryCode, string vatNumber)
// https://ec.europa.eu/taxation_customs/vies/faqvies.do#item_11
// https://ec.europa.eu/taxation_customs/vies/
public static bool ValidateFormat(string countryCode, string vatNumber)
{
return countryCode.ToUpperInvariant() switch
{
"DK" => CheckVatNumberDenmark(vatNumber),
"NO" => CheckVatNumberNorway(vatNumber),
"SE" => CheckVatNumberSweden(vatNumber),
"DK" => ValidateFormatDk(vatNumber),
"NO" => ValidateFormatNo(vatNumber),
"SE" => ValidateFormatSe(vatNumber),
_ => false
};
}
private 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 && CheckModolus11(vatNumber.Substring(0, 8));
}
private static bool CheckVatNumberDenmark(string vatNumber)
private static bool ValidateFormatDk(string vatNumber)
{
// https://wiki.scn.sap.com/wiki/display/CRM/Denmark
// 8 digits 0 to 9
// C1..C7
// C8 Modulo 11 check digit
// C8 check-digit MOD11
// C1 > 0
// R = (2*C1 + 7*C2 + 6*C3 + 5*C4 + 4*C5 + 3*C6 + 2*C7 + C8)
if ((int)char.GetNumericValue(vatNumber[0]) < 1 || vatNumber.Length > 8)
var vatToCheck = SanitizeVatNumber(vatNumber);
if (vatToCheck.Length != 8)
return false;
return CheckModolus11(vatNumber);
if ((int)char.GetNumericValue(vatToCheck[0]) < 1 || vatToCheck.Length > 8)
return false;
return ValidateMod11(vatToCheck);
}
private static bool CheckVatNumberSweden(string 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
var vatToCheck = SanitizeVatNumber(vatNumber);
if (vatToCheck.Length != 9)
return false;
return long.Parse(vatToCheck) != 0 && ValidateMod11(vatNumber);
}
private static bool ValidateFormatSe(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
// C10 = (10 (18 + 5 + 1 + 8 + 4)MOD10 10) MOD10
// 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)
// 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 = SanitizeVatNumber(vatNumber);
if (vatToCheck.Length < 10 || long.Parse(vatToCheck) == 0)
return false;
// validate if number
if (!int.TryParse(vatNumber, out var result))
return false;
//validate char 11 and 12
var valid = int.TryParse(vatNumber.Substring(10, 2), out var v2);
if(valid && v2 is < 1 or > 94 )
return false;
// check vatnumber
return CheckLuhn(vatNumber);
}
private static bool CheckModolus11(string number)
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)
{
int[] factors;
switch (number.Length)
{
case 8:
factors = new [] { 2, 7, 6, 5, 4, 3, 2, 1 };
break;
case 9:
factors = new[] { 3, 2, 7, 6, 5, 4, 3, 2, 1 };
break;
case 10:
factors = new[] { 4, 3, 2, 7, 6, 5, 4, 3, 2, 1 };
break;
default:
return false;
return $"{vatToCheck[..9]}{c10}" == vatNumber;
}
var i = 0;
var r = factors.Sum(m => (int)char.GetNumericValue(number[i++]) * m);
return r % 11 == 0;
return $"{vatToCheck[..9]}{c10}01" == vatNumber;
}
private static bool CheckLuhn(string vatNumber)
private static bool ValidateMod11(string number)
{
// 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);
}
private static string AddSelfCheckDigit(string number)
{
// modulus 11
var multi = number.Length;
if (long.Parse(number) == 0)
return false;
var sum = 0;
for (int i = number.Length - 1, multiplier = 2; i >= 0; i--)
for (int i = number.Length - 1, multiplier = 1; i >= 0; i--)
{
sum += (int)char.GetNumericValue(number[i]) * multiplier;
if (++multiplier == multi) multiplier = 2;
if (++multiplier > 7) multiplier = 2;
}
var validator = (11 - (sum % 11)).ToString();
validator = validator switch
return sum % 11 == 0;
}
private static string SanitizeVatNumber(string vatNumber)
{
"11" => "0",
"10" => "X",
_ => validator
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
};
return number + validator;
}
}

View file

@ -26,7 +26,7 @@ namespace Wonky.Client.Models
[Required(ErrorMessage = "Sælger skal udfyldes")] public string SalesRep { get; set; } = "";
// From company row
[Required(ErrorMessage = "Konto skal udfyldes")] public string Account { get; set; } = "";
[Required(ErrorMessage = "Moms nummer skal udfyldes")] public string VatNumber { get; set; } = "";
[Required(ErrorMessage = "CVR / ORG nummer skal udfyldes")] public string VatNumber { get; set; } = "";
[Required(ErrorMessage = "Navn skal udfyldes")] public string Name { get; set; } = "";
public string Address { get; set; } = "";
public string Address2 { get; set; } = "";

View file

@ -25,6 +25,7 @@ using Wonky.Client.Services;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.Extensions.Logging;
using Wonky.Client.Helpers;
using Wonky.Client.Models;
using Wonky.Entity.DTO;
using Wonky.Entity.Models;
@ -39,7 +40,7 @@ namespace Wonky.Client.Pages
[Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public IToastService ToastService { get; set; }
[Inject] public ILogger<CompanyCreate> Logger { get; set; }
[Inject] public VirkRegistryService VirkRegistryService { get; set; }
[Inject] public VatOwnerLookupService VatOwnerLookupService { get; set; }
[Inject] public ILocalStorageService StorageService { get; set; }
[Inject] public NavigationManager Navigation { get; set; }
private CompanyDto _companyDto = new();
@ -55,14 +56,14 @@ namespace Wonky.Client.Pages
var ux = await StorageService.GetItemAsync<UserInfoDto>("_ux");
_companyDto.SalesRepId = ux.Id;
_companyDto.CountryCode = ux.CountryCode;
Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent();
}
private async Task GetInfoFromAddress(VatAddress address)
{
VInfos = await VirkRegistryService.QueryVirkRegistry(
VInfos = await VatOwnerLookupService.QueryVirkRegistry(
new VirkParams
{
StreetName = address.StreetName,
@ -76,9 +77,8 @@ namespace Wonky.Client.Pages
}
private async Task GetInfoFromVat(string vatNumber)
{
VInfos = await VirkRegistryService
VInfos = await VatOwnerLookupService
.QueryVirkRegistry(new VirkParams {VatNumber = vatNumber});
if (!VInfos.Any())
{
ToastService.ShowError($"Firma med CVR '{vatNumber}' findes ikke.");
@ -106,8 +106,15 @@ namespace Wonky.Client.Pages
}
private void HandleFieldChanged(object sender, FieldChangedEventArgs e)
{
if (!VatUtils.ValidateFormat(_companyDto.CountryCode, _companyDto.VatNumber))
{
_formInvalid = false;
}
else
{
_formInvalid = !_editContext.Validate();
}
StateHasChanged();
}
private void ValidationChanged(object sender, ValidationStateChangedEventArgs e)

View file

@ -14,24 +14,17 @@
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
*@
@page "/company/{account}/update"
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components
@attribute [Authorize(Roles = "Adviser")]
@using Wonky.Client.Components
@attribute [Authorize(Roles = "Adviser")]
@page "/company/{companyId}/update"
@if (!string.IsNullOrEmpty(_companyDto.Name))
@if (_company.Name != "")
{
<div class="card">
<div class="card-header">
<div><DisplayStateComponent StateClass="@RegState"></DisplayStateComponent> CVR status</div>
<div>Konto @_companyDto.Account</div>
<div>CompanyId @_companyDto.CompanyId</div>
<div>EDIT Næste besøg @NextVisit</div>
<div>EDIT Sidst besøgt @LastVisit</div>
<div>DB Næste besøg @_companyDto.NextVisit</div>
<div>DB Sidst besøgt @_companyDto.LastVisit</div>
<div class="h2">@_company.Account - @_company.Name</div>
</div>
<div class="card-body">
<EditForm EditContext="_editContext" OnValidSubmit="Update">
@ -39,61 +32,65 @@
<div class="form-group row mb-2">
<label for="name" class="col-md-2 col-form-label">Firmanavn</label>
<div class="col-md-10">
<InputText id="name" class="form-control" @bind-Value="_companyDto.Name"/>
<InputText id="name" class="form-control" @bind-Value="_company.Name"/>
<ValidationMessage For="@(() => _company.Name)"></ValidationMessage>
</div>
</div>
<div class="form-group row mb-2">
<label for="address1" class="col-md-2 col-form-label">Adresse</label>
<div class="col-md-10">
<InputText id="address1" class="form-control" @bind-Value="_companyDto.Address1"/>
<InputText id="address1" class="form-control" @bind-Value="_company.Address1"/>
</div>
</div>
<div class="form-group row mb-2">
<label for="address2" class="col-md-2 col-form-label">Adresse</label>
<div class="col-md-10">
<InputText id="address2" class="form-control" @bind-Value="_companyDto.Address2"/>
<InputText id="address2" class="form-control" @bind-Value="_company.Address2"/>
</div>
</div>
<div class="form-group row mb-2">
<label for="zipCode" class="col-md-2 col-form-label">Postnr</label>
<div class="col-md-10">
<InputText id="zipCode" class="form-control" @bind-Value="_companyDto.ZipCode"/>
<InputText id="zipCode" class="form-control" @bind-Value="_company.ZipCode"/>
<ValidationMessage For="@(() => _company.ZipCode)"></ValidationMessage>
</div>
</div>
<div class="form-group row mb-2">
<label for="city" class="col-md-2 col-form-label">Bynavn</label>
<div class="col-md-10">
<InputText id="city" class="form-control" @bind-Value="_companyDto.City"/>
<InputText id="city" class="form-control" @bind-Value="_company.City"/>
<ValidationMessage For="@(() => _company.City)"></ValidationMessage>
</div>
</div>
<div class="form-group row mb-2">
<label for="vatNumber" class="col-md-2 col-form-label">CVR/ORG</label>
<div class="col-md-10">
<InputText id="vatNumber" class="form-control" @bind-Value="_companyDto.VatNumber"/>
<InputText id="vatNumber" class="form-control" @bind-Value="_company.VatNumber"/>
<ValidationMessage For="@(() => _company.VatNumber)"></ValidationMessage>
</div>
</div>
<div class="form-group row mb-2">
<label for="phone" class="col-md-2 col-form-label">Telefon nummer</label>
<div class="col-md-10">
<InputText id="phone" class="form-control" @bind-Value="_companyDto.Phone"/>
<InputText id="phone" class="form-control" @bind-Value="_company.Phone"/>
</div>
</div>
<div class="form-group row mb-2">
<label for="mobile" class="col-md-2 col-form-label">Mobil nummer</label>
<div class="col-md-10">
<InputText id="mobile" class="form-control" @bind-Value="_companyDto.Mobile"/>
<InputText id="mobile" class="form-control" @bind-Value="_company.Mobile"/>
</div>
</div>
<div class="form-group row mb-2">
<label for="email" class="col-md-2 col-form-label">Email</label>
<div class="col-md-10">
<InputText id="email" class="form-control" @bind-Value="_companyDto.Email"/>
<InputText id="email" class="form-control" @bind-Value="_company.Email"/>
</div>
</div>
<div class="form-group row mb-2">
<label for="attention" class="col-md-2 col-form-label">Attention</label>
<div class="col-md-10">
<InputText id="attention" class="form-control" @bind-Value="_companyDto.Attention"/>
<InputText id="attention" class="form-control" @bind-Value="_company.Attention"/>
</div>
</div>
<div class="form-group row mb-2">
@ -111,7 +108,7 @@
<div class="form-group row mb-2">
<label for="interval" class="col-form-label col-md-2">Besøgs interval Interval</label>
<div class="col-md-3">
<InputNumber id="interval" class="form-control" @bind-Value="_companyDto.Interval"/>
<InputNumber id="interval" class="form-control" @bind-Value="_company.Interval"/>
</div>
</div>
<div class="row mb-2">
@ -132,5 +129,5 @@
}
else
{
<div><img class="spinner" src="loader.gif" alt="Vent venligst..."/> Henter data...</div>
@* <AppSpinner/> *@
}

View file

@ -13,11 +13,14 @@
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
using System.Text.Json;
using System.Text.Json.Serialization;
using Blazored.Toast.Services;
using Wonky.Client.HttpInterceptors;
using Wonky.Client.HttpRepository;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Wonky.Client.Helpers;
using Wonky.Client.Models;
using Wonky.Client.Services;
using Wonky.Entity.DTO;
@ -33,44 +36,59 @@ public partial class CompanyUpdate : IDisposable
[Inject] public IToastService ToastService { get; set; }
[Inject] public ILogger<CompanyCreate> Logger { get; set; }
[Inject] public NavigationManager Navigation { get; set; }
[Inject] public VirkRegistryService VirkRegistryService { get; set; }
[Parameter] public string Account { get; set; } = null!;
private CompanyDto _companyDto;
private EditContext _editContext;
[Inject] public VatOwnerLookupService VatOwnerLookupService { get; set; }
[Parameter] public string Account { get; set; } = "";
[Parameter] public string CompanyId { get; set; } = "";
private CompanyDto _company { get; set; }
private EditContext _editContext { get; set; }
private List<VirkRegInfo> VInfos { get; set; } = new();
private VirkRegInfo _virkRegInfo { get; set; } = new();
private DateTime LastVisit { get; set; }
private DateTime NextVisit { get; set; }
private string RegState { get; set; } = "the-ugly";
private string _vatState { get; set; } = "the-ugly";
protected override async Task OnInitializedAsync()
{
_companyDto = await CompanyRepo.GetCompanyByAccount(Account);
LastVisit = DateTime.Parse(_companyDto.LastVisit);
NextVisit = DateTime.Parse(_companyDto.NextVisit);
_editContext = new EditContext(_companyDto);
Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent();
if(!string.IsNullOrWhiteSpace(_companyDto.VatNumber))
await GetInfoFromVat(_companyDto.VatNumber);
//_companyDto.CompanyId = Squid.DecodeSquid(_companyDto.CompanyId).ToString();
_company = await CompanyRepo.GetCompanyById(CompanyId);
LastVisit = DateTime.Parse(_company.LastVisit);
NextVisit = DateTime.Parse(_company.NextVisit);
_editContext = new EditContext(_company);
Console.WriteLine(JsonSerializer.Serialize(_company));
if(_company.HasFolded == 1)
{
_vatState = "the-dead";
}
else
{
_vatState = VatUtils.ValidateFormat(_company.CountryCode, _company.VatNumber) ? "the-good" : "the-draw";
}
}
private async Task Update()
{
var lv = DateTime.TryParse(_companyDto.LastVisit, out var lvValidated);
var nv = DateTime.TryParse(_companyDto.NextVisit, out var nvValidated);
if (!VatUtils.ValidateFormat(_company.CountryCode, _company.VatNumber))
{
ToastService.ShowError($"CVR/VAT/ORG nummer er ugyldig.");
StateHasChanged();
return;
}
var lv = DateTime.TryParse(_company.LastVisit, out var lvValidated);
var nv = DateTime.TryParse(_company.NextVisit, out var nvValidated);
if (lv && nv)
{
_companyDto.LastVisit = $"{lvValidated:yyyy-MM-dd}";
_companyDto.NextVisit = $"{nvValidated:yyyy-MM-dd}";
_company.LastVisit = $"{lvValidated:yyyy-MM-dd}";
_company.NextVisit = $"{nvValidated:yyyy-MM-dd}";
await CompanyRepo.UpdateCompany(_companyDto);
ToastService.ShowSuccess($"Godt så. Firma '{_companyDto!.Name}' er opdateret.");
Navigation.NavigateTo($"/company/id/{_companyDto.CompanyId}");
await CompanyRepo.UpdateCompany(_company);
ToastService.ShowSuccess($"Godt så. Firma '{_company!.Name}' er opdateret.");
Navigation.NavigateTo($"/company/{_company.CompanyId}");
}
}
private async Task GetInfoFromVat(string vatNumber)
{
@ -79,7 +97,7 @@ public partial class CompanyUpdate : IDisposable
ToastService.ShowError($"CVR nummer mangler.");
return;
}
VInfos = await VirkRegistryService
VInfos = await VatOwnerLookupService
.QueryVirkRegistry(
new VirkParams
{
@ -94,7 +112,7 @@ public partial class CompanyUpdate : IDisposable
private async Task GetInfoFromAddress(VatAddress address)
{
VInfos = await VirkRegistryService.QueryVirkRegistry(
VInfos = await VatOwnerLookupService.QueryVirkRegistry(
new VirkParams
{
StreetName = address.StreetName,
@ -109,12 +127,12 @@ public partial class CompanyUpdate : IDisposable
private void SelectCompany(string vatNumber)
{
_virkRegInfo = (from x in VInfos where x.VatNumber == vatNumber select x).First();
_companyDto.Name = _virkRegInfo.Name;
_companyDto.Address1 = _virkRegInfo.CoName;
_companyDto.Address2 = _virkRegInfo.Address;
_companyDto.ZipCode = _virkRegInfo.ZipCode;
_companyDto.City = _virkRegInfo.City;
_companyDto.VatNumber = _virkRegInfo.VatNumber;
_company.Name = _virkRegInfo.Name;
_company.Address1 = _virkRegInfo.CoName;
_company.Address2 = _virkRegInfo.Address;
_company.ZipCode = _virkRegInfo.ZipCode;
_company.City = _virkRegInfo.City;
_company.VatNumber = _virkRegInfo.VatNumber;
}
public void Dispose()

View file

@ -15,61 +15,63 @@
//
*@
@page "/company/account/{account}"
@page "/company/id/{companyId}"
@page "/company/{companyId}"
@using Microsoft.AspNetCore.Authorization
@using Wonky.Client.Components;
@using Wonky.Client.Helpers
@using Wonky.Entity.Models
@attribute [Authorize(Roles = "Adviser")]
<div class="card">
<div class="card-header">
<div class="card-header">
<div class="h2">@(_hasFolded ? @_company.Account : "LUKKET" ) - @_company.Name</div>
</div>
</div>
<div class="card-body">
<table class="table table-sm table-striped table-bordered">
<tbody>
<tr>
<th scope="row">Navn</th>
<td colspan="2">@CompanyDto.Name</td>
<td colspan="2">@_company.Name</td>
</tr>
<tr>
<th scope="row">CO navn</th>
<td colspan="2">@CompanyDto.Address1</td>
<td colspan="2">@_company.Address1</td>
</tr>
<tr>
<th scope="row">Adresse</th>
<td colspan="2">@CompanyDto.Address2</td>
<td colspan="2">@_company.Address2</td>
</tr>
<tr>
<th scope="row">Postnummer</th>
<td colspan="2">@CompanyDto.ZipCode</td>
<td colspan="2">@_company.ZipCode</td>
</tr>
<tr>
<th scope="row">Bynavn</th>
<td colspan="2">@CompanyDto.City</td>
<td colspan="2">@_company.City</td>
</tr>
<tr>
<th scope="row">CVR</th>
<td><RegStateVatNumber VatNumber="@CompanyDto.VatNumber"></RegStateVatNumber></td>
<td>@CompanyDto.VatNumber</td>
<td class="state"><DisplayStateComponent StateClass="@_vatState"></DisplayStateComponent></td>
<td>@_company.VatNumber</td>
</tr>
<tr>
<th scope="row">Telefon</th>
<td colspan="2">@CompanyDto.Phone</td>
<td colspan="2">@_company.Phone</td>
</tr>
<tr>
<th scope="row">Email</th>
<td colspan="2">@CompanyDto.Email</td>
<td colspan="2">@_company.Email</td>
</tr>
<tr>
<th scope="row">Sidste besøg</th>
<td colspan="2">@CompanyDto.LastVisit</td>
<td colspan="2">@_company.LastVisit</td>
</tr>
<tr>
<th scope="row">Næste besøg</th>
<td><DisplayStateComponent StateClass="@(Utils.GetVisitState(CompanyDto.NextVisit))"></DisplayStateComponent></td>
<td>@CompanyDto.NextVisit</td>
<td class="state"><DisplayStateComponent StateClass="@(Utils.GetVisitState(_company.NextVisit))"></DisplayStateComponent></td>
<td>@_company.NextVisit</td>
</tr>
</tbody>
</table>
@ -78,10 +80,10 @@
<div class="row flex-row align-items-end">
<div class="col flex-column">
<a class="btn btn-primary float-start mx-2" href="/companies">Tilbage</a>
<a class="btn btn-primary float-start" href="/company/@CompanyDto.Account/update">Rediger</a>
<a class="btn btn-primary float-start" href="/company/@_company.CompanyId/update">Rediger</a>
</div>
<div class="col flex-column">
<a class="btn btn-primary float-end mx-2" href="/company/@CompanyDto.Account/Activity">Aktivitet</a>
<a class="btn btn-primary float-end mx-2" href="/company/@_company.CompanyId/Activity">Aktivitet</a>
</div>
</div>
</div>

View file

@ -29,45 +29,35 @@ public partial class CompanyView : IDisposable
{
[Inject] public ICompanyHttpRepository CompanyRepo { get; set; }
[Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public VirkRegistryService VirkRegistryService { get; set; }
[Parameter] public string Account { get; set; } = "";
[Inject] public VatOwnerLookupService VatOwnerLookup { get; set; }
[Inject] public ILogger<CompanyView> Logger { get; set; }
[Parameter] public string CompanyId { get; set; } = "";
private CompanyDto CompanyDto { get; set; } = new ();
private VirkRegInfo VirkRegInfo { get; set; } = new();
private string VisitState { get; set; } = "the-ugly";
private bool ValidCvr { get; set; } = true;
private CompanyDto _company { get; set; } = new ();
private string _vatState { get; set; } = "the-dead";
private bool _hasFolded { get; set; }
protected override async Task OnInitializedAsync()
{
Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent();
if (!string.IsNullOrWhiteSpace(Account))
_company = await CompanyRepo.GetCompanyById(CompanyId);
if(_company.HasFolded == 1)
{
CompanyDto = await CompanyRepo.GetCompanyByAccount(Account);
_vatState = "the-dead";
_hasFolded = true;
}
else
{
if (!string.IsNullOrWhiteSpace(CompanyId))
{
CompanyDto = await CompanyRepo.GetCompanyById(CompanyId);
_vatState = VatUtils.ValidateFormat(_company.CountryCode, _company.VatNumber) ? "the-good" : "the-draw";
}
}
var theUgly = DateTime.Parse(CompanyDto.NextVisit);
var theBad = theUgly.AddDays(-14);
if (DateTime.Now <= theUgly)
{
VisitState = DateTime.Now >= theBad ? "the-bad" : "the-good";
}
ValidCvr = string.IsNullOrEmpty(CompanyDto.VatNumber) || CompanyDto.VatNumber.Length <= 8;
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
Interceptor!.DisposeEvent();
Interceptor.DisposeEvent();
}
}

View file

@ -15,7 +15,7 @@
//
*@
@page "/company/{account}/activity"
@page "/company/{companyId}/activity"
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Roles = "Adviser")]
@using Wonky.Client.Components
@ -102,6 +102,9 @@
<div class="row mb-2">
<div class="col">
<a class="btn btn-primary" href="/company/@_company.CompanyId"></a>
</div>
<div class="col">
<button type="submit" class="btn btn-success" disabled="@_poFormInvalid">Tilbud</button>
<button type="submit" class="btn btn-success" disabled="@_poFormInvalid">Bestilling</button>

View file

@ -33,7 +33,7 @@ public partial class PurchaseOrderCreate : IDisposable
{
private List<SalesItemDto> SalesItemList { get; set; } = new();
private PurchaseOrder _purchaseOrder = new ();
private CompanyDto _companyDto = new();
private CompanyDto _company = new();
private EditContext _editContext;
private bool _poFormInvalid = true;
private MetaData? MetaData { get; set; } = new();
@ -46,7 +46,7 @@ public partial class PurchaseOrderCreate : IDisposable
[Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public ILocalStorageService StorageService { get; set; }
[Inject] public ISalesItemHttpRepository SalesItemRepo { get; set; }
[Parameter] public string Account { get; set; }
[Parameter] public string CompanyId { get; set; }
public List<CrmSalesLines> Lines { get; set; } = new();
protected override async Task OnInitializedAsync()
@ -55,9 +55,7 @@ public partial class PurchaseOrderCreate : IDisposable
Interceptor.RegisterBeforeSendEvent();
var ux = await StorageService.GetItemAsync<UserInfoDto>("_ux");
_companyDto = await CompanyRepo.GetCompanyByAccount(Account);
_company = await CompanyRepo.GetCompanyById(CompanyId);
_editContext = new EditContext(_purchaseOrder);
_editContext.OnFieldChanged += HandleFieldChanged;
@ -66,30 +64,30 @@ public partial class PurchaseOrderCreate : IDisposable
// permanent identifications
_purchaseOrder.SalesRep = ux.Adviser;
_purchaseOrder.Account = Account;
_purchaseOrder.VatNumber = _companyDto.VatNumber;
_purchaseOrder.EMail = _companyDto.Email;
_purchaseOrder.Phone = _companyDto.Phone;
_purchaseOrder.Account = _company.Account;
_purchaseOrder.VatNumber = _company.VatNumber;
_purchaseOrder.EMail = _company.Email;
_purchaseOrder.Phone = _company.Phone;
_purchaseOrder.OurRef = ux.FullName.Split(" ")[0];
_purchaseOrder.Name = _companyDto.Name;
_purchaseOrder.Address = _companyDto.Address1;
_purchaseOrder.Address2 = _companyDto.Address2;
_purchaseOrder.ZipCode = _companyDto.ZipCode;
_purchaseOrder.City = _companyDto.City;
_purchaseOrder.Name = _company.Name;
_purchaseOrder.Address = _company.Address1;
_purchaseOrder.Address2 = _company.Address2;
_purchaseOrder.ZipCode = _company.ZipCode;
_purchaseOrder.City = _company.City;
_purchaseOrder.DlvName = _companyDto.Name;
_purchaseOrder.DlvAddress1 = _companyDto.Address1;
_purchaseOrder.DlvAddress2 = _companyDto.Address2;
_purchaseOrder.DlvZipCode = _companyDto.ZipCode;
_purchaseOrder.DlvCity = _companyDto.City;
_purchaseOrder.DlvName = _company.Name;
_purchaseOrder.DlvAddress1 = _company.Address1;
_purchaseOrder.DlvAddress2 = _company.Address2;
_purchaseOrder.DlvZipCode = _company.ZipCode;
_purchaseOrder.DlvCity = _company.City;
}
private async Task CreateActivity()
{
await StorageService.SetItemAsync(Account, _purchaseOrder);
await StorageService.SetItemAsync(CompanyId, _purchaseOrder);
ToastService.ShowSuccess($"Aktivitet oprettet.");
}

View file

@ -57,7 +57,7 @@ builder.Services.AddAuthorizationCore();
builder.Services.AddScoped<AuthenticationStateProvider, AuthStateProvider>();
builder.Services.AddScoped<IAuthenticationService, AuthenticationService>();
builder.Services.AddScoped<RefreshTokenService>();
builder.Services.AddScoped<VirkRegistryService>();
builder.Services.AddScoped<VatOwnerLookupService>();
builder.Services.AddScoped<UserPreferenceService>();

View file

@ -22,14 +22,14 @@ using Wonky.Entity.Requests;
namespace Wonky.Client.Services;
public class VirkRegistryService
public class VatOwnerLookupService
{
private readonly JsonSerializerOptions _options = new() { PropertyNameCaseInsensitive = true };
private readonly HttpClient _client;
private readonly IOptions<ApiConfig> _apiConfig;
private readonly List<VirkRegInfo> _noData = new() { new VirkRegInfo { Name = "INGEN DATA" } };
public VirkRegistryService(HttpClient client, IOptions<ApiConfig> apiConfig)
public VatOwnerLookupService(HttpClient client, IOptions<ApiConfig> apiConfig)
{
_client = client;
_apiConfig = apiConfig;

View file

@ -14,6 +14,9 @@
min-width: 24px;
min-height: 24px;
}
.the-dead {
background-color: black;
}
.the-draw {
background-color: purple;
}

View file

@ -21,10 +21,10 @@ namespace Wonky.Entity.DTO;
public class CompanyDto
{
[Required(ErrorMessage = "Navn skal udyldes")] public string Name { get; set; } = "";
[Required(ErrorMessage = "Postnummer skal udfyldes")] public string ZipCode { get; set; } = "";
[Required(ErrorMessage = "Bynavn skal udfyldes")] public string City { get; set; } = "";
public string VatNumber { get; set; } = "";
[Required(ErrorMessage = "Navn skal udyldes")] public string Name { get; set; }
[Required(ErrorMessage = "Postnummer skal udfyldes")] public string ZipCode { get; set; }
[Required(ErrorMessage = "Bynavn skal udfyldes")] public string City { get; set; }
[Required(ErrorMessage = "ORG/VAT/CVR er ikke et gyldigt nummer")] public string VatNumber { get; set; }
public string CompanyId { get; set; } = "";
public string SalesRepId { get; set; } = "";
public string BcId { get; set; } = "";