WIP: intermediate production release v.0.116.1

This commit is contained in:
Frede Hundewadt 2023-02-14 12:41:27 +01:00
parent 0ac35a1f10
commit c461d4e26c
33 changed files with 224 additions and 383 deletions

View file

@ -58,10 +58,10 @@
<button class="btn btn-warning" @onclick="() => ShowActivityList(company.CompanyId)" >Aktivitet</button>
</div>
<div class="col">
<button class="btn btn-success" @onclick="() => ShowProductList(company.CompanyId)">Produkt</button>
<button class="btn btn-success" @onclick="() => ShowInventory(company.CompanyId)">Produkt</button>
</div>
<div class="col">
<button class="btn btn-primary" disabled >Bestilling</button>
@* <a class="btn btn-primary" href="/office/customers/@company.CountryCode.ToLower()/@company.CompanyId/order" >Bestilling</a> *@
</div>
</div>
</div>
@ -69,13 +69,13 @@
</div>
}
</div>
<OfficeCustomerInvoiceListOverlay Company="@SelectedCompany" InvoiceList="@InvoiceList" @ref="InvoiceListOverlay" />
<OfficeCustomerActivityListOverlay Company="SelectedCompany" ActivityList="ActivityList" @ref="ActivityListOverlay" />
<OfficeCustomerProductListOverlay Company="SelectedCompany" ProductList="ProductList" @ref="ProductListOverlay" />
}
else
{
<div>Ingen data</div>
}
<OfficeCustomerInvoiceListOverlay Company="@SelectedCompany" CustomerInvoices="@InvoiceViewList" @ref="InvoiceListOverlay" />
<OfficeCustomerActivityListOverlay Activities="ActivityList" Company="SelectedCompany" @ref="ActivityListOverlay" />
<OfficeCustomerProductListOverlay Company="SelectedCompany" ProductList="ProductList" @ref="ProductListOverlay" />

View file

