Compare commits

...

42 Commits

Author SHA1 Message Date
Lorenz Hilpert
d48680c59e Merge branch 'release/3.3' 2024-11-12 17:04:15 +01:00
Lorenz Hilpert
1d472ce3df (cherry picked from commit 4c027922283bc4113253310c9d47e7c8944427a3) 2024-10-07 19:04:31 +02:00
Nino Righi
1d19779dac Merged PR 1805: #4687 Hotfix Organisation Name Update Order
#4687 Hotfix Organisation Name Update Order
2024-10-07 14:33:04 +00:00
Nino
90e671d285 #4687 Changes to View, Added Organisation Input Field 2024-10-07 12:07:28 +02:00
Lorenz Hilpert
33fb44f20a Upgrade Version to 3.3 2024-09-24 16:51:36 +02:00
Lorenz Hilpert
8723f7aa7e Merge tag '3.2' into develop
Finish Release 3.2 3.2
2024-09-24 16:47:21 +02:00
Lorenz Hilpert
03815586f7 Merge branch 'release/3.2' 2024-09-24 16:47:03 +02:00
Nino Righi
86a11ff07a Merged PR 1791: #4715 Disable option for Staff to Add new Billing Adresses and only show the...
#4715 Disable option for Staff to Add new Billing Adresses and only show the very first attached to their accounts
2024-09-24 14:25:48 +00:00
Nino Righi
41be8533dc Merged PR 1790: #4776 Suchbegriff in der Artikelsuche soll bei Klick auf Filter bestehen blei...
#4776 Suchbegriff in der Artikelsuche soll bei Klick auf Filter bestehen bleiben (Trefferliste)
2024-09-24 13:42:17 +00:00
Nino Righi
186afbc828 Merged PR 1789: #4687 WA, Abholfach, HSC - First and Lastname Update on Buyer just on Order
#4687 WA, Abholfach, HSC - First and Lastname Update on Buyer just on Order
2024-09-24 13:39:57 +00:00
Nino Righi
c3561339a9 Merged PR 1788: #4794 Adjusted Route Error Handling
#4794 Adjusted Route Error Handling
2024-09-24 13:01:43 +00:00
Nino Righi
5312073184 Merged PR 1787: #4710 Initially Select All Possible Items Inside Purchase Options Modal
#4710 Initially Select All Possible Items Inside Purchase Options Modal
2024-09-24 12:45:49 +00:00
Lorenz Hilpert
4dfe3bfa11 Merge tag 'KameraOffline' into develop
Kamera kann nur geöffnet werden wenn man Online ist. KameraOffline
2024-09-24 14:39:19 +02:00
Lorenz Hilpert
9b7a1b1c21 Merge branch 'hotfix/skip-open-camera-when-offline' 2024-09-24 14:39:11 +02:00
Lorenz Hilpert
a290d3b249 Kamera öffnet sich nur wenn man Online ist 2024-09-24 14:37:48 +02:00
Lorenz Hilpert
ad348af551 Merge branch 'master' into release/3.2 2024-09-17 10:56:13 +02:00
Lorenz Hilpert
f1bdba5d10 Merge tag 'online-offline-verhalten' into develop
Merge Online Offline Verhalten online-offline-verhalten
2024-09-16 16:46:38 +02:00
Lorenz Hilpert
c4134e7f99 Merge branch 'hotfix/online-offline-network' 2024-09-16 16:46:28 +02:00
Lorenz Hilpert
b7a16f5d30 IPad 6 Fehlermeldung word wrap 2024-09-16 14:39:00 +02:00
Lorenz Hilpert
4105709286 Added Styles instead of classes for word wrapping 2024-09-16 14:23:11 +02:00
Lorenz Hilpert
0c3b322fbd Ipad 4 Error Anzeige 2024-09-16 13:31:00 +02:00
Lorenz Hilpert
12096754c7 Set Max Screen Width Error 2024-09-16 12:28:25 +02:00
Lorenz Hilpert
453d921a99 Nachricht angepasst 2024-09-16 11:54:52 +02:00
Lorenz Hilpert
bad05fd098 Offline und Online Banner
Initialisierung Wartet auf Netzwerk
2024-09-13 17:30:08 +02:00
Lorenz Hilpert
363daf1e35 console.log entfernt 2024-09-13 16:08:21 +02:00
Lorenz Hilpert
e0cb0974cf Initialisierung gibt ein Feedback an den Benutzer aus. Feedback wenn Benutzer offline ist. 2024-09-13 16:05:54 +02:00
Lorenz Hilpert
c3d9274766 Merge branch 'hotfix/pwa-camera-dialog-size' 2024-09-13 11:03:04 +02:00
Lorenz Hilpert
bc16b841fb Kamera Overlay Größe
(cherry picked from commit d5dc4e053d)
2024-09-13 11:02:30 +02:00
Lorenz Hilpert
d5dc4e053d Kamera Overlay Größe 2024-09-12 18:03:07 +02:00
Lorenz Hilpert
3c6833988c Change Variables in pipeline Minor from 1 to 2 2024-09-04 17:58:00 +02:00
Lorenz Hilpert
28fb4ebb48 Merge tag '3.1' into develop 2024-09-04 17:56:06 +02:00
Lorenz Hilpert
2118bd996a Merge branch 'release/3.1' 2024-09-04 17:52:55 +02:00
Lorenz Hilpert
8a6448cc17 Merge branch 'develop' into release/3.1 2024-08-19 15:01:59 +02:00
Lorenz Hilpert
f2c7d57ad6 Fix Remi Filter 2024-08-16 14:17:11 +02:00
Lorenz Hilpert
9c9ddfaeec #4774 Remi // Wannennummer nur einmal am Tag benutzbar 2024-08-14 15:45:39 +02:00
Lorenz Hilpert
6eaa347de5 Merge branch 'master' into develop 2024-08-13 11:04:36 +02:00
Lorenz Hilpert
a16f355396 Merge branch 'hotfix/scandit-lizenz-erneuern' 2024-08-13 11:02:16 +02:00
Lorenz Hilpert
8b8db6e335 Update Scandit Lizenz 2024-08-12 13:39:32 +02:00
Lorenz Hilpert
06e248d615 Kundensuche abbrechen 2024-06-27 15:47:41 +02:00
Nino Righi
920b8eb8e3 Merged PR 1778: #4004 Changed Minimum Birth Date for Kubi Case
#4004 Changed Minimum Birth Date for Kubi Case
2024-05-06 12:00:58 +00:00
Nino Righi
4db28b1aa7 Merged PR 1777: Merge Develop -> Release/3.1
Merge Develop -> Release/3.1
2024-05-03 13:00:46 +00:00
Lorenz Hilpert
ed7dc10246 Bump Version 2024-04-09 10:43:39 +02:00
93 changed files with 1043 additions and 753 deletions

View File

