Add stock taking close functionality and UI improvements

- Added CloseStockTaking method to IStockSignalREndpointCommon and implemented it in FruitBankSignalRClient.
- Renamed IsEditable to Editable in PalletItemComponent.razor and updated all usages.
- Updated StockTakingTemplate.razor: "Módosít" button is now always disabled, "Lezárás" button is enabled only when appropriate, and form layouts are disabled when stock taking is closed.
- Improved async UI updates by using InvokeAsync(StateHasChanged).
- Enhanced order note display and added warning state for invalid average weight in MeasuringOut.razor.
This commit is contained in:
Loretta 2026-01-09 11:10:15 +01:00
parent bba26c42da
commit 0368f0809a
5 changed files with 31 additions and 22 deletions

View File

@ -19,6 +19,7 @@ public interface IStockSignalREndpointCommon
public Task<List<StockTakingItemPallet>?> GetStockTakingItemPallets(); public Task<List<StockTakingItemPallet>?> GetStockTakingItemPallets();
public Task<List<StockTakingItemPallet>?> GetStockTakingItemPalletsByProductId(int productId); public Task<List<StockTakingItemPallet>?> GetStockTakingItemPalletsByProductId(int productId);
public Task<StockTaking?> CloseStockTaking(int stockTakingId);
public Task<StockTakingItemPallet?> AddStockTakingItemPallet(StockTakingItemPallet stockTakingItemPallet); public Task<StockTakingItemPallet?> AddStockTakingItemPallet(StockTakingItemPallet stockTakingItemPallet);
public Task<StockTakingItemPallet?> UpdateStockTakingItemPallet(StockTakingItemPallet stockTakingItemPallet); public Task<StockTakingItemPallet?> UpdateStockTakingItemPallet(StockTakingItemPallet stockTakingItemPallet);
} }

View File

