Skip to content

Commit 1732166

Browse files
committed
feat: Update POD Upload Report to include Crate tracking
- Changed title and subtitle in PodUploadReport.razor to reflect inclusion of Crate POD tracking. - Updated relevant text to clarify tracking of both product and crate proof of delivery. fix: Enhance User Management search functionality - Changed input type from text to search for better semantics. - Updated search handling to trigger on input change instead of keyup. refactor: Modify PriceService to support live pricing option - Added `useLivePricing` parameter to `GetPricesByBusinessPartnerAsync` method. - Updated logic to conditionally fetch live pricing from SAP. feat: Add new user location in PodInvoiceCreatorLocations - Added new user location mapping for user ID 77. fix: Update PriceController to handle live pricing - Added `useLivePricing` parameter to the PriceController's endpoint for fetching prices. feat: Enhance GetPodUploadStatusHandler to include Crate POD status - Integrated crate POD status retrieval into the existing upload status logic. - Merged product and crate POD information for comprehensive status reporting. feat: Expand GetPricesByBusinessPartnerHandler to include live pricing logic - Implemented logic to fetch live pricing from SAP and fallback to local pricing. - Added detailed logging for pricing retrieval processes. chore: Update GetPricesByBusinessPartnerQuery to include live pricing flag - Added `UseLivePricing` boolean to the query parameters for better control over pricing retrieval. feat: Implement advisory locking for Sales Order posting - Introduced advisory locks to prevent duplicate posting of sales orders to SAP. - Enhanced error handling and logging for sales order posting operations. fix: Update PopulateSAPPricesAsync to use live SAP pricing - Refactored to prioritize live SAP pricing over local catalog prices. - Improved logging to reflect changes in pricing source.
1 parent cab33b9 commit 1732166

11 files changed

Lines changed: 959 additions & 100 deletions

File tree

ShopInventory.Web/Components/Pages/CustomerPortal/CustomerPods.razor

