mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
Merged PR 1888: fix: improve sorting of remission return receipts
fix: improve sorting of remission return receipts - Refactor data fetching to use a single API call for all returns - Apply sorting separately to completed and incomplete returns - Fix template tracking to use index instead of potentially undefined ID - Remove redundant API calls for incomplete returns This ensures proper sorting of remission return receipts while maintaining the separation between completed and incomplete items in the display order. Ref: #5224
This commit is contained in:
committed by
Nino Righi
parent
442670bdd0
commit
598df7d5ed
@@ -50,7 +50,7 @@ export class RemissionReturnReceiptService {
|
|||||||
* const completedReturns = await service
|
* const completedReturns = await service
|
||||||
* .fetchCompletedRemissionReturnReceipts(controller.signal);
|
* .fetchCompletedRemissionReturnReceipts(controller.signal);
|
||||||
*/
|
*/
|
||||||
async fetchCompletedRemissionReturnReceipts(
|
async fetchRemissionReturnReceipts(
|
||||||
abortSignal?: AbortSignal,
|
abortSignal?: AbortSignal,
|
||||||
): Promise<Return[]> {
|
): Promise<Return[]> {
|
||||||
this.#logger.debug('Fetching completed remission return receipts');
|
this.#logger.debug('Fetching completed remission return receipts');
|
||||||
@@ -108,50 +108,50 @@ export class RemissionReturnReceiptService {
|
|||||||
* const incompleteReturns = await service
|
* const incompleteReturns = await service
|
||||||
* .fetchIncompletedRemissionReturnReceipts();
|
* .fetchIncompletedRemissionReturnReceipts();
|
||||||
*/
|
*/
|
||||||
async fetchIncompletedRemissionReturnReceipts(
|
// async fetchIncompletedRemissionReturnReceipts(
|
||||||
abortSignal?: AbortSignal,
|
// abortSignal?: AbortSignal,
|
||||||
): Promise<Return[]> {
|
// ): Promise<Return[]> {
|
||||||
this.#logger.debug('Fetching incomplete remission return receipts');
|
// this.#logger.debug('Fetching incomplete remission return receipts');
|
||||||
|
|
||||||
const assignedStock =
|
// const assignedStock =
|
||||||
await this.#remissionStockService.fetchAssignedStock(abortSignal);
|
// await this.#remissionStockService.fetchAssignedStock(abortSignal);
|
||||||
|
|
||||||
this.#logger.info('Fetching incomplete returns from API', () => ({
|
// this.#logger.info('Fetching incomplete returns from API', () => ({
|
||||||
stockId: assignedStock.id,
|
// stockId: assignedStock.id,
|
||||||
startDate: subDays(new Date(), 7).toISOString(),
|
// startDate: subDays(new Date(), 7).toISOString(),
|
||||||
}));
|
// }));
|
||||||
|
|
||||||
let req$ = this.#returnService.ReturnQueryReturns({
|
// let req$ = this.#returnService.ReturnQueryReturns({
|
||||||
stockId: assignedStock.id,
|
// stockId: assignedStock.id,
|
||||||
queryToken: {
|
// queryToken: {
|
||||||
input: { returncompleted: 'false' },
|
// input: { returncompleted: 'false' },
|
||||||
start: subDays(new Date(), 7).toISOString(),
|
// start: subDays(new Date(), 7).toISOString(),
|
||||||
eagerLoading: 3,
|
// eagerLoading: 3,
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
|
|
||||||
if (abortSignal) {
|
// if (abortSignal) {
|
||||||
this.#logger.debug('Request configured with abort signal');
|
// this.#logger.debug('Request configured with abort signal');
|
||||||
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
// req$ = req$.pipe(takeUntilAborted(abortSignal));
|
||||||
}
|
// }
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
// const res = await firstValueFrom(req$);
|
||||||
|
|
||||||
if (res?.error) {
|
// if (res?.error) {
|
||||||
this.#logger.error(
|
// this.#logger.error(
|
||||||
'Failed to fetch incomplete returns',
|
// 'Failed to fetch incomplete returns',
|
||||||
new Error(res.message || 'Unknown error'),
|
// new Error(res.message || 'Unknown error'),
|
||||||
);
|
// );
|
||||||
throw new ResponseArgsError(res);
|
// throw new ResponseArgsError(res);
|
||||||
}
|
// }
|
||||||
|
|
||||||
const returns = (res?.result as Return[]) || [];
|
// const returns = (res?.result as Return[]) || [];
|
||||||
this.#logger.debug('Successfully fetched incomplete returns', () => ({
|
// this.#logger.debug('Successfully fetched incomplete returns', () => ({
|
||||||
returnCount: returns.length,
|
// returnCount: returns.length,
|
||||||
}));
|
// }));
|
||||||
|
|
||||||
return returns;
|
// return returns;
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches a specific remission return receipt by receipt and return IDs.
|
* Fetches a specific remission return receipt by receipt and return IDs.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-flow-rows grid-cols-1 gap-4">
|
<div class="grid grid-flow-rows grid-cols-1 gap-4">
|
||||||
@for (remissionReturn of returns(); track remissionReturn[1].id) {
|
@for (remissionReturn of returns(); track $index) {
|
||||||
<a [routerLink]="[remissionReturn[0].id, remissionReturn[1].id]">
|
<a [routerLink]="[remissionReturn[0].id, remissionReturn[1].id]">
|
||||||
<remi-return-receipt-list-item
|
<remi-return-receipt-list-item
|
||||||
[remissionReturn]="remissionReturn[0]"
|
[remissionReturn]="remissionReturn[0]"
|
||||||
|
|||||||
@@ -64,19 +64,19 @@ export class RemissionReturnReceiptListComponent {
|
|||||||
* Resource that fetches completed remission return receipts.
|
* Resource that fetches completed remission return receipts.
|
||||||
* Automatically loads when the component is initialized.
|
* Automatically loads when the component is initialized.
|
||||||
*/
|
*/
|
||||||
completedRemissionReturnsResource = resource({
|
remissionReturnsResource = resource({
|
||||||
loader: () =>
|
loader: () =>
|
||||||
this.#remissionReturnReceiptService.fetchCompletedRemissionReturnReceipts(),
|
this.#remissionReturnReceiptService.fetchRemissionReturnReceipts(),
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resource that fetches incomplete remission return receipts.
|
* Resource that fetches incomplete remission return receipts.
|
||||||
* Automatically loads when the component is initialized.
|
* Automatically loads when the component is initialized.
|
||||||
*/
|
*/
|
||||||
incompletedRemissionReturnsResource = resource({
|
// incompletedRemissionReturnsResource = resource({
|
||||||
loader: () =>
|
// loader: () =>
|
||||||
this.#remissionReturnReceiptService.fetchIncompletedRemissionReturnReceipts(),
|
// this.#remissionReturnReceiptService.fetchIncompletedRemissionReturnReceipts(),
|
||||||
});
|
// });
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computed signal that combines completed and incomplete returns.
|
* Computed signal that combines completed and incomplete returns.
|
||||||
@@ -85,32 +85,35 @@ export class RemissionReturnReceiptListComponent {
|
|||||||
* @returns {Array<[Return, Receipt]>} Array of tuples containing return and receipt pairs
|
* @returns {Array<[Return, Receipt]>} Array of tuples containing return and receipt pairs
|
||||||
*/
|
*/
|
||||||
returns = computed(() => {
|
returns = computed(() => {
|
||||||
const completed = this.completedRemissionReturnsResource.value() || [];
|
const returns = this.remissionReturnsResource.value() || [];
|
||||||
const incompleted = this.incompletedRemissionReturnsResource.value() || [];
|
let completed = returns.filter((ret) => ret.completed);
|
||||||
|
let incompleted = returns.filter((ret) => !ret.completed);
|
||||||
const orderBy = this.orderDateBy();
|
const orderBy = this.orderDateBy();
|
||||||
|
|
||||||
const allReturnReceiptTuples = [...incompleted, ...completed].flatMap(
|
if (orderBy) {
|
||||||
(ret) =>
|
const compareFn = (a: string | undefined, b: string | undefined) => {
|
||||||
ret.receipts
|
if (a === undefined) return 1;
|
||||||
.filter((rec) => rec.data != null)
|
if (b === undefined) return -1;
|
||||||
.map((rec) => [ret, rec.data] as [Return, Receipt]),
|
return (orderBy.dir === 'desc' ? compareDesc : compareAsc)(a, b);
|
||||||
);
|
};
|
||||||
|
|
||||||
if (!orderBy) {
|
const orderByField = orderBy.by as 'created' | 'completed';
|
||||||
return allReturnReceiptTuples;
|
completed = orderByKey(completed, orderByField, compareFn);
|
||||||
|
incompleted = orderByKey(incompleted, orderByField, compareFn);
|
||||||
}
|
}
|
||||||
|
|
||||||
const orderByField = orderBy.by as 'created' | 'completed';
|
return [...incompleted, ...completed].flatMap((ret) =>
|
||||||
const compareFn = orderBy.dir === 'desc' ? compareDesc : compareAsc;
|
ret.receipts
|
||||||
|
.filter((rec) => rec.data != null)
|
||||||
return allReturnReceiptTuples.sort((a, b) => {
|
.map((rec) => [ret, rec.data] as [Return, Receipt]),
|
||||||
const dateA = a[1][orderByField];
|
);
|
||||||
const dateB = b[1][orderByField];
|
|
||||||
|
|
||||||
if (!dateA) return -1;
|
|
||||||
if (!dateB) return 1;
|
|
||||||
|
|
||||||
return compareFn(dateA, dateB);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function orderByKey<T, K extends keyof T>(
|
||||||
|
items: T[],
|
||||||
|
by: K,
|
||||||
|
compareFn: T[K] extends infer U ? (a: U, b: U) => number : never,
|
||||||
|
): T[] {
|
||||||
|
return [...items].sort((a, b) => compareFn(a[by], b[by]) ?? 0);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user