@@ -4,12 +4,11 @@
.scanner-container {
width: 100vw;
max-width: 95vw;
max-height: calc(95vh - 120px);
height: 100vh;
}
.close-scanner {
@apply block px-6 py-4 bg-white text-brand border-2 border-solid border-brand rounded-full text-lg font-bold mx-auto mt-4;
@apply absolute bottom-12 left-[50%] -translate-x-[50%] block px-6 py-4 bg-white text-brand border-2 border-solid border-brand rounded-full text-lg font-bold mx-auto mt-4;
}
@screen desktop {

View File

@@ -9,12 +9,20 @@ import { Config } from '@core/config';
import { ComponentPortal } from '@angular/cdk/portal';
import { ScanditOverlayComponent } from './scandit-overlay.component';
import { EnvironmentService } from '@core/environment';
import { injectNetworkStatus$ } from 'apps/isa-app/src/app/services/network-status.service';
import { toSignal } from '@angular/core/rxjs-interop';
@Injectable()
export class ScanditScanAdapter implements ScanAdapter {
readonly name = 'Scandit';
constructor(private readonly _config: Config, private _overlay: Overlay, private _environmentService: EnvironmentService) {}
private $networkStatus = toSignal(injectNetworkStatus$());
constructor(
private readonly _config: Config,
private _overlay: Overlay,
private _environmentService: EnvironmentService,
) {}
async init(): Promise<boolean> {
if (this._environmentService.isTablet()) {
@@ -30,6 +38,11 @@ export class ScanditScanAdapter implements ScanAdapter {
scan(): Observable<string> {
return new Observable((observer) => {
if (this.$networkStatus() === 'offline') {
observer.error(new Error('No network connection'));
return;
}
const overlay = this.createOverlay();
const portal = this.createPortal();
@@ -49,7 +62,7 @@ export class ScanditScanAdapter implements ScanAdapter {
sub.add(
overlay.backdropClick().subscribe(() => {
complete();
})
}),
);
ref.instance.onScan((code) => {

View File

@@ -17,7 +17,10 @@ export class AuthService {
private _authConfig: AuthConfig;
constructor(private _config: Config, private readonly _oAuthService: OAuthService) {
constructor(
private _config: Config,
private readonly _oAuthService: OAuthService,
) {
this._oAuthService.events?.subscribe((event) => {
if (event.type === 'token_received') {
console.log('SSO Token Expiration:', new Date(this._oAuthService.getAccessTokenExpiration()));
@@ -45,6 +48,8 @@ export class AuthService {
await this._oAuthService.loadDiscoveryDocumentAndTryLogin();
} catch (error) {
this.login();
throw error;
}
this._initialized.next(true);

View File

@@ -13,7 +13,10 @@ export class ThumbnailUrlPipe implements PipeTransform, OnDestroy {
private onDestroy$ = new Subject<void>();
constructor(private domainCatalogThumbnailService: DomainCatalogThumbnailService, private cdr: ChangeDetectorRef) {}
constructor(
private domainCatalogThumbnailService: DomainCatalogThumbnailService,
private cdr: ChangeDetectorRef,
) {}
ngOnDestroy(): void {
this.onDestroy$.next();
@@ -27,7 +30,7 @@ export class ThumbnailUrlPipe implements PipeTransform, OnDestroy {
this.input$
.pipe(
takeUntil(this.onDestroy$),
switchMap((input) => this.domainCatalogThumbnailService.getThumnaulUrl(input))
switchMap((input) => this.domainCatalogThumbnailService.getThumnaulUrl(input)),
)
.subscribe((result) => {
this.result = result;

View File

@@ -1,6 +1,7 @@
import { Injectable } from '@angular/core';
import {
BranchService,
BuyerDTO,
ChangeStockStatusCodeValues,
HistoryDTO,
NotificationChannel,
@@ -29,7 +30,7 @@ export class DomainOmsService {
private branchService: BranchService,
private vatService: VATService,
private stockStatusCodeService: StockStatusCodeService,
private _orderCheckoutService: OrderCheckoutService
private _orderCheckoutService: OrderCheckoutService,
) {}
getOrderItemsByCustomerNumber(customerNumber: string, skip: number): Observable<OrderListItemDTO[]> {
@@ -54,7 +55,7 @@ export class DomainOmsService {
return this.receiptService
.ReceiptGetReceiptsByOrderItemSubset({
payload: {
receiptType: (65 as unknown) as any,
receiptType: 65 as unknown as any,
ids: orderItemSubsetIds,
eagerLoading: 1,
},
@@ -76,7 +77,7 @@ export class DomainOmsService {
getStockStatusCodes({ supplierId, eagerLoading = 0 }: { supplierId: number; eagerLoading?: number }) {
return this.stockStatusCodeService.StockStatusCodeGetStockStatusCodes({ supplierId, eagerLoading }).pipe(
map((response) => response.result),
shareReplay()
shareReplay(),
);
}
@@ -120,7 +121,7 @@ export class DomainOmsService {
orderId: number,
orderItemId: number,
orderItemSubsetId: number,
data: StatusValues
data: StatusValues,
): Observable<ValueTupleOfOrderItemSubsetDTOAndOrderItemSubsetDTO> {
return this.orderService
.OrderChangeStatus({
@@ -184,7 +185,7 @@ export class DomainOmsService {
selected: order.notificationChannels,
email: order.buyer?.communicationDetails?.email,
mobile: order.buyer?.communicationDetails?.mobile,
}))
})),
);
}
@@ -205,12 +206,47 @@ export class DomainOmsService {
delete communicationDetails.mobile;
}
return this.updateOrder({ orderId, notificationChannels: changes.selected, communicationDetails });
}
updateOrder({
orderId,
notificationChannels,
communicationDetails,
firstName,
lastName,
organisation,
}: {
orderId: number;
notificationChannels?: NotificationChannel;
communicationDetails?: { email?: string; mobile?: string };
lastName?: string;
firstName?: string;
organisation?: string;
}) {
const buyer: BuyerDTO = {};
if (!!communicationDetails) {
buyer.communicationDetails = { ...communicationDetails };
}
if (!!lastName || !!firstName) {
buyer.lastName = lastName;
buyer.firstName = firstName;
}
if (!!organisation) {
buyer.organisation = {
name: organisation,
};
}
return this.orderService
.OrderPatchOrder({
orderId: orderId,
order: {
notificationChannels: changes.selected,
buyer: { communicationDetails },
notificationChannels,
buyer,
},
})
.pipe(map((res) => res.result));
@@ -242,11 +278,14 @@ export class DomainOmsService {
map((res) =>
res.result
.sort((a, b) => new Date(b.completed).getTime() - new Date(a.completed).getTime())
.reduce((data, result) => {
(data[result.name] = data[result.name] || []).push(new Date(result.completed));
return data;
}, {} as Record<string, Date[]>)
)
.reduce(
(data, result) => {
(data[result.name] = data[result.name] || []).push(new Date(result.completed));
return data;
},
{} as Record<string, Date[]>,
),
),
);
}
}

View File

@@ -1,4 +1,4 @@
import { inject, isDevMode, NgModule } from '@angular/core';
import { isDevMode, NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import {
CanActivateCartGuard,
@@ -8,8 +8,6 @@ import {
CanActivateCustomerOrdersWithProcessIdGuard,
CanActivateCustomerWithProcessIdGuard,
CanActivateGoodsInGuard,
CanActivateGoodsOutGuard,
CanActivateGoodsOutWithProcessIdGuard,
CanActivateProductGuard,
CanActivateProductWithProcessIdGuard,
CanActivateRemissionGuard,
@@ -22,7 +20,6 @@ import { MainComponent } from './main.component';
import { PreviewComponent } from './preview';
import { BranchSectionResolver, CustomerSectionResolver, ProcessIdResolver } from './resolvers';
import { TokenLoginComponent, TokenLoginModule } from './token-login';
import { ApplicationService } from '@core/application';
import { ProcessIdGuard } from './guards/process-id.guard';
import { ActivateProcessIdGuard, ActivateProcessIdWithConfigKeyGuard } from './guards/activate-process-id.guard';

View File

@@ -1 +1,28 @@
@if ($offlineBannerVisible()) {
<div [@fadeInOut] class="bg-brand text-white text-center fixed inset-x-0 top-0 z-tooltip p-4">
<h3 class="font-bold grid grid-flow-col items-center justify-center text-xl gap-4">
<div>
<ng-icon name="matWifiOff"></ng-icon>
</div>
<div>Sie sind offline, keine Verbindung zum Netzwerk.</div>
</h3>
<p>Bereits geladene Ihnalte werden angezeigt, Interaktionen sind aktuell nicht möglich.</p>
</div>
}
@if ($onlineBannerVisible()) {
<div [@fadeInOut] class="bg-green-500 text-white text-center fixed inset-x-0 top-0 z-tooltip p-4">
<h3 class="font-bold grid grid-flow-col items-center justify-center text-xl gap-4">
<div>
<ng-icon name="matWifi"></ng-icon>
</div>
<div>Sie sind wieder online.</div>
</h3>
<button class="fixed top-2 right-4 text-3xl w-12 h-12" type="button" (click)="$onlineBannerVisible.set(false)">
<ng-icon name="matClose"></ng-icon>
</button>
</div>
}
<router-outlet></router-outlet>

View File

@@ -1,5 +1,5 @@
import { DOCUMENT } from '@angular/common';
import { Component, HostListener, Inject, OnInit, Renderer2 } from '@angular/core';
import { Component, effect, HostListener, Inject, OnInit, Renderer2, signal, untracked } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { SwUpdate } from '@angular/service-worker';
import { ApplicationService } from '@core/application';
@@ -12,17 +12,60 @@ import { IsaLogProvider } from './providers';
import { EnvironmentService } from '@core/environment';
import { AuthService } from '@core/auth';
import { UiMessageModalComponent, UiModalService } from '@ui/modal';
import { injectOnline$ } from './services/network-status.service';
import { toSignal } from '@angular/core/rxjs-interop';
import { animate, style, transition, trigger } from '@angular/animations';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
animations: [
trigger('fadeInOut', [
transition(':enter', [
// :enter wird ausgelöst, wenn das Element zum DOM hinzugefügt wird
style({ opacity: 0, transform: 'translateY(-100%)' }),
animate('300ms', style({ opacity: 1, transform: 'translateY(0)' })),
]),
transition(':leave', [
// :leave wird ausgelöst, wenn das Element aus dem DOM entfernt wird
animate('300ms', style({ opacity: 0, transform: 'translateY(-100%)' })),
]),
]),
],
})
export class AppComponent implements OnInit {
$online = toSignal(injectOnline$());
$offlineBannerVisible = signal(false);
$onlineBannerVisible = signal(false);
private onlineBannerDismissTimeout: any;
onlineEffects = effect(() => {
const online = this.$online();
const offlineBannerVisible = this.$offlineBannerVisible();
untracked(() => {
this.$offlineBannerVisible.set(!online);
if (!online) {
this.$onlineBannerVisible.set(false);
clearTimeout(this.onlineBannerDismissTimeout);
}
if (offlineBannerVisible && online) {
this.$onlineBannerVisible.set(true);
this.onlineBannerDismissTimeout = setTimeout(() => this.$onlineBannerVisible.set(false), 5000);
}
});
});
private _checkForUpdates: number = this._config.get('checkForUpdates');
get checkForUpdates(): number {
return this._checkForUpdates;
return this._checkForUpdates ?? 60 * 60 * 1000; // default 1 hour
}
// For Unit Testing
@@ -43,7 +86,7 @@ export class AppComponent implements OnInit {
private infoService: UserStateService,
private readonly _environment: EnvironmentService,
private readonly _authService: AuthService,
private readonly _modal: UiModalService
private readonly _modal: UiModalService,
) {
this.updateClient();
IsaLogProvider.InfoService = this.infoService;

View File

@@ -37,6 +37,10 @@ import { NativeContainerService } from 'native-container';
import { ShellModule } from '@shared/shell';
import { MainComponent } from './main.component';
import { IconModule } from '@shared/components/icon';
import { NgIconsModule } from '@ng-icons/core';
import { matClose, matWifi, matWifiOff } from '@ng-icons/material-icons/baseline';
import { NetworkStatusService } from './services/network-status.service';
import { firstValueFrom } from 'rxjs';
registerLocaleData(localeDe, localeDeExtra);
registerLocaleData(localeDe, 'de', localeDeExtra);
@@ -46,26 +50,68 @@ export function _appInitializerFactory(
auth: AuthService,
injector: Injector,
scanAdapter: ScanAdapterService,
nativeContainer: NativeContainerService
nativeContainer: NativeContainerService,
networkStatus: NetworkStatusService,
) {
return async () => {
const statusElement = document.querySelector('#init-status');
statusElement.innerHTML = 'Konfigurationen werden geladen...';
await config.init();
statusElement.innerHTML = 'Authentifizierung wird geprüft...';
await auth.init();
const laoderElement = document.querySelector('#init-loader');
if (auth.isAuthenticated()) {
statusElement.innerHTML = 'App wird initialisiert...';
const state = injector.get(RootStateService);
await state.init();
try {
let online = false;
while (!online) {
online = await firstValueFrom(networkStatus.online$);
if (!online) {
statusElement.innerHTML =
'<b>Warte auf Netzwerkverbindung (WLAN)</b><br><br>Bitte prüfen Sie die Netzwerkverbindung (WLAN).<br>Sobald eine Netzwerkverbindung besteht, wird die App automatisch neu geladen.';
await new Promise((resolve) => setTimeout(resolve, 250));
}
}
statusElement.innerHTML = 'Konfigurationen werden geladen...';
await config.init();
statusElement.innerHTML = 'Authentifizierung wird geprüft...';
await auth.init();
if (auth.isAuthenticated()) {
statusElement.innerHTML = 'App wird initialisiert...';
const state = injector.get(RootStateService);
await state.init();
}
statusElement.innerHTML = 'Native Container wird initialisiert...';
await nativeContainer.init();
statusElement.innerHTML = 'Scanner wird initialisiert...';
await scanAdapter.init();
} catch (error) {
laoderElement.remove();
statusElement.classList.add('text-xl');
statusElement.innerHTML = '<b>Fehler bei der Initialisierung</b><br><br>Bitte prüfen Sie die Netzwerkverbindung (WLAN).<br><br>';
const reload = document.createElement('button');
reload.classList.add('bg-brand', 'text-white', 'p-2', 'rounded', 'cursor-pointer');
reload.innerHTML = 'App neu laden';
reload.onclick = () => window.location.reload();
statusElement.appendChild(reload);
const preLabel = document.createElement('div');
preLabel.classList.add('mt-12');
preLabel.innerHTML = 'Fehlermeldung:';
statusElement.appendChild(preLabel);
const pre = document.createElement('pre');
pre.classList.add('mt-4', 'text-wrap');
pre.innerHTML = error.message;
statusElement.appendChild(pre);
console.error('Error during app initialization', error);
throw error;
}
statusElement.innerHTML = 'Native Container wird initialisiert...';
await nativeContainer.init();
statusElement.innerHTML = 'Scanner wird initialisiert...';
await scanAdapter.init();
};
}
@@ -107,13 +153,14 @@ export function _notificationsHubOptionsFactory(config: Config, auth: AuthServic
ScanditScanAdapterModule.forRoot(),
PlatformModule,
IconModule.forRoot(),
NgIconsModule.withIcons({ matWifiOff, matClose, matWifi }),
],
providers: [
{
provide: APP_INITIALIZER,
useFactory: _appInitializerFactory,
multi: true,
deps: [Config, AuthService, Injector, ScanAdapterService, NativeContainerService],
deps: [Config, AuthService, Injector, ScanAdapterService, NativeContainerService, NetworkStatusService],
},
{
provide: NOTIFICATIONS_HUB_OPTIONS,

View File

@@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
import { AuthService } from '@core/auth';
import { ScanAdapterService } from '@adapter/scan';
import { AuthService as IsaAuthService } from '@swagger/isa';
@@ -9,11 +9,12 @@ import { EnvironmentService } from '@core/environment';
@Injectable({ providedIn: 'root' })
export class IsAuthenticatedGuard {
constructor(
private _router: Router,
private _authService: AuthService,
private _scanService: ScanAdapterService,
private _isaAuthService: IsaAuthService,
private _modal: UiModalService,
private _environmentService: EnvironmentService
private _environmentService: EnvironmentService,
) {}
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {

View File

@@ -2,30 +2,31 @@ import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpEvent, HttpHandler, HttpRequest, HttpErrorResponse } from '@angular/common/http';
import { NEVER, Observable, throwError } from 'rxjs';
import { UiMessageModalComponent, UiModalService } from '@ui/modal';
import { catchError, mergeMap, tap } from 'rxjs/operators';
import { catchError, filter, mergeMap, takeUntil, tap } from 'rxjs/operators';
import { AuthService } from '@core/auth';
import { IsaLogProvider } from '../providers';
import { LogLevel } from '@core/logger';
import { injectOnline$ } from '../services/network-status.service';
@Injectable()
export class HttpErrorInterceptor implements HttpInterceptor {
constructor(private _modal: UiModalService, private _auth: AuthService, private _isaLogProvider: IsaLogProvider) {}
readonly offline$ = injectOnline$().pipe(filter((online) => !online));
constructor(
private _modal: UiModalService,
private _auth: AuthService,
private _isaLogProvider: IsaLogProvider,
) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req).pipe(catchError((error: HttpErrorResponse, caught: any) => this.handleError(error)));
return next.handle(req).pipe(
takeUntil(this.offline$),
catchError((error: HttpErrorResponse, caught: any) => this.handleError(error)),
);
}
handleError(error: HttpErrorResponse): Observable<any> {
if (error.status === 0) {
return this._modal
.open({
content: UiMessageModalComponent,
title: 'Sie sind offline, keine Verbindung zum Netzwerk',
data: { message: 'Bereits geladene Inhalte werden angezeigt. Interaktionen sind aktuell nicht möglich.' },
})
.afterClosed$.pipe(mergeMap(() => throwError(error)));
} else if (error.status === 401) {
console.log('401', error);
if (error.status === 401) {
return this._modal
.open({
content: UiMessageModalComponent,
@@ -36,11 +37,13 @@ export class HttpErrorInterceptor implements HttpInterceptor {
tap(() => {
this._auth.login();
}),
mergeMap(() => NEVER)
mergeMap(() => NEVER),
);
}
this._isaLogProvider.log(LogLevel.ERROR, 'Http Error', error);
if (!error.url.endsWith('/isa/logging')) {
this._isaLogProvider.log(LogLevel.ERROR, 'Http Error', error);
}
return throwError(error);
}

View File

@@ -7,7 +7,11 @@ import { LogLevel } from '@core/logger';
@Injectable({ providedIn: 'root' })
export class IsaErrorHandler implements ErrorHandler {
constructor(private _modal: UiModalService, private _authService: AuthService, private _isaLogProvider: IsaLogProvider) {}
constructor(
private _modal: UiModalService,
private _authService: AuthService,
private _isaLogProvider: IsaLogProvider,
) {}
async handleError(error: any): Promise<void> {
console.error(error);
@@ -37,13 +41,13 @@ export class IsaErrorHandler implements ErrorHandler {
this._isaLogProvider.log(LogLevel.ERROR, 'Client Error', error);
this._modal.open({
content: UiErrorModalComponent,
title:
!navigator.onLine || (error instanceof HttpErrorResponse && error?.status === 0)
? 'Sie sind offline, keine Verbindung zum Netzwerk'
: 'Unbekannter Fehler',
data: error,
});
// this._modal.open({
// content: UiErrorModalComponent,
// title:
// !navigator.onLine || (error instanceof HttpErrorResponse && error?.status === 0)
// ? 'Sie sind offline, keine Verbindung zum Netzwerk'
// : 'Unbekannter Fehler',
// data: error,
// });
}
}

View File

@@ -0,0 +1,25 @@
import { inject, Injectable } from '@angular/core';
import { map, Observable } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class NetworkStatusService {
online$ = new Observable<boolean>((subscriber) => {
const handler = () => subscriber.next(navigator.onLine);
window.addEventListener('online', handler);
window.addEventListener('offline', handler);
handler();
return () => {
window.removeEventListener('online', handler);
window.removeEventListener('offline', handler);
};
});
status$ = this.online$.pipe(map((online) => (online ? 'online' : 'offline')));
}
export const injectNetworkStatus$ = () => inject(NetworkStatusService).status$;
export const injectOnline$ = () => inject(NetworkStatusService).online$;

View File

@@ -73,7 +73,7 @@
},
"checkForUpdates": 3600000,
"licence": {
"scandit": "Ae7z0WDdRDFqG6oYuAXzesYGJpDLDqt+xWtQHOESiOjaSkB7IEIDJAk534U+cg1zGnk++4hOEK9hXEGR01NLTjh76w1fDL0U63OUjo50EHBXIUvzAVSur3pRY+1ER7SvSEWaT0hDOLYvYrTpdECtt1graN9yMvJzXD38VJKUfssT92p+YENV2Hul3eXIvaVjHqXE/yvupF+MlOMMUMhX0/Km/yTU9H9SjBdsXYihZmYWbt2JotO3Zs1ojXb0+3La10xb01S1q0XdDN6El3XMVilEtdmrP3WoGois8vpQBvOCEvduxCfILFAqjeWXTZvXSut9u+kQKpK8uHW4rVV6iVClpZfPYqKJqTh78AI9gpnfb/zO9GfQEDS3g7wI5WbQKqaNRzhTVowFRri4Ep9R5TRC1bnd00RC4zVaMkbu5kBOA7YoRjgUiYWHKJpi/VokZWyN6u1lsi5mTUbQkm1ZWfX5I/iUVYBgyHZYl+8kfFkwLPXGZNrF4xqubjKiCZRQj0oyNjHOBeHqvAekzhk7scX2g/NN+liRQv4ur413b+uXacSiiYIrLhtGgzrz1KRrtu19uB5odk3LoerDoiYXat7wEg9zUYT/+uBfO2X+uS7L5LW0PMI3hV+joQVpDk5SlA2868Nx0KWtPWmMf7xCuFIhDskfBsXZNRTblqxkk0RzzSqtjx9ihGr+/Tuzm8Pm0s4OQqV7b+++/Zn+Vo4rCqMTwutjOO7dqhah5hbOT1MqY/6VcjCXyDad3BXXr+WYU4GtYTe8Ytjkm/ZTG3fImoDbMchEcqnCw3oxG5e/gkdurE8g/mZlFOtzAN7KkqIsg6qLaC5COjfLPXsi/A=="
"scandit": "Ac2kvx5ZOzjvFl/LuAd6wds3C30YJ4g8Cm6PX4sgUnKPePVMuH+rFQIyVNn1YdS3myORojEOBsIZWhMw2nRUGBtOnQ5FO+cRHgQu0pkP+VG6OYvt8ETUTn8Aa2f9bmfqclO3LI8WN8psWr+adkZEtqNTvCgyDLZaICh8S7RfmwJVVWaOPX4LDagGhLDPS2YQdg+ibpR0l0ZlX2h/3GttofE64HOlBN3QtDB8yihHJNgVcUVy2UQVS+BXOyvIfZEFbFgPYVt5HZ0aQgcISlYVAmJvRsHyeKYRUnIi3ZN73EQmHzWcOV4/HWVoTs1MTW0mxV074vNwqExYW9LYmz9zgLUD7FMnKMFClkzRBHRN1CC7brosCnFkZWQp3CV4Ua48Fn9GW0Zpn/4MIZgzSU26inl5ZnT3dCc2+3BH3Us1uugTUrOPwFuwsPpr4NZYXWJMOmcm4kBBVJd0Uwk28GyZM7x1hXADcQgcc23+gDtbbUZWVmr3TE7GBcV3j+XUeOk8nHZw3DsYJ46MT2sSfks3QXRl4tBkBad6M+UxW4tb2IQC/4K9IXKhDN8VYXpzrrRHJNvOiH5+NrixthDZHHd/MGNuBDrJFOuXq8L7O6PxBoVZ0NPXmCO5vKyYdhBz5gJ5u3vNkSke7p+cDcvFicsVyNWRaaoFL0UN9gxFVMY8hkJKBZyGxZL2LEDXD44PxPsDnygpDC1Jyc7pkhEA0fKSc9aXZb1HDpwe1hqyyRVBtHkgPiN78GmJImbaUlj8XsK3yVyAjs2XvPR0/3ASHS53ViwzWKL3Oi8I515IJDtDhlvrkeh7MrWMaEu9k6ZQXJi1uJsh3JGfyS+yDlPjePVdsVqnZ4uw9pKMXvjlJeNcIiGM2Cf5S89nk2Qe/56MrKB9Frm6Q5wQHai8TNdCZYBi67dmAX8KHPXvEU4K6KyyW89YGcabZQ3eOJDr4oqW9ZcYPBttREdH3WI/HxvpEq6bqoDhT9AxpIWEMVb6y/DcDHSEresepibug4qOr9xOPq0yk2uiWYhPubFnCk7thQCXOGv9crWnQoOrt9c1qoaWXM4YmKqfcaQ67Tn+uFQmYTZyqw4jlJU4GgKe5/GNCVQM5aNUg1J0Px1NlFCS+rrIDyMQp0byFcgTd/E9sA5d1+YZKHKmJiQwEAz6oU9yyoUlxntSI42GHB/UttPc7Hj14V5+oJ+Yz+CZodmkXFg57Vx4NuxveNtO"
},
"gender": {
"0": "Keine Anrede",

View File

@@ -72,7 +72,7 @@
},
"checkForUpdates": 900000,
"licence": {
"scandit": "Ae7z0WDdRDFqG6oYuAXzesYGJpDLDqt+xWtQHOESiOjaSkB7IEIDJAk534U+cg1zGnk++4hOEK9hXEGR01NLTjh76w1fDL0U63OUjo50EHBXIUvzAVSur3pRY+1ER7SvSEWaT0hDOLYvYrTpdECtt1graN9yMvJzXD38VJKUfssT92p+YENV2Hul3eXIvaVjHqXE/yvupF+MlOMMUMhX0/Km/yTU9H9SjBdsXYihZmYWbt2JotO3Zs1ojXb0+3La10xb01S1q0XdDN6El3XMVilEtdmrP3WoGois8vpQBvOCEvduxCfILFAqjeWXTZvXSut9u+kQKpK8uHW4rVV6iVClpZfPYqKJqTh78AI9gpnfb/zO9GfQEDS3g7wI5WbQKqaNRzhTVowFRri4Ep9R5TRC1bnd00RC4zVaMkbu5kBOA7YoRjgUiYWHKJpi/VokZWyN6u1lsi5mTUbQkm1ZWfX5I/iUVYBgyHZYl+8kfFkwLPXGZNrF4xqubjKiCZRQj0oyNjHOBeHqvAekzhk7scX2g/NN+liRQv4ur413b+uXacSiiYIrLhtGgzrz1KRrtu19uB5odk3LoerDoiYXat7wEg9zUYT/+uBfO2X+uS7L5LW0PMI3hV+joQVpDk5SlA2868Nx0KWtPWmMf7xCuFIhDskfBsXZNRTblqxkk0RzzSqtjx9ihGr+/Tuzm8Pm0s4OQqV7b+++/Zn+Vo4rCqMTwutjOO7dqhah5hbOT1MqY/6VcjCXyDad3BXXr+WYU4GtYTe8Ytjkm/ZTG3fImoDbMchEcqnCw3oxG5e/gkdurE8g/mZlFOtzAN7KkqIsg6qLaC5COjfLPXsi/A=="
"scandit": "Ac2kvx5ZOzjvFl/LuAd6wds3C30YJ4g8Cm6PX4sgUnKPePVMuH+rFQIyVNn1YdS3myORojEOBsIZWhMw2nRUGBtOnQ5FO+cRHgQu0pkP+VG6OYvt8ETUTn8Aa2f9bmfqclO3LI8WN8psWr+adkZEtqNTvCgyDLZaICh8S7RfmwJVVWaOPX4LDagGhLDPS2YQdg+ibpR0l0ZlX2h/3GttofE64HOlBN3QtDB8yihHJNgVcUVy2UQVS+BXOyvIfZEFbFgPYVt5HZ0aQgcISlYVAmJvRsHyeKYRUnIi3ZN73EQmHzWcOV4/HWVoTs1MTW0mxV074vNwqExYW9LYmz9zgLUD7FMnKMFClkzRBHRN1CC7brosCnFkZWQp3CV4Ua48Fn9GW0Zpn/4MIZgzSU26inl5ZnT3dCc2+3BH3Us1uugTUrOPwFuwsPpr4NZYXWJMOmcm4kBBVJd0Uwk28GyZM7x1hXADcQgcc23+gDtbbUZWVmr3TE7GBcV3j+XUeOk8nHZw3DsYJ46MT2sSfks3QXRl4tBkBad6M+UxW4tb2IQC/4K9IXKhDN8VYXpzrrRHJNvOiH5+NrixthDZHHd/MGNuBDrJFOuXq8L7O6PxBoVZ0NPXmCO5vKyYdhBz5gJ5u3vNkSke7p+cDcvFicsVyNWRaaoFL0UN9gxFVMY8hkJKBZyGxZL2LEDXD44PxPsDnygpDC1Jyc7pkhEA0fKSc9aXZb1HDpwe1hqyyRVBtHkgPiN78GmJImbaUlj8XsK3yVyAjs2XvPR0/3ASHS53ViwzWKL3Oi8I515IJDtDhlvrkeh7MrWMaEu9k6ZQXJi1uJsh3JGfyS+yDlPjePVdsVqnZ4uw9pKMXvjlJeNcIiGM2Cf5S89nk2Qe/56MrKB9Frm6Q5wQHai8TNdCZYBi67dmAX8KHPXvEU4K6KyyW89YGcabZQ3eOJDr4oqW9ZcYPBttREdH3WI/HxvpEq6bqoDhT9AxpIWEMVb6y/DcDHSEresepibug4qOr9xOPq0yk2uiWYhPubFnCk7thQCXOGv9crWnQoOrt9c1qoaWXM4YmKqfcaQ67Tn+uFQmYTZyqw4jlJU4GgKe5/GNCVQM5aNUg1J0Px1NlFCS+rrIDyMQp0byFcgTd/E9sA5d1+YZKHKmJiQwEAz6oU9yyoUlxntSI42GHB/UttPc7Hj14V5+oJ+Yz+CZodmkXFg57Vx4NuxveNtO"
},
"gender": {
"0": "Keine Anrede",

View File

@@ -74,7 +74,7 @@
},
"checkForUpdates": 3600000,
"licence": {
"scandit": "Ae7z0WDdRDFqG6oYuAXzesYGJpDLDqt+xWtQHOESiOjaSkB7IEIDJAk534U+cg1zGnk++4hOEK9hXEGR01NLTjh76w1fDL0U63OUjo50EHBXIUvzAVSur3pRY+1ER7SvSEWaT0hDOLYvYrTpdECtt1graN9yMvJzXD38VJKUfssT92p+YENV2Hul3eXIvaVjHqXE/yvupF+MlOMMUMhX0/Km/yTU9H9SjBdsXYihZmYWbt2JotO3Zs1ojXb0+3La10xb01S1q0XdDN6El3XMVilEtdmrP3WoGois8vpQBvOCEvduxCfILFAqjeWXTZvXSut9u+kQKpK8uHW4rVV6iVClpZfPYqKJqTh78AI9gpnfb/zO9GfQEDS3g7wI5WbQKqaNRzhTVowFRri4Ep9R5TRC1bnd00RC4zVaMkbu5kBOA7YoRjgUiYWHKJpi/VokZWyN6u1lsi5mTUbQkm1ZWfX5I/iUVYBgyHZYl+8kfFkwLPXGZNrF4xqubjKiCZRQj0oyNjHOBeHqvAekzhk7scX2g/NN+liRQv4ur413b+uXacSiiYIrLhtGgzrz1KRrtu19uB5odk3LoerDoiYXat7wEg9zUYT/+uBfO2X+uS7L5LW0PMI3hV+joQVpDk5SlA2868Nx0KWtPWmMf7xCuFIhDskfBsXZNRTblqxkk0RzzSqtjx9ihGr+/Tuzm8Pm0s4OQqV7b+++/Zn+Vo4rCqMTwutjOO7dqhah5hbOT1MqY/6VcjCXyDad3BXXr+WYU4GtYTe8Ytjkm/ZTG3fImoDbMchEcqnCw3oxG5e/gkdurE8g/mZlFOtzAN7KkqIsg6qLaC5COjfLPXsi/A=="
"scandit": "Ac2kvx5ZOzjvFl/LuAd6wds3C30YJ4g8Cm6PX4sgUnKPePVMuH+rFQIyVNn1YdS3myORojEOBsIZWhMw2nRUGBtOnQ5FO+cRHgQu0pkP+VG6OYvt8ETUTn8Aa2f9bmfqclO3LI8WN8psWr+adkZEtqNTvCgyDLZaICh8S7RfmwJVVWaOPX4LDagGhLDPS2YQdg+ibpR0l0ZlX2h/3GttofE64HOlBN3QtDB8yihHJNgVcUVy2UQVS+BXOyvIfZEFbFgPYVt5HZ0aQgcISlYVAmJvRsHyeKYRUnIi3ZN73EQmHzWcOV4/HWVoTs1MTW0mxV074vNwqExYW9LYmz9zgLUD7FMnKMFClkzRBHRN1CC7brosCnFkZWQp3CV4Ua48Fn9GW0Zpn/4MIZgzSU26inl5ZnT3dCc2+3BH3Us1uugTUrOPwFuwsPpr4NZYXWJMOmcm4kBBVJd0Uwk28GyZM7x1hXADcQgcc23+gDtbbUZWVmr3TE7GBcV3j+XUeOk8nHZw3DsYJ46MT2sSfks3QXRl4tBkBad6M+UxW4tb2IQC/4K9IXKhDN8VYXpzrrRHJNvOiH5+NrixthDZHHd/MGNuBDrJFOuXq8L7O6PxBoVZ0NPXmCO5vKyYdhBz5gJ5u3vNkSke7p+cDcvFicsVyNWRaaoFL0UN9gxFVMY8hkJKBZyGxZL2LEDXD44PxPsDnygpDC1Jyc7pkhEA0fKSc9aXZb1HDpwe1hqyyRVBtHkgPiN78GmJImbaUlj8XsK3yVyAjs2XvPR0/3ASHS53ViwzWKL3Oi8I515IJDtDhlvrkeh7MrWMaEu9k6ZQXJi1uJsh3JGfyS+yDlPjePVdsVqnZ4uw9pKMXvjlJeNcIiGM2Cf5S89nk2Qe/56MrKB9Frm6Q5wQHai8TNdCZYBi67dmAX8KHPXvEU4K6KyyW89YGcabZQ3eOJDr4oqW9ZcYPBttREdH3WI/HxvpEq6bqoDhT9AxpIWEMVb6y/DcDHSEresepibug4qOr9xOPq0yk2uiWYhPubFnCk7thQCXOGv9crWnQoOrt9c1qoaWXM4YmKqfcaQ67Tn+uFQmYTZyqw4jlJU4GgKe5/GNCVQM5aNUg1J0Px1NlFCS+rrIDyMQp0byFcgTd/E9sA5d1+YZKHKmJiQwEAz6oU9yyoUlxntSI42GHB/UttPc7Hj14V5+oJ+Yz+CZodmkXFg57Vx4NuxveNtO"
},
"gender": {
"0": "Keine Anrede",

View File

@@ -73,7 +73,7 @@
},
"checkForUpdates": 3600000,
"licence": {
"scandit": "AVljxT/dG+TAIDDL2jTxm843juR2OtZ6lHLxRpYR7x9uYiSvY2IAHdRx8tjsf9KU7wK0F5cAeb/nLMHF6Vor9ps79wvuBQw6G3N0IW978b78ZUgPOFzxHUAMuD8dbkDZlX8r9y1cOd9sT3UNEwGrQ4siUt2oCkigyTxJAgYs1ijnjQid7q42hHk3tMXywrAYeu5MhF0TV1H77DRDMxPHD/xiR0zhFQRB2Dtnm1+e3LHKCyQjZ/zknEpQB6HS7UbCBoEDj4tohb83E6oqmQFWwt85/Jk9f49gxXakIcNODnQI5H63kSqpEmV9Al1a5L+WGZ6Bq1gwBbnD8FBXlVqxoooiFXW7jzzBa9LNmQiQ5J8yEkIsPeyOHec7F4ERvVONSMYwWyH39ZweSiRsZRM1UsFPhN96bCT5MEwkjPFn4gji6TPGEceJZvV3HwsiCT5Bgjla4bvDsZ2jYvAr9tSij8kIii9dHvsWlrimt+szHJLSz+8uNI6jAvXyr2f3oRxZD/F9osZHVWkgtAc+vVWqkxVJCqmpmoHOXI6TFSqSjYHddhZyU5r2lgQt0+NI6k/bV3iN7Le1RJCP/wuSDCTZjzsU1igB7UnIN2Y70CqCjIeVH9qlxaI1YAC9lwFv1FZvsiueYeJP1n39mmXCSELVtzxgIBEX5yaIHNbbGXd+e8JUgcO8vJ2JA2kJudaU+xfYR5SY//+J1kPsNSbnBnM25LL+LjeRB3QTfqV5sFq8ORWcIMITvkEaRfP3PVcOzb+hO4Ren4ezhJuyADulmvG8a9Kxxk6ymzBbE7a93SGVbxp7OQNEmvTn5+B9wJ7/l1mtvZL2TilrDZBQVMYWrGuUGpA="
"scandit": "AZ70hgtZLmFWHbYP+BDq8VAEgAxmNGYcPU8YpOc3DryEXj4zMzYQFrQuUm0YfzKaR2xbfjsImjXJN7C/TE1CYXsv3DeqIzgDRA/kII4LzqoICWm9mnwejER1kMu1Vf+1NWbwUuYJjsQVQXYkwkWgnv53obevBZtjpgZqIzlStufIU+sPNEWSd9BlrLmiSEu6nXC5lbstyPJVaqihsFoBPNJ0Q+IgJUjqaxhTf6hGtNB3Rqcpv0ZT349NdK9mQ+9lAQYCwXdmYbELdlbZVSja0aJQlkf0TaAjixDbNcR32/VMIw98F2YxVRVWPnADUaJ9Bn8oa7NkOJIUfB7VAg1KtUl8IIwSXvRk436UtPZGxg+PQM7UXX/TgiBuqCQWdUChoH/QAoY2fyKRKgXJHnGdt+pBRQ2OYs7TZWCJLZsLKgnHV+eWh3Y3EB1hN9cmcszdnmYiyD1gCY8pSETFbWV01nVPvIuUTc+jMipv3NN81VQDS5/eU1VJNpRuDiufdBKJv0jjHQk+hTdqe+2GSmMD24ZG8FQXJZZPBCodWR1A81T8toCaIAGHnOfZeO7nxZu9Uo+6ohrVxc5F4szSizra+M3zfuFnm5FGgxCKt5uibLYgRyNcmR8/9vqTfMZgalTklbKHEFw1i+xOwrFrqRMh7FoovDRoI3QuaHLpV+ZUpZo3zTOQofdXPthKAmSLc11cjn509oTnnXUBBoBn/hErrwC/v8dZep1YEKM3wjfuIFsHRrsECswqNjwN/yOZCirm2VvFJEPMuKIwy+8jdNGncm8v4R9Br3c+wYJ8696L7Dg0iFShoyoP4OqIvBNY+dYyy935yGkIF2KI6l01xQZcWoHSVKPd6/78Iwy4lTKhtOqtu7ETJqOE53gQpR9jaAY0RiBB1SLm+Jbwt3ipSJiCDgKmkVmk5AU9HC0XYR/erjg13HF4hIcpLPW1ZWMKSxTqZ8z8FMJilInBgfcBwvjNE5seWvdFKltvlItnGhSh7BLUZ5UInDhl00NJBE2PdstDvRvQjLKvYUoFly3jONVsUfuQpzrcjT0g6gEgL8ZtlmaF11owcCvqhNDxWuTAJTX/xXf6WehxEB0qy3xCdxahbuneS3DPI0z2kAQwrx19i5r+RKQ8bWDaQ/OGY47sLPJgDgijEz16CvAMBSN0PvOso6FstsT/ynR3LLTPcY0QDw21Dv3wNHNa9HbanJcb3/MuhZGlrKp7"
},
"gender": {
"0": "Keine Anrede",

View File

@@ -73,7 +73,7 @@
},
"checkForUpdates": 3600000,
"licence": {
"scandit": "AVljxT/dG+TAIDDL2jTxm843juR2OtZ6lHLxRpYR7x9uYiSvY2IAHdRx8tjsf9KU7wK0F5cAeb/nLMHF6Vor9ps79wvuBQw6G3N0IW978b78ZUgPOFzxHUAMuD8dbkDZlX8r9y1cOd9sT3UNEwGrQ4siUt2oCkigyTxJAgYs1ijnjQid7q42hHk3tMXywrAYeu5MhF0TV1H77DRDMxPHD/xiR0zhFQRB2Dtnm1+e3LHKCyQjZ/zknEpQB6HS7UbCBoEDj4tohb83E6oqmQFWwt85/Jk9f49gxXakIcNODnQI5H63kSqpEmV9Al1a5L+WGZ6Bq1gwBbnD8FBXlVqxoooiFXW7jzzBa9LNmQiQ5J8yEkIsPeyOHec7F4ERvVONSMYwWyH39ZweSiRsZRM1UsFPhN96bCT5MEwkjPFn4gji6TPGEceJZvV3HwsiCT5Bgjla4bvDsZ2jYvAr9tSij8kIii9dHvsWlrimt+szHJLSz+8uNI6jAvXyr2f3oRxZD/F9osZHVWkgtAc+vVWqkxVJCqmpmoHOXI6TFSqSjYHddhZyU5r2lgQt0+NI6k/bV3iN7Le1RJCP/wuSDCTZjzsU1igB7UnIN2Y70CqCjIeVH9qlxaI1YAC9lwFv1FZvsiueYeJP1n39mmXCSELVtzxgIBEX5yaIHNbbGXd+e8JUgcO8vJ2JA2kJudaU+xfYR5SY//+J1kPsNSbnBnM25LL+LjeRB3QTfqV5sFq8ORWcIMITvkEaRfP3PVcOzb+hO4Ren4ezhJuyADulmvG8a9Kxxk6ymzBbE7a93SGVbxp7OQNEmvTn5+B9wJ7/l1mtvZL2TilrDZBQVMYWrGuUGpA="
"scandit": "AZ70hgtZLmFWHbYP+BDq8VAEgAxmNGYcPU8YpOc3DryEXj4zMzYQFrQuUm0YfzKaR2xbfjsImjXJN7C/TE1CYXsv3DeqIzgDRA/kII4LzqoICWm9mnwejER1kMu1Vf+1NWbwUuYJjsQVQXYkwkWgnv53obevBZtjpgZqIzlStufIU+sPNEWSd9BlrLmiSEu6nXC5lbstyPJVaqihsFoBPNJ0Q+IgJUjqaxhTf6hGtNB3Rqcpv0ZT349NdK9mQ+9lAQYCwXdmYbELdlbZVSja0aJQlkf0TaAjixDbNcR32/VMIw98F2YxVRVWPnADUaJ9Bn8oa7NkOJIUfB7VAg1KtUl8IIwSXvRk436UtPZGxg+PQM7UXX/TgiBuqCQWdUChoH/QAoY2fyKRKgXJHnGdt+pBRQ2OYs7TZWCJLZsLKgnHV+eWh3Y3EB1hN9cmcszdnmYiyD1gCY8pSETFbWV01nVPvIuUTc+jMipv3NN81VQDS5/eU1VJNpRuDiufdBKJv0jjHQk+hTdqe+2GSmMD24ZG8FQXJZZPBCodWR1A81T8toCaIAGHnOfZeO7nxZu9Uo+6ohrVxc5F4szSizra+M3zfuFnm5FGgxCKt5uibLYgRyNcmR8/9vqTfMZgalTklbKHEFw1i+xOwrFrqRMh7FoovDRoI3QuaHLpV+ZUpZo3zTOQofdXPthKAmSLc11cjn509oTnnXUBBoBn/hErrwC/v8dZep1YEKM3wjfuIFsHRrsECswqNjwN/yOZCirm2VvFJEPMuKIwy+8jdNGncm8v4R9Br3c+wYJ8696L7Dg0iFShoyoP4OqIvBNY+dYyy935yGkIF2KI6l01xQZcWoHSVKPd6/78Iwy4lTKhtOqtu7ETJqOE53gQpR9jaAY0RiBB1SLm+Jbwt3ipSJiCDgKmkVmk5AU9HC0XYR/erjg13HF4hIcpLPW1ZWMKSxTqZ8z8FMJilInBgfcBwvjNE5seWvdFKltvlItnGhSh7BLUZ5UInDhl00NJBE2PdstDvRvQjLKvYUoFly3jONVsUfuQpzrcjT0g6gEgL8ZtlmaF11owcCvqhNDxWuTAJTX/xXf6WehxEB0qy3xCdxahbuneS3DPI0z2kAQwrx19i5r+RKQ8bWDaQ/OGY47sLPJgDgijEz16CvAMBSN0PvOso6FstsT/ynR3LLTPcY0QDw21Dv3wNHNa9HbanJcb3/MuhZGlrKp7"
},
"gender": {
"0": "Keine Anrede",

View File

@@ -74,7 +74,7 @@
},
"checkForUpdates": 3600000,
"licence": {
"scandit": "Ae7z0WDdRDFqG6oYuAXzesYGJpDLDqt+xWtQHOESiOjaSkB7IEIDJAk534U+cg1zGnk++4hOEK9hXEGR01NLTjh76w1fDL0U63OUjo50EHBXIUvzAVSur3pRY+1ER7SvSEWaT0hDOLYvYrTpdECtt1graN9yMvJzXD38VJKUfssT92p+YENV2Hul3eXIvaVjHqXE/yvupF+MlOMMUMhX0/Km/yTU9H9SjBdsXYihZmYWbt2JotO3Zs1ojXb0+3La10xb01S1q0XdDN6El3XMVilEtdmrP3WoGois8vpQBvOCEvduxCfILFAqjeWXTZvXSut9u+kQKpK8uHW4rVV6iVClpZfPYqKJqTh78AI9gpnfb/zO9GfQEDS3g7wI5WbQKqaNRzhTVowFRri4Ep9R5TRC1bnd00RC4zVaMkbu5kBOA7YoRjgUiYWHKJpi/VokZWyN6u1lsi5mTUbQkm1ZWfX5I/iUVYBgyHZYl+8kfFkwLPXGZNrF4xqubjKiCZRQj0oyNjHOBeHqvAekzhk7scX2g/NN+liRQv4ur413b+uXacSiiYIrLhtGgzrz1KRrtu19uB5odk3LoerDoiYXat7wEg9zUYT/+uBfO2X+uS7L5LW0PMI3hV+joQVpDk5SlA2868Nx0KWtPWmMf7xCuFIhDskfBsXZNRTblqxkk0RzzSqtjx9ihGr+/Tuzm8Pm0s4OQqV7b+++/Zn+Vo4rCqMTwutjOO7dqhah5hbOT1MqY/6VcjCXyDad3BXXr+WYU4GtYTe8Ytjkm/ZTG3fImoDbMchEcqnCw3oxG5e/gkdurE8g/mZlFOtzAN7KkqIsg6qLaC5COjfLPXsi/A=="
"scandit": "Ac2kvx5ZOzjvFl/LuAd6wds3C30YJ4g8Cm6PX4sgUnKPePVMuH+rFQIyVNn1YdS3myORojEOBsIZWhMw2nRUGBtOnQ5FO+cRHgQu0pkP+VG6OYvt8ETUTn8Aa2f9bmfqclO3LI8WN8psWr+adkZEtqNTvCgyDLZaICh8S7RfmwJVVWaOPX4LDagGhLDPS2YQdg+ibpR0l0ZlX2h/3GttofE64HOlBN3QtDB8yihHJNgVcUVy2UQVS+BXOyvIfZEFbFgPYVt5HZ0aQgcISlYVAmJvRsHyeKYRUnIi3ZN73EQmHzWcOV4/HWVoTs1MTW0mxV074vNwqExYW9LYmz9zgLUD7FMnKMFClkzRBHRN1CC7brosCnFkZWQp3CV4Ua48Fn9GW0Zpn/4MIZgzSU26inl5ZnT3dCc2+3BH3Us1uugTUrOPwFuwsPpr4NZYXWJMOmcm4kBBVJd0Uwk28GyZM7x1hXADcQgcc23+gDtbbUZWVmr3TE7GBcV3j+XUeOk8nHZw3DsYJ46MT2sSfks3QXRl4tBkBad6M+UxW4tb2IQC/4K9IXKhDN8VYXpzrrRHJNvOiH5+NrixthDZHHd/MGNuBDrJFOuXq8L7O6PxBoVZ0NPXmCO5vKyYdhBz5gJ5u3vNkSke7p+cDcvFicsVyNWRaaoFL0UN9gxFVMY8hkJKBZyGxZL2LEDXD44PxPsDnygpDC1Jyc7pkhEA0fKSc9aXZb1HDpwe1hqyyRVBtHkgPiN78GmJImbaUlj8XsK3yVyAjs2XvPR0/3ASHS53ViwzWKL3Oi8I515IJDtDhlvrkeh7MrWMaEu9k6ZQXJi1uJsh3JGfyS+yDlPjePVdsVqnZ4uw9pKMXvjlJeNcIiGM2Cf5S89nk2Qe/56MrKB9Frm6Q5wQHai8TNdCZYBi67dmAX8KHPXvEU4K6KyyW89YGcabZQ3eOJDr4oqW9ZcYPBttREdH3WI/HxvpEq6bqoDhT9AxpIWEMVb6y/DcDHSEresepibug4qOr9xOPq0yk2uiWYhPubFnCk7thQCXOGv9crWnQoOrt9c1qoaWXM4YmKqfcaQ67Tn+uFQmYTZyqw4jlJU4GgKe5/GNCVQM5aNUg1J0Px1NlFCS+rrIDyMQp0byFcgTd/E9sA5d1+YZKHKmJiQwEAz6oU9yyoUlxntSI42GHB/UttPc7Hj14V5+oJ+Yz+CZodmkXFg57Vx4NuxveNtO"
},
"gender": {
"0": "Keine Anrede",

View File

@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
@@ -15,7 +15,7 @@
<app-root>
<div class="grid place-items-center h-screen">
<div class="grid grid-flow-row gap-4 items-center justify-center">
<div class="flex flex-col items-center">
<div id="init-loader" class="flex flex-col items-center">
<img class="animate-spin" src="/assets/images/spinner.svg" alt="spinner animation" />
</div>
<div id="init-status" class="text-center">App wird geladen</div>

View File

@@ -1,25 +1,12 @@
import { Injectable } from '@angular/core';
import {
Observable,
of,
BehaviorSubject,
Subject,
merge,
combineLatest,
} from 'rxjs';
import { Observable, of, BehaviorSubject, Subject, merge, combineLatest } from 'rxjs';
import { delay, distinctUntilChanged, map } from 'rxjs/operators';
import { createRandomStringId, createRandomId } from './util';
import {
product,
removeSourcePriceAndProductFromProduct,
} from './data/product';
import { product, removeSourcePriceAndProductFromProduct } from './data/product';
import { RemissionService } from '../services/remission.service';
import { RemissionProcess } from '../models/remission-process';
import { RemissionProduct } from '../models/remission-product';
import {
remissionProducts,
createRemissionProduct,
} from './data/remission-products';
import { remissionProducts, createRemissionProduct } from './data/remission-products';
import { remissionProcessTemplateMock } from './data/remission-process-template';
import { ShippingDocument } from '../models/shipping-document';
import { shippingDocument } from './data/shipping-document';
@@ -41,33 +28,21 @@ import { ActionResult, CapacityType } from '../models';
@Injectable({ providedIn: 'root' })
export class MockRemissionService extends RemissionService {
private delayInMs = 100;
private remissionSubjectStore = new Map<
number,
BehaviorSubject<RemissionProcess>
>();
private remissionSubjectStore = new Map<number, BehaviorSubject<RemissionProcess>>();
private remissionSubjectIdRef = new Map<number, number>();
private reloadProductsSubject = new Subject<void>();
private productSubject = new BehaviorSubject<RemissionProduct[]>(
remissionProducts
);
private productSubject = new BehaviorSubject<RemissionProduct[]>(remissionProducts);
private getRemissionFromStore = (
remissionProcessId: number
): BehaviorSubject<RemissionProcess> => {
private getRemissionFromStore = (remissionProcessId: number): BehaviorSubject<RemissionProcess> => {
const remission =
this.remissionSubjectStore.get(remissionProcessId) ||
this.remissionSubjectStore.get(
this.remissionSubjectIdRef.get(remissionProcessId)
);
this.remissionSubjectStore.get(this.remissionSubjectIdRef.get(remissionProcessId));
return remission;
};
private saveRemissionInStore = (
remissionProcessId: number,
remissionSubject: BehaviorSubject<RemissionProcess>
) => {
private saveRemissionInStore = (remissionProcessId: number, remissionSubject: BehaviorSubject<RemissionProcess>) => {
this.remissionSubjectStore.set(remissionProcessId, remissionSubject);
};
@@ -80,27 +55,20 @@ export class MockRemissionService extends RemissionService {
return processSubject.pipe(distinctUntilChanged(), delay(this.delayInMs));
}
getRemissionProducts(params: {
remissionProcessId: number;
}): Observable<{
getRemissionProducts(params: { remissionProcessId: number }): Observable<{
skip?: number;
take?: number;
hits?: number;
items: RemissionProduct[];
completed: boolean;
}> {
const processSubject = this.getRemissionFromStore(
params.remissionProcessId
);
const processSubject = this.getRemissionFromStore(params.remissionProcessId);
if (!processSubject) {
throw new Error('Prozess nicht gefunden');
}
const process$ = merge(
processSubject,
this.reloadProductsSubject.pipe(map((_) => processSubject.value))
);
const process$ = merge(processSubject, this.reloadProductsSubject.pipe(map((_) => processSubject.value)));
const products$ = this.productSubject.asObservable();
@@ -126,24 +94,19 @@ export class MockRemissionService extends RemissionService {
const productGroupFilter = filter.filter['421228ce'] || [];
if (productGroupFilter.length > 0) {
result.items = result.items.filter((product) =>
productGroupFilter.some((s) => product.productGroup === s)
);
result.items = result.items.filter((product) => productGroupFilter.some((s) => product.productGroup === s));
}
const actionFilter = filter.filter['ce9ee0be'] || [];
result.hits = result.items.length;
result.items = result.items.slice(
result.skip,
result.skip + result.take
);
result.items = result.items.slice(result.skip, result.skip + result.take);
result.completed = result.skip + result.take >= result.hits;
return result;
})
}),
);
}
@@ -153,9 +116,7 @@ export class MockRemissionService extends RemissionService {
createShippingDocument?: boolean;
};
}): Observable<RemissionProcess> {
const processSubject = this.remissionSubjectStore.get(
params.remissionProcessId
);
const processSubject = this.remissionSubjectStore.get(params.remissionProcessId);
if (!processSubject) {
throw new Error('Prozess nicht gefunden');
@@ -214,12 +175,8 @@ export class MockRemissionService extends RemissionService {
}
}
completeRemission(params: {
remissionProcessId: number;
}): Observable<boolean> {
let processSubject = this.remissionSubjectStore.get(
params.remissionProcessId
);
completeRemission(params: { remissionProcessId: number }): Observable<boolean> {
let processSubject = this.remissionSubjectStore.get(params.remissionProcessId);
if (!processSubject) {
const refId = this.remissionSubjectIdRef.get(params.remissionProcessId);
@@ -236,9 +193,7 @@ export class MockRemissionService extends RemissionService {
}
}
getRemission(params: {
remissionProcessId: number;
}): Observable<RemissionProcess> {
getRemission(params: { remissionProcessId: number }): Observable<RemissionProcess> {
const remission = this.getRemissionFromStore(params.remissionProcessId);
if (!remission) {
@@ -248,11 +203,7 @@ export class MockRemissionService extends RemissionService {
return remission.pipe(distinctUntilChanged(), delay(this.delayInMs));
}
isPrintingRequired({
remissionProcessId,
}: {
remissionProcessId: number;
}): Observable<boolean> {
isPrintingRequired({ remissionProcessId }: { remissionProcessId: number }): Observable<boolean> {
const remission = this.getRemissionFromStore(remissionProcessId);
if (!remission) {
@@ -272,10 +223,7 @@ export class MockRemissionService extends RemissionService {
return of(printers).pipe(delay(this.delayInMs));
}
printRemissionList(params: {
remissionProcessId: number;
printerKey: string;
}): Observable<boolean> {
printRemissionList(params: { remissionProcessId: number; printerKey: string }): Observable<boolean> {
const remission = this.getRemissionFromStore(params.remissionProcessId);
if (!remission) {
@@ -285,11 +233,7 @@ export class MockRemissionService extends RemissionService {
return of(true).pipe(delay(this.delayInMs));
}
printShippingDocument(params: {
remissionProcessId: number;
shippingDocumentId?: number;
printerKey: string;
}): Observable<boolean> {
printShippingDocument(params: { remissionProcessId: number; shippingDocumentId?: number; printerKey: string }): Observable<boolean> {
const remission = this.getRemissionFromStore(params.remissionProcessId);
if (!remission || !params.printerKey) {
@@ -307,8 +251,7 @@ export class MockRemissionService extends RemissionService {
getFilters(params: { remissionProcessId: number }): Observable<Filter[]> {
const remission = this.getRemissionFromStore(params.remissionProcessId);
const filterForGivenSourceType =
remission.value.filter.source === 'zentral' ? filter : filterUeberlauf;
const filterForGivenSourceType = remission.value.filter.source === 'zentral' ? filter : filterUeberlauf;
return of(filterForGivenSourceType).pipe(delay(this.delayInMs));
}
@@ -327,38 +270,24 @@ export class MockRemissionService extends RemissionService {
return of(remissionSources).pipe(delay(this.delayInMs));
}
getShippingDocuments(params: {
remissionProcessId: number;
shippingDocumentId: number;
}): Observable<ShippingDocument> {
getShippingDocuments(params: { remissionProcessId: number; shippingDocumentId: number }): Observable<ShippingDocument> {
const remissionSub = this.getRemissionFromStore(params.remissionProcessId);
return remissionSub.pipe(
map((remission) =>
remission.shippingDocuments.find(
(shippingDoc) => shippingDoc.id === params.shippingDocumentId
)
),
map((remission) => remission.shippingDocuments.find((shippingDoc) => shippingDoc.id === params.shippingDocumentId)),
distinctUntilChanged(),
delay(this.delayInMs)
delay(this.delayInMs),
);
}
deleteProductFromRemissionList(input: {
remissionProcessId: number;
remissionProductId: number;
}): Observable<ActionResult<boolean>> {
deleteProductFromRemissionList(input: { remissionProcessId: number; remissionProductId: number }): Observable<ActionResult<boolean>> {
return of({
error: false,
result: true,
});
}
addProductToRemit(input: {
product: Product;
remissionReason: string;
remissionQuantity: number;
}): Observable<RemissionProduct> {
addProductToRemit(input: { product: Product; remissionReason: string; remissionQuantity: number }): Observable<RemissionProduct> {
const productToAdd = removeSourcePriceAndProductFromProduct({ ...product });
const newProduct = createRemissionProduct({
@@ -382,9 +311,7 @@ export class MockRemissionService extends RemissionService {
quantity?: number;
inStock?: number;
}): Observable<ActionResult<boolean>> {
const processSubject = this.getRemissionFromStore(
params.remissionProcessId
);
const processSubject = this.getRemissionFromStore(params.remissionProcessId);
const process = processSubject.value;
const products = this.productSubject.value;
@@ -392,22 +319,15 @@ export class MockRemissionService extends RemissionService {
throw new Error('Prozess nicht gefunden');
}
let productToAdd = products.find(
(product) => product.id === params.remissionProductId
);
let newProducts = products.filter(
(product) => product.id !== params.remissionProductId
);
let productToAdd = products.find((product) => product.id === params.remissionProductId);
let newProducts = products.filter((product) => product.id !== params.remissionProductId);
if (!!params.placementType || !!params.quantity) {
const productToUpdateInProductList = {
...productToAdd,
remissionQuantity: productToAdd.remissionQuantity - params.quantity,
};
newProducts =
productToAdd.remissionQuantity - params.quantity < 1
? newProducts
: [...newProducts, productToUpdateInProductList];
newProducts = productToAdd.remissionQuantity - params.quantity < 1 ? newProducts : [...newProducts, productToUpdateInProductList];
productToAdd = {
...productToAdd,
@@ -415,9 +335,7 @@ export class MockRemissionService extends RemissionService {
};
}
const shippingDocumentToUpdate = process.shippingDocuments.find(
(document) => document.id === params.shippingDocumentId
);
const shippingDocumentToUpdate = process.shippingDocuments.find((document) => document.id === params.shippingDocumentId);
const updatedShippingDocument = {
...shippingDocumentToUpdate,
products: [...shippingDocumentToUpdate.products, productToAdd],
@@ -426,9 +344,7 @@ export class MockRemissionService extends RemissionService {
const updatedProcess = {
...process,
shippingDocuments: [
...process.shippingDocuments.filter(
(document) => document.id !== params.shippingDocumentId
),
...process.shippingDocuments.filter((document) => document.id !== params.shippingDocumentId),
updatedShippingDocument,
],
};
@@ -448,9 +364,7 @@ export class MockRemissionService extends RemissionService {
remissionProductId: number;
placementType?: string;
}): Observable<boolean> {
const processSubject = this.getRemissionFromStore(
params.remissionProcessId
);
const processSubject = this.getRemissionFromStore(params.remissionProcessId);
const process = processSubject.value;
const products = this.productSubject.value;
@@ -458,44 +372,30 @@ export class MockRemissionService extends RemissionService {
throw new Error('Prozess nicht gefunden');
}
const shippingDocumentToUpdate = process.shippingDocuments.find(
(document) => document.id === params.shippingDocumentId
);
const shippingDocumentToUpdate = process.shippingDocuments.find((document) => document.id === params.shippingDocumentId);
const updatedShippingDocument = {
...shippingDocumentToUpdate,
products: shippingDocumentToUpdate.products.filter(
(product) => product.id !== params.remissionProductId
),
products: shippingDocumentToUpdate.products.filter((product) => product.id !== params.remissionProductId),
};
const productToRemove = shippingDocumentToUpdate.products.find(
(product) => product.id === params.remissionProductId
);
const productInProductList = products.find(
(product) => product.id === params.remissionProductId
);
const productToRemove = shippingDocumentToUpdate.products.find((product) => product.id === params.remissionProductId);
const productInProductList = products.find((product) => product.id === params.remissionProductId);
const updatedProductInProductList = !!productInProductList
? {
...productInProductList,
remissionQuantity:
Number(productInProductList.remissionQuantity) +
Number(productToRemove.remissionQuantity),
remissionQuantity: Number(productInProductList.remissionQuantity) + Number(productToRemove.remissionQuantity),
}
: productToRemove;
const updatedProcess = {
...process,
shippingDocuments: [
...process.shippingDocuments.filter(
(document) => document.id !== params.shippingDocumentId
),
...process.shippingDocuments.filter((document) => document.id !== params.shippingDocumentId),
updatedShippingDocument,
],
};
const updatedProducts = [
...this.productSubject.value.filter(
(product) => product.id !== updatedProductInProductList.id
),
...this.productSubject.value.filter((product) => product.id !== updatedProductInProductList.id),
updatedProductInProductList,
];
@@ -509,12 +409,8 @@ export class MockRemissionService extends RemissionService {
this.reloadProductsSubject.next();
}
createShippingDocument(params: {
remissionProcessId: number;
}): Observable<ShippingDocument> {
const processSubject = this.getRemissionFromStore(
params.remissionProcessId
);
createShippingDocument(params: { remissionProcessId: number }): Observable<ShippingDocument> {
const processSubject = this.getRemissionFromStore(params.remissionProcessId);
if (!processSubject) {
throw new Error('Prozess nicht gefunden');
@@ -526,10 +422,7 @@ export class MockRemissionService extends RemissionService {
id: createRandomId(),
shippingDocumentNumber: createRandomStringId(),
};
const updatedShippingDocuments = [
...process.shippingDocuments,
newShippingDocument,
];
const updatedShippingDocuments = [...process.shippingDocuments, newShippingDocument];
const updatedProcess = {
...process,
shippingDocuments: updatedShippingDocuments,
@@ -545,18 +438,14 @@ export class MockRemissionService extends RemissionService {
shippingDocumentId: number;
containerId: string;
}): Observable<ActionResult<boolean>> {
const processSubject = this.getRemissionFromStore(
params.remissionProcessId
);
const processSubject = this.getRemissionFromStore(params.remissionProcessId);
if (!processSubject) {
throw new Error('Prozess nicht gefunden');
}
const process = processSubject.value;
const shippingContainerToUpdate = process.shippingDocuments.find(
(document) => document.id === params.shippingDocumentId
);
const shippingContainerToUpdate = process.shippingDocuments.find((document) => document.id === params.shippingDocumentId);
const updatedShippingContainer = {
...shippingContainerToUpdate,
isCompleted: true,
@@ -564,9 +453,7 @@ export class MockRemissionService extends RemissionService {
const updatedProcess = {
...process,
shippingDocuments: [
...process.shippingDocuments.filter(
(document) => document.id !== params.shippingDocumentId
),
...process.shippingDocuments.filter((document) => document.id !== params.shippingDocumentId),
updatedShippingContainer,
],
};
@@ -579,9 +466,7 @@ export class MockRemissionService extends RemissionService {
}).pipe(delay(this.delayInMs));
}
completeRemissions(params: {
remissionProcessId: number;
}): Observable<boolean> {
completeRemissions(params: { remissionProcessId: number }): Observable<boolean> {
return;
}
@@ -605,9 +490,7 @@ export class MockRemissionService extends RemissionService {
return of(true);
}
deleteShippingDocument(): Observable<
ActionResult<{ deleted: boolean; completedRemissionsExist: boolean }>
> {
deleteShippingDocument(): Observable<ActionResult<{ deleted: boolean; completedRemissionsExist: boolean }>> {
return of({
result: {
deleted: true,
@@ -620,10 +503,7 @@ export class MockRemissionService extends RemissionService {
return;
}
getCapacities(params: {
selectedFilters?: { [filterId: string]: string[] };
supplierId: number;
}): Observable<CapacityType[]> {
getCapacities(params: { selectedFilters?: { [filterId: string]: string[] }; supplierId: number }): Observable<CapacityType[]> {
return of([]);
}
}

View File

@@ -4,8 +4,8 @@
}
.page-price-update-item__item-card {
@apply grid grid-flow-col;
grid-template-columns: 63px auto minmax(230px, auto);
@apply grid grid-flow-col gap-2;
grid-template-columns: 63px 1fr 14rem;
box-shadow: 0px 0px 10px rgba(220, 226, 233, 0.5);
}
@@ -20,5 +20,11 @@
.page-price-update-item__item-addition {
@apply grid grid-flow-row justify-items-end;
grid-template-rows: 27px 27px 41px 52px auto;
grid-template-rows: auto auto 2.56rem 3.25rem auto;
}
.page-price-update-item__item-product-group-details,
.page-price-update-item__item-title {
word-break: break-word;
overflow-wrap: break-word;
}

View File

@@ -58,11 +58,11 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
this.store.isDownloadAvailabilityAvailable$,
]).pipe(
map((values) => values.some((v) => v)),
shareReplay()
shareReplay(),
);
showDeliveryTruck$ = combineLatest([this.store.isDeliveryAvailabilityAvailable$, this.store.isDeliveryDigAvailabilityAvailable$]).pipe(
map(([delivery, digDelivery]) => delivery || digDelivery)
map(([delivery, digDelivery]) => delivery || digDelivery),
);
showDeliveryB2BTruck$ = combineLatest([
@@ -71,7 +71,7 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
]).pipe(map(([digDelivery, b2bDelivery]) => b2bDelivery && !digDelivery));
customerFeatures$ = this.applicationService.activatedProcessId$.pipe(
switchMap((processId) => this._domainCheckoutService.getCustomerFeatures({ processId }))
switchMap((processId) => this._domainCheckoutService.getCustomerFeatures({ processId })),
);
showSubscriptionBadge$ = this.store.item$.pipe(map((item) => item?.features?.find((i) => i.key === 'PFO')));
@@ -80,13 +80,13 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
promotionPoints$ = this.store.item$.pipe(map((item) => item?.redemptionPoints));
showPromotionBadge$ = combineLatest([this.hasPromotionFeature$, this.promotionPoints$]).pipe(
map(([hasPromotionFeature, promotionPoints]) => hasPromotionFeature && promotionPoints > 0)
map(([hasPromotionFeature, promotionPoints]) => hasPromotionFeature && promotionPoints > 0),
);
showArchivBadge$ = this.store.item$.pipe(map((item) => item?.features?.find((i) => i.key === 'ARC')));
isBadgeVisible$ = combineLatest([this.showSubscriptionBadge$, this.showPromotionBadge$, this.showArchivBadge$]).pipe(
map(([showSubscriptionBadge, showPromotionBadge, showArchivBadge]) => showSubscriptionBadge || showPromotionBadge || showArchivBadge)
map(([showSubscriptionBadge, showPromotionBadge, showArchivBadge]) => showSubscriptionBadge || showPromotionBadge || showArchivBadge),
);
contributors$ = this.store.item$.pipe(map((item) => item?.product?.contributors?.split(';').map((m) => m.trim())));
@@ -101,11 +101,11 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
}
return this._datePipe.transform(date, 'dd. MMMM y');
})
}),
);
selectedBranchId$ = this.applicationService.activatedProcessId$.pipe(
switchMap((processId) => this.applicationService.getSelectedBranch$(processId))
switchMap((processId) => this.applicationService.getSelectedBranch$(processId)),
);
get isTablet$() {
@@ -131,7 +131,7 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
return 'Sie sehen den Bestand einer anderen Filiale.';
}
return '';
})
}),
);
priceMaintained$ = combineLatest([
@@ -142,7 +142,7 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
]).pipe(
map((availabilities) => {
return availabilities?.some((availability) => (availability as any)?.priceMaintained) ?? false;
})
}),
);
price$ = combineLatest([
@@ -174,7 +174,7 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
}
return null;
})
}),
);
constructor(
@@ -193,7 +193,7 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
private _environment: EnvironmentService,
private _router: Router,
private _domainCheckoutService: DomainCheckoutService,
private _store: Store
private _store: Store,
) {}
ngOnInit() {
@@ -201,8 +201,8 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
.pipe(
debounceTime(0),
switchMap((params) =>
this.applicationService.getSelectedBranch$(Number(params.processId)).pipe(map((selectedBranch) => ({ params, selectedBranch })))
)
this.applicationService.getSelectedBranch$(Number(params.processId)).pipe(map((selectedBranch) => ({ params, selectedBranch }))),
),
)
.subscribe(({ params, selectedBranch }) => {
const processId = Number(params.processId);
@@ -221,13 +221,13 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
const id$ = this.activatedRoute.params.pipe(
tap((_) => (this.showRecommendations = false)),
map((params) => Number(params?.id) || undefined),
filter((f) => !!f)
filter((f) => !!f),
);
const ean$ = this.activatedRoute.params.pipe(
tap((_) => (this.showRecommendations = false)),
map((params) => params?.ean || undefined),
filter((f) => !!f)
filter((f) => !!f),
);
const more$ = this.activatedRoute.params.subscribe(() => (this.showMore = false));
@@ -241,9 +241,9 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
this.store.item$
.pipe(
withLatestFrom(this.isTablet$),
filter(([item, isTablet]) => !!item)
filter(([item, isTablet]) => !!item),
)
.subscribe(([item, isTablet]) => (isTablet ? this.updateBreadcrumb(item) : this.updateBreadcrumbDesktop(item)))
.subscribe(([item, isTablet]) => (isTablet ? this.updateBreadcrumb(item) : this.updateBreadcrumbDesktop(item))),
);
}
@@ -354,7 +354,7 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
if (result?.data) {
this.showPurchasingModal(result.data);
}
})
}),
);
}
@@ -425,7 +425,7 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
first(),
switchMap((customerFeatures) => {
return this._domainCheckoutService.canSetCustomer({ processId: this.applicationService.activatedProcessId, customerFeatures });
})
}),
)
.toPromise();
this._router.navigate(nav.path, {

View File

@@ -31,7 +31,7 @@ export class ArticleSearchComponent implements OnInit, OnDestroy {
private _breadcrumb: BreadcrumbService,
private _articleSearch: ArticleSearchService,
private _activatedRoute: ActivatedRoute,
private _navigationService: ProductCatalogNavigationService
private _navigationService: ProductCatalogNavigationService,
) {}
ngOnInit() {

View File

@@ -65,7 +65,7 @@ export class ArticleSearchFilterComponent implements OnInit, OnDestroy {
private _environment: EnvironmentService,
private _activatedRoute: ActivatedRoute,
public application: ApplicationService,
private _navigationService: ProductCatalogNavigationService
private _navigationService: ProductCatalogNavigationService,
) {}
ngOnInit() {

View File

@@ -11,7 +11,7 @@
[hint]="searchboxHint$ | async"
[loading]="fetching$ | async"
[inputGroup]="filter?.input | group: 'main'"
(search)="search({filter, clear: true})"
(search)="search({ filter, clear: true })"
[showDescription]="false"
[scanner]="true"
></shared-filter-input-group-main>
@@ -20,7 +20,7 @@
class="page-search-results__filter w-[6.75rem] h-14 rounded font-bold px-5 mb-4 text-lg bg-[#AEB7C1] flex flex-row flex-nowrap items-center justify-center"
[class.active]="hasFilter$ | async"
[routerLink]="filterRoute"
queryParamsHandling="preserve"
[queryParams]="filterQueryParams"
>
<shared-icon class="mr-2" icon="filter-variant"></shared-icon>
Filter
@@ -32,8 +32,7 @@
class="page-search-results__items-count inline-flex flex-row items-center pr-5 text-p3"
[class.mb-4]="primaryOutletActive$ | async"
>
{{ hits ??
0 }}
{{ hits ?? 0 }}
Titel
</div>
</div>

View File

@@ -59,7 +59,7 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy, AfterVi
selectedItems$ = combineLatest([this.results$, this.selectedItemIds$]).pipe(
map(([items, selectedItemIds]) => {
return items?.filter((item) => selectedItemIds?.find((selectedItemId) => item.id === selectedItemId));
})
}),
);
getProcessId(): number {
@@ -84,7 +84,7 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy, AfterVi
map(([filter, defaultFilter]) => {
const filterQueryParams = filter?.getQueryParams();
return !isEqual(this.resetQueryParamsQueryAndOrderBy(filterQueryParams), Filter.create(defaultFilter).getQueryParams());
})
}),
);
get filterRoute() {
@@ -95,6 +95,10 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy, AfterVi
}).path;
}
get filterQueryParams() {
return this.cleanupQueryParams(this.searchService?.filter?.getQueryParams());
}
get primaryOutletActive$() {
return this._environment.matchDesktop$.pipe(map((matches) => matches && this.route.outlet === 'primary'));
}
@@ -116,7 +120,7 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy, AfterVi
private _environment: EnvironmentService,
private _navigationService: ProductCatalogNavigationService,
private _availability: DomainAvailabilityService,
private _router: Router
private _router: Router,
) {}
ngOnInit() {
@@ -125,8 +129,8 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy, AfterVi
.pipe(
debounceTime(0),
switchMap(([processId, queryParams]) =>
this.application.getSelectedBranch$(processId).pipe(map((selectedBranch) => ({ processId, queryParams, selectedBranch })))
)
this.application.getSelectedBranch$(processId).pipe(map((selectedBranch) => ({ processId, queryParams, selectedBranch }))),
),
)
.subscribe(async ({ processId, queryParams, selectedBranch }) => {
const processChanged = processId !== this.searchService.processId;
@@ -138,7 +142,7 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy, AfterVi
this.cacheCurrentData(
this.searchService.processId,
this.searchService.filter.getQueryParams(),
this.searchService?.selectedBranch?.id
this.searchService?.selectedBranch?.id,
);
this.updateBreadcrumbs(this.searchService.processId, this.searchService.filter.getQueryParams());
}
@@ -190,7 +194,7 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy, AfterVi
if (this.route?.outlet === 'primary') {
await this.removeDetailsBreadcrumb(processId);
}
})
}),
);
this.subscriptions.add(
@@ -244,7 +248,7 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy, AfterVi
}
}
}
})
}),
);
// #4143 To make Splitscreen Search and Filter work combined
@@ -258,7 +262,7 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy, AfterVi
await this.searchService.setDefaultFilter(queryParams);
}
})
}),
);
}
@@ -337,7 +341,7 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy, AfterVi
async updateBreadcrumbs(
processId: number = this.searchService.processId,
queryParams: Record<string, string> = this.searchService.filter?.getQueryParams()
queryParams: Record<string, string> = this.searchService.filter?.getQueryParams(),
) {
const selected_item_ids = this.searchService?.selectedItemIds?.toString();
@@ -559,7 +563,7 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy, AfterVi
this.unselectAll();
}
this.loading$.next(false);
})
}),
);
}
}

View File

@@ -60,7 +60,7 @@ export class PageCatalogComponent implements OnInit, AfterViewInit, OnDestroy {
public auth: AuthService,
private _environmentService: EnvironmentService,
private _renderer: Renderer2,
private _actions: ActionsSubject
private _actions: ActionsSubject,
) {}
ngOnInit() {
@@ -76,7 +76,7 @@ export class PageCatalogComponent implements OnInit, AfterViewInit, OnDestroy {
return 'Bitte wählen Sie eine Filiale aus, um den Bestand einer anderen Filiale zu sehen';
}
return '';
})
}),
);
}

