FIX various bugs and display issues with office phone order process

This commit is contained in:
Frede Hundewadt 2023-06-07 08:40:57 +02:00
parent 3c738e3313
commit 278f116e95
19 changed files with 198 additions and 202 deletions

View file

@ -49,7 +49,7 @@
<td>Log af</td>
</tr>
<tr>
<td><i class="bi-question" style="font-size:1.3rem"></i></td>
<td><i class="bi-life-preserver" style="font-size:1.3rem"></i></td>
<td>Hjælp/Info</td>
</tr>
</thead>

View file

@ -24,20 +24,22 @@
{
<div class="col-sm-6">
<div class="card">
<div class="card-header">
<span class="fw-bold">@company.Name</span>
</div>
<div class="card-body">
<h5 class="card-title">
@company.Name
</h5>
<div class="row">
<div class="col-sm-3 col-md-3 fw-bold">Konto</div>
<div class="col-sm-3 col-dm-3">@company.Account</div>
<div class="col-sm-3 col-md-3 fw-bold">CVR / ORG</div>
<div class="col-sm-3 col-md-3 fw-bold">Org Nr.</div>
<div class="col-sm-3 col-md-3">@company.VatNumber</div>
</div>
<div class="row">
<div class="col-sm-3 col-md-3 fw-bold">Telefon</div>
<div class="col-sm-3 col-md-3">@company.Phone</div>
<div class="col-sm-3 col-md-3 fw-bold">Besøg</div>
<div class="col-sm-3 col-md-3">@company.LastVisit <DisplayStateComponent StateClass="@(company.HasFolded == 1 ? "the-dead" : Utils.GetVisitState(company.NextVisit))"/></div>
</div>
<div class="row">
<div class="col-sm-3 col-md-3 fw-bold">Adresse</div>
@ -51,16 +53,16 @@
<div class="card-footer">
<div class="row">
<div class="col">
<button class="btn btn-danger" @onclick="@(() => ShowInvoiceList(company.CompanyId))" >Faktura</button>
<button class="btn btn-danger" @onclick="@(() => ShowInvoiceList(company.CompanyId))">Faktura</button>
</div>
<div class="col">
<button class="btn btn-warning" @onclick="@(() => ShowActivityList(company.CompanyId))" >Aktivitet</button>
<button class="btn btn-warning" @onclick="@(() => ShowActivityList(company.CompanyId))">Aktivitet</button>
</div>
<div class="col">
<button class="btn btn-success" @onclick="@(() => ShowInventory(company.CompanyId))">Produkt</button>
</div>
<div class="col">
<a class="btn btn-primary" href="/office/customers/@company.CountryCode.ToLower()/@company.CompanyId/order" >Bestilling</a>
<a class="btn btn-primary" href="/office/customers/@company.CountryCode.ToLower()/@company.CompanyId/order">Bestilling</a>
</div>
</div>
</div>
@ -68,13 +70,11 @@
</div>
}
</div>
<OfficeCustomerInvoiceListOverlay Company="@SelectedCompany" InvoiceList="@InvoiceList" @ref="InvoiceListOverlay" />
<OfficeCustomerActivityListOverlay Company="SelectedCompany" ActivityList="ActivityList" @ref="ActivityListOverlay" />
<OfficeCustomerInventoryListOverlay Company="SelectedCompany" Inventory="ProductList" @ref="InventoryListOverlay" />
<OfficeCustomerInvoiceListOverlay Company="@SelectedCompany" InvoiceList="@InvoiceList" @ref="InvoiceListOverlay"/>
<OfficeCustomerActivityListOverlay Company="SelectedCompany" ActivityList="ActivityList" @ref="ActivityListOverlay"/>
<OfficeCustomerListInventoryOverlay Company="SelectedCompany" Inventory="ProductList" @ref="InventoryListOverlay"/>
}
else
{
<div>Ingen data</div>
}
}

View file

@ -48,7 +48,7 @@ public partial class OfficeCountryCustomerListComponent
// overlays
private OfficeCustomerInvoiceListOverlay InvoiceListOverlay { get; set; } = new();
private OfficeCustomerActivityListOverlay ActivityListOverlay { get; set; } = new();
private OfficeCustomerInventoryListOverlay InventoryListOverlay { get; set; } = new();
private OfficeCustomerListInventoryOverlay InventoryListOverlay { get; set; } = new();
// ******************************************************
// variables

