Refactor measuring UI, centralize status logic

- Reworked MeasuringIn to use tabbed interface with card view and improved form layout
- Unified status badge/text/color logic via new MeasurementService helpers
- Updated MeasuringOut to use centralized status display and improved order note handling
- Added shipping date column to GridShippingDocument
- Improved link styling in MgGridDataColumn
- Removed redundant code and applied minor UI/layout tweaks for consistency and maintainability
This commit is contained in:
Loretta 2026-03-23 17:43:06 +01:00
parent e22b6f304e
commit fcd7866d09
6 changed files with 314 additions and 172 deletions

View File

@ -43,6 +43,7 @@
</DxComboBoxSettings> </DxComboBoxSettings>
</EditSettings> </EditSettings>
</DxGridDataColumn> </DxGridDataColumn>
<DxGridDataColumn FieldName="Shipping.ShippingDate" Caption="Beérkezés" ReadOnly="true" />
<DxGridDataColumn FieldName="ShippingId" Caption="Shipping" Visible="@(!ParentDataItemIsShipping)" ReadOnly="@ParentDataItemIsShipping"> <DxGridDataColumn FieldName="ShippingId" Caption="Shipping" Visible="@(!ParentDataItemIsShipping)" ReadOnly="@ParentDataItemIsShipping">
<EditSettings> <EditSettings>
<DxComboBoxSettings Data="Shippings" <DxComboBoxSettings Data="Shippings"

View File