@ -13,68 +13,91 @@
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
using System.Reflection.Metadata.Ecma335;
using Microsoft.AspNetCore.Components;
using Microsoft.VisualBasic.CompilerServices;
using Wonky.Client.HttpInterfaces;
using Wonky.Client.OverlayOffice;
using Wonky.Entity.DTO;
using Wonky.Entity.Views;
using Wonky.Client.Helpers;
using Wonky.Client.Models;
using Wonky.Client.Shared;
using Utils = Wonky.Client.Helpers.Utils;
#pragma warning disable CS8618
namespace Wonky.Client.Components
{
public partial class OfficeCountryCustomerListComponent
{
[Parameter] public List<CompanyDto> CompanyList { get; set; } = new();
// ******************************************************
// parameters
[Parameter] public string CountryCode { get; set; } = "";
[Parameter] public List<CompanyDto> CompanyList { get; set; } = new();
// [Parameter] public EventCallback<DraftItem> OnOrderItem { get; set; }
[CascadingParameter] public DraftStateProvider DraftProvider { get; set; }
// ******************************************************
// injects
[Inject] public ICountryCustomerHistoryRepository HistoryRepo { get; set; }
[Inject] public ICountryActivityRepository ActivityRepo { get; set; }
// ******************************************************
// overlays
private OfficeCustomerInvoiceListOverlay InvoiceListOverlay { get; set; } = new();
private OfficeCustomerActivityListOverlay ActivityListOverlay { get; set; } = new();
private OfficeCustomerProductListOverlay ProductListOverlay { get; set; } = new();
private string CompanyName { get; set; } = "";
private string CompanyId { get; set; } = "";
private string LastSync { get; set; } = "";
private InvoiceListView InvoiceViewList { get; set; } = new();
// ******************************************************
// variables
private InvoiceListView InvoiceList { get; set; } = new();
private List<ReportItemView> ActivityList { get; set; } = new();
private List<ProductInventoryView> ProductList { get; set; } = new();
private CompanyDto SelectedCompany { get; set; } = new();
private void OnInventoryCallback()
{
}
// ******************************************************
// functions
private async Task ShowInvoiceList(string companyId)
{
// check for console manipulation
if (!Utils.Validate(VType.Id, companyId)) return;
SelectedCompany = CompanyList.First(x => x.CompanyId == companyId);
// call erp to crm sync before requesting invoices
// get company last sync from company list
SelectedCompany = CompanyList.Find(x => x.CompanyId == companyId);
var newSyncDate = await HistoryRepo.InvoiceErpToCrmRpc(CountryCode, companyId, SelectedCompany.HistorySync);
var newSyncDate = await HistoryRepo.RequestErpToCrmSync(CountryCode, companyId, SelectedCompany.HistorySync);
await Task.Delay(500);
InvoiceViewList = await HistoryRepo.FetchInvoiceList(CountryCode, companyId);
SelectedCompany.HistorySync = newSyncDate;
InvoiceList = await HistoryRepo.RequestInvoiceList(CountryCode, companyId);
if(!string.IsNullOrWhiteSpace(newSyncDate)) SelectedCompany.HistorySync = newSyncDate;
InvoiceListOverlay.Show();
}
private async Task ShowActivityList(string companyId)
{
// call erp to crm sync before requesting invoices
// get company last sync from company list
SelectedCompany = CompanyList.Find(x => x.CompanyId == companyId);
ActivityList = await ActivityRepo.GetCustomerActivities(companyId);
// check for console manipulation
if (!Utils.Validate(VType.Id, companyId)) return;
SelectedCompany = CompanyList.First(x => x.CompanyId == companyId);
ActivityList = await ActivityRepo.RequestActitivityList(companyId);
ActivityListOverlay.Show();
}
private async Task ShowProductList(string companyId)
private async Task ShowInventory(string companyId)
{
// call erp to crm sync before requesting invoices
// get company last sync from company list
SelectedCompany = CompanyList.Find(x => x.CompanyId == companyId);
ProductList = await HistoryRepo.FetchInventory(SelectedCompany.CountryCode, SelectedCompany.CompanyId);
// check for console manipulation
if (!Utils.Validate(VType.Id, companyId)) return;
SelectedCompany = CompanyList.First(x => x.CompanyId == companyId);
// call erp to crm sync before requesting products
var newSyncDate = await HistoryRepo.RequestErpToCrmSync(CountryCode, companyId, SelectedCompany.HistorySync);
await Task.Delay(500);
if(!string.IsNullOrWhiteSpace(newSyncDate)) SelectedCompany.HistorySync = newSyncDate;
ProductList = await HistoryRepo.RequestInventory(SelectedCompany.CountryCode, SelectedCompany.CompanyId);
ProductListOverlay.Show();
}
private async Task ShowOrder(string companyId)
{
// check for console manipulation
if (!Utils.Validate(VType.Id, companyId)) return;
SelectedCompany = CompanyList.First(x => x.CompanyId == companyId);
}
}
}

View file

@ -1,82 +0,0 @@
@*
// Copyright (C) 2022 FCS Frede's Computer Services.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
*@
@using Wonky.Client.Models
@using System.ComponentModel.Design
<div class="row">
@if (Inventory.Any())
{
<div class="list-group mt-2">
<div class="list-group-item bg-dark text-white">
<div class="row">
<div class="col-sm-4" style="cursor: pointer;" @onclick="() => SortProducts(PSort.Desc)"><i class="bi-sort-alpha-down"></i> Navn <i class="bi-sort-alpha-up-alt"></i></div>
<div class="col-sm-3" style="cursor: pointer;" @onclick="() => SortProducts(PSort.Sku)"><i class="bi-sort-alpha-down"></i> Varenr <i class="bi-sort-alpha-up-alt"></i></div>
<div class="col-sm-2 text-center" style="cursor: pointer;" @onclick="() => SortProducts(PSort.Qty)"><i class="bi-sort-numeric-down"></i> Antal <i class="bi-sort-numeric-up-alt"></i></div>
<div class="col-sm-2"></div>
<div class="col-sm-1"></div>
</div>
</div>
@foreach (var product in Inventory)
{
<div class="list-group-item">
<div class="row align-items-center">
<div class="col-sm-4">
<div class="position-relative">
@product.Description
@if (product.Discontinued)
{
<span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger">Udgået</span>
<span class="visually-hidden">Produktet er udgået</span>
}
</div>
</div>
<div class="col-sm-3">
@product.Sku
</div>
<div class="col-sm-2 text-center">
@product.Quantity
</div>
<div class="col-sm-2">
<a class="btn btn-info d-block" type="button" @onclick="() => CallShowReorderModal(product.Sku)"><i class="bi-cart"></i> Genbestil</a>
</div>
<div class="col-sm-1" @onclick="() => ProductCheck(product.Sku)">
<input type="checkbox" class="btn-check" id="btn-@product.Sku.Replace(",", "")" autocomplete="off"/>
@if (product.Check)
{
<label class="btn btn-success" for="btn-@product.Sku.Replace(",", "")">
<i class="bi-check"></i>
</label>
}
else
{
<label class="btn btn-warning" for="btn-@product.Sku.Replace(",", "")">
<i class="bi-dash"></i>
</label>
}
</div>
</div>
</div>
}
</div>
}
else
{
<div>Ingen data</div>
}
</div>

