b2b order

This commit is contained in:
Frede Hundewadt 2023-12-15 14:58:26 +01:00
parent f89403a69e
commit d6ce9344c3
12 changed files with 163 additions and 136 deletions

View file

@ -13,8 +13,6 @@
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html] // along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
*@ *@
@using Wonky.Client.Pages
<CascadingAuthenticationState> <CascadingAuthenticationState>
<DraftStateProvider> <DraftStateProvider>
<Router AppAssembly="@typeof(App).Assembly"> <Router AppAssembly="@typeof(App).Assembly">
@ -31,7 +29,7 @@
</Found> </Found>
<NotFound> <NotFound>
<LayoutView Layout="@typeof(MainLayout)"> <LayoutView Layout="@typeof(MainLayout)">
<ErrorPage404 /> <ErrorPage404/>
</LayoutView> </LayoutView>
</NotFound> </NotFound>
</Router> </Router>

View file

@ -18,105 +18,100 @@
@using Wonky.Client.Helpers; @using Wonky.Client.Helpers;
@using Wonky.Client.OverlayOffice @using Wonky.Client.OverlayOffice
@if (CompanyList.Any()) <div class="office-customer-paged">
{ @if (CompanyList.Any())
<div class="row mt-2 d-flex g-3"> {
@foreach (var company in CompanyList) <div class="row mt-2 d-flex g-1">
{ @foreach (var company in CompanyList)
<div class="mx-3 card px-0 col-sm-12 col-lg-6 col-xxl-4" style="width:500px;"> {
@* <div class="card me-1 px-0 col-sm-12 col-lg-6 col-xxl-4" style="width:460px;">
<div class="row g-0"> @if (string.IsNullOrWhiteSpace(company.Blocked))
{
<div class="col-sm-12 col-md-6 col-lg-4 col-xl-3"> <div class="card-header fw-bold @(company.HasFolded == 1 ? "alert alert-dark" : "alert alert-success")">
<div class="card"> @company.Name @(company.HasFolded == 1 ? "(OPHØRT)" : "")
*@ </div>
@if (string.IsNullOrWhiteSpace(company.Blocked)) }
{ else
<div class="card-header fw-bold @(company.HasFolded == 1 ? "alert alert-dark" : "alert alert-success")"> {
@company.Name @(company.HasFolded == 1 ? "(OPHØRT)" : "") <div class="card-header fw-bold alert alert-danger">
@company.Name (spærret med kode '@company.Blocked')
</div>
}
<div class="card-body mx-0">
<table class="m-0 table table-sm table-striped table-light">
<thead></thead>
<tbody>
<tr>
<th scope="row" class="text-sm-start align-middle">Konto</th>
<td class="text-sm-start align-middle">@company.Account</td>
<th scope="row" class="text-sm-start align-middle">Org Nr.</th>
<td class="text-sm-start align-middle">@(string.IsNullOrWhiteSpace(company.VatNumber) ? "mangler" : company.VatNumber) </td>
</tr>
<tr>
<th scope="row" class="text-sm-start align-middle">Telefon</th>
<td colspan="3" class="text-sm-start align-middle">@company.Phone</td>
</tr>
<tr>
<th scope="row" class="text-sm-start align-middle">Adresse</th>
<td colspan="3" class="text-sm-start align-middle">@company.Address1 @(string.IsNullOrWhiteSpace(company.Address2) ? "" : ",") @company.Address2</td>
</tr>
<tr>
<th scope="row" class="text-sm-start align-middle">Post By</th>
<td colspan="3" class="text-sm-start align-middle">@company.CountryCode.ToUpper()-@company.ZipCode @company.City</td>
</tr>
<tr>
<th scope="row" class="text-sm-start align-middle">
Sælger Nr.
</th>
<td colspan="3" class="text-sm-start align-middle">
@company.SalesRep
</td>
</tr>
<tr>
<th scope="row" class="text-sm-start align-middle">Sidst besøgt</th>
<td class="text-sm-start align-middle">
@(Mapper.MapVisitState(company.LastVisit) == "the-draw" ? "?" : company.LastVisit)
</td>
<td colspan="2" class="text-sm-end fw-bold align-middle">@(company.IsHidden == 1 ? "Skjult af sælger." : "")</td>
</tr>
<tr>
<th scope="row" class="text-sm-start align-middle">Næste besøg</th>
<td class="text-sm-start align-middle">
@(Mapper.MapVisitState(company.LastVisit) == "the-draw" ? "?" : company.NextVisit)
</td>
<td></td>
<td class="align-middle">
<button class="btn btn-sm btn-secondary w-100" disabled="@(company.Account.StartsWith("NY") || company.Account.StartsWith("KA"))" @onclick="() => RequestBusinessCentralData(company.CompanyId, true)"><i class="bi-arrow-repeat"></i> BC</button>
</td>
</tr>
</tbody>
</table>
</div> </div>
} <div class="card-footer">
else <div class="row">
{ <div class="px-1 col-sm-3">
<div class="card-header fw-bold alert alert-danger"> <button class="btn btn-sm btn-danger w-100" @onclick="@(() => ShowInvoiceList(company.CompanyId))"> Salg</button>
@company.Name (spærret med kode '@company.Blocked') </div>
</div> <div class="px-1 col-sm-3">
} <button class="btn btn-sm btn-warning w-100" @onclick="@(() => ShowActivityList(company.CompanyId))">Aktivitet</button>
<div class="card-body mx-0"> </div>
<table class="m-0 table table-sm table-striped table-light"> <div class="px-1 col-sm-3">
<thead></thead> <button class="btn btn-sm btn-success w-100" @onclick="@(() => ShowInventory(company.CompanyId))">Produkt</button>
<tbody> </div>
<tr> <div class="px-1 col-sm-3">
<th scope="row" class="text-sm-start align-middle">Konto</th> <a class="btn btn-sm btn-primary w-100" href="/office/customers/@CountryCode/@company.CompanyId/order">Bestilling</a>
<td class="text-sm-start align-middle">@company.Account</td> </div>
<th scope="row" class="text-sm-start align-middle">Org Nr.</th>
<td class="text-sm-start align-middle">@(string.IsNullOrWhiteSpace(company.VatNumber) ? "mangler" : company.VatNumber) </td>
</tr>
<tr>
<th scope="row" class="text-sm-start align-middle">Telefon</th>
<td colspan="3" class="text-sm-start align-middle">@company.Phone</td>
</tr>
<tr>
<th scope="row" class="text-sm-start align-middle">Adresse</th>
<td colspan="3" class="text-sm-start align-middle">@company.Address1 @(string.IsNullOrWhiteSpace(company.Address2) ? "" : ",") @company.Address2</td>
</tr>
<tr>
<th scope="row" class="text-sm-start align-middle">Post By</th>
<td colspan="3" class="text-sm-start align-middle">@company.CountryCode.ToUpper()-@company.ZipCode @company.City</td>
</tr>
<tr>
<th scope="row" class="text-sm-start align-middle">
Sælger Nr.
</th>
<td colspan="3" class="text-sm-start align-middle">
@company.SalesRep
</td>
</tr>
<tr>
<th scope="row" class="text-sm-start align-middle">Sidst besøgt</th>
<td class="text-sm-start align-middle">
@(Mapper.MapVisitState(company.LastVisit) == "the-draw" ? "?" : company.LastVisit)
</td>
<td colspan="2" class="text-sm-end fw-bold align-middle">@(company.IsHidden == 1 ? "Skjult af sælger." : "")</td>
</tr>
<tr>
<th scope="row" class="text-sm-start align-middle">Næste besøg</th>
<td class="text-sm-start align-middle">
@(Mapper.MapVisitState(company.LastVisit) == "the-draw" ? "?" : company.NextVisit)
</td>
<td></td>
<td class="align-middle">
<button class="btn btn-sm btn-secondary w-100" @onclick="() => RequestBusinessCentralData(company.CompanyId, true)"><i class="bi-arrow-repeat"></i> BC</button>
</td>
</tr>
</tbody>
</table>
</div>
<div class="card-footer">
<div class="row">
<div class="px-1 col-sm-3">
<button class="btn btn-sm btn-danger w-100" @onclick="@(() => ShowInvoiceList(company.CompanyId))"> Salg</button>
</div>
<div class="px-1 col-sm-3">
<button class="btn btn-sm btn-warning w-100" @onclick="@(() => ShowActivityList(company.CompanyId))">Aktivitet</button>
</div>
<div class="px-1 col-sm-3">
<button class="btn btn-sm btn-success w-100" @onclick="@(() => ShowInventory(company.CompanyId))">Produkt</button>
</div>
<div class="px-1 col-sm-3">
<a class="btn btn-sm btn-primary w-100" href="/office/customers/@CountryCode/@company.CompanyId/order">Bestilling</a>
</div> </div>
</div> </div>
</div> </div>
</div> }
// </div> </div>
} <OfficeCustomerInvoiceListOverlay Company="@SelectedCompany" InvoiceList="@InvoiceList" @ref="@InvoiceListOverlay"/>
</div> <OfficeCustomerActivityListOverlay Company="@SelectedCompany" ActivityList="@ActivityList" @ref="@ActivityListOverlay"/>
<OfficeCustomerInvoiceListOverlay Company="@SelectedCompany" InvoiceList="@InvoiceList" @ref="@InvoiceListOverlay"/> <OfficeCustomerListInventoryOverlay Company="@SelectedCompany" Inventory="@ProductInventory" @ref="@InventoryListOverlay"/>
<OfficeCustomerActivityListOverlay Company="@SelectedCompany" ActivityList="@ActivityList" @ref="@ActivityListOverlay"/> }
<OfficeCustomerListInventoryOverlay Company="@SelectedCompany" Inventory="@ProductInventory" @ref="@InventoryListOverlay"/> else
} {
else <div>Ingen data</div>
{ }
<div>Ingen data</div> </div>
}