Lines changed: 124 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
@page "/customer-portal/pods"
22
@using ShopInventory.Web.Models
33
@using ShopInventory.Web.Services
4-
@inject IPodService PodService
4+
@using System.Net.Http.Json
5+
@inject HttpClient Http
56
@inject ICustomerPortalSessionService CustomerSession
67
@inject IJSRuntime JSRuntime
78
@inject ILogger<CustomerPods> Logger
@@ -37,7 +38,7 @@
3738
{
3839
<span class="badge bg-light text-dark mt-1" style="font-size: 0.75rem;">
3940
Filtered &mdash; @(linkedAccounts.FirstOrDefault(a => a.CardCode == selectedAccountFilter)?.CardName
40-
?? selectedAccountFilter)
41+
?? selectedAccountFilter)
4142
</span>
4243
}
4344
}
@@ -75,6 +76,18 @@
7576
</div>
7677
</div>
7778
}
79+
else if (isLoading)
80+
{
81+
<div class="cpod-card">
82+
<div class="cpod-auth-state">
83+
<div class="spinner-border" role="status" style="width: 2.5rem; height: 2.5rem;">
84+
<span class="visually-hidden">Loading...</span>
85+
</div>
86+
<h5 class="cpod-empty-title mt-3">Loading PODs</h5>
87+
<p class="cpod-empty-sub">Retrieving proof of delivery records for your account.</p>
88+
</div>
89+
</div>
90+
}
7891
else if (customerInfo != null)
7992
{
8093
@* Date Range Filters *@
@@ -213,6 +226,13 @@
213226
<span class="cpod-record-count">@(podResponse?.TotalCount ?? 0) total</span>
214227
</div>
215228
<div class="cpod-table-wrap">
229+
@if (!string.IsNullOrWhiteSpace(loadErrorMessage))
230+
{
231+
<div class="alert alert-warning m-3 mb-0" role="alert">
232+
@loadErrorMessage
233+
</div>
234+
}
235+
216236
@if (podResponse?.Items?.Any() == true)
217237
{
218238
var groupedPods = podResponse.Items.GroupBy(p => p.InvoiceDocEntry).ToList();
@@ -243,7 +263,7 @@
243263
{
244264
<td rowspan="@pods.Count" class="align-middle">
245265
<span class="cpod-invoice-badge">@(first.InvoiceDocNum > 0 ?
246-
first.InvoiceDocNum.ToString() : "-")</span>
266+
first.InvoiceDocNum.ToString() : "-")</span>
247267
</td>
248268
<td rowspan="@pods.Count" class="align-middle">
249269
<div class="cpod-customer-name">@(first.CardName ?? "-")</div>
@@ -293,7 +313,7 @@
293313
<div class="cpod-mobile-header-block">
294314
<div class="cpod-mobile-label">Invoice #</div>
295315
<span class="cpod-invoice-badge">@(first.InvoiceDocNum > 0 ? first.InvoiceDocNum.ToString()
296-
: "-")</span>
316+
: "-")</span>
297317
</div>
298318
<div class="cpod-mobile-header-block cpod-mobile-customer-block">
299319
<div class="cpod-mobile-label">Customer</div>
@@ -376,7 +396,7 @@
376396
<div class="cpod-pagination">
377397
<span class="cpod-pagination-info">
378398
Showing @((currentPage - 1) * pageSize + 1)@Math.Min(currentPage * pageSize,
379-
podResponse.TotalCount)
399+
podResponse.TotalCount)
380400
of @podResponse.TotalCount
381401
</span>
382402
<div class="cpod-pagination-btns">
@@ -392,7 +412,7 @@
392412
</div>
393413
}
394414
}
395-
else
415+
else if (string.IsNullOrWhiteSpace(loadErrorMessage))
396416
{
397417
<div class="cpod-empty-state">
398418
<div class="cpod-empty-icon">
@@ -1084,7 +1104,7 @@
10841104
private CustomerPortalSession? portalSession;
10851105
private CustomerInfo? customerInfo;
10861106
private PodAttachmentListResponse? podResponse;
1087-
private bool isLoading = false;
1107+
private bool isLoading = true;
10881108
private bool hasLoaded = false;
10891109
private int currentPage = 1;
10901110
private const int pageSize = 20;
@@ -1093,6 +1113,7 @@
10931113
private bool isMultiAccount;
10941114
private string selectedAccountFilter = "";
10951115
private List<LinkedAccountInfo> linkedAccounts = new();
1116+
private string? loadErrorMessage;
10961117

10971118
// Viewer state
10981119
private bool showViewer;
@@ -1107,6 +1128,16 @@
11071128
if (firstRender)
11081129
{
11091130
await LoadCustomerInfo();
1131+
1132+
if (customerInfo != null)
1133+
{
1134+
await LoadData();
1135+
}
1136+
else
1137+
{
1138+
isLoading = false;
1139+
}
1140+
11101141
StateHasChanged();
11111142
}
11121143
}
@@ -1151,6 +1182,88 @@
11511182
return new List<string>();
11521183
}
11531184