View File

@@ -52,17 +52,17 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
// Ticket #4228 Für die korrekte Gruppierung der Items bei gleichem Bestellziel (Aufsplitten von Abholung und Rücklage)
const ordersWithMultipleFeatures = filteredOrders.filter((order) =>
order.items.find((item) => item.features.orderType !== order.features.orderType)
order.items.find((item) => item.features.orderType !== order.features.orderType),
);
if (!!ordersWithMultipleFeatures) {
for (let orderWithMultipleFeatures of ordersWithMultipleFeatures) {
if (orderWithMultipleFeatures?.items?.length > 1) {
const itemsWithOrderFeature = orderWithMultipleFeatures.items.filter(
(item) => item.features.orderType === orderWithMultipleFeatures.features.orderType
(item) => item.features.orderType === orderWithMultipleFeatures.features.orderType,
);
const itemsWithDifferentOrderFeature = orderWithMultipleFeatures.items.filter(
(item) => item.features.orderType !== orderWithMultipleFeatures.features.orderType
(item) => item.features.orderType !== orderWithMultipleFeatures.features.orderType,
);
filteredOrders = [...filteredOrders.filter((order) => order.id !== orderWithMultipleFeatures.id)];
@@ -85,20 +85,20 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
};
});
}),
shareReplay()
shareReplay(),
);
hasAbholung$ = this.displayOrders$.pipe(
map((displayOrders) => displayOrders.filter((order) => order.features?.orderType === 'Abholung')?.length > 0)
map((displayOrders) => displayOrders.filter((order) => order.features?.orderType === 'Abholung')?.length > 0),
);
totalItemCount$ = this.displayOrders$.pipe(
map((displayOrders) =>
displayOrders.reduce(
(total, displayOrder) => total + displayOrder?.items?.reduce((subTotal, order) => subTotal + order?.quantity, 0),
0
)
)
0,
),
),
);
totalReadingPoints$ = this.displayOrders$.pipe(
@@ -122,7 +122,7 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
} else {
return NEVER;
}
})
}),
);
totalPrice$ = this.displayOrders$.pipe(
@@ -130,9 +130,9 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
displayOrders.reduce(
(total, displayOrder) =>
total + displayOrder?.items?.reduce((subTotal, order) => subTotal + order?.price?.value?.value * order.quantity, 0),
0
)
)
0,
),
),
);
isPrinting$ = new BehaviorSubject(false);
@@ -142,20 +142,20 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
containsDeliveryOrder$ = this.displayOrders$.pipe(
map(
(displayOrders) =>
displayOrders.filter((o) => ['Versand', 'B2B-Versand', 'DIG-Versand'].indexOf(o.features?.orderType) > -1)?.length > 0
)
displayOrders.filter((o) => ['Versand', 'B2B-Versand', 'DIG-Versand'].indexOf(o.features?.orderType) > -1)?.length > 0,
),
);
customer$ = this.displayOrders$.pipe(
switchMap((o) => this.customerService.getCustomers(o[0].buyerNumber, { take: 5 })),
map((customers) => customers.result[0]),
shareReplay()
shareReplay(),
);
isB2BCustomer$ = this.customer$.pipe(map((customer) => customer?.features?.find((f) => f.key === 'b2b') != null));
takeNowOrders$ = this.displayOrders$.pipe(
map((displayOrders) => displayOrders.filter((o) => o.items.find((oi) => oi.features?.orderType === 'Rücklage') != null))
map((displayOrders) => displayOrders.filter((o) => o.items.find((oi) => oi.features?.orderType === 'Rücklage') != null)),
);
get isDesktop$() {
@@ -184,7 +184,7 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
private _productNavigationService: ProductCatalogNavigationService,
private _shelfOutNavigationService: PickUpShelfOutNavigationService,
private _environmentService: EnvironmentService,
private _cdr: ChangeDetectorRef
private _cdr: ChangeDetectorRef,
) {
this.breadcrumb
.getBreadcrumbsByKeyAndTags$(this.applicationService.activatedProcessId, ['checkout'])
@@ -319,7 +319,7 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
first(),
map((printers) => {
if (Array.isArray(printers)) return printers.find((printer) => printer.selected === true);
})
}),
)
.toPromise();