View file

@ -19,7 +19,7 @@
<Authorized>
<div class="d-print-none">
<a class="btn btn-outline-light" href="/logout" title="Log af" ><i class="bi-lock"></i></a>
<a class="btn btn-outline-light" href="/info" title="Information"><i class="bi-question"></i></a>
<a class="btn btn-outline-light" href="/info" title="Information"><i class="bi-life-preserver"></i></a>
<a class="btn btn-outline-light" href="/preferences" title="Indstillinger"><i class="bi-sliders"></i></a>
</div>
</Authorized>

View file

@ -336,7 +336,7 @@ public static class Utils
public static string GetVisitState(string dtNextVisit)
{
if (dtNextVisit is "0001-01-01" or "1970-01-01")
if (dtNextVisit is "0001-01-01" or "1970-01-01" or "2010-01-01")
return "the-draw";
if (!DateTime.TryParse(dtNextVisit, out _))
return "the-draw";

View file

@ -24,7 +24,7 @@ using Wonky.Entity.Views;
namespace Wonky.Client.OverlayOffice;
public partial class OfficeCustomerInventoryReorderOverlay
public partial class OfficeCustomerInventoryItemReorderOverlay
{
// ##############################################################
[Parameter] public CompanyDto Company { get; set; }

View file

@ -1,110 +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 Wonky.Client.Enums
<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">@Company.Name - Produkt oversigt</h3>
<button type="button" class="btn btn-danger" @onclick="@Hide" data-bs-dismiss="modal" aria-label="Luk"><i class="bi-x-lg"></i></button>
</div>
<div class="modal-body">
<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(ProductSort.Description))"><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(ProductSort.Sku))"><i class="bi-sort-alpha-down"></i> Varenr <i class="bi-sort-alpha-up-alt"></i></div>
*@
<div class="col-sm-7 text-end">
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="sortOrder" checked @onclick="@SetSortOrder"/>
<label class="form-check-label" for="sortOrder">
<i class="@(Descending ? "bi-sort-up" : "bi-sort-down-alt")"></i>
</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="sortCol" id="description" value="description"
onclick="@(() => SortProducts(SortColumn.Description))">
<label class="form-check-label" for="description">Navn</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="sortCol" id="itemNumber" value="itemNumber"
onclick="@(() => SortProducts(SortColumn.Sku))">
<label class="form-check-label" for="itemNumber">Vare Nr.</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="sortCol" id="lastInvoiceDate" value="itemDate"
onclick="@(() => SortProducts(SortColumn.LastInvoiceDate))" checked>
<label class="form-check-label" for="lastInvoiceDate">Sidst leveret</label>
</div>
</div>
<div class="col-sm-5">
<SearchPhraseComponent OnChanged="OnSearchChanged"/>
</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-3">
</div>
</div>
</div>
}
</div>
}
else
{
<div>Ingen data</div>
}
</div>
</div>
</div>
</div>
</div>
@if (_showBackdrop)
{
<div class="modal-backdrop fade show"></div>
}
@*
reorder overlay
invoked by list component OnReorderSku=OnReorderCallback
*@
<OfficeCustomerInventoryReorderOverlay Company="Company" SalesItem="SalesItem" @ref="ReorderOverlay"/>

View file

