mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
Merged PR 1936: fix(remission): filter search results by stock availability and display stock...
fix(remission): filter search results by stock availability and display stock info - Add stock resource integration to search item component - Filter search results to only show items with available stock (> 0) - Display current stock information in search result items - Implement calculateAvailableStock utility for accurate stock calculation - Add inStock input parameter to SearchItemToRemitComponent - Create reusable instock.resource for stock data fetching The search now only displays items that are actually available for remission, improving user experience by preventing selection of out-of-stock items. Ref: #5318
This commit is contained in:
committed by
Andreas Schickinger
parent
e58ec93087
commit
c52f18e979
@@ -0,0 +1,39 @@
|
||||
import { inject, resource } from '@angular/core';
|
||||
import { RemissionStockService } from '@isa/remission/data-access';
|
||||
|
||||
export const createInStockResource = (
|
||||
params: () => {
|
||||
itemIds: number[];
|
||||
},
|
||||
) => {
|
||||
const remissionStockService = inject(RemissionStockService);
|
||||
return resource({
|
||||
params,
|
||||
loader: async ({ abortSignal, params }) => {
|
||||
if (!params?.itemIds || params.itemIds.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const assignedStock =
|
||||
await remissionStockService.fetchAssignedStock(abortSignal);
|
||||
|
||||
if (!assignedStock || !assignedStock.id) {
|
||||
throw new Error('No current stock available');
|
||||
}
|
||||
|
||||
const itemIds = params.itemIds;
|
||||
|
||||
if (itemIds.some((id) => isNaN(id))) {
|
||||
throw new Error('Invalid Catalog Product Number provided');
|
||||
}
|
||||
|
||||
return await remissionStockService.fetchStock(
|
||||
{
|
||||
itemIds,
|
||||
assignedStockId: assignedStock.id,
|
||||
},
|
||||
abortSignal,
|
||||
);
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -38,12 +38,16 @@
|
||||
@if (searchResource.value()?.result; as items) {
|
||||
@for (item of items; track item.id) {
|
||||
@defer {
|
||||
<remi-search-item-to-remit
|
||||
[item]="item"
|
||||
data-what="list-item"
|
||||
data-which="search-result"
|
||||
[attr.data-item-id]="item.id"
|
||||
></remi-search-item-to-remit>
|
||||
@let inStock = getAvailableStockForItem(item);
|
||||
@if (inStock > 0) {
|
||||
<remi-search-item-to-remit
|
||||
[item]="item"
|
||||
[inStock]="inStock"
|
||||
data-what="list-item"
|
||||
data-which="search-result"
|
||||
[attr.data-item-id]="item.id"
|
||||
></remi-search-item-to-remit>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
computed,
|
||||
inject,
|
||||
OnInit,
|
||||
resource,
|
||||
@@ -28,6 +29,8 @@ import {
|
||||
import { SearchItemToRemitDialogComponent } from './search-item-to-remit-dialog.component';
|
||||
import { CdkTrapFocus } from '@angular/cdk/a11y';
|
||||
import { TooltipDirective } from '@isa/ui/tooltip';
|
||||
import { createInStockResource } from './instock.resource';
|
||||
import { calculateAvailableStock } from '@isa/remission/data-access';
|
||||
@Component({
|
||||
selector: 'remi-search-item-to-remit-list',
|
||||
templateUrl: './search-item-to-remit-list.component.html',
|
||||
@@ -52,6 +55,30 @@ export class SearchItemToRemitListComponent implements OnInit {
|
||||
|
||||
searchParams = signal<SearchByTermInput | undefined>(undefined);
|
||||
|
||||
inStockResource = createInStockResource(() => {
|
||||
return {
|
||||
itemIds:
|
||||
this.searchResource
|
||||
.value()
|
||||
?.result?.map((item) => item?.id)
|
||||
.filter((id) => !!id) ?? [],
|
||||
};
|
||||
});
|
||||
inStockResponseValue = computed(() => this.inStockResource.value());
|
||||
|
||||
stockInfoMap = computed(() => {
|
||||
const infos = this.inStockResponseValue() ?? [];
|
||||
return new Map(infos.map((info) => [info.itemId, info]));
|
||||
});
|
||||
|
||||
getAvailableStockForItem(item: Item): number {
|
||||
const stockInfo = this.stockInfoMap().get(item.id);
|
||||
return calculateAvailableStock({
|
||||
stock: stockInfo?.inStock,
|
||||
removedFromStock: stockInfo?.removedFromStock,
|
||||
});
|
||||
}
|
||||
|
||||
triggerSearch(): void {
|
||||
this.searchParams.set({
|
||||
searchTerm: this.host.searchTerm(),
|
||||
|
||||
@@ -6,7 +6,13 @@
|
||||
[orientation]="productInfoOrientation()"
|
||||
[innerGridClass]="'grid-cols-[minmax(20rem,1fr),minmax(18rem,auto)]'"
|
||||
></remi-product-info>
|
||||
<div class="text-right">
|
||||
<div class="flex flex-col items-end justify-center gap-6">
|
||||
<div
|
||||
class="text-isa-neutral-900 w-[18rem] flex flex-row items-center justify-between"
|
||||
>
|
||||
<span class="isa-text-body-2-regular">Aktueller Bestand</span>
|
||||
<span class="isa-text-body-2-bold">{{ inStock() }}x</span>
|
||||
</div>
|
||||
<button
|
||||
class="-mr-5"
|
||||
type="button"
|
||||
|
||||
@@ -22,6 +22,7 @@ export class SearchItemToRemitComponent {
|
||||
host = inject(SearchItemToRemitDialogComponent);
|
||||
|
||||
item = input.required<Item>();
|
||||
inStock = input.required<number>();
|
||||
|
||||
desktopBreakpoint = breakpoint([Breakpoint.DekstopL, Breakpoint.DekstopXL]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user