mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
Merge branch 'release/4.0'
This commit is contained in:
@@ -1,18 +1,18 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Logger, LogLevel } from '@core/logger';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { debounceTime, switchMap, takeUntil } from 'rxjs/operators';
|
||||
import { RootState } from './root.state';
|
||||
import packageInfo from 'packageJson';
|
||||
import { environment } from '../../environments/environment';
|
||||
import { Subject } from 'rxjs';
|
||||
import { AuthService } from '@core/auth';
|
||||
import { injectStorage, UserStorageProvider } from '@isa/core/storage';
|
||||
import { isEqual } from 'lodash';
|
||||
import { Injectable } from "@angular/core";
|
||||
import { Logger, LogLevel } from "@core/logger";
|
||||
import { Store } from "@ngrx/store";
|
||||
import { debounceTime, switchMap, takeUntil } from "rxjs/operators";
|
||||
import { RootState } from "./root.state";
|
||||
import packageInfo from "packageJson";
|
||||
import { environment } from "../../environments/environment";
|
||||
import { Subject } from "rxjs";
|
||||
import { AuthService } from "@core/auth";
|
||||
import { injectStorage, UserStorageProvider } from "@isa/core/storage";
|
||||
import { isEqual } from "lodash";
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
@Injectable({ providedIn: "root" })
|
||||
export class RootStateService {
|
||||
static LOCAL_STORAGE_KEY = 'ISA_APP_INITIALSTATE';
|
||||
static LOCAL_STORAGE_KEY = "ISA_APP_INITIALSTATE";
|
||||
|
||||
#storage = injectStorage(UserStorageProvider);
|
||||
|
||||
@@ -29,14 +29,17 @@ export class RootStateService {
|
||||
);
|
||||
}
|
||||
|
||||
window['clearUserState'] = () => {
|
||||
window["clearUserState"] = () => {
|
||||
this.clear();
|
||||
};
|
||||
}
|
||||
|
||||
async init() {
|
||||
await this.load();
|
||||
this._store.dispatch({ type: 'HYDRATE', payload: RootStateService.LoadFromLocalStorage() });
|
||||
this._store.dispatch({
|
||||
type: "HYDRATE",
|
||||
payload: RootStateService.LoadFromLocalStorage(),
|
||||
});
|
||||
this.initSave();
|
||||
}
|
||||
|
||||
@@ -50,14 +53,10 @@ export class RootStateService {
|
||||
const data = {
|
||||
...state,
|
||||
version: packageInfo.version,
|
||||
sub: this._authService.getClaimByKey('sub'),
|
||||
sub: this._authService.getClaimByKey("sub"),
|
||||
};
|
||||
RootStateService.SaveToLocalStorageRaw(JSON.stringify(data));
|
||||
return this.#storage.set('state', {
|
||||
...state,
|
||||
version: packageInfo.version,
|
||||
sub: this._authService.getClaimByKey('sub'),
|
||||
});
|
||||
return this.#storage.set("state", data);
|
||||
}),
|
||||
)
|
||||
.subscribe();
|
||||
@@ -68,7 +67,7 @@ export class RootStateService {
|
||||
*/
|
||||
async load(): Promise<boolean> {
|
||||
try {
|
||||
const res = await this.#storage.get('state');
|
||||
const res = await this.#storage.get("state");
|
||||
|
||||
const storageContent = RootStateService.LoadFromLocalStorageRaw();
|
||||
|
||||
@@ -88,7 +87,7 @@ export class RootStateService {
|
||||
async clear() {
|
||||
try {
|
||||
this._cancelSave.next();
|
||||
await this.#storage.clear('state');
|
||||
await this.#storage.clear("state");
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
RootStateService.RemoveFromLocalStorage();
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
@@ -112,7 +111,7 @@ export class RootStateService {
|
||||
try {
|
||||
return JSON.parse(raw);
|
||||
} catch (error) {
|
||||
console.error('Error parsing local storage:', error);
|
||||
console.error("Error parsing local storage:", error);
|
||||
this.RemoveFromLocalStorage();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,20 +16,20 @@ import {
|
||||
forwardRef,
|
||||
Optional,
|
||||
inject,
|
||||
} from '@angular/core';
|
||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
import { UiAutocompleteComponent } from '@ui/autocomplete';
|
||||
import { UiFormControlDirective } from '@ui/form-control';
|
||||
import { containsElement } from '@utils/common';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { ScanAdapterService } from '@adapter/scan';
|
||||
import { injectCancelSearch } from '@shared/services/cancel-subject';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
} from "@angular/core";
|
||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms";
|
||||
import { UiAutocompleteComponent } from "@ui/autocomplete";
|
||||
import { UiFormControlDirective } from "@ui/form-control";
|
||||
import { containsElement } from "@utils/common";
|
||||
import { Subscription } from "rxjs";
|
||||
import { ScanAdapterService } from "@adapter/scan";
|
||||
import { injectCancelSearch } from "@shared/services/cancel-subject";
|
||||
import { EnvironmentService } from "@core/environment";
|
||||
|
||||
@Component({
|
||||
selector: 'shared-searchbox',
|
||||
templateUrl: 'searchbox.component.html',
|
||||
styleUrls: ['searchbox.component.scss'],
|
||||
selector: "shared-searchbox",
|
||||
templateUrl: "searchbox.component.html",
|
||||
styleUrls: ["searchbox.component.scss"],
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
@@ -49,9 +49,9 @@ export class SearchboxComponent
|
||||
cancelSearch = injectCancelSearch({ optional: true });
|
||||
|
||||
disabled: boolean;
|
||||
type = 'text';
|
||||
type = "text";
|
||||
|
||||
@ViewChild('input', { read: ElementRef, static: true })
|
||||
@ViewChild("input", { read: ElementRef, static: true })
|
||||
input: ElementRef;
|
||||
|
||||
@ContentChild(UiAutocompleteComponent)
|
||||
@@ -61,9 +61,9 @@ export class SearchboxComponent
|
||||
focusAfterViewInit = true;
|
||||
|
||||
@Input()
|
||||
placeholder = '';
|
||||
placeholder = "";
|
||||
|
||||
private _query = '';
|
||||
private _query = "";
|
||||
|
||||
@Input()
|
||||
get query() {
|
||||
@@ -94,7 +94,7 @@ export class SearchboxComponent
|
||||
scanner = false;
|
||||
|
||||
@Input()
|
||||
hint = '';
|
||||
hint = "";
|
||||
|
||||
@Input()
|
||||
autocompleteValueSelector: (item: any) => string = (item: any) => item;
|
||||
@@ -104,11 +104,11 @@ export class SearchboxComponent
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this.setQuery('');
|
||||
this.setQuery("");
|
||||
this.cancelSearch();
|
||||
}
|
||||
|
||||
@HostBinding('class.autocomplete-opend')
|
||||
@HostBinding("class.autocomplete-opend")
|
||||
get autocompleteOpen() {
|
||||
return this.autocomplete?.opend;
|
||||
}
|
||||
@@ -213,13 +213,13 @@ export class SearchboxComponent
|
||||
}
|
||||
|
||||
clearHint() {
|
||||
this.hint = '';
|
||||
this.hint = "";
|
||||
this.focused.emit(true);
|
||||
this.cdr.markForCheck();
|
||||
}
|
||||
|
||||
onKeyup(event: KeyboardEvent) {
|
||||
if (event.key === 'Enter') {
|
||||
if (event.key === "Enter") {
|
||||
if (this.autocomplete?.opend && this.autocomplete?.activeItem) {
|
||||
this.setQuery(this.autocomplete?.activeItem?.item);
|
||||
this.autocomplete?.close();
|
||||
@@ -227,7 +227,7 @@ export class SearchboxComponent
|
||||
this.search.emit(this.query);
|
||||
|
||||
event.preventDefault();
|
||||
} else if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {
|
||||
} else if (event.key === "ArrowUp" || event.key === "ArrowDown") {
|
||||
this.handleArrowUpDownEvent(event);
|
||||
}
|
||||
}
|
||||
@@ -242,7 +242,7 @@ export class SearchboxComponent
|
||||
}
|
||||
}
|
||||
|
||||
@HostListener('window:click', ['$event'])
|
||||
@HostListener("window:click", ["$event"])
|
||||
focusLost(event: MouseEvent) {
|
||||
if (
|
||||
this.autocomplete?.opend &&
|
||||
@@ -256,9 +256,11 @@ export class SearchboxComponent
|
||||
this.search.emit(this.query);
|
||||
}
|
||||
|
||||
@HostListener('focusout', ['$event'])
|
||||
@HostListener("focusout", ["$event"])
|
||||
onBlur() {
|
||||
this.onTouched();
|
||||
if (typeof this.onTouched === "function") {
|
||||
this.onTouched();
|
||||
}
|
||||
this.focused.emit(false);
|
||||
this.cdr.markForCheck();
|
||||
}
|
||||
|
||||
@@ -16,20 +16,20 @@ import {
|
||||
forwardRef,
|
||||
Optional,
|
||||
inject,
|
||||
} from '@angular/core';
|
||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
import { UiAutocompleteComponent } from '@ui/autocomplete';
|
||||
import { UiFormControlDirective } from '@ui/form-control';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { ScanAdapterService } from '@adapter/scan';
|
||||
import { injectCancelSearch } from '@shared/services/cancel-subject';
|
||||
import { containsElement } from '@utils/common';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
} from "@angular/core";
|
||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms";
|
||||
import { UiAutocompleteComponent } from "@ui/autocomplete";
|
||||
import { UiFormControlDirective } from "@ui/form-control";
|
||||
import { Subscription } from "rxjs";
|
||||
import { ScanAdapterService } from "@adapter/scan";
|
||||
import { injectCancelSearch } from "@shared/services/cancel-subject";
|
||||
import { containsElement } from "@utils/common";
|
||||
import { EnvironmentService } from "@core/environment";
|
||||
|
||||
@Component({
|
||||
selector: 'ui-searchbox',
|
||||
templateUrl: 'searchbox.component.html',
|
||||
styleUrls: ['searchbox.component.scss'],
|
||||
selector: "ui-searchbox",
|
||||
templateUrl: "searchbox.component.html",
|
||||
styleUrls: ["searchbox.component.scss"],
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
@@ -49,9 +49,9 @@ export class UiSearchboxNextComponent
|
||||
private readonly _cancelSearch = injectCancelSearch({ optional: true });
|
||||
|
||||
disabled: boolean;
|
||||
type = 'text';
|
||||
type = "text";
|
||||
|
||||
@ViewChild('input', { read: ElementRef, static: true })
|
||||
@ViewChild("input", { read: ElementRef, static: true })
|
||||
input: ElementRef;
|
||||
|
||||
@ContentChild(UiAutocompleteComponent)
|
||||
@@ -61,9 +61,9 @@ export class UiSearchboxNextComponent
|
||||
focusAfterViewInit: boolean = true;
|
||||
|
||||
@Input()
|
||||
placeholder: string = '';
|
||||
placeholder: string = "";
|
||||
|
||||
private _query = '';
|
||||
private _query = "";
|
||||
|
||||
@Input()
|
||||
get query() {
|
||||
@@ -94,7 +94,7 @@ export class UiSearchboxNextComponent
|
||||
scanner = false;
|
||||
|
||||
@Input()
|
||||
hint: string = '';
|
||||
hint: string = "";
|
||||
|
||||
@Output()
|
||||
hintCleared = new EventEmitter<void>();
|
||||
@@ -107,11 +107,11 @@ export class UiSearchboxNextComponent
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this.setQuery('');
|
||||
this.setQuery("");
|
||||
this._cancelSearch();
|
||||
}
|
||||
|
||||
@HostBinding('class.autocomplete-opend')
|
||||
@HostBinding("class.autocomplete-opend")
|
||||
get autocompleteOpen() {
|
||||
return this.autocomplete?.opend;
|
||||
}
|
||||
@@ -212,14 +212,14 @@ export class UiSearchboxNextComponent
|
||||
}
|
||||
|
||||
clearHint() {
|
||||
this.hint = '';
|
||||
this.hint = "";
|
||||
this.focused.emit(true);
|
||||
this.hintCleared.emit();
|
||||
this.cdr.markForCheck();
|
||||
}
|
||||
|
||||
onKeyup(event: KeyboardEvent) {
|
||||
if (event.key === 'Enter') {
|
||||
if (event.key === "Enter") {
|
||||
if (this.autocomplete?.opend && this.autocomplete?.activeItem) {
|
||||
this.setQuery(this.autocomplete?.activeItem?.item);
|
||||
this.autocomplete?.close();
|
||||
@@ -227,7 +227,7 @@ export class UiSearchboxNextComponent
|
||||
this.search.emit(this.query);
|
||||
|
||||
event.preventDefault();
|
||||
} else if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {
|
||||
} else if (event.key === "ArrowUp" || event.key === "ArrowDown") {
|
||||
this.handleArrowUpDownEvent(event);
|
||||
}
|
||||
}
|
||||
@@ -235,12 +235,14 @@ export class UiSearchboxNextComponent
|
||||
handleArrowUpDownEvent(event: KeyboardEvent) {
|
||||
this.autocomplete?.handleKeyboardEvent(event);
|
||||
if (this.autocomplete?.activeItem) {
|
||||
const query = this.autocompleteValueSelector(this.autocomplete.activeItem.item);
|
||||
const query = this.autocompleteValueSelector(
|
||||
this.autocomplete.activeItem.item,
|
||||
);
|
||||
this.setQuery(query, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
@HostListener('window:click', ['$event'])
|
||||
@HostListener("window:click", ["$event"])
|
||||
focusLost(event: MouseEvent) {
|
||||
if (
|
||||
this.autocomplete?.opend &&
|
||||
@@ -254,9 +256,11 @@ export class UiSearchboxNextComponent
|
||||
this.search.emit(this.query);
|
||||
}
|
||||
|
||||
@HostListener('focusout', ['$event'])
|
||||
@HostListener("focusout", ["$event"])
|
||||
onBlur() {
|
||||
this.onTouched();
|
||||
if (typeof this.onTouched === "function") {
|
||||
this.onTouched();
|
||||
}
|
||||
this.focused.emit(false);
|
||||
this.cdr.markForCheck();
|
||||
}
|
||||
|
||||
@@ -1,27 +1,42 @@
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import { StorageProvider } from './storage-provider';
|
||||
import { UserStateService } from '@generated/swagger/isa-api';
|
||||
import { firstValueFrom, map, shareReplay } from 'rxjs';
|
||||
import { inject, Injectable } from "@angular/core";
|
||||
import { StorageProvider } from "./storage-provider";
|
||||
import { UserStateService } from "@generated/swagger/isa-api";
|
||||
import { catchError, firstValueFrom, map, of } from "rxjs";
|
||||
import { isEmpty } from "lodash";
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
@Injectable({ providedIn: "root" })
|
||||
export class UserStorageProvider implements StorageProvider {
|
||||
#userStateService = inject(UserStateService);
|
||||
|
||||
private state$ = this.#userStateService.UserStateGetUserState().pipe(
|
||||
map((res) => {
|
||||
if (res.result?.content) {
|
||||
if (res?.result?.content) {
|
||||
return JSON.parse(res.result.content);
|
||||
}
|
||||
return {};
|
||||
}),
|
||||
shareReplay(1),
|
||||
catchError((err) => {
|
||||
console.warn(
|
||||
"No UserStateGetUserState found, returning empty object:",
|
||||
err,
|
||||
);
|
||||
return of({}); // Return empty state fallback
|
||||
}),
|
||||
// shareReplay(1), #5249, #5270 Würde beim Fehlerfall den fehlerhaften Zustand behalten
|
||||
// Aktuell wird nun jedes mal 2 mal der UserState aufgerufen (GET + POST)
|
||||
// Damit bei der set Funktion immer der aktuelle Zustand verwendet wird
|
||||
);
|
||||
|
||||
async set(key: string, value: unknown): Promise<void> {
|
||||
async set(key: string, value: Record<string, unknown>): Promise<void> {
|
||||
const current = await firstValueFrom(this.state$);
|
||||
firstValueFrom(
|
||||
const content =
|
||||
current && !isEmpty(current)
|
||||
? { ...current, [key]: value }
|
||||
: { [key]: value };
|
||||
|
||||
await firstValueFrom(
|
||||
this.#userStateService.UserStateSetUserState({
|
||||
content: JSON.stringify({ ...current, [key]: value }),
|
||||
content: JSON.stringify(content),
|
||||
}),
|
||||
);
|
||||
}
|
||||
@@ -32,7 +47,6 @@ export class UserStorageProvider implements StorageProvider {
|
||||
}
|
||||
|
||||
async clear(key: string): Promise<void> {
|
||||
|
||||
const current = await firstValueFrom(this.state$);
|
||||
delete current[key];
|
||||
firstValueFrom(this.#userStateService.UserStateResetUserState());
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
name="isaActionEdit"
|
||||
data-what="button"
|
||||
data-which="edit-return-item"
|
||||
(click)="navigateBack()"
|
||||
[disabled]="returnItemsAndPrintReciptPending()"
|
||||
(click)="location.back()"
|
||||
></ui-icon-button>
|
||||
</div>
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { createRoutingFactory, Spectator } from '@ngneat/spectator/jest';
|
||||
import { ReturnSummaryItemComponent } from './return-summary-item.component';
|
||||
import { MockComponents, MockProvider } from 'ng-mocks';
|
||||
import { ReturnProductInfoComponent } from '@isa/oms/shared/product-info';
|
||||
import { createRoutingFactory, Spectator } from "@ngneat/spectator/jest";
|
||||
import { ReturnSummaryItemComponent } from "./return-summary-item.component";
|
||||
import { MockComponents, MockProvider } from "ng-mocks";
|
||||
import { ReturnProductInfoComponent } from "@isa/oms/shared/product-info";
|
||||
import {
|
||||
Product,
|
||||
ReturnProcess,
|
||||
ReturnProcessQuestionKey,
|
||||
ReturnProcessService,
|
||||
} from '@isa/oms/data-access';
|
||||
import { NgIcon } from '@ng-icons/core';
|
||||
import { IconButtonComponent } from '@isa/ui/buttons';
|
||||
import { Router } from '@angular/router';
|
||||
} from "@isa/oms/data-access";
|
||||
import { NgIcon } from "@ng-icons/core";
|
||||
import { IconButtonComponent } from "@isa/ui/buttons";
|
||||
import { Location } from "@angular/common";
|
||||
|
||||
/**
|
||||
* Creates a mock ReturnProcess with default values that can be overridden
|
||||
@@ -21,20 +21,20 @@ function createMockReturnProcess(
|
||||
return {
|
||||
id: 1,
|
||||
processId: 1,
|
||||
productCategory: 'Electronics',
|
||||
productCategory: "Electronics",
|
||||
answers: {},
|
||||
receiptId: 123,
|
||||
receiptItem: {
|
||||
id: 321,
|
||||
product: {
|
||||
name: 'Test Product',
|
||||
name: "Test Product",
|
||||
},
|
||||
},
|
||||
...partial,
|
||||
} as ReturnProcess;
|
||||
}
|
||||
|
||||
describe('ReturnSummaryItemComponent', () => {
|
||||
describe("ReturnSummaryItemComponent", () => {
|
||||
let spectator: Spectator<ReturnSummaryItemComponent>;
|
||||
let returnProcessService: jest.Mocked<ReturnProcessService>;
|
||||
|
||||
@@ -48,7 +48,10 @@ describe('ReturnSummaryItemComponent', () => {
|
||||
providers: [
|
||||
MockProvider(ReturnProcessService, {
|
||||
getReturnInfo: jest.fn(),
|
||||
eligibleForReturn: jest.fn().mockReturnValue({ state: 'eligible' }),
|
||||
eligibleForReturn: jest.fn().mockReturnValue({ state: "eligible" }),
|
||||
}),
|
||||
MockProvider(Location, {
|
||||
back: jest.fn(),
|
||||
}),
|
||||
],
|
||||
shallow: true,
|
||||
@@ -64,38 +67,38 @@ describe('ReturnSummaryItemComponent', () => {
|
||||
spectator.detectChanges();
|
||||
});
|
||||
|
||||
describe('Component Creation', () => {
|
||||
it('should create the component', () => {
|
||||
describe("Component Creation", () => {
|
||||
it("should create the component", () => {
|
||||
expect(spectator.component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Return Information Display', () => {
|
||||
describe("Return Information Display", () => {
|
||||
const mockReturnInfo = {
|
||||
itemCondition: 'itemCondition',
|
||||
returnDetails: { [ReturnProcessQuestionKey.CaseDamaged]: 'no' },
|
||||
returnReason: 'returnReason',
|
||||
itemCondition: "itemCondition",
|
||||
returnDetails: { [ReturnProcessQuestionKey.CaseDamaged]: "no" },
|
||||
returnReason: "returnReason",
|
||||
otherProduct: {
|
||||
ean: 'ean',
|
||||
ean: "ean",
|
||||
} as Product,
|
||||
comment: 'comment',
|
||||
comment: "comment",
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
jest
|
||||
.spyOn(returnProcessService, 'getReturnInfo')
|
||||
.spyOn(returnProcessService, "getReturnInfo")
|
||||
.mockReturnValue(mockReturnInfo);
|
||||
spectator.setInput('returnProcess', createMockReturnProcess({ id: 2 }));
|
||||
spectator.setInput("returnProcess", createMockReturnProcess({ id: 2 }));
|
||||
spectator.detectChanges();
|
||||
});
|
||||
it('should provide correct return information array', () => {
|
||||
it("should provide correct return information array", () => {
|
||||
// Arrange
|
||||
const expectedInfos = [
|
||||
'itemCondition',
|
||||
'returnReason',
|
||||
'Gehäuse beschädigt: no',
|
||||
'Geliefert wurde: ean',
|
||||
'comment',
|
||||
"itemCondition",
|
||||
"returnReason",
|
||||
"Gehäuse beschädigt: no",
|
||||
"Geliefert wurde: ean",
|
||||
"comment",
|
||||
];
|
||||
|
||||
// Act
|
||||
@@ -105,14 +108,14 @@ describe('ReturnSummaryItemComponent', () => {
|
||||
expect(actualInfos).toEqual(expectedInfos);
|
||||
expect(actualInfos.length).toBe(5);
|
||||
});
|
||||
it('should render return info items with correct content', () => {
|
||||
it("should render return info items with correct content", () => {
|
||||
// Arrange
|
||||
const expectedInfos = [
|
||||
'itemCondition',
|
||||
'returnReason',
|
||||
'Gehäuse beschädigt: no',
|
||||
'Geliefert wurde: ean',
|
||||
'comment',
|
||||
"itemCondition",
|
||||
"returnReason",
|
||||
"Gehäuse beschädigt: no",
|
||||
"Geliefert wurde: ean",
|
||||
"comment",
|
||||
];
|
||||
|
||||
// Act
|
||||
@@ -125,14 +128,14 @@ describe('ReturnSummaryItemComponent', () => {
|
||||
expect(listItems.length).toBe(expectedInfos.length);
|
||||
listItems.forEach((item, index) => {
|
||||
expect(item).toHaveText(expectedInfos[index]);
|
||||
expect(item).toHaveAttribute('data-info-index', index.toString());
|
||||
expect(item).toHaveAttribute("data-info-index", index.toString());
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle undefined return info gracefully', () => {
|
||||
it("should handle undefined return info gracefully", () => {
|
||||
// Arrange
|
||||
returnProcessService.getReturnInfo.mockReturnValue(undefined);
|
||||
spectator.setInput('returnProcess', createMockReturnProcess({ id: 3 }));
|
||||
spectator.setInput("returnProcess", createMockReturnProcess({ id: 3 }));
|
||||
spectator.detectChanges();
|
||||
|
||||
// Act
|
||||
@@ -146,26 +149,26 @@ describe('ReturnSummaryItemComponent', () => {
|
||||
expect(listItems.length).toBe(0);
|
||||
});
|
||||
|
||||
describe('returnDetails mapping', () => {
|
||||
it('should map multiple returnDetails keys to correct info strings', () => {
|
||||
describe("returnDetails mapping", () => {
|
||||
it("should map multiple returnDetails keys to correct info strings", () => {
|
||||
const expected = [
|
||||
'itemCondition',
|
||||
'returnReason',
|
||||
'Gehäuse beschädigt: Ja',
|
||||
'Display beschädigt: Nein',
|
||||
'Geliefert wurde: ean',
|
||||
'comment',
|
||||
"itemCondition",
|
||||
"returnReason",
|
||||
"Gehäuse beschädigt: Ja",
|
||||
"Display beschädigt: Nein",
|
||||
"Geliefert wurde: ean",
|
||||
"comment",
|
||||
];
|
||||
// Arrange
|
||||
const details = {
|
||||
[ReturnProcessQuestionKey.CaseDamaged]: 'Ja',
|
||||
[ReturnProcessQuestionKey.DisplayDamaged]: 'Nein',
|
||||
[ReturnProcessQuestionKey.CaseDamaged]: "Ja",
|
||||
[ReturnProcessQuestionKey.DisplayDamaged]: "Nein",
|
||||
};
|
||||
returnProcessService.getReturnInfo.mockReturnValue({
|
||||
...mockReturnInfo,
|
||||
returnDetails: details,
|
||||
});
|
||||
spectator.setInput('returnProcess', createMockReturnProcess({ id: 4 }));
|
||||
spectator.setInput("returnProcess", createMockReturnProcess({ id: 4 }));
|
||||
spectator.detectChanges();
|
||||
|
||||
// Act
|
||||
@@ -173,31 +176,31 @@ describe('ReturnSummaryItemComponent', () => {
|
||||
expect(infos).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should not include returnDetails if empty', () => {
|
||||
it("should not include returnDetails if empty", () => {
|
||||
// Arrange
|
||||
returnProcessService.getReturnInfo.mockReturnValue({
|
||||
...mockReturnInfo,
|
||||
returnDetails: {},
|
||||
});
|
||||
spectator.setInput('returnProcess', createMockReturnProcess({ id: 5 }));
|
||||
spectator.setInput("returnProcess", createMockReturnProcess({ id: 5 }));
|
||||
spectator.detectChanges();
|
||||
|
||||
// Act
|
||||
const infos = spectator.component.returnInfos();
|
||||
|
||||
// Assert
|
||||
expect(infos.some((info) => info.includes('Gehäuse beschädigt'))).toBe(
|
||||
expect(infos.some((info) => info.includes("Gehäuse beschädigt"))).toBe(
|
||||
false,
|
||||
);
|
||||
expect(infos.some((info) => info.includes('Zubehör fehlt'))).toBe(
|
||||
expect(infos.some((info) => info.includes("Zubehör fehlt"))).toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Navigation', () => {
|
||||
it('should render edit button with correct attributes', () => {
|
||||
describe("Navigation", () => {
|
||||
it("should render edit button with correct attributes", () => {
|
||||
// Assert
|
||||
const editButton = spectator.query(
|
||||
'[data-what="button"][data-which="edit-return-item"]',
|
||||
@@ -205,7 +208,7 @@ describe('ReturnSummaryItemComponent', () => {
|
||||
expect(editButton).toExist();
|
||||
});
|
||||
|
||||
it('should navigate back when edit button is clicked', () => {
|
||||
it("should navigate back when edit button is clicked", () => {
|
||||
// Arrange
|
||||
const editButton = spectator.query(
|
||||
'[data-what="button"][data-which="edit-return-item"]',
|
||||
@@ -217,25 +220,20 @@ describe('ReturnSummaryItemComponent', () => {
|
||||
}
|
||||
|
||||
// Assert
|
||||
expect(spectator.inject(Router).navigate).toHaveBeenCalledWith(
|
||||
['..'],
|
||||
expect.objectContaining({
|
||||
relativeTo: expect.anything(),
|
||||
}),
|
||||
);
|
||||
expect(spectator.inject(Location).back).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('should render the product info component', () => {
|
||||
it("should render the product info component", () => {
|
||||
const productInfo = spectator.query(ReturnProductInfoComponent);
|
||||
expect(productInfo).toExist();
|
||||
});
|
||||
|
||||
it('should compute eligibility state as eligible', () => {
|
||||
it("should compute eligibility state as eligible", () => {
|
||||
(returnProcessService.eligibleForReturn as jest.Mock).mockReturnValue({
|
||||
state: 'eligible',
|
||||
state: "eligible",
|
||||
});
|
||||
spectator.detectChanges();
|
||||
expect(spectator.component.eligibleForReturn()?.state).toBe('eligible');
|
||||
expect(spectator.component.eligibleForReturn()?.state).toBe("eligible");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,13 +4,13 @@ import {
|
||||
computed,
|
||||
inject,
|
||||
input,
|
||||
} from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
} from "@angular/core";
|
||||
import { Location } from "@angular/common";
|
||||
import {
|
||||
isaActionChevronRight,
|
||||
isaActionClose,
|
||||
isaActionEdit,
|
||||
} from '@isa/icons';
|
||||
} from "@isa/icons";
|
||||
import {
|
||||
EligibleForReturn,
|
||||
EligibleForReturnState,
|
||||
@@ -18,10 +18,10 @@ import {
|
||||
ReturnProcessService,
|
||||
ProductCategory,
|
||||
returnDetailsMapping,
|
||||
} from '@isa/oms/data-access';
|
||||
import { ReturnProductInfoComponent } from '@isa/oms/shared/product-info';
|
||||
import { IconButtonComponent } from '@isa/ui/buttons';
|
||||
import { NgIcon, provideIcons } from '@ng-icons/core';
|
||||
} from "@isa/oms/data-access";
|
||||
import { ReturnProductInfoComponent } from "@isa/oms/shared/product-info";
|
||||
import { IconButtonComponent } from "@isa/ui/buttons";
|
||||
import { NgIcon, provideIcons } from "@ng-icons/core";
|
||||
|
||||
/**
|
||||
* Displays a single item in the return process summary, showing product details
|
||||
@@ -47,30 +47,34 @@ import { NgIcon, provideIcons } from '@ng-icons/core';
|
||||
* ```
|
||||
*/
|
||||
@Component({
|
||||
selector: 'oms-feature-return-summary-item',
|
||||
templateUrl: './return-summary-item.component.html',
|
||||
styleUrls: ['./return-summary-item.component.scss'],
|
||||
selector: "oms-feature-return-summary-item",
|
||||
templateUrl: "./return-summary-item.component.html",
|
||||
styleUrls: ["./return-summary-item.component.scss"],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [ReturnProductInfoComponent, NgIcon, IconButtonComponent],
|
||||
providers: [
|
||||
provideIcons({ isaActionChevronRight, isaActionEdit, isaActionClose }),
|
||||
],
|
||||
host: {
|
||||
'data-what': 'list-item',
|
||||
'data-which': 'return-process-item',
|
||||
'[attr.data-receipt-id]': 'returnProcess()?.receiptId',
|
||||
'[attr.data-return-item-id]': 'returnProcess()?.returnItem?.id',
|
||||
"data-what": "list-item",
|
||||
"data-which": "return-process-item",
|
||||
"[attr.data-receipt-id]": "returnProcess()?.receiptId",
|
||||
"[attr.data-return-item-id]": "returnProcess()?.returnItem?.id",
|
||||
},
|
||||
})
|
||||
export class ReturnSummaryItemComponent {
|
||||
EligibleForReturnState = EligibleForReturnState;
|
||||
#returnProcessService = inject(ReturnProcessService);
|
||||
#router = inject(Router);
|
||||
#activatedRoute = inject(ActivatedRoute);
|
||||
|
||||
/** Angular Location service for navigation */
|
||||
location = inject(Location);
|
||||
|
||||
/** The return process object containing all information about the return */
|
||||
returnProcess = input.required<ReturnProcess>();
|
||||
|
||||
/** The status of the return items and print receipt operation */
|
||||
returnItemsAndPrintReciptPending = input<boolean>(false);
|
||||
|
||||
/**
|
||||
* Computes whether the current return process is eligible for return.
|
||||
*
|
||||
@@ -149,8 +153,4 @@ export class ReturnSummaryItemComponent {
|
||||
// remove duplicates
|
||||
return Array.from(new Set(result));
|
||||
});
|
||||
|
||||
navigateBack() {
|
||||
this.#router.navigate(['..'], { relativeTo: this.#activatedRoute });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
color="tertiary"
|
||||
size="small"
|
||||
class="px-[0.875rem] py-1 min-w-0 bg-white gap-1 absolute top-0 left-0"
|
||||
[disabled]="returnItemsAndPrintReciptStatusPending()"
|
||||
(click)="location.back()"
|
||||
>
|
||||
<ng-icon name="isaActionChevronLeft" size="1.5rem" class="-ml-2"></ng-icon>
|
||||
@@ -28,19 +29,22 @@
|
||||
data-which="return-process-item"
|
||||
[attr.data-item-id]="item.id"
|
||||
[attr.data-item-category]="item.productCategory"
|
||||
[returnItemsAndPrintReciptPending]="
|
||||
returnItemsAndPrintReciptStatusPending()
|
||||
"
|
||||
></oms-feature-return-summary-item>
|
||||
}
|
||||
</div>
|
||||
<div class="mt-6 text-center">
|
||||
@if (returnItemsAndPrintReciptStatus() !== 'success') {
|
||||
@if (returnItemsAndPrintReciptStatus() !== "success") {
|
||||
<button
|
||||
type="button"
|
||||
size="large"
|
||||
uiButton
|
||||
color="brand"
|
||||
(click)="returnItemsAndPrintRecipt()"
|
||||
[pending]="returnItemsAndPrintReciptStatus() === 'pending'"
|
||||
[disabled]="returnItemsAndPrintReciptStatus() === 'pending'"
|
||||
[pending]="returnItemsAndPrintReciptStatusPending()"
|
||||
[disabled]="returnItemsAndPrintReciptStatusPending()"
|
||||
data-what="button"
|
||||
data-which="return-and-print"
|
||||
>
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
import { createComponentFactory, Spectator } from '@ngneat/spectator/jest';
|
||||
import { MockComponent } from 'ng-mocks';
|
||||
import { ReturnSummaryComponent } from './return-summary.component';
|
||||
import { createComponentFactory, Spectator } from "@ngneat/spectator/jest";
|
||||
import { MockComponent } from "ng-mocks";
|
||||
import { ReturnSummaryComponent } from "./return-summary.component";
|
||||
import {
|
||||
ReturnProcess,
|
||||
ReturnProcessService,
|
||||
ReturnProcessStore,
|
||||
} from '@isa/oms/data-access';
|
||||
import { ReturnSummaryItemComponent } from './return-summary-item/return-summary-item.component';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
} from "@isa/oms/data-access";
|
||||
import { ReturnSummaryItemComponent } from "./return-summary-item/return-summary-item.component";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
|
||||
jest.mock('@isa/core/process', () => ({
|
||||
jest.mock("@isa/core/process", () => ({
|
||||
injectActivatedProcessId: () => jest.fn(() => 1),
|
||||
}));
|
||||
|
||||
const MOCK_RETURN_PROCESSES: ReturnProcess[] = [
|
||||
{ id: 1, processId: 1, productCategory: 'Electronics' } as ReturnProcess,
|
||||
{ id: 2, processId: 1, productCategory: 'Books' } as ReturnProcess,
|
||||
{ id: 3, processId: 2, productCategory: 'Clothing' } as ReturnProcess,
|
||||
{ id: 4, processId: 2, productCategory: 'Home Goods' } as ReturnProcess,
|
||||
{ id: 5, processId: 3, productCategory: 'Electronics' } as ReturnProcess,
|
||||
{ id: 6, processId: 3, productCategory: 'Toys' } as ReturnProcess,
|
||||
{ id: 7, processId: 4, productCategory: 'Books' } as ReturnProcess,
|
||||
{ id: 8, processId: 4, productCategory: 'Garden' } as ReturnProcess,
|
||||
{ id: 1, processId: 1, productCategory: "Electronics" } as ReturnProcess,
|
||||
{ id: 2, processId: 1, productCategory: "Books" } as ReturnProcess,
|
||||
{ id: 3, processId: 2, productCategory: "Clothing" } as ReturnProcess,
|
||||
{ id: 4, processId: 2, productCategory: "Home Goods" } as ReturnProcess,
|
||||
{ id: 5, processId: 3, productCategory: "Electronics" } as ReturnProcess,
|
||||
{ id: 6, processId: 3, productCategory: "Toys" } as ReturnProcess,
|
||||
{ id: 7, processId: 4, productCategory: "Books" } as ReturnProcess,
|
||||
{ id: 8, processId: 4, productCategory: "Garden" } as ReturnProcess,
|
||||
];
|
||||
|
||||
describe('ReturnSummaryComponent', () => {
|
||||
describe("ReturnSummaryComponent", () => {
|
||||
let spectator: Spectator<ReturnSummaryComponent>;
|
||||
// Use createComponentFactory for standalone components
|
||||
const createComponent = createComponentFactory({
|
||||
@@ -47,17 +47,17 @@ describe('ReturnSummaryComponent', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should create the component', () => {
|
||||
it("should create the component", () => {
|
||||
// Assert: Check if the component instance was created successfully
|
||||
expect(spectator.component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should have a defined processId', () => {
|
||||
it("should have a defined processId", () => {
|
||||
// Assert: Check if the processId is defined
|
||||
expect(spectator.component.processId()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should have two return processes', () => {
|
||||
it("should have two return processes", () => {
|
||||
// Arrange:
|
||||
const mockReturnProcesses: ReturnProcess[] = [
|
||||
MOCK_RETURN_PROCESSES[0],
|
||||
@@ -72,14 +72,14 @@ describe('ReturnSummaryComponent', () => {
|
||||
expect(returnProcesses).toEqual(mockReturnProcesses);
|
||||
});
|
||||
|
||||
it('should render the return summary item component', () => {
|
||||
it("should render the return summary item component", () => {
|
||||
// Arrange:
|
||||
const mockReturnProcesses: ReturnProcess[] = [
|
||||
MOCK_RETURN_PROCESSES[0],
|
||||
MOCK_RETURN_PROCESSES[1],
|
||||
];
|
||||
jest
|
||||
.spyOn(spectator.component, 'returnProcesses')
|
||||
.spyOn(spectator.component, "returnProcesses")
|
||||
.mockReturnValue(mockReturnProcesses);
|
||||
|
||||
// Act: Trigger change detection
|
||||
@@ -91,14 +91,14 @@ describe('ReturnSummaryComponent', () => {
|
||||
expect(returnSummaryItems.length).toBe(mockReturnProcesses.length);
|
||||
});
|
||||
|
||||
it('should set the returnProcess input correctly', () => {
|
||||
it("should set the returnProcess input correctly", () => {
|
||||
// Arrange:
|
||||
const mockReturnProcesses: ReturnProcess[] = [
|
||||
MOCK_RETURN_PROCESSES[0],
|
||||
MOCK_RETURN_PROCESSES[1],
|
||||
];
|
||||
jest
|
||||
.spyOn(spectator.component, 'returnProcesses')
|
||||
.spyOn(spectator.component, "returnProcesses")
|
||||
.mockReturnValue(mockReturnProcesses);
|
||||
|
||||
// Act: Trigger change detection
|
||||
@@ -110,7 +110,7 @@ describe('ReturnSummaryComponent', () => {
|
||||
expect(returnSummaryItems[1].returnProcess).toEqual(mockReturnProcesses[1]);
|
||||
});
|
||||
|
||||
it('should have proper E2E testing attributes', () => {
|
||||
it("should have proper E2E testing attributes", () => {
|
||||
// Arrange
|
||||
const mockReturnProcesses: ReturnProcess[] = [
|
||||
MOCK_RETURN_PROCESSES[0], // id: 1, processId: 1, category: 'Electronics'
|
||||
@@ -118,7 +118,7 @@ describe('ReturnSummaryComponent', () => {
|
||||
];
|
||||
|
||||
jest
|
||||
.spyOn(spectator.component, 'returnProcesses')
|
||||
.spyOn(spectator.component, "returnProcesses")
|
||||
.mockReturnValue(mockReturnProcesses);
|
||||
|
||||
// Act
|
||||
@@ -128,57 +128,57 @@ describe('ReturnSummaryComponent', () => {
|
||||
// Check heading attributes
|
||||
const heading = spectator.query('[data-what="heading"]');
|
||||
expect(heading).toBeTruthy();
|
||||
expect(heading).toHaveAttribute('data-which', 'return-summary-title');
|
||||
expect(heading).toHaveAttribute("data-which", "return-summary-title");
|
||||
|
||||
// Check container attributes
|
||||
const container = spectator.query('[data-what="container"]');
|
||||
expect(container).toBeTruthy();
|
||||
expect(container).toHaveAttribute('data-which', 'return-items-list');
|
||||
expect(container).toHaveAttribute("data-which", "return-items-list");
|
||||
|
||||
// Check list item attributes
|
||||
const listItems = spectator.queryAll('oms-feature-return-summary-item');
|
||||
const listItems = spectator.queryAll("oms-feature-return-summary-item");
|
||||
expect(listItems.length).toBe(mockReturnProcesses.length);
|
||||
|
||||
// Check attributes for the first item
|
||||
expect(listItems[0]).toHaveAttribute('data-what', 'list-item');
|
||||
expect(listItems[0]).toHaveAttribute('data-which', 'return-process-item');
|
||||
expect(listItems[0]).toHaveAttribute("data-what", "list-item");
|
||||
expect(listItems[0]).toHaveAttribute("data-which", "return-process-item");
|
||||
expect(listItems[0]).toHaveAttribute(
|
||||
'data-item-id',
|
||||
"data-item-id",
|
||||
`${mockReturnProcesses[0].id}`,
|
||||
);
|
||||
|
||||
expect(listItems[0]).toHaveAttribute(
|
||||
'data-item-category',
|
||||
"data-item-category",
|
||||
mockReturnProcesses[0].productCategory,
|
||||
);
|
||||
|
||||
// Check attributes for the second item
|
||||
expect(listItems[1]).toHaveAttribute('data-what', 'list-item');
|
||||
expect(listItems[1]).toHaveAttribute('data-which', 'return-process-item');
|
||||
expect(listItems[1]).toHaveAttribute("data-what", "list-item");
|
||||
expect(listItems[1]).toHaveAttribute("data-which", "return-process-item");
|
||||
expect(listItems[1]).toHaveAttribute(
|
||||
'data-item-id',
|
||||
"data-item-id",
|
||||
`${mockReturnProcesses[1].id}`,
|
||||
);
|
||||
expect(listItems[1]).toHaveAttribute(
|
||||
'data-item-category',
|
||||
"data-item-category",
|
||||
`${mockReturnProcesses[1].productCategory}`,
|
||||
);
|
||||
expect(listItems[1]).toHaveAttribute(
|
||||
'data-item-category',
|
||||
"data-item-category",
|
||||
mockReturnProcesses[1].productCategory,
|
||||
);
|
||||
|
||||
// Check button attributes
|
||||
const button = spectator.query('[data-what="button"]');
|
||||
expect(button).toBeTruthy();
|
||||
expect(button).toHaveAttribute('data-which', 'return-and-print');
|
||||
expect(button).toHaveAttribute("data-which", "return-and-print");
|
||||
});
|
||||
|
||||
it('should call returnItemsAndPrintRecipt when button is clicked', () => {
|
||||
it("should call returnItemsAndPrintRecipt when button is clicked", () => {
|
||||
// Arrange: Spy on the returnItemsAndPrintRecipt method
|
||||
const returnItemsAndPrintReciptSpy = jest.spyOn(
|
||||
spectator.component,
|
||||
'returnItemsAndPrintRecipt',
|
||||
"returnItemsAndPrintRecipt",
|
||||
);
|
||||
|
||||
// Act: Trigger button click
|
||||
|
||||
@@ -4,20 +4,20 @@ import {
|
||||
computed,
|
||||
inject,
|
||||
signal,
|
||||
} from '@angular/core';
|
||||
import { ReturnSummaryItemComponent } from './return-summary-item/return-summary-item.component';
|
||||
import { injectActivatedProcessId } from '@isa/core/process';
|
||||
} from "@angular/core";
|
||||
import { ReturnSummaryItemComponent } from "./return-summary-item/return-summary-item.component";
|
||||
import { injectActivatedProcessId } from "@isa/core/process";
|
||||
import {
|
||||
ReturnProcess,
|
||||
ReturnProcessService,
|
||||
ReturnProcessStore,
|
||||
} from '@isa/oms/data-access';
|
||||
import { ButtonComponent } from '@isa/ui/buttons';
|
||||
import { NgIcon, provideIcons } from '@ng-icons/core';
|
||||
import { Location } from '@angular/common';
|
||||
import { isaActionChevronLeft } from '@isa/icons';
|
||||
import { logger } from '@isa/core/logging';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
} from "@isa/oms/data-access";
|
||||
import { ButtonComponent } from "@isa/ui/buttons";
|
||||
import { NgIcon, provideIcons } from "@ng-icons/core";
|
||||
import { Location } from "@angular/common";
|
||||
import { isaActionChevronLeft } from "@isa/icons";
|
||||
import { logger } from "@isa/core/logging";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
|
||||
/**
|
||||
* Main component for the return summary feature. Displays a list of items being returned
|
||||
@@ -35,9 +35,9 @@ import { ActivatedRoute, Router } from '@angular/router';
|
||||
* ```
|
||||
*/
|
||||
@Component({
|
||||
selector: 'oms-feature-return-summary',
|
||||
templateUrl: './return-summary.component.html',
|
||||
styleUrls: ['./return-summary.component.scss'],
|
||||
selector: "oms-feature-return-summary",
|
||||
templateUrl: "./return-summary.component.html",
|
||||
styleUrls: ["./return-summary.component.scss"],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [ReturnSummaryItemComponent, ButtonComponent, NgIcon],
|
||||
providers: [provideIcons({ isaActionChevronLeft })],
|
||||
@@ -74,9 +74,21 @@ export class ReturnSummaryComponent {
|
||||
* - 'error': Operation failed
|
||||
*/
|
||||
returnItemsAndPrintReciptStatus = signal<
|
||||
undefined | 'pending' | 'success' | 'error'
|
||||
undefined | "pending" | "success" | "error"
|
||||
>(undefined);
|
||||
|
||||
/**
|
||||
* Computed signal to determine if the return items and print receipt operation is pending.
|
||||
*
|
||||
* This signal checks the current status of the returnItemsAndPrintReciptStatus signal
|
||||
* and returns true if the status is 'pending', otherwise false.
|
||||
*
|
||||
* @returns {boolean} True if the operation is pending, false otherwise
|
||||
*/
|
||||
returnItemsAndPrintReciptStatusPending = computed(() => {
|
||||
return this.returnItemsAndPrintReciptStatus() === "pending";
|
||||
});
|
||||
|
||||
/**
|
||||
* Handles the return and print process for multiple items.
|
||||
*
|
||||
@@ -93,35 +105,35 @@ export class ReturnSummaryComponent {
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async returnItemsAndPrintRecipt() {
|
||||
if (this.returnItemsAndPrintReciptStatus() === 'pending') {
|
||||
this.#logger.warn('Return process already in progress', () => ({
|
||||
function: 'returnItemsAndPrintRecipt',
|
||||
if (this.returnItemsAndPrintReciptStatus() === "pending") {
|
||||
this.#logger.warn("Return process already in progress", () => ({
|
||||
function: "returnItemsAndPrintRecipt",
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.returnItemsAndPrintReciptStatus.set('pending');
|
||||
this.returnItemsAndPrintReciptStatus.set("pending");
|
||||
|
||||
const returnReceipts =
|
||||
await this.#returnProcessService.completeReturnProcess(
|
||||
this.returnProcesses(),
|
||||
);
|
||||
|
||||
this.#logger.info('Return receipts created', () => ({
|
||||
this.#logger.info("Return receipts created", () => ({
|
||||
count: returnReceipts.length,
|
||||
}));
|
||||
this.returnItemsAndPrintReciptStatus.set('success');
|
||||
this.returnItemsAndPrintReciptStatus.set("success");
|
||||
|
||||
this.#returnProcessStore.finishProcess(returnReceipts);
|
||||
await this.#router.navigate(['../', 'review'], {
|
||||
await this.#router.navigate(["../", "review"], {
|
||||
relativeTo: this.#activatedRoute,
|
||||
});
|
||||
} catch (error) {
|
||||
this.#logger.error('Error completing return process', error, () => ({
|
||||
function: 'returnItemsAndPrintRecipt',
|
||||
this.#logger.error("Error completing return process", error, () => ({
|
||||
function: "returnItemsAndPrintRecipt",
|
||||
}));
|
||||
this.returnItemsAndPrintReciptStatus.set('error');
|
||||
this.returnItemsAndPrintReciptStatus.set("error");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user