View file

@ -14,8 +14,9 @@
*@ *@
<div class="input-group"> <div class="input-group">
<input id="search-input" type="text" class="form-control" placeholder="Søg ..." aria-described-by="search-addon" <input id="search-input" tabindex="-1" type="text" class="form-control" placeholder="Søg ..." aria-described-by="search-addon"
@bind-value="SearchTerm" @bind-value:event="oninput" @onkeyup="@OnSearchChanged" /> @bind-value="SearchTerm" @bind-value:event="oninput" @onkeyup="@OnSearchChanged"/>
<span class="input-group-text" id="search-addon"><i class="bi-backspace" @onclick="@ClearSearch"></i></span> <span class="input-group-text" id="search-addon">
</div> <i class="bi-backspace" @onclick="@ClearSearch"></i>
</span>
</div>

View file

@ -15,7 +15,9 @@
using System.Timers; using System.Timers;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Toolbelt.Blazor.HotKeys2;
using Timer = System.Timers.Timer; using Timer = System.Timers.Timer;
using Wonky.Client.Helpers;
namespace Wonky.Client.Components; namespace Wonky.Client.Components;
@ -23,7 +25,7 @@ public partial class SearchPhraseComponent
{ {
private string SearchTerm { get; set; } = ""; private string SearchTerm { get; set; } = "";
[Parameter] public EventCallback<string> OnChanged { get; set; } [Parameter] public EventCallback<string> OnChanged { get; set; }
private void ClearSearch() private void ClearSearch()
{ {
SearchTerm = ""; SearchTerm = "";

View file

@ -78,8 +78,8 @@ public class CountryCustomerRepository : ICountryCustomerRepository
var content = await response.Content.ReadAsStringAsync(); var content = await response.Content.ReadAsStringAsync();
var pagingResponse = new PagingResponse<CompanyDto> var pagingResponse = new PagingResponse<CompanyDto>
{ {
Items = JsonSerializer.Deserialize<List<CompanyDto>>(content, _options) ?? new List<CompanyDto>(), Items = JsonSerializer.Deserialize<List<CompanyDto>>(content, _options),
MetaData = JsonSerializer.Deserialize<MetaData>(response.Headers.GetValues("X-Pagination").First(), _options) ?? new MetaData() MetaData = JsonSerializer.Deserialize<MetaData>(response.Headers.GetValues("X-Pagination").First(), _options)
}; };
return pagingResponse; return pagingResponse;
} }
@ -91,8 +91,7 @@ public class CountryCustomerRepository : ICountryCustomerRepository
/// <param name="salesRepId"></param> /// <param name="salesRepId"></param>
/// <param name="paging"></param> /// <param name="paging"></param>
/// <returns></returns> /// <returns></returns>
public async Task<PagingResponse<CompanyDto>> GetCompaniesPaged(string countryCode, string salesRepId, public async Task<PagingResponse<CompanyDto>> GetCompaniesPaged(string countryCode, string salesRepId, CustomerPaging paging)
CustomerPaging paging)
{ {
var queryDictionary = new Dictionary<string, string> var queryDictionary = new Dictionary<string, string>
{ {

View file

@ -42,6 +42,16 @@
@CountryCode.ToUpper()-@Activity.DlvZipCode @Activity.DlvCity @CountryCode.ToUpper()-@Activity.DlvZipCode @Activity.DlvCity
</div> </div>
</div> </div>
<div class="card-body">
<div class="row">
<div class="col">
<label for="acceptCondition">Accepter betingelser</label>
<InputCheckbox id="acceptCondition" class="form-check-input" bind-Value="@ConditionsAccepted" bind-Value:event="onchange"></InputCheckbox>
<button class="btn btn-primary" @onclick="CreateActivity">Send Bestilling</button>
<button class="btn btn-secondary" onclick="history.back()">Tilbage</button>
</div>
</div>
</div>
<div class="card-body"> <div class="card-body">
<div class="list-group-item"> <div class="list-group-item">
<div class="row"> <div class="row">
@ -71,4 +81,15 @@
} }
</div> </div>
</div> </div>
<div class="card-body">
<div class="list-group">
<div class="list-group-item-info">Bestillingen følger de til enhver tid gældende listepriser</div>
<div class="list-group-item-info">Individuelle aftaler honoreres</div>
<div class="list-group-item-info">Priser tillægges moms og afgifter</div>
<div class="list-group-item-info">Ved tvivl om gældede priser kontaktes Innotec's konsulent</div>
<div class="list-group-item-info">Fragt og Leveringomkostninger tillægges</div>
<div class="list-group-item-info">Betaling netto kontant</div>
<div class="list-group-item-info">Varer forbliver Innotec's ejendom til betaling er modtaget</div>
</div>
</div>
</div> </div>

View file

@ -40,6 +40,7 @@ public partial class BusinessOrderViewPage
private ActivityDto Activity { get; set; } = new(); private ActivityDto Activity { get; set; } = new();
private DateTime SelectedDate { get; set; } private DateTime SelectedDate { get; set; }
private bool Working { get; set; } = true; private bool Working { get; set; } = true;
private bool ConditionsAccepted { get; set; }
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
@ -83,7 +84,7 @@ public partial class BusinessOrderViewPage
Activity.BcId = _businessInfo.BcId; Activity.BcId = _businessInfo.BcId;
Activity.CompanyId = _businessInfo.CompanyId; Activity.CompanyId = _businessInfo.CompanyId;
// assign activity properties // assign activity properties
// var lineNo = 0; // var lineNo = 0;
// foreach (var item in DraftProvider.Draft.Items) // foreach (var item in DraftProvider.Draft.Items)
// { // {

View file

@ -21,7 +21,6 @@ using Wonky.Client.HttpRepository;
using Wonky.Client.Local.Services; using Wonky.Client.Local.Services;
using Wonky.Entity.DTO; using Wonky.Entity.DTO;
using Wonky.Entity.Requests; using Wonky.Entity.Requests;
using Wonky.Entity.Views;
#pragma warning disable CS8618 #pragma warning disable CS8618
namespace Wonky.Client.Pages; namespace Wonky.Client.Pages;
@ -40,7 +39,7 @@ public partial class OfficeCustomerCountryPagedListPage : IDisposable
[Parameter] public string CountryCode { get; set; } = ""; [Parameter] public string CountryCode { get; set; } = "";
// ############################################################# // #############################################################
private List<CompanyDto> Companies { get; set; } = new(); private List<CompanyDto> Companies { get; set; } = [];
private UserPreference Preference { get; set; } = new(); private UserPreference Preference { get; set; } = new();
private UserManagerEditView XUserInfo { get; set; } = new(); private UserManagerEditView XUserInfo { get; set; } = new();
private string SavedSearch { get; set; } = ""; private string SavedSearch { get; set; } = "";
@ -50,11 +49,11 @@ public partial class OfficeCustomerCountryPagedListPage : IDisposable
private CustomerPaging Paging { get; set; } = new(); private CustomerPaging Paging { get; set; } = new();
private string ToggleFoldedText { get; set; } = "Vis Lukkede"; private string ToggleFoldedText { get; set; } = "Vis Lukkede";
protected override async Task OnParametersSetAsync() protected override Task OnParametersSetAsync()
{ {
Interceptor.RegisterEvent(); Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent(); Interceptor.RegisterBeforeSendEvent();
await FetchCustomers(); return FetchCustomers();
} }
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
@ -71,8 +70,12 @@ public partial class OfficeCustomerCountryPagedListPage : IDisposable
Paging.HasFolded = ShowFolded ? 1 : 0; Paging.HasFolded = ShowFolded ? 1 : 0;
// load saved search // load saved search
SavedSearch = string.IsNullOrWhiteSpace(Preference.CompanyFilterPhrase) ? "" : Preference.CompanyFilterPhrase; SavedSearch = string.IsNullOrWhiteSpace(Preference.CompanyFilterPhrase)
? ""
: Preference.CompanyFilterPhrase;
await SetSearchPhrase(SavedSearch); await SetSearchPhrase(SavedSearch);
Working = false; Working = false;
} }
@ -93,70 +96,70 @@ public partial class OfficeCustomerCountryPagedListPage : IDisposable
} }
else else
{ {
Companies = new List<CompanyDto>(); Companies = [];
PageData = new MetaData(); PageData = new MetaData();
} }
Working = false; Working = false;
} }
private async Task ToggleFolded() private Task ToggleFolded()
{ {
Working = true; Working = true;
ShowFolded = !ShowFolded; ShowFolded = !ShowFolded;
ToggleFoldedText = ShowFolded ? "Normal Visning" : "Vis Lukkede"; ToggleFoldedText = ShowFolded ? "Normal Visning" : "Vis Lukkede";
Companies = new List<CompanyDto>(); Companies = [];
Paging.PageNumber = 1; Paging.PageNumber = 1;
Paging.HasFolded = ShowFolded ? 1 : 0; Paging.HasFolded = ShowFolded ? 1 : 0;
await FetchCustomers(); return FetchCustomers();
} }
private async Task SetSelectedPage(int page) private Task SetSelectedPage(int page)
{ {
Working = true; Working = true;
Companies = new List<CompanyDto>(); Companies = new List<CompanyDto>();
Paging.PageNumber = page; Paging.PageNumber = page;
await FetchCustomers(); return FetchCustomers();
} }
private async Task SetSearchCol(string searchColumn) private Task SetSearchCol(string searchColumn)
{ {
Working = true; Working = true;
Companies = new List<CompanyDto>(); Companies = [];
Paging.SearchColumn = searchColumn; Paging.SearchColumn = searchColumn;
Paging.PageNumber = 1; Paging.PageNumber = 1;
await FetchCustomers(); return FetchCustomers();
} }
private async Task SetPageSize(string pageSize) private Task SetPageSize(string pageSize)
{ {
Working = true; Working = true;
Companies = new List<CompanyDto>(); Companies = [];
Paging.PageSize = Convert.ToInt32(pageSize); Paging.PageSize = Convert.ToInt32(pageSize);
Paging.PageNumber = 1; Paging.PageNumber = 1;
await FetchCustomers(); return FetchCustomers();
} }
private async Task SetSearchPhrase(string searchTerm) private Task SetSearchPhrase(string searchTerm)
{ {
Working = true; Working = true;
Companies = new List<CompanyDto>(); Companies = [];
Paging.PageNumber = 1; Paging.PageNumber = 1;
Paging.SearchTerm = searchTerm; Paging.SearchTerm = searchTerm;
await FetchCustomers(); return FetchCustomers();
} }
private async Task SetSortCol(string orderBy) private Task SetSortCol(string orderBy)
{ {
Working = true; Working = true;
Companies = new List<CompanyDto>(); Companies = [];
Paging.OrderBy = orderBy; Paging.OrderBy = orderBy;
await FetchCustomers(); return FetchCustomers();
} }