View File

@@ -78,12 +78,12 @@ export class CustomerOrderDetailsItemComponent extends ComponentStore<CustomerOr
switchMap((oi) =>
this._omsService
.getCompletedTasks({ orderId: oi.orderId, orderItemId: oi.orderItemId, orderItemSubsetId: oi.orderItemSubsetId, take: 4, skip: 0 })
.pipe(catchError(() => NEVER))
)
.pipe(catchError(() => NEVER)),
),
);
canChangeQuantity$ = combineLatest([this.orderItem$, this._store.fetchPartial$]).pipe(
map(([item, partialPickup]) => ([16, 8192].includes(item?.processingStatus) || partialPickup) && item.quantity > 1)
map(([item, partialPickup]) => ([16, 8192].includes(item?.processingStatus) || partialPickup) && item.quantity > 1),
);
get quantity() {
@@ -109,7 +109,7 @@ export class CustomerOrderDetailsItemComponent extends ComponentStore<CustomerOr
}
readonly selected$ = combineLatest([this.orderItem$, this._store.selectedeOrderItemSubsetIds$]).pipe(
map(([orderItem, selectedItems]) => selectedItems.includes(orderItem?.orderItemSubsetId))
map(([orderItem, selectedItems]) => selectedItems.includes(orderItem?.orderItemSubsetId)),
);
@Output()
@@ -120,7 +120,7 @@ export class CustomerOrderDetailsItemComponent extends ComponentStore<CustomerOr
}
readonly selectable$ = combineLatest([this._store.items$, this._store.itemsSelectable$, this._store.fetchPartial$]).pipe(
map(([orderItems, selectable, fetchPartial]) => orderItems.length > 1 && selectable && fetchPartial)
map(([orderItems, selectable, fetchPartial]) => orderItems.length > 1 && selectable && fetchPartial),
);
get receipts() {
@@ -152,7 +152,7 @@ export class CustomerOrderDetailsItemComponent extends ComponentStore<CustomerOr
private _domainReceiptService: DomainReceiptService,
private _omsService: DomainOmsService,
private _cdr: ChangeDetectorRef,
private _environment: EnvironmentService
private _environment: EnvironmentService,
) {
super({
more: false,
@@ -194,11 +194,11 @@ export class CustomerOrderDetailsItemComponent extends ComponentStore<CustomerOr
done?.([]);
}
},
() => {}
)
)
)
)
() => {},
),
),
),
),
);
async saveSpecialComment() {
@@ -254,12 +254,15 @@ export class CustomerOrderDetailsItemComponent extends ComponentStore<CustomerOr
// Macht aus einem String Array ein Array von Objekten mit den keys trackingProvider und trackingNumber
private _trackingTransformationHelper(trackingInformationPairs: string[]): Array<{ trackingProvider: string; trackingNumber: string }> {
return trackingInformationPairs.reduce((acc, current, index, array) => {
if (index % 2 === 0) {
acc.push({ trackingProvider: current, trackingNumber: array[index + 1] });
}
return acc;
}, [] as { trackingProvider: string; trackingNumber: string }[]);
return trackingInformationPairs.reduce(
(acc, current, index, array) => {
if (index % 2 === 0) {
acc.push({ trackingProvider: current, trackingNumber: array[index + 1] });
}
return acc;
},
[] as { trackingProvider: string; trackingNumber: string }[],
);
}
getTrackingNumberLink(trackingNumber: string) {

View File

@@ -11,7 +11,7 @@
[order]="order$ | async"
[selected]="true"
(historyClick)="navigateToHistoryPage($event)"
(specialCommentChanged)="updateCustomerOrderResults()"
(specialCommentChanged)="onSpecialCommentChange()"
></page-customer-order-details-item>
<page-customer-order-details-tags *ngIf="showTagsComponent$ | async"></page-customer-order-details-tags>
</div>

View File

@@ -8,7 +8,7 @@ import {
OnInit,
QueryList,
} from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { ActivatedRoute, NavigationError, Router } from '@angular/router';
import { BreadcrumbService } from '@core/breadcrumb';
import { EnvironmentService } from '@core/environment';
import { OrderItemsContext } from '@domain/oms';
@@ -84,7 +84,7 @@ export class CustomerOrderDetailsComponent implements OnInit, AfterViewInit, OnD
const first = items?.find((_) => true);
const hasArrivedAction = first?.actions?.some((a) => a.command?.includes('ARRIVED'));
return hasArrivedAction && !fetching;
})
}),
);
actionsDisabled$ = combineLatest([
@@ -94,7 +94,7 @@ export class CustomerOrderDetailsComponent implements OnInit, AfterViewInit, OnD
]).pipe(map(([disabled, partial, orderItems]) => disabled || (partial && orderItems.length > 1)));
addToPreviousCompartmentActionDisabled$ = combineLatest([this.compartmentInfo$, this.changeActionDisabled$, this.fetching$]).pipe(
map(([compartmentInfo, changeActionDisabled, fetching]) => (!!compartmentInfo || changeActionDisabled) && fetching)
map(([compartmentInfo, changeActionDisabled, fetching]) => (!!compartmentInfo || changeActionDisabled) && fetching),
);
constructor(
@@ -105,7 +105,7 @@ export class CustomerOrderDetailsComponent implements OnInit, AfterViewInit, OnD
private _router: Router,
private _uiModal: UiModalService,
private _environment: EnvironmentService,
private _commandService: CommandService
private _commandService: CommandService,
) {}
ngOnInit() {
@@ -113,7 +113,7 @@ export class CustomerOrderDetailsComponent implements OnInit, AfterViewInit, OnD
this._activatedRoute.queryParams.subscribe((params) => {
const buyerNumber: string = decodeURIComponent(params.buyerNumber ?? '');
this._store.patchState({ buyerNumber });
})
}),
);
this.subscriptions.add(
@@ -136,7 +136,7 @@ export class CustomerOrderDetailsComponent implements OnInit, AfterViewInit, OnD
}
await this.removeDetailsCrumbs();
})
}),
);
this.subscriptions.add(
@@ -153,7 +153,7 @@ export class CustomerOrderDetailsComponent implements OnInit, AfterViewInit, OnD
this._store.patchState({ orderId });
this._store.loadOrder();
}
})
}),
);
this.removeBreadcrumbs();
@@ -172,7 +172,7 @@ export class CustomerOrderDetailsComponent implements OnInit, AfterViewInit, OnD
this.items$.subscribe((_) => {
this.customerOrderDetailsTags?.writeValue(this.compartmentInfo);
this.customerOrderDetailsTags?.registerOnChange((compartmentInfo) => (this._store.compartmentInfo = compartmentInfo));
})
}),
);
}
@@ -286,7 +286,7 @@ export class CustomerOrderDetailsComponent implements OnInit, AfterViewInit, OnD
getItemQuantityMap(): Map<number, number> {
return new Map(
this.customerOrderDetailsItemComponents.toArray().map((component) => [component.orderItem.orderItemSubsetId, component.quantity])
this.customerOrderDetailsItemComponents.toArray().map((component) => [component.orderItem.orderItemSubsetId, component.quantity]),
);
}
@@ -300,7 +300,7 @@ export class CustomerOrderDetailsComponent implements OnInit, AfterViewInit, OnD
async handleAction(
action: KeyValueDTOOfStringAndString,
{ compartmentCode, compartmentInfo }: { compartmentCode?: string; compartmentInfo?: string } = {}
{ compartmentCode, compartmentInfo }: { compartmentCode?: string; compartmentInfo?: string } = {},
) {
if (action.command.includes('FETCHED_PARTIAL')) {
this._store.patchState({ fetchPartial: true });
@@ -312,7 +312,7 @@ export class CustomerOrderDetailsComponent implements OnInit, AfterViewInit, OnD
(itemComponent) =>
new Promise<ReceiptDTO[]>((resolve) => {
itemComponent.loadReceipts((r) => resolve(r));
})
}),
);
receipts = await Promise.all(receiptsPromise).then((r) => r.reduce((acc, val) => acc.concat(val), []));
@@ -352,10 +352,14 @@ export class CustomerOrderDetailsComponent implements OnInit, AfterViewInit, OnD
await this.actionHandled({ orderItemsContext: commandData, command: action.command, navigation: navigateTo });
this._store.updateOrderItems(commandData.items);
} catch (error) {
this._uiModal.open({
content: UiErrorModalComponent,
data: error,
});
if (error instanceof NavigationError) {
await this.handleRouterMatchNoRoutesError(); // Refresh Result list but stay on same page
} else {
this._uiModal.open({
content: UiErrorModalComponent,
data: error,
});
}
console.error(error);
}
@@ -374,24 +378,36 @@ export class CustomerOrderDetailsComponent implements OnInit, AfterViewInit, OnD
if (handler.navigation === 'main') {
await this._navigationService.getCustomerOrdersBasePath(this.processId).navigate();
} else {
const item: OrderItemListItemDTO = handler.orderItemsContext.items.find((_) => true);
await this._router.navigate(this.getDetailsPath(item), {
queryParams: { ...this._activatedRoute.snapshot.queryParams, buyerNumber: item.buyerNumber },
});
await this.updateCustomerOrderResults();
const item: OrderItemListItemDTO = handler?.orderItemsContext?.items?.find((_) => true);
if (!!item) {
await this._router.navigate(this.getDetailsPath(item), {
queryParams: { ...this._activatedRoute.snapshot.queryParams, buyerNumber: item.buyerNumber },
});
}
if (this.isDesktop) {
await this.refreshResults();
}
await this.removeDetailsCrumbs();
this._store.loadItems();
}
}
async updateCustomerOrderResults() {
async handleRouterMatchNoRoutesError() {
await this.refreshResults();
}
async onSpecialCommentChange() {
if (this.isDesktop) {
await this._router.navigate([], {
queryParams: { ...this._activatedRoute.snapshot.queryParams, updateResults: true },
});
await this.refreshResults();
}
}
async refreshResults() {
await this._router.navigate([], {
queryParams: { ...this._activatedRoute.snapshot.queryParams, updateResults: true },
});
}
async arrivedActionNavigation(): Promise<'main'> {
const detailsCrumbs = await this._breadcrumb
.getBreadcrumbsByKeyAndTags$('customer-order', ['customer-order', 'details'])

View File

@@ -79,7 +79,7 @@ export class CustomerOrderSearchFilterComponent implements OnInit, OnDestroy {
private _environment: EnvironmentService,
private _activatedRoute: ActivatedRoute,
public application: ApplicationService,
private _navigationService: CustomerOrdersNavigationService
private _navigationService: CustomerOrdersNavigationService,
) {}
ngOnInit() {

View File

@@ -35,7 +35,7 @@ export class CustomerOrderSearchComponent implements OnInit, OnDestroy {
private _navigationService: CustomerOrdersNavigationService,
private _breadcrumb: BreadcrumbService,
private _activatedRoute: ActivatedRoute,
private _environment: EnvironmentService
private _environment: EnvironmentService,
) {}
ngOnInit() {

View File

@@ -127,7 +127,10 @@ export class CustomerOrderSearchStore extends ComponentStore<CustomerOrderSearch
cancelSearch$ = new Subject<void>();
constructor(private _domainGoodsInService: DomainCustomerOrderService, private _cache: CacheService) {
constructor(
private _domainGoodsInService: DomainCustomerOrderService,
private _cache: CacheService,
) {
super({
fetching: false,
silentFetching: false,
@@ -289,10 +292,10 @@ export class CustomerOrderSearchStore extends ComponentStore<CustomerOrderSearch
}
this.patchState({ fetching: false, silentFetching: false });
console.error('GoodsInSearchStore.search()', err);
}
)
},
),
);
})
)
}),
),
);
}