1185+
private static PodAttachmentListResponse CreateEmptyPodResponse(int page, int pageSize)
1186+
{
1187+
return new PodAttachmentListResponse
1188+
{
1189+
Items = new List<PodAttachmentItemDto>(),
1190+
TotalCount = 0,
1191+
Page = page,
1192+
PageSize = pageSize,
1193+
HasMore = false
1194+
};
1195+
}
1196+
1197+
private async Task<PodAttachmentListResponse> GetPodsForCurrentScopeAsync(int page)
1198+
{
1199+
var cardCodes = await ResolveCardCodesAsync();
1200+
if (cardCodes.Count == 0)
1201+
{
1202+
loadErrorMessage = "We couldn't determine which account to load PODs for.";
1203+
return CreateEmptyPodResponse(page, pageSize);
1204+
}
1205+
1206+
var queryParams = new List<string>
1207+
{
1208+
$"page={page}",
1209+
$"pageSize={pageSize}",
1210+
$"cardCode={Uri.EscapeDataString(string.Join(",", cardCodes))}"
1211+
};
1212+
1213+
if (fromDate.HasValue)
1214+
{
1215+
queryParams.Add($"fromDate={fromDate.Value:yyyy-MM-dd}");
1216+
}
1217+
1218+
if (toDate.HasValue)
1219+
{
1220+
queryParams.Add($"toDate={toDate.Value:yyyy-MM-dd}");
1221+
}
1222+
1223+
var url = $"api/invoice/pods?{string.Join("&", queryParams)}";
1224+
using var response = await Http.GetAsync(url);
1225+
if (!response.IsSuccessStatusCode)
1226+
{
1227+
var errorBody = await response.Content.ReadAsStringAsync();
1228+
Logger.LogWarning(
1229+
"Customer POD API GET {Url} failed with status {StatusCode}. Response: {ResponseBody}",
1230+
url,
1231+
(int)response.StatusCode,
1232+
errorBody);
1233+
loadErrorMessage = "We couldn't load proof of delivery records right now. Please try again.";
1234+
return CreateEmptyPodResponse(page, pageSize);
1235+
}
1236+
1237+
var responseModel = await response.Content.ReadFromJsonAsync<PodAttachmentListResponse>();
1238+
if (responseModel == null)
1239+
{
1240+
Logger.LogWarning("Customer POD API GET {Url} returned an empty response body", url);
1241+
loadErrorMessage = "We couldn't read the proof of delivery response. Please try again.";
1242+
return CreateEmptyPodResponse(page, pageSize);
1243+
}
1244+
1245+
loadErrorMessage = null;
1246+
return responseModel;
1247+
}
1248+
1249+
private async Task<byte[]?> DownloadPodContentAsync(int docEntry, int attachmentId)
1250+
{
1251+
var url = $"api/invoice/{docEntry}/attachments/{attachmentId}/download";
1252+
using var response = await Http.GetAsync(url);
1253+
if (!response.IsSuccessStatusCode)
1254+
{
1255+
var errorBody = await response.Content.ReadAsStringAsync();
1256+
Logger.LogWarning(
1257+
"Customer POD download {Url} failed with status {StatusCode}. Response: {ResponseBody}",
1258+
url,
1259+
(int)response.StatusCode,
1260+
errorBody);
1261+
return null;
1262+
}
1263+
1264+
return await response.Content.ReadAsByteArrayAsync();
1265+
}
1266+
11541267
private async Task LoadData()
11551268
{
11561269
if (customerInfo == null) return;
@@ -1160,8 +1273,7 @@
11601273
try
11611274
{
11621275
currentPage = 1;
1163-
var cardCodes = await ResolveCardCodesAsync();
1164-
podResponse = await PodService.GetAllPodsForAccountsAsync(currentPage, pageSize, cardCodes, fromDate, toDate);
1276+
podResponse = await GetPodsForCurrentScopeAsync(currentPage);
11651277
hasLoaded = true;
11661278
}
11671279
catch (Exception ex)
@@ -1181,8 +1293,7 @@
11811293

11821294
try
11831295
{
1184-
var cardCodes = await ResolveCardCodesAsync();
1185-
podResponse = await PodService.GetAllPodsForAccountsAsync(currentPage, pageSize, cardCodes, fromDate, toDate);
1296+
podResponse = await GetPodsForCurrentScopeAsync(currentPage);
11861297
}
11871298
catch (Exception ex)
11881299
{
@@ -1213,7 +1324,7 @@
12131324
return;
12141325
}
12151326

1216-
var content = await PodService.DownloadPodAsync(pod.InvoiceDocEntry, pod.Id);
1327+
var content = await DownloadPodContentAsync(pod.InvoiceDocEntry, pod.Id);
12171328
if (content == null || content.Length == 0)
12181329
{
12191330
return;
@@ -1251,7 +1362,7 @@
12511362
isLoadingViewer = true;
12521363
StateHasChanged();
12531364

1254-
var content = await PodService.DownloadPodAsync(pod.InvoiceDocEntry, pod.Id);
1365+
var content = await DownloadPodContentAsync(pod.InvoiceDocEntry, pod.Id);
12551366
if (content == null || content.Length == 0)
12561367
{
12571368
showViewer = false;

0 commit comments

Comments
 (0)