View file

@ -1,86 +0,0 @@
// Copyright (C) 2022 FCS Frede's Computer Services.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
using Blazored.LocalStorage;
using Microsoft.AspNetCore.Components;
using Wonky.Client.Models;
using Wonky.Entity.Views;
#pragma warning disable CS8618
namespace Wonky.Client.Components;
public partial class OfficeCustomerInventoryListComponent
{
[Inject] private ILocalStorageService Storage { get; set; }
// Parameters
[Parameter] public List<ProductInventoryView> Inventory { get; set; } = new();
[Parameter] public string CompanyId { get; set; } = "";
[Parameter] public EventCallback<string> OnReorderSelected { get; set; }
// private variables
private bool Descending { get; set; }
private void SortProducts(PSort column)
{
Descending = !Descending;
switch (column)
{
case PSort.Desc:
if (Descending)
{
Inventory = Inventory.OrderByDescending(x => x.Description).ToList();
break;
}
Inventory = Inventory.OrderBy(x => x.Description).ToList();
break;
case PSort.Sku:
if (Descending)
{
Inventory = Inventory.OrderByDescending(x => x.Sku).ToList();
break;
}
Inventory = Inventory.OrderBy(x => x.Sku).ToList();
break;
case PSort.Qty:
if (Descending)
{
Inventory = Inventory.OrderByDescending(x => x.Quantity).ToList();
break;
}
Inventory = Inventory.OrderBy(x => x.Quantity).ToList();
break;
case PSort.None:
break;
case PSort.Abbr:
break;
default:
Inventory = Inventory.OrderByDescending(x => x.Quantity).ToList();
break;
}
}
private async Task CallShowReorderModal(string sku)
{
await ProductCheck(sku);
await OnReorderSelected.InvokeAsync(sku);
}
private async Task ProductCheck(string sku)
{
var x = Inventory.First(x => x.Sku == sku);
x.Check = !x.Check;
await Storage.SetItemAsync($"{CompanyId}-products", Inventory);
}
}

View file

@ -14,6 +14,7 @@
//
using System.Net.Mail;
using Wonky.Client.Models;
namespace Wonky.Client.Helpers;
@ -22,12 +23,25 @@ namespace Wonky.Client.Helpers;
/// </summary>
public static class Utils
{
public static bool Validate(VType vType, string toValidate)
{
return vType switch
{
VType.ISODate => toValidate.Length == 10 && DateTime.TryParse(toValidate, out _),
VType.Id => Squid.TryDecode(toValidate, out _),
VType.Passwd => IsValidPasswd(toValidate),
VType.Email => IsValidEmail(toValidate),
_ => false
};
}
/// <summary>
/// validate password to contain a-z and A-Z and 0-9
/// </summary>
/// <param name="toValidate"></param>
/// <param name="length">optional (default 10)</param>
/// <returns></returns>
public static bool ValidatePasswd(string toValidate, int length)
public static bool IsValidPasswd(string toValidate, int length = 10)
{
if (toValidate.Length < length)
return false;

View file

@ -36,5 +36,5 @@ public interface ICountryActivityRepository
/// </summary>
/// <param name="customerId"></param>
/// <returns></returns>
Task<List<ReportItemView>> GetCustomerActivities(string customerId);
Task<List<ReportItemView>> RequestActitivityList(string customerId);
}

View file

@ -28,7 +28,7 @@ public interface ICountryCustomerHistoryRepository
/// </summary>
/// <param name="companyId"></param>
/// <returns></returns>
Task<InvoiceListView> FetchInvoiceList(string countryCode, string companyId);
Task<InvoiceListView> RequestInvoiceList(string countryCode, string companyId);
/// <summary>
/// Fetch given invoice for given customer
@ -43,7 +43,7 @@ public interface ICountryCustomerHistoryRepository
/// </summary>
/// <param name="companyId"></param>
/// <returns></returns>
Task<List<ProductInventoryView>> FetchInventory(string countryCode, string companyId);
Task<List<ProductInventoryView>> RequestInventory(string countryCode, string companyId);
/// <summary>
/// Fetch History for given customer
@ -58,7 +58,7 @@ public interface ICountryCustomerHistoryRepository
/// <param name="companyId"></param>
/// <param name="sku"></param>
/// <returns></returns>
Task<List<ProductHistoryView>> FetchHistory(string countryCode, string companyId, string sku);
Task<List<ProductHistoryView>> FetchHistorySku(string countryCode, string companyId, string sku);
/// <summary>
/// RPC call to initiate remote server sync for given customer
@ -66,5 +66,5 @@ public interface ICountryCustomerHistoryRepository
/// <param name="companyId"></param>
/// <param name="syncDate"></param>
/// <returns></returns>
Task<string> InvoiceErpToCrmRpc(string countryCode, string companyId, string syncDate);
Task<string> RequestErpToCrmSync(string countryCode, string companyId, string syncDate);
}