@ -17,15 +17,13 @@
@using Wonky.Client.Models
@using System.ComponentModel.Design
@using Wonky.Client.Enums
@using Wonky.Client.Components
<div class="row">
@if (Inventory.Any())
{
<div class="list-group mt-2">
<div class="list-group-item">
<div class="row">
@* <div class="col-sm-4" style="cursor: pointer;" @onclick="@(() => SortProducts(ProductSort.Description))"><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(ProductSort.Sku))"><i class="bi-sort-alpha-down"></i> Varenr <i class="bi-sort-alpha-up-alt"></i></div> *@
<div class="col-sm-7 text-end">
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="sortOrder" checked @onclick="@SetSortOrder"/>
@ -52,11 +50,23 @@
</div>
</div>
</div>
@foreach (var product in Inventory)
@foreach (var product in DisplayList)
{
<div class="list-group-item">
<div class="row align-items-center">
<div class="col-sm-4">
<div class="col-sm-2">
<div class="position-relative">
@product.LastInvoiceDate
@if (product.AgedProduct() && !product.Discontinued)
{
<span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger">
Længe siden
<span class="visually-hidden">Længe siden</span>
</span>
}
</div>
</div>
<div class="col-sm-3">
<div class="position-relative">
@product.Description
@if (product.Discontinued)
@ -72,7 +82,7 @@
<div class="col-sm-2 text-center">
@product.Quantity
</div>
<div class="col-sm-3">
<div class="col">
<button class="btn btn-info d-block" type="button" @onclick="@(() => CallShowReorderModal(product.Sku))"><i class="bi-cart"></i> Genbestil</button>
</div>
</div>

View file

@ -21,10 +21,10 @@ using Wonky.Client.Models;
using Wonky.Entity.Views;
using Utils = Wonky.Client.Helpers.Utils;
namespace Wonky.Client.Components;
namespace Wonky.Client.OverlayOffice;
#pragma warning disable CS8618
public partial class OfficeCustomerInventoryListComponent
public partial class OfficeCustomerInventoryListReorderComponent
{
// *************************************************************
// Injections
@ -39,22 +39,22 @@ public partial class OfficeCustomerInventoryListComponent
// *************************************************************
// private variables
private bool Descending { get; set; } = true;
private string SearchTerm { get; set; } = "";
private List<ProductInventoryItemView> FilteredList { get; set; } = new();
private string DisplayFilter { get; set; } = "";
private List<ProductInventoryItemView> DisplayList { get; set; } = new();
private SortColumn SortColumn { get; set; } = SortColumn.LastInvoiceDate;
protected override void OnParametersSet()
{
Inventory = Utils.SortInventory(Inventory, SortColumn, Descending);
FilterItems(SearchTerm);
FilterItems(DisplayFilter);
}
private void SetSortOrder()
{
Descending = !Descending;
FilteredList = Utils.SortInventory(FilteredList, SortColumn, Descending);
DisplayList = Utils.SortInventory(DisplayList, SortColumn, Descending);
}
@ -66,8 +66,8 @@ public partial class OfficeCustomerInventoryListComponent
private void FilterItems(string filter)
{
SearchTerm = filter;
FilteredList = string.IsNullOrWhiteSpace(filter)
DisplayFilter = filter;
DisplayList = string.IsNullOrWhiteSpace(filter)
? Inventory
: Inventory.Where(i => i.Description.ToLower().Contains(filter.ToLower())).ToList();
}
@ -75,13 +75,13 @@ public partial class OfficeCustomerInventoryListComponent
private void SortProducts(SortColumn column)
{
FilteredList = Utils.SortInventory(FilteredList, column, Descending);
SortColumn = column;
DisplayList = Utils.SortInventory(DisplayList, SortColumn, Descending);
}
private async Task CallShowReorderModal(string sku)
{
// await ProductCheck(sku);
await OnReorderSelected.InvokeAsync(sku);
}
}

View file

@ -25,7 +25,7 @@
</div>
<div class="modal-body">
@* component listing invoices*@
<CustomerInvoiceListComponent OnShowInvoice="@CallInvoiceModal" CompanyId="@Company.CompanyId" Invoices="@Invoices"/>
<CustomerInvoiceListComponent OnShowInvoice="@CallInvoiceModal" Invoices="@Invoices"/>
</div>
</div>
</div>

View file

@ -38,10 +38,10 @@ public partial class OfficeCustomerInvoiceListOverlay
private OfficeCustomerInvoiceViewOverlay InvoiceView { get; set; } = new();
private List<InvoiceListItemView> Invoices { get; set; } = new();
protected override async Task OnParametersSetAsync()
protected override void OnParametersSet()
{
// extract company from customer invoices
Logger.LogDebug("CustomerInvoiceListOverlay => company => {}", JsonSerializer.Serialize(Company));
Logger.LogDebug("OfficeInvoiceListOverlay => company => {}", JsonSerializer.Serialize(Company));
// if there is invoices -> order by document date
if (InvoiceList.Invoices.Any())
Invoices = InvoiceList.Invoices.OrderByDescending(x => x.DocumentDate).ToList();

View file

@ -1,4 +1,4 @@
00@* Copyright (C) 2022 FCS Frede's Computer Services.
@* 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

View file

@ -0,0 +1,112 @@
@* 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 Wonky.Client.Enums
@using Wonky.Client.Components
@using System.Text.Json
<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">@Company.Name - Produkt oversigt</h3>
<button type="button" class="btn btn-danger" @onclick="@Hide" data-bs-dismiss="modal" aria-label="Luk">
<i class="bi-x-lg"></i>
</button>
</div>
<div class="modal-body">
@if (DisplayList.Any())
{
<div class="list-group mt-2">
<div class="list-group-item">
<div class="row">
<div class="col-sm-7 text-end">
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="sortOrder" checked @onclick="@SetSortOrder"/>
<label class="form-check-label" for="sortOrder">
<i class="@(Descending ? "bi-sort-up" : "bi-sort-down-alt")"></i>
</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="sortCol" id="description" value="description"
onclick="@(() => SortDisplayList(SortColumn.Description))">
<label class="form-check-label" for="description">Navn</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="sortCol" id="itemNumber" value="itemNumber"
onclick="@(() => SortDisplayList(SortColumn.Sku))">
<label class="form-check-label" for="itemNumber">Vare Nr.</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="sortCol" id="lastInvoiceDate" value="itemDate"
onclick="@(() => SortDisplayList(SortColumn.LastInvoiceDate))" checked>
<label class="form-check-label" for="lastInvoiceDate">Sidst leveret</label>
</div>
</div>
<div class="col-sm-5">
<SearchPhraseComponent OnChanged="OnSearchChanged"/>
</div>
</div>
</div>
@foreach (var product in DisplayList)
{
<div class="list-group-item">
<div class="row align-items-center">
<div class="col-sm-2">
<div class="position-relative">
@product.LastInvoiceDate
@if (product.AgedProduct() && !product.Discontinued)
{
<span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger">
Længe siden
<span class="visually-hidden">Længe siden</span>
</span>
}
</div>
</div>
<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>
</div>
}
</div>
}
else
{
<div>Ingen data</div>
}
</div>
</div>
</div>
</div>
@if (_showBackdrop)
{
<div class="modal-backdrop fade show"></div>
}

View file

@ -14,6 +14,7 @@
//
using System.Text.Json;
using Microsoft.AspNetCore.Components;
using Wonky.Client.Enums;
using Wonky.Client.Helpers;
@ -27,12 +28,10 @@ using Wonky.Entity.Views;
namespace Wonky.Client.OverlayOffice;
public partial class OfficeCustomerInventoryListOverlay : IDisposable
public partial class OfficeCustomerListInventoryOverlay
{
// ##############################################################
[Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public ICountryCatalogRepository CatalogRepo { get; set; }
[Inject] public ILogger<OfficeCustomerInventoryListOverlay> Logger { get; set; }
[Inject] public ILogger<OfficeCustomerListInventoryOverlay> Logger { get; set; }
// ##############################################################
[Parameter] public CompanyDto Company { get; set; } = new();
@ -41,58 +40,50 @@ public partial class OfficeCustomerInventoryListOverlay : IDisposable
// ##############################################################
private string _modalDisplay = "";
private bool _showBackdrop;
private DraftItem DraftItem { get; set; } = new();
private SalesItemView SalesItem { get; set; } = new();
private OfficeCustomerInventoryReorderOverlay ReorderOverlay { get; set; } = new();
private bool Descending { get; set; } = true;
private string SearchTerm { get; set; } = "";
private List<ProductInventoryItemView> FilteredList { get; set; } = new();
private string DisplayFilter { get; set; } = "";
private List<ProductInventoryItemView> DisplayList { get; set; } = new();
private SortColumn SortColumn { get; set; } = SortColumn.LastInvoiceDate;
protected override void OnInitialized()
protected override void OnParametersSet()
{
Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent();
// sort the base Inventory
Inventory = Utils.SortInventory(Inventory, SortColumn, Descending);
FilterItems(SearchTerm);
StateHasChanged();
// initialize FilteredList
ApplyInventoryFilter(DisplayFilter);
Logger.LogDebug("OffCustListInvenOverlay {}", JsonSerializer.Serialize(DisplayList));
}
private void OnSearchChanged(string searchTerm)
{
FilterItems(searchTerm);
}
private void SortProducts(SortColumn column)
{
Descending = !Descending;
FilteredList = Utils.SortInventory(FilteredList, column, Descending);
}
private void SetSortOrder()
{
Descending = !Descending;
FilteredList = Utils.SortInventory(FilteredList, SortColumn, Descending);
SortDisplayList(SortColumn);
}
private void SortDisplayList(SortColumn sortColumn)
{
SortColumn = sortColumn;
DisplayList = Utils.SortInventory(DisplayList, SortColumn, Descending);
}
private void FilterItems(string filter)
private void OnSearchChanged(string searchTerm)
{
SearchTerm = filter;
FilteredList = string.IsNullOrWhiteSpace(filter)
// use search input to filter list
ApplyInventoryFilter(searchTerm);
}
private void ApplyInventoryFilter(string searchTerm)
{
DisplayFilter = searchTerm;
DisplayList = string.IsNullOrWhiteSpace(searchTerm)
? Inventory
: Inventory.Where(i => i.Description.ToLower().Contains(filter.ToLower())).ToList();
}
private async Task ShowSkuReorder(string sku)
{
SalesItem = await CatalogRepo.GetSalesItemSku(Company.CountryCode.ToLower(), sku);
ReorderOverlay.Show();
: Inventory.Where(i => i.Description.ToLower().Contains(searchTerm.ToLower())).ToList();
}
@ -110,10 +101,4 @@ public partial class OfficeCustomerInventoryListOverlay : IDisposable
_showBackdrop = false;
StateHasChanged();
}
public void Dispose()
{
Interceptor.DisposeEvent();
}
}

View file

@ -23,7 +23,7 @@
<button type="button" class="btn btn-danger" @onclick="@Hide" data-bs-dismiss="modal" aria-label="Luk"><i class="bi-x-lg"></i></button>
</div>
<div class="modal-body">
<OfficeCustomerInventoryListComponent OnReorderSelected="OnReorderCallback" CompanyId="@Company.CompanyId" Inventory="@Inventory"/>
<OfficeCustomerInventoryListReorderComponent OnReorderSelected="OnReorderCallback" CompanyId="@Company.CompanyId" Inventory="@Inventory"/>
</div>
</div>
</div>

View file

@ -35,7 +35,7 @@
<PageSizeComponent OnChanged="SetPageSize" />
</div>
<div class="col-sm-2 mx-auto">
<button type button class="btn btn-warning @(ShowFolded ? "active" : "")"
<button type="button" class="btn btn-warning @(ShowFolded ? "active" : "")"
data-bs-toggle="button" aria-pressed="@ShowFolded" @onclick="@ToggleFolded">
@ToggleFoldedText
</button>
@ -70,4 +70,3 @@
{
<WorkingThreeDots />
}

View file

@ -141,7 +141,7 @@
<AuthorizeView Roles="Admin,Advisor,Management,Office,Supervisor,Warehouse">
<div class="nav-item px-3">
<NavLink class="nav-link ps-2" href="/info">
<i class="bi-question pe-2" style="font-size:1.3em;" aria-hidden="true"></i> Hjælp
<i class="bi-life-preserver pe-2" style="font-size:1.3em;" aria-hidden="true"></i> Hjælp
</NavLink>
</div>
<div class="nav-item px-3">

View file

@ -1,15 +1,15 @@
{
"appInfo": {
"name": "Wonky Online",
"version": "161.0",
"version": "162.0",
"rc": true,
"sandBox": false,
"image": "grumpy-coder.png"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"System": "Information",
"Default": "None",
"System": "None",
"Microsoft": "Information"
},
"Debug": {