adding product catalog without price for b2b product lookup

refactor namespace to distinguish better product catalog from price catalog
This commit is contained in:
Frede Hundewadt 2023-10-29 04:29:27 +01:00
parent 614df811a2
commit 2b65bfe8d2
28 changed files with 514 additions and 90 deletions

View file

@ -37,7 +37,7 @@ public partial class AdvisorLandingComponent
[Inject] public UserPreferenceService PreferenceService { get; set; } [Inject] public UserPreferenceService PreferenceService { get; set; }
[Inject] public ICabinetDrawerService CabinetDrawerService { get; set; } [Inject] public ICabinetDrawerService CabinetDrawerService { get; set; }
[Inject] public IUserInfoService UserInfo { get; set; } [Inject] public IUserInfoService UserInfo { get; set; }
[Inject] public ICountryCatalogRepository CatalogRepo { get; set; } [Inject] public ICountryPriceCatalogRepository PriceCatalogRepo { get; set; }
// ############################################################## // ##############################################################

View file

@ -26,7 +26,7 @@ using Wonky.Entity.Views;
namespace Wonky.Client.HttpRepository; namespace Wonky.Client.HttpRepository;
public class CountryCatalogRepository : ICountryCatalogRepository public class CountryPriceCatalogRepository : ICountryPriceCatalogRepository
{ {
private readonly JsonSerializerOptions _options = new JsonSerializerOptions private readonly JsonSerializerOptions _options = new JsonSerializerOptions
{ {
@ -34,12 +34,12 @@ public class CountryCatalogRepository : ICountryCatalogRepository
}; };
private readonly NavigationManager _navigation; private readonly NavigationManager _navigation;
private ILogger<CountryCatalogRepository> _logger; private ILogger<CountryPriceCatalogRepository> _logger;
private readonly HttpClient _client; private readonly HttpClient _client;
private readonly ApiConfig _api; private readonly ApiConfig _api;
public CountryCatalogRepository(HttpClient client, public CountryPriceCatalogRepository(HttpClient client,
ILogger<CountryCatalogRepository> logger, ILogger<CountryPriceCatalogRepository> logger,
NavigationManager navigation, IOptions<ApiConfig> configuration) NavigationManager navigation, IOptions<ApiConfig> configuration)
{ {
_client = client; _client = client;
@ -57,7 +57,7 @@ public class CountryCatalogRepository : ICountryCatalogRepository
public async Task<List<SalesItemView>> GetPriceList(string countryCode) public async Task<List<SalesItemView>> GetPriceList(string countryCode)
{ {
var result = await _client.GetFromJsonAsync<List<SalesItemView>>( var result = await _client.GetFromJsonAsync<List<SalesItemView>>(
$"{_api.Catalog}/{countryCode}", _options); $"{_api.CountryPriceCatalog}/{countryCode}", _options);
return result ?? new List<SalesItemView>(); return result ?? new List<SalesItemView>();
} }
@ -80,7 +80,7 @@ public class CountryCatalogRepository : ICountryCatalogRepository
["selectGroup"] = pager.SelectGroup == "0" ? "" : pager.SelectGroup ["selectGroup"] = pager.SelectGroup == "0" ? "" : pager.SelectGroup
}; };
var endpoint = WebUtils.QueryHelper($"{_api.Catalog}/{countryCode}/page", queryDictionary); var endpoint = WebUtils.QueryHelper($"{_api.CountryPriceCatalog}/{countryCode}/page", queryDictionary);
var response = await _client.GetAsync(endpoint); var response = await _client.GetAsync(endpoint);
if (!response.IsSuccessStatusCode) if (!response.IsSuccessStatusCode)
@ -111,7 +111,7 @@ public class CountryCatalogRepository : ICountryCatalogRepository
/// <returns></returns> /// <returns></returns>
public async Task<SalesItemView> GetSalesItemSku(string countryCode, string sku) public async Task<SalesItemView> GetSalesItemSku(string countryCode, string sku)
{ {
var salesItem = await _client.GetFromJsonAsync<SalesItemView>($"{_api.Catalog}/{countryCode}/sku/{sku}"); var salesItem = await _client.GetFromJsonAsync<SalesItemView>($"{_api.CountryPriceCatalog}/{countryCode}/sku/{sku}");
return salesItem ?? new SalesItemView(); return salesItem ?? new SalesItemView();
} }
@ -124,7 +124,7 @@ public class CountryCatalogRepository : ICountryCatalogRepository
public async Task<ProductDetailView> GetProductDetailView(string salesItemId) public async Task<ProductDetailView> GetProductDetailView(string salesItemId)
{ {
var detailView = await _client var detailView = await _client
.GetFromJsonAsync<ProductDetailView>($"{_api.Catalog}/{salesItemId}"); .GetFromJsonAsync<ProductDetailView>($"{_api.CountryPriceCatalog}/{salesItemId}");
return detailView ?? new ProductDetailView(); return detailView ?? new ProductDetailView();
} }
@ -137,7 +137,7 @@ public class CountryCatalogRepository : ICountryCatalogRepository
public async Task<ProductDetailView> GetVariantDetailView(string variantId) public async Task<ProductDetailView> GetVariantDetailView(string variantId)
{ {
var detailView = await _client var detailView = await _client
.GetFromJsonAsync<ProductDetailView>($"{_api.Catalog}/variant/{variantId}"); .GetFromJsonAsync<ProductDetailView>($"{_api.CountryPriceCatalog}/variant/{variantId}");
return detailView ?? new ProductDetailView(); return detailView ?? new ProductDetailView();
} }
} }