View file

@ -50,6 +50,8 @@ builder.Services.AddHttpClient("inno-api", (sp, cl) =>
builder.Services.AddBlazoredToast(); builder.Services.AddBlazoredToast();
builder.Services.AddHttpClientInterceptor(); builder.Services.AddHttpClientInterceptor();
builder.Services.AddHotKeys2();
// api config object // api config object
builder.Services.Configure<ApiConfig>(builder.Configuration.GetSection("ApiConfig")); builder.Services.Configure<ApiConfig>(builder.Configuration.GetSection("ApiConfig"));
// app info object // app info object

View file

@ -19,6 +19,7 @@
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Configuration" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging.Configuration" Version="8.0.0" />
<PackageReference Include="Toolbelt.Blazor.HotKeys2" Version="3.2.1" />
<PackageReference Include="Toolbelt.Blazor.HttpClientInterceptor" Version="10.2.0" /> <PackageReference Include="Toolbelt.Blazor.HttpClientInterceptor" Version="10.2.0" />
</ItemGroup> </ItemGroup>

View file

@ -1,7 +1,7 @@
{ {
"appInfo": { "appInfo": {
"name": "Wonky Online", "name": "Wonky Online",
"version": "316.0", "version": "316.1",
"rc": false, "rc": false,
"sandBox": true, "sandBox": true,
"image": "grumpy-coder.png", "image": "grumpy-coder.png",

View file

@ -3,6 +3,10 @@
/*background-color: #eeeeee;*/ /*background-color: #eeeeee;*/
} }
.office-customer-paged {
left: 0;
width: 100%;
}
.draft-expires-msg { .draft-expires-msg {
font-size: 0.8em; font-size: 0.8em;
} }