@ -12,7 +12,7 @@
@typeparam TPalletItem where TPalletItem : class, IMeasuringItemPalletBase @typeparam TPalletItem where TPalletItem : class, IMeasuringItemPalletBase
<DxFormLayout Context="ctxFromLayoutPallet" Data="@PalletItem" CaptionPosition="CaptionPosition.Vertical" CssClass="w-100 measuring-form-layout" <DxFormLayout Context="ctxFromLayoutPallet" Data="@PalletItem" CaptionPosition="CaptionPosition.Vertical" CssClass="w-100 measuring-form-layout"
ItemUpdating="@((pair) => OnItemUpdating(pair.Key, pair.Value, PalletItem))" Enabled="IsEditable"> ItemUpdating="@((pair) => OnItemUpdating(pair.Key, pair.Value, PalletItem))" Enabled="Editable">
<DxFormLayoutItem Context="ctxFromLayoutItemPallet" ColSpanMd="1" BeginRow="true"> <DxFormLayoutItem Context="ctxFromLayoutItemPallet" ColSpanMd="1" BeginRow="true">
<b>@(MeasuringIndex). MÉRÉS</b> <b>@(MeasuringIndex). MÉRÉS</b>
@ -21,24 +21,24 @@
<DxFormLayoutItem Context="ctxFromLayoutItemPallet" CaptionCssClass="@(GetOrderItemPalletsCssClassNames(nameof(IMeasuringItemPalletBase.PalletWeight)))" <DxFormLayoutItem Context="ctxFromLayoutItemPallet" CaptionCssClass="@(GetOrderItemPalletsCssClassNames(nameof(IMeasuringItemPalletBase.PalletWeight)))"
Field="@nameof(ShippingItemPallet.PalletWeight)" Field="@nameof(ShippingItemPallet.PalletWeight)"
Enabled="@(IsEditable && IsMeasurable && ProductId > 0)" Visible="@(IsMeasurable)" Enabled="@(Editable && IsMeasurable && ProductId > 0)" Visible="@(IsMeasurable)"
Caption="Rakl.súly(kg)" ColSpanMd="2" /> Caption="Rakl.súly(kg)" ColSpanMd="2" />
<DxFormLayoutItem Context="ctxFromLayoutItemPallet" CaptionCssClass="@(GetOrderItemPalletsCssClassNames(nameof(IMeasuringItemPalletBase.TareWeight)))" <DxFormLayoutItem Context="ctxFromLayoutItemPallet" CaptionCssClass="@(GetOrderItemPalletsCssClassNames(nameof(IMeasuringItemPalletBase.TareWeight)))"
Field="@nameof(ShippingItemPallet.TareWeight)" Field="@nameof(ShippingItemPallet.TareWeight)"
Enabled="@(IsEditable && IsMeasurable && ProductId > 0)" Visible="@(IsMeasurable)" Enabled="@(Editable && IsMeasurable && ProductId > 0)" Visible="@(IsMeasurable)"
Caption="Tára(kg)" ColSpanMd="2" /> Caption="Tára(kg)" ColSpanMd="2" />
@* <DxFormLayoutItem Context="ctxFromLayoutItemPallet" ColSpanMd="1" /> *@ @* <DxFormLayoutItem Context="ctxFromLayoutItemPallet" ColSpanMd="1" /> *@
<DxFormLayoutItem Context="ctxFromLayoutItemPallet" CaptionCssClass="@(GetOrderItemPalletsCssClassNames(nameof(IMeasuringItemPalletBase.TrayQuantity)))" <DxFormLayoutItem Context="ctxFromLayoutItemPallet" CaptionCssClass="@(GetOrderItemPalletsCssClassNames(nameof(IMeasuringItemPalletBase.TrayQuantity)))"
Field="@nameof(ShippingItemPallet.TrayQuantity)" Field="@nameof(ShippingItemPallet.TrayQuantity)"
Enabled="@(IsEditable && ProductId > 0)" Enabled="@(Editable && ProductId > 0)"
Caption="Rekesz/csomag" ColSpanMd="2" /> Caption="Rekesz/csomag" ColSpanMd="2" />
<DxFormLayoutItem Context="ctxFromLayoutItemPallet" CaptionCssClass="@(GetOrderItemPalletsCssClassNames(nameof(IMeasuringItemPalletBase.GrossWeight)))" <DxFormLayoutItem Context="ctxFromLayoutItemPallet" CaptionCssClass="@(GetOrderItemPalletsCssClassNames(nameof(IMeasuringItemPalletBase.GrossWeight)))"
Field="@nameof(ShippingItemPallet.GrossWeight)" Field="@nameof(ShippingItemPallet.GrossWeight)"
Enabled="@(IsEditable && IsMeasurable && ProductId > 0)" Visible="@(IsMeasurable)" Enabled="@(Editable && IsMeasurable && ProductId > 0)" Visible="@(IsMeasurable)"
Caption="Br.súly(kg)" ColSpanMd="2"> Caption="Br.súly(kg)" ColSpanMd="2">
</DxFormLayoutItem> </DxFormLayoutItem>
@ -48,13 +48,13 @@
</DxFormLayoutItem> </DxFormLayoutItem>
<DxFormLayoutItem Context="ctxFromLayoutItemPallet" ColSpanMd="@(HasAuditButton ? 1 : 2)"> <DxFormLayoutItem Context="ctxFromLayoutItemPallet" ColSpanMd="@(HasAuditButton ? 1 : 2)">
<DxButton Enabled="@(IsEditable && BtnSaveEnabled)" Text="@(PalletItem.Id == 0 ? "Mentés" : "Módosít")" Click="() => PalletItemSaveClick()" CssClass="w-100" /> <DxButton Enabled="@(Editable && BtnSaveEnabled)" Text="@(PalletItem.Id == 0 ? "Mentés" : "Módosít")" Click="() => PalletItemSaveClick()" CssClass="w-100" />
</DxFormLayoutItem> </DxFormLayoutItem>
@if (HasAuditButton) @if (HasAuditButton)
{ {
<DxFormLayoutItem Context="ctxFromLayoutItemPallet" ColSpanMd="1"> <DxFormLayoutItem Context="ctxFromLayoutItemPallet" ColSpanMd="1">
<DxButton Enabled="@(IsEditable && OrderItemPallet!.IsMeasuredAndValid(IsMeasurable) && !OrderItemPallet.IsAudited && IsMaxTrayQuantityValid)" <DxButton Enabled="@(Editable && OrderItemPallet!.IsMeasuredAndValid(IsMeasurable) && !OrderItemPallet.IsAudited && IsMaxTrayQuantityValid)"
Text="@(OrderItemPallet!.IsAudited ? "Jóváhagyva" : "Jóváhagy")" Click="() => PalletItemAuditedClick()" CssClass="w-100" /> Text="@(OrderItemPallet!.IsAudited ? "Jóváhagyva" : "Jóváhagy")" Click="() => PalletItemAuditedClick()" CssClass="w-100" />
</DxFormLayoutItem> </DxFormLayoutItem>
} }
@ -73,7 +73,7 @@
[Parameter] public int? AddOrUpdateSignalRTag { get; set; } = null; [Parameter] public int? AddOrUpdateSignalRTag { get; set; } = null;
[Parameter] public int? MaxTrayQuantity { get; set; } = null; [Parameter] public int? MaxTrayQuantity { get; set; } = null;
[Parameter] public bool IsEditable { get; set; } = true; [Parameter] public bool Editable { get; set; } = true;
//[Parameter] public EventCallback OnPalletItemSaveClick { get; set; } //[Parameter] public EventCallback OnPalletItemSaveClick { get; set; }
[Parameter] public Func<TPalletItem?, Task>? OnPalletItemSaved { get; set; } [Parameter] public Func<TPalletItem?, Task>? OnPalletItemSaved { get; set; }
@ -81,7 +81,7 @@
[Parameter] public Func<TPalletItem?, Task>? OnPalletItemAuditedClick { get; set; } [Parameter] public Func<TPalletItem?, Task>? OnPalletItemAuditedClick { get; set; }
//public bool LoadingPanelVisible { get; set; } = false; //public bool LoadingPanelVisible { get; set; } = false;
//public bool IsEditable => !HasAuditButton || (OrderItemPallet.IsAudited); //public bool Editable => !HasAuditButton || (OrderItemPallet.IsAudited);
public bool BtnSaveEnabled { get; set; } public bool BtnSaveEnabled { get; set; }
@ -93,7 +93,7 @@
private bool GetBtnSaveEnabled() private bool GetBtnSaveEnabled()
{ {
return IsEditable && PalletItem.IsValidMeasuringValues(IsMeasurable) && !PalletItem.IsMeasured && IsMaxTrayQuantityValid; return Editable && PalletItem.IsValidMeasuringValues(IsMeasurable) && !PalletItem.IsMeasured && IsMaxTrayQuantityValid;
} }
private bool IsMaxTrayQuantityValid => (!MaxTrayQuantity.HasValue || PalletItem.TrayQuantity <= MaxTrayQuantity.Value); private bool IsMaxTrayQuantityValid => (!MaxTrayQuantity.HasValue || PalletItem.TrayQuantity <= MaxTrayQuantity.Value);

