mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
Merged PR 1893: feat(remission): add remission processed hint component and update schemas
feat(remission): add remission processed hint component and update schemas - Introduced RemissionProcessedHintComponent to display hints based on remission processing status. - Updated fetch-remission-return-receipts schema to include parameters for completed returns. - Refactored remission return receipt service to handle completed and incomplete returns separately. - Adjusted remission list component to utilize the new hint component and updated data fetching logic. Refs: #5240 #5136
This commit is contained in:
committed by
Nino Righi
parent
71e9a6da0e
commit
72bcacefb6
@@ -0,0 +1,14 @@
|
||||
import z from 'zod';
|
||||
|
||||
export const FetchRemissionReturnReceiptsSchema = z.object({
|
||||
returncompleted: z.boolean(),
|
||||
start: z.coerce.date().optional(),
|
||||
});
|
||||
|
||||
export type FetchRemissionReturnReceipts = z.infer<
|
||||
typeof FetchRemissionReturnReceiptsSchema
|
||||
>;
|
||||
|
||||
export type FetchRemissionReturnReceiptsParams = z.input<
|
||||
typeof FetchRemissionReturnReceiptsSchema
|
||||
>;
|
||||
@@ -1,9 +1,10 @@
|
||||
export * from './fetch-query-settings.schema';
|
||||
export * from './fetch-remission-return-receipt.schema';
|
||||
export * from './fetch-stock-in-stock.schema';
|
||||
export * from './query-token.schema';
|
||||
export * from './create-return.schema';
|
||||
export * from './create-receipt.schema';
|
||||
export * from './assign-package.schema';
|
||||
export * from './add-return-item.schema';
|
||||
export * from './add-return-suggestion.schema';
|
||||
export * from './assign-package.schema';
|
||||
export * from './create-receipt.schema';
|
||||
export * from './create-return.schema';
|
||||
export * from './fetch-query-settings.schema';
|
||||
export * from './fetch-remission-return-receipt.schema';
|
||||
export * from './fetch-remission-return-receipts.schema';
|
||||
export * from './fetch-stock-in-stock.schema';
|
||||
export * from './query-token.schema';
|
||||
|
||||
@@ -16,6 +16,8 @@ import {
|
||||
CreateReturnSchema,
|
||||
FetchRemissionReturnParams,
|
||||
FetchRemissionReturnReceiptSchema,
|
||||
FetchRemissionReturnReceiptsParams,
|
||||
FetchRemissionReturnReceiptsSchema,
|
||||
} from '../schemas';
|
||||
import {
|
||||
Receipt,
|
||||
@@ -67,23 +69,27 @@ export class RemissionReturnReceiptService {
|
||||
* .fetchCompletedRemissionReturnReceipts(controller.signal);
|
||||
*/
|
||||
async fetchRemissionReturnReceipts(
|
||||
params: FetchRemissionReturnReceiptsParams,
|
||||
abortSignal?: AbortSignal,
|
||||
): Promise<Return[]> {
|
||||
this.#logger.debug('Fetching completed remission return receipts');
|
||||
|
||||
const { start, returncompleted } =
|
||||
FetchRemissionReturnReceiptsSchema.parse(params);
|
||||
|
||||
const assignedStock =
|
||||
await this.#remissionStockService.fetchAssignedStock(abortSignal);
|
||||
|
||||
this.#logger.info('Fetching completed returns from API', () => ({
|
||||
stockId: assignedStock.id,
|
||||
startDate: subDays(new Date(), 7).toISOString(),
|
||||
startDate: start?.toISOString(),
|
||||
}));
|
||||
|
||||
let req$ = this.#returnService.ReturnQueryReturns({
|
||||
stockId: assignedStock.id,
|
||||
queryToken: {
|
||||
input: { returncompleted: 'true' },
|
||||
start: subDays(new Date(), 7).toISOString(),
|
||||
filter: { returncompleted: returncompleted ? 'true' : 'false' },
|
||||
start: start?.toISOString(),
|
||||
eagerLoading: 3,
|
||||
},
|
||||
});
|
||||
@@ -111,64 +117,6 @@ export class RemissionReturnReceiptService {
|
||||
return returns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches all incomplete remission return receipts for the assigned stock.
|
||||
* Returns receipts not yet marked as completed within the last 7 days.
|
||||
*
|
||||
* @async
|
||||
* @param {AbortSignal} [abortSignal] - Optional signal to abort the request
|
||||
* @returns {Promise<Return[]>} Array of incomplete return objects with receipts
|
||||
* @throws {ResponseArgsError} When the API request fails
|
||||
*
|
||||
* @example
|
||||
* const incompleteReturns = await service
|
||||
* .fetchIncompletedRemissionReturnReceipts();
|
||||
*/
|
||||
// async fetchIncompletedRemissionReturnReceipts(
|
||||
// abortSignal?: AbortSignal,
|
||||
// ): Promise<Return[]> {
|
||||
// this.#logger.debug('Fetching incomplete remission return receipts');
|
||||
|
||||
// const assignedStock =
|
||||
// await this.#remissionStockService.fetchAssignedStock(abortSignal);
|
||||
|
||||
// this.#logger.info('Fetching incomplete returns from API', () => ({
|
||||
// stockId: assignedStock.id,
|
||||
// startDate: subDays(new Date(), 7).toISOString(),
|
||||
// }));
|
||||
|
||||
// let req$ = this.#returnService.ReturnQueryReturns({
|
||||
// stockId: assignedStock.id,
|
||||
// queryToken: {
|
||||
// input: { returncompleted: 'false' },
|
||||
// start: subDays(new Date(), 7).toISOString(),
|
||||
// eagerLoading: 3,
|
||||
// },
|
||||
// });
|
||||
|
||||
// if (abortSignal) {
|
||||
// this.#logger.debug('Request configured with abort signal');
|
||||
// req$ = req$.pipe(takeUntilAborted(abortSignal));
|
||||
// }
|
||||
|
||||
// const res = await firstValueFrom(req$);
|
||||
|
||||
// if (res?.error) {
|
||||
// this.#logger.error(
|
||||
// 'Failed to fetch incomplete returns',
|
||||
// new Error(res.message || 'Unknown error'),
|
||||
// );
|
||||
// throw new ResponseArgsError(res);
|
||||
// }
|
||||
|
||||
// const returns = (res?.result as Return[]) || [];
|
||||
// this.#logger.debug('Successfully fetched incomplete returns', () => ({
|
||||
// returnCount: returns.length,
|
||||
// }));
|
||||
|
||||
// return returns;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Fetches a specific remission return receipt by receipt and return IDs.
|
||||
* Validates parameters using FetchRemissionReturnReceiptSchema before making the request.
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
<remi-remission-processed-hint></remi-remission-processed-hint>
|
||||
|
||||
@if (!remissionStarted()) {
|
||||
<remi-feature-remission-start-card></remi-feature-remission-start-card>
|
||||
} @else {
|
||||
|
||||
@@ -44,6 +44,7 @@ import { SearchItemToRemitDialogComponent } from '@isa/remission/shared/search-i
|
||||
import { RemissionListType } from '@isa/remission/data-access';
|
||||
import { RemissionReturnCardComponent } from './remission-return-card/remission-return-card.component';
|
||||
import { logger } from '@isa/core/logging';
|
||||
import { RemissionProcessedHintComponent } from './remission-processed-hint/remission-processed-hint.component';
|
||||
|
||||
function querySettingsFactory() {
|
||||
return inject(ActivatedRoute).snapshot.data['querySettings'];
|
||||
@@ -83,6 +84,7 @@ function querySettingsFactory() {
|
||||
RemissionListItemComponent,
|
||||
IconButtonComponent,
|
||||
StatefulButtonComponent,
|
||||
RemissionProcessedHintComponent,
|
||||
],
|
||||
host: {
|
||||
'[class]':
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
@if (showHint() && !isLoading()) {
|
||||
<ng-icon name="isaOtherInfo" size="1.5rem"></ng-icon>
|
||||
<span class="mt-[2px]">
|
||||
Die Remissionsliste wurde seit {{ daysThreshold() }} Tagen nicht bearbeitet
|
||||
</span>
|
||||
} @else if (error()) {
|
||||
<button (click)="retry()" class="text-isa-accent-red hover:underline">
|
||||
Fehler beim Laden. Erneut versuchen
|
||||
</button>
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
:host {
|
||||
@apply flex items-start gap-1 justify-start;
|
||||
@apply text-isa-accent-red isa-text-body-2-bold;
|
||||
|
||||
&:empty {
|
||||
@apply hidden;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
computed,
|
||||
inject,
|
||||
input,
|
||||
resource,
|
||||
} from '@angular/core';
|
||||
import { isaOtherInfo } from '@isa/icons';
|
||||
import { RemissionReturnReceiptService } from '@isa/remission/data-access';
|
||||
import { NgIcon, provideIcons } from '@ng-icons/core';
|
||||
import { subDays } from 'date-fns';
|
||||
|
||||
@Component({
|
||||
selector: 'remi-remission-processed-hint',
|
||||
templateUrl: './remission-processed-hint.component.html',
|
||||
styleUrls: ['./remission-processed-hint.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [NgIcon],
|
||||
providers: [provideIcons({ isaOtherInfo })],
|
||||
})
|
||||
export class RemissionProcessedHintComponent {
|
||||
readonly #remissionReturnReceiptService = inject(
|
||||
RemissionReturnReceiptService,
|
||||
);
|
||||
|
||||
/**
|
||||
* Threshold in days where at least one remission has been processed.
|
||||
* If no remission has been processed in the last 7 days,
|
||||
* the hint will be displayed.
|
||||
*/
|
||||
readonly daysThreshold = input<number>(7);
|
||||
|
||||
/**
|
||||
* Resource that fetches remission return receipts.
|
||||
* Automatically loads when the component is initialized.
|
||||
*/
|
||||
readonly returnReceiptsResource = resource({
|
||||
params: () => ({
|
||||
returncompleted: false,
|
||||
start: subDays(new Date(), this.daysThreshold()),
|
||||
}),
|
||||
loader: ({ params, abortSignal }) =>
|
||||
this.#remissionReturnReceiptService.fetchRemissionReturnReceipts(
|
||||
params,
|
||||
abortSignal,
|
||||
),
|
||||
});
|
||||
|
||||
readonly showHint = computed(() => {
|
||||
const receipts = this.returnReceiptsResource.value();
|
||||
return receipts && receipts.length === 0;
|
||||
});
|
||||
|
||||
readonly error = this.returnReceiptsResource.error;
|
||||
|
||||
readonly isLoading = this.returnReceiptsResource.isLoading;
|
||||
|
||||
readonly retry = () => {
|
||||
this.returnReceiptsResource.reload();
|
||||
};
|
||||
}
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
FilterService,
|
||||
} from '@isa/shared/filter';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { compareAsc, compareDesc } from 'date-fns';
|
||||
import { compareAsc, compareDesc, subDays } from 'date-fns';
|
||||
import { RETURN_RECEIPT_QUERY_SETTINGS } from './remission-return-receipt-list.query-settings';
|
||||
|
||||
/**
|
||||
@@ -64,19 +64,25 @@ export class RemissionReturnReceiptListComponent {
|
||||
* Resource that fetches completed remission return receipts.
|
||||
* Automatically loads when the component is initialized.
|
||||
*/
|
||||
remissionReturnsResource = resource({
|
||||
loader: () =>
|
||||
this.#remissionReturnReceiptService.fetchRemissionReturnReceipts(),
|
||||
completedRemissionReturnsResource = resource({
|
||||
loader: ({ abortSignal }) =>
|
||||
this.#remissionReturnReceiptService.fetchRemissionReturnReceipts(
|
||||
{ returncompleted: true, start: subDays(new Date(), 7) },
|
||||
abortSignal,
|
||||
),
|
||||
});
|
||||
|
||||
/**
|
||||
* Resource that fetches incomplete remission return receipts.
|
||||
* Automatically loads when the component is initialized.
|
||||
*/
|
||||
// incompletedRemissionReturnsResource = resource({
|
||||
// loader: () =>
|
||||
// this.#remissionReturnReceiptService.fetchIncompletedRemissionReturnReceipts(),
|
||||
// });
|
||||
incompletedRemissionReturnsResource = resource({
|
||||
loader: ({ abortSignal }) =>
|
||||
this.#remissionReturnReceiptService.fetchRemissionReturnReceipts(
|
||||
{ returncompleted: false },
|
||||
abortSignal,
|
||||
),
|
||||
});
|
||||
|
||||
/**
|
||||
* Computed signal that combines completed and incomplete returns.
|
||||
@@ -85,9 +91,8 @@ export class RemissionReturnReceiptListComponent {
|
||||
* @returns {Array<[Return, Receipt]>} Array of tuples containing return and receipt pairs
|
||||
*/
|
||||
returns = computed(() => {
|
||||
const returns = this.remissionReturnsResource.value() || [];
|
||||
let completed = returns.filter((ret) => ret.completed);
|
||||
let incompleted = returns.filter((ret) => !ret.completed);
|
||||
let completed = this.completedRemissionReturnsResource.value() || [];
|
||||
let incompleted = this.incompletedRemissionReturnsResource.value() || [];
|
||||
const orderBy = this.orderDateBy();
|
||||
|
||||
if (orderBy) {
|
||||
|
||||
Reference in New Issue
Block a user