View file

@ -67,7 +67,7 @@ public class CountryActivityRepository : ICountryActivityRepository
/// </summary>
/// <param name="customerId"></param>
/// <returns></returns>
public async Task<List<ReportItemView>> GetCustomerActivities(string customerId)
public async Task<List<ReportItemView>> RequestActitivityList(string customerId)
{
var response = await _client.GetAsync($"{_api.CrmActivities}/company/{customerId}");
var content = await response.Content.ReadAsStringAsync();

View file

@ -52,7 +52,7 @@ public class CountryCustomerHistoryRepository : ICountryCustomerHistoryRepositor
/// <param name="countryCode"></param>
/// <param name="companyId"></param>
/// <returns></returns>
public async Task<InvoiceListView> FetchInvoiceList(string countryCode, string companyId)
public async Task<InvoiceListView> RequestInvoiceList(string countryCode, string companyId)
{
var response = await _client.GetAsync($"{_api.OfficeCustomers}/{countryCode}/{companyId}/invoices");
@ -89,7 +89,7 @@ public class CountryCustomerHistoryRepository : ICountryCustomerHistoryRepositor
/// <param name="countryCode"></param>
/// <param name="companyId"></param>
/// <returns></returns>
public async Task<List<ProductInventoryView>> FetchInventory(string countryCode, string companyId)
public async Task<List<ProductInventoryView>> RequestInventory(string countryCode, string companyId)
{
var response = await _client.GetAsync($"{_api.OfficeCustomers}/{countryCode}/{companyId}/history/inventory");
if (!response.IsSuccessStatusCode)
@ -125,7 +125,7 @@ public class CountryCustomerHistoryRepository : ICountryCustomerHistoryRepositor
/// <param name="companyId"></param>
/// <param name="sku"></param>
/// <returns></returns>
public async Task<List<ProductHistoryView>> FetchHistory(string countryCode, string companyId, string sku)
public async Task<List<ProductHistoryView>> FetchHistorySku(string countryCode, string companyId, string sku)
{
var response = await _client.GetAsync($"{_api.OfficeCustomers}/{countryCode}/{companyId}/history/products/{sku}");
if (!response.IsSuccessStatusCode)
@ -143,7 +143,7 @@ public class CountryCustomerHistoryRepository : ICountryCustomerHistoryRepositor
/// <param name="companyId"></param>
/// <param name="syncDate"></param>
/// <returns></returns>
public async Task<string> InvoiceErpToCrmRpc(string countryCode, string companyId, string syncDate)
public async Task<string> RequestErpToCrmSync(string countryCode, string companyId, string syncDate)
{
var x = await _client.GetAsync($"{_api.OfficeCustomers}/{countryCode}/{companyId}/{_api.SyncRpcInvoiceExt}/{syncDate}");
if (!x.IsSuccessStatusCode)

View file

@ -0,0 +1,9 @@
namespace Wonky.Client.Models;
public enum VType
{
Id,
ISODate,
Passwd,
Email
}

View file

@ -25,7 +25,7 @@
</div>
<div class="modal-body">
@* activity list *@
<OfficeCustomerActivityListComponent Activities="Activities"/>
<OfficeCustomerActivityListComponent Activities="ActivityList"/>
</div>
</div>
</div>

View file

@ -23,7 +23,7 @@ namespace Wonky.Client.OverlayOffice;
public partial class OfficeCustomerActivityListOverlay
{
[Parameter] public CompanyDto Company { get; set; } = new();
[Parameter] public List<ReportItemView> Activities { get; set; } = new();
[Parameter] public List<ReportItemView> ActivityList { get; set; } = new();
private string _modalDisplay = "";
private bool _showBackdrop;

View file

@ -1,38 +0,0 @@
@*
// Copyright (C) 2022 FCS Frede's Computer Services.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
*@
@using Wonky.Client.Components
<div class="modal" tabindex="-1" role="dialog" style="display:@_modalDisplay">
<div class="modal-dialog modal-dialog-scrollable modal-fullscreen">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title">@CompanyName - Produktoversigt</h3>
<button type="button" class="btn-close" @onclick="Hide" data-bs-dismiss="modal" aria-label="Luk"></button>
</div>
<div class="modal-body">
@* product list *@
<OfficeCustomerInventoryListComponent OnReorderSelected="OnReorderCallback" CompanyId="@CompanyId" Inventory="@Inventory"/>
</div>
</div>
</div>
</div>
@if (_showBackdrop)
{
<div class="modal-backdrop fade show"></div>
}
@* reorder overlay *@
<OfficeCustomerInventoryReorderOverlay CompanyId="@CompanyId" SalesItem="SalesItem" OnSelected="OnInventorySelected" @ref="ReorderOverlay" />

View file

@ -1,85 +0,0 @@
// Copyright (C) 2022 FCS Frede's Computer Services.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
using Microsoft.AspNetCore.Components;
using Wonky.Client.HttpInterceptors;
using Wonky.Client.HttpInterfaces;
using Wonky.Client.Models;
using Wonky.Entity.DTO;
using Wonky.Entity.Views;
#pragma warning disable CS8618
namespace Wonky.Client.OverlayOffice;
public partial class OfficeCustomerInventoryListOverlay : IDisposable
{
[Inject] private HttpInterceptorService Interceptor { get; set; }
[Inject] private ICountryCatalogRepository CatalogRepo { get; set; }
[Inject] private ILogger<OfficeCustomerInventoryListOverlay> Logger { get; set; }
[Parameter] public string CompanyName { get; set; } = "";
[Parameter] public string CompanyId { get; set; } = "";
[Parameter] public string CountryCode { get; set; } = "";
[Parameter] public List<ProductInventoryView> Inventory { get; set; } = new();
[Parameter] public EventCallback<DraftItem> OnInventorySelected { get; set; }
private string _modalDisplay = "";
private bool _showBackdrop;
private CompanyDto _company { get; set; } = new();
private List<ProductInventoryView> _inventory { get; set; } = new();
private DraftItem DraftItem { get; set; } = new();
private SalesItemView SalesItem { get; set; } = new();
private OfficeCustomerInventoryReorderOverlay ReorderOverlay { get; set; } = new();
protected override void OnInitialized()
{
Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent();
StateHasChanged();
}
private async Task OnReorderCallback(string sku)
{
SalesItem = await CatalogRepo.GetSalesItemSku(CountryCode.ToLower(), sku);
ReorderOverlay.Show();
}
private async Task OnSelectedItem(DraftItem draftItem)
{
await OnInventorySelected.InvokeAsync(draftItem);
Hide();
}
public void Show()
{
_modalDisplay = "block;";
_showBackdrop = true;
StateHasChanged();
}
private void Hide()
{
_modalDisplay = "none;";
_showBackdrop = false;
StateHasChanged();
}
public void Dispose()
{
Interceptor.DisposeEvent();
}
}

View file

@ -18,6 +18,7 @@ using System.Globalization;
using Microsoft.AspNetCore.Components;
using Wonky.Client.HttpInterfaces;
using Wonky.Client.Models;
using Wonky.Entity.DTO;
using Wonky.Entity.Views;
#pragma warning disable CS8618
@ -25,11 +26,11 @@ namespace Wonky.Client.OverlayOffice;
public partial class OfficeCustomerInventoryReorderOverlay
{
[Parameter] public string CompanyId { get; set; } = "";
[Parameter] public CompanyDto Company { get; set; }
[Parameter] public SalesItemView SalesItem { get; set; } = new();
[Inject] public ICountryCustomerHistoryRepository HistoryRepo { get; set; }
[Parameter] public EventCallback<DraftItem> OnSelected { get; set; }
private List<ProductHistoryView>? History { get; set; } = new();
[Parameter] public EventCallback<DraftItem> OrderItemCallback { get; set; }
private List<ProductHistoryView> History { get; set; } = new();
private DraftItem SelectedItem { get; set; } = new();
private string ProductName { get; set; } = "";
private string _modalDisplay = "";
@ -41,9 +42,9 @@ public partial class OfficeCustomerInventoryReorderOverlay
if (string.IsNullOrWhiteSpace(SalesItem.Sku))
return;
History = await HistoryRepo.FetchHistory(CompanyId, SalesItem.Sku);
if (!History.Any())
await Task.Delay(1000);
History = await HistoryRepo.FetchHistorySku(Company.CountryCode, Company.CompanyId, SalesItem.Sku);
// if (!History.Any())
// await Task.Delay(500);
SelectedItem.Item = SalesItem;
SelectedItem.Discount = 0;
SelectedItem.Quantity = 1;
@ -54,7 +55,7 @@ public partial class OfficeCustomerInventoryReorderOverlay
private async Task SendToOrder(DraftItem item)
{
SelectedItem = new DraftItem();
await OnSelected.InvokeAsync(item);
await OrderItemCallback.InvokeAsync(item);
Hide();
}

View file

@ -24,7 +24,7 @@ namespace Wonky.Client.OverlayOffice;
public partial class OfficeCustomerInvoiceListOverlay
{
[Parameter] public InvoiceListView CustomerInvoices { get; set; } = new();
[Parameter] public InvoiceListView InvoiceList { get; set; } = new();
[Parameter] public CompanyDto Company { get; set; } = new();
// dependency injection
[Inject] private ILogger<OfficeCustomerInvoiceListOverlay> Logger { get; set; }
@ -39,8 +39,8 @@ public partial class OfficeCustomerInvoiceListOverlay
// extract company from customer invoices
Logger.LogDebug("CustomerInvoiceListOverlay => company => {}", JsonSerializer.Serialize(Company));
// if there is invoices -> order by document date
if (CustomerInvoices.Invoices.Any())
Invoices = CustomerInvoices.Invoices.OrderByDescending(x => x.DocumentDate).ToList();
if (InvoiceList.Invoices.Any())
Invoices = InvoiceList.Invoices.OrderByDescending(x => x.DocumentDate).ToList();
Logger.LogDebug("invoices => {}", JsonSerializer.Serialize(Invoices));
}

View file

@ -14,7 +14,7 @@
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
*@
@using Wonky.Client.Components
@using Wonky.Client.Models
<div class="modal" tabindex="-1" role="dialog" style="display:@_modalDisplay">
<div class="modal-dialog modal-dialog-scrollable modal-fullscreen">
@ -24,8 +24,51 @@
<button type="button" class="btn-close" @onclick="Hide" data-bs-dismiss="modal" aria-label="Luk"></button>
</div>
<div class="modal-body">
@* product list *@
<CustomerInventoryListComponent OnReorderSelected="OnReorderCallback" CompanyId="@Company.CompanyId" Inventory="@ProductList"/>
<div class="row">
@if (ProductList.Any())
{
<div class="list-group mt-2">
<div class="list-group-item bg-dark text-white">
<div class="row">
<div class="col-sm-4" style="cursor: pointer;" @onclick="() => SortProducts(PSort.Desc)"><i class="bi-sort-alpha-down"></i> Navn <i class="bi-sort-alpha-up-alt"></i></div>
<div class="col-sm-3" style="cursor: pointer;" @onclick="() => SortProducts(PSort.Sku)"><i class="bi-sort-alpha-down"></i> Varenr <i class="bi-sort-alpha-up-alt"></i></div>
<div class="col-sm-2 text-center" style="cursor: pointer;" @onclick="() => SortProducts(PSort.Qty)"><i class="bi-sort-numeric-down"></i> Antal <i class="bi-sort-numeric-up-alt"></i></div>
<div class="col-sm-2"></div>
<div class="col-sm-1"></div>
</div>
</div>
@foreach (var product in ProductList)
{
<div class="list-group-item">
<div class="row align-items-center">
<div class="col-sm-4">
<div class="position-relative">
@product.Description
@if (product.Discontinued)
{
<span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger">Udgået</span>
<span class="visually-hidden">Produktet er udgået</span>
}
</div>
</div>
<div class="col-sm-3">
@product.Sku
</div>
<div class="col-sm-2 text-center">
@product.Quantity
</div>
<div class="col-sm-3">
</div>
</div>
</div>
}
</div>
}
else
{
<div>Ingen data</div>
}
</div>
</div>
</div>
</div>
@ -34,5 +77,9 @@
{
<div class="modal-backdrop fade show"></div>
}
@* reorder overlay *@
<OfficeCustomerInventoryReorderOverlay CompanyId="@Company.CompanyId" SalesItem="SalesItem" OnSelected="OnInventorySelected" @ref="ReorderOverlay" />
@*
reorder overlay
invoked by list component OnReorderSku=OnReorderCallback
*@
<OfficeCustomerInventoryReorderOverlay Company="Company" SalesItem="SalesItem" @ref="ReorderOverlay"/>

View file

@ -1,4 +1,3 @@
// Copyright (C) 2022 FCS Frede's Computer Services.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
@ -20,6 +19,7 @@ using Wonky.Client.HttpInterfaces;
using Wonky.Client.Models;
using Wonky.Entity.DTO;
using Wonky.Entity.Views;
#pragma warning disable CS8618
namespace Wonky.Client.OverlayOffice;
@ -29,52 +29,85 @@ public partial class OfficeCustomerProductListOverlay : IDisposable
[Inject] private HttpInterceptorService Interceptor { get; set; }
[Inject] private ICountryCatalogRepository CatalogRepo { get; set; }
[Inject] private ILogger<OfficeCustomerProductListOverlay> Logger { get; set; }
[Parameter] public CompanyDto Company { get; set; }
[Parameter] public List<ProductInventoryView> ProductList { get; set; } = new();
[Parameter] public EventCallback<DraftItem> OnInventorySelected { get; set; }
private string _modalDisplay = "";
private bool _showBackdrop;
private CompanyDto _company { get; set; } = new();
private List<ProductInventoryView> _inventory { get; set; } = new();
private DraftItem DraftItem { get; set; } = new();
private SalesItemView SalesItem { get; set; } = new();
private OfficeCustomerInventoryReorderOverlay ReorderOverlay { get; set; } = new();
private bool Descending { get; set; }
[Parameter] public CompanyDto Company { get; set; } = new();
[Parameter] public List<ProductInventoryView> ProductList { get; set; } = new();
protected override void OnInitialized()
{
Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent();
StateHasChanged();
}
private async Task OnReorderCallback(string sku)
private async Task ShowSkuReorder(string sku)
{
SalesItem = await CatalogRepo.GetSalesItemSku(Company.CountryCode.ToLower(), sku);
ReorderOverlay.Show();
}
private async Task OnSelectedItem(DraftItem draftItem)
{
await OnInventorySelected.InvokeAsync(draftItem);
Hide();
}
private void SortProducts(PSort column)
{
Descending = !Descending;
switch (column)
{
case PSort.Desc:
if (Descending)
{
ProductList = ProductList.OrderByDescending(x => x.Description).ToList();
break;
}
ProductList = ProductList.OrderBy(x => x.Description).ToList();
break;
case PSort.Sku:
if (Descending)
{
ProductList = ProductList.OrderByDescending(x => x.Sku).ToList();
break;
}
ProductList = ProductList.OrderBy(x => x.Sku).ToList();
break;
case PSort.Qty:
if (Descending)
{
ProductList = ProductList.OrderByDescending(x => x.Quantity).ToList();
break;
}
ProductList = ProductList.OrderBy(x => x.Quantity).ToList();
break;
case PSort.None:
break;
case PSort.Abbr:
break;
default:
ProductList = ProductList.OrderByDescending(x => x.Quantity).ToList();
break;
}
}
public void Show()
{
_modalDisplay = "block;";
_showBackdrop = true;
StateHasChanged();
}
private void Hide()
{
_modalDisplay = "none;";
_showBackdrop = false;
StateHasChanged();
}
public void Dispose()
{
Interceptor.DisposeEvent();

View file

@ -16,14 +16,14 @@
using Microsoft.AspNetCore.Components;
using Wonky.Client.HttpInterceptors;
using Wonky.Client.HttpInterfaces;
using Wonky.Client.HttpRepository;
using Wonky.Client.Models;
using Wonky.Client.Services;
using Wonky.Entity.Requests;
using Wonky.Entity.Views;
#pragma warning disable CS8618
namespace Wonky.Client.Shared;
namespace Wonky.Client.OverlayOrderCreate;
public partial class PriceCatalogOverlay : IDisposable
{

View file

@ -17,7 +17,7 @@
using Microsoft.AspNetCore.Components;
using Wonky.Entity.Views;
namespace Wonky.Client.Shared;
namespace Wonky.Client.OverlayOrderCreate;
public partial class ProductCheckConfirmationOverlay
{

View file

@ -15,16 +15,12 @@
//
using Microsoft.AspNetCore.Components;
using Wonky.Client.HttpInterceptors;
using Wonky.Client.HttpInterfaces;
using Wonky.Client.HttpRepository;
using Wonky.Client.Models;
using Wonky.Client.Services;
using Wonky.Entity.Requests;
using Wonky.Entity.Views;
#pragma warning disable CS8618
namespace Wonky.Client.Shared;
namespace Wonky.Client.OverlayOrderCreate;
public partial class ProductHistoryOverlay
{

View file

@ -17,9 +17,10 @@
using Microsoft.AspNetCore.Components;
using Wonky.Client.HttpInterfaces;
using Wonky.Entity.Views;
#pragma warning disable CS8618
namespace Wonky.Client.Shared;
namespace Wonky.Client.OverlayOrderCreate;
public partial class ProductPriceHistoryOverlay
{

View file

@ -18,6 +18,7 @@
@using Microsoft.AspNetCore.Authorization
@using Wonky.Client.Components
@using Wonky.Client.OverlayCustomer
@using Wonky.Client.OverlayOrderCreate
@attribute [Authorize(Roles = "Advisor")]
@page "/advisor/customers/{CompanyId}/activities/new"

View file

@ -25,6 +25,7 @@ using Wonky.Client.HttpInterceptors;
using Wonky.Client.HttpInterfaces;
using Wonky.Client.Models;
using Wonky.Client.OverlayCustomer;
using Wonky.Client.OverlayOrderCreate;
using Wonky.Client.Services;
using Wonky.Client.Shared;
using Wonky.Entity.DTO;

View file

@ -16,8 +16,9 @@
*@
@using Wonky.Client.Components
@using Wonky.Client.OverlayOrderCreate
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Roles = "Admin,Office,Warehouse")]
@attribute [Authorize(Roles = "Admin,Office,Supervisor,Warehouse")]
@page "/office/customers/{CountryCode}/{CompanyId}/order"
<PageTitle>Telefon Ordre - @Customer.Name - @Customer.Account</PageTitle>

View file

@ -20,6 +20,7 @@ using Microsoft.AspNetCore.Components.Forms;
using Wonky.Client.HttpInterceptors;
using Wonky.Client.HttpInterfaces;
using Wonky.Client.Models;
using Wonky.Client.OverlayOrderCreate;
using Wonky.Client.Shared;
using Wonky.Entity.DTO;
using Wonky.Entity.Views;

View file

@ -83,7 +83,7 @@ public partial class SystemUserViewEditPage : IDisposable
private void PwValidationChanged(object sender, ValidationStateChangedEventArgs e)
{
PwInvalid = true;
if (!Utils.ValidatePasswd(Passwords.NewPassword, MinPwLength))
if (!Utils.IsValidPasswd(Passwords.NewPassword, MinPwLength))
return;
PasswdContext.OnFieldChanged -= PwHandleFieldChanged;

View file

@ -3795,4 +3795,8 @@
<None Remove="wwwroot\icons\**" />
</ItemGroup>
<ItemGroup>
<Folder Include="OverlayAdvisor" />
</ItemGroup>
</Project>

View file

@ -1,7 +1,7 @@
{
"appInfo": {
"name": "Wonky Online",
"version": "0.116.0",
"version": "0.116.1",
"rc": true,
"sandBox": false,
"image": "grumpy-coder.png"
@ -19,7 +19,7 @@
}
},
"apiConfig": {
"baseUrl": "https://dev.innotec.dk",
"baseUrl": "https://zeta.innotec.dk",
"catalog": "api/v2/catalog/country",
"crmCustomers": "api/v2/crm/companies",
"crmInventoryExt": "history/inventory",