View File

@@ -42,8 +42,10 @@ export interface CustomerOrderSearchResultsState {
styleUrls: ['customer-order-search-results.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CustomerOrderSearchResultsComponent extends ComponentStore<CustomerOrderSearchResultsState>
implements OnInit, AfterViewInit, OnDestroy {
export class CustomerOrderSearchResultsComponent
extends ComponentStore<CustomerOrderSearchResultsState>
implements OnInit, AfterViewInit, OnDestroy
{
@ViewChildren(CustomerOrderItemComponent) listItems: QueryList<CustomerOrderItemComponent>;
@ViewChild(UiScrollContainerComponent) scrollContainer: UiScrollContainerComponent;
@@ -63,7 +65,7 @@ export class CustomerOrderSearchResultsComponent extends ComponentStore<Customer
listEmpty$ = combineLatest([this.loading$, this.hits$]).pipe(
map(([loading, hits]) => !loading && hits === 0),
shareReplay()
shareReplay(),
);
message$ = this._customerOrderSearchStore.message$;
@@ -76,9 +78,9 @@ export class CustomerOrderSearchResultsComponent extends ComponentStore<Customer
actions$ = combineLatest([this.items$, this.selectedOrderItemSubsetIds$]).pipe(
map(([items, selectedOrderItemSubsetIds]) =>
items?.find((item) => selectedOrderItemSubsetIds.find((orderItemSubsetId) => item.orderItemSubsetId === orderItemSubsetId))
items?.find((item) => selectedOrderItemSubsetIds.find((orderItemSubsetId) => item.orderItemSubsetId === orderItemSubsetId)),
),
map((item) => item?.actions?.filter((action) => this.selectionRules(action)))
map((item) => item?.actions?.filter((action) => this.selectionRules(action))),
);
get selectedItems() {
@@ -108,7 +110,7 @@ export class CustomerOrderSearchResultsComponent extends ComponentStore<Customer
filter$ = this._customerOrderSearchStore.filter$.pipe(filter((f) => !!f));
hasFilter$ = combineLatest([this.filter$, this._customerOrderSearchStore.defaultSettings$]).pipe(
map(([filter, defaultFilter]) => !isEqual(filter?.getQueryParams(), Filter.create(defaultFilter).getQueryParams()))
map(([filter, defaultFilter]) => !isEqual(filter?.getQueryParams(), Filter.create(defaultFilter).getQueryParams())),
);
get isTablet$() {
@@ -148,7 +150,7 @@ export class CustomerOrderSearchResultsComponent extends ComponentStore<Customer
private _navigationService: CustomerOrdersNavigationService,
private _application: ApplicationService,
private _cache: CacheService,
private _router: Router
private _router: Router,
) {
super({
selectedOrderItemSubsetIds: [],
@@ -166,7 +168,7 @@ export class CustomerOrderSearchResultsComponent extends ComponentStore<Customer
const clean = { ...queryParams };
delete clean['updateResults'];
}
})
}),
);
this._searchResultSubscription.add(
@@ -174,8 +176,8 @@ export class CustomerOrderSearchResultsComponent extends ComponentStore<Customer
.pipe(
debounceTime(150),
switchMap(([processId, params]) =>
this._application.getSelectedBranch$(processId).pipe(map((selectedBranch) => ({ processId, params, selectedBranch })))
)
this._application.getSelectedBranch$(processId).pipe(map((selectedBranch) => ({ processId, params, selectedBranch }))),
),
)
.subscribe(async ({ processId, params, selectedBranch }) => {
const branchChanged = selectedBranch?.id !== this._customerOrderSearchStore?.selectedBranch?.id;
@@ -243,7 +245,7 @@ export class CustomerOrderSearchResultsComponent extends ComponentStore<Customer
if (this._activatedRoute?.outlet === 'primary') {
await this.removeDetailsBreadcrumb(processId);
}
})
}),
);
this._searchResultSubscription.add(
@@ -261,12 +263,12 @@ export class CustomerOrderSearchResultsComponent extends ComponentStore<Customer
await this.navigateToDetails(
processId,
result?.results?.result?.find((_) => true),
queryParams
queryParams,
);
} else if ((!!result?.clear || this._activatedRoute.outlet === 'primary') && this.isDesktopLarge) {
await this._navigationService.getCustomerOrdersResultsPath(processId, { queryParams }).navigate();
}
})
}),
);
this._customerOrderSearchStore.searchResultClearedSubject.pipe(takeUntil(this._onDestroy$)).subscribe((_) => this.clearSelectedItems());
@@ -279,7 +281,7 @@ export class CustomerOrderSearchResultsComponent extends ComponentStore<Customer
main_qs: this.sharedFilterInputGroupMain?.uiInput?.value,
};
this._customerOrderSearchStore?.setQueryParams(queryParams);
})
}),
);
this._router.events.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((event) => {
@@ -302,7 +304,7 @@ export class CustomerOrderSearchResultsComponent extends ComponentStore<Customer
if (this._activatedRoute.outlet === 'primary') {
this._cache.set<number>(
{ processId: this._customerOrderSearchStore.processId, token: this.SCROLL_POSITION_TOKEN },
this.scrollContainer?.scrollPos
this.scrollContainer?.scrollPos,
);
}
}

View File

@@ -43,12 +43,12 @@ export class CustomerOrderComponent implements OnInit {
private _renderer: Renderer2,
private _environmentService: EnvironmentService,
public auth: AuthService,
private _store: CustomerOrderSearchStore
private _store: CustomerOrderSearchStore,
) {}
ngOnInit(): void {
this.selectedBranch$ = this.application.activatedProcessId$.pipe(
switchMap((processId) => this.application.getSelectedBranch$(Number(processId)))
switchMap((processId) => this.application.getSelectedBranch$(Number(processId))),
);
/* Ticket #4544 - Suchrequest abbrechen bei Prozesswechsel

View File

@@ -41,8 +41,10 @@ export interface CustomerTypeSelectorState {
},
],
})
export class CustomerTypeSelectorComponent extends ComponentStore<CustomerTypeSelectorState>
implements OnInit, OnDestroy, ControlValueAccessor {
export class CustomerTypeSelectorComponent
extends ComponentStore<CustomerTypeSelectorState>
implements OnInit, OnDestroy, ControlValueAccessor
{
@ViewChildren(UiCheckboxComponent)
checkboxes: QueryList<UiCheckboxComponent>;
@@ -133,7 +135,7 @@ export class CustomerTypeSelectorComponent extends ComponentStore<CustomerTypeSe
return result;
}),
shareReplay(1)
shareReplay(1),
);
}
@@ -144,7 +146,11 @@ export class CustomerTypeSelectorComponent extends ComponentStore<CustomerTypeSe
onChange = (value: string) => {};
onTouched = () => {};
constructor(private _checkoutService: DomainCheckoutService, private _cache: CacheService, private _cdr: ChangeDetectorRef) {
constructor(
private _checkoutService: DomainCheckoutService,
private _cache: CacheService,
private _cdr: ChangeDetectorRef,
) {
super({
processId: undefined,
customerType: undefined,
@@ -165,10 +171,10 @@ export class CustomerTypeSelectorComponent extends ComponentStore<CustomerTypeSe
this.patchState({ options });
this._cache.set('customerTypeOptions', options);
},
(err) => {}
)
)
)
(err) => {},
),
),
),
);
});

View File

@@ -76,7 +76,7 @@ export abstract class AbstractCreateCustomer implements OnInit, OnDestroy {
protected modal: UiModalService,
protected breadcrumb: BreadcrumbService,
protected cdr: ChangeDetectorRef,
protected customerSearchNavigation: CustomerSearchNavigation
protected customerSearchNavigation: CustomerSearchNavigation,
) {
this._initProcessId$();
}
@@ -88,7 +88,7 @@ export abstract class AbstractCreateCustomer implements OnInit, OnDestroy {
map((data) => +data.processId),
tap((processId) => (this.latestProcessId = processId)),
distinctUntilChanged(),
shareReplay(1)
shareReplay(1),
);
this.processId$
@@ -118,7 +118,7 @@ export abstract class AbstractCreateCustomer implements OnInit, OnDestroy {
const formData = await this.activatedRoute.queryParams
.pipe(
map((params) => params['formData']),
first()
first(),
)
.toPromise();
@@ -192,7 +192,7 @@ export abstract class AbstractCreateCustomer implements OnInit, OnDestroy {
minBirthDateValidator = (): ValidatorFn => {
return (control: AbstractControl): ValidationErrors | null => {
const minAge = 18; // 18 years
const minAge = 16; // 16 years
if (!control.value) {
return null;
@@ -202,8 +202,8 @@ export abstract class AbstractCreateCustomer implements OnInit, OnDestroy {
const minBirthDate = new Date();
minBirthDate.setFullYear(minBirthDate.getFullYear() - minAge);
// Check if customer is over 18 years old
if (this._checkIfAgeOver18(controlBirthDate, minBirthDate)) {
// Check if customer is over 16 years old
if (this._checkIfAgeOver16(controlBirthDate, minBirthDate)) {
return null;
} else {
return { minBirthDate: `Teilnahme ab ${minAge} Jahren` };
@@ -211,7 +211,7 @@ export abstract class AbstractCreateCustomer implements OnInit, OnDestroy {
};
};
private _checkIfAgeOver18(inputDate: Date, minBirthDate: Date): boolean {
private _checkIfAgeOver16(inputDate: Date, minBirthDate: Date): boolean {
// Check year
if (inputDate.getFullYear() < minBirthDate.getFullYear()) {
return true;
@@ -251,7 +251,7 @@ export abstract class AbstractCreateCustomer implements OnInit, OnDestroy {
return of({ invalid: 'E-Mail ist ungültig' });
}
}
})
}),
);
}),
tap((error) => {
@@ -260,7 +260,7 @@ export abstract class AbstractCreateCustomer implements OnInit, OnDestroy {
}
control.markAsTouched();
this.cdr.markForCheck();
})
}),
);
};
@@ -307,13 +307,13 @@ export abstract class AbstractCreateCustomer implements OnInit, OnDestroy {
return of({ invalid: 'Kundenkartencode ist ungültig' });
}
}
})
}),
);
}),
tap(() => {
control.markAsTouched();
this.cdr.markForCheck();
})
}),
);
};

View File

@@ -84,7 +84,7 @@ export class CreateP4MCustomerComponent extends AbstractCreateCustomer implement
return this.fetchCustomerInfo();
}
return of(null);
})
}),
);
this.existingCustomer$
@@ -94,12 +94,12 @@ export class CreateP4MCustomerComponent extends AbstractCreateCustomer implement
if (info) {
return this.customerService.getCustomer(info.id, 2).pipe(
map((res) => res.result),
catchError((err) => NEVER)
catchError((err) => NEVER),
);
}
return NEVER;
}),
withLatestFrom(this.processId$)
withLatestFrom(this.processId$),
)
.subscribe(([customer, processId]) => {
if (customer) {
@@ -166,7 +166,7 @@ export class CreateP4MCustomerComponent extends AbstractCreateCustomer implement
data: err,
});
return [null];
})
}),
);
}

View File

@@ -1,6 +1,6 @@
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy } from '@angular/core';
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy, inject, effect, untracked } from '@angular/core';
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
import { BehaviorSubject, Subject, Subscription } from 'rxjs';
import { BehaviorSubject, Subject, Subscription, fromEvent } from 'rxjs';
import { CustomerSearchStore } from './store/customer-search.store';
import { provideComponentStore } from '@ngrx/component-store';
import { Breadcrumb, BreadcrumbService } from '@core/breadcrumb';
@@ -8,6 +8,7 @@ import { delay, filter, first, switchMap, takeUntil } from 'rxjs/operators';
import { CustomerCreateNavigation, CustomerSearchNavigation } from '@shared/services';
import { CustomerSearchMainAutocompleteProvider } from './providers/customer-search-main-autocomplete.provider';
import { FilterAutocompleteProvider } from '@shared/components/filter';
import { toSignal } from '@angular/core/rxjs-interop';
@Component({
selector: 'page-customer-search',
@@ -24,6 +25,10 @@ import { FilterAutocompleteProvider } from '@shared/components/filter';
],
})
export class CustomerSearchComponent implements OnInit, OnDestroy {
private searchStore = inject(CustomerSearchStore);
keyEscPressed = toSignal(fromEvent(document, 'keydown').pipe(filter((e: KeyboardEvent) => e.key === 'Escape')));
get breadcrumb() {
let breadcrumb: string;
@@ -38,7 +43,7 @@ export class CustomerSearchComponent implements OnInit, OnDestroy {
private _breadcrumbs$ = this._store.processId$.pipe(
filter((id) => !!id),
switchMap((id) => this._breadcrumbService.getBreadcrumbsByKeyAndTag$(id, 'customer'))
switchMap((id) => this._breadcrumbService.getBreadcrumbsByKeyAndTag$(id, 'customer')),
);
side$ = new BehaviorSubject<string | undefined>(undefined);
@@ -73,7 +78,7 @@ export class CustomerSearchComponent implements OnInit, OnDestroy {
private _router: Router,
private _breadcrumbService: BreadcrumbService,
private _navigation: CustomerSearchNavigation,
private _createNavigation: CustomerCreateNavigation
private _createNavigation: CustomerCreateNavigation,
) {}
ngOnInit(): void {
@@ -542,4 +547,11 @@ export class CustomerSearchComponent implements OnInit, OnDestroy {
this._breadcrumbService.removeBreadcrumb(orderDetailsHistoryBreadcrumb.id);
}
}
cancelSearchEffect = effect(() => {
const event = this.keyEscPressed();
untracked(() => {
this.searchStore.cancelSearch();
});
});
}

View File

@@ -1,7 +1,7 @@
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy, Host } from '@angular/core';
import { CustomerSearchStore } from '../../store';
import { CrmCustomerService } from '@domain/crm';
import { map, switchMap, takeUntil } from 'rxjs/operators';
import { debounceTime, map, switchMap, takeUntil } from 'rxjs/operators';
import { Observable, Subject, combineLatest } from 'rxjs';
import { AssignedPayerDTO, CustomerDTO, ListResponseArgsOfAssignedPayerDTO } from '@swagger/crm';
import { AsyncPipe, NgFor, NgIf } from '@angular/common';
@@ -27,8 +27,10 @@ interface DetailsMainViewBillingAddressesComponentState {
standalone: true,
imports: [NgIf, NgFor, AsyncPipe, CustomerPipesModule, RouterLink],
})
export class DetailsMainViewBillingAddressesComponent extends ComponentStore<DetailsMainViewBillingAddressesComponentState>
implements OnInit, OnDestroy {
export class DetailsMainViewBillingAddressesComponent
extends ComponentStore<DetailsMainViewBillingAddressesComponentState>
implements OnInit, OnDestroy
{
assignedPayers$ = this.select((state) => state.assignedPayers);
selectedPayer$ = this.select((state) => state.selectedPayer);
@@ -36,7 +38,7 @@ export class DetailsMainViewBillingAddressesComponent extends ComponentStore<Det
isNotBusinessKonto$ = this._store.isBusinessKonto$.pipe(map((isBusinessKonto) => !isBusinessKonto));
showCustomerAddress$ = combineLatest([this._store.isBusinessKonto$, this._store.isMitarbeiter$, this._store.isKundenkarte$]).pipe(
map(([isBusinessKonto, isMitarbeiter, isKundenkarte]) => isBusinessKonto || isMitarbeiter || isKundenkarte)
map(([isBusinessKonto, isMitarbeiter, isKundenkarte]) => isBusinessKonto || isMitarbeiter || isKundenkarte),
);
get showCustomerAddress() {
@@ -47,12 +49,8 @@ export class DetailsMainViewBillingAddressesComponent extends ComponentStore<Det
this._store.isOnlinekonto$,
this._store.isOnlineKontoMitKundenkarte$,
this._store.isKundenkarte$,
this._store.isMitarbeiter$,
]).pipe(
map(
([isOnlinekonto, isOnlineKontoMitKundenkarte, isKundenkarte, isMitarbeiter]) =>
isOnlinekonto || isOnlineKontoMitKundenkarte || isKundenkarte || isMitarbeiter
)
map(([isOnlinekonto, isOnlineKontoMitKundenkarte, isKundenkarte]) => isOnlinekonto || isOnlineKontoMitKundenkarte || isKundenkarte),
);
canEditAddress$ = combineLatest([this._store.isKundenkarte$]).pipe(map(([isKundenkarte]) => isKundenkarte));
@@ -62,13 +60,13 @@ export class DetailsMainViewBillingAddressesComponent extends ComponentStore<Det
private _onDestroy$ = new Subject<void>();
editRoute$ = combineLatest([this._store.processId$, this._store.customerId$, this._store.isBusinessKonto$]).pipe(
map(([processId, customerId, isB2b]) => this._navigation.editRoute({ processId, customerId, isB2b }))
map(([processId, customerId, isB2b]) => this._navigation.editRoute({ processId, customerId, isB2b })),
);
addBillingAddressRoute$ = combineLatest([this.canAddNewAddress$, this._store.processId$, this._store.customerId$]).pipe(
map(([canAddNewAddress, processId, customerId]) =>
canAddNewAddress ? this._navigation.addBillingAddressRoute({ processId, customerId }) : undefined
)
canAddNewAddress ? this._navigation.addBillingAddressRoute({ processId, customerId }) : undefined,
),
);
constructor(
@@ -76,7 +74,7 @@ export class DetailsMainViewBillingAddressesComponent extends ComponentStore<Det
private _store: CustomerSearchStore,
private _customerService: CrmCustomerService,
private _modal: UiModalService,
private _navigation: CustomerSearchNavigation
private _navigation: CustomerSearchNavigation,
) {
super({
assignedPayers: [],
@@ -89,12 +87,15 @@ export class DetailsMainViewBillingAddressesComponent extends ComponentStore<Det
}
ngOnInit() {
this._store.customerId$.pipe(takeUntil(this._onDestroy$)).subscribe((customerId) => {
this.resetStore();
if (customerId) {
this.loadAssignedPayers(customerId);
}
});
combineLatest([this._store.customerId$, this._store.isMitarbeiter$])
.pipe(takeUntil(this._onDestroy$), debounceTime(250))
.subscribe(([customerId, isMitarbeiter]) => {
this.resetStore();
// #4715 Hier erfolgt ein Check auf Mitarbeiter, da Mitarbeiter keine zusätzlichen Rechnungsadressen haben sollen
if (customerId && !isMitarbeiter) {
this.loadAssignedPayers(customerId);
}
});
combineLatest([this.selectedPayer$, this._store.customer$])
.pipe(takeUntil(this._onDestroy$))
@@ -151,9 +152,9 @@ export class DetailsMainViewBillingAddressesComponent extends ComponentStore<Det
switchMap((customerId) =>
this._customerService
.getAssignedPayers({ customerId })
.pipe(tapResponse(this.handleLoadAssignedPayersResponse, this.handleLoadAssignedPayersError))
)
)
.pipe(tapResponse(this.handleLoadAssignedPayersResponse, this.handleLoadAssignedPayersError)),
),
),
);
handleLoadAssignedPayersResponse = (response: ListResponseArgsOfAssignedPayerDTO) => {

View File

@@ -34,7 +34,7 @@ export class CustomerDetailsViewMainComponent extends ComponentStore<CustomerDet
customerService = inject(CrmCustomerService);
fetching$ = combineLatest([this._store.fetchingCustomer$, this._store.fetchingCustomerList$]).pipe(
map(([fetchingCustomer, fetchingList]) => fetchingCustomer || fetchingList)
map(([fetchingCustomer, fetchingList]) => fetchingCustomer || fetchingList),
);
isBusy$ = this.select((s) => s.isBusy);
@@ -46,31 +46,31 @@ export class CustomerDetailsViewMainComponent extends ComponentStore<CustomerDet
customerId$ = this._store.customerId$;
historyRoute$ = combineLatest([this.processId$, this.customerId$]).pipe(
map(([processId, customerId]) => this._navigation.historyRoute({ processId, customerId }))
map(([processId, customerId]) => this._navigation.historyRoute({ processId, customerId })),
);
ordersRoute$ = combineLatest([this.processId$, this.customerId$]).pipe(
map(([processId, customerId]) => this._navigation.ordersRoute({ processId, customerId }))
map(([processId, customerId]) => this._navigation.ordersRoute({ processId, customerId })),
);
isB2b$ = this._store.isBusinessKonto$;
editRoute$ = combineLatest([this.processId$, this.customerId$, this.isB2b$]).pipe(
map(([processId, customerId, isB2b]) => this._navigation.editRoute({ processId, customerId, isB2b }))
map(([processId, customerId, isB2b]) => this._navigation.editRoute({ processId, customerId, isB2b })),
);
showEditButton$ = combineLatest([this._store.isOnlinekonto$, this._store.isBestellungOhneKonto$]).pipe(
map(([isOnlinekonto, isBestellungOhneKonto]) => !isOnlinekonto && !isBestellungOhneKonto)
map(([isOnlinekonto, isBestellungOhneKonto]) => !isOnlinekonto && !isBestellungOhneKonto),
);
hasKundenkarte$ = combineLatest([this._store.isKundenkarte$, this._store.isOnlineKontoMitKundenkarte$]).pipe(
map(([isKundenkarte, isOnlineKontoMitKundenkarte]) => isKundenkarte || isOnlineKontoMitKundenkarte)
map(([isKundenkarte, isOnlineKontoMitKundenkarte]) => isKundenkarte || isOnlineKontoMitKundenkarte),
);
kundenkarteRoute$ = combineLatest([this.hasKundenkarte$, this.processId$, this.customerId$]).pipe(
map(([hasKundenkarte, processId, customerId]) =>
hasKundenkarte ? this._navigation.kundenkarteRoute({ processId, customerId }) : undefined
)
hasKundenkarte ? this._navigation.kundenkarteRoute({ processId, customerId }) : undefined,
),
);
customerType$ = this._store.select((s) => s.customer?.features?.find((f) => f.enabled)?.description);
@@ -194,7 +194,7 @@ export class CustomerDetailsViewMainComponent extends ComponentStore<CustomerDet
private _checkoutNavigation: CheckoutNavigationService,
private _router: Router,
private _activatedRoute: ActivatedRoute,
private _genderSettings: GenderSettingsService
private _genderSettings: GenderSettingsService,
) {
super({ isBusy: false, shoppingCart: undefined, shippingAddress: undefined, payer: undefined });
}
@@ -221,8 +221,8 @@ export class CustomerDetailsViewMainComponent extends ComponentStore<CustomerDet
this._checkoutService.getShoppingCart({
processId: pid,
latest: true,
})
)
}),
),
)
.subscribe((shoppingCart) => {
this.patchState({ shoppingCart });

View File

@@ -4,6 +4,7 @@ import { CustomerSearchStore } from '../store';
import { Filter } from '@shared/components/filter';
import { CustomerSearchNavigation } from '@shared/services';
import { Router } from '@angular/router';
import { injectCancelSearch } from '../inject-cancel-search';
@Component({
selector: 'page-customer-filter-main-view',
@@ -13,6 +14,8 @@ import { Router } from '@angular/router';
host: { class: 'page-customer-filter-main-view' },
})
export class CustomerFilterMainViewComponent {
cancelSearch = injectCancelSearch();
fetchingFilterSettings$ = this._store.fetchingFilter$;
fetching$ = this._store.fetchingCustomerList$;
@@ -38,8 +41,10 @@ export class CustomerFilterMainViewComponent {
private _store: CustomerSearchStore,
private _location: Location,
private _router: Router,
private _customerSearchNavigation: CustomerSearchNavigation
) {}
private _customerSearchNavigation: CustomerSearchNavigation,
) {
this.cancelSearch();
}
search(filter: Filter) {
this._store.setFilter(filter);

View File

@@ -0,0 +1,10 @@
import { inject } from '@angular/core';
import { CustomerSearchStore } from './store';
export function injectCancelSearch() {
const store = inject(CustomerSearchStore);
return () => {
console.log('Cancel search');
store.cancelSearch();
};
}

View File

@@ -5,6 +5,7 @@
*ngIf="filter$ | async; let filter"
[inputGroup]="filter?.input | group: 'main'"
(search)="search(filter)"
(queryChange)="cancelSearch()"
[hint]="message$ | async"
[loading]="fetching$ | async"
[scanner]="true"

View File

@@ -8,6 +8,7 @@ import { isEmpty } from 'lodash';
import { Filter } from '@shared/components/filter';
import { CustomerResultListComponent } from '../../components/customer-result-list/customer-result-list.component';
import { EnvironmentService } from '@core/environment';
import { injectCancelSearch } from '../inject-cancel-search';
@Component({
selector: 'page-customer-results-main-view',
@@ -16,6 +17,8 @@ import { EnvironmentService } from '@core/environment';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CustomerResultsMainViewComponent implements OnInit, OnDestroy, AfterContentInit {
cancelSearch = injectCancelSearch();
processId$ = this._store.processId$;
currentUrl$ = new BehaviorSubject<string>(this._router.url);
@@ -38,7 +41,7 @@ export class CustomerResultsMainViewComponent implements OnInit, OnDestroy, Afte
}
return route;
})
}),
);
routerEventsSubscription: Subscription;
@@ -50,7 +53,7 @@ export class CustomerResultsMainViewComponent implements OnInit, OnDestroy, Afte
if (!filter) return false;
const qt = filter.getQueryToken();
return !isEmpty(qt.filter);
})
}),
);
fetching$ = this._store.fetchingCustomerList$;
@@ -73,7 +76,7 @@ export class CustomerResultsMainViewComponent implements OnInit, OnDestroy, Afte
private _store: CustomerSearchStore,
private _router: Router,
private _navigation: CustomerSearchNavigation,
private _environment: EnvironmentService
private _environment: EnvironmentService,
) {}
ngOnInit(): void {

View File

@@ -5,6 +5,7 @@
*ngIf="filter$ | async; let filter"
[inputGroup]="filter?.input | group: 'main'"
(search)="search(filter)"
(queryChange)="cancelSearch()"
[hint]="message$ | async"
[loading]="fetching$ | async"
[scanner]="true"
@@ -23,7 +24,7 @@
</a>
<button
class="btn btn-light h-14 font-bold"
(click)="closeFilter()"
(click)="closeFilter(); cancelSearch()"
[class.bg-active-branch]="hasFilter$ | async"
[class.text-white]="hasFilter$ | async"
*ngIf="isFilterRouteActive"

View File

@@ -8,6 +8,7 @@ import { CustomerResultListComponent } from '../../components/customer-result-li
import { isEmpty } from 'lodash';
import { CustomerSearchNavigation, NavigationRoute } from '@shared/services';
import { Location } from '@angular/common';
import { injectCancelSearch } from '../inject-cancel-search';
@Component({
selector: 'page-customer-results-side-view',
@@ -16,6 +17,8 @@ import { Location } from '@angular/common';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CustomerResultsSideViewComponent implements OnInit, OnDestroy {
cancelSearch = injectCancelSearch();
processId$ = this._store.processId$;
currentUrl$ = new BehaviorSubject<string>(this._router.url);
@@ -36,7 +39,7 @@ export class CustomerResultsSideViewComponent implements OnInit, OnDestroy {
}
return route;
})
}),
);
get isFilterRouteActive() {
@@ -57,7 +60,7 @@ export class CustomerResultsSideViewComponent implements OnInit, OnDestroy {
if (!filter) return false;
const qt = filter.getQueryToken();
return !isEmpty(qt.filter);
})
}),
);
message$ = this._store.message$;
@@ -76,7 +79,7 @@ export class CustomerResultsSideViewComponent implements OnInit, OnDestroy {
private _store: CustomerSearchStore,
private _router: Router,
private _navigation: CustomerSearchNavigation,
private _location: Location
private _location: Location,
) {}
ngOnInit(): void {

View File

@@ -163,7 +163,11 @@ export class CustomerSearchStore extends ComponentStore<CustomerSearchState> imp
selectedOrderItem$ = this.select(S.selectSelectedOrderItem);
constructor(private _customerService: CrmCustomerService, private _omsService: DomainOmsService, private _modal: UiModalService) {
constructor(
private _customerService: CrmCustomerService,
private _omsService: DomainOmsService,
private _modal: UiModalService,
) {
super({ customerListCount: 0 });
}
@@ -192,9 +196,9 @@ export class CustomerSearchStore extends ComponentStore<CustomerSearchState> imp
switchMap(({ customerId }) =>
this._customerService
.getCustomer(+customerId, 2)
.pipe(tapResponse(this.handleSelectCustomerResponse, this.handleSelectCustomerError, this.handleSelectCustomerComplete))
)
)
.pipe(tapResponse(this.handleSelectCustomerResponse, this.handleSelectCustomerError, this.handleSelectCustomerComplete)),
),
),
);
setFilter = this.updater((state, filter: Filter) => ({ ...state, queryParams: filter?.getQueryParams() ?? {} }));
@@ -221,9 +225,9 @@ export class CustomerSearchStore extends ComponentStore<CustomerSearchState> imp
switchMap((orderId) =>
this._omsService
.getOrder(orderId)
.pipe(tapResponse(this.handleSelectOrderResponse, this.handleSelectOrderError, this.handleSelectOrderComplete))
)
)
.pipe(tapResponse(this.handleSelectOrderResponse, this.handleSelectOrderError, this.handleSelectOrderComplete)),
),
),
);
handleSelectOrderResponse = (order: OrderDTO) => {
@@ -250,10 +254,14 @@ export class CustomerSearchStore extends ComponentStore<CustomerSearchState> imp
this._omsService
.getOrderItemsByCustomerNumber(customer.customerNumber, 0)
.pipe(
tapResponse(this.handleFetchCustomerOrdersResponse, this.handleFetchCustomerOrdersError, this.handleFetchCustomerOrdersComplete)
)
)
)
tapResponse(
this.handleFetchCustomerOrdersResponse,
this.handleFetchCustomerOrdersError,
this.handleFetchCustomerOrdersComplete,
),
),
),
),
);
handleFetchCustomerOrdersResponse = (orders: OrderListItemDTO[]) => {
@@ -275,9 +283,9 @@ export class CustomerSearchStore extends ComponentStore<CustomerSearchState> imp
switchMap(() =>
this._customerService
.filterSettings()
.pipe(tapResponse(this.handleFetchFilterResponse, this.handleFetchFilterError, this.handleFetchFilterComplete))
)
)
.pipe(tapResponse(this.handleFetchFilterResponse, this.handleFetchFilterError, this.handleFetchFilterComplete)),
),
),
);
handleFetchFilterResponse = (result: QuerySettingsDTO) => {
@@ -298,8 +306,8 @@ export class CustomerSearchStore extends ComponentStore<CustomerSearchState> imp
delayWhen(() =>
this.filter$.pipe(
filter((filter) => !!filter),
first()
)
first(),
),
),
withLatestFrom(this.filter$, this.processId$),
map(([a1, a2, a3]) => {
@@ -328,24 +336,23 @@ export class CustomerSearchStore extends ComponentStore<CustomerSearchState> imp
tapResponse(
this.handleSearchResponse(filter, processId, ignoreRestore ? false : restored, !!skipNavigation),
this.handleSearchError,
this.handleSearchComplete
)
)
)
)
this.handleSearchComplete,
),
),
),
),
);
handleSearchResponse = (filter: Filter, processId: number, restored: boolean, skipNavigation: boolean) => (
result: ListResponseArgsOfCustomerInfoDTO
) => {
this.patchState({
customerList: result.result,
customerListCount: result.hits,
message: result?.hits > 0 ? '' : 'Keine Suchergebnisse',
});
this._customerListResponse.next([result, filter, processId, restored, skipNavigation]);
this.cacheSearchResult();
};
handleSearchResponse =
(filter: Filter, processId: number, restored: boolean, skipNavigation: boolean) => (result: ListResponseArgsOfCustomerInfoDTO) => {
this.patchState({
customerList: result.result,
customerListCount: result.hits,
message: result?.hits > 0 ? '' : 'Keine Suchergebnisse',
});
this._customerListResponse.next([result, filter, processId, restored, skipNavigation]);
this.cacheSearchResult();
};
handleSearchError = (err: any) => {
this._modal.error('Fehler beim Laden der Liste', err);
@@ -364,7 +371,7 @@ export class CustomerSearchStore extends ComponentStore<CustomerSearchState> imp
withLatestFrom(this.filter$, this.processId$, this.customerList$, this.fetchingCustomerList$),
filter(
([_, __, ___, customerList, fetchingCustomerList]) =>
!fetchingCustomerList && customerList.length && customerList.length < this.customerListCount
!fetchingCustomerList && customerList.length && customerList.length < this.customerListCount,
),
delayWhen(() => this.fetchingCustomerList$.pipe(filter((fetching) => !fetching))),
tap(() => {
@@ -378,10 +385,10 @@ export class CustomerSearchStore extends ComponentStore<CustomerSearchState> imp
})
.pipe(
takeUntil(this._cancelSearch),
tapResponse(this.handlePaginateResponse, this.handlePaginateError, this.handlePaginateComplete)
)
)
)
tapResponse(this.handlePaginateResponse, this.handlePaginateError, this.handlePaginateComplete),
),
),
),
);
handlePaginateResponse = (result: ListResponseArgsOfCustomerInfoDTO) => {
@@ -429,7 +436,7 @@ export class CustomerSearchStore extends ComponentStore<CustomerSearchState> imp
JSON.stringify({
customerList,
customerListCount,
})
}),
);
}
@@ -458,7 +465,7 @@ export class CustomerSearchStore extends ComponentStore<CustomerSearchState> imp
`CUSTOMER_INFO_CACHE_${customerId}`,
JSON.stringify({
customer,
})
}),
);
}

View File

@@ -30,9 +30,7 @@
<span class="ssc-text" [class.err]="sscInvalid$ | async">{{ sscText$ | async }}</span>
</div>
<div class="err" *ngIf="supplierIdError$ | async">
Kein Lieferant vorhanden
</div>
<div class="err" *ngIf="supplierIdError$ | async">Kein Lieferant vorhanden</div>
</ng-container>
</div>
</div>
@@ -74,7 +72,7 @@
</div>
<div class="price">
<strong>{{ orderItem.price | currency: 'EUR':'code' }}</strong>
<strong>{{ orderItem.price | currency: 'EUR' : 'code' }}</strong>
</div>
<div class="status spec">
<span>Status</span>
@@ -99,8 +97,6 @@
</div>
<div class="footer">
<button class="cta-reorder" (click)="showReorderModal(); $event.stopPropagation()" [disabled]="editSsc$ | async">
Nachbestellen
</button>
<button class="cta-reorder" (click)="showReorderModal(); $event.stopPropagation()" [disabled]="editSsc$ | async">Nachbestellen</button>
</div>
</ng-container>

View File

@@ -111,7 +111,7 @@ export class GoodsInListItemComponent extends ComponentStore<GoodsInListItemComp
catchError(() => {
this.patchState({ supplierIdError: true });
return [undefined];
})
}),
);
readonly instruction$ = this.statusCodes$.pipe(
@@ -120,7 +120,7 @@ export class GoodsInListItemComponent extends ComponentStore<GoodsInListItemComp
const textObj = code?.texts?.find((text) => text?.textType === 'REWORK');
return textObj && textObj.text ? textObj.text : '';
}),
shareReplay()
shareReplay(),
);
private _onDestroy$ = new Subject<void>();
@@ -129,7 +129,7 @@ export class GoodsInListItemComponent extends ComponentStore<GoodsInListItemComp
private _omsService: DomainOmsService,
private _command: CommandService,
private _modal: UiModalService,
public environmentService: EnvironmentService
public environmentService: EnvironmentService,
) {
super({
item: undefined,

View File

@@ -50,7 +50,7 @@ export class GoodsInListComponent implements OnInit, AfterViewInit, OnDestroy {
listEmpty$ = combineLatest([this.loading$, this.hits$]).pipe(
map(([loading, hits]) => !loading && hits === 0),
shareReplay()
shareReplay(),
);
editSsc: boolean;
@@ -70,7 +70,7 @@ export class GoodsInListComponent implements OnInit, AfterViewInit, OnDestroy {
private _router: Router,
private _route: ActivatedRoute,
private readonly _config: Config,
private _cache: CacheService
private _cache: CacheService,
) {}
ngOnInit() {
@@ -155,7 +155,7 @@ export class GoodsInListComponent implements OnInit, AfterViewInit, OnDestroy {
private _addScrollPositionToCache(): void {
this._cache.set<number>(
{ processId: this._config.get('process.ids.goodsIn'), token: this.SCROLL_POSITION_TOKEN },
this.scrollContainer?.scrollPos
this.scrollContainer?.scrollPos,
);
}

View File

@@ -50,7 +50,7 @@ export class GoodsOutDetailsComponent extends ComponentStore<GoodsOutDetailsComp
order$ = this.orderId$.pipe(
filter((orderId) => !!orderId),
switchMap((orderId) => this._omsService.getOrder(orderId)),
shareReplay()
shareReplay(),
);
get processId() {
@@ -67,7 +67,7 @@ export class GoodsOutDetailsComponent extends ComponentStore<GoodsOutDetailsComp
private _omsService: DomainOmsService,
private _breadcrumb: BreadcrumbService,
private _router: Router,
private _uiModal: UiModalService
private _uiModal: UiModalService,
) {
super({
fetching: false,
@@ -166,11 +166,11 @@ export class GoodsOutDetailsComponent extends ComponentStore<GoodsOutDetailsComp
(err) => {},
() => {
this.patchState({ fetching: false });
}
)
},
),
);
})
)
}),
),
);
openModalIfItemsHaveDifferentCustomers(items: OrderItemListItemDTO[]) {

View File

@@ -46,7 +46,7 @@ export class GoodsOutSearchFilterComponent implements OnInit, OnDestroy {
private _goodsOutSearchStore: GoodsOutSearchStore,
private _breadcrumb: BreadcrumbService,
private _cdr: ChangeDetectorRef,
private _router: Router
private _router: Router,
) {}
ngOnInit() {

View File

@@ -33,7 +33,7 @@ export class GoodsOutSearchComponent implements OnInit, OnDestroy {
private _onDestroy$ = new Subject<void>();
hasFilter$ = combineLatest([this._goodsOutSearchStore.filter$, this._goodsOutSearchStore.defaultSettings$]).pipe(
map(([filter, defaultFilter]) => !isEqual(filter?.getQueryParams(), UiFilter.create(defaultFilter).getQueryParams()))
map(([filter, defaultFilter]) => !isEqual(filter?.getQueryParams(), UiFilter.create(defaultFilter).getQueryParams())),
);
processId$ = this._activatedRoute.data.pipe(map((data) => +data.processId));
@@ -41,7 +41,7 @@ export class GoodsOutSearchComponent implements OnInit, OnDestroy {
constructor(
private _goodsOutSearchStore: GoodsOutSearchStore,
private _breadcrumb: BreadcrumbService,
private _activatedRoute: ActivatedRoute
private _activatedRoute: ActivatedRoute,
) {}
ngOnInit() {

View File

@@ -36,7 +36,7 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
listEmpty$ = combineLatest([this.loading$, this.hits$]).pipe(
map(([loading, hits]) => !loading && hits === 0),
shareReplay()
shareReplay(),
);
selectedOrderItemSubsetIds$ = this.select((s) => s.selectedOrderItemSubsetIds);
@@ -47,9 +47,9 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
actions$ = combineLatest([this.items$, this.selectedOrderItemSubsetIds$]).pipe(
map(([items, selectedOrderItemSubsetIds]) =>
items?.find((item) => selectedOrderItemSubsetIds.find((orderItemSubsetId) => item.orderItemSubsetId === orderItemSubsetId))
items?.find((item) => selectedOrderItemSubsetIds.find((orderItemSubsetId) => item.orderItemSubsetId === orderItemSubsetId)),
),
map((item) => item?.actions?.filter((action) => this.selectionRules(action)))
map((item) => item?.actions?.filter((action) => this.selectionRules(action))),
);
get selectedItems() {
@@ -84,7 +84,7 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
private _activatedRoute: ActivatedRoute,
private _breadcrumb: BreadcrumbService,
private _commandService: CommandService,
private _modal: UiModalService
private _modal: UiModalService,
) {
super({
selectedOrderItemSubsetIds: [],
@@ -233,7 +233,7 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
this.removeScrollPosition(processId);
}
}
})
}),
);
this._searchResultSubscription.add(
@@ -244,7 +244,7 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
this.scrollContainer?.scrollTo(scrollPos);
this.removeScrollPosition(processId);
}
})
}),
);
}
@@ -273,7 +273,7 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
buyerNumber: orderItem.buyerNumber,
archive,
},
}
},
);
} else {
this._router.navigate([`/kunde/${processId}/goods/out/details/order/${encodeURIComponent(orderNumber)}/${processingStatus}`], {

View File

@@ -61,7 +61,7 @@ export class PickupShelfInDetailsComponent extends PickupShelfDetailsBaseCompone
fetchingCoverItems$ = this.store.fetchingCoverOrderItems$;
viewFetching$ = combineLatest([this.fetchingItems$, this.orderItems$]).pipe(
map(([fetchingItems, orderItems]) => fetchingItems && orderItems.length === 0)
map(([fetchingItems, orderItems]) => fetchingItems && orderItems.length === 0),
);
selectedCompartmentInfo = this.store.selectedCompartmentInfo;
@@ -93,14 +93,17 @@ export class PickupShelfInDetailsComponent extends PickupShelfDetailsBaseCompone
return `${latestCompartmentInfos?.latestCompartmentCode}_${latestCompartmentInfos?.latestCompartmentInfo}`;
}
return latestCompartmentInfos?.latestCompartmentCode;
})
}),
);
addToPreviousCompartmentActionDisabled$ = combineLatest([this.displayedCompartmentInfo$, this.changeActionDisabled$]).pipe(
map(([compartmentInfo, changeActionDisabled]) => !!compartmentInfo || changeActionDisabled)
map(([compartmentInfo, changeActionDisabled]) => !!compartmentInfo || changeActionDisabled),
);
constructor(private _uiModal: UiModalService, private _activatedRoute: ActivatedRoute) {
constructor(
private _uiModal: UiModalService,
private _activatedRoute: ActivatedRoute,
) {
super();
}
@@ -110,7 +113,7 @@ export class PickupShelfInDetailsComponent extends PickupShelfDetailsBaseCompone
.subscribe(([params, items]) => {
const orderItemSubsetId = +params?.orderItemSubsetId;
const selectedItem: DBHOrderItemListItemDTO = items?.find(
(item: DBHOrderItemListItemDTO) => item?.orderItemSubsetId === orderItemSubsetId
(item: DBHOrderItemListItemDTO) => item?.orderItemSubsetId === orderItemSubsetId,
);
// Trigger functions only if a new item gets selected
@@ -176,7 +179,7 @@ export class PickupShelfInDetailsComponent extends PickupShelfDetailsBaseCompone
},
side: false,
}).path,
{ queryParamsHandling: 'preserve' }
{ queryParamsHandling: 'preserve' },
);
this.listStore.patchOrderItem({
orderItemSubsetId: item.orderItemSubsetId,
@@ -224,17 +227,17 @@ export class PickupShelfInDetailsComponent extends PickupShelfDetailsBaseCompone
switch (type) {
case 'delivery':
this.store.selectedOrderItems.forEach((item) =>
this.store.patchOrderItemSubset({ item, changes: { estimatedShippingDate: date.toISOString() } })
this.store.patchOrderItemSubset({ item, changes: { estimatedShippingDate: date.toISOString() } }),
);
break;
case 'pickup':
this.store.selectedOrderItems.forEach((item) =>
this.store.patchOrderItemSubset({ item, changes: { compartmentStop: date.toISOString() } })
this.store.patchOrderItemSubset({ item, changes: { compartmentStop: date.toISOString() } }),
);
break;
case 'preferred':
this.store.selectedOrderItems.forEach((item) =>
this.store.patchOrderItemSubset({ item, changes: { preferredPickUpDate: date.toISOString() } })
this.store.patchOrderItemSubset({ item, changes: { preferredPickUpDate: date.toISOString() } }),
);
break;
default:
@@ -258,9 +261,9 @@ export class PickupShelfInDetailsComponent extends PickupShelfDetailsBaseCompone
orderItemSubsetId: orderItem.orderItemSubsetId,
compartmentInfo: orderItem.compartmentInfo,
},
{ side: this.side }
{ side: this.side },
).path,
{ queryParams: { buyerNumber: orderItem?.buyerNumber }, queryParamsHandling: 'merge' }
{ queryParams: { buyerNumber: orderItem?.buyerNumber }, queryParamsHandling: 'merge' },
);
}
@@ -275,9 +278,9 @@ export class PickupShelfInDetailsComponent extends PickupShelfDetailsBaseCompone
orderItemSubsetId: orderItem.orderItemSubsetId,
compartmentInfo: orderItem.compartmentInfo,
},
{ side: this.side }
{ side: this.side },
).path,
{ queryParams: { orderItemSubsetId: orderItem.orderItemSubsetId }, queryParamsHandling: 'merge' }
{ queryParams: { orderItemSubsetId: orderItem.orderItemSubsetId }, queryParamsHandling: 'merge' },
);
}
@@ -301,7 +304,7 @@ export class PickupShelfInDetailsComponent extends PickupShelfDetailsBaseCompone
},
side: this.side,
}).path,
{ queryParamsHandling: 'preserve' }
{ queryParamsHandling: 'preserve' },
);
} else {
if (orderItems.every((item) => item.processingStatus === 128)) {

View File

@@ -65,14 +65,14 @@ export class PickupShelfOutDetailsComponent extends PickupShelfDetailsBaseCompon
}
return groups;
})
}),
);
fetchingOrder$ = this.store.fetchingOrder$;
fetchingItems$ = this.store.fetchingOrderItems$;
viewFetching$ = combineLatest([this.orderItems$, this.fetchingItems$]).pipe(
map(([orderItems, fetchingItems]) => orderItems?.length === 0 && fetchingItems)
map(([orderItems, fetchingItems]) => orderItems?.length === 0 && fetchingItems),
);
selectedCompartmentInfo = this.store.selectedCompartmentInfo;
@@ -129,7 +129,7 @@ export class PickupShelfOutDetailsComponent extends PickupShelfDetailsBaseCompon
compartmentInfo: item.compartmentInfo,
},
}).path,
{ queryParamsHandling: 'preserve' }
{ queryParamsHandling: 'preserve' },
);
}
}
@@ -156,17 +156,17 @@ export class PickupShelfOutDetailsComponent extends PickupShelfDetailsBaseCompon
switch (type) {
case 'delivery': // vsl. Lieferdatum
this.store.orderItems.forEach((item) =>
this.store.patchOrderItemSubset({ item, changes: { estimatedShippingDate: date.toISOString() } })
this.store.patchOrderItemSubset({ item, changes: { estimatedShippingDate: date.toISOString() } }),
);
break;
case 'pickup': // Abholfrist
this.store.orderItems.forEach((item) =>
this.store.patchOrderItemSubset({ item, changes: { compartmentStop: date.toISOString() } })
this.store.patchOrderItemSubset({ item, changes: { compartmentStop: date.toISOString() } }),
);
break;
case 'preferred': // Zurücklegen bis
this.store.orderItems.forEach((item) =>
this.store.patchOrderItemSubset({ item, changes: { preferredPickUpDate: date.toISOString() } })
this.store.patchOrderItemSubset({ item, changes: { preferredPickUpDate: date.toISOString() } }),
);
break;
default:
@@ -191,7 +191,7 @@ export class PickupShelfOutDetailsComponent extends PickupShelfDetailsBaseCompon
compartmentInfo: orderItem.compartmentInfo,
},
}).path,
{ queryParams: { buyerNumber: orderItem?.buyerNumber }, queryParamsHandling: 'merge' }
{ queryParams: { buyerNumber: orderItem?.buyerNumber }, queryParamsHandling: 'merge' },
);
}
@@ -207,7 +207,7 @@ export class PickupShelfOutDetailsComponent extends PickupShelfDetailsBaseCompon
compartmentInfo: orderItem.compartmentInfo,
},
}).path,
{ queryParams: { orderItemSubsetId: orderItem.orderItemSubsetId }, queryParamsHandling: 'merge' }
{ queryParams: { orderItemSubsetId: orderItem.orderItemSubsetId }, queryParamsHandling: 'merge' },
);
}

View File

@@ -127,7 +127,7 @@ export class PickupShelfOutComponent extends PickupShelfBaseComponent {
processingStatus: item.processingStatus,
compartmentInfo: item.compartmentInfo,
},
})
}),
);
}
@@ -142,7 +142,7 @@ export class PickupShelfOutComponent extends PickupShelfBaseComponent {
processingStatus: item.processingStatus,
compartmentInfo: item.compartmentInfo,
},
})
}),
);
}
@@ -179,7 +179,7 @@ export class PickupShelfOutComponent extends PickupShelfBaseComponent {
processingStatus: item.processingStatus,
compartmentInfo: item.compartmentInfo,
},
})
}),
);
}

View File

@@ -20,6 +20,10 @@
</button>
</div>
<ng-template #featureLoading>
<shared-skeleton-loader class="w-64 h-6"></shared-skeleton-loader>
</ng-template>
<div class="page-pickup-shelf-details-header__details bg-white px-4 pt-4 pb-5">
<div class="flex flex-row items-center" [class.mb-8]="!orderItem?.features?.paid && !isKulturpass">
<page-pickup-shelf-details-header-nav-menu class="mr-2" [customer]="customer$ | async"></page-pickup-shelf-details-header-nav-menu>

View File

@@ -75,12 +75,12 @@ export class PickUpShelfDetailsHeaderComponent {
latestDate = new Date(
subsetItems?.reduce((a, b) => {
return new Date(a.data.preferredPickUpDate) > new Date(b.data.preferredPickUpDate) ? a : b;
})?.data?.preferredPickUpDate
})?.data?.preferredPickUpDate,
);
}
return latestDate;
})
}),
);
notificationsChannel$: Observable<NotificationChannel> = this.order$.pipe(map((order) => order?.notificationChannels ?? 0));
@@ -115,7 +115,7 @@ export class PickUpShelfDetailsHeaderComponent {
features$ = this.customer$.pipe(
map((customer) => customer?.features || []),
map((features) => features.filter((f) => f.enabled && !!f.description)),
shareReplay()
shareReplay(),
);
statusActions$ = this.orderItem$.pipe(map((orderItem) => orderItem?.actions?.filter((action) => action.enabled === false)));
@@ -123,14 +123,17 @@ export class PickUpShelfDetailsHeaderComponent {
crudaUpdate$ = this.orderItem$.pipe(map((orederItem) => !!(orederItem?.cruda & 4)));
editButtonDisabled$ = combineLatest([this.changeStatusLoader$, this.crudaUpdate$]).pipe(
map(([changeStatusLoader, crudaUpdate]) => changeStatusLoader || !crudaUpdate)
map(([changeStatusLoader, crudaUpdate]) => changeStatusLoader || !crudaUpdate),
);
canEditStatus$ = combineLatest([this.statusActions$, this.crudaUpdate$]).pipe(
map(([statusActions, crudaUpdate]) => statusActions?.length > 0 && crudaUpdate)
map(([statusActions, crudaUpdate]) => statusActions?.length > 0 && crudaUpdate),
);
constructor(private dateAdapter: DateAdapter, private cdr: ChangeDetectorRef) {}
constructor(
private dateAdapter: DateAdapter,
private cdr: ChangeDetectorRef,
) {}
async handleActionClick(action?: KeyValueDTOOfStringAndString) {
this.changeStatusLoader$.next(true);

View File

@@ -50,9 +50,7 @@
<div>{{ orderItem.product?.name }}</div>
</h3>
<div class="history-wrapper flex flex-col items-end justify-center">
<button class="cta-history text-p1" (click)="historyClick.emit(orderItem)">
Historie
</button>
<button class="cta-history text-p1" (click)="historyClick.emit(orderItem)">Historie</button>
<input
*ngIf="selectable$ | async"

View File

@@ -104,7 +104,7 @@ export class PickUpShelfDetailsItemComponent extends ComponentStore<PickUpShelfD
readonly orderItem$ = this.select((s) => s.orderItem);
emailNotificationDates$ = this.orderItem$.pipe(
switchMap((orderItem) => this._store.getEmailNotificationDate$(orderItem?.orderItemSubsetId))
switchMap((orderItem) => this._store.getEmailNotificationDate$(orderItem?.orderItemSubsetId)),
);
hasEmailNotification$ = this.emailNotificationDates$.pipe(map((dates) => dates?.length > 0));
@@ -114,7 +114,7 @@ export class PickUpShelfDetailsItemComponent extends ComponentStore<PickUpShelfD
hasSmsNotification$ = this.smsNotificationDates$.pipe(map((dates) => dates?.length > 0));
canChangeQuantity$ = combineLatest([this.orderItem$, this._store.fetchPartial$]).pipe(
map(([item, partialPickup]) => ([16, 8192].includes(item?.processingStatus) || partialPickup) && item.quantity > 1)
map(([item, partialPickup]) => ([16, 8192].includes(item?.processingStatus) || partialPickup) && item.quantity > 1),
);
get quantity() {
@@ -141,7 +141,7 @@ export class PickUpShelfDetailsItemComponent extends ComponentStore<PickUpShelfD
}
readonly selected$ = combineLatest([this.orderItem$, this._store.selectedOrderItemIds$]).pipe(
map(([orderItem, selectedItems]) => selectedItems.includes(orderItem?.orderItemSubsetId))
map(([orderItem, selectedItems]) => selectedItems.includes(orderItem?.orderItemSubsetId)),
);
@Output()
@@ -156,7 +156,7 @@ export class PickUpShelfDetailsItemComponent extends ComponentStore<PickUpShelfD
}
readonly selectable$ = combineLatest([this._store.orderItems$, this._store.fetchPartial$]).pipe(
map(([orderItems, fetchPartial]) => orderItems.length > 1 && this.isItemSelectable && fetchPartial)
map(([orderItems, fetchPartial]) => orderItems.length > 1 && this.isItemSelectable && fetchPartial),
);
get receipts() {

View File

@@ -80,13 +80,13 @@ export class PickUpShelfListItemComponent {
}
selected$ = this.store.selectedListItems$.pipe(
map((selectedListItems) => selectedListItems?.find((item) => item?.orderItemSubsetId === this.item?.orderItemSubsetId))
map((selectedListItems) => selectedListItems?.find((item) => item?.orderItemSubsetId === this.item?.orderItemSubsetId)),
);
constructor(
private _elRef: ElementRef,
private _environment: EnvironmentService,
private _processingStatusPipe: PickupShelfProcessingStatusPipe
private _processingStatusPipe: PickupShelfProcessingStatusPipe,
) {}
onDetailsClick() {
@@ -124,7 +124,7 @@ export class PickUpShelfListItemComponent {
store: 'PickupShelfDetailsStore',
},
[this.item],
{ persist: false, ttl: 1000 }
{ persist: false, ttl: 1000 },
);
}

View File

@@ -162,10 +162,13 @@ export const selectNotifications = (orderItemSubsetId: number) => (s: PickupShel
return tasks
.sort((a, b) => new Date(b.completed).getTime() - new Date(a.completed).getTime())
.reduce((data, result) => {
(data[result.name] = data[result.name] || []).push(new Date(result.completed));
return data;
}, {} as Record<string, Date[]>);
.reduce(
(data, result) => {
(data[result.name] = data[result.name] || []).push(new Date(result.completed));
return data;
},
{} as Record<string, Date[]>,
);
};
export const selectLatestNotificationDatesFor = (orderItemSubsetId: number, keys: string[]) => (s: PickupShelfDetailsState) => {

View File

@@ -333,9 +333,9 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
ids: [item.orderItemSubsetId],
eagerLoading: 1,
})
.pipe(tapResponse(this.fetchReceiptsDone, this.fetchReceiptsFailed))
)
)
.pipe(tapResponse(this.fetchReceiptsDone, this.fetchReceiptsFailed)),
),
),
);
private beforeFetchReceipts = () => {
@@ -357,9 +357,9 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
tap(({ orderId }) => this.beforeFetchOrder(orderId)),
// delay(10000),
switchMap(({ orderId }) =>
this._pickupShelfService.getOrderByOrderId(orderId).pipe(tapResponse(this.fetchOrderSuccess, this.fetchOrderFailed))
)
)
this._pickupShelfService.getOrderByOrderId(orderId).pipe(tapResponse(this.fetchOrderSuccess, this.fetchOrderFailed)),
),
),
);
private beforeFetchOrder = (orderId) => {
@@ -400,7 +400,7 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
orderItemSubsetId?: number;
orderDate?: string;
done?: { resolve: (items: DBHOrderItemListItemDTO[]) => void; reject: (err?) => void };
}>
}>,
) =>
trigger$.pipe(
tap((data) => this.beforeFetchOrderItems(data)),
@@ -409,11 +409,11 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
this._pickupShelfIOService.getOrderItemsByOrderNumberOrCompartmentCode({ compartmentCode, orderNumber, filter }).pipe(
tapResponse(
(r) => this.fetchOrderItemsSuccess({ compartmentCode, compartmentInfo, orderItemProcessingStatus }, done?.resolve)(r),
(e) => this.fetchOrderItemsFailed(done?.reject)(e)
)
)
)
)
(e) => this.fetchOrderItemsFailed(done?.reject)(e),
),
),
),
),
);
private beforeFetchOrderItems = ({
@@ -451,41 +451,43 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
});
};
private fetchOrderItemsSuccess = (
{
compartmentCode,
compartmentInfo,
orderItemProcessingStatus,
}: {
compartmentCode?: string;
compartmentInfo?: string;
orderItemProcessingStatus?: OrderItemProcessingStatusValue;
},
resolve?: (items: DBHOrderItemListItemDTO[]) => void
) => (res: ListResponseArgsOfDBHOrderItemListItemDTO) => {
// // Ticket #4348
// check if order items belong to the same customer
// if (buyerNumbers.length > 1) {
// this._modal.error('Fehler beim Laden der Bestellpositionen', new Error('Die Bestellpositionen gehören zu unterschiedlichen Kunden.'));
// return;
// }
this._cacheService.set<DBHOrderItemListItemDTO[]>(
private fetchOrderItemsSuccess =
(
{
name: 'orderItems',
orderId: this.order?.id,
compartmentCode,
compartmentInfo,
orderItemProcessingStatus,
store: 'PickupShelfDetailsStore',
}: {
compartmentCode?: string;
compartmentInfo?: string;
orderItemProcessingStatus?: OrderItemProcessingStatusValue;
},
res.result
);
resolve?: (items: DBHOrderItemListItemDTO[]) => void,
) =>
(res: ListResponseArgsOfDBHOrderItemListItemDTO) => {
// // Ticket #4348
// check if order items belong to the same customer
// if (buyerNumbers.length > 1) {
// this._modal.error('Fehler beim Laden der Bestellpositionen', new Error('Die Bestellpositionen gehören zu unterschiedlichen Kunden.'));
// return;
// }
this.patchState({ fetchingOrderItems: false, orderItems: res.result });
this._runCheckTrigger.next();
resolve?.(res.result);
};
this._cacheService.set<DBHOrderItemListItemDTO[]>(
{
name: 'orderItems',
orderId: this.order?.id,
compartmentCode,
compartmentInfo,
orderItemProcessingStatus,
store: 'PickupShelfDetailsStore',
},
res.result,
);
this.patchState({ fetchingOrderItems: false, orderItems: res.result });
this._runCheckTrigger.next();
resolve?.(res.result);
};
private fetchOrderItemsFailed = (reject?: (err?) => void) => (err: any) => {
this._modal.error('Fehler beim Laden der Bestellpositionen', err);
@@ -498,9 +500,9 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
filter(({ buyerNumber }) => this.customer?.customerNumber !== buyerNumber),
tap(() => this.beforeFetchCustomer()),
switchMap(({ buyerNumber }) =>
this._customerService.getCustomers(buyerNumber).pipe(tapResponse(this.fetchCustomerSuccess, this.fetchCustomerFailed))
)
)
this._customerService.getCustomers(buyerNumber).pipe(tapResponse(this.fetchCustomerSuccess, this.fetchCustomerFailed)),
),
),
);
beforeFetchCustomer = () => {
@@ -546,7 +548,7 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
store: 'PickupShelfDetailsStore',
},
customer,
{ persist: true, ttl: 3600000 }
{ persist: true, ttl: 3600000 },
);
this.patchState({ fetchingCustomer: false, customer });
@@ -564,11 +566,11 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
this._pickupShelfService.patchOrderItemSubset(data.item, data.changes).pipe(
tapResponse(
(res) => this.patchOrderItemSubsetDone(data.item)(res),
(err) => this.patchOrderItemSubsetError(err)
)
)
)
)
(err) => this.patchOrderItemSubsetError(err),
),
),
),
),
);
private patchOrderItemSubsetDone = (item: DBHOrderItemListItemDTO) => (res: ResponseArgsOfOrderItemSubsetDTO) => {
@@ -633,7 +635,7 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
return i;
}) ?? [],
};
}
},
);
fetchOrderItemSubsetTasks = this.effect((item$: Observable<DBHOrderItemListItemDTO>) =>
@@ -642,9 +644,9 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
mergeMap((item) =>
this._pickupShelfService
.getOrderItemSubsetTasks(item)
.pipe(tapResponse(this.fetchOrderItemSubsetTasksDone(item), this.fetchOrderItemSubsetTasksFailed(item)))
)
)
.pipe(tapResponse(this.fetchOrderItemSubsetTasksDone(item), this.fetchOrderItemSubsetTasksFailed(item))),
),
),
);
private beforeFetchOrderItemSubsetTasks = (item: DBHOrderItemListItemDTO) => {
@@ -703,8 +705,8 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
delayWhenCustomerNumberNotExists = delayWhen(() =>
this.customerNumber$.pipe(
filter((cn) => !!cn),
take(1)
)
take(1),
),
);
fetchCoverOrderItems = this.effect((trigger$: Observable<void>) =>
@@ -720,11 +722,11 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
.pipe(
tapResponse(
(res) => this.fetchCoverOrderItemsDone(res),
(err) => this.fetchCoverOrderItemsFailed(err)
)
)
)
)
(err) => this.fetchCoverOrderItemsFailed(err),
),
),
),
),
);
private beforeFetchCoverOrderItems = () => {

View File

@@ -96,7 +96,7 @@ export class PickupShelfStore extends ComponentStore<PickupShelfState> implement
searchboxHint$ = combineLatest([this.fetchingList$, this.fetchListResponse$]).pipe(
debounceTime(100),
map(([fetching, response]) => (response?.response?.hits === 0 && !fetching ? 'Keine Suchergebnisse' : ''))
map(([fetching, response]) => (response?.response?.hits === 0 && !fetching ? 'Keine Suchergebnisse' : '')),
);
readonly selectedListItems$ = this.select(Selectors.selectSelectedListItems);
@@ -174,9 +174,9 @@ export class PickupShelfStore extends ComponentStore<PickupShelfState> implement
map(() => this.beforeFetchQuerySettings()),
filter((shouldFetch) => shouldFetch),
switchMap(() =>
this._pickupShelfIOService.getQuerySettings().pipe(tapResponse(this.fetchQuerySettingsDone, this.fetchQuerySettingsError))
)
)
this._pickupShelfIOService.getQuerySettings().pipe(tapResponse(this.fetchQuerySettingsDone, this.fetchQuerySettingsError)),
),
),
);
/**
@@ -212,8 +212,8 @@ export class PickupShelfStore extends ComponentStore<PickupShelfState> implement
delayWhenFilterIsNotReady = delayWhen((value: { emitFetchListResponse: boolean } | void) =>
this.filter$.pipe(
filter((filter) => !!filter),
take(1)
)
take(1),
),
);
fetchList = this.effect((trigger$: Observable<{ emitFetchListResponse: boolean } | void>) =>
@@ -221,7 +221,7 @@ export class PickupShelfStore extends ComponentStore<PickupShelfState> implement
this.delayWhenFilterIsNotReady,
withLatestFrom(this.filter$, this.processId$),
map(([{ emitFetchListResponse } = { emitFetchListResponse: true }, filter, processId]) =>
this.beforeFetchList(emitFetchListResponse, filter, processId)
this.beforeFetchList(emitFetchListResponse, filter, processId),
),
switchMap(({ emitFetchListResponse, filter, processId, list }) =>
this._pickupShelfIOService
@@ -233,11 +233,11 @@ export class PickupShelfStore extends ComponentStore<PickupShelfState> implement
takeUntil(this._cancelListRequests),
tapResponse(
(res) => this.fetchListDone({ processId, queryParams: filter.getQueryParams(), emitFetchListResponse })(res),
(err) => this.fetchListError(err)
)
)
)
)
(err) => this.fetchListError(err),
),
),
),
),
);
private beforeFetchList = (emitFetchListResponse: boolean, filter: Filter, processId: number) => {
@@ -258,22 +258,26 @@ export class PickupShelfStore extends ComponentStore<PickupShelfState> implement
return { emitFetchListResponse, filter, processId, list };
};
private fetchListDone = ({
processId,
queryParams,
emitFetchListResponse,
}: {
processId: number;
queryParams: Record<string, string>;
emitFetchListResponse: boolean;
}) => (response: ListResponseArgsOfDBHOrderItemListItemDTO) => {
this.patchState({ fetchingList: false, list: response.result, listHits: response.hits });
if (emitFetchListResponse) {
this._fetchListResponse.next({ processId, response, queryParams });
}
private fetchListDone =
({
processId,
queryParams,
emitFetchListResponse,
}: {
processId: number;
queryParams: Record<string, string>;
emitFetchListResponse: boolean;
}) =>
(response: ListResponseArgsOfDBHOrderItemListItemDTO) => {
this.patchState({ fetchingList: false, list: response.result, listHits: response.hits });
if (emitFetchListResponse) {
this._fetchListResponse.next({ processId, response, queryParams });
}
this._cacheService.set<ListResponseArgsOfDBHOrderItemListItemDTO>({ processId, queryToken: queryParams }, response, { persist: true });
};
this._cacheService.set<ListResponseArgsOfDBHOrderItemListItemDTO>({ processId, queryToken: queryParams }, response, {
persist: true,
});
};
private fetchListError = (err: any) => {
this._modalService.error('Fehler beim Laden der Liste', err);
@@ -295,11 +299,11 @@ export class PickupShelfStore extends ComponentStore<PickupShelfState> implement
takeUntil(this._cancelListRequests),
tapResponse(
(r) => this.fetchMoreListDone(r),
(e) => this.fetchMoreListError(e)
)
(e) => this.fetchMoreListError(e),
),
);
})
)
}),
),
);
private beforeFetchMoreList = () => {
@@ -319,6 +323,6 @@ export class PickupShelfStore extends ComponentStore<PickupShelfState> implement
patchOrderItem = this.updater(
(state, { orderItemSubsetId, changes }: { orderItemSubsetId: number; changes: Partial<DBHOrderItemListItemDTO> }) => {
return { ...state, list: this.list.map((li) => (li.orderItemSubsetId === orderItemSubsetId ? { ...li, ...changes } : li)) };
}
},
);
}

View File

@@ -47,7 +47,7 @@ export class FinishShippingDocumentComponent implements OnInit, OnDestroy {
private _router: Router,
private _breadcrumb: BreadcrumbService,
private _config: Config,
private _remissionService: DomainRemissionService
private _remissionService: DomainRemissionService,
) {}
ngOnInit() {
@@ -89,15 +89,17 @@ export class FinishShippingDocumentComponent implements OnInit, OnDestroy {
modal.afterClosed$.pipe(takeUntil(this._onDestroy$)).subscribe(async (result) => {
if (result?.data === 'correct') {
await this.createReceiptAndAssignPackageNumber(query);
try {
await this.createReceiptAndAssignPackageNumber(query);
if (coerceBooleanProperty(this._activatedRoute.snapshot.queryParams?.complete)) {
this._router.navigate(['/filiale', 'remission', this.returnId, 'shipping-document'], {
queryParams: { complete: true },
});
} else {
await this.navigateToRemissionList(query);
}
if (coerceBooleanProperty(this._activatedRoute.snapshot.queryParams?.complete)) {
this._router.navigate(['/filiale', 'remission', this.returnId, 'shipping-document'], {
queryParams: { complete: true },
});
} else {
await this.navigateToRemissionList(query);
}
} catch (error) {}
} else if (result?.data === 'rescan') {
this.searchboxComponent.clear();
}
@@ -120,7 +122,11 @@ export class FinishShippingDocumentComponent implements OnInit, OnDestroy {
packageNumber,
});
} catch (error) {
this._modal.error('Fehler beim Speichern der Wannennummer', error);
this._modal.error('Fehler beim Speichern der Wannennummer', error).afterClosed$.subscribe(() => {
this._router.navigate(['/filiale', 'remission', this.returnId, 'finish-shipping-document', this.receiptId]);
});
throw error;
}
}

View File

@@ -45,7 +45,7 @@ export class AddProductModalComponent implements OnInit, OnDestroy {
private _remiService: DomainRemissionService,
private _modal: UiModalService,
private _config: Config,
private _cache: CacheService
private _cache: CacheService,
) {
this.item = this._modalRef.data.item;

View File

@@ -26,6 +26,8 @@ export class RemissionFilterComponent implements OnDestroy {
}
applyFilter(filter: UiFilter) {
console.log('filter', filter);
this.store.applyFilter(filter);
this.close.emit();
}

View File

@@ -44,7 +44,7 @@
{{ item.ean }}
</div>
<div class="font-bold price">
{{ item.price.value.value | currency: item.price.value.currency:'code' }}
{{ item.price.value.value | currency: item.price.value.currency : 'code' }}
</div>
<div *ngIf="item.assortment | assortment; let assortment">
<button [uiOverlayTrigger]="assortmentTooltip" data-name="assortment" class="text-active-branch font-bold">

View File

@@ -69,7 +69,7 @@ export class RemissionListItemComponent implements OnDestroy {
private _modal: UiModalService,
private _remissionService: DomainRemissionService,
private _store: RemissionListComponentStore,
@Host() private _listComponent: RemissionListComponent
@Host() private _listComponent: RemissionListComponent,
) {}
ngOnDestroy() {
@@ -178,7 +178,7 @@ export class RemissionListItemComponent implements OnDestroy {
const items = await this._store.items$.pipe(first()).toPromise();
const itemsByEan = items?.filter(
(i) => i.dto.product.ean === this.item.dto.product.ean && i.dto.id !== this.item.dto.id && i.placementType === 'Stapel'
(i) => i.dto.product.ean === this.item.dto.product.ean && i.dto.id !== this.item.dto.id && i.placementType === 'Stapel',
);
if (itemsByEan?.length > 0) {

View File

@@ -7,7 +7,7 @@ import { ComponentStore, tapResponse } from '@ngrx/component-store';
import { ReturnItemDTO, ReturnSuggestionDTO, SupplierDTO } from '@swagger/remi';
import { UiFilter } from '@ui/filter';
import { BehaviorSubject, combineLatest, Observable, Subject } from 'rxjs';
import { debounceTime, filter, switchMap, takeUntil, tap, withLatestFrom } from 'rxjs/operators';
import { debounceTime, distinctUntilChanged, filter, switchMap, takeUntil, tap, withLatestFrom } from 'rxjs/operators';
export interface RemissionState {
suppliers: SupplierDTO[];
@@ -57,11 +57,11 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
}
get selectedSupplier() {
return this.get((s) => s.suppliers?.find((si) => si.id === s.selectedSupplierId));
return this.get((s) => s.suppliers?.find((si) => si.id === s.selectedSupplierId) ?? s.suppliers[0]);
}
get selectedSupplier$() {
return this.select((s) => s.suppliers?.find((si) => si.id === s.selectedSupplierId));
return this.select((s) => s.suppliers?.find((si) => si.id === s.selectedSupplierId) ?? s.suppliers[0]);
}
get sources() {
@@ -137,7 +137,7 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
private readonly _config: Config,
private readonly _cache: CacheService,
private readonly _activatedRoute: ActivatedRoute,
private readonly _router: Router
private readonly _router: Router,
) {
super({
suppliers: [],
@@ -186,11 +186,11 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
this._domainRemissionService.getSuppliers().pipe(
tapResponse(
(suppliers) => this.setSuppliers(suppliers),
(err) => {}
)
)
)
)
(err) => {},
),
),
),
),
);
loadSources = this.effect(($) =>
@@ -200,11 +200,11 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
this._domainRemissionService.getSources().pipe(
tapResponse(
(sources) => this.setSources(sources),
(err) => {}
)
)
)
)
(err) => {},
),
),
),
),
);
loadRequiredCapacities = this.effect(($) =>
@@ -220,11 +220,11 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
return this._domainRemissionService.getRequiredCapacities({ supplierId: supplier?.id, departments }).pipe(
tapResponse(
(response) => this.setRequiredCapacities(response),
(err) => {}
)
(err) => {},
),
);
})
)
}),
),
);
loadFilter = this.effect((options$: Observable<{ loadDefault?: boolean }>) =>
@@ -259,11 +259,11 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
this._filterChange$.next(true);
}
},
(err) => {}
)
)
)
)
(err) => {},
),
),
),
),
);
search = this.effect((options$: Observable<{ newSearch?: boolean }>) =>
@@ -332,11 +332,11 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
this.setFetching(false);
this._searchCompleted.next(this.get());
},
(err) => {}
)
)
)
)
(err) => {},
),
),
),
),
);
setFetching = this.updater<boolean>((state, fetching) => ({
@@ -435,7 +435,7 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
{
items: this.items,
hits: this.hits,
}
},
);
}

View File

@@ -98,12 +98,12 @@ export class RemissionListComponent implements OnInit, OnDestroy {
}
return true;
})
}),
);
listEmpty$ = combineLatest([this.fetching$, this.hits$]).pipe(
map(([loading, hits]) => !loading && hits === 0),
shareReplay()
shareReplay(),
);
get queryParams$() {
@@ -115,7 +115,7 @@ export class RemissionListComponent implements OnInit, OnDestroy {
queryParams = { ...filter.getQueryParams(), ...params, supplier, source };
}
return queryParams;
})
}),
);
}
@@ -131,7 +131,7 @@ export class RemissionListComponent implements OnInit, OnDestroy {
return suppliers;
}
return suppliers.filter((supplier) => supplier?.id === selectedSupplier?.id);
})
}),
);
trackByItemId: TrackByFunction<RemissionListItem> = (_, item) => item.dto.id;
@@ -147,7 +147,7 @@ export class RemissionListComponent implements OnInit, OnDestroy {
private readonly _activatedRoute: ActivatedRoute,
private readonly _breadcrumb: BreadcrumbService,
private readonly _applicationService: ApplicationService,
private readonly _config: Config
private readonly _config: Config,
) {}
ngOnInit() {

View File

@@ -29,7 +29,7 @@ export class RemissionComponent implements OnInit, OnDestroy {
private _applicationService: ApplicationService,
private _router: Router,
private _cache: CacheService,
private _toastService: ToasterService
private _toastService: ToasterService,
) {}
ngOnInit(): void {
@@ -38,7 +38,7 @@ export class RemissionComponent implements OnInit, OnDestroy {
this._router.events
?.pipe(
filter((event) => event instanceof NavigationEnd),
takeUntil(this._onDestroy$)
takeUntil(this._onDestroy$),
)
.subscribe(() => {
this.updateProcess();

View File

@@ -96,13 +96,13 @@ export class TaskInfoComponent implements OnChanges {
teaser$ = this.info$.pipe(
filter((info) => !isNullOrUndefined(info)),
switchMap((info) => this.domainTaskCalendarService.getTeaserFile({ infoId: info.id }).pipe(catchError((error) => [undefined])))
switchMap((info) => this.domainTaskCalendarService.getTeaserFile({ infoId: info.id }).pipe(catchError((error) => [undefined]))),
);
attachments$ = this.info$.pipe(
filter((info) => info.attachments > 0),
switchMap((info) => this.domainTaskCalendarService.getFiles({ infoId: info.id })),
map((response) => response.result)
map((response) => response.result),
);
type$ = this.info$.pipe(map((info) => this.domainTaskCalendarService.getInfoType(info)));
@@ -119,19 +119,19 @@ export class TaskInfoComponent implements OnChanges {
res.result.map((comment) => ({
date: new Date(comment.created),
note: comment.text,
}))
)
})),
),
);
processingStatus$ = this.info$.pipe(
map((info) => this.domainTaskCalendarService.getProcessingStatusList(info)),
shareReplay()
shareReplay(),
);
showUpdateComment$ = combineLatest([this.info$, this.processingStatus$]).pipe(
map(
([info, processingStatus]) => !!info.updateComment && ((info.successor && processingStatus.includes('Removed')) || info.predecessor)
)
([info, processingStatus]) => !!info.updateComment && ((info.successor && processingStatus.includes('Removed')) || info.predecessor),
),
);
@HostBinding('class')
@@ -146,7 +146,7 @@ export class TaskInfoComponent implements OnChanges {
private uiModal: UiModalService,
private clipboard: Clipboard,
@Optional() private modalRef: UiModalRef,
private router: Router
private router: Router,
) {}
ngOnChanges({ info }: SimpleChanges): void {

View File

@@ -30,7 +30,7 @@ export class TaskSearchbarComponent implements OnInit, OnDestroy {
private _activatedRoute: ActivatedRoute,
private _cdr: ChangeDetectorRef,
private _breadcrumb: BreadcrumbService,
private _config: Config
private _config: Config,
) {}
getControlValueFromQuery() {

View File

@@ -29,7 +29,7 @@ export class TaskCalendarFilterComponent implements OnInit, OnDestroy {
private _router: Router,
private _activatedRoute: ActivatedRoute,
private _breadcrumb: BreadcrumbService,
private _config: Config
private _config: Config,
) {}
private _initFilter(filter: UiFilter) {

View File

@@ -32,13 +32,17 @@ export class PageTaskCalendarComponent implements OnInit, OnDestroy {
map(([_, filter, initialFilter]) => {
return !isEqual(filter?.getQueryParams(), initialFilter?.getQueryParams());
}),
shareReplay()
shareReplay(),
);
@ViewChild(TaskSearchbarComponent)
searchbar: TaskSearchbarComponent;
constructor(private taskCalendarStore: TaskCalendarStore, private _activatedRoute: ActivatedRoute, private readonly _config: Config) {
constructor(
private taskCalendarStore: TaskCalendarStore,
private _activatedRoute: ActivatedRoute,
private readonly _config: Config,
) {
this.taskCalendarStore.loadFilter();
}

View File

@@ -40,14 +40,14 @@ export class TaskSearchComponent implements OnInit, OnDestroy, AfterViewInit {
grouped.map((g) => ({
...g,
items: this.domainTaskCalendarService.sort(g.items, ['Overdue', 'InProcess', 'Approved', 'Completed', 'Removed']),
}))
})),
),
// Entfernte ans ende der Gruppe setzen
map((grouped) => grouped.map((g) => ({ ...g, items: g.items.sort((a, b) => this.domainTaskCalendarService.moveRemovedToEnd(a, b)) })))
map((grouped) => grouped.map((g) => ({ ...g, items: g.items.sort((a, b) => this.domainTaskCalendarService.moveRemovedToEnd(a, b)) }))),
);
showEmptyMessage$ = combineLatest([this.fetching$, this.searchResultsLength$, this.taskCalendarStore.hits$]).pipe(
map(([fetching, length, hits]) => !fetching && length <= 0 && hits === 0)
map(([fetching, length, hits]) => !fetching && length <= 0 && hits === 0),
);
previousBreadcrumb$: Observable<Breadcrumb> = this._breadcrumb.getBreadcrumbsByKeyAndTags$(this._taskCalendarKey, ['task-calendar']).pipe(
@@ -57,7 +57,7 @@ export class TaskSearchComponent implements OnInit, OnDestroy, AfterViewInit {
}
// Fallback wenn kein vorheriger Breadcrumb existiert
return { path: '/filiale/task-calendar/tasks', name: 'Aufgaben', section: 'branch', key: 'task-calendar' };
})
}),
);
constructor(
@@ -66,7 +66,7 @@ export class TaskSearchComponent implements OnInit, OnDestroy, AfterViewInit {
private domainTaskCalendarService: DomainTaskCalendarService,
private _activatedRoute: ActivatedRoute,
private _config: Config,
private _breadcrumb: BreadcrumbService
private _breadcrumb: BreadcrumbService,
) {}
ngOnInit() {

View File

@@ -118,7 +118,11 @@ export class BranchSelectorComponent implements OnInit, OnDestroy, AfterViewInit
@HostBinding('class.focused')
focused = false;
constructor(public store: BranchSelectorStore, private _auth: AuthService, private _elementRef: ElementRef) {}
constructor(
public store: BranchSelectorStore,
private _auth: AuthService,
private _elementRef: ElementRef,
) {}
writeValue(obj: any): void {
if (obj?.id) {
@@ -157,7 +161,7 @@ export class BranchSelectorComponent implements OnInit, OnDestroy, AfterViewInit
this.complete
.pipe(takeUntil(this._onDestroy$), withLatestFrom(this.store.branches$))
.subscribe(([query, branches]) =>
query?.length > 1 ? this.filterBranchesFn({ query, branches }) : this.store.setFilteredBranches(branches)
query?.length > 1 ? this.filterBranchesFn({ query, branches }) : this.store.setFilteredBranches(branches),
);
}

View File

@@ -79,7 +79,7 @@ export class FilterInputGroupMainComponent implements OnInit, OnDestroy, AfterVi
constructor(
@Inject(FilterAutocompleteProvider) @Optional() private autocompleteProviders: FilterAutocompleteProvider[],
private cdr: ChangeDetectorRef
private cdr: ChangeDetectorRef,
) {}
// cancle autocomplete
@@ -130,7 +130,7 @@ export class FilterInputGroupMainComponent implements OnInit, OnDestroy, AfterVi
} else {
this.autocompleteComponent?.close();
}
})
}),
);
}

View File

@@ -37,8 +37,10 @@ export interface SharedGoodsInOutOrderDetailsItemComponentState {
styleUrls: ['goods-in-out-order-details-item.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class SharedGoodsInOutOrderDetailsItemComponent extends ComponentStore<SharedGoodsInOutOrderDetailsItemComponentState>
implements OnInit, OnDestroy {
export class SharedGoodsInOutOrderDetailsItemComponent
extends ComponentStore<SharedGoodsInOutOrderDetailsItemComponentState>
implements OnInit, OnDestroy
{
@ViewChild('autosize') autosize: CdkTextareaAutosize;
@Input()
@@ -78,12 +80,12 @@ export class SharedGoodsInOutOrderDetailsItemComponent extends ComponentStore<Sh
switchMap((oi) =>
this._omsService
.getCompletedTasks({ orderId: oi.orderId, orderItemId: oi.orderItemId, orderItemSubsetId: oi.orderItemSubsetId, take: 4, skip: 0 })
.pipe(catchError(() => NEVER))
)
.pipe(catchError(() => NEVER)),
),
);
canChangeQuantity$ = combineLatest([this.orderItem$, this._host.fetchPartial$]).pipe(
map(([item, partialPickup]) => ([16, 8192].includes(item?.processingStatus) || partialPickup) && item.quantity > 1)
map(([item, partialPickup]) => ([16, 8192].includes(item?.processingStatus) || partialPickup) && item.quantity > 1),
);
get quantity() {
@@ -109,7 +111,7 @@ export class SharedGoodsInOutOrderDetailsItemComponent extends ComponentStore<Sh
}
readonly selected$ = combineLatest([this.orderItem$, this._host.selectedeOrderItemSubsetIds$]).pipe(
map(([orderItem, selectedItems]) => selectedItems.includes(orderItem?.orderItemSubsetId))
map(([orderItem, selectedItems]) => selectedItems.includes(orderItem?.orderItemSubsetId)),
);
@Output()
@@ -120,7 +122,7 @@ export class SharedGoodsInOutOrderDetailsItemComponent extends ComponentStore<Sh
}
readonly selectable$ = combineLatest([this._host.orderItems$, this._host.itemsSelectable$, this._host.fetchPartial$]).pipe(
map(([orderItems, selectable, fetchPartial]) => orderItems.length > 1 && selectable && fetchPartial)
map(([orderItems, selectable, fetchPartial]) => orderItems.length > 1 && selectable && fetchPartial),
);
get receipts() {
@@ -152,7 +154,7 @@ export class SharedGoodsInOutOrderDetailsItemComponent extends ComponentStore<Sh
private _omsService: DomainOmsService,
private _modal: UiModalService,
private _cdr: ChangeDetectorRef,
private _auth: AuthService
private _auth: AuthService,
) {
super({
more: false,
@@ -193,11 +195,11 @@ export class SharedGoodsInOutOrderDetailsItemComponent extends ComponentStore<Sh
done?.([]);
}
},
() => {}
)
)
)
)
() => {},
),
),
),
),
);
async saveSpecialComment() {

View File

@@ -29,6 +29,20 @@
<input uiInput formControlName="buyerNumber" />
</ui-form-control>
<ng-container *ngIf="showNameFields">
<ui-form-control label="Name" variant="inline" [statusLabel]="canEditNameFields ? '' : 'Nicht Änderbar'">
<input uiInput formControlName="firstName" />
</ui-form-control>
<ui-form-control label="Vorname" variant="inline" [statusLabel]="canEditNameFields ? '' : 'Nicht Änderbar'">
<input uiInput formControlName="lastName" />
</ui-form-control>
<ui-form-control *ngIf="isB2B" label="Firmenname" variant="inline" [statusLabel]="canEditNameFields ? '' : 'Nicht Änderbar'">
<input uiInput formControlName="organisation" />
</ui-form-control>
</ng-container>
<div formArrayName="items">
<div *ngFor="let item of itemsControl.controls; index as i" [formGroupName]="i">
<div class="item-header-wrapper">

View File

@@ -82,6 +82,20 @@ export class SharedGoodsInOutOrderEditComponent implements OnChanges, OnDestroy
return Array.from(ProcessingStatusNameMap.keys());
}
get showNameFields(): boolean {
// orderType 1 === Abholung / Rücklage
return this.items[0]?.orderType === 1; // Felder nur bei "Rücklage" oder "Abholung" anzeigen #4687
}
get canEditNameFields(): boolean {
return this.items[0]?.processingStatus === 16; // Felder nur im Status bestellt bearbeitbar #4687
}
// #4687 Ungenauer B2B-Check, da Customer Features nicht am OrderItemListItemDTO hängen
get isB2B(): boolean {
return !!this.items[0]?.organisation;
}
constructor(
private fb: UntypedFormBuilder,
private processingStatusPipe: ProcessingStatusPipe,
@@ -89,7 +103,7 @@ export class SharedGoodsInOutOrderEditComponent implements OnChanges, OnDestroy
private omsService: DomainOmsService,
private dateAdapter: DateAdapter,
private cdr: ChangeDetectorRef,
private _modal: UiModalService
private _modal: UiModalService,
) {}
ngOnDestroy(): void {
@@ -123,6 +137,9 @@ export class SharedGoodsInOutOrderEditComponent implements OnChanges, OnDestroy
orderDate: fb.control({ value: this.datePipe.transform(items[0].orderDate), disabled: true }),
clientChannel: fb.control({ value: (await this.getOrderSource()) ?? items[0].features?.orderSource, disabled: true }),
buyerNumber: fb.control({ value: items[0].buyerNumber, disabled: true }),
firstName: fb.control({ value: items[0].firstName, disabled: !this.canEditNameFields }),
lastName: fb.control({ value: items[0].lastName, disabled: !this.canEditNameFields }),
organisation: fb.control({ value: items[0].organisation, disabled: !this.canEditNameFields }),
items: fb.array([]),
notificationChannel: this.notificationsGroup,
});
@@ -169,7 +186,7 @@ export class SharedGoodsInOutOrderEditComponent implements OnChanges, OnDestroy
if (!value) {
fbItem.get('compartmentInfo').reset('');
}
})
}),
);
this.itemsControl.push(fbItem);
@@ -246,10 +263,10 @@ export class SharedGoodsInOutOrderEditComponent implements OnChanges, OnDestroy
notificationChannels.length === 2
? ['email', 'sms']
: notificationChannels[0] === 1
? ['email']
: notificationChannels[0] === 2
? ['sms']
: [],
? ['email']
: notificationChannels[0] === 2
? ['sms']
: [],
})
.pipe(first())
.toPromise();
@@ -270,6 +287,9 @@ export class SharedGoodsInOutOrderEditComponent implements OnChanges, OnDestroy
try {
const control = this.control.getRawValue();
const orderId = control.orderId;
const firstName = control.firstName;
const lastName = control.lastName;
const organisation = control.organisation;
if (this.notificationsGroup.dirty) {
try {
@@ -305,6 +325,19 @@ export class SharedGoodsInOutOrderEditComponent implements OnChanges, OnDestroy
throw error;
}
try {
if (this.firstOrLastNameOrOrganisationChanged()) {
await this.omsService.updateOrder({ orderId, firstName, lastName, organisation }).pipe(first()).toPromise();
}
} catch (error) {
this._modal.open({
content: UiErrorModalComponent,
data: error,
title: 'Fehler beim Aktualisieren der Bestellung - Vorname und Name konnten nicht übernommen werden',
});
throw error;
}
try {
if (this.isOrderItemDirty(formGroup)) {
await this.omsService
@@ -350,7 +383,7 @@ export class SharedGoodsInOutOrderEditComponent implements OnChanges, OnDestroy
},
})
.pipe(first())
.toPromise()
.toPromise(),
);
}
} catch (error) {
@@ -382,6 +415,10 @@ export class SharedGoodsInOutOrderEditComponent implements OnChanges, OnDestroy
}
}
firstOrLastNameOrOrganisationChanged() {
return this.control.get('firstName').dirty || this.control.get('lastName').dirty || this.control.get('organisation').dirty;
}
getFormGroupByOrderItemSubsetId(orderItemSubsetId: number): UntypedFormGroup {
const arr = this.control.get('items') as UntypedFormArray;
return arr.controls.find((c) => (c as UntypedFormGroup).controls.orderItemSubsetId.value === orderItemSubsetId) as UntypedFormGroup;

View File

@@ -92,7 +92,7 @@
</ng-template>
</div>
<div class="item-price">
{{ item.price | currency: 'EUR':'code' }}
{{ item.price | currency: 'EUR' : 'code' }}
</div>
<div class="label-value" *ngIf="showSupplier; else showBranch">

View File

@@ -135,7 +135,10 @@ export class PurchaseOptionsStore extends ComponentStore<PurchaseOptionsState> {
return this._service.getVats$();
}
constructor(private _service: PurchaseOptionsService, private _catalogService: DomainCatalogService) {
constructor(
private _service: PurchaseOptionsService,
private _catalogService: DomainCatalogService,
) {
super({
defaultBranch: undefined,
inStoreBranch: undefined,
@@ -184,6 +187,7 @@ export class PurchaseOptionsStore extends ComponentStore<PurchaseOptionsState> {
await this._loadAvailabilities();
await this._loadCanAdd();
this.selectSelectableItems();
}
// #region Private funtions for loading and setting Branches and Availabilities
@@ -407,7 +411,7 @@ export class PurchaseOptionsStore extends ComponentStore<PurchaseOptionsState> {
this.patchState({ availabilities });
} else {
let availabilities = this.availabilities.filter(
(a) => !(a.itemId === availability.itemId && a.purchaseOption === availability.purchaseOption)
(a) => !(a.itemId === availability.itemId && a.purchaseOption === availability.purchaseOption),
);
this.patchState({ availabilities });
}
@@ -440,7 +444,7 @@ export class PurchaseOptionsStore extends ComponentStore<PurchaseOptionsState> {
availability: inStoreAvailability.data,
quantity: item.quantity ?? 1,
type: this.type,
})
}),
);
}
@@ -456,7 +460,7 @@ export class PurchaseOptionsStore extends ComponentStore<PurchaseOptionsState> {
availability: deliveryAvailability.data,
quantity: item.quantity ?? 1,
type: this.type,
})
}),
);
}
@@ -469,7 +473,7 @@ export class PurchaseOptionsStore extends ComponentStore<PurchaseOptionsState> {
availability: pickupAvailability.data,
quantity: item.quantity ?? 1,
type: this.type,
})
}),
);
}
@@ -482,7 +486,7 @@ export class PurchaseOptionsStore extends ComponentStore<PurchaseOptionsState> {
availability: downloadAvailability.data,
quantity: item.quantity ?? 1,
type: this.type,
})
}),
);
}
});

View File

@@ -40,7 +40,7 @@ export class CustomerSearchNavigation {
];
const queryParams: Record<string, string> = {};
console.log(params.customer);
if (params.customer) {
queryParams.main_qs = params.customer?.customerNumber;
queryParams.filter_customertype = '';

View File

@@ -67,7 +67,7 @@ export class SearchComponentStoreService<T = any> extends ComponentStore<SearchS
@Inject(SEARCH_STATE_SETTINGS_LOADER) private readonly _settingsLoader: SearchStateSettingsLoader,
@Inject(SEARCH_STATE_SEARCH_SERVICE) private readonly _searchService: SearchStateSearchService<T>,
private readonly _cache: CacheService,
private readonly _uiModal: UiModalService
private readonly _uiModal: UiModalService,
) {
super({
items: [],
@@ -77,7 +77,7 @@ export class SearchComponentStoreService<T = any> extends ComponentStore<SearchS
this.filter$
.pipe(
takeUntil(this._onDestroy$),
filter((filter) => !!filter)
filter((filter) => !!filter),
)
.subscribe((filter) => {
const cachedResult = this._cache.get(filter?.getQueryParams());
@@ -190,14 +190,14 @@ export class SearchComponentStoreService<T = any> extends ComponentStore<SearchS
this.cacheResults(filter, { items: [...items, ...res.items], hits: res.hits });
this.patchState({ latestResponse: res.response });
},
(err) => this.handleSearchError(err)
(err) => this.handleSearchError(err),
),
finalize(() => {
this.searchCompleted.next(this.state);
})
}),
);
})
)
}),
),
);
searchRequest(filter: UiFilter, items: T[]): Observable<SearchStateSearchResult<T>> {

View File

@@ -12,7 +12,7 @@ variables:
value: '3'
# Minor Version einstellen
- name: 'Minor'
value: '0'
value: '3'
- name: 'Patch'
value: "$[counter(format('{0}.{1}', variables['Major'], variables['Minor']),0)]"
- name: 'BuildUniqueID'

34
package-lock.json generated
View File

@@ -20,6 +20,8 @@
"@angular/router": "^17.3.10",
"@angular/service-worker": "^17.3.10",
"@microsoft/signalr": "^7.0.0",
"@ng-icons/core": "^27.5.2",
"@ng-icons/material-icons": "^29.5.0",
"@ngrx/component-store": "^17.2.0",
"@ngrx/effects": "^17.2.0",
"@ngrx/entity": "^17.2.0",
@@ -3403,6 +3405,22 @@
"ws": "^7.4.5"
}
},
"node_modules/@ng-icons/core": {
"version": "27.5.2",
"resolved": "https://registry.npmjs.org/@ng-icons/core/-/core-27.5.2.tgz",
"integrity": "sha512-LDfhrfxJ5yM8NkpSlz9ix+RRuecFHZYjfCgXH0dVDuk5gx+40Dxi/v9vL8oRpUP4oL9spR7Ndry2ENVZY/h4Tw==",
"dependencies": {
"tslib": "^2.2.0"
}
},
"node_modules/@ng-icons/material-icons": {
"version": "29.5.0",
"resolved": "https://registry.npmjs.org/@ng-icons/material-icons/-/material-icons-29.5.0.tgz",
"integrity": "sha512-iPkyDJ/fy9i4m4DUp2krHjMiG9XOiYozonHKJg5O/RlzjsQE4+aTyp+Imm8VAXDC35KgTO0aeeo6rltiGypWqg==",
"dependencies": {
"tslib": "^2.2.0"
}
},
"node_modules/@ngneat/spectator": {
"version": "15.0.1",
"resolved": "https://registry.npmjs.org/@ngneat/spectator/-/spectator-15.0.1.tgz",
@@ -18342,6 +18360,22 @@
"ws": "^7.4.5"
}
},
"@ng-icons/core": {
"version": "27.5.2",
"resolved": "https://registry.npmjs.org/@ng-icons/core/-/core-27.5.2.tgz",
"integrity": "sha512-LDfhrfxJ5yM8NkpSlz9ix+RRuecFHZYjfCgXH0dVDuk5gx+40Dxi/v9vL8oRpUP4oL9spR7Ndry2ENVZY/h4Tw==",
"requires": {
"tslib": "^2.2.0"
}
},
"@ng-icons/material-icons": {
"version": "29.5.0",
"resolved": "https://registry.npmjs.org/@ng-icons/material-icons/-/material-icons-29.5.0.tgz",
"integrity": "sha512-iPkyDJ/fy9i4m4DUp2krHjMiG9XOiYozonHKJg5O/RlzjsQE4+aTyp+Imm8VAXDC35KgTO0aeeo6rltiGypWqg==",
"requires": {
"tslib": "^2.2.0"
}
},
"@ngneat/spectator": {
"version": "15.0.1",
"resolved": "https://registry.npmjs.org/@ngneat/spectator/-/spectator-15.0.1.tgz",

View File

@@ -71,6 +71,8 @@
"@angular/router": "^17.3.10",
"@angular/service-worker": "^17.3.10",
"@microsoft/signalr": "^7.0.0",
"@ng-icons/core": "^27.5.2",
"@ng-icons/material-icons": "^29.5.0",
"@ngrx/component-store": "^17.2.0",
"@ngrx/effects": "^17.2.0",
"@ngrx/entity": "^17.2.0",