@ -3,9 +3,11 @@
@using DevExpress.Blazor @using DevExpress.Blazor
@using DevExpress.Blazor.Internal @using DevExpress.Blazor.Internal
@using FruitBank.Common.Entities @using FruitBank.Common.Entities
@using FruitBank.Common.Enums
@using FruitBank.Common.SignalRs @using FruitBank.Common.SignalRs
@using FruitBankHybrid.Shared.Components @using FruitBankHybrid.Shared.Components
@using FruitBankHybrid.Shared.Services @using FruitBankHybrid.Shared.Services
@using AyCode.Blazor.Components.Components.CardViews
@using Mango.Nop.Core.Dtos @using Mango.Nop.Core.Dtos
<h3>Áru bevételezés</h3> <h3>Áru bevételezés</h3>
@ -19,8 +21,9 @@
IndicatorAnimationType="WaitIndicatorAnimationType.Spin" IndicatorAnimationType="WaitIndicatorAnimationType.Spin"
Text="Adatok szinkronizálása folyamatban..."> Text="Adatok szinkronizálása folyamatban...">
<DxFormLayout CaptionPosition="CaptionPosition.Vertical" CssClass="w-100"> <DxFormLayout CaptionPosition="CaptionPosition.Vertical" CssClass="w-100 measuring-form-layout">
<DxFormLayoutItem Caption="Dátum" ColSpanMd="2" CaptionCssClass="@(SelectedShipping != null && _measuringDates.Where(x => MeasurementService.DaysEqual(x.DateTime, SelectedShipping.ShippingDate)).All(x => x.IsMeasured) ? "text-success" : "")"> <DxFormLayoutItem Caption="Dátum" ColSpanXs="8" ColSpanSm="8" ColSpanMd="2"
CaptionCssClass="@(SelectedShipping != null && _measuringDates.Where(x => MeasurementService.DaysEqual(x.DateTime, SelectedShipping.ShippingDate)).All(x => x.IsMeasured) ? "text-success" : "")">
<DxDateEdit CssClass="cw-320" <DxDateEdit CssClass="cw-320"
DisplayFormat="m" DisplayFormat="m"
Format="m" Format="m"
@ -46,144 +49,203 @@
</DayCellTemplate> </DayCellTemplate>
</DxDateEdit> </DxDateEdit>
</DxFormLayoutItem> </DxFormLayoutItem>
<DxFormLayoutItem Caption="Rendszám:" ColSpanMd="2" CaptionCssClass="@(SelectedShipping?.IsAllMeasured == true ? "text-success" : "")">
<DxComboBox Data="@NotMeasuredShippings"
@bind-Value="@SelectedShipping"
Text="Select licence plate"
ValueFieldName="@nameof(Shipping.Id)"
TextFieldName="@nameof(Shipping.LicencePlate)"
CssClass="cw-480"
DropDownBodyCssClass="dd-body-class"
Context="ctxShipping"
SelectedDataItemChanged="@((SelectedDataItemChangedEventArgs<Shipping> args) => OnSelectedShippingChanged(args))"
InputId="cbNotMeasuredShippings">
<ItemDisplayTemplate>
<span class="@(ctxShipping.DataItem.IsAllMeasured ? "text-success" : "")">@ctxShipping.DisplayText</span>
</ItemDisplayTemplate>
</DxComboBox>
</DxFormLayoutItem>
@* <DxFormLayoutItem Caption="Partner:" ColSpanMd="3" CaptionCssClass="@(SelectedShippingDocument?.IsAllMeasured == true ? "text-success" : "")">
<DxComboBox Data="@SelectedShipping?.ShippingDocuments"
@bind-Value="@SelectedShippingDocument"
Text="Select partner"
ValueFieldName="@nameof(ShippingDocument.Id)"
TextFieldName="@(nameof(ShippingDocument.Partner) + '.' + nameof(Partner.Name))"
CssClass="cw-480"
DropDownBodyCssClass="dd-body-class"
Context="ctxShippingDocument"
SelectedDataItemChanged="@((SelectedDataItemChangedEventArgs<ShippingDocument> args) => OnSelectedShippingDocumentChanged(args))"
InputId="cbShippingDocument">
<ItemDisplayTemplate>
<span class="@(ctxShippingDocument.DataItem.IsAllMeasured ? "text-success" : "")">@ctxShippingDocument.DisplayText</span>
</ItemDisplayTemplate>
</DxComboBox>
</DxFormLayoutItem>
*@
<DxFormLayoutItem Caption="Termék:" ColSpanMd="5" CaptionCssClass="@(SelectedShippingItem?.IsMeasured == true ? "text-success" : "")">
<DxComboBox Data="@_shippingItemsDataSource"
@bind-Value="@SelectedShippingItem"
Text="Select item"
ValueFieldName="@nameof(ShippingItem.Id)"
TextFieldName="@(nameof(ShippingItem.ProductName))"
CssClass="cw-480"
SearchMode="ListSearchMode.AutoSearch"
SearchFilterCondition="ListSearchFilterCondition.Contains"
SearchTextParseMode="ListSearchTextParseMode.GroupWordsByAnd"
ClearButtonDisplayMode="DataEditorClearButtonDisplayMode.Auto"
DropDownTriggerMode="DropDownTriggerMode.Click"
ListRenderMode="ListRenderMode.Entire"
ShowDropDownButton="false"
DropDownBodyCssClass="dd-body-class"
Context="ctxShippingitem"
SelectedDataItemChanged="@((SelectedDataItemChangedEventArgs<ShippingItem> args) => OnSelectedShippingItemChanged(args))"
InputId="cbShippingItem">
<ItemDisplayTemplate>
@* <div class="combobox-item-template">
<img src="/images/ok_green_lt.jpg" alt="" />
<span class="icon counter-icon" aria-hidden="true"></span>
<div class="combobox-item-template-text">
<span>@ctxShippingitem.DisplayText</span>
</div>
</div>
*@
<span class="@(ctxShippingitem.DataItem.IsMeasured ? "text-success" : "")">@ctxShippingitem.DisplayText)</span>
</ItemDisplayTemplate>
<Buttons>
<DxEditorButton IconCssClass="editor-icon editor-icon-add" Text="R" Tooltip="Adatok frissítése..."
Click="() => OnOrdersRefreshClick()" />
</Buttons>
</DxComboBox>
</DxFormLayoutItem>
<DxFormLayoutItem Caption="Partner:" ColSpanMd="3" CaptionCssClass="@(SelectedShippingItem?.ShippingDocument?.IsAllMeasured == true ? "text-success" : "")">
@{
var sd = SelectedShippingItem?.ShippingDocument;
if (sd != null)
{
var partnerName = sd.Partner?.Name;
<span class="@(sd.IsAllMeasured == true ? " text-success" : "")">
@($"{partnerName}, {sd.ShippingItems?.Count(si => si.IsMeasured) ?? 0}/{sd.ShippingItems?.Count ?? 0} kész.")
</span>
}
}
</DxFormLayoutItem>
</DxFormLayout> </DxFormLayout>
<div style="margin-top: 50px;"> <DxTabs ActiveTabIndex="(int)_activeTab" ActiveTabIndexChanged="i => _activeTab = (MeasuringTab)i" RenderMode="TabsRenderMode.OnDemand" CssClass="measuring-tabs">
@if (SelectedShippingItem is { ProductId: > 0 }) <DxTabPage Text="Napi feladatok">
{ <div class="p-3">
<h3 style="margin-bottom: 30px;" class="@(SelectedShippingItem.IsMeasured && SelectedShippingItem.ShippingItemPallets!.All(x => x.IsMeasuredAndValid(SelectedShippingItem.IsMeasurable)) ? "text-success" : "")"> <MgCardView TItem="Shipping" Data="@FilteredShippings"
#@(SelectedShippingItem.ProductId). @(SelectedShippingItem.ProductName) ShowFilterPanel="true"
</h3> OnCardClick="NavigateToMeasuringTab"
ScrollToItem="@SelectedShipping"
<DxFormLayout Data="@SelectedShippingItem" CaptionPosition="CaptionPosition.Vertical" CssClass="w-100"> ItemKeySelector="s => s.Id"
<DxFormLayoutItem Context="ctxShippingItemFromLayoutItem" ColSpanMd="12"> Height="calc(100vh - 220px)">
@for (var index = 0; index < (SelectedShippingItem?.ShippingItemPallets?.Count ?? 0); index++) <FilterPanel>
{ <DxTagBox Data="@(new[] { MeasuringStatus.NotStarted, MeasuringStatus.Started, MeasuringStatus.Finnished })"
var localI = index + 1; NullText="Összes státusz"
var currentShippingItemPallet = SelectedShippingItem!.ShippingItemPallets![index]; @bind-Values="_statusFilter"
ClearButtonDisplayMode="DataEditorClearButtonDisplayMode.Auto"
<PalletItemComponent IsMeasurable="@SelectedShippingItem.IsMeasurable" CssClass="cw-480" />
MeasuringIndex="@localI" </FilterPanel>
PalletItem="@currentShippingItemPallet" <CardTemplate>
ProductId="@SelectedShippingItem.ProductId!.Value" <div class="d-flex justify-content-between align-items-start mb-2">
AddOrUpdateSignalRTag="SignalRTags.AddOrUpdateMeasuredShippingItemPallet" <h6 class="mb-0">@context.LicencePlate</h6>
OnPalletItemSaved="pallet => OnShippingItemPalletSaved(pallet)" <span class="badge @(MeasurementService.GetMeasuringStatusBadgeCssClass(MeasurementService.GetShippingMeasuringStatus(context), hasAuditedStage: false))">@(MeasurementService.GetMeasuringStatusText(MeasurementService.GetShippingMeasuringStatus(context)))</span>
OnPalletItemValueChanged="pallet => OnShippingItemPalletValueChanged(pallet, SelectedShippingItem)"> </div>
</PalletItemComponent> <div class="text-muted small mb-2">
} <strong>@context.ShippingDate.ToString("yyyy.MM.dd")</strong>
</DxFormLayoutItem> @if (!string.IsNullOrWhiteSpace(context.CargoCompany))
{
<DxFormLayoutItem Context="vfdfgfd" ColSpanMd="12" BeginRow="true"> <span> — @context.CargoCompany</span>
<DxFormLayout CssClass="w-100"> }
<DxFormLayoutItem ColSpanMd="1" BeginRow="false"><strong>TOTAL:</strong></DxFormLayoutItem> </div>
<DxFormLayoutItem ColSpanMd="2" BeginRow="false" Visible="@(SelectedShippingItem.IsMeasurable)" /> @{
<DxFormLayoutItem ColSpanMd="2" BeginRow="false" Visible="@(SelectedShippingItem.IsMeasurable)" /> var allItems = context.ShippingDocuments?
<DxFormLayoutItem ColSpanMd="2" BeginRow="false"><strong>Rekesz: @(SelectedShippingItem.MeasuredQuantity) db</strong></DxFormLayoutItem> .Where(sd => sd.ShippingItems is not null)
<DxFormLayoutItem ColSpanMd="2" BeginRow="false" Visible="@(SelectedShippingItem.IsMeasurable)"><strong>Br: @(SelectedShippingItem.MeasuredGrossWeight) kg</strong></DxFormLayoutItem> .SelectMany(sd => sd.ShippingItems!);
<DxFormLayoutItem ColSpanMd="1" BeginRow="false" Visible="@(SelectedShippingItem.IsMeasurable)"><strong>Net: @(SelectedShippingItem.MeasuredNetWeight) kg</strong></DxFormLayoutItem> }
<DxFormLayoutItem ColSpanMd="1" BeginRow="false" /> @if (allItems is not null)
</DxFormLayout> {
</DxFormLayoutItem> @foreach (var item in allItems)
{
@* <DxFormLayoutItem ColSpanMd="12" BeginRow="true"> <div class="@(MeasurementService.GetMeasuringStatusCssClass(item.MeasuringStatus, hasAuditedStage: false)) small">
<ValidationSummary/> @item.ProductName — @item.MeasuredQuantity/@item.QuantityOnDocument rekesz
</DxFormLayoutItem> *@ </div>
}
@if (!_errorText.IsNullOrWhiteSpace()) }
{ @if (!string.IsNullOrWhiteSpace(context.Comment))
<DxFormLayoutItem ColSpanMd="12" BeginRow="true"> {
<text>HIBA! @_errorText</text> <div class="text-muted small mt-2 fst-italic">
📝 @context.Comment
</div>
}
</CardTemplate>
</MgCardView>
</div>
</DxTabPage>
<DxTabPage Text="Mérés">
<div class="p-3">
<DxFormLayout CaptionPosition="CaptionPosition.Vertical" CssClass="w-100">
<DxFormLayoutItem Caption="Rendszám:" ColSpanMd="2" CaptionCssClass="@(SelectedShipping?.IsAllMeasured == true ? "text-success" : "")">
<DxComboBox Data="@NotMeasuredShippings"
@bind-Value="@SelectedShipping"
Text="Select licence plate"
ValueFieldName="@nameof(Shipping.Id)"
TextFieldName="@nameof(Shipping.LicencePlate)"
CssClass="cw-480"
DropDownBodyCssClass="dd-body-class"
Context="ctxShipping"
SelectedDataItemChanged="@((SelectedDataItemChangedEventArgs<Shipping> args) => OnSelectedShippingChanged(args))"
InputId="cbNotMeasuredShippings">
<ItemDisplayTemplate>
<span class="@(ctxShipping.DataItem.IsAllMeasured ? "text-success" : "")">@ctxShipping.DisplayText</span>
</ItemDisplayTemplate>
</DxComboBox>
</DxFormLayoutItem> </DxFormLayoutItem>
//_errorText = string.Empty;
} @* <DxFormLayoutItem Caption="Partner:" ColSpanMd="3" CaptionCssClass="@(SelectedShippingDocument?.IsAllMeasured == true ? "text-success" : "")">
</DxFormLayout> <DxComboBox Data="@SelectedShipping?.ShippingDocuments"
} @bind-Value="@SelectedShippingDocument"
</div> Text="Select partner"
ValueFieldName="@nameof(ShippingDocument.Id)"
TextFieldName="@(nameof(ShippingDocument.Partner) + '.' + nameof(Partner.Name))"
CssClass="cw-480"
DropDownBodyCssClass="dd-body-class"
Context="ctxShippingDocument"
SelectedDataItemChanged="@((SelectedDataItemChangedEventArgs<ShippingDocument> args) => OnSelectedShippingDocumentChanged(args))"
InputId="cbShippingDocument">
<ItemDisplayTemplate>
<span class="@(ctxShippingDocument.DataItem.IsAllMeasured ? "text-success" : "")">@ctxShippingDocument.DisplayText</span>
</ItemDisplayTemplate>
</DxComboBox>
</DxFormLayoutItem> *@
<DxFormLayoutItem Caption="Termék:" ColSpanMd="5" CaptionCssClass="@(SelectedShippingItem?.IsMeasured == true ? "text-success" : "")">
<DxComboBox Data="@_shippingItemsDataSource"
@bind-Value="@SelectedShippingItem"
Text="Select item"
ValueFieldName="@nameof(ShippingItem.Id)"
TextFieldName="@(nameof(ShippingItem.ProductName))"
CssClass="cw-480"
SearchMode="ListSearchMode.AutoSearch"
SearchFilterCondition="ListSearchFilterCondition.Contains"
SearchTextParseMode="ListSearchTextParseMode.GroupWordsByAnd"
ClearButtonDisplayMode="DataEditorClearButtonDisplayMode.Auto"
DropDownTriggerMode="DropDownTriggerMode.Click"
ListRenderMode="ListRenderMode.Entire"
ShowDropDownButton="false"
DropDownBodyCssClass="dd-body-class"
Context="ctxShippingitem"
SelectedDataItemChanged="@((SelectedDataItemChangedEventArgs<ShippingItem> args) => OnSelectedShippingItemChanged(args))"
InputId="cbShippingItem">
<ItemDisplayTemplate>
@* <div class="combobox-item-template">
<img src="/images/ok_green_lt.jpg" alt="" />
<span class="icon counter-icon" aria-hidden="true"></span>
<div class="combobox-item-template-text">
<span>@ctxShippingitem.DisplayText</span>
</div>
</div> *@
<span class="@(ctxShippingitem.DataItem.IsMeasured ? "text-success" : "")">@ctxShippingitem.DisplayText)</span>
</ItemDisplayTemplate>
<Buttons>
<DxEditorButton IconCssClass="editor-icon editor-icon-add" Text="R" Tooltip="Adatok frissítése..."
Click="() => OnOrdersRefreshClick()" />
</Buttons>
</DxComboBox>
</DxFormLayoutItem>
<DxFormLayoutItem Caption="Partner:" ColSpanMd="3" CaptionCssClass="@(SelectedShippingItem?.ShippingDocument?.IsAllMeasured == true ? "text-success" : "")">
@{
var sd = SelectedShippingItem?.ShippingDocument;
if (sd != null)
{
var partnerName = sd.Partner?.Name;
<span class="@(sd.IsAllMeasured == true ? " text-success" : "")">
@($"{partnerName}, {sd.ShippingItems?.Count(si => si.IsMeasured) ?? 0}/{sd.ShippingItems?.Count ?? 0} kész.")
</span>
}
}
</DxFormLayoutItem>
</DxFormLayout>
<div style="margin-top: 50px;">
@if (SelectedShippingItem is { ProductId: > 0 })
{
<h3 style="margin-bottom: 30px;" class="@(SelectedShippingItem.IsMeasured && SelectedShippingItem.ShippingItemPallets!.All(x => x.IsMeasuredAndValid(SelectedShippingItem.IsMeasurable)) ? "text-success" : "")">
#@(SelectedShippingItem.ProductId). @(SelectedShippingItem.ProductName)
</h3>
<DxFormLayout Data="@SelectedShippingItem" CaptionPosition="CaptionPosition.Vertical" CssClass="w-100">
<DxFormLayoutItem Context="ctxShippingItemFromLayoutItem" ColSpanMd="12">
@for (var index = 0; index < (SelectedShippingItem?.ShippingItemPallets?.Count ?? 0); index++)
{
var localI = index + 1;
var currentShippingItemPallet = SelectedShippingItem!.ShippingItemPallets![index];
<PalletItemComponent IsMeasurable="@SelectedShippingItem.IsMeasurable"
MeasuringIndex="@localI"
PalletItem="@currentShippingItemPallet"
ProductId="@SelectedShippingItem.ProductId!.Value"
AddOrUpdateSignalRTag="SignalRTags.AddOrUpdateMeasuredShippingItemPallet"
OnPalletItemSaved="pallet => OnShippingItemPalletSaved(pallet)"
OnPalletItemValueChanged="pallet => OnShippingItemPalletValueChanged(pallet, SelectedShippingItem)">
</PalletItemComponent>
}
</DxFormLayoutItem>
<DxFormLayoutItem Context="vfdfgfd" ColSpanMd="12" BeginRow="true">
<DxFormLayout CssClass="w-100">
<DxFormLayoutItem ColSpanMd="1" BeginRow="false"><strong>TOTAL:</strong></DxFormLayoutItem>
<DxFormLayoutItem ColSpanMd="2" BeginRow="false" Visible="@(SelectedShippingItem.IsMeasurable)" />
<DxFormLayoutItem ColSpanMd="2" BeginRow="false" Visible="@(SelectedShippingItem.IsMeasurable)" />
<DxFormLayoutItem ColSpanMd="2" BeginRow="false"><strong>Rekesz: @(SelectedShippingItem.MeasuredQuantity) db</strong></DxFormLayoutItem>
<DxFormLayoutItem ColSpanMd="2" BeginRow="false" Visible="@(SelectedShippingItem.IsMeasurable)"><strong>Br: @(SelectedShippingItem.MeasuredGrossWeight) kg</strong></DxFormLayoutItem>
<DxFormLayoutItem ColSpanMd="1" BeginRow="false" Visible="@(SelectedShippingItem.IsMeasurable)"><strong>Net: @(SelectedShippingItem.MeasuredNetWeight) kg</strong></DxFormLayoutItem>
<DxFormLayoutItem ColSpanMd="1" BeginRow="false" />
</DxFormLayout>
</DxFormLayoutItem>
@* <DxFormLayoutItem ColSpanMd="12" BeginRow="true">
<ValidationSummary/>
</DxFormLayoutItem> *@
@if (!_errorText.IsNullOrWhiteSpace())
{
<DxFormLayoutItem ColSpanMd="12" BeginRow="true">
<text>HIBA! @_errorText</text>
</DxFormLayoutItem>
//_errorText = string.Empty;
}
</DxFormLayout>
}
</div>
</div>
</DxTabPage>
</DxTabs>
</DxLoadingPanel> </DxLoadingPanel>
</div> </div>
@code {
}

