CompanyInventoryList sorting and tagging
This commit is contained in:
parent
8cd924e817
commit
1afbf20b15
56 changed files with 643 additions and 1028 deletions
|
@ -23,37 +23,74 @@
|
|||
<div class="list-group mt-2">
|
||||
<div class="list-group-item d-print-none">
|
||||
<div class="row">
|
||||
<div class="col-sm-4 action-link-element" @onclick="@(() => SortProducts(ProductSort.Desc))"><i class="bi-sort-alpha-down"></i> Navn <i class="bi-sort-alpha-up-alt"></i></div>
|
||||
<div class="col-sm-3 action-link-element" @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-2 text-center action-link-element" @onclick="@(() => SortProducts(ProductSort.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 class="col-sm-4 action-link-element" 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 action-link-element" 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(ProductSort.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(ProductSort.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(ProductSort.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)
|
||||
@foreach (var product in FilteredList)
|
||||
{
|
||||
<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>
|
||||
<span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger">
|
||||
Udgået
|
||||
<span class="visually-hidden">Produktet er udgået</span>
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<div class="col-sm-2 text-sm-start">
|
||||
@product.Sku
|
||||
</div>
|
||||
<div class="col-sm-2 text-center">
|
||||
<div class="col-sm-1 text-center">
|
||||
@product.Quantity
|
||||
</div>
|
||||
<div class="col-sm-2 d-print-none">
|
||||
<button type="button" class="btn btn-info d-block" @onclick="@(() => CallShowReorderModal(product.Sku))"><i class="bi-cart"></i> Genbestil</button>
|
||||
<button type="button" class="btn btn-info d-block" @onclick="@(() => CallShowReorderModal(product.Sku))"><i class="bi-cart"></i> Genbestil</button>
|
||||
</div>
|
||||
<div class="col-sm-1 d-print-none" @onclick="@(() => ProductCheck(product.Sku))">
|
||||
<div class="col-sm-1 d-print-none" @onclick="@(() => SetProductCheckmark(product.Sku))">
|
||||
<input type="checkbox" class="btn-check" id="btn-@product.Sku.Replace(",", "")" autocomplete="off"/>
|
||||
@if (product.Check)
|
||||
{
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
using Blazored.LocalStorage;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Wonky.Client.Enums;
|
||||
using Wonky.Client.Helpers;
|
||||
using Wonky.Client.Models;
|
||||
using Wonky.Entity.Views;
|
||||
|
||||
|
@ -24,71 +25,68 @@ namespace Wonky.Client.Components;
|
|||
|
||||
public partial class CustomerInventoryListComponent
|
||||
{
|
||||
// ##############################################3333############
|
||||
[Inject] public ILocalStorageService Storage { get; set; }
|
||||
// Parameters
|
||||
[Inject] public ILogger<CustomerInventoryListComponent> Logger { get; set; }
|
||||
|
||||
// ##############################################3333############
|
||||
[Parameter] public List<ProductInventoryItemView> Inventory { get; set; } = new();
|
||||
[Parameter] public string CompanyId { get; set; } = "";
|
||||
[Parameter] public EventCallback<string> OnReorderSelected { get; set; }
|
||||
|
||||
// ##############################################3333############
|
||||
// private variables
|
||||
private bool Descending { get; set; }
|
||||
|
||||
protected override void OnParametersSet()
|
||||
private bool Descending { get; set; } = true;
|
||||
private string SearchTerm { get; set; } = "";
|
||||
private List<ProductInventoryItemView> FilteredList { get; set; }
|
||||
private ProductSort SortColumn { get; set; } = ProductSort.LastInvoiceDate;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
if(Inventory.Any())
|
||||
Inventory = Inventory.OrderBy(x => x.Description).ToList();
|
||||
// sort base list
|
||||
Inventory = Utils.SortInventory(Inventory, SortColumn, Descending);
|
||||
// initialize FilteredList
|
||||
FilterItems(SearchTerm);
|
||||
}
|
||||
|
||||
|
||||
private void SetSortOrder()
|
||||
{
|
||||
Descending = !Descending;
|
||||
FilteredList = Utils.SortInventory(FilteredList, SortColumn, Descending);
|
||||
}
|
||||
|
||||
|
||||
private void OnSearchChanged(string searchTerm)
|
||||
{
|
||||
// use search input to filter list
|
||||
FilterItems(searchTerm);
|
||||
}
|
||||
|
||||
|
||||
private void FilterItems(string filter)
|
||||
{
|
||||
SearchTerm = filter;
|
||||
FilteredList = string.IsNullOrWhiteSpace(filter)
|
||||
? Inventory
|
||||
: Inventory.Where(i => i.Description.ToLower().Contains(filter.ToLower())).ToList();
|
||||
}
|
||||
|
||||
|
||||
private void SortProducts(ProductSort column)
|
||||
{
|
||||
Descending = !Descending;
|
||||
switch (column)
|
||||
{
|
||||
case ProductSort.Desc:
|
||||
if (Descending)
|
||||
{
|
||||
Inventory = Inventory.OrderByDescending(x => x.Description).ToList();
|
||||
break;
|
||||
}
|
||||
Inventory = Inventory.OrderBy(x => x.Description).ToList();
|
||||
break;
|
||||
case ProductSort.Sku:
|
||||
if (Descending)
|
||||
{
|
||||
Inventory = Inventory.OrderByDescending(x => x.Sku).ToList();
|
||||
break;
|
||||
}
|
||||
Inventory = Inventory.OrderBy(x => x.Sku).ToList();
|
||||
break;
|
||||
case ProductSort.Qty:
|
||||
if (Descending)
|
||||
{
|
||||
Inventory = Inventory.OrderByDescending(x => x.Quantity).ToList();
|
||||
break;
|
||||
}
|
||||
Inventory = Inventory.OrderBy(x => x.Quantity).ToList();
|
||||
break;
|
||||
case ProductSort.None:
|
||||
Inventory = Inventory.OrderBy(x => x.Description).ToList();
|
||||
break;
|
||||
case ProductSort.Abbr:
|
||||
break;
|
||||
default:
|
||||
Inventory = Inventory.OrderBy(x => x.Description).ToList();
|
||||
break;
|
||||
}
|
||||
FilteredList = Utils.SortInventory(FilteredList, column, Descending);
|
||||
}
|
||||
|
||||
|
||||
private async Task CallShowReorderModal(string sku)
|
||||
{
|
||||
await ProductCheck(sku);
|
||||
await SetProductCheckmark(sku);
|
||||
await OnReorderSelected.InvokeAsync(sku);
|
||||
}
|
||||
|
||||
|
||||
private async Task ProductCheck(string sku)
|
||||
private async Task SetProductCheckmark(string sku)
|
||||
{
|
||||
var x = Inventory.First(x => x.Sku == sku);
|
||||
x.Check = !x.Check;
|
||||
|
|
|
@ -22,24 +22,50 @@
|
|||
<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.Desc))"><i class="bi-sort-alpha-down"></i> Navn <i class="bi-sort-alpha-up-alt"></i></div>
|
||||
@*
|
||||
<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-2 text-center" style="cursor: pointer;" @onclick="@(() => SortProducts(ProductSort.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 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") "></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(ProductSort.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(ProductSort.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(ProductSort.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-2">
|
||||
@product.LastInvoiceDate
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
@product.Description
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<div class="col-sm-2">
|
||||
@product.Sku
|
||||
</div>
|
||||
<div class="col-sm-2 text-center">
|
||||
<div class="col-sm-1 text-center">
|
||||
@product.Quantity
|
||||
</div>
|
||||
<div class="col-sm-2">
|
||||
|
|
|
@ -13,9 +13,11 @@
|
|||
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
|
||||
//
|
||||
|
||||
using System.Security.Policy;
|
||||
using Blazored.LocalStorage;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Wonky.Client.Enums;
|
||||
using Wonky.Client.Helpers;
|
||||
using Wonky.Client.Models;
|
||||
using Wonky.Entity.Views;
|
||||
#pragma warning disable CS8618
|
||||
|
@ -27,57 +29,48 @@ public partial class CustomerProductCheckListComponent
|
|||
[Parameter] public string CompanyId { get; set; } = "";
|
||||
[Inject] public ILocalStorageService Storage { get; set; }
|
||||
// private variables
|
||||
private bool Descending { get; set; }
|
||||
|
||||
private bool Descending { get; set; } = true;
|
||||
private string SearchTerm { get; set; } = "";
|
||||
private List<ProductInventoryItemView> FilteredList { get; set; } = new();
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
if(Inventory.Any())
|
||||
Inventory = Inventory.OrderBy(x => x.Description).ToList();
|
||||
Inventory = Utils.SortInventory(Inventory, ProductSort.LastInvoiceDate, Descending);
|
||||
FilterItems(SearchTerm);
|
||||
}
|
||||
|
||||
|
||||
private void SetSortOrder()
|
||||
{
|
||||
Descending = !Descending;
|
||||
FilteredList = Utils.SortInventory(FilteredList, ProductSort.LastInvoiceDate, Descending);
|
||||
}
|
||||
|
||||
|
||||
private void OnSearchChanged(string searchTerm)
|
||||
{
|
||||
FilterItems(searchTerm);
|
||||
}
|
||||
|
||||
|
||||
private void FilterItems(string filter)
|
||||
{
|
||||
SearchTerm = filter;
|
||||
FilteredList = string.IsNullOrWhiteSpace(filter)
|
||||
? Inventory
|
||||
: Inventory.Where(i => i.Description.ToLower().Contains(filter.ToLower())).ToList();
|
||||
}
|
||||
|
||||
|
||||
private void SortProducts(ProductSort column)
|
||||
{
|
||||
Descending = !Descending;
|
||||
switch (column)
|
||||
{
|
||||
case ProductSort.Desc:
|
||||
if (Descending)
|
||||
{
|
||||
Inventory = Inventory.OrderByDescending(x => x.Description).ToList();
|
||||
break;
|
||||
}
|
||||
Inventory = Inventory.OrderBy(x => x.Description).ToList();
|
||||
break;
|
||||
case ProductSort.Sku:
|
||||
if (Descending)
|
||||
{
|
||||
Inventory = Inventory.OrderByDescending(x => x.Sku).ToList();
|
||||
break;
|
||||
}
|
||||
Inventory = Inventory.OrderBy(x => x.Sku).ToList();
|
||||
break;
|
||||
case ProductSort.Qty:
|
||||
if (Descending)
|
||||
{
|
||||
Inventory = Inventory.OrderByDescending(x => x.Quantity).ToList();
|
||||
break;
|
||||
}
|
||||
Inventory = Inventory.OrderBy(x => x.Quantity).ToList();
|
||||
break;
|
||||
case ProductSort.None:
|
||||
break;
|
||||
case ProductSort.Abbr:
|
||||
break;
|
||||
default:
|
||||
Inventory = Inventory.OrderByDescending(x => x.Quantity).ToList();
|
||||
break;
|
||||
}
|
||||
FilteredList = Utils.SortInventory(Inventory, column, Descending);
|
||||
}
|
||||
|
||||
private async Task ProductCheck(string sku)
|
||||
|
||||
private void ProductCheck(string sku)
|
||||
{
|
||||
var x = Inventory.First(x => x.Sku == sku);
|
||||
x.Check = !x.Check;
|
||||
await Storage.SetItemAsync($"{CompanyId}-products", Inventory);
|
||||
}
|
||||
}
|
|
@ -1,60 +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
|
||||
|
||||
<h3>Pakning / Forsendelse</h3>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Symbol</th>
|
||||
<th>Betydning</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="align-middle">
|
||||
<div class="color-code">
|
||||
<DisplayStateComponent StateClass="the-good"/>
|
||||
</div>
|
||||
</td>
|
||||
<td class="align-middle">Ubehandlet</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="align-middle">
|
||||
<div class="color-code">
|
||||
<DisplayStateComponent StateClass="the-bad"/>
|
||||
</div>
|
||||
</td>
|
||||
<td class="align-middle">Varer er plukket</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="align-middle">
|
||||
<div class="color-code">
|
||||
<DisplayStateComponent StateClass="the-ugly"/>
|
||||
</div>
|
||||
</td>
|
||||
<td class="align-middle">Varer er pakket</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="align-middle">
|
||||
<div class="color-code">
|
||||
<DisplayStateComponent StateClass="the-dead"/>
|
||||
</div>
|
||||
</td>
|
||||
<td class="align-middle">Varer er afsendt</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
|
@ -36,6 +36,7 @@
|
|||
<td><i class="bi-printer" style="font-size:1.3rem"></i></td>
|
||||
<td>Udskrevet</td>
|
||||
</tr>
|
||||
@*
|
||||
<tr>
|
||||
<td><i class="bi-file-earmark-check" style="font-size:1.3rem"></i></td>
|
||||
<td>Plukket</td>
|
||||
|
@ -48,5 +49,6 @@
|
|||
<td><i class="bi-truck" style="font-size:1.3rem"></i></td>
|
||||
<td>Leveret</td>
|
||||
</tr>
|
||||
*@
|
||||
</thead>
|
||||
</table>
|
||||
|
|
|
@ -70,7 +70,7 @@
|
|||
</div>
|
||||
<OfficeCustomerInvoiceListOverlay Company="@SelectedCompany" InvoiceList="@InvoiceList" @ref="InvoiceListOverlay" />
|
||||
<OfficeCustomerActivityListOverlay Company="SelectedCompany" ActivityList="ActivityList" @ref="ActivityListOverlay" />
|
||||
<OfficeCustomerProductListOverlay Company="SelectedCompany" Inventory="ProductList" @ref="ProductListOverlay" />
|
||||
<OfficeCustomerInventoryListOverlay Company="SelectedCompany" Inventory="ProductList" @ref="InventoryListOverlay" />
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -48,7 +48,7 @@ public partial class OfficeCountryCustomerListComponent
|
|||
// overlays
|
||||
private OfficeCustomerInvoiceListOverlay InvoiceListOverlay { get; set; } = new();
|
||||
private OfficeCustomerActivityListOverlay ActivityListOverlay { get; set; } = new();
|
||||
private OfficeCustomerProductListOverlay ProductListOverlay { get; set; } = new();
|
||||
private OfficeCustomerInventoryListOverlay InventoryListOverlay { get; set; } = new();
|
||||
|
||||
// ******************************************************
|
||||
// variables
|
||||
|
@ -108,7 +108,7 @@ public partial class OfficeCountryCustomerListComponent
|
|||
SelectedCompany.HistorySync = newSyncDate;
|
||||
}
|
||||
ProductList = await HistoryRepo.GetInventory(SelectedCompany.CountryCode, SelectedCompany.CompanyId);
|
||||
ProductListOverlay.Show();
|
||||
InventoryListOverlay.Show();
|
||||
}
|
||||
|
||||
private void ShowOrder(string companyId)
|
||||
|
|
|
@ -24,11 +24,32 @@
|
|||
<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.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(ProductSort.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(ProductSort.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 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") "></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(ProductSort.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(ProductSort.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(ProductSort.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)
|
|
@ -15,72 +15,70 @@
|
|||
|
||||
using Blazored.LocalStorage;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.VisualBasic.CompilerServices;
|
||||
using Wonky.Client.Enums;
|
||||
using Wonky.Client.Models;
|
||||
using Wonky.Entity.Views;
|
||||
using Utils = Wonky.Client.Helpers.Utils;
|
||||
|
||||
namespace Wonky.Client.Components;
|
||||
#pragma warning disable CS8618
|
||||
|
||||
public partial class OfficeInventoryListComponent
|
||||
public partial class OfficeCustomerInventoryListComponent
|
||||
{
|
||||
// *************************************************************
|
||||
// Injections
|
||||
[Inject] public ILocalStorageService Storage { get; set; }
|
||||
|
||||
// *************************************************************
|
||||
// Parameters
|
||||
[Parameter] public List<ProductInventoryItemView> 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 bool Descending { get; set; } = true;
|
||||
private string SearchTerm { get; set; } = "";
|
||||
private List<ProductInventoryItemView> FilteredList { get; set; } = new();
|
||||
private ProductSort SortColumn { get; set; } = ProductSort.LastInvoiceDate;
|
||||
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
if(Inventory.Any())
|
||||
Inventory = Inventory.OrderBy(x => x.Description).ToList();
|
||||
Inventory = Utils.SortInventory(Inventory, SortColumn, Descending);
|
||||
FilterItems(SearchTerm);
|
||||
}
|
||||
|
||||
|
||||
private void SetSortOrder()
|
||||
{
|
||||
Descending = !Descending;
|
||||
FilteredList = Utils.SortInventory(FilteredList, SortColumn, Descending);
|
||||
}
|
||||
|
||||
|
||||
private void OnSearchChanged(string searchTerm)
|
||||
{
|
||||
FilterItems(searchTerm);
|
||||
}
|
||||
|
||||
|
||||
private void FilterItems(string filter)
|
||||
{
|
||||
SearchTerm = filter;
|
||||
FilteredList = string.IsNullOrWhiteSpace(filter)
|
||||
? Inventory
|
||||
: Inventory.Where(i => i.Description.ToLower().Contains(filter.ToLower())).ToList();
|
||||
}
|
||||
|
||||
|
||||
private void SortProducts(ProductSort column)
|
||||
{
|
||||
Descending = !Descending;
|
||||
switch (column)
|
||||
{
|
||||
case ProductSort.Desc:
|
||||
if (Descending)
|
||||
{
|
||||
Inventory = Inventory.OrderByDescending(x => x.Description).ToList();
|
||||
break;
|
||||
}
|
||||
Inventory = Inventory.OrderBy(x => x.Description).ToList();
|
||||
break;
|
||||
case ProductSort.Sku:
|
||||
if (Descending)
|
||||
{
|
||||
Inventory = Inventory.OrderByDescending(x => x.Sku).ToList();
|
||||
break;
|
||||
}
|
||||
Inventory = Inventory.OrderBy(x => x.Sku).ToList();
|
||||
break;
|
||||
case ProductSort.Qty:
|
||||
if (Descending)
|
||||
{
|
||||
Inventory = Inventory.OrderByDescending(x => x.Quantity).ToList();
|
||||
break;
|
||||
}
|
||||
Inventory = Inventory.OrderBy(x => x.Quantity).ToList();
|
||||
break;
|
||||
case ProductSort.None:
|
||||
break;
|
||||
case ProductSort.Abbr:
|
||||
break;
|
||||
default:
|
||||
Inventory = Inventory.OrderByDescending(x => x.Quantity).ToList();
|
||||
break;
|
||||
}
|
||||
FilteredList = Utils.SortInventory(FilteredList, column, Descending);
|
||||
}
|
||||
|
||||
|
||||
private async Task CallShowReorderModal(string sku)
|
||||
{
|
||||
// await ProductCheck(sku);
|
|
@ -13,20 +13,9 @@
|
|||
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
|
||||
*@
|
||||
|
||||
<h3>Lager</h3>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Symbol</th>
|
||||
<th>Betydning</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<i class="bi-box" style="font-size:1.3rem"></i>
|
||||
</td>
|
||||
<td>Pakning / Forsendelse</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="input-group">
|
||||
<input id="search-input" type="text" class="form-control" placeholder="Søg ..." aria-described-by="search-addon"
|
||||
@bind-value="SearchTerm" @bind-value:event="oninput" onkeyup="@OnSearchChanged" />
|
||||
<span class="input-group-text" id="search-addon"><i class="oi oi-delete" @onclick="@ClearSearch"></i></span>
|
||||
</div>
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
/* 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
|
||||
|
@ -11,10 +11,27 @@
|
|||
//
|
||||
// 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]
|
||||
*/
|
||||
.pictogram {
|
||||
max-width: 30px;
|
||||
}
|
||||
.color-code {
|
||||
max-width: 30px;
|
||||
//
|
||||
|
||||
using System.Timers;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Timer = System.Timers.Timer;
|
||||
|
||||
namespace Wonky.Client.Components;
|
||||
|
||||
public partial class SearchPhraseComponent
|
||||
{
|
||||
private string SearchTerm { get; set; } = "";
|
||||
[Parameter] public EventCallback<string> OnChanged { get; set; }
|
||||
|
||||
private void ClearSearch()
|
||||
{
|
||||
SearchTerm = "";
|
||||
OnChanged.InvokeAsync("");
|
||||
}
|
||||
|
||||
private void OnSearchChanged()
|
||||
{
|
||||
OnChanged.InvokeAsync(SearchTerm);
|
||||
}
|
||||
}
|
|
@ -1,102 +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
|
||||
|
||||
@if (OrderList != null)
|
||||
{
|
||||
<div class="row mb-3">
|
||||
<div class="col-sm-4">
|
||||
<div class="btn-group" role="group" aria-label="Ordre status">
|
||||
<input type="radio" class="btn-check" name="btn-order" id="btn-order1" @onchange="() => GetWithStatus(ProcessStatus.None)" autocomplete="off" checked="checked"/>
|
||||
<label class="btn btn-success" for="btn-order1">Ubehandlet</label>
|
||||
|
||||
<input type="radio" class="btn-check" name="btn-order" id="btn-order2" @onchange="() => GetWithStatus(ProcessStatus.Picked)" autocomplete="off"/>
|
||||
<label class="btn btn-warning" for="btn-order2">Plukket</label>
|
||||
|
||||
<input type="radio" class="btn-check" name="btn-order" id="btn-order3" @onchange="() => GetWithStatus(ProcessStatus.Packed)" autocomplete="off"/>
|
||||
<label class="btn btn-danger" for="btn-order3">Pakket</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4 text-end">
|
||||
<label class="btn btn-outline-dark position-relative">
|
||||
@Header
|
||||
<span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-info">@Orders.Count</span>
|
||||
<span class="visually-hidden">ordrer i listen</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-sm-4 text-end">
|
||||
@if (ReadyToShip && Orders.Any())
|
||||
{
|
||||
<button type="button" class="btn btn-primary text-sm-center" @onclick="@SetShipStatus">Sæt alle afsendt</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-group list-group-flush">
|
||||
<div class="list-group-item">
|
||||
<div class="row">
|
||||
<div class="col-sm-4">
|
||||
<h4>Modtager</h4>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<h5>Post By</h5>
|
||||
</div>
|
||||
<div class="col-sm-2">
|
||||
<h5>Dato</h5>
|
||||
</div>
|
||||
<div class="col-sm-3 text-end">
|
||||
<h5><i class="bi-lightning-fill"></i> Status</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@foreach (var order in Orders)
|
||||
{
|
||||
<div class="list-group-item list-group-item-action" style="cursor: hand;">
|
||||
<div class="row">
|
||||
<div class="col-sm-4">
|
||||
@order.Company.Name
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
@order.Company.ZipCode @order.Company.City
|
||||
</div>
|
||||
<div class="col-sm-2">
|
||||
@order.OrderDate
|
||||
</div>
|
||||
<div class="col-sm-3 d-flex">
|
||||
@if (order.Express)
|
||||
{
|
||||
<i class="bi-lightning-fill text-warning"></i>
|
||||
}
|
||||
@switch (order.ProcessStatusEnum.ToLower())
|
||||
{
|
||||
case "none":
|
||||
<button class="btn btn-outline-danger me-4" @onclick="@(() => QuickPak(order.OrderId))">QuickPak</button>
|
||||
<a class="btn btn-warning" href="warehouse/orders/process/@order.OrderId">Pluk varer</a>
|
||||
break;
|
||||
case "picked":
|
||||
<a class="btn btn-warning" href="warehouse/orders/process/@order.OrderId">Pak varer</a>
|
||||
break;
|
||||
case "packed":
|
||||
<a class="btn btn-warning" href="warehouse/orders/process/@order.OrderId">Afhent varer</a>
|
||||
break;
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
|
@ -1,56 +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.Enums;
|
||||
using Wonky.Client.Models;
|
||||
using Wonky.Entity.Views;
|
||||
|
||||
namespace Wonky.Client.Components;
|
||||
|
||||
public partial class WarehouseListComponent
|
||||
{
|
||||
[Parameter] public string Header { get; set; } = "";
|
||||
[Parameter] public List<WarehouseOrderView> OrderList { get; set; } = new();
|
||||
[Parameter] public bool ReadyToShip { get; set; }
|
||||
[Parameter] public EventCallback<ProcessStatus> OnGetStatus { get; set; }
|
||||
[Parameter] public EventCallback OnSetShipped { get; set; }
|
||||
[Parameter] public EventCallback<string> OnQPak { get; set; }
|
||||
|
||||
private List<WarehouseOrderView> Orders { get; set; } = new();
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
while (OrderList == null)
|
||||
await Task.Delay(500);
|
||||
|
||||
Orders = OrderList;
|
||||
}
|
||||
|
||||
private async Task SetShipStatus()
|
||||
{
|
||||
await OnSetShipped.InvokeAsync();
|
||||
}
|
||||
|
||||
private async Task GetWithStatus(ProcessStatus status)
|
||||
{
|
||||
await OnGetStatus.InvokeAsync(status);
|
||||
}
|
||||
|
||||
private async Task QuickPak(string orderId)
|
||||
{
|
||||
await OnQPak.InvokeAsync(orderId);
|
||||
}
|
||||
}
|
|
@ -18,9 +18,7 @@ namespace Wonky.Client.Enums;
|
|||
|
||||
public enum ProductSort
|
||||
{
|
||||
None,
|
||||
Desc,
|
||||
Description,
|
||||
Sku,
|
||||
Qty,
|
||||
Abbr
|
||||
LastInvoiceDate
|
||||
}
|
|
@ -27,11 +27,37 @@ namespace Wonky.Client.Helpers;
|
|||
/// </summary>
|
||||
public static class Utils
|
||||
{
|
||||
public static List<ProductInventoryItemView> SortInventory(IEnumerable<ProductInventoryItemView> inventory,
|
||||
ProductSort column, bool descending)
|
||||
{
|
||||
return column switch
|
||||
{
|
||||
ProductSort.Description => descending
|
||||
? inventory.OrderByDescending(x => x.Description).ToList()
|
||||
: inventory.OrderBy(x => x.Description).ToList(),
|
||||
ProductSort.Sku => descending
|
||||
? inventory.OrderByDescending(x => x.Sku).ToList()
|
||||
: inventory.OrderBy(x => x.Sku).ToList(),
|
||||
ProductSort.LastInvoiceDate => descending
|
||||
? inventory.OrderByDescending(x => x.LastInvoiceDate).ToList()
|
||||
: inventory.OrderBy(x => x.LastInvoiceDate).ToList(),
|
||||
_ => inventory.OrderByDescending(x => x.LastInvoiceDate).ToList()
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public static List<ProductVariant> GenerateVariantListDto(IEnumerable<DocView> items)
|
||||
{
|
||||
return items.Select(item => new ProductVariant { VariantId = item.VariantId, S5A = item.S5A, S9A = item.S9A }).ToList();
|
||||
return items.Select(item => new ProductVariant
|
||||
{
|
||||
VariantId = item.VariantId,
|
||||
S5A = item.S5A,
|
||||
S9A = item.S9A
|
||||
})
|
||||
.ToList();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static List<DocView> GenerateRevListView(IEnumerable<WorkplaceProduct> products)
|
||||
{
|
||||
var result = new List<DocView>();
|
||||
|
@ -64,17 +90,19 @@ public static class Utils
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
result.Add(newDoc);
|
||||
}
|
||||
}
|
||||
|
||||
return result.OrderBy(x => x.VariantName).ToList();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public static List<DocView> GenerateDocListView(IEnumerable<WorkplaceProduct> products)
|
||||
{
|
||||
var result = new List<DocView>();
|
||||
|
||||
|
||||
var docProducts = products.OrderBy(x => x.TradingName).ToList();
|
||||
|
||||
foreach (var product in docProducts)
|
||||
|
@ -104,45 +132,47 @@ public static class Utils
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
result.Add(newDoc);
|
||||
}
|
||||
}
|
||||
|
||||
return result.OrderBy(x => x.VariantName).ToList();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public static List<EmailContact> ParseRecipientsFromString(string recipients)
|
||||
{
|
||||
var addresses = recipients
|
||||
.Replace(" ", ",")
|
||||
.Replace(",,",",")
|
||||
.Replace(",,", ",")
|
||||
.Split(",");
|
||||
|
||||
return (from address
|
||||
in addresses
|
||||
where IsValidEmail(address)
|
||||
return (from address
|
||||
in addresses
|
||||
where IsValidEmail(address)
|
||||
select new EmailContact
|
||||
{
|
||||
Name = address, Email = address
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static List<UserRoleAssignment> MapSaveAssignedRoles(RoleAssignment model)
|
||||
{
|
||||
return new List<UserRoleAssignment>()
|
||||
{
|
||||
new (){ Name = "Admin", Assigned = model.Admin},
|
||||
new (){ Name = "Advisor", Assigned = model.Advisor},
|
||||
new (){ Name = "EDoc", Assigned = model.EDoc},
|
||||
new (){ Name = "EShop", Assigned = model.EShop},
|
||||
new (){ Name = "Management", Assigned = model.Management},
|
||||
new (){ Name = "Office", Assigned = model.Office},
|
||||
new (){ Name = "Supervisor", Assigned = model.Supervisor},
|
||||
new (){ Name = "Warehouse", Assigned = model.Warehouse}
|
||||
new() { Name = "Admin", Assigned = model.Admin },
|
||||
new() { Name = "Advisor", Assigned = model.Advisor },
|
||||
new() { Name = "EDoc", Assigned = model.EDoc },
|
||||
new() { Name = "EShop", Assigned = model.EShop },
|
||||
new() { Name = "Management", Assigned = model.Management },
|
||||
new() { Name = "Office", Assigned = model.Office },
|
||||
new() { Name = "Supervisor", Assigned = model.Supervisor },
|
||||
new() { Name = "Warehouse", Assigned = model.Warehouse }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static RoleAssignment MapEditAssignedRoles(UserManagerEditView model)
|
||||
{
|
||||
|
@ -177,9 +207,10 @@ public static class Utils
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static string StringToDigits(string digitString)
|
||||
{
|
||||
|
@ -195,7 +226,7 @@ public static class Utils
|
|||
return check.All(c => c is >= '0' and <= '9');
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static bool Validate(ValidateType validateType, string toValidate)
|
||||
{
|
||||
return validateType switch
|
||||
|
@ -231,7 +262,7 @@ public static class Utils
|
|||
{
|
||||
validConditions++;
|
||||
}
|
||||
|
||||
|
||||
return validConditions == 3;
|
||||
}
|
||||
|
||||
|
|
|
@ -69,7 +69,8 @@ public class HttpInterceptorService
|
|||
var absolutePath = e.Request.RequestUri.AbsolutePath;
|
||||
if (!absolutePath.Contains("token"))
|
||||
{
|
||||
// call TryRefreshToken
|
||||
// we are using the tryRefreshToken
|
||||
// the service returns the current access token or a new token using refreshToken
|
||||
var token = await _refreshTokenService.TryRefreshToken();
|
||||
if (!string.IsNullOrEmpty(token))
|
||||
{
|
||||
|
|
|
@ -34,6 +34,7 @@ public class CrmCustomerHistoryRepository : ICrmCustomerHistoryRepository
|
|||
private readonly HttpClient _client;
|
||||
private readonly ApiConfig _api;
|
||||
|
||||
|
||||
public CrmCustomerHistoryRepository(
|
||||
HttpClient client, ILogger<CrmCustomerHistoryRepository> logger,
|
||||
NavigationManager navigation, IOptions<ApiConfig> configuration)
|
||||
|
@ -44,92 +45,80 @@ public class CrmCustomerHistoryRepository : ICrmCustomerHistoryRepository
|
|||
_api = configuration.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetch Invoice LIst
|
||||
/// </summary>
|
||||
/// <param name="companyId"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
public async Task<InvoiceListView> FetchInvoiceList(string companyId)
|
||||
{
|
||||
var response = await _client.GetAsync($"{_api.CrmCustomers}/{companyId}/invoices");
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
return response.IsSuccessStatusCode
|
||||
? JsonSerializer.Deserialize<InvoiceListView>(content, _options)
|
||||
: new InvoiceListView();
|
||||
if (!response.IsSuccessStatusCode || string.IsNullOrWhiteSpace(content))
|
||||
{
|
||||
return new InvoiceListView();
|
||||
}
|
||||
return JsonSerializer.Deserialize<InvoiceListView>(content, _options) ?? new InvoiceListView();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetch given invoice for given customer
|
||||
/// </summary>
|
||||
/// <param name="companyId"></param>
|
||||
/// <param name="invoiceId"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
public async Task<InvoiceView> FetchInvoice(string companyId, string invoiceId)
|
||||
{
|
||||
return await _client
|
||||
var content = await _client
|
||||
.GetFromJsonAsync<InvoiceView>($"{_api.CrmCustomers}/{companyId}/invoices/{invoiceId}", _options);
|
||||
return content ?? new InvoiceView();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetch inventory from given customer
|
||||
/// </summary>
|
||||
/// <param name="companyId"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
public async Task<List<ProductInventoryItemView>> FetchInventory(string companyId)
|
||||
{
|
||||
var response = await _client.GetAsync($"{_api.CrmCustomers}/{companyId}/{_api.CrmInventoryExt}");
|
||||
if (!response.IsSuccessStatusCode)
|
||||
return new List<ProductInventoryItemView>();
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
return string.IsNullOrWhiteSpace(content)
|
||||
? new List<ProductInventoryItemView>()
|
||||
: JsonSerializer.Deserialize<List<ProductInventoryItemView>>(content, _options);
|
||||
if (!response.IsSuccessStatusCode || string.IsNullOrWhiteSpace(content))
|
||||
return new List<ProductInventoryItemView>();
|
||||
return JsonSerializer.Deserialize<List<ProductInventoryItemView>>(content, _options) ?? new List<ProductInventoryItemView>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetch History for given customer
|
||||
/// </summary>
|
||||
/// <param name="companyId"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<List<ProductHistoryView>> FetchHistory(string companyId)
|
||||
|
||||
public async Task<List<ProductHistoryView>> GetProductInvoiceLines(string companyId)
|
||||
{
|
||||
var response = await _client.GetAsync($"{_api.CrmCustomers}/{companyId}/{_api.CrmProductExt}");
|
||||
if (!response.IsSuccessStatusCode)
|
||||
return new List<ProductHistoryView>();
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
return string.IsNullOrWhiteSpace(content)
|
||||
? new List<ProductHistoryView>()
|
||||
: JsonSerializer.Deserialize<List<ProductHistoryView>>(content, _options);
|
||||
if (!response.IsSuccessStatusCode || string.IsNullOrWhiteSpace(content))
|
||||
{
|
||||
return new List<ProductHistoryView>();
|
||||
}
|
||||
return JsonSerializer.Deserialize<List<ProductHistoryView>>(content, _options) ?? new List<ProductHistoryView>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetch history for given customer and a given product
|
||||
/// </summary>
|
||||
/// <param name="companyId"></param>
|
||||
/// <param name="sku"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<List<ProductHistoryView>> FetchHistory(string companyId, string sku)
|
||||
|
||||
public async Task<List<ProductHistoryView>> GetProductInvoiceLines(string companyId, int months)
|
||||
{
|
||||
var response = await _client.GetAsync($"{_api.CrmCustomers}/{companyId}/{_api.CrmProductExt}/statistic?months={months}");
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
if (!response.IsSuccessStatusCode || string.IsNullOrWhiteSpace(content))
|
||||
{
|
||||
return new List<ProductHistoryView>();
|
||||
}
|
||||
return JsonSerializer.Deserialize<List<ProductHistoryView>>(content, _options) ?? new List<ProductHistoryView>();
|
||||
}
|
||||
|
||||
|
||||
public async Task<List<ProductHistoryView>> GetProductInvoiceLines(string companyId, string sku)
|
||||
{
|
||||
var response = await _client.GetAsync($"{_api.CrmCustomers}/{companyId}/{_api.CrmProductExt}/{sku}");
|
||||
if (!response.IsSuccessStatusCode)
|
||||
return new List<ProductHistoryView>();
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
return string.IsNullOrWhiteSpace(content)
|
||||
? new List<ProductHistoryView>()
|
||||
: JsonSerializer.Deserialize<List<ProductHistoryView>>(content, _options);
|
||||
if (!response.IsSuccessStatusCode || string.IsNullOrWhiteSpace(content))
|
||||
{
|
||||
return new List<ProductHistoryView>();
|
||||
}
|
||||
return JsonSerializer.Deserialize<List<ProductHistoryView>>(content, _options) ?? new List<ProductHistoryView>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RPC call to initiate remote server sync for given customer
|
||||
/// </summary>
|
||||
/// <param name="companyId"></param>
|
||||
/// <param name="syncDate"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
public async Task<string> InvoiceErpToCrmRpc(string companyId, string syncDate)
|
||||
{
|
||||
var x = await _client.GetAsync($"{_api.SyncRpc}/companies/{companyId}/invoices/{syncDate}");
|
||||
if (!x.IsSuccessStatusCode)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
return await x.Content.ReadAsStringAsync();
|
||||
}
|
||||
}
|
|
@ -49,15 +49,23 @@ public interface ICrmCustomerHistoryRepository
|
|||
/// </summary>
|
||||
/// <param name="companyId"></param>
|
||||
/// <returns></returns>
|
||||
Task<List<ProductHistoryView>> FetchHistory(string companyId);
|
||||
Task<List<ProductHistoryView>> GetProductInvoiceLines(string companyId);
|
||||
|
||||
/// <summary>
|
||||
/// Fetch history for customer for the past months. A hard limit on 24 months is enforced by the backed
|
||||
/// </summary>
|
||||
/// <param name="companyId"></param>
|
||||
/// <param name="months"></param>
|
||||
/// <returns></returns>
|
||||
Task<List<ProductHistoryView>> GetProductInvoiceLines(string companyId, int months);
|
||||
|
||||
/// <summary>
|
||||
/// Fetch history for given customer and a given product
|
||||
/// </summary>
|
||||
/// <param name="companyId"></param>
|
||||
/// <param name="sku"></param>
|
||||
/// <returns></returns>
|
||||
Task<List<ProductHistoryView>> FetchHistory(string companyId, string sku);
|
||||
Task<List<ProductHistoryView>> GetProductInvoiceLines(string companyId, string sku);
|
||||
|
||||
/// <summary>
|
||||
/// RPC call to initiate remote server sync for given customer
|
||||
|
|
|
@ -150,11 +150,22 @@ public class AuthenticationService : IAuthenticationService
|
|||
((AuthStateProvider)_authStateProvider).NotifyUserLogout();
|
||||
}
|
||||
|
||||
|
||||
public async Task<string> AccessToken()
|
||||
{
|
||||
return await _infoService.GetAccessToken();
|
||||
}
|
||||
|
||||
|
||||
public async Task<UserManagerEditView> UserInfo(bool write = false)
|
||||
{
|
||||
// use http to fetch userInfo for authenticated user
|
||||
var response = await _client.GetAsync(_apiConfig.Value.UserInfoAuth).ConfigureAwait(true);
|
||||
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
if (!response.IsSuccessStatusCode || string.IsNullOrWhiteSpace(content))
|
||||
{
|
||||
return new UserManagerEditView();
|
||||
}
|
||||
var userInfo = JsonSerializer.Deserialize<UserManagerEditView>(content, _options) ?? new UserManagerEditView();
|
||||
if (write)
|
||||
{
|
||||
|
|
|
@ -23,6 +23,7 @@ public interface IAuthenticationService
|
|||
{
|
||||
Task<AuthResponseView> Login(CredentialDto credentials);
|
||||
Task Logout();
|
||||
Task<string> AccessToken();
|
||||
Task<string> RefreshToken();
|
||||
Task<UserManagerEditView> UserInfo(bool write = false);
|
||||
}
|
|
@ -39,14 +39,13 @@ public class RefreshTokenService
|
|||
var user = authState.User;
|
||||
|
||||
var expClaim = user.FindFirst(c => c.Type.Contains("exp"))?.Value;
|
||||
|
||||
//var expTime = DateTimeOffset.FromUnixTimeSeconds(Convert.ToInt64(expClaim));
|
||||
|
||||
var expTime = DateTimeOffset.FromUnixTimeSeconds(Convert.ToInt64(expClaim));
|
||||
|
||||
var diff = expTime - DateTime.UtcNow;
|
||||
return diff.TotalMinutes <= 2
|
||||
? await _authService.RefreshToken() //.ConfigureAwait(true)
|
||||
: string.Empty;
|
||||
return diff.TotalMinutes <= 10
|
||||
? await _authService.RefreshToken()
|
||||
: await _authService.AccessToken();
|
||||
}
|
||||
|
||||
}
|
|
@ -47,7 +47,7 @@ public partial class CustomerInventoryReorderOverlay
|
|||
if (string.IsNullOrWhiteSpace(SalesItem.Sku))
|
||||
return;
|
||||
|
||||
History = await HistoryRepo.FetchHistory(CompanyId, SalesItem.Sku);
|
||||
History = await HistoryRepo.GetProductInvoiceLines(CompanyId, SalesItem.Sku);
|
||||
if (!History.Any())
|
||||
await Task.Delay(1000);
|
||||
SelectedItem.Item = SalesItem;
|
||||
|
|
|
@ -24,10 +24,15 @@ namespace Wonky.Client.OverlayCustomer;
|
|||
|
||||
public partial class CustomerInvoiceViewOverlay : IDisposable
|
||||
{
|
||||
[Parameter] public string CompanyId { get; set; } = "";
|
||||
[Parameter] public string InvoiceId { get; set; } = "";
|
||||
// ##############################################################
|
||||
[Inject] public HttpInterceptorService Interceptor { get; set; }
|
||||
[Inject] public ICrmCustomerHistoryRepository HistoryRepo { get; set; }
|
||||
|
||||
// ##############################################################
|
||||
[Parameter] public string CompanyId { get; set; } = "";
|
||||
[Parameter] public string InvoiceId { get; set; } = "";
|
||||
|
||||
// ##############################################################
|
||||
private string _modalDisplay = "";
|
||||
private bool _showBackdrop;
|
||||
private InvoiceView Invoice { get; set; } = new();
|
||||
|
|
|
@ -31,22 +31,13 @@ public partial class ProductSelectionOverlay
|
|||
private List<DocView> FilteredList { get; set; } = new();
|
||||
private string SearchTerm { get; set; } = "";
|
||||
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
FilterItems(SearchTerm);
|
||||
}
|
||||
|
||||
private void ClearSearch()
|
||||
{
|
||||
SearchTerm = "";
|
||||
FilterItems(SearchTerm);
|
||||
}
|
||||
|
||||
private void OnSearchChanged()
|
||||
{
|
||||
FilterItems(SearchTerm);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private async Task SelectItem(DocView item)
|
||||
{
|
||||
item.Added = !item.Added;
|
||||
|
@ -54,6 +45,19 @@ public partial class ProductSelectionOverlay
|
|||
}
|
||||
|
||||
|
||||
private void ClearSearch()
|
||||
{
|
||||
SearchTerm = "";
|
||||
FilterItems(SearchTerm);
|
||||
}
|
||||
|
||||
|
||||
private void OnSearchChanged()
|
||||
{
|
||||
FilterItems(SearchTerm);
|
||||
}
|
||||
|
||||
|
||||
private void FilterItems(string filter)
|
||||
{
|
||||
SearchTerm = filter;
|
||||
|
|
|
@ -22,9 +22,11 @@ namespace Wonky.Client.OverlayOffice;
|
|||
|
||||
public partial class OfficeCustomerActivityListOverlay
|
||||
{
|
||||
// ##############################################################
|
||||
[Parameter] public CompanyDto Company { get; set; } = new();
|
||||
[Parameter] public List<ReportItemView> ActivityList { get; set; } = new();
|
||||
|
||||
// ##############################################################
|
||||
private string _modalDisplay = "";
|
||||
private bool _showBackdrop;
|
||||
|
||||
|
|
|
@ -21,7 +21,10 @@ namespace Wonky.Client.OverlayOffice;
|
|||
|
||||
public partial class OfficeCustomerActivityViewOverlay
|
||||
{
|
||||
// ##############################################################
|
||||
[Parameter] public ReportItemView Activity { get; set; } = new();
|
||||
|
||||
// ##############################################################
|
||||
private string _modalDisplay = "";
|
||||
private bool _showBackdrop;
|
||||
|
||||
|
|
|
@ -30,11 +30,36 @@
|
|||
<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.Desc))"><i class="bi-sort-alpha-down"></i> Navn <i class="bi-sort-alpha-up-alt"></i></div>
|
||||
@*
|
||||
<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-2 text-center" style="cursor: pointer;" @onclick="@(() => SortProducts(ProductSort.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 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(ProductSort.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(ProductSort.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(ProductSort.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)
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Wonky.Client.Enums;
|
||||
using Wonky.Client.Helpers;
|
||||
using Wonky.Client.HttpInterceptors;
|
||||
using Wonky.Client.HttpRepository;
|
||||
using Wonky.Client.Models;
|
||||
|
@ -26,81 +27,75 @@ using Wonky.Entity.Views;
|
|||
|
||||
namespace Wonky.Client.OverlayOffice;
|
||||
|
||||
public partial class OfficeCustomerProductListOverlay : IDisposable
|
||||
public partial class OfficeCustomerInventoryListOverlay : IDisposable
|
||||
{
|
||||
// ##############################################################
|
||||
[Inject] public HttpInterceptorService Interceptor { get; set; }
|
||||
[Inject] public ICountryCatalogRepository CatalogRepo { get; set; }
|
||||
[Inject] public ILogger<OfficeCustomerProductListOverlay> Logger { get; set; }
|
||||
[Inject] public ILogger<OfficeCustomerInventoryListOverlay> Logger { get; set; }
|
||||
|
||||
// ##############################################################
|
||||
[Parameter] public CompanyDto Company { get; set; } = new();
|
||||
[Parameter] public List<ProductInventoryItemView> Inventory { get; set; } = new();
|
||||
|
||||
// ##############################################################
|
||||
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; }
|
||||
private bool Descending { get; set; } = true;
|
||||
private string SearchTerm { get; set; } = "";
|
||||
private List<ProductInventoryItemView> FilteredList { get; set; } = new();
|
||||
private ProductSort SortColumn { get; set; } = ProductSort.LastInvoiceDate;
|
||||
|
||||
|
||||
[Parameter] public CompanyDto Company { get; set; } = new();
|
||||
[Parameter] public List<ProductInventoryItemView> Inventory { get; set; } = new();
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
if(Inventory.Any())
|
||||
Inventory = Inventory.OrderBy(x => x.Description).ToList();
|
||||
}
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
Interceptor.RegisterEvent();
|
||||
Interceptor.RegisterBeforeSendEvent();
|
||||
Inventory = Utils.SortInventory(Inventory, SortColumn, Descending);
|
||||
FilterItems(SearchTerm);
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
|
||||
private void OnSearchChanged(string searchTerm)
|
||||
{
|
||||
FilterItems(searchTerm);
|
||||
}
|
||||
|
||||
|
||||
private void SortProducts(ProductSort column)
|
||||
{
|
||||
Descending = !Descending;
|
||||
FilteredList = Utils.SortInventory(FilteredList, column, Descending);
|
||||
}
|
||||
|
||||
|
||||
private void SetSortOrder()
|
||||
{
|
||||
Descending = !Descending;
|
||||
FilteredList = Utils.SortInventory(FilteredList, SortColumn, Descending);
|
||||
}
|
||||
|
||||
|
||||
private void FilterItems(string filter)
|
||||
{
|
||||
SearchTerm = filter;
|
||||
FilteredList = string.IsNullOrWhiteSpace(filter)
|
||||
? 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();
|
||||
}
|
||||
|
||||
private void SortProducts(ProductSort column)
|
||||
{
|
||||
Descending = !Descending;
|
||||
switch (column)
|
||||
{
|
||||
case ProductSort.Desc:
|
||||
if (Descending)
|
||||
{
|
||||
Inventory = Inventory.OrderByDescending(x => x.Description).ToList();
|
||||
break;
|
||||
}
|
||||
|
||||
Inventory = Inventory.OrderBy(x => x.Description).ToList();
|
||||
break;
|
||||
case ProductSort.Sku:
|
||||
if (Descending)
|
||||
{
|
||||
Inventory = Inventory.OrderByDescending(x => x.Sku).ToList();
|
||||
break;
|
||||
}
|
||||
|
||||
Inventory = Inventory.OrderBy(x => x.Sku).ToList();
|
||||
break;
|
||||
case ProductSort.Qty:
|
||||
if (Descending)
|
||||
{
|
||||
Inventory = Inventory.OrderByDescending(x => x.Quantity).ToList();
|
||||
break;
|
||||
}
|
||||
|
||||
Inventory = Inventory.OrderBy(x => x.Quantity).ToList();
|
||||
break;
|
||||
case ProductSort.None:
|
||||
break;
|
||||
case ProductSort.Abbr:
|
||||
break;
|
||||
default:
|
||||
Inventory = Inventory.OrderByDescending(x => x.Quantity).ToList();
|
||||
break;
|
||||
}
|
||||
}
|
||||
public void Show()
|
||||
{
|
||||
_modalDisplay = "block;";
|
||||
|
@ -108,6 +103,7 @@ public partial class OfficeCustomerProductListOverlay : IDisposable
|
|||
StateHasChanged();
|
||||
}
|
||||
|
||||
|
||||
private void Hide()
|
||||
{
|
||||
_modalDisplay = "none;";
|
||||
|
@ -115,9 +111,9 @@ public partial class OfficeCustomerProductListOverlay : IDisposable
|
|||
StateHasChanged();
|
||||
}
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Interceptor.DisposeEvent();
|
||||
}
|
||||
|
||||
}
|
|
@ -26,10 +26,15 @@ namespace Wonky.Client.OverlayOffice;
|
|||
|
||||
public partial class OfficeCustomerInventoryReorderOverlay
|
||||
{
|
||||
// ##############################################################
|
||||
[Parameter] public CompanyDto Company { get; set; }
|
||||
[Parameter] public SalesItemView SalesItem { get; set; } = new();
|
||||
[Inject] public ICountryCustomerHistoryRepository HistoryRepo { get; set; }
|
||||
|
||||
// ##############################################################
|
||||
[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; } = "";
|
||||
|
|
|
@ -24,12 +24,16 @@ namespace Wonky.Client.OverlayOffice;
|
|||
|
||||
public partial class OfficeCustomerInvoiceViewOverlay : IDisposable
|
||||
{
|
||||
// ##############################################################
|
||||
[Parameter] public string CompanyId { get; set; } = "";
|
||||
[Parameter] public string InvoiceId { get; set; } = "";
|
||||
[Parameter] public string CountryCode { get; set; } = "";
|
||||
|
||||
// ##############################################################
|
||||
[Inject] public HttpInterceptorService Interceptor { get; set; }
|
||||
[Inject] public ICountryCustomerHistoryRepository HistoryRepo { get; set; }
|
||||
|
||||
// ##############################################################
|
||||
private string _modalDisplay = "";
|
||||
private bool _showBackdrop;
|
||||
private InvoiceView Invoice { get; set; } = new();
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
<button type="button" class="btn-close" @onclick="@Hide" data-bs-dismiss="modal" aria-label="Luk"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<OfficeInventoryListComponent OnReorderSelected="OnReorderCallback" CompanyId="@Company.CompanyId" Inventory="@Inventory"/>
|
||||
<OfficeCustomerInventoryListComponent OnReorderSelected="OnReorderCallback" CompanyId="@Company.CompanyId" Inventory="@Inventory"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -33,4 +33,4 @@
|
|||
<div class="modal-backdrop fade show"></div>
|
||||
}
|
||||
|
||||
<OfficeOrderInventoryReorderOverlay Company="@Company" SalesItem="SalesItem" OnSelected="OnSelected" @ref="ReorderOverlay" />
|
||||
<OfficeCustomerOrderInventoryReorderOverlay Company="@Company" SalesItem="SalesItem" OnSelected="OnSelected" @ref="ReorderOverlay" />
|
|
@ -24,23 +24,26 @@ using Wonky.Entity.Views;
|
|||
|
||||
namespace Wonky.Client.OverlayOffice;
|
||||
|
||||
public partial class OfficeOrderInventoryListOverlay : IDisposable
|
||||
public partial class OfficeCustomerOrderInventoryListOverlay : IDisposable
|
||||
{
|
||||
// ##############################################################
|
||||
[Inject] public HttpInterceptorService Interceptor { get; set; }
|
||||
[Inject] public ICountryCatalogRepository CatalogRepo { get; set; }
|
||||
[Inject] public ILogger<OfficeOrderInventoryListOverlay> Logger { get; set; }
|
||||
[Inject] public ILogger<OfficeCustomerOrderInventoryListOverlay> Logger { get; set; }
|
||||
|
||||
// ##############################################################
|
||||
[Parameter] public CompanyDto Company { get; set; } = new();
|
||||
[Parameter] public List<ProductInventoryItemView> Inventory { get; set; } = new();
|
||||
[Parameter] public EventCallback<DraftItem> OnSelected { get; set; }
|
||||
|
||||
// ##############################################################
|
||||
private string _modalDisplay = "";
|
||||
private bool _showBackdrop;
|
||||
// private List<ProductInventoryView> ProductList { get; set; } = new();
|
||||
private DraftItem DraftItem { get; set; } = new();
|
||||
private SalesItemView SalesItem { get; set; } = new();
|
||||
|
||||
private OfficeOrderInventoryReorderOverlay ReorderOverlay { get; set; } = new();
|
||||
private OfficeCustomerOrderInventoryReorderOverlay ReorderOverlay { get; set; } = new();
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
|
@ -24,12 +24,17 @@ using Wonky.Entity.Views;
|
|||
|
||||
namespace Wonky.Client.OverlayOffice;
|
||||
|
||||
public partial class OfficeOrderInventoryReorderOverlay
|
||||
public partial class OfficeCustomerOrderInventoryReorderOverlay
|
||||
{
|
||||
// ##############################################################
|
||||
[Inject] public ICountryCustomerHistoryRepository HistoryRepo { get; set; }
|
||||
|
||||
// ##############################################################
|
||||
[Parameter] public CompanyDto Company { get; set; } = new();
|
||||
[Parameter] public SalesItemView SalesItem { get; set; } = new();
|
||||
[Parameter] public EventCallback<DraftItem> OnSelected { get; set; }
|
||||
|
||||
// ##############################################################
|
||||
private List<ProductHistoryView>? ProductHistory { get; set; } = new();
|
||||
private DraftItem SelectedItem { get; set; } = new();
|
||||
private string ProductName { get; set; } = "";
|
|
@ -29,17 +29,17 @@ namespace Wonky.Client.OverlayOrderCreate;
|
|||
|
||||
public partial class CatalogPagedOverlay : IDisposable
|
||||
{
|
||||
// injections
|
||||
// ##############################################################
|
||||
[Inject] public ICountryCatalogRepository CatalogRepo { get; set; }
|
||||
[Inject] public HttpInterceptorService Interceptor { get; set; }
|
||||
[Inject] public UserPreferenceService PreferenceService { get; set; }
|
||||
[Inject] public ILogger<CatalogPagedOverlay> Logger { get; set; }
|
||||
|
||||
// parameters
|
||||
// ##############################################################
|
||||
[Parameter] public string CountryCode { get; set; } = "";
|
||||
[Parameter] public EventCallback<SelectedSku> OnSelected { get; set; }
|
||||
|
||||
// variables
|
||||
// ##############################################################
|
||||
private string _modalDisplay = "";
|
||||
private bool _showBackdrop;
|
||||
private List<SalesItemView> Items { get; set; } = new();
|
||||
|
|
|
@ -21,12 +21,15 @@ namespace Wonky.Client.OverlayOrderCreate;
|
|||
|
||||
public partial class ProductCheckConfirmationOverlay
|
||||
{
|
||||
private string _modalDisplay = "";
|
||||
private bool _showBackdrop;
|
||||
// ##############################################################
|
||||
[Parameter] public string BodyMessage { get; set; } = "";
|
||||
[Parameter] public string CompanyId { get; set; } = "";
|
||||
[Parameter] public List<ProductInventoryItemView> Products { get; set; } = new();
|
||||
[Parameter] public EventCallback OnOkClicked { get; set; }
|
||||
|
||||
// ##############################################################
|
||||
private string _modalDisplay = "";
|
||||
private bool _showBackdrop;
|
||||
|
||||
public void Show()
|
||||
{
|
||||
|
|
|
@ -24,10 +24,14 @@ namespace Wonky.Client.OverlayOrderCreate;
|
|||
|
||||
public partial class ProductHistoryOverlay
|
||||
{
|
||||
// [Parameter] public EventCallback<decimal> OnSelected { get; set; }
|
||||
// ##############################################################
|
||||
[Inject] public ICrmCustomerHistoryRepository HistoryRepo { get; set; }
|
||||
|
||||
// ##############################################################
|
||||
[Parameter] public string CompanyId { get; set; } = "";
|
||||
[Parameter] public string ItemSku { get; set; } = "";
|
||||
[Inject] public ICrmCustomerHistoryRepository HistoryRepo { get; set; }
|
||||
|
||||
// ##############################################################
|
||||
private List<ProductHistoryView>? History { get; set; }
|
||||
private string ProductName { get; set; } = "";
|
||||
private string _modalDisplay = "";
|
||||
|
@ -35,18 +39,13 @@ public partial class ProductHistoryOverlay
|
|||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
History = await HistoryRepo.FetchHistory(CompanyId, ItemSku);
|
||||
History = await HistoryRepo.GetProductInvoiceLines(CompanyId, ItemSku);
|
||||
if (History.Any())
|
||||
{
|
||||
ProductName = History[0].Description;
|
||||
}
|
||||
}
|
||||
|
||||
// private void SelectPrice(decimal price)
|
||||
// {
|
||||
// OnSelected.InvokeAsync(price);
|
||||
// Hide();
|
||||
// }
|
||||
|
||||
|
||||
public void Show()
|
||||
{
|
||||
|
@ -55,6 +54,7 @@ public partial class ProductHistoryOverlay
|
|||
StateHasChanged();
|
||||
}
|
||||
|
||||
|
||||
private void Hide()
|
||||
{
|
||||
_modalDisplay = "none;";
|
||||
|
|
|
@ -24,10 +24,15 @@ namespace Wonky.Client.OverlayOrderCreate;
|
|||
|
||||
public partial class ProductPriceHistoryOverlay
|
||||
{
|
||||
// ##############################################################
|
||||
[Inject] public ICrmCustomerHistoryRepository HistoryRepo { get; set; }
|
||||
|
||||
// ##############################################################
|
||||
[Parameter] public EventCallback<decimal> OnSelected { get; set; }
|
||||
[Parameter] public string CompanyId { get; set; } = "";
|
||||
[Parameter] public string Sku { get; set; } = "";
|
||||
[Inject] public ICrmCustomerHistoryRepository HistoryRepo { get; set; }
|
||||
|
||||
// ##############################################################
|
||||
private List<ProductHistoryView>? ProductHistory { get; set; }
|
||||
private string ProductName { get; set; } = "";
|
||||
private string _modalDisplay = "";
|
||||
|
@ -38,19 +43,21 @@ public partial class ProductPriceHistoryOverlay
|
|||
if (string.IsNullOrWhiteSpace(Sku))
|
||||
return;
|
||||
|
||||
ProductHistory = await HistoryRepo.FetchHistory(CompanyId, Sku);
|
||||
ProductHistory = await HistoryRepo.GetProductInvoiceLines(CompanyId, Sku);
|
||||
if (ProductHistory.Any())
|
||||
{
|
||||
ProductName = ProductHistory[0].Description;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void SelectPrice(decimal price)
|
||||
{
|
||||
OnSelected.InvokeAsync(price);
|
||||
Hide();
|
||||
}
|
||||
|
||||
|
||||
public void Show()
|
||||
{
|
||||
_modalDisplay = "block;";
|
||||
|
@ -58,6 +65,7 @@ public partial class ProductPriceHistoryOverlay
|
|||
StateHasChanged();
|
||||
}
|
||||
|
||||
|
||||
private void Hide()
|
||||
{
|
||||
_modalDisplay = "none;";
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
<PageTitle>Produkt oversigt for @Company.Name</PageTitle>
|
||||
<div class="row ps-3 pt-2 pb-1 rounded-2 bg-dark text-white">
|
||||
<div class="col-sm-6">
|
||||
<h4 class="pt-1">Produkt oversigt @Company.Name</h4>
|
||||
<h4 class="pt-1">Produkt køb @Company.Name</h4>
|
||||
</div>
|
||||
<div class="col-sm-3 align-content-end d-print-none">
|
||||
<a class="btn btn-primary d-block" href="/advisor/customers/@CompanyId"><i class="bi-chevron-left"></i> Stamkort</a>
|
||||
|
@ -33,10 +33,9 @@
|
|||
</div>
|
||||
|
||||
<CustomerInventoryListComponent OnReorderSelected="OnReorderCallback" CompanyId="@CompanyId" Inventory="@Inventory"/>
|
||||
<CustomerInventoryReorderOverlay OnSelected="@OnSelectedItem" CompanyId="@CompanyId" SalesItem="@SalesItem" @ref="ReorderOverlay"/>
|
||||
|
||||
@if (Working)
|
||||
{
|
||||
<WorkingThreeDots/>
|
||||
}
|
||||
|
||||
<CustomerInventoryReorderOverlay OnSelected="@OnSelectedItem" CompanyId="@CompanyId" SalesItem="@SalesItem" @ref="ReorderOverlay"/>
|
||||
}
|
|
@ -19,6 +19,8 @@ using System.Xml;
|
|||
using Blazored.LocalStorage;
|
||||
using Blazored.Toast.Services;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Wonky.Client.Enums;
|
||||
using Wonky.Client.Helpers;
|
||||
using Wonky.Client.HttpInterceptors;
|
||||
using Wonky.Client.HttpRepository;
|
||||
using Wonky.Client.Models;
|
||||
|
@ -65,7 +67,8 @@ public partial class AdvisorCustomerInventoryListPage : IDisposable
|
|||
|
||||
Working = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private async Task OnReorderCallback(string sku)
|
||||
{
|
||||
// fetch item from http repo
|
||||
|
|
|
@ -311,12 +311,9 @@
|
|||
<button type="button" class="btn btn-outline-dark" @onclick="@ToggleVisibility">@ToggleButtonText</button>
|
||||
</div>
|
||||
<div class="col-sm-4 d-grid">
|
||||
@if (AppInfo!.Value!.Rc)
|
||||
@if (UserInfo.CountryCode is "DK")
|
||||
{
|
||||
@if (UserInfo.CountryCode is "DK")
|
||||
{
|
||||
<a class="btn btn-info" href="@($"/advisor/customers/{CompanyId}/workplaces")">Kemi Dokumentation</a>
|
||||
}
|
||||
<a class="btn btn-info" href="@($"/advisor/customers/{CompanyId}/workplaces")">Kemi Dokumentation</a>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -33,12 +33,11 @@
|
|||
<div class="col-sm-12 col-md-6">
|
||||
<InfoColorCustomerComponent/>
|
||||
</div>
|
||||
@*
|
||||
<div class="col-sm-12 col-md-6">
|
||||
<InfoColorPackageComponent/>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-6">
|
||||
<InfoCommonComponent />
|
||||
</div>
|
||||
*@
|
||||
<div class="col-sm-12 col-md-6">
|
||||
<InfoProcessStateComponent />
|
||||
</div>
|
||||
|
@ -48,12 +47,17 @@
|
|||
<div class="col-sm-12 col-md-6">
|
||||
<InfoQuoteToolbarComponent/>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-6">
|
||||
<InfoCommonComponent />
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-6">
|
||||
<InfoOfficeComponent />
|
||||
</div>
|
||||
@*
|
||||
<div class="col-sm-12 col-md-6">
|
||||
<InfoWarehouseComponent />
|
||||
</div>
|
||||
*@
|
||||
<div class="col-sm-12 col-md-6">
|
||||
<InfoBrowserComponent />
|
||||
</div>
|
||||
|
|
|
@ -245,4 +245,4 @@
|
|||
<CatalogPagedOverlay @ref="CatalogOverlay" CountryCode="@CountryCode" OnSelected="PriceListCallback"/>
|
||||
<OfficeCustomerInvoiceListOverlay @ref="InvoiceListOverlay" Company="Company" InvoiceList="CompanyInvoices"/>
|
||||
<OfficeCustomerActivityListOverlay @ref="ActivityListOverlay" Company="Company" ActivityList="CompanyActivities"/>
|
||||
<OfficeOrderInventoryListOverlay @ref="InventoryListOverlay" Company="Company" Inventory="CompanyInventory" OnSelected="InventoryCallback"/>
|
||||
<OfficeCustomerOrderInventoryListOverlay @ref="InventoryListOverlay" Company="Company" Inventory="CompanyInventory" OnSelected="InventoryCallback"/>
|
|
@ -80,7 +80,7 @@ public partial class OfficeOrderCreatePage : IDisposable
|
|||
private CatalogPagedOverlay CatalogOverlay { get; set; } = new();
|
||||
private OfficeCustomerInvoiceListOverlay InvoiceListOverlay { get; set; } = new();
|
||||
private OfficeCustomerActivityListOverlay ActivityListOverlay { get; set; } = new();
|
||||
private OfficeOrderInventoryListOverlay InventoryListOverlay { get; set; } = new();
|
||||
private OfficeCustomerOrderInventoryListOverlay InventoryListOverlay { get; set; } = new();
|
||||
|
||||
// #############################################################
|
||||
// lists
|
||||
|
|
|
@ -37,6 +37,7 @@ public partial class SupervisorDocumentNewPage : IDisposable
|
|||
[Inject] public ILogger<SupervisorDocumentNewPage> Logger { get; set; }
|
||||
[Inject] public IToastService Toaster { get; set; }
|
||||
[Inject] public NavigationManager Navigator { get; set; }
|
||||
[Inject] public ISystemSendMailService SendMail { get; set; }
|
||||
|
||||
|
||||
// ############################################################
|
||||
|
@ -102,6 +103,25 @@ public partial class SupervisorDocumentNewPage : IDisposable
|
|||
else
|
||||
{
|
||||
Toaster.ShowSuccess("Ok");
|
||||
var sendTo = new List<EmailContact>
|
||||
{
|
||||
new () { Email = "paul@innotec.dk", Name = "Paul Vendelbo" },
|
||||
new () { Email = "eddie@innotec.dk", Name = "Eddie Broch" }
|
||||
};
|
||||
var msg = new EmailMessage
|
||||
{
|
||||
Body = Document.Content,
|
||||
Subject = Document.Description,
|
||||
To = sendTo,
|
||||
IsBodyHtml = false
|
||||
};
|
||||
Toaster.ShowInfo("Sender email ...");
|
||||
var result = await SendMail.SendMail("system", msg);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
Toaster.ClearAll();
|
||||
Toaster.ShowInfo("Email sendt.");
|
||||
}
|
||||
Navigator.NavigateTo($"/supervisor/advisors/{AdvisorId}/documents");
|
||||
}
|
||||
Toaster.ClearAll();
|
||||
|
|
|
@ -82,7 +82,7 @@
|
|||
<div class="card-footer">
|
||||
<div class="row">
|
||||
<div class="col text-start">
|
||||
<button type="button" class="btn btn-warning" nclick="@RemoveDocument"><i class="bi-trash"></i> Slet</button>
|
||||
<button type="button" class="btn btn-warning" @onclick="@RemoveDocument"><i class="bi-trash"></i> Slet</button>
|
||||
</div>
|
||||
<div class="col text-end">
|
||||
<button type="submit" class="btn btn-primary"><i class="bi-cloud-upload"></i> Gem</button>
|
||||
|
|
|
@ -1,36 +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
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@attribute [Authorize(Roles = "Admin,Office,Warehouse")]
|
||||
|
||||
@page "/warehouse/orders/{Status}"
|
||||
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h2>Forsendelser</h2>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="busy-signal" style="display:@(Working ? "block" : "none")">
|
||||
<div class="spinner-grow text-info" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<WarehouseListComponent Header="@Header" OrderList="@OrderList" ReadyToShip="@ReadyToShip"
|
||||
OnGetStatus="GetStatusCallback" OnSetShipped="@SetShippedCallback" OnQPak="QPakCallback" />
|
|
@ -1,133 +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.Enums;
|
||||
using Wonky.Client.Helpers;
|
||||
using Wonky.Client.HttpInterceptors;
|
||||
using Wonky.Client.HttpRepository;
|
||||
using Wonky.Client.Models;
|
||||
using Wonky.Entity.DTO;
|
||||
using Wonky.Entity.Views;
|
||||
#pragma warning disable CS8618
|
||||
|
||||
namespace Wonky.Client.Pages;
|
||||
|
||||
public partial class WarehouseOrderListPage : IDisposable
|
||||
{
|
||||
// #############################################################
|
||||
[Inject] public HttpInterceptorService Interceptor { get; set; }
|
||||
[Inject] public IOrderProcessRepository OrderProcessRepo { get; set; }
|
||||
[Inject] public NavigationManager Navigator { get; set; }
|
||||
|
||||
// #############################################################
|
||||
[Parameter] public string Status { get; set; } = "none";
|
||||
|
||||
// #############################################################
|
||||
private List<WarehouseOrderView> OrderList { get; set; } = new();
|
||||
private bool Working { get; set; } = true;
|
||||
private string Header { get; set; } = "Ubehandlet";
|
||||
private bool ReadyToShip { get; set; }
|
||||
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
Interceptor.RegisterEvent();
|
||||
Interceptor.RegisterBeforeSendEvent();
|
||||
OrderList = await FetchOrders(Status);
|
||||
}
|
||||
|
||||
private async Task GetStatusCallback(ProcessStatus status)
|
||||
{
|
||||
Working = true;
|
||||
OrderList = new List<WarehouseOrderView>();
|
||||
switch (status)
|
||||
{
|
||||
case ProcessStatus.None or ProcessStatus.Printed:
|
||||
Header = "Ubehandlede ordrer";
|
||||
ReadyToShip = false;
|
||||
break;
|
||||
case ProcessStatus.Picked:
|
||||
Header = "Plukkede ordrer";
|
||||
ReadyToShip = false;
|
||||
break;
|
||||
case ProcessStatus.Packed:
|
||||
Header = "Pakkede ordrer";
|
||||
ReadyToShip = true;
|
||||
break;
|
||||
case ProcessStatus.Shipped:
|
||||
break;
|
||||
case ProcessStatus.All:
|
||||
break;
|
||||
case ProcessStatus.Express:
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(status), status, null);
|
||||
}
|
||||
Status = Utils.EnumToString(status).ToLower();
|
||||
OrderList = await FetchOrders(Status);
|
||||
Working = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// QPak - quick mark an order as shipped
|
||||
/// </summary>
|
||||
/// <param name="orderId"></param>
|
||||
private async Task QPakCallback(string orderId)
|
||||
{
|
||||
Working = true;
|
||||
var order = OrderList.First(x => x.OrderId == orderId);
|
||||
order.ProcessStatusEnum = "packed";
|
||||
var process = new OrderProcessState
|
||||
{
|
||||
OrderId = order.OrderId,
|
||||
ProcessStatusEnum = "packed"
|
||||
};
|
||||
await OrderProcessRepo.UpdateWarehouseOrderStatus(process);
|
||||
OrderList.Remove(order);
|
||||
Working = false;
|
||||
}
|
||||
/// <summary>
|
||||
/// Set status shipped where status is packed
|
||||
/// </summary>
|
||||
private async Task SetShippedCallback()
|
||||
{
|
||||
Working = true;
|
||||
foreach (var order in OrderList.Where(order => order.ProcessStatusEnum.ToLower() == "packed"))
|
||||
{
|
||||
order.ProcessStatusEnum = "shipped";
|
||||
var process = new OrderProcessState
|
||||
{
|
||||
OrderId = order.OrderId,
|
||||
ProcessStatusEnum = "shipped"
|
||||
};
|
||||
await OrderProcessRepo.UpdateWarehouseOrderStatus(process);
|
||||
}
|
||||
Working = false;
|
||||
}
|
||||
|
||||
private async Task<List<WarehouseOrderView>> FetchOrders(string status)
|
||||
{
|
||||
Working = true;
|
||||
var orderList = await OrderProcessRepo.GetWarehouseOrderListByStatus(status.ToLower());
|
||||
if(orderList.Any(x => x.Express))
|
||||
orderList = orderList.OrderByDescending(x => x.Express).ToList();
|
||||
Working = false;
|
||||
return orderList;
|
||||
}
|
||||
|
||||
public void Dispose() => Interceptor.DisposeEvent();
|
||||
}
|
|
@ -1,129 +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.Authorization
|
||||
@using Wonky.Client.Components
|
||||
@attribute [Authorize(Roles = "Admin,Office,Warehouse")]
|
||||
|
||||
@page "/warehouse/orders/process/{OrderId}"
|
||||
|
||||
@if (!string.IsNullOrWhiteSpace(Order.OrderDate))
|
||||
{
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="4">
|
||||
@if (Order.Express)
|
||||
{
|
||||
<h2 class="text-center fw-bold">HASTE ORDRE</h2>
|
||||
}
|
||||
<h2 class="text-center">@Order.Company.Name</h2>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row">Konto</th>
|
||||
<td>@Order.Company.Account</td>
|
||||
<th scope="row">Telefon</th>
|
||||
<td>@Order.Company.Phone</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Kunde</th>
|
||||
<td>@Order.Company.Name</td>
|
||||
<th scope="row">Lev.Navn</th>
|
||||
<td>@Order.DlvName</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Adresse</th>
|
||||
<td>@Order.Company.Address1</td>
|
||||
<th scope="row">Lev.Adresse</th>
|
||||
<td>@Order.DlvAddress1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Adresse</th>
|
||||
<td>@Order.Company.Address2</td>
|
||||
<th scope="row">Lev.Adresse</th>
|
||||
<td>@Order.DlvAddress2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Postnr By</th>
|
||||
<td>@Order.Company.ZipCode @Order.Company.City</td>
|
||||
<th scope="row">Lev.Postnr By</th>
|
||||
<td>@Order.DlvZipCity</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Placering</th>
|
||||
<th scope="col">Antal</th>
|
||||
<th scope="col">Varenr</th>
|
||||
<th scope="col">Beskrivelse</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var line in Order.Lines)
|
||||
{
|
||||
<tr>
|
||||
<td class="fw-bold">@line.Location</td>
|
||||
<td>@line.Quantity</td>
|
||||
<td>@line.Sku</td>
|
||||
<td>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="@line.LineNumber"/>
|
||||
<label class="form-check-label" for="@line.LineNumber">@line.Description</label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
@if (!string.IsNullOrWhiteSpace(Order.OfficeNote))
|
||||
{
|
||||
<div class="alert bg-light border-dark border-2">
|
||||
<h3 class="text-center">@Order.OfficeNote</h3>
|
||||
</div>
|
||||
}
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<a class="btn btn-outline-success text-nowrap" href="/warehouse/orders/none">Ubehandlet</a>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
@if (Order.ProcessStatusEnum.ToLower() is "none" or "printed")
|
||||
{
|
||||
<button class="btn btn-lg btn-warning text-nowrap" type="button" @onclick="@SetProcessStatusPicked" disabled="@Working">Sæt status plukket</button>
|
||||
}
|
||||
@if (Order.ProcessStatusEnum.ToLower() == "picked")
|
||||
{
|
||||
<button class="btn btn-lg btn-danger text-nowrap" type="button" @onclick="@SetProcessStatusPacked" disabled="@Working">Sæt status pakket</button>
|
||||
}
|
||||
@if (Order.ProcessStatusEnum.ToLower() == "packed")
|
||||
{
|
||||
<button class="btn btn-lg btn-primary text-nowrap" type="button" @onclick="@SetProcessStatusShipped" disabled="@Working">Sæt status afsendt</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
@if (Working)
|
||||
{
|
||||
<WorkingThreeDots/>
|
||||
}
|
|
@ -1,103 +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 System.Text.Json;
|
||||
using Blazored.Toast.Services;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Wonky.Client.HttpInterceptors;
|
||||
using Wonky.Client.HttpRepository;
|
||||
using Wonky.Entity.DTO;
|
||||
using Wonky.Entity.Views;
|
||||
#pragma warning disable CS8618
|
||||
|
||||
namespace Wonky.Client.Pages;
|
||||
|
||||
public partial class WarehouseOrderViewPage : IDisposable
|
||||
{
|
||||
// #############################################################
|
||||
[Inject] public HttpInterceptorService Interceptor { get; set; }
|
||||
[Inject] public IOrderProcessRepository OrderProcessRepo { get; set; }
|
||||
[Inject] public NavigationManager Navigator { get; set; }
|
||||
[Inject] public IToastService Toast { get; set; }
|
||||
[Inject] public ILogger<WarehouseOrderViewPage> Logger { get; set; }
|
||||
|
||||
// #############################################################
|
||||
[Parameter] public string OrderId { get; set; } = "";
|
||||
|
||||
// #############################################################
|
||||
private WarehouseOrderView Order { get; set; } = new();
|
||||
private bool Working { get; set; } = true;
|
||||
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
Interceptor.RegisterEvent();
|
||||
Interceptor.RegisterBeforeSendEvent();
|
||||
if (!string.IsNullOrWhiteSpace(OrderId))
|
||||
Order = await OrderProcessRepo.GetWarehouseOrder(OrderId);
|
||||
|
||||
Logger.LogDebug("Warehouse OrderView =>\n{}", JsonSerializer.Serialize(Order));
|
||||
Working = false;
|
||||
}
|
||||
|
||||
private async Task SetProcessStatusPicked()
|
||||
{
|
||||
if (Working)
|
||||
return;
|
||||
|
||||
Working = true;
|
||||
var process = new OrderProcessState
|
||||
{
|
||||
OrderId = Order.OrderId,
|
||||
ProcessStatusEnum = "picked"
|
||||
};
|
||||
await OrderProcessRepo.UpdateWarehouseOrderStatus(process);
|
||||
Navigator.NavigateTo("/warehouse/orders/none");
|
||||
}
|
||||
|
||||
private async Task SetProcessStatusPacked()
|
||||
{
|
||||
if (Working)
|
||||
return;
|
||||
Working = true;
|
||||
var process = new OrderProcessState
|
||||
{
|
||||
OrderId = Order.OrderId,
|
||||
ProcessStatusEnum = "packed"
|
||||
};
|
||||
await OrderProcessRepo.UpdateWarehouseOrderStatus(process);
|
||||
Navigator.NavigateTo("/warehouse/orders/picked");
|
||||
}
|
||||
|
||||
private async Task SetProcessStatusShipped()
|
||||
{
|
||||
if (Working)
|
||||
return;
|
||||
Working = true;
|
||||
var process = new OrderProcessState
|
||||
{
|
||||
OrderId = Order.OrderId,
|
||||
ProcessStatusEnum = "shipped"
|
||||
};
|
||||
await OrderProcessRepo.UpdateWarehouseOrderStatus(process);
|
||||
Navigator.NavigateTo("/warehouse/orders/none");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Interceptor.DisposeEvent();
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
using System.Net.Http.Headers;
|
||||
using System.Security.Claims;
|
||||
using System.Text.Json;
|
||||
using Blazored.LocalStorage;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using Wonky.Client.Local.Services;
|
||||
|
@ -26,35 +27,43 @@ namespace Wonky.Client.Shared;
|
|||
public class AuthStateProvider : AuthenticationStateProvider
|
||||
{
|
||||
private readonly HttpClient _client;
|
||||
// private readonly ILocalStorageService _storage;
|
||||
private readonly AuthenticationState _anonymous;
|
||||
private readonly IUserInfoService _infoService;
|
||||
|
||||
|
||||
public AuthStateProvider(HttpClient client, IUserInfoService infoService)
|
||||
private readonly ILogger<AuthStateProvider> _logger;
|
||||
|
||||
public AuthStateProvider(HttpClient client, IUserInfoService infoService, ILogger<AuthStateProvider> logger)
|
||||
{
|
||||
_client = client;
|
||||
_infoService = infoService;
|
||||
_logger = logger;
|
||||
_anonymous = new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
|
||||
{
|
||||
var token = await _infoService.GetAccessToken();
|
||||
_logger.LogDebug("accessToken {}", token);
|
||||
if (string.IsNullOrEmpty(token))
|
||||
{
|
||||
return _anonymous;
|
||||
}
|
||||
|
||||
var userInfo = await _infoService.GetUserInfo();
|
||||
if (string.IsNullOrWhiteSpace(userInfo.UserId))
|
||||
_logger.LogDebug("userInfo {}", JsonSerializer.Serialize(userInfo));
|
||||
|
||||
if (userInfo == null || string.IsNullOrWhiteSpace(userInfo.FirstName))
|
||||
{
|
||||
NotifyUserLogout();
|
||||
return _anonymous;
|
||||
}
|
||||
|
||||
_logger.LogDebug("userInfo.FirstName {}", userInfo.FirstName);
|
||||
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", token);
|
||||
|
||||
var exp = await _infoService.GetExpiration();
|
||||
_logger.LogDebug("expiration {}", exp);
|
||||
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new(ClaimTypes.Name, $"{userInfo.FirstName} {userInfo.LastName}"),
|
||||
|
@ -64,30 +73,37 @@ public class AuthStateProvider : AuthenticationStateProvider
|
|||
new(ClaimTypes.Expiration, exp.ToString())
|
||||
};
|
||||
claims.AddRange(
|
||||
from role in userInfo.AssignedRoles
|
||||
where role.Assigned select new Claim(ClaimTypes.Role, role.Name)
|
||||
);
|
||||
claims.Add( new Claim(ClaimTypes.Role, userInfo.CountryCode));
|
||||
|
||||
from role in userInfo.AssignedRoles
|
||||
where role.Assigned
|
||||
select new Claim(ClaimTypes.Role, role.Name)
|
||||
);
|
||||
|
||||
// return the authState for the user
|
||||
return new AuthenticationState(
|
||||
new ClaimsPrincipal(
|
||||
new ClaimsIdentity(claims, "token")));
|
||||
new ClaimsIdentity(claims, "token"))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public async void NotifyUserAuthenticationAsync(string token)
|
||||
{
|
||||
if (string.IsNullOrEmpty(token))
|
||||
{
|
||||
NotifyUserLogout();
|
||||
return;
|
||||
}
|
||||
|
||||
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", token);
|
||||
|
||||
var userInfo = await _infoService.GetUserInfo();
|
||||
if (string.IsNullOrWhiteSpace(userInfo.UserId))
|
||||
{
|
||||
NotifyUserLogout();
|
||||
return;
|
||||
}
|
||||
|
||||
var exp = await _infoService.GetExpiration();
|
||||
|
||||
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new(ClaimTypes.Name, $"{userInfo.FirstName} {userInfo.LastName}"),
|
||||
|
@ -97,18 +113,22 @@ public class AuthStateProvider : AuthenticationStateProvider
|
|||
new(ClaimTypes.Expiration, exp.ToString())
|
||||
};
|
||||
claims.AddRange(
|
||||
from role in userInfo.AssignedRoles
|
||||
where role.Assigned select new Claim(ClaimTypes.Role, role.Name));
|
||||
|
||||
from role in userInfo.AssignedRoles
|
||||
where role.Assigned
|
||||
select new Claim(ClaimTypes.Role, role.Name)
|
||||
);
|
||||
|
||||
var authState = Task.FromResult(
|
||||
new AuthenticationState(
|
||||
new ClaimsPrincipal(
|
||||
new ClaimsIdentity(claims, "token"))));
|
||||
new ClaimsIdentity(claims, "token"))
|
||||
)
|
||||
);
|
||||
|
||||
NotifyAuthenticationStateChanged(authState);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void NotifyUserLogout()
|
||||
{
|
||||
_client.DefaultRequestHeaders.Authorization = null;
|
||||
|
|
|
@ -66,11 +66,13 @@
|
|||
<i class="bi-building pe-2" style="font-size:1.3em;" aria-hidden="true"></i> Kunder SE
|
||||
</NavLink>
|
||||
</div>
|
||||
@*
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link ps-2" href="/warehouse/orders/none">
|
||||
<i class="bi-box pe-2" style="font-size:1.3em;" aria-hidden="true"></i> Forsendelse
|
||||
</NavLink>
|
||||
</div>
|
||||
*@
|
||||
</AuthorizeView>
|
||||
|
||||
<AuthorizeView Roles="Advisor">
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
{
|
||||
"appInfo": {
|
||||
"name": "Wonky Online",
|
||||
"version": "153.0",
|
||||
"version": "157.1",
|
||||
"rc": true,
|
||||
"sandBox": false,
|
||||
"image": "grumpy-coder.png"
|
||||
},
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"System": "Information",
|
||||
"Default": "Debug",
|
||||
"System": "Debug",
|
||||
"Microsoft": "Information"
|
||||
},
|
||||
"Debug": {
|
||||
|
@ -19,7 +19,7 @@
|
|||
}
|
||||
},
|
||||
"apiConfig": {
|
||||
"baseUrl": "https://zeta.innotec.dk",
|
||||
"baseUrl": "https://dev.innotec.dk",
|
||||
"catalog": "api/v2/catalog/country",
|
||||
"crmCustomers": "api/v2/crm/companies",
|
||||
"crmInventoryExt": "history/inventory",
|
||||
|
|
|
@ -16,6 +16,14 @@ body {
|
|||
.workDate {
|
||||
font-variant: small-caps;
|
||||
}
|
||||
|
||||
.action-link-element {
|
||||
cursor: pointer;
|
||||
}
|
||||
.i-larger {
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.btn.btn-edit {
|
||||
color: #030303;
|
||||
background-color: #a2a2ec;
|
||||
|
@ -219,13 +227,6 @@ a, .btn-link {
|
|||
}
|
||||
/* end led elements */
|
||||
|
||||
.action-link-element {
|
||||
cursor: pointer;
|
||||
}
|
||||
.i-larger {
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.footer {
|
||||
border-top: 2px solid orange;
|
||||
position: relative;
|
||||
|
|
|
@ -17,11 +17,17 @@ namespace Wonky.Entity.Views;
|
|||
|
||||
public class ProductInventoryItemView
|
||||
{
|
||||
public virtual bool AgedProduct()
|
||||
{
|
||||
return DateTime.Parse(LastInvoiceDate) < DateTime.Now.AddMonths(-12);
|
||||
}
|
||||
public virtual bool Check { get; set; }
|
||||
public string Description { get; set; } = "";
|
||||
public bool Discontinued { get; set; }
|
||||
public string PictureLink { get; set; } = "";
|
||||
public int Quantity { get; set; }
|
||||
public string LastInvoiceDate { get; set; } = "";
|
||||
public string Sku { get; set; } = "";
|
||||
public string VendorItemNo { get; set; } = "";
|
||||
public string VendorItemNo { get; set; } = "";
|
||||
|
||||
}
|
Loading…
Reference in a new issue