View file

@ -0,0 +1,143 @@
// 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.Net.Http.Json;
using System.Text;
using System.Text.Json;
using Wonky.Client.Features;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Options;
using Wonky.Client.Helpers;
using Wonky.Entity.Configuration;
using Wonky.Entity.Requests;
using Wonky.Entity.Views;
namespace Wonky.Client.HttpRepository;
public class CountryProductCatalogRepository : ICountryProductCatalogRepository
{
private readonly JsonSerializerOptions _options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
private readonly NavigationManager _navigation;
private ILogger<CountryProductCatalogRepository> _logger;
private readonly HttpClient _client;
private readonly ApiConfig _api;
public CountryProductCatalogRepository(HttpClient client,
ILogger<CountryProductCatalogRepository> logger,
NavigationManager navigation, IOptions<ApiConfig> configuration)
{
_client = client;
_logger = logger;
_navigation = navigation;
_api = configuration.Value;
}
/// <summary>
/// Complete catalog for print country
/// </summary>
/// <param name="countryCode"></param>
/// <returns></returns>
public async Task<List<ProductItemView>> GetProductList(string countryCode)
{
var result = await _client.GetFromJsonAsync<List<ProductItemView>>(
$"{_api:CountryProductCatalog}/{countryCode}", _options);
return result ?? new List<ProductItemView>();
}
/// <summary>
/// Get a paged sales item list
/// </summary>
/// <param name="countryCode"></param>
/// <param name="pager"></param>
/// <returns></returns>
public async Task<PagingResponse<ProductItemView>> GetProductItemsPaged(string countryCode, CatalogPager pager)
{
var queryDictionary = new Dictionary<string, string>
{
["pageNumber"] = pager.PageNumber.ToString(),
["pageSize"] = pager.PageSize.ToString(),
["orderBy"] = pager.OrderBy,
["searchColumn"] = pager.SearchColumn,
["searchTerm"] = pager.SearchTerm,
["selectGroup"] = pager.SelectGroup == "0" ? "" : pager.SelectGroup
};
var endpoint = WebUtils.QueryHelper($"{_api:CountryProductCatalog}/{countryCode}/page", queryDictionary);
var response = await _client.GetAsync(endpoint);
if (!response.IsSuccessStatusCode)
{
return new PagingResponse<ProductItemView>
{
Items = new List<ProductItemView>(),
MetaData = new MetaData()
};
}
var content = await response.Content.ReadAsStringAsync();
var pagingResponse = new PagingResponse<ProductItemView>
{
Items = JsonSerializer.Deserialize<List<ProductItemView>>(content, _options),
MetaData = JsonSerializer.Deserialize<MetaData>(
response.Headers.GetValues("X-Pagination").First(), _options)
};
return pagingResponse;
}
/// <summary>
/// Overload Get sales item by sku and country code
/// </summary>
/// <param name="sku"></param>
/// <param name="countryCode"></param>
/// <returns></returns>
public async Task<ProductItemView> GetProductItemSku(string countryCode, string sku)
{
var salesItem = await _client.GetFromJsonAsync<ProductItemView>($"{_api:CountryProductCatalog}/{countryCode}/sku/{sku}");
return salesItem ?? new ProductItemView();
}
/// <summary>
/// Get sales item by id
/// </summary>
/// <param name="salesItemId"></param>
/// <returns></returns>
public async Task<ProductDetailView> GetProductDetailView(string salesItemId)
{
var detailView = await _client
.GetFromJsonAsync<ProductDetailView>($"{_api:CountryProductCatalog}/{salesItemId}");
return detailView ?? new ProductDetailView();
}
/// <summary>
/// Get sales item by variant id
/// </summary>
/// <param name="variantId"></param>
/// <returns></returns>
public async Task<ProductDetailView> GetVariantDetailView(string variantId)
{
var detailView = await _client
.GetFromJsonAsync<ProductDetailView>($"{_api:CountryProductCatalog}/variant/{variantId}");
return detailView ?? new ProductDetailView();
}
}

View file

@ -35,4 +35,6 @@ public class ExternalProductRepository : IExternalProductRepository
.GetFromJsonAsync<List<ExternalProductListView>>(_api.PublicProducts, _options); .GetFromJsonAsync<List<ExternalProductListView>>(_api.PublicProducts, _options);
return result ?? new List<ExternalProductListView>(); return result ?? new List<ExternalProductListView>();
} }
} }

View file

