Merge branch 'develop' into release/4.0

This commit is contained in:
Nino
2025-06-17 16:45:37 +02:00
10 changed files with 37 additions and 12 deletions

View File

@@ -182,8 +182,8 @@ export const ReturnProcessStore = signalStore(
store.storeState();
},
finishProcess: (returnReceipts: { [id: number]: Receipt }) => {
const entities = store.entities().map((entity) => {
const receipt = returnReceipts[entity.receiptId];
const entities = store.entities().map((entity, i) => {
const receipt = returnReceipts[i];
if (receipt) {
return { ...entity, returnReceipt: receipt };
}

View File

@@ -1,4 +1,4 @@
<div>
<div class="flex flex-row w-full">
@if (quantityDropdownValues().length > 1) {
<ui-dropdown
class="quantity-dropdown"

View File

@@ -1,5 +1,5 @@
:host {
@apply flex justify-center items-center gap-4;
@apply flex flex-col-reverse items-end desktop:flex-row desktop:justify-center desktop:items-center gap-4;
:has(.product-dropdown):has(.quantity-dropdown) {
.quantity-dropdown.ui-dropdown {

View File

@@ -8,12 +8,15 @@
<ui-text-field-container>
<ui-text-field size="small" class="min-w-[22.875rem]">
<input
#inputRef
uiInputControl
class="isa-text-body-2-bold placeholder:isa-text-body-2-bold"
placeholder="EAN eingeben / scannen"
type="text"
[formControl]="control"
(cleared)="resetProduct()"
(blur)="control.updateValueAndValidity()"
(keydown.enter)="check()"
/>
@if (!p) {
<button
@@ -32,17 +35,18 @@
</ui-text-field>
<ui-text-field-errors>
@if (!p && status().hasResult === false) {
@if (!p && status().hasResult === false && !control.invalid) {
<span>Kein Artikel gefunden</span>
}
@if (control.invalid && control.touched && !control.dirty) {
@if (control.invalid && control.touched) {
<span>Die eingegebene EAN ist ungültig</span>
}
</ui-text-field-errors>
</ui-text-field-container>
<shared-scanner-button
class="self-start"
[disabled]="!!control?.value"
(scan)="onScan($event)"
>

View File

@@ -2,9 +2,11 @@ import {
ChangeDetectionStrategy,
Component,
effect,
ElementRef,
inject,
input,
signal,
viewChild,
} from '@angular/core';
import {
AbstractControl,
@@ -19,7 +21,7 @@ import {
ReturnProcessProductQuestion,
ReturnProcessStore,
} from '@isa/oms/data-access';
import { IconButtonComponent, TextButtonComponent } from '@isa/ui/buttons';
import { TextButtonComponent } from '@isa/ui/buttons';
import {
InputControlDirective,
TextFieldClearComponent,
@@ -36,6 +38,7 @@ import { provideIcons } from '@ng-icons/core';
import { isaActionScanner } from '@isa/icons';
import { ScannerButtonComponent } from '@isa/shared/scanner';
import { ProductRouterLinkDirective } from '@isa/shared/product-router-link';
import { toSignal } from '@angular/core/rxjs-interop';
const eanValidator: ValidatorFn = (
control: AbstractControl,
@@ -61,7 +64,6 @@ const eanValidator: ValidatorFn = (
TextFieldComponent,
TextFieldClearComponent,
ProductImageDirective,
IconButtonComponent,
ScannerButtonComponent,
ProductRouterLinkDirective,
],
@@ -71,11 +73,14 @@ export class ReturnProcessProductQuestionComponent {
#returnProcessStore = inject(ReturnProcessStore);
#catalogueSearchService = inject(CatalougeSearchService);
inputElement = viewChild<ElementRef<HTMLInputElement>>('inputRef');
returnProcessId = input.required<number>();
question = input.required<ReturnProcessProductQuestion>();
control = new FormControl<string>('', [Validators.required, eanValidator]);
valueChanges = toSignal(this.control.valueChanges);
product = signal<Product | undefined>(undefined);
status = signal<{ fetching: boolean; hasResult?: boolean }>({
@@ -83,6 +88,14 @@ export class ReturnProcessProductQuestionComponent {
});
constructor() {
effect(() => {
const valueChanged = this.valueChanges();
if (valueChanged) {
this.control.setErrors(null);
this.status.set({ fetching: false, hasResult: undefined });
}
});
effect(() => {
const product = this.#returnProcessStore.entityMap()[
this.returnProcessId()
@@ -91,6 +104,8 @@ export class ReturnProcessProductQuestionComponent {
if (product) {
this.control.setValue(product.ean);
this.product.set(product);
} else {
this.inputElement()?.nativeElement?.focus();
}
});
}
@@ -101,6 +116,7 @@ export class ReturnProcessProductQuestionComponent {
this.returnProcessId(),
this.question().key,
);
this.inputElement()?.nativeElement?.focus();
}
onScan(value: string | null) {
@@ -114,6 +130,7 @@ export class ReturnProcessProductQuestionComponent {
pipe(
filter(() => this.control.valid),
tap(() => {
this.control.updateValueAndValidity();
this.status.set({ fetching: true, hasResult: undefined });
}),
switchMap(() =>

View File

@@ -22,8 +22,8 @@ export class ReturnReviewComponent {
if (processId) {
const receiptIds = this.#returnProcessStore
.entities()
.filter((p) => p.processId === processId && p.receiptId)
.map((p) => p.receiptId);
.filter((p) => p.processId === processId && p.returnReceipt?.id)
.map((p) => p.returnReceipt!.id);
await this.#printReceiptsService.printReturnReceipts({
returnReceiptIds: receiptIds,

View File

@@ -7,7 +7,7 @@
via Rechnungsnummer, E-Mail-Adresse oder Kundennamen
<ui-tooltip-icon
title="Wo finde ich den QR Code?"
content="In den Rechnungsmails con hugendubel.de ist die Rechnungsnummer als QR-Code integriert. Diesen können Sie sich auf einem Smartphone vorzeigen lassen und scannen."
content="In den Rechnungsmails von hugendubel.de ist die Rechnungsnummer als QR-Code integriert. Diesen können Sie sich auf einem Smartphone vorzeigen lassen und scannen."
></ui-tooltip-icon>
</p>
</div>

View File

@@ -113,6 +113,7 @@ export class ReturnSummaryComponent {
}));
this.returnItemsAndPrintReciptStatus.set('success');
this.#returnProcessStore.finishProcess(returnReceipts);
await this.#router.navigate(['../', 'review'], {
relativeTo: this.#activatedRoute,
});

View File

@@ -1,7 +1,9 @@
.ui-text-field-container {
@apply flex flex-col gap-1 items-start justify-center;
@apply flex flex-col items-start justify-center;
&:has(.ui-text-field-errors > *) {
@apply gap-1;
.ui-text-field {
@apply border-isa-accent-red;
}

View File

@@ -10,6 +10,7 @@ import { TooltipDirective } from './tooltip.directive';
providers: [provideIcons({ isaOtherInfo })],
host: {
'[class]': '["ui-tooltip-icon"]',
'[attr.title]': 'null',
},
hostDirectives: [
{