View File

@ -40,10 +40,10 @@
<DxButton Text="Új" Enabled="@(_stockTakings.All(x => x.IsClosed))" Click="() => NewStockTakingClick()"></DxButton> <DxButton Text="Új" Enabled="@(_stockTakings.All(x => x.IsClosed))" Click="() => NewStockTakingClick()"></DxButton>
</DxFormLayoutItem> </DxFormLayoutItem>
<DxFormLayoutItem ColSpanMd="1"> <DxFormLayoutItem ColSpanMd="1">
<DxButton Text="Módosít" Enabled="@(SelectedStockTaking?.IsClosed ?? false)" Click="() => UpdateStockTakingClick()"></DxButton> <DxButton Text="Módosít" Enabled="@((SelectedStockTaking?.IsClosed ?? false) && false)" Click="() => UpdateStockTakingClick()"></DxButton>
</DxFormLayoutItem> </DxFormLayoutItem>
<DxFormLayoutItem ColSpanMd="1"> <DxFormLayoutItem ColSpanMd="1">
<DxButton Text="Lezárás" Enabled="@(SelectedStockTaking?.IsReadyForClose() ?? false)" Click="() => StockTakingCloseClick()"></DxButton> <DxButton Text="Lezárás" Enabled="@((!SelectedStockTaking?.IsClosed ?? false) && (SelectedStockTaking?.IsReadyForClose() ?? false))" Click="() => StockTakingCloseClick(SelectedStockTaking!.Id)"></DxButton>
</DxFormLayoutItem> </DxFormLayoutItem>
</DxFormLayout> </DxFormLayout>
@ -61,7 +61,7 @@
<span>@a</span> <span>@a</span>
} }
</div> </div>
<DxFormLayout Data="@SelectedStockTakingItem" CaptionPosition="CaptionPosition.Vertical" CssClass="w-100"> <DxFormLayout Data="@SelectedStockTakingItem" CaptionPosition="CaptionPosition.Vertical" CssClass="w-100" Enabled="@((!SelectedStockTaking?.IsClosed ?? false))">
<DxFormLayoutItem Context="ctxShippingItemFromLayoutItem" ColSpanMd="12"> <DxFormLayoutItem Context="ctxShippingItemFromLayoutItem" ColSpanMd="12">
@for (var index = 0; index < (SelectedStockTakingItem?.StockTakingItemPallets?.Count ?? 0); index++) @for (var index = 0; index < (SelectedStockTakingItem?.StockTakingItemPallets?.Count ?? 0); index++)
{ {
@ -70,6 +70,7 @@
<PalletItemComponent IsMeasurable="@SelectedStockTakingItem!.IsMeasurable" <PalletItemComponent IsMeasurable="@SelectedStockTakingItem!.IsMeasurable"
MeasuringIndex="@localI" MeasuringIndex="@localI"
IsEditable="@(!SelectedStockTaking?.IsClosed ?? false)"
PalletItem="@currentShippingItemPallet" PalletItem="@currentShippingItemPallet"
ProductId="@SelectedStockTakingItem.Product!.Id" ProductId="@SelectedStockTakingItem.Product!.Id"
AddOrUpdateSignalRTag="SignalRTags.AddOrUpdateMeasuredStockTakingItemPallet" AddOrUpdateSignalRTag="SignalRTags.AddOrUpdateMeasuredStockTakingItemPallet"
@ -142,16 +143,18 @@
// if (resultStockTaking == null) return; // if (resultStockTaking == null) return;
// _stockTakings.Add(resultStockTaking); // _stockTakings.Add(resultStockTaking);
StateHasChanged(); await InvokeAsync(StateHasChanged);
} }
private async Task StockTakingCloseClick() private async Task StockTakingCloseClick(int stockTakingId)
{ {
// var resultStockTaking = await FruitBankSignalRClient.AddStockTaking(stockTaking); var resultStockTaking = await FruitBankSignalRClient.CloseStockTaking(stockTakingId);
// if (resultStockTaking == null) return; if (resultStockTaking == null) return;
// _stockTakings.Add(resultStockTaking); _stockTakings.UpdateCollection(resultStockTaking, false);
StateHasChanged(); await StockTakingComboValueChanged(_stockTakings.FirstOrDefault(x => x.Id == resultStockTaking.Id));
await InvokeAsync(StateHasChanged);
} }
private async Task StockTakingComboValueChanged(StockTaking? newValue) private async Task StockTakingComboValueChanged(StockTaking? newValue)
@ -163,7 +166,7 @@
SelectedStockTakingItem = _stockTakingItems.FirstOrDefault(); SelectedStockTakingItem = _stockTakingItems.FirstOrDefault();
StateHasChanged(); await InvokeAsync(StateHasChanged);
} }
private void PrepareStockTakingItems(StockTaking? stockTaking) private void PrepareStockTakingItems(StockTaking? stockTaking)