View File

@ -3,6 +3,7 @@ using AyCode.Core.Loggers;
using DevExpress.Blazor; using DevExpress.Blazor;
using FruitBank.Common.Dtos; using FruitBank.Common.Dtos;
using FruitBank.Common.Entities; using FruitBank.Common.Entities;
using FruitBank.Common.Enums;
using FruitBank.Common.Helpers; using FruitBank.Common.Helpers;
using FruitBank.Common.Interfaces; using FruitBank.Common.Interfaces;
using FruitBank.Common.Models; using FruitBank.Common.Models;
@ -26,6 +27,15 @@ namespace FruitBankHybrid.Shared.Pages
private ILogger _logger = null!; private ILogger _logger = null!;
private string _errorText; private string _errorText;
private enum MeasuringTab
{
DailyTasks = 0,
Measuring = 1
}
private MeasuringTab _activeTab = MeasuringTab.DailyTasks;
private IEnumerable<MeasuringStatus> _statusFilter = [];
private List<Shipping> NotMeasuredShippings { get; set; } = null!; private List<Shipping> NotMeasuredShippings { get; set; } = null!;
private Shipping? SelectedShipping { get; set; } private Shipping? SelectedShipping { get; set; }
//private ShippingDocument? SelectedShippingDocument { get; set; } //private ShippingDocument? SelectedShippingDocument { get; set; }
@ -37,6 +47,12 @@ namespace FruitBankHybrid.Shared.Pages
private List<ShippingItem>? _shippingItemsDataSource; private List<ShippingItem>? _shippingItemsDataSource;
private List<MeasuringDateSelectorModel> _measuringDates = null!; private List<MeasuringDateSelectorModel> _measuringDates = null!;
private IReadOnlyList<Shipping> FilteredShippings => NotMeasuredShippings is null
? []
: _statusFilter.Any()
? NotMeasuredShippings.Where(s => _statusFilter.Contains(MeasurementService.GetShippingMeasuringStatus(s))).ToList()
: NotMeasuredShippings;
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
LoadingPanelVisible = true; LoadingPanelVisible = true;
@ -181,6 +197,20 @@ namespace FruitBankHybrid.Shared.Pages
//Nem végezhető el a mérés, nincs megadva a ProductId! Jelezze a vezetőségnek... //Nem végezhető el a mérés, nincs megadva a ProductId! Jelezze a vezetőségnek...
} }
/// <summary>
/// Navigates from a card click (Napi feladatok tab) to the Mérés tab with the selected shipping.
/// </summary>
private void NavigateToMeasuringTab(Shipping shipping)
{
SelectedShipping = shipping;
PrepareShippingItems(shipping);
_shippingItemsDataSource = GetShippingItemsDataSource(shipping);
SelectedShippingItem = _shippingItemsDataSource?.FirstOrDefault();
_activeTab = MeasuringTab.Measuring;
}
private void PrepareShippingItems(Shipping? shipping) private void PrepareShippingItems(Shipping? shipping)
{ {
if (shipping?.ShippingDocuments == null) return; if (shipping?.ShippingDocuments == null) return;

View File

@ -48,7 +48,7 @@
</DayCellTemplate> </DayCellTemplate>
</DxDateEdit> </DxDateEdit>
</DxFormLayoutItem> </DxFormLayoutItem>
<DxFormLayoutItem Caption="Napok száma" ColSpanXs="4" ColSpanSm="4" ColSpanMd="1"> <DxFormLayoutItem Caption="Napok száma" ColSpanXs="4" ColSpanSm="4" ColSpanMd="2">
<DxSpinEdit T="int" Value="1" Increment="1" MinValue="1" <DxSpinEdit T="int" Value="1" Increment="1" MinValue="1"
ValueChanged="async i => await RefreshOrdersFromDb(DateTime.Now, i)" /> ValueChanged="async i => await RefreshOrdersFromDb(DateTime.Now, i)" />
</DxFormLayoutItem> </DxFormLayoutItem>
@ -73,18 +73,27 @@
<CardTemplate> <CardTemplate>
<div class="d-flex justify-content-between align-items-start mb-2"> <div class="d-flex justify-content-between align-items-start mb-2">
<h6 class="mb-0">#@context.CustomOrderNumber</h6> <h6 class="mb-0">#@context.CustomOrderNumber</h6>
<span class="badge @GetOrderStatusBadgeCssClass(context.MeasuringStatus)">@GetOrderStatusText(context.MeasuringStatus)</span> <span class="badge @(MeasurementService.GetMeasuringStatusBadgeCssClass(context.MeasuringStatus))">@(MeasurementService.GetMeasuringStatusText(context.MeasuringStatus))</span>
</div> </div>
<div class="text-muted small mb-2"> <div class="text-muted small mb-2">
<strong>@context.DateOfReceiptOrCreated.ToString("HH:mm")</strong> — @context.Customer.Company <strong>@context.DateOfReceiptOrCreated.ToString("HH:mm")</strong> — @context.Customer.Company
</div> </div>
@foreach (var item in context.OrderItemDtos) @foreach (var item in context.OrderItemDtos)
{ {
<div class="@GetOrderStatusCssClass(item.MeasuringStatus) small"> <div class="@(MeasurementService.GetMeasuringStatusCssClass(item.MeasuringStatus)) small">
@item.ProductName — @item.TrayQuantity/@item.Quantity rekesz @item.ProductName — @item.TrayQuantity/@item.Quantity rekesz
</div> </div>
} }
</CardTemplate> @{
var cardOrderNote = MeasurementService.GetOrderNote(context.OrderNotes);
}
@if (!string.IsNullOrWhiteSpace(cardOrderNote))
{
<div class="text-muted small mt-2 fst-italic">
📝 @cardOrderNote
</div>
}
</CardTemplate>
</MgCardView> </MgCardView>
</div> </div>
</DxTabPage> </DxTabPage>
@ -169,8 +178,8 @@
} }
else else
{ {
string? orderNote; var orderNote = MeasurementService.GetOrderNote(SelectedOrder?.OrderNotes);
if (!(orderNote = SelectedOrder?.OrderNotes.LastOrDefault(x => x.Note.StartsWith('*'))?.Note).IsNullOrWhiteSpace()) if (!string.IsNullOrWhiteSpace(orderNote))
{ {
<div class="alert alert-info mt-3" role="alert"> <div class="alert alert-info mt-3" role="alert">
<strong>📝 Megjegyzés:</strong> @(orderNote) <strong>📝 Megjegyzés:</strong> @(orderNote)

View File

@ -410,30 +410,6 @@ namespace FruitBankHybrid.Shared.Pages
await DialogService.ShowMessageBoxAsync("Információ", "A mérés már folyamatban, válasszon másik rendelést!", MessageBoxRenderStyle.Info); await DialogService.ShowMessageBoxAsync("Információ", "A mérés már folyamatban, válasszon másik rendelést!", MessageBoxRenderStyle.Info);
} }
private static string GetOrderStatusCssClass(MeasuringStatus status) => status switch
{
MeasuringStatus.Audited => "text-success",
MeasuringStatus.Finnished => "text-primary",
MeasuringStatus.Started => "text-warning",
_ => "text-muted"
};
private static string GetOrderStatusBadgeCssClass(MeasuringStatus status) => status switch
{
MeasuringStatus.Audited => "bg-success",
MeasuringStatus.Finnished => "bg-primary",
MeasuringStatus.Started => "bg-warning text-dark",
_ => "bg-secondary"
};
private static string GetOrderStatusText(MeasuringStatus status) => status switch
{
MeasuringStatus.Audited => "Lezárva",
MeasuringStatus.Finnished => "Kész",
MeasuringStatus.Started => "Folyamatban",
_ => "Nem kezdett"
};
public void Dispose() public void Dispose()
{ {
FruitBankSignalRClient.OnMessageReceived -= SignalRClientOnMessageReceived; FruitBankSignalRClient.OnMessageReceived -= SignalRClientOnMessageReceived;

View File

@ -2,12 +2,14 @@
using DevExpress.Blazor; using DevExpress.Blazor;
using FruitBank.Common.Dtos; using FruitBank.Common.Dtos;
using FruitBank.Common.Entities; using FruitBank.Common.Entities;
using FruitBank.Common.Enums;
using FruitBank.Common.Interfaces; using FruitBank.Common.Interfaces;
using FruitBank.Common.Services; using FruitBank.Common.Services;
using FruitBankHybrid.Shared.Models; using FruitBankHybrid.Shared.Models;
using FruitBankHybrid.Shared.Services.Loggers; using FruitBankHybrid.Shared.Services.Loggers;
using Mango.Nop.Core.Dtos; using Mango.Nop.Core.Dtos;
using Mango.Nop.Core.Loggers; using Mango.Nop.Core.Loggers;
using Nop.Core.Domain.Orders;
namespace FruitBankHybrid.Shared.Services; namespace FruitBankHybrid.Shared.Services;
@ -109,4 +111,66 @@ public class MeasurementService(IEnumerable<IAcLogWriterClientBase> logWriters)
public static bool IsCustomItemPalletMeasuredAndValid(IMeasuringItemPalletBase customItemPallet, bool isMeasurable) public static bool IsCustomItemPalletMeasuredAndValid(IMeasuringItemPalletBase customItemPallet, bool isMeasurable)
=> customItemPallet.IsMeasuredAndValid(isMeasurable); => customItemPallet.IsMeasuredAndValid(isMeasurable);
/// <summary>
/// Returns the last order note starting with '*', or null if none exists.
/// </summary>
public static string? GetOrderNote(IEnumerable<OrderNote>? orderNotes)
=> orderNotes?.LastOrDefault(x => x.Note.StartsWith('*'))?.Note;
/// <summary>
/// Returns a Bootstrap badge CSS class for the given measuring status.
/// When <paramref name="hasAuditedStage"/> is false, Finnished is treated as the final state (success/green).
/// </summary>
public static string GetMeasuringStatusBadgeCssClass(MeasuringStatus status, bool hasAuditedStage = true) => status switch
{
MeasuringStatus.Audited => "bg-success",
MeasuringStatus.Finnished => hasAuditedStage ? "bg-primary" : "bg-success",
MeasuringStatus.Started => "bg-warning text-dark",
_ => "bg-secondary"
};
/// <summary>
/// Returns a localized display text for the given measuring status.
/// </summary>
public static string GetMeasuringStatusText(MeasuringStatus status) => status switch
{
MeasuringStatus.Audited => "Lezárva",
MeasuringStatus.Finnished => "Kész",
MeasuringStatus.Started => "Folyamatban",
_ => "Nem kezdett"
};
/// <summary>
/// Returns a text color CSS class for the given measuring status.
/// When <paramref name="hasAuditedStage"/> is false, Finnished is treated as the final state (success/green).
/// </summary>
public static string GetMeasuringStatusCssClass(MeasuringStatus status, bool hasAuditedStage = true) => status switch
{
MeasuringStatus.Audited => "text-success",
MeasuringStatus.Finnished => hasAuditedStage ? "text-primary" : "text-success",
MeasuringStatus.Started => "text-warning",
_ => "text-muted"
};
/// <summary>
/// Computes a shipping-level MeasuringStatus from its items.
/// </summary>
public static MeasuringStatus GetShippingMeasuringStatus(Shipping shipping)
{
var items = shipping.ShippingDocuments?
.Where(sd => sd.ShippingItems is not null)
.SelectMany(sd => sd.ShippingItems!);
if (items is null || !items.Any())
return MeasuringStatus.NotStarted;
if (items.All(si => si.IsMeasured))
return MeasuringStatus.Finnished;
if (items.Any(si => si.MeasuringStatus == MeasuringStatus.Started || si.IsMeasured))
return MeasuringStatus.Started;
return MeasuringStatus.NotStarted;
}
} }