@ -20,9 +20,9 @@ using Wonky.Entity.Views;
namespace Wonky.Client.HttpRepository; namespace Wonky.Client.HttpRepository;
/// <summary> /// <summary>
/// Interface Catalog Http repository /// Interface CountryPriceCatalog Http repository
/// </summary> /// </summary>
public interface ICountryCatalogRepository public interface ICountryPriceCatalogRepository
{ {
/// <summary> /// <summary>
/// Complete catalog for print country /// Complete catalog for print country

View file

@ -0,0 +1,67 @@
// 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.Features;
using Wonky.Entity.Requests;
using Wonky.Entity.Views;
namespace Wonky.Client.HttpRepository;
/// <summary>
/// Interface CountryPriceCatalog Http repository
/// </summary>
public interface ICountryProductCatalogRepository
{
/// <summary>
/// Complete catalog for print country
/// </summary>
/// <param name="countryCode"></param>
/// <returns></returns>
Task<List<ProductItemView>> GetProductList(string countryCode);
/// <summary>
/// Get a paged sales item list
/// </summary>
/// <param name="countryCode"></param>
/// <param name="pager"></param>
/// <returns></returns>
Task<PagingResponse<ProductItemView>> GetProductItemsPaged(string countryCode, CatalogPager pager);
/// <summary>
/// Overload Get sales item by sku and country code
/// </summary>
/// <param name="sku"></param>
/// <param name="countryCode"></param>
/// <returns></returns>
Task<ProductItemView> GetProductItemSku(string countryCode, string sku);
/// <summary>
/// Get sales item by id
/// </summary>
/// <param name="salesItemId"></param>
/// <returns></returns>
Task<ProductDetailView> GetProductDetailView(string salesItemId);
/// <summary>
/// Get sales item by variant id
/// </summary>
/// <param name="variantId"></param>
/// <returns></returns>
Task<ProductDetailView> GetVariantDetailView(string variantId);
}

View file

@ -17,19 +17,19 @@ public class CabinetDrawerService : ICabinetDrawerService
private readonly IAdvisorActivityRepository _activityRepo; private readonly IAdvisorActivityRepository _activityRepo;
private readonly IAdvisorCustomerRepository _customerRepo; private readonly IAdvisorCustomerRepository _customerRepo;
private readonly IAdvisorCustomerHistoryRepository _historyRepo; private readonly IAdvisorCustomerHistoryRepository _historyRepo;
private readonly ICountryCatalogRepository _catalogRepo; private readonly ICountryPriceCatalogRepository _priceCatalogRepo;
public CabinetDrawerService( public CabinetDrawerService(
ILogger<CabinetDrawerService> logger, ILogger<CabinetDrawerService> logger,
ILocalStorageService asyncStorageService, ILocalStorageService asyncStorageService,
ICountryCatalogRepository catalogRepo, ICountryPriceCatalogRepository priceCatalogRepo,
IAdvisorCustomerHistoryRepository historyRepo, IAdvisorCustomerHistoryRepository historyRepo,
IAdvisorCustomerRepository customerRepo, IAdvisorCustomerRepository customerRepo,
IAdvisorActivityRepository activityRepo) IAdvisorActivityRepository activityRepo)
{ {
_logger = logger; _logger = logger;
_asyncStorageService = asyncStorageService; _asyncStorageService = asyncStorageService;
_catalogRepo = catalogRepo; _priceCatalogRepo = priceCatalogRepo;
_historyRepo = historyRepo; _historyRepo = historyRepo;
_customerRepo = customerRepo; _customerRepo = customerRepo;
_activityRepo = activityRepo; _activityRepo = activityRepo;
@ -60,7 +60,7 @@ public class CabinetDrawerService : ICabinetDrawerService
if (drawer == null) force = true; if (drawer == null) force = true;
if (!force) return drawer ?? new CatalogDrawer(); if (!force) return drawer ?? new CatalogDrawer();
var result = await _catalogRepo.GetPriceList(countryCode); var result = await _priceCatalogRepo.GetPriceList(countryCode);
drawer = new CatalogDrawer drawer = new CatalogDrawer
{ {
LastDateModified = DateTime.Today, LastDateModified = DateTime.Today,

View file

@ -4,7 +4,7 @@ namespace Wonky.Client.Models;
public class CatalogDrawer public class CatalogDrawer
{ {
public const string Label = "Catalog"; public const string Label = "CountryPriceCatalog";
public DateTime LastDateModified { get; set; } public DateTime LastDateModified { get; set; }
public List<SalesItemView> Content { get; set; } = new(); public List<SalesItemView> Content { get; set; } = new();
} }

View file

@ -0,0 +1,66 @@
@* 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]
*@
<div class="modal" tabindex="-1" role="dialog" style="display:@_modalDisplay">
<div class="modal-dialog modal-dialog-scrollable modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">@ProductName</h5>
<button type="button" class="btn btn-danger" @onclick="@Hide" data-bs-dismiss="modal" aria-label="Luk">
<i class="bi-x-lg"></i>
</button>
</div>
<div class="modal-body">
<div class="alert alert-info">
Antallet er et forslag baseret på sidste køb.<br />
Priser er historiske priser.<br />
Kontakt venligst din konsulent for oplysning om gældende listepris.
</div>
<div class="row">
<label class="col-sm-2 col-form-label">Bestil antal</label>
<div class="col">
<InputNumber class="form-control" @bind-Value="@_qty" />
</div>
<div class="col">
<button class="btn btn-primary" @onclick="@SubmitItem">Læg til kladde</button>
</div>
</div>
<table class="table table-striped">
<thead>
<tr>
<th scope="col">Dato</th>
<th scope="col">Antal</th>
<th scope="col">Pris</th>
</tr>
</thead>
<tbody>
@foreach (var entry in ProductHistory)
{
<tr>
<td>@entry.DeliveryDate</td>
<td>@entry.Quantity</td>
<td>@entry.Price</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>
</div>
@if (_showBackdrop)
{
<div class="modal-backdrop fade show"></div>
}

View file

@ -0,0 +1,77 @@
// 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.HttpRepository;
using Wonky.Client.Models;
using Wonky.Entity.Views;
#pragma warning disable CS8618
namespace Wonky.Client.OverlayB2B;
public partial class B2BGetOrderQuantityOverlay
{
// ##############################################################
[Inject] public IB2BRepository HistoryRepo { get; set; }
// ##############################################################
[Parameter] public string ProductName { get; set; } = "";
[Parameter] public ItemSelect SelectedItem { get; set; } = new();
[Parameter] public EventCallback<ItemSelect> OnSelected { get; set; }
[Parameter] public List<ProductHistoryView> ProductHistory { get; set; } = new();
// ##############################################################
private string _modalDisplay = "";
private bool _showBackdrop;
private int _qty = 1;
private ItemSelect _selectedItem = new();
protected override void OnParametersSet()
{
_selectedItem = SelectedItem;
if (!string.IsNullOrWhiteSpace(_selectedItem.Quantity))
{
_qty = int.Parse(_selectedItem.Quantity);
}
}
private async Task SubmitItem()
{
Console.WriteLine($"_qty => {_qty}");
_selectedItem.Quantity = $"{_qty}";
await OnSelected.InvokeAsync(_selectedItem);
Hide();
}
public void Show()
{
_modalDisplay = "block;";
_showBackdrop = true;
// StateHasChanged();
}
private void Hide()
{
_modalDisplay = "none;";
_showBackdrop = false;
// StateHasChanged();
}
}

View file

@ -32,7 +32,7 @@ public partial class B2BProductPriceHistoryOverlay
[Parameter] public string Sku { get; set; } = ""; [Parameter] public string Sku { get; set; } = "";
// ############################################################## // ##############################################################
private List<ProductHistoryView>? ProductHistory { get; set; } private List<ProductHistoryView> ProductHistory { get; set; } = new();
private string ProductName { get; set; } = ""; private string ProductName { get; set; } = "";
private string _modalDisplay = ""; private string _modalDisplay = "";
private bool _showBackdrop; private bool _showBackdrop;
@ -43,7 +43,7 @@ public partial class B2BProductPriceHistoryOverlay
return; return;
ProductHistory = await HistoryRepo.GetCustomerProductHistory(CompanyId, Sku); ProductHistory = await HistoryRepo.GetCustomerProductHistory(CompanyId, Sku);
if (ProductHistory.Any()) if (ProductHistory.Count > 0)
{ {
ProductName = ProductHistory[0].Description; ProductName = ProductHistory[0].Description;
} }

View file

@ -30,7 +30,7 @@ public partial class CustomerInventoryListOverlay : IDisposable
*/ */
[Inject] public ILogger<CustomerInventoryListOverlay> Logger { get; set; } [Inject] public ILogger<CustomerInventoryListOverlay> Logger { get; set; }
[Inject] public HttpInterceptorService Interceptor { get; set; } [Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public ICountryCatalogRepository CatalogRepo { get; set; } [Inject] public ICountryPriceCatalogRepository PriceCatalogRepo { get; set; }
/* /*
* Parameters * Parameters
*/ */
@ -81,7 +81,7 @@ public partial class CustomerInventoryListOverlay : IDisposable
/// <param name="sku"></param> /// <param name="sku"></param>
private async Task OnReorderCallback(string sku) private async Task OnReorderCallback(string sku)
{ {
SalesItem = await CatalogRepo.GetSalesItemSku(CountryCode.ToLower(), sku); SalesItem = await PriceCatalogRepo.GetSalesItemSku(CountryCode.ToLower(), sku);
ReorderOverlay.Show(); ReorderOverlay.Show();
} }

View file

@ -28,7 +28,7 @@ public partial class OfficeCustomerOrderInventoryListOverlay : IDisposable
{ {
// ############################################################## // ##############################################################
[Inject] public HttpInterceptorService Interceptor { get; set; } [Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public ICountryCatalogRepository CatalogRepo { get; set; } [Inject] public ICountryPriceCatalogRepository PriceCatalogRepo { get; set; }
[Inject] public ILogger<OfficeCustomerOrderInventoryListOverlay> Logger { get; set; } [Inject] public ILogger<OfficeCustomerOrderInventoryListOverlay> Logger { get; set; }
// ############################################################## // ##############################################################
@ -59,7 +59,7 @@ public partial class OfficeCustomerOrderInventoryListOverlay : IDisposable
private async Task OnReorderCallback(string sku) private async Task OnReorderCallback(string sku)
{ {
SalesItem = await CatalogRepo.GetSalesItemSku(Company.CountryCode.ToLower(), sku); SalesItem = await PriceCatalogRepo.GetSalesItemSku(Company.CountryCode.ToLower(), sku);
ReorderOverlay.Show(); ReorderOverlay.Show();
} }

View file

@ -30,7 +30,7 @@ namespace Wonky.Client.OverlayOrderCreate;
public partial class CatalogPagedOverlay : IDisposable public partial class CatalogPagedOverlay : IDisposable
{ {
// ############################################################## // ##############################################################
[Inject] public ICountryCatalogRepository CatalogRepo { get; set; } [Inject] public ICountryPriceCatalogRepository PriceCatalogRepo { get; set; }
[Inject] public HttpInterceptorService Interceptor { get; set; } [Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public UserPreferenceService PreferenceService { get; set; } [Inject] public UserPreferenceService PreferenceService { get; set; }
[Inject] public ILogger<CatalogPagedOverlay> Logger { get; set; } [Inject] public ILogger<CatalogPagedOverlay> Logger { get; set; }
@ -64,7 +64,7 @@ public partial class CatalogPagedOverlay : IDisposable
private async Task GetSalesItems() private async Task GetSalesItems()
{ {
var pagingResponse = await CatalogRepo.GetSalesItemsPaged(CountryCode, _pager); var pagingResponse = await PriceCatalogRepo.GetSalesItemsPaged(CountryCode, _pager);
Items = pagingResponse.Items!; Items = pagingResponse.Items!;
PageData = pagingResponse.MetaData; PageData = pagingResponse.MetaData;
Logger.LogDebug("PriceCatalogOverlay => Items <= {}", JsonSerializer.Serialize(Items)); Logger.LogDebug("PriceCatalogOverlay => Items <= {}", JsonSerializer.Serialize(Items));

View file

@ -44,7 +44,7 @@ public partial class AdvisorActivityCreatePage : IDisposable
[Inject] public IToastService Toaster { get; set; } [Inject] public IToastService Toaster { get; set; }
[Inject] public NavigationManager Navigator { get; set; } [Inject] public NavigationManager Navigator { get; set; }
[Inject] public ILocalStorageService Storage { get; set; } [Inject] public ILocalStorageService Storage { get; set; }
[Inject] public ICountryCatalogRepository CatalogRepo { get; set; } [Inject] public ICountryPriceCatalogRepository PriceCatalogRepo { get; set; }
[Inject] public IAdvisorCustomerRepository CompanyRepo { get; set; } [Inject] public IAdvisorCustomerRepository CompanyRepo { get; set; }
[Inject] public IAdvisorActivityRepository ActivityRepo { get; set; } [Inject] public IAdvisorActivityRepository ActivityRepo { get; set; }
[Inject] public IAdvisorSalesReportRepository ReportRepo { get; set; } [Inject] public IAdvisorSalesReportRepository ReportRepo { get; set; }
@ -325,7 +325,7 @@ public partial class AdvisorActivityCreatePage : IDisposable
{ {
return; return;
} }
_selectedItem = await CatalogRepo.GetSalesItemSku(_company.CountryCode, selectedItem.ItemNo); _selectedItem = await PriceCatalogRepo.GetSalesItemSku(_company.CountryCode, selectedItem.ItemNo);
ShowItem = true; ShowItem = true;
Price = selectedItem.Rate; Price = selectedItem.Rate;
Quantity = selectedItem.Quantity; Quantity = selectedItem.Quantity;

View file

@ -44,7 +44,7 @@ public partial class AdvisorCustomerInventoryListPage : IDisposable
[Inject] public HttpInterceptorService Interceptor { get; set; } [Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public IToastService Toaster { get; set; } [Inject] public IToastService Toaster { get; set; }
[Inject] public ILocalStorageService Storage { get; set; } [Inject] public ILocalStorageService Storage { get; set; }
[Inject] public ICountryCatalogRepository CatalogRepo { get; set; } [Inject] public ICountryPriceCatalogRepository PriceCatalogRepo { get; set; }
[Inject] public ICabinetDrawerService DrawerService { get; set; } [Inject] public ICabinetDrawerService DrawerService { get; set; }
/* /*
* Parameters * Parameters
@ -80,7 +80,7 @@ public partial class AdvisorCustomerInventoryListPage : IDisposable
private async Task OnReorderCallback(string sku) private async Task OnReorderCallback(string sku)
{ {
// fetch item from http repo // fetch item from http repo
SalesItem = await CatalogRepo.GetSalesItemSku(Company.CountryCode.ToLower(), sku); SalesItem = await PriceCatalogRepo.GetSalesItemSku(Company.CountryCode.ToLower(), sku);
ReorderOverlay.Show(); ReorderOverlay.Show();
} }

View file

@ -110,7 +110,6 @@
<tr> <tr>
<th scope="col">Sidste køb</th> <th scope="col">Sidste køb</th>
<th scope="col">Forbrug</th> <th scope="col">Forbrug</th>
<th></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -121,17 +120,12 @@
<td> <td>
@product.Quantity @product.Quantity
</td> </td>
<td>
<a role="button" class="btn-link" @onclick="() => ShowProductHistoryOverlay(product.Sku)">
Historik
</a>
</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
<div class="mt-3 d-grid align-content-end"> <div class="mt-3 d-grid align-content-end">
<button type="button" class="btn btn-primary btn-sm" <button type="button" class="btn btn-primary btn-sm"
@onclick="() => ShowProductHistoryOverlay(product.Sku)"> @onclick="() => ShowAddQuantity(product.Sku)">
Genbestil Genbestil
</button> </button>
</div> </div>
@ -141,7 +135,11 @@
</div> </div>
} }
</div> </div>
<B2BProductPriceHistoryOverlay CompanyId="@CompanyId" Sku="@_sku" @ref="PriceHistoryOverlay"/> @* <B2BProductPriceHistoryOverlay CompanyId="@CompanyId" Sku="@_sku" @ref="PriceHistoryOverlay"/> *@
<B2BGetOrderQuantityOverlay SelectedItem="_selectedItem"
ProductHistory="@_productHistory"
ProductName="@_productName"
OnSelected="AddItemToOrder" @ref="GetQuantity" />
} }
else else
{ {

View file

@ -19,14 +19,11 @@ public partial class BusinessCustomerLandingPage : IDisposable
// ############################################################## // ##############################################################
[Inject] public HttpInterceptorService Interceptor { get; set; } [Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public IB2BRepository B2BRepo { get; set; } [Inject] public IB2BRepository B2BRepo { get; set; }
[Inject] public ICountryProductCatalogRepository ProductCatalog { get; set; }
[Inject]
public ICountryCatalogRepository Catalog { get; set; }
[Inject] private IOptions<ApiConfig> Config { get; set; } [Inject] private IOptions<ApiConfig> Config { get; set; }
// ############################################################## // ##############################################################
[CascadingParameter] private DraftStateProvider DraftProvider { get; set; } = new(); [CascadingParameter] private DraftStateProvider DraftProvider { get; set; } = new();
[Parameter] public string CountryCode { get; set; } = ""; [Parameter] public string CountryCode { get; set; } = "";
[Parameter] public string CompanyId { get; set; } = ""; [Parameter] public string CompanyId { get; set; } = "";
@ -39,8 +36,10 @@ public partial class BusinessCustomerLandingPage : IDisposable
private B2BProductPriceHistoryOverlay PriceHistoryOverlay { get; set; } private B2BProductPriceHistoryOverlay PriceHistoryOverlay { get; set; }
private string _price = "0"; private string _price = "0";
private string _quantity = "1"; private string _quantity = "1";
private string _productName = "";
private ItemSelect _selectedItem = new(); private ItemSelect _selectedItem = new();
private string _sku = ""; private string _sku = "";
private B2BGetOrderQuantityOverlay GetQuantity { get; set; }
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
@ -51,41 +50,85 @@ public partial class BusinessCustomerLandingPage : IDisposable
_businessInfo = await B2BRepo.GetBusinessInfo(CompanyId); _businessInfo = await B2BRepo.GetBusinessInfo(CompanyId);
_advisorInfo = await B2BRepo.GetAdvisorInfo(CompanyId); _advisorInfo = await B2BRepo.GetAdvisorInfo(CompanyId);
_productInventory = await B2BRepo.GetCustomerInventory(CompanyId); _productInventory = await B2BRepo.GetCustomerInventory(CompanyId);
if (_productInventory.Any()) if (_productInventory.Count > 0)
{ {
_productInventory = _productInventory _productInventory = _productInventory
.OrderByDescending(x => x.Quantity) .OrderByDescending(x => x.Quantity)
.ToList(); .ToList();
} }
DraftProvider.Draft.DraftId = CompanyId;
await DraftProvider.SaveChangesAsync();
} }
private async Task AddItemToOrder(string sku) private async Task RemoveItem(string sku)
{ {
var item = await Catalog.GetSalesItemSku(CountryCode, sku); var draftItem = DraftProvider.Draft.Items.Where(x => x.Item.Sku == sku).ToList()[0];
var history = await B2BRepo.GetCustomerProductHistory(CompanyId, sku); DraftProvider.Draft.Items.Remove(draftItem);
var line = history await DraftProvider.SaveChangesAsync();
.OrderByDescending(x => x.DeliveryDate) }
.Where(x => x.Price != 0).Take(1).ToList()[0];
DraftProvider.Draft.DraftId = CompanyId;
DraftProvider.Draft.Items.Add( private async Task ShowAddQuantity(string sku)
new DraftItem() {
_productHistory = await B2BRepo.GetCustomerProductHistory(CompanyId, sku);
_productName = _productHistory[0].Description;
_selectedItem = new ItemSelect
{
ItemNo = sku,
Quantity = $"{_productHistory[0].Quantity}",
Rate = $"{_productHistory[0].Price}",
};
GetQuantity.Show();
}
private async Task AddItemToOrder(ItemSelect selectedItem)
{
var draftItem = DraftProvider.Draft.Items.FirstOrDefault(x => x.Item.Sku == selectedItem.ItemNo);
if (draftItem is not null)
{
draftItem.Quantity += int.Parse(selectedItem.Quantity);
}
else
{
var pItem = await ProductCatalog.GetProductItemSku(CountryCode, selectedItem.ItemNo);
var item = new SalesItemView
{ {
Price = line.Price, Sku = pItem.Sku,
Quantity = line.Quantity, Discontinued = pItem.Discontinued,
Discount = 0, Location = pItem.Location,
Sas = false, Name = pItem.Name,
Item = item BoxSize = pItem.BoxSize,
}); OnDemand = pItem.OnDemand,
PictureLink = pItem.PictureLink,
ProductGroup = pItem.ProductGroup,
ShortName = pItem.ShortName,
VariantId = pItem.VariantId,
SalesItemId = pItem.SalesItemId,
Rates = new List<SalesRateView>(),
};
DraftProvider.Draft.Items.Add(
new DraftItem
{
Price = decimal.Parse(selectedItem.Rate),
Quantity = int.Parse(selectedItem.Quantity),
Discount = 0,
Sas = false,
Item = item
});
}
await DraftProvider.SaveChangesAsync(); await DraftProvider.SaveChangesAsync();
} }
private void ShowProductHistoryOverlay(string sku) // private void ShowProductHistoryOverlay(string sku)
{ // {
_sku = sku; // _sku = sku;
PriceHistoryOverlay.Show(); // PriceHistoryOverlay.Show();
} // }
// private async Task PriceCatalogOverlayCallback(ItemSelect selectedItem) // private async Task PriceCatalogOverlayCallback(ItemSelect selectedItem)
@ -95,7 +138,7 @@ public partial class BusinessCustomerLandingPage : IDisposable
// { // {
// return; // return;
// } // }
// _selectedItem = await CatalogRepo.GetSalesItemSku(_company.CountryCode, selectedItem.ItemNo); // _selectedItem = await PriceCatalogRepo.GetSalesItemSku(_company.CountryCode, selectedItem.ItemNo);
// ShowItem = true; // ShowItem = true;
// Price = selectedItem.Rate; // Price = selectedItem.Rate;
// Quantity = selectedItem.Quantity; // Quantity = selectedItem.Quantity;
@ -103,18 +146,6 @@ public partial class BusinessCustomerLandingPage : IDisposable
// } // }
private void PriceHistoryOverlayCallback(decimal price)
{
if (price == 0)
{
return;
}
_price = price.ToString("N2", CultureInfo.InvariantCulture);
StateHasChanged();
}
public void Dispose() public void Dispose()
{ {
Interceptor.DisposeEvent(); Interceptor.DisposeEvent();

View file

@ -19,7 +19,7 @@ public partial class BusinessOrderViewPage
[Inject] public IB2BRepository B2BRepo { get; set; } [Inject] public IB2BRepository B2BRepo { get; set; }
[Inject] [Inject]
public ICountryCatalogRepository Catalog { get; set; } public ICountryPriceCatalogRepository PriceCatalog { get; set; }
[Inject] private IOptions<ApiConfig> Config { get; set; } [Inject] private IOptions<ApiConfig> Config { get; set; }
// ############################################################## // ##############################################################

View file

@ -32,7 +32,7 @@ public partial class CatalogCountryPagedListPage : IDisposable
{ {
// ############################################################## // ##############################################################
[Inject] public ILocalStorageService Storage { get; set; } [Inject] public ILocalStorageService Storage { get; set; }
[Inject] public ICountryCatalogRepository Catalog { get; set; } [Inject] public ICountryPriceCatalogRepository PriceCatalog { get; set; }
[Inject] public HttpInterceptorService Interceptor { get; set; } [Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public UserPreferenceService PreferenceService { get; set; } [Inject] public UserPreferenceService PreferenceService { get; set; }
[Inject] public ILogger<CatalogCountryPagedListPage> Logger { get; set; } [Inject] public ILogger<CatalogCountryPagedListPage> Logger { get; set; }
@ -85,7 +85,7 @@ public partial class CatalogCountryPagedListPage : IDisposable
if (Working) if (Working)
return; return;
Working = true; Working = true;
var page = await Catalog.GetSalesItemsPaged(CountryCode, Paging); var page = await PriceCatalog.GetSalesItemsPaged(CountryCode, Paging);
Items = page.Items!; Items = page.Items!;
PageData = page.MetaData!; PageData = page.MetaData!;
Working = false; Working = false;

View file

@ -26,7 +26,7 @@ namespace Wonky.Client.Pages;
public partial class CatalogCountryPrintPage : IDisposable public partial class CatalogCountryPrintPage : IDisposable
{ {
[Inject] public ILocalStorageService Storage { get; set; } [Inject] public ILocalStorageService Storage { get; set; }
[Inject] public ICountryCatalogRepository Catalog { get; set; } [Inject] public ICountryPriceCatalogRepository PriceCatalog { get; set; }
[Inject] public HttpInterceptorService Interceptor { get; set; } [Inject] public HttpInterceptorService Interceptor { get; set; }
[Parameter] public string CountryCode { get; set; } = ""; [Parameter] public string CountryCode { get; set; } = "";
private List<SalesItemView> Items { get; set; } = new(); private List<SalesItemView> Items { get; set; } = new();
@ -37,7 +37,7 @@ public partial class CatalogCountryPrintPage : IDisposable
{ {
Interceptor.RegisterEvent(); Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent(); Interceptor.RegisterBeforeSendEvent();
Items = await Catalog.GetPriceList(CountryCode); Items = await PriceCatalog.GetPriceList(CountryCode);
CountryName = Utils.CountryName(CountryCode); CountryName = Utils.CountryName(CountryCode);
Working = false; Working = false;
} }

View file

@ -11,7 +11,7 @@ public partial class CatalogProductDetailPage
{ {
// ############################################################## // ##############################################################
[Inject] public HttpInterceptorService Interceptor { get; set; } [Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public ICountryCatalogRepository Catalog { get; set; } [Inject] public ICountryPriceCatalogRepository PriceCatalog { get; set; }
// ############################################################## // ##############################################################
[Parameter] public string SalesItemId { get; set; } = ""; [Parameter] public string SalesItemId { get; set; } = "";
@ -26,7 +26,7 @@ public partial class CatalogProductDetailPage
Interceptor.RegisterEvent(); Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent(); Interceptor.RegisterBeforeSendEvent();
_item = await Catalog.GetProductDetailView(SalesItemId); _item = await PriceCatalog.GetProductDetailView(SalesItemId);
_working = false; _working = false;
} }
} }

View file

@ -174,7 +174,7 @@
<td class="align-middle text-black text-end fw-bold">@($"{DraftProvider.Draft.Total:N2}")</td> <td class="align-middle text-black text-end fw-bold">@($"{DraftProvider.Draft.Total:N2}")</td>
<td class="align-middle text-end"> <td class="align-middle text-end">
@* @*
***************** Product Catalog overlay ***************************** ***************** Product CountryPricePriceCatalog overlay *****************************
*@ *@
<button class="btn btn-primary" type="button" @onclick="@ShowCatalogOverlay"> <button class="btn btn-primary" type="button" @onclick="@ShowCatalogOverlay">
<i class="bi-plus"></i> Ny linje <i class="bi-plus"></i> Ny linje

View file

@ -40,7 +40,7 @@ public partial class OfficeOrderCreatePage : IDisposable
[Inject] public ILogger<OfficeOrderCreatePage> Logger { get; set; } [Inject] public ILogger<OfficeOrderCreatePage> Logger { get; set; }
[Inject] public IToastService Toaster { get; set; } [Inject] public IToastService Toaster { get; set; }
[Inject] public HttpInterceptorService Interceptor { get; set; } [Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public ICountryCatalogRepository Catalog { get; set; } [Inject] public ICountryPriceCatalogRepository PriceCatalog { get; set; }
[Inject] public ICountryCustomerRepository CustomerRepo { get; set; } [Inject] public ICountryCustomerRepository CustomerRepo { get; set; }
[Inject] public ICountryCustomerHistoryRepository HistoryRepo { get; set; } [Inject] public ICountryCustomerHistoryRepository HistoryRepo { get; set; }
[Inject] public ICountryCustomerActivityRepository CustomerActivityRepo { get; set; } [Inject] public ICountryCustomerActivityRepository CustomerActivityRepo { get; set; }
@ -210,7 +210,7 @@ public partial class OfficeOrderCreatePage : IDisposable
// get selected item // get selected item
if (string.IsNullOrWhiteSpace(selectedItem.ItemNo)) if (string.IsNullOrWhiteSpace(selectedItem.ItemNo))
return; return;
SelectedItem = await Catalog.GetSalesItemSku(CountryCode, selectedItem.ItemNo); SelectedItem = await PriceCatalog.GetSalesItemSku(CountryCode, selectedItem.ItemNo);
ShowItem = true; ShowItem = true;
Price = selectedItem.Rate; Price = selectedItem.Rate;
Quantity = selectedItem.Quantity; Quantity = selectedItem.Quantity;

View file

@ -71,7 +71,8 @@ builder.Services.AddScoped<IExternalProductRepository, ExternalProductRepository
// administrative repositories // administrative repositories
builder.Services.AddScoped<ICountryCustomerHistoryRepository, CountryCustomerHistoryRepository>(); builder.Services.AddScoped<ICountryCustomerHistoryRepository, CountryCustomerHistoryRepository>();
builder.Services.AddScoped<ICountryCustomerActivityRepository, CountryCustomerActivityRepository>(); builder.Services.AddScoped<ICountryCustomerActivityRepository, CountryCustomerActivityRepository>();
builder.Services.AddScoped<ICountryCatalogRepository, CountryCatalogRepository>(); builder.Services.AddScoped<ICountryProductCatalogRepository, CountryProductCatalogRepository>();
builder.Services.AddScoped<ICountryPriceCatalogRepository, CountryPriceCatalogRepository>();
builder.Services.AddScoped<ICountryCustomerRepository, CountryCustomerRepository>(); builder.Services.AddScoped<ICountryCustomerRepository, CountryCustomerRepository>();
builder.Services.AddScoped<ICountryReportRepository, CountryReportRepository>(); builder.Services.AddScoped<ICountryReportRepository, CountryReportRepository>();
builder.Services.AddScoped<ISystemLabelsRepository, SystemLabelsRepository>(); builder.Services.AddScoped<ISystemLabelsRepository, SystemLabelsRepository>();

View file

@ -1,7 +1,7 @@
{ {
"appInfo": { "appInfo": {
"name": "Wonky Online", "name": "Wonky Online",
"version": "258.0", "version": "259.0",
"rc": true, "rc": true,
"sandBox": true, "sandBox": true,
"image": "grumpy-coder.png", "image": "grumpy-coder.png",
@ -22,7 +22,8 @@
"apiConfig": { "apiConfig": {
"assetUrl": "https://files.innotec.dk", "assetUrl": "https://files.innotec.dk",
"baseUrl": "https://dev.innotec.dk", "baseUrl": "https://dev.innotec.dk",
"catalog": "api/v2/catalog/country", "countryPriceCatalog": "api/v2/catalog/country",
"countryPublicCatalog": "api/v2/catalog/public",
"crmCustomers": "api/v2/crm/companies", "crmCustomers": "api/v2/crm/companies",
"crmReports": "api/v2/crm/advisors/reports", "crmReports": "api/v2/crm/advisors/reports",
"crmActivities": "api/v2/crm/advisors/activities", "crmActivities": "api/v2/crm/advisors/activities",

View file

@ -29,9 +29,14 @@ public class ApiConfig
public string BaseUrl { get; set; } = ""; public string BaseUrl { get; set; } = "";
/// <summary> /// <summary>
/// Application uri for product catalog request /// Application uri for price catalog request
/// </summary> /// </summary>
public string Catalog { get; set; } = ""; public string CountryPriceCatalog { get; set; } = "";
/// <summary>
/// Application uri for public product catalog
/// </summary>
public string CountryPublicCatalog { get; set; } = "";
/// <summary> /// <summary>
/// Application uri for activity request /// Application uri for activity request

View file

@ -0,0 +1,33 @@
// 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.Collections.Generic;
namespace Wonky.Entity.Views;
public class ProductItemView
{
public string SalesItemId { get; set; } = "";
public string VariantId { get; set; } = "";
public string Name { get; set; } = "";
public string Sku { get; set; } = "";
public string ShortName { get; set; } = "";
public string ProductGroup { get; set; } = "";
public string PictureLink { get; set; } = "";
public string Location { get; set; } = "";
public bool Discontinued { get; set; }
public bool OnDemand { get; set; }
public int BoxSize { get; set; }
}