View File

@ -127,7 +127,7 @@
else else
{ {
string? orderNote; string? orderNote;
if (!(orderNote = SelectedOrder?.OrderNotes.LastOrDefault(x=>x.Note.StartsWith('*'))?.Note).IsNullOrWhiteSpace()) if (!(orderNote = SelectedOrder?.OrderNotes.LastOrDefault(x => x.Note.StartsWith('*'))?.Note).IsNullOrWhiteSpace())
{ {
<div class="container-fluid p-0" style="margin-top: 20px"> <div class="container-fluid p-0" style="margin-top: 20px">
<b> Megjegyzés: </b><span>@(orderNote) </span> <b> Megjegyzés: </b><span>@(orderNote) </span>
@ -159,7 +159,8 @@
var isValid = selectedOrderItemDto.IsValidMeasuringValues(); var isValid = selectedOrderItemDto.IsValidMeasuringValues();
var isValidAndMeasured = isValid && selectedOrderItemDto.IsMeasuredAndValid(); // && selectedOrderItemDto.; var isValidAndMeasured = isValid && selectedOrderItemDto.IsMeasuredAndValid(); // && selectedOrderItemDto.;
if (isValidAndMeasured) cssClass = "text-success"; if (isValid && !selectedOrderItemDto.AverageWeightIsValid) cssClass = "text-warning";
else if (isValidAndMeasured) cssClass = "text-success";
else if (isValid) cssClass = string.Empty; else if (isValid) cssClass = string.Empty;
var displayText = $"{selectedOrderItemDto.ProductName} - [{trayQuantity}/{selectedOrderItemDto.Quantity} rekesz, {(selectedOrderItemDto.IsMeasurable ? "net.súly: " + selectedOrderItemDto.NetWeight + "kg." : "nem mérendő!")}]"; var displayText = $"{selectedOrderItemDto.ProductName} - [{trayQuantity}/{selectedOrderItemDto.Quantity} rekesz, {(selectedOrderItemDto.IsMeasurable ? "net.súly: " + selectedOrderItemDto.NetWeight + "kg." : "nem mérendő!")}]";

View File

@ -326,6 +326,10 @@ namespace FruitBankHybrid.Shared.Services.SignalRs
throw new NotImplementedException(); throw new NotImplementedException();
} }
public Task<StockTaking?> CloseStockTaking(int stockTakingId)
=> PostDataAsync<int, StockTaking?>(SignalRTags.CloseStockTaking, stockTakingId);
public async Task<StockTakingItemPallet?> AddStockTakingItemPallet(StockTakingItemPallet stockTakingItemPallet) public async Task<StockTakingItemPallet?> AddStockTakingItemPallet(StockTakingItemPallet stockTakingItemPallet)
{ {
throw new NotImplementedException(); throw new NotImplementedException();