Compare commits

...

21 Commits

Author SHA1 Message Date
Nino
16b047f2da #4534 Goods In Out Order Edit Always Show Price with Two Decimal Places 2024-01-04 10:25:53 +01:00
Nino Righi
6feb8079b7 Merged PR 1714: #4550 Fix Multiple Processes Bug
#4550 Fix Multiple Processes Bug
2024-01-04 08:23:31 +00:00
Nino
7f8f48f393 Updated tsconfig 2024-01-03 11:54:03 +01:00
Nino
0fe0c5242d Merge branch 'release/3.0' into develop 2024-01-03 11:52:25 +01:00
Nino
d208bdaf97 Added Package Inspection Class Name in Details Page for Page Objects Targetting 2024-01-02 15:08:19 +01:00
Nino Righi
dc80df4ad4 Merged PR 1712: #4524 Page Article Search Improved Order by Filter Handling
#4524 Page Article Search Improved Order by Filter Handling
2023-12-29 16:12:53 +00:00
Nino Righi
3020609682 Merged PR 1711: #4545 #4548 Fix HSC Breadcrumb and Multiple Processes bug
#4545 #4548 Fix HSC Breadcrumb and Multiple Processes bug
2023-12-29 15:22:26 +00:00
Nino Righi
5c3e1ed2ad Merged PR 1710: #4544 Fix Proveded Store correctly, removed take from filter and cancleSearch...
#4544 Fix Proveded Store correctly, removed take from filter and cancleSearchRequests on process change
2023-12-29 15:12:51 +00:00
Nino Righi
e832feebc5 Merged PR 1709: #4545 Fix Missing Main Breadcrumb
#4545 Fix Missing Main Breadcrumb
2023-12-28 15:10:44 +00:00
Nino Righi
08580d782d Merged PR 1708: #4546 HSC Customer Orders Fixed Navigation Link Active Styling
#4546 HSC Customer Orders Fixed Navigation Link Active Styling
2023-12-28 15:01:40 +00:00
Nino Righi
2d07556341 Merged PR 1707: #4533 Fixed Breadcrumb and Searchbox after Scan
#4533 Fixed Breadcrumb and Searchbox after Scan
2023-12-28 12:23:48 +00:00
Nino Righi
9ad1256019 Merged PR 1706: #4543 Styling Fix Checkout Review for multiple Destinations per OrderType
#4543 Styling Fix Checkout Review for multiple Destinations per OrderType
2023-12-27 16:00:23 +00:00
Nino Righi
250002f057 Merged PR 1705: #4516 Fix Also Show Details Items Group in Pick Up Shelf In
#4516 Fix Also Show Details Items Group in Pick Up Shelf In
2023-12-27 15:59:11 +00:00
Nino Righi
0973b01bf0 Merged PR 1704: #4539 Fix Skip Location Change Filter
#4539 Fix Skip Location Change Filter
2023-12-27 14:39:15 +00:00
Nino Righi
d5254cc150 Merged PR 1703: #4541 Added Errorhandling to Customer Search Store
#4541 Added Errorhandling to Customer Search Store
2023-12-27 08:09:29 +00:00
Nino Righi
adc5a5a280 Merged PR 1702: #4516 WA Implementation of orderType Groups
#4516 WA Implementation of orderType Groups
2023-12-22 16:13:52 +00:00
Lorenz Hilpert
f0b653fd0f Merged PR 1699: #4533 Breadcrumb wird falsch dargestellt
#4533 Breadcrumb wird falsch dargestellt
2023-12-20 16:17:39 +00:00
Lorenz Hilpert
14eba6e5ea Merged PR 1698: #4485 Kundendaten werden übernommen wenn welche vorhanden sind
#4485 Kundendaten werden übernommen wenn welche vorhanden sind
2023-12-20 14:55:04 +00:00
Nino Righi
5073693fc2 Merged PR 1697: #4530 Notification Batch Messages for each type
#4530 Notification Batch Messages for each type
2023-12-19 13:34:22 +00:00
Nino Righi
f3cb6236a5 Merged PR 1695: #4523 AHF, WA Added other notification types to Email Notification Badge
#4523 AHF, WA Added other notification types to Email Notification Badge
2023-12-15 16:03:34 +00:00
Lorenz Hilpert
4ab9890313 #4485 #4500 Kundenkartenkonto anlage Verhalten and Suche angeglichen 2023-12-15 14:34:24 +01:00
39 changed files with 469 additions and 300 deletions

View File

@@ -40,8 +40,9 @@
<div class="page-search-results__order-by mb-[0.125rem]" [class.page-search-results__order-by-primary]="primaryOutletActive$ | async">
<shared-order-by-filter
[orderBy]="(filter$ | async)?.orderBy"
(selectedOrderByChange)="search({ clear: true, orderBy: true }); updateBreadcrumbs()"
*ngIf="filter$ | async; let filter"
[orderBy]="filter?.orderBy"
(selectedOrderByChange)="search({ filter, clear: true, orderBy: true }); updateBreadcrumbs()"
>
</shared-order-by-filter>
</div>

View File

@@ -11,7 +11,7 @@ import {
AfterViewInit,
inject,
} from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { ActivatedRoute, Router } from '@angular/router';
import { ApplicationService } from '@core/application';
import { BreadcrumbService } from '@core/breadcrumb';
import { EnvironmentService } from '@core/environment';
@@ -20,7 +20,7 @@ import { ItemDTO } from '@swagger/cat';
import { AddToShoppingCartDTO } from '@swagger/checkout';
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
import { CacheService } from 'apps/core/cache/src/public-api';
import { debounce, isEqual } from 'lodash';
import { isEqual } from 'lodash';
import { BehaviorSubject, combineLatest, Subscription } from 'rxjs';
import { debounceTime, first, map, switchMap, withLatestFrom } from 'rxjs/operators';
import { ArticleSearchService } from '../article-search.store';
@@ -115,7 +115,8 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy, AfterVi
private _checkoutService: DomainCheckoutService,
private _environment: EnvironmentService,
private _navigationService: ProductCatalogNavigationService,
private _availability: DomainAvailabilityService
private _availability: DomainAvailabilityService,
private _router: Router
) {}
ngOnInit() {
@@ -198,9 +199,9 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy, AfterVi
.subscribe(async ([searchCompleted, processId]) => {
const params = searchCompleted.state.filter.getQueryParams();
if (searchCompleted.state.searchState === '') {
// Keine Navigation bei OrderBy
// Ticket 4524 Korrekte Navigation bei orderBy mit aktuellen queryParams
if (searchCompleted?.orderBy) {
return;
return await this._router.navigate([], { queryParams: params });
}
// Navigation auf Details bzw. Results | Details wenn hits 1

View File

@@ -81,8 +81,11 @@
*ngIf="group?.orderType !== undefined && (item.features?.orderType === 'Abholung' || item.features?.orderType === 'Rücklage')"
>
<ng-container *ngIf="item?.destination?.data?.targetBranch?.data; let targetBranch">
<ng-container *ngIf="i === 0 || targetBranch.id !== group.items[i - 1].destination?.data?.targetBranch?.data.id">
<div class="flex flex-row items-center px-5 pt-0 pb-[0.875rem] -mt-2 bg-[#F5F7FA]">
<ng-container *ngIf="i === 0 || checkIfMultipleDestinationsForOrderTypeExist(targetBranch, group, i)">
<div
class="flex flex-row items-center px-5 pt-0 pb-[0.875rem] -mt-2 bg-[#F5F7FA]"
[class.multiple-destinations]="checkIfMultipleDestinationsForOrderTypeExist(targetBranch, group, i)"
>
<span class="branch-name">{{ targetBranch?.name }} | {{ targetBranch | branchAddress }}</span>
</div>
<hr />

View File

@@ -105,6 +105,10 @@ h1 {
}
}
.multiple-destinations {
@apply py-[0.875rem] mt-0;
}
.icon-order-type {
@apply text-black mr-2;
}

View File

@@ -14,7 +14,7 @@ import { Router } from '@angular/router';
import { ApplicationService } from '@core/application';
import { DomainAvailabilityService } from '@domain/availability';
import { DomainCheckoutService } from '@domain/checkout';
import { AvailabilityDTO, DestinationDTO, ShoppingCartItemDTO } from '@swagger/checkout';
import { AvailabilityDTO, BranchDTO, DestinationDTO, ShoppingCartItemDTO } from '@swagger/checkout';
import { UiMessageModalComponent, UiModalService } from '@ui/modal';
import { PrintModalData, PrintModalComponent } from '@modal/printer';
import { delay, first, map, switchMap, takeUntil, tap } from 'rxjs/operators';
@@ -254,6 +254,10 @@ export class CheckoutReviewComponent implements OnInit, OnDestroy, AfterViewInit
});
}
checkIfMultipleDestinationsForOrderTypeExist(targetBranch: BranchDTO, group: { items: ShoppingCartItemDTO[] }, i: number) {
return i === 0 ? false : targetBranch.id !== group.items[i - 1].destination?.data?.targetBranch?.data.id;
}
async refreshAvailabilities() {
this.checkingOla$.next(true);

View File

@@ -7,7 +7,7 @@ import { Filter } from '@shared/components/filter';
import { BranchDTO, ListResponseArgsOfOrderItemListItemDTO, OrderItemListItemDTO, QuerySettingsDTO } from '@swagger/oms';
import { isResponseArgs } from '@utils/object';
import { Observable, Subject } from 'rxjs';
import { switchMap, tap, withLatestFrom } from 'rxjs/operators';
import { switchMap, takeUntil, tap, withLatestFrom } from 'rxjs/operators';
export interface CustomerOrderSearchState {
defaultSettings?: QuerySettingsDTO;
@@ -125,6 +125,8 @@ export class CustomerOrderSearchStore extends ComponentStore<CustomerOrderSearch
searchStarted = new Subject<{ clear?: boolean; silentReload?: boolean }>();
cancelSearch$ = new Subject<void>();
constructor(private _domainGoodsInService: DomainCustomerOrderService, private _cache: CacheService) {
super({
fetching: false,
@@ -192,6 +194,11 @@ export class CustomerOrderSearchStore extends ComponentStore<CustomerOrderSearch
});
}
cancelSearchRequest() {
this.cancelSearch$.next();
this.patchState({ fetching: false, silentFetching: false });
}
search = this.effect((options$: Observable<{ clear?: boolean; siletReload?: boolean }>) =>
options$.pipe(
tap((_) => {
@@ -238,6 +245,7 @@ export class CustomerOrderSearchStore extends ComponentStore<CustomerOrderSearch
}
return this._domainGoodsInService.search(queryToken).pipe(
takeUntil(this.cancelSearch$),
tapResponse(
(res) => {
let _results: OrderItemListItemDTO[] = [];

View File

@@ -17,10 +17,7 @@ import { ApplicationService } from '@core/application';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CustomerOrderSearchMainComponent implements OnInit, OnDestroy {
filter$ = this._customerOrderSearchStore.filter$.pipe(
filter((f) => !!f),
take(1)
);
filter$ = this._customerOrderSearchStore.filter$.pipe(filter((f) => !!f));
loading$ = this._customerOrderSearchStore.fetching$;

View File

@@ -170,10 +170,9 @@ export class CustomerOrderSearchResultsComponent extends ComponentStore<Customer
);
this._searchResultSubscription.add(
this.processId$
combineLatest([this.processId$, this._activatedRoute.queryParams])
.pipe(
debounceTime(150),
withLatestFrom(this._activatedRoute.queryParams),
switchMap(([processId, params]) =>
this._application.getSelectedBranch$(processId).pipe(map((selectedBranch) => ({ processId, params, selectedBranch })))
)
@@ -185,16 +184,6 @@ export class CustomerOrderSearchResultsComponent extends ComponentStore<Customer
if (processChanged) {
if (!!this._customerOrderSearchStore.processId && this._customerOrderSearchStore.filter instanceof Filter) {
const queryToken = {
...this._customerOrderSearchStore.filter?.getQueryParams(),
processId,
branchId: String(selectedBranch?.id),
};
this._customerOrderSearchStore.setCache({
queryToken,
hits: this._customerOrderSearchStore.hits,
results: this._customerOrderSearchStore.results,
});
await this.updateBreadcrumb(processId, this._customerOrderSearchStore.filter?.getQueryParams());
}
this._customerOrderSearchStore.patchState({ processId });
@@ -212,6 +201,7 @@ export class CustomerOrderSearchResultsComponent extends ComponentStore<Customer
if (!isEqual(cleanQueryParams, this.cleanupQueryParams(this._customerOrderSearchStore.filter.getQueryParams()))) {
this._customerOrderSearchStore.setQueryParams(params);
const queryToken = {
...this._customerOrderSearchStore.filter.getQueryParams(),
processId,
@@ -246,8 +236,8 @@ export class CustomerOrderSearchResultsComponent extends ComponentStore<Customer
const process = await this._application.getProcessById$(processId).pipe(first()).toPromise();
if (!!process) {
await this.updateBreadcrumb(processId, params);
await this.createBreadcrumb(processId, params);
await this.updateBreadcrumb(processId, params);
}
if (this._activatedRoute?.outlet === 'primary') {
@@ -288,13 +278,13 @@ export class CustomerOrderSearchResultsComponent extends ComponentStore<Customer
...this.cleanupQueryParams(this._customerOrderSearchStore?.filter?.getQueryParams()),
main_qs: this.sharedFilterInputGroupMain?.uiInput?.value,
};
this._customerOrderSearchStore?.setQueryParams(queryParams);
})
);
this._router.events.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((event) => {
if (event instanceof NavigationStart) {
this.cacheResults();
this._addScrollPositionToCache();
}
});
@@ -335,18 +325,6 @@ export class CustomerOrderSearchResultsComponent extends ComponentStore<Customer
this._onDestroy$.complete();
this._searchResultSubscription.unsubscribe();
const queryToken = {
...this._customerOrderSearchStore.filter?.getQueryParams(),
processId: this._customerOrderSearchStore.processId,
branchId: String(this._customerOrderSearchStore.selectedBranch?.id),
};
this._customerOrderSearchStore.setCache({
queryToken,
hits: this._customerOrderSearchStore.hits,
results: this._customerOrderSearchStore.results,
});
await this.updateBreadcrumb(this._customerOrderSearchStore.processId, this._customerOrderSearchStore.filter?.getQueryParams());
}
@@ -364,25 +342,6 @@ export class CustomerOrderSearchResultsComponent extends ComponentStore<Customer
return clean;
}
async removeBreadcrumbs(processId: number) {
const editCrumbs = await this._breadcrumb.getBreadcrumbsByKeyAndTags$(processId, ['customer-order', 'edit']).pipe(first()).toPromise();
const historyCrumbs = await this._breadcrumb
.getBreadcrumbsByKeyAndTags$(processId, ['customer-order', 'history'])
.pipe(first())
.toPromise();
editCrumbs.forEach((crumb) => {
this._breadcrumb.removeBreadcrumb(crumb.id, true);
});
historyCrumbs.forEach((crumb) => {
this._breadcrumb.removeBreadcrumb(crumb.id, true);
});
await this.removeDetailsBreadcrumb(processId);
}
async removeDetailsBreadcrumb(processId: number) {
const detailsCrumbs = await this._breadcrumb
.getBreadcrumbsByKeyAndTags$(processId, ['customer-order', 'details'])
@@ -394,7 +353,19 @@ export class CustomerOrderSearchResultsComponent extends ComponentStore<Customer
});
}
async createMainBreadcrumb(processId: number, params: Record<string, string>) {
await this._breadcrumb.addBreadcrumbIfNotExists({
key: processId,
name: 'Kundenbestellung',
path: this._navigationService.getCustomerOrdersBasePath(processId).path,
params,
tags: ['customer-order', 'main', 'filter'],
section: 'customer',
});
}
async createBreadcrumb(processId: number, params: Record<string, string>) {
await this.createMainBreadcrumb(processId, params);
await this._breadcrumb.addOrUpdateBreadcrumbIfNotExists({
key: processId,
name: this.getBreadcrumbName(params),
@@ -423,6 +394,20 @@ export class CustomerOrderSearchResultsComponent extends ComponentStore<Customer
}
}
cacheResults() {
const queryToken = {
...this._customerOrderSearchStore.filter?.getQueryParams(),
processId: this._customerOrderSearchStore.processId,
branchId: String(this._customerOrderSearchStore.selectedBranch?.id),
};
this._customerOrderSearchStore.setCache({
queryToken,
hits: this._customerOrderSearchStore.hits,
results: this._customerOrderSearchStore.results,
});
}
getBreadcrumbName(params: Record<string, string>) {
const input = params?.main_qs;
@@ -442,8 +427,8 @@ export class CustomerOrderSearchResultsComponent extends ComponentStore<Customer
search({ filter, clear = false }: { filter?: Filter; clear?: boolean }) {
if (!!filter) {
this.sharedFilterInputGroupMain.cancelAutocomplete();
this._customerOrderSearchStore.setQueryParams(filter?.getQueryParams());
}
this._customerOrderSearchStore.search({ clear });
}

View File

@@ -42,13 +42,24 @@ export class CustomerOrderComponent implements OnInit {
private _uiModal: UiModalService,
private _renderer: Renderer2,
private _environmentService: EnvironmentService,
public auth: AuthService
public auth: AuthService,
private _store: CustomerOrderSearchStore
) {}
ngOnInit(): void {
this.selectedBranch$ = this.application.activatedProcessId$.pipe(
switchMap((processId) => this.application.getSelectedBranch$(Number(processId)))
);
/* Ticket #4544 - Suchrequest abbrechen bei Prozesswechsel
/ um zu verhindern, dass die Suche in einen anderen Kundenbestellungen Prozess übernommen wird
/ bei Prozesswechsel zwischen 2 Kundenbestellungen Prozessen
*/
this.processId$.pipe(takeUntil(this._onDestroy$)).subscribe((processId) => {
if (Number(processId) !== this._store.processId) {
this._store.cancelSearchRequest();
}
});
}
ngAfterViewInit(): void {

View File

@@ -7,7 +7,7 @@ import { CrmCustomerService } from '@domain/crm';
import { AddressDTO, CustomerDTO, CustomerInfoDTO, PayerDTO, ShippingAddressDTO } from '@swagger/crm';
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
import { UiValidators } from '@ui/validators';
import { isNull } from 'lodash';
import { isNull, merge } from 'lodash';
import { BehaviorSubject, Observable, of, Subject } from 'rxjs';
import {
first,
@@ -229,7 +229,33 @@ export abstract class AbstractCreateCustomer implements OnInit, OnDestroy {
const customerId = this.formData?._meta?.customerDto?.id ?? this.formData?._meta?.customerInfoDto?.id;
return this.customerService.checkLoyaltyCard({ loyaltyCardNumber: value, customerId }).pipe(
map((response) => {
return !response?.error && (response as any)?.result === 1 ? null : { invalid: 'Kundenkartencode ist ungültig' };
if (response.error) {
throw response.message;
}
/**
* #4485 Kubi // Verhalten mit angelegte aber nicht verknüpfte Kundenkartencode in Kundensuche und Kundendaten erfassen ist nicht gleich
* Fall1: Kundenkarte hat Daten in point4more:
* Sobald Kundenkartencode in Feld "Kundenkartencode" reingegeben wird- werden die Daten von point4more in Formular "Kundendaten Erfassen" eingefügt und ersetzen (im Ganzen, nicht inkremental) die Daten in Felder, falls welche schon reingetippt werden.
* Fall2: Kundenkarte hat keine Daten in point4more:
* Sobald Kundenkartencode in Feld "Kundenkartencode" reingegeben wird- bleiben die Daten in Formular "Kundendaten Erfassen" in Felder, falls welche schon reingetippt werden.
*/
if (response.result && response.result.customer) {
const customer = response.result.customer;
const data = mapCustomerInfoDtoToCustomerCreateFormData(customer);
if (data.name.firstName && data.name.lastName) {
// Fall1
this._formData.next(data);
} else {
// Fall2 Hier müssen die Metadaten gesetzt werden um eine verknüfung zur kundenkarte zu ermöglichen.
const current = this.formData;
current._meta = data._meta;
current.p4m = data.p4m;
}
}
return null;
}),
catchError((error) => {
if (error instanceof HttpErrorResponse) {
@@ -242,31 +268,13 @@ export abstract class AbstractCreateCustomer implements OnInit, OnDestroy {
})
);
}),
tap(async (result) => {
tap(() => {
control.markAsTouched();
this.cdr.markForCheck();
if (result === null) {
const customerInfoDto = await this.getAnonymousCustomerForCode(control.value);
if (customerInfoDto) {
const data = mapCustomerInfoDtoToCustomerCreateFormData(customerInfoDto);
this._formData.next(data);
}
}
})
);
};
async getAnonymousCustomerForCode(code: string): Promise<CustomerInfoDTO | undefined> {
try {
const res = await this.customerService.getCustomers(code).toPromise();
if (res.result.length > 0 && res.result[0].id < 0) {
return res.result[0];
}
} catch (error) {}
}
async navigateToCustomerDetails(customer: CustomerDTO) {
const processId = await this.processId$.pipe(first()).toPromise();
const route = this.customerSearchNavigation.detailsRoute({ processId, customerId: customer.id, customer });

View File

@@ -12,6 +12,7 @@ import { isEmpty } from 'lodash';
import { DomainOmsService } from '@domain/oms';
import { OrderDTO, OrderListItemDTO } from '@swagger/oms';
import { hash } from '@utils/common';
import { UiModalService } from '@ui/modal';
@Injectable()
export class CustomerSearchStore extends ComponentStore<CustomerSearchState> implements OnStoreInit, OnDestroy {
@@ -163,7 +164,7 @@ export class CustomerSearchStore extends ComponentStore<CustomerSearchState> imp
selectedOrderItem$ = this.select(S.selectSelectedOrderItem);
constructor(private _customerService: CrmCustomerService, private _omsService: DomainOmsService) {
constructor(private _customerService: CrmCustomerService, private _omsService: DomainOmsService, private _modal: UiModalService) {
super({ customerListCount: 0 });
}
@@ -205,7 +206,8 @@ export class CustomerSearchStore extends ComponentStore<CustomerSearchState> imp
};
handleSelectCustomerError = (err: any) => {
console.error(err);
this._modal.error('Fehler beim Auswählen des Kundens', err);
this.patchState({ fetchingCustomer: false });
};
handleSelectCustomerComplete = () => {
@@ -230,7 +232,8 @@ export class CustomerSearchStore extends ComponentStore<CustomerSearchState> imp
};
handleSelectOrderError = (err: any) => {
console.error(err);
this._modal.error('Fehler beim Auswählen der Bestellung', err);
this.patchState({ fetchingOrder: false });
};
handleSelectOrderComplete = () => {
@@ -259,7 +262,8 @@ export class CustomerSearchStore extends ComponentStore<CustomerSearchState> imp
};
handleFetchCustomerOrdersError = (err: any) => {
console.error(err);
this._modal.error('Fehler beim Laden der Kundenbestellungen', err);
this.patchState({ fetchingCustomerOrders: false });
};
handleFetchCustomerOrdersComplete = () => {
@@ -282,7 +286,8 @@ export class CustomerSearchStore extends ComponentStore<CustomerSearchState> imp
};
handleFetchFilterError = (err: any) => {
console.error(err);
this._modal.error('Fehler beim Laden der Filter', err);
this.patchState({ fetchingFilter: false });
};
handleFetchFilterComplete = () => {
@@ -341,7 +346,8 @@ export class CustomerSearchStore extends ComponentStore<CustomerSearchState> imp
};
handleSearchError = (err: any) => {
console.error(err);
this._modal.error('Fehler beim Laden der Liste', err);
this.patchState({ fetchingCustomerList: false });
};
handleSearchComplete = () => {

View File

@@ -75,7 +75,10 @@
>Zur erneuten Prüfung 7 Tage nach Avisierung.</ui-tooltip
>
</ng-container>
<div class="isa-label text-white font-bold" [class]="packageDetails.package.arrivalStatus | arrivalStatusColorClass">
<div
class="isa-label text-white font-bold page-package-details__arrival-status"
[class]="packageDetails.package.arrivalStatus | arrivalStatusColorClass"
>
{{ packageDetails.package.arrivalStatus | arrivalStatus }}
</div>
</div>

View File

@@ -12,6 +12,7 @@ import { RunCheckTrigger } from './trigger';
import { OrderItemsContext } from '@domain/oms';
import { ActionHandlerService } from './services/action-handler.service';
import { Config } from '@core/config';
import { debounce } from '@utils/common';
export type GetNameForBreadcrumbData = {
processId: number;
@@ -64,6 +65,11 @@ export abstract class PickupShelfBaseComponent implements OnInit {
this._runChecks();
}
// der debounce soll verhindern, dass die breadcrumb zu oft aktualisiert,
// besonders bei asynchronen calls kommt es sonst zu fehlern
// @debounce(500)
// Auskommentiert, da es zu anderen Problemen führt, siehe z.B. Ticket #4538 oder #4540
// Ursprungsproblem des Tickets #4533 konnte anders gelöst werden, somit wird debounce hier nicht mehr benötigt
private _runChecks() {
const processId = this._checkAndUpdateProcessId();
const queryParams = this._checkAndUpdateQueryParams();
@@ -120,7 +126,7 @@ export abstract class PickupShelfBaseComponent implements OnInit {
// Only Update QueryParams if the user is already on the details, edit or history page
const view: string = this.activatedRoute.snapshot.data.view;
if (['details', 'edit', 'history'].includes(view)) {
if (['filter', 'details', 'edit', 'history'].includes(view)) {
await this.router.navigate([], { queryParams: { ...queryParams, ...filterQueryParams }, skipLocationChange: true });
return;
}

View File

@@ -17,17 +17,25 @@
(updateDate)="updateDate($event)"
(editClick)="navigateToEditPage($event)"
></page-pickup-shelf-details-header>
<page-pickup-shelf-details-item
*ngIf="selectedItem$ | async; let item"
class="mb-px-2"
[orderItem]="item"
[selected]="true"
(historyClick)="navigateToHistoryPage($event)"
[order]="order$ | async"
(specialCommentChanged)="updateSpecialComment(item, $event)"
(sharedOnInit)="fetchNotifications(item)"
></page-pickup-shelf-details-item>
<ng-container *ngIf="selectedItem$ | async; let item">
<page-pickup-shelf-details-items-group
[orderType]="selectedItemOrderType$ | async"
[groupedItems]="[item]"
></page-pickup-shelf-details-items-group>
<page-pickup-shelf-details-item
class="mb-px-2"
[orderItem]="item"
[selected]="true"
(historyClick)="navigateToHistoryPage($event)"
[order]="order$ | async"
(specialCommentChanged)="updateSpecialComment(item, $event)"
(sharedOnInit)="fetchNotifications(item)"
></page-pickup-shelf-details-item>
</ng-container>
<page-pickup-shelf-details-tags class="mb-px-2" *ngIf="showTagsComponent$ | async"></page-pickup-shelf-details-tags>
<page-pickup-shelf-details-covers
*ngIf="(coverOrderItems$ | async)?.length > 0"
[coverItems]="coverOrderItems$ | async"

View File

@@ -16,6 +16,7 @@ import { DBHOrderItemListItemDTO, KeyValueDTOOfStringAndString } from '@swagger/
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
import { ActivatedRoute } from '@angular/router';
import { RunCheckTrigger } from '../../trigger';
import { PickUpShelfDetailsItemsGroupComponent } from '../../shared/pickup-shelf-details-items-group/pickup-shelf-details-items-group.component';
@Component({
selector: 'page-pickup-shelf-in-details',
@@ -32,6 +33,7 @@ import { RunCheckTrigger } from '../../trigger';
PickUpShelfDetailsItemComponent,
PickUpShelfDetailsTagsComponent,
PickUpShelfDetailsCoversComponent,
PickUpShelfDetailsItemsGroupComponent,
PickupShelfAddToPreviousCompartmentCodeLabelPipe,
UiSpinnerModule,
OnInitDirective,
@@ -74,6 +76,8 @@ export class PickupShelfInDetailsComponent extends PickupShelfDetailsBaseCompone
selectedItem$ = this.store.selectedOrderItem$;
selectedItemOrderType$ = this.selectedItem$.pipe(map((item) => item?.features?.orderType));
coverOrderItems$ = this.store.coverOrderItems$;
displayedCompartmentInfo$ = this.store.compartmentInfo$;

View File

@@ -14,16 +14,24 @@
(updateDate)="updateDate($event)"
(editClick)="navigateToEditPage($event)"
></page-pickup-shelf-details-header>
<page-pickup-shelf-details-item
class="mb-px-2"
*ngFor="let item of orderItems$ | async; trackBy: trackByFnDBHOrderItemListItemDTO"
[orderItem]="item"
[selected]="true"
(historyClick)="navigateToHistoryPage($event)"
[order]="order$ | async"
(specialCommentChanged)="updateSpecialComment(item, $event)"
(sharedOnInit)="fetchNotifications(item)"
></page-pickup-shelf-details-item>
<ng-container *ngFor="let group of groupedItems$ | async; trackBy: trackByFnGroupDBHOrderItemListItemDTO">
<page-pickup-shelf-details-items-group
[orderType]="group.type"
[groupedItems]="group.items"
></page-pickup-shelf-details-items-group>
<page-pickup-shelf-details-item
class="mb-px-2"
*ngFor="let item of group.items; trackBy: trackByFnDBHOrderItemListItemDTO"
[orderItem]="item"
[selected]="true"
(historyClick)="navigateToHistoryPage($event)"
[order]="order$ | async"
(specialCommentChanged)="updateSpecialComment(item, $event)"
(sharedOnInit)="fetchNotifications(item)"
></page-pickup-shelf-details-item>
</ng-container>
<page-pickup-shelf-details-tags
*ngIf="showTagsComponent$ | async"
[ngModel]="selectedCompartmentInfo$ | async"

View File

@@ -3,9 +3,9 @@ import { PickupShelfDetailsBaseComponent } from '../../pickup-shelf-details-base
import { AsyncPipe, NgFor, NgIf } from '@angular/common';
import { PickUpShelfDetailsHeaderComponent } from '../../shared/pickup-shelf-details-header/pickup-shelf-details-header.component';
import { PickUpShelfDetailsItemComponent } from '../../shared/pickup-shelf-details-item/pickup-shelf-details-item.component';
import { DBHOrderItemListItemDTO, KeyValueDTOOfStringAndString, OrderItemProcessingStatusValue } from '@swagger/oms';
import { DBHOrderItemListItemDTO, KeyValueDTOOfStringAndString } from '@swagger/oms';
import { PickUpShelfOutNavigationService } from '@shared/services';
import { BehaviorSubject, asapScheduler, combineLatest } from 'rxjs';
import { BehaviorSubject, Observable, asapScheduler, combineLatest } from 'rxjs';
import { map } from 'rxjs/operators';
import { PickUpShelfDetailsTagsComponent } from '../../shared/pickup-shelf-details-tags/pickup-shelf-details-tags.component';
import { UiSpinnerModule } from '@ui/spinner';
@@ -13,6 +13,7 @@ import { UiErrorModalComponent, UiModalService } from '@ui/modal';
import { OnInitDirective } from '@shared/directives/element-lifecycle';
import { FormsModule } from '@angular/forms';
import { RunCheckTrigger } from '../../trigger';
import { PickUpShelfDetailsItemsGroupComponent } from '../../shared/pickup-shelf-details-items-group/pickup-shelf-details-items-group.component';
@Component({
selector: 'page-pickup-shelf-out-details',
@@ -28,6 +29,7 @@ import { RunCheckTrigger } from '../../trigger';
PickUpShelfDetailsHeaderComponent,
PickUpShelfDetailsItemComponent,
PickUpShelfDetailsTagsComponent,
PickUpShelfDetailsItemsGroupComponent,
UiSpinnerModule,
OnInitDirective,
FormsModule,
@@ -44,7 +46,25 @@ export class PickupShelfOutDetailsComponent extends PickupShelfDetailsBaseCompon
order$ = this.store.order$;
orderItems$ = this.store.orderItems$;
groupedItems$: Observable<Array<{ type: string; items: DBHOrderItemListItemDTO[] }>> = this.store.orderItems$.pipe(
map((items) => {
const groups: Array<{ type: string; items: DBHOrderItemListItemDTO[] }> = [];
// New Set to remove duplicates
const types = Array.from(new Set(items.map((item) => item?.features?.orderType)));
for (let type of types) {
const filteredItemsByType = items.filter((item) => item?.features?.orderType === type);
if (!!type && filteredItemsByType.length > 0) {
// Add items to matching orderType group
groups.push({ type, items: filteredItemsByType });
}
}
return groups;
})
);
fetching$ = this.store.fetchingOrder$;
fetchingItems$ = this.store.fetchingOrderItems$;
@@ -66,6 +86,8 @@ export class PickupShelfOutDetailsComponent extends PickupShelfDetailsBaseCompon
mainActions$ = this.store.mainActions$;
trackByFnGroupDBHOrderItemListItemDTO = (index: number, group: { type: string; items: DBHOrderItemListItemDTO[] }) => group.type;
trackByFnDBHOrderItemListItemDTO = (index: number, item: DBHOrderItemListItemDTO) => item.orderItemSubsetId;
get processId() {

View File

@@ -145,96 +145,6 @@
</div>
</div>
</div>
<div class="flex flex-row items-center relative bg-[#F5F7FA] p-4 rounded-t">
<div *ngIf="showFeature" class="flex flex-row items-center mr-3">
<ng-container [ngSwitch]="order.features.orderType">
<ng-container *ngSwitchCase="'Versand'">
<div class="flex items-center justify-center bg-[#D8DFE5] w-[2.25rem] h-[2.25rem] rounded rounded-br-none mr-2">
<shared-icon [size]="24" icon="isa-truck"></shared-icon>
</div>
<p class="font-bold text-p1">Versand</p>
</ng-container>
<ng-container *ngSwitchCase="'DIG-Versand'">
<div class="flex items-center justify-center bg-[#D8DFE5] w-[2.25rem] h-[2.25rem] rounded rounded-br-none mr-2">
<shared-icon [size]="24" icon="isa-truck"></shared-icon>
</div>
<p class="font-bold text-p1">Versand</p>
</ng-container>
<ng-container *ngSwitchCase="'B2B-Versand'">
<div class="flex items-center justify-center bg-[#D8DFE5] w-[2.25rem] h-[2.25rem] rounded rounded-br-none mr-2">
<shared-icon [size]="24" icon="isa-b2b-truck"></shared-icon>
</div>
<p class="font-bold text-p1">B2B-Versand</p>
</ng-container>
<ng-container *ngSwitchCase="'Abholung'">
<div class="flex items-center justify-center bg-[#D8DFE5] w-[2.25rem] h-[2.25rem] rounded rounded-br-none mr-2">
<shared-icon [size]="24" icon="isa-box-out"></shared-icon>
</div>
<p class="font-bold text-p1 mr-3">Abholung</p>
{{ orderItem.targetBranch }}
</ng-container>
<ng-container *ngSwitchCase="'Rücklage'">
<div class="flex items-center justify-center bg-[#D8DFE5] w-[2.25rem] h-[2.25rem] rounded rounded-br-none mr-2">
<shared-icon [size]="24" icon="isa-shopping-bag"></shared-icon>
</div>
<p class="font-bold text-p1">Rücklage</p>
</ng-container>
<ng-container *ngSwitchCase="'Download'">
<div class="flex items-center justify-center bg-[#D8DFE5] w-[2.25rem] h-[2.25rem] rounded rounded-br-none mr-2">
<shared-icon [size]="24" icon="isa-download"></shared-icon>
</div>
<p class="font-bold text-p1">Download</p>
</ng-container>
</ng-container>
</div>
<div class="page-pickup-shelf-details-header__additional-addresses" *ngIf="showAddresses">
<button (click)="openAddresses = !openAddresses" class="text-[#0556B4]">
Lieferadresse / Rechnungsadresse {{ openAddresses ? 'ausblenden' : 'anzeigen' }}
</button>
<div class="page-pickup-shelf-details-header__addresses-popover" *ngIf="openAddresses">
<button (click)="openAddresses = !openAddresses" class="close">
<shared-icon icon="close" [size]="24"></shared-icon>
</button>
<div class="page-pickup-shelf-details-header__addresses-popover-data">
<div *ngIf="order.shipping" class="page-pickup-shelf-details-header__addresses-popover-delivery">
<p>Lieferadresse</p>
<div class="page-pickup-shelf-details-header__addresses-popover-delivery-data">
<ng-container *ngIf="order.shipping?.data?.organisation">
<p>{{ order.shipping?.data?.organisation?.name }}</p>
<p>{{ order.shipping?.data?.organisation?.department }}</p>
</ng-container>
<p>{{ order.shipping?.data?.firstName }} {{ order.shipping?.data?.lastName }}</p>
<p>{{ order.shipping?.data?.address?.info }}</p>
<p>{{ order.shipping?.data?.address?.street }} {{ order.shipping?.data?.address?.streetNumber }}</p>
<p>{{ order.shipping?.data?.address?.zipCode }} {{ order.shipping?.data?.address?.city }}</p>
</div>
</div>
<div *ngIf="order.billing" class="page-pickup-shelf-details-header__addresses-popover-billing">
<p>Rechnungsadresse</p>
<div class="page-pickup-shelf-details-header__addresses-popover-billing-data">
<ng-container *ngIf="order.billing?.data?.organisation">
<p>{{ order.billing?.data?.organisation?.name }}</p>
<p>{{ order.billing?.data?.organisation?.department }}</p>
</ng-container>
<p>{{ order.billing?.data?.firstName }} {{ order.billing?.data?.lastName }}</p>
<p>{{ order.billing?.data?.address?.info }}</p>
<p>{{ order.billing?.data?.address?.street }} {{ order.billing?.data?.address?.streetNumber }}</p>
<p>{{ order.billing?.data?.address?.zipCode }} {{ order.billing?.data?.address?.city }}</p>
</div>
</div>
</div>
</div>
</div>
<div class="page-pickup-shelf-details-header__select grow" *ngIf="showMultiselect$ | async">
<button class="cta-select-all" (click)="selectAll()">Alle auswählen</button>
{{ selectedOrderItemCount$ | async }} von {{ orderItemCount$ | async }} Titeln
</div>
</div>
</div>
<ng-template #featureLoading>

View File

@@ -81,51 +81,6 @@
}
}
.page-pickup-shelf-details-header__select {
@apply flex flex-col items-end;
}
.page-pickup-shelf-details-header__additional-addresses {
.page-pickup-shelf-details-header__addresses-popover {
@apply absolute inset-x-0 top-16 bottom-0 z-popover;
.close {
@apply bg-white absolute right-0 p-6;
}
.page-pickup-shelf-details-header__addresses-popover-data {
@apply flex flex-col bg-white p-6 z-popover min-h-[200px];
box-shadow: 0px 6px 24px rgba(206, 212, 219, 0.8);
.page-pickup-shelf-details-header__addresses-popover-delivery {
@apply grid mb-6;
grid-template-columns: 9.5625rem auto;
.page-pickup-shelf-details-header__addresses-popover-delivery-data {
p {
@apply font-bold;
}
}
}
.page-pickup-shelf-details-header__addresses-popover-billing {
@apply grid;
grid-template-columns: 9.5625rem auto;
.page-pickup-shelf-details-header__addresses-popover-billing-data {
p {
@apply font-bold;
}
}
}
}
}
}
.cta-select-all {
@apply text-brand bg-transparent text-p2 font-bold outline-none border-none;
}
.fetch-wrapper {
@apply grid grid-flow-col gap-4;
}

View File

@@ -92,10 +92,6 @@ export class PickUpShelfDetailsHeaderComponent {
minDateDatepicker = this.dateAdapter.addCalendarDays(this.dateAdapter.today(), -1);
today = this.dateAdapter.today();
selectedOrderItemCount$ = this._store.selectedOrderItemIds$.pipe(map((ids) => ids?.length ?? 0));
orderItemCount$ = this._store.orderItems$.pipe(map((items) => items?.length ?? 0));
orderItem$ = this._store.orderItems$.pipe(map((orderItems) => orderItems?.find((_) => true)));
changeDateLoader$ = new BehaviorSubject<boolean>(false);
@@ -115,14 +111,6 @@ export class PickUpShelfDetailsHeaderComponent {
statusActions$ = this.orderItem$.pipe(map((orderItem) => orderItem?.actions?.filter((action) => action.enabled === false)));
get isItemSelectable() {
return this._store.orderItems?.some((item) => !!item?.actions && item?.actions?.length > 0);
}
showMultiselect$ = combineLatest([this._store.orderItems$, this._store.fetchPartial$]).pipe(
map(([orderItems, fetchPartial]) => this.isItemSelectable && fetchPartial && orderItems?.length > 1)
);
crudaUpdate$ = this.orderItem$.pipe(map((orederItem) => !!(orederItem?.cruda & 4)));
editButtonDisabled$ = combineLatest([this.changeStatusLoader$, this.crudaUpdate$]).pipe(
@@ -133,20 +121,6 @@ export class PickUpShelfDetailsHeaderComponent {
map(([statusActions, crudaUpdate]) => statusActions?.length > 0 && crudaUpdate)
);
openAddresses: boolean = false;
get digOrderNumber(): string {
return this.order?.linkedRecords?.find((_) => true)?.number;
}
get showAddresses(): boolean {
return (this.order?.orderType === 2 || this.order?.orderType === 4) && (!!this.order?.shipping || !!this.order?.billing);
}
get showFeature(): boolean {
return !!this.order?.features && !!this.order?.features?.orderType;
}
constructor(private dateAdapter: DateAdapter, private cdr: ChangeDetectorRef) {}
async handleActionClick(action?: KeyValueDTOOfStringAndString) {
@@ -156,10 +130,6 @@ export class PickUpShelfDetailsHeaderComponent {
this.cdr.markForCheck();
}
selectAll() {
this._store.selectAllOrderItemIds();
}
updatePickupDeadline(date: Date) {
this.updateDate.emit({ date, type: 'pickup' });
}

View File

@@ -0,0 +1,89 @@
<div class="flex flex-row items-center relative bg-[#F5F7FA] p-4 rounded-t mb-[0.125rem]">
<div *ngIf="showFeature" class="flex flex-row items-center mr-3">
<ng-container [ngSwitch]="orderType">
<ng-container *ngSwitchCase="'Versand'">
<div class="flex items-center justify-center bg-[#D8DFE5] w-[2.25rem] h-[2.25rem] rounded rounded-br-none mr-2">
<shared-icon [size]="24" icon="isa-truck"></shared-icon>
</div>
<p class="font-bold text-p1">Versand</p>
</ng-container>
<ng-container *ngSwitchCase="'DIG-Versand'">
<div class="flex items-center justify-center bg-[#D8DFE5] w-[2.25rem] h-[2.25rem] rounded rounded-br-none mr-2">
<shared-icon [size]="24" icon="isa-truck"></shared-icon>
</div>
<p class="font-bold text-p1">Versand</p>
</ng-container>
<ng-container *ngSwitchCase="'B2B-Versand'">
<div class="flex items-center justify-center bg-[#D8DFE5] w-[2.25rem] h-[2.25rem] rounded rounded-br-none mr-2">
<shared-icon [size]="24" icon="isa-b2b-truck"></shared-icon>
</div>
<p class="font-bold text-p1">B2B-Versand</p>
</ng-container>
<ng-container *ngSwitchCase="'Abholung'">
<div class="flex items-center justify-center bg-[#D8DFE5] w-[2.25rem] h-[2.25rem] rounded rounded-br-none mr-2">
<shared-icon [size]="24" icon="isa-box-out"></shared-icon>
</div>
<p class="font-bold text-p1 mr-3">Abholung</p>
{{ targetBranches }}
</ng-container>
<ng-container *ngSwitchCase="'Rücklage'">
<div class="flex items-center justify-center bg-[#D8DFE5] w-[2.25rem] h-[2.25rem] rounded rounded-br-none mr-2">
<shared-icon [size]="24" icon="isa-shopping-bag"></shared-icon>
</div>
<p class="font-bold text-p1">Rücklage</p>
</ng-container>
<ng-container *ngSwitchCase="'Download'">
<div class="flex items-center justify-center bg-[#D8DFE5] w-[2.25rem] h-[2.25rem] rounded rounded-br-none mr-2">
<shared-icon [size]="24" icon="isa-download"></shared-icon>
</div>
<p class="font-bold text-p1">Download</p>
</ng-container>
</ng-container>
</div>
<div class="page-pickup-shelf-details-items-group__additional-addresses" *ngIf="showAddresses">
<button (click)="openAddresses = !openAddresses" class="text-[#0556B4]">
Lieferadresse / Rechnungsadresse {{ openAddresses ? 'ausblenden' : 'anzeigen' }}
</button>
<div class="page-pickup-shelf-details-items-group__addresses-popover" *ngIf="openAddresses">
<button (click)="openAddresses = !openAddresses" class="close">
<shared-icon icon="close" [size]="24"></shared-icon>
</button>
<div class="page-pickup-shelf-details-items-group__addresses-popover-data">
<div *ngIf="order.shipping" class="page-pickup-shelf-details-items-group__addresses-popover-delivery">
<p>Lieferadresse</p>
<div class="page-pickup-shelf-details-items-group__addresses-popover-delivery-data">
<ng-container *ngIf="order.shipping?.data?.organisation">
<p>{{ order.shipping?.data?.organisation?.name }}</p>
<p>{{ order.shipping?.data?.organisation?.department }}</p>
</ng-container>
<p>{{ order.shipping?.data?.firstName }} {{ order.shipping?.data?.lastName }}</p>
<p>{{ order.shipping?.data?.address?.info }}</p>
<p>{{ order.shipping?.data?.address?.street }} {{ order.shipping?.data?.address?.streetNumber }}</p>
<p>{{ order.shipping?.data?.address?.zipCode }} {{ order.shipping?.data?.address?.city }}</p>
</div>
</div>
<div *ngIf="order.billing" class="page-pickup-shelf-details-items-group__addresses-popover-billing">
<p>Rechnungsadresse</p>
<div class="page-pickup-shelf-details-items-group__addresses-popover-billing-data">
<ng-container *ngIf="order.billing?.data?.organisation">
<p>{{ order.billing?.data?.organisation?.name }}</p>
<p>{{ order.billing?.data?.organisation?.department }}</p>
</ng-container>
<p>{{ order.billing?.data?.firstName }} {{ order.billing?.data?.lastName }}</p>
<p>{{ order.billing?.data?.address?.info }}</p>
<p>{{ order.billing?.data?.address?.street }} {{ order.billing?.data?.address?.streetNumber }}</p>
<p>{{ order.billing?.data?.address?.zipCode }} {{ order.billing?.data?.address?.city }}</p>
</div>
</div>
</div>
</div>
</div>
<div class="page-pickup-shelf-details-items-group__select grow" *ngIf="showMultiselect$ | async">
<button class="cta-select-all" (click)="selectAll()">Alle auswählen</button>
{{ selectedOrderItemCount$ | async }} von {{ groupedItems.length }} Titeln
</div>
</div>

View File

@@ -0,0 +1,48 @@
:host {
@apply grid grid-flow-row;
}
.page-pickup-shelf-details-items-group__select {
@apply flex flex-col items-end;
}
.page-pickup-shelf-details-items-group__additional-addresses {
.page-pickup-shelf-details-items-group__addresses-popover {
@apply absolute inset-x-0 top-16 bottom-0 z-popover;
.close {
@apply bg-white absolute right-0 p-6;
}
.page-pickup-shelf-details-items-group__addresses-popover-data {
@apply flex flex-col bg-white p-6 z-popover min-h-[200px];
box-shadow: 0px 6px 24px rgba(206, 212, 219, 0.8);
.page-pickup-shelf-details-items-group__addresses-popover-delivery {
@apply grid mb-6;
grid-template-columns: 9.5625rem auto;
.page-pickup-shelf-details-items-group__addresses-popover-delivery-data {
p {
@apply font-bold;
}
}
}
.page-pickup-shelf-details-items-group__addresses-popover-billing {
@apply grid;
grid-template-columns: 9.5625rem auto;
.page-pickup-shelf-details-items-group__addresses-popover-billing-data {
p {
@apply font-bold;
}
}
}
}
}
}
.cta-select-all {
@apply text-brand bg-transparent text-p2 font-bold outline-none border-none;
}

View File

@@ -0,0 +1,65 @@
import { ChangeDetectionStrategy, Component, Input, OnInit, inject } from '@angular/core';
import { PickupShelfDetailsStore } from '../../store';
import { map } from 'rxjs/operators';
import { DBHOrderItemListItemDTO, OrderDTO } from '@swagger/oms';
import { AsyncPipe, NgFor, NgIf, NgSwitch, NgSwitchCase } from '@angular/common';
import { IconModule } from '@shared/components/icon';
@Component({
selector: 'page-pickup-shelf-details-items-group',
templateUrl: 'pickup-shelf-details-items-group.component.html',
styleUrls: ['pickup-shelf-details-items-group.component.scss'],
standalone: true,
host: { class: 'page-pickup-shelf-details-items-group' },
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [NgIf, NgFor, NgSwitch, NgSwitchCase, IconModule, AsyncPipe],
})
export class PickUpShelfDetailsItemsGroupComponent implements OnInit {
private _store = inject(PickupShelfDetailsStore);
get order(): OrderDTO {
return this._store.order;
}
@Input() orderType: string;
@Input() groupedItems: DBHOrderItemListItemDTO[];
get firstGroupedItem() {
return this.groupedItems?.find((_) => true);
}
openAddresses: boolean = false;
get showAddresses(): boolean {
return (this.order?.orderType === 2 || this.order?.orderType === 4) && (!!this.order?.shipping || !!this.order?.billing);
}
get showFeature(): boolean {
return !!this.firstGroupedItem?.features && !!this.firstGroupedItem?.features?.orderType;
}
get targetBranches(): string {
return Array.from(new Set(this.groupedItems?.map((item) => item?.targetBranch))).join('; ');
}
get isItemSelectable() {
return this.groupedItems?.some((item) => !!item?.actions && item?.actions?.length > 0);
}
showMultiselect$ = this._store.fetchPartial$.pipe(
map((fetchPartial) => this.isItemSelectable && fetchPartial && this.groupedItems?.length > 1)
);
selectedOrderItemCount$ = this._store.selectedOrderItemIds$.pipe(
map((ids) => this.groupedItems?.filter((groupedItem) => ids?.includes(groupedItem?.orderItemSubsetId))?.length ?? 0)
);
constructor() {}
ngOnInit() {}
selectAll() {
this._store.selectAllOrderItemIds();
}
}

View File

@@ -113,7 +113,13 @@ export class PickupShelfStore extends ComponentStore<PickupShelfState> implement
}
setQueryParams(queryParams: Record<string, string> | undefined) {
this.patchState({ queryParams });
// #4533 Wenn ein Abholschein gescannt wird, soll ORD: nicht in der Suchbox stehen und somit auch nicht in der Breadcrumb enthalten sein
const isScannedPickUpCode = queryParams?.main_qs?.includes('ORD:');
if (isScannedPickUpCode) {
this.patchState({ queryParams: { ...queryParams, main_qs: queryParams?.main_qs?.replace('ORD:', '') } });
} else {
this.patchState({ queryParams });
}
}
cancelListRequests() {

View File

@@ -152,10 +152,7 @@ export class SharedGoodsInOutOrderEditComponent implements OnChanges, OnDestroy
name: fb.control(item.product?.name),
ean: fb.control(item.product?.ean, [Validators.required]),
quantity: fb.control({ value: item.quantity + ' x', disabled: true }),
price: fb.control(item.price ? String(item.price).replace('.', ',') : '', [
Validators.required,
Validators.pattern(/^\d+([\,]\d{1,2})?$/),
]),
price: fb.control(this.formatPrice(item?.price), [Validators.required, Validators.pattern(/^\d+([\,]\d{1,2})?$/)]),
currency: fb.control(item.currency),
targetBranch: fb.control({ value: item.targetBranch, disabled: true }),
supplier: fb.control({ value: item.supplier, disabled: true }),
@@ -208,6 +205,15 @@ export class SharedGoodsInOutOrderEditComponent implements OnChanges, OnDestroy
return this.omsService.getOrderSource(+orderId).toPromise();
}
formatPrice(price: number) {
if (!price) {
return '';
}
const priceWithTwoDecimalPlaces = price.toFixed(2);
return String(priceWithTwoDecimalPlaces).replace('.', ',');
}
changeEstimatedDeliveryDate(date: Date, item: OrderItemListItemDTO) {
if (!date) {
return;

View File

@@ -98,7 +98,8 @@
class="side-menu-group-item"
(click)="closeSideMenu(); resetBranch(); focusSearchBox()"
[routerLink]="customerOrdersRoutePath$ | async"
routerLinkActive="active"
sharedRegexRouterLinkActive="active"
sharedRegexRouterLinkActiveTest="^\/kunde\/\d*\/order"
(isActiveChange)="focusSearchBox()"
>
<span class="side-menu-group-item-icon">

View File

@@ -7,7 +7,6 @@ export { DialogOfString } from './models/dialog-of-string';
export { DialogSettings } from './models/dialog-settings';
export { DialogContentType } from './models/dialog-content-type';
export { KeyValueDTOOfStringAndString } from './models/key-value-dtoof-string-and-string';
export { IPublicUserInfo } from './models/ipublic-user-info';
export { ProblemDetails } from './models/problem-details';
export { ResponseArgsOfIEnumerableOfCountryDTO } from './models/response-args-of-ienumerable-of-country-dto';
export { CountryDTO } from './models/country-dto';
@@ -15,6 +14,7 @@ export { EntityDTOBaseOfCountryDTOAndICountry } from './models/entity-dtobase-of
export { EntityDTOBase } from './models/entity-dtobase';
export { EntityDTO } from './models/entity-dto';
export { EntityStatus } from './models/entity-status';
export { CRUDA } from './models/cruda';
export { ResponseArgsOfInputDTO } from './models/response-args-of-input-dto';
export { InputDTO } from './models/input-dto';
export { InputType } from './models/input-type';
@@ -92,5 +92,8 @@ export { DiffDTO } from './models/diff-dto';
export { ResponseArgsOfIEnumerableOfEntityKeyValueDTOOfStringAndString } from './models/response-args-of-ienumerable-of-entity-key-value-dtoof-string-and-string';
export { EntityKeyValueDTOOfStringAndString } from './models/entity-key-value-dtoof-string-and-string';
export { ResponseArgsOfIEnumerableOfKeyValueDTOOfStringAndString } from './models/response-args-of-ienumerable-of-key-value-dtoof-string-and-string';
export { ResponseArgsOfCheckLoyaltyCardResult } from './models/response-args-of-check-loyalty-card-result';
export { CheckLoyaltyCardResult } from './models/check-loyalty-card-result';
export { LoyaltyCardStatus } from './models/loyalty-card-status';
export { ResponseArgsOfPayerDTO } from './models/response-args-of-payer-dto';
export { ResponseArgsOfShippingAddressDTO } from './models/response-args-of-shipping-address-dto';

View File

@@ -0,0 +1,15 @@
/* tslint:disable */
import { CustomerInfoDTO } from './customer-info-dto';
import { LoyaltyCardStatus } from './loyalty-card-status';
export interface CheckLoyaltyCardResult {
/**
* Customer
*/
customer?: CustomerInfoDTO;
/**
* Status
*/
status: LoyaltyCardStatus;
}

View File

@@ -0,0 +1,2 @@
/* tslint:disable */
export type CRUDA = 0 | 1 | 2 | 4 | 8 | 16;

View File

@@ -1,11 +1,14 @@
/* tslint:disable */
import { TouchedBase } from './touched-base';
import { CRUDA } from './cruda';
import { EntityStatus } from './entity-status';
export interface EntityDTO extends TouchedBase{
changed?: string;
created?: string;
cruda?: CRUDA;
id?: number;
pId?: string;
status?: EntityStatus;
uId?: string;
version?: number;
}

View File

@@ -8,4 +8,5 @@ export interface EntityDTOReferenceContainer extends TouchedBase{
id?: number;
pId?: string;
selected?: boolean;
uId?: string;
}

View File

@@ -1,7 +0,0 @@
/* tslint:disable */
export interface IPublicUserInfo {
alias?: string;
displayName?: string;
isAuthenticated: boolean;
username?: string;
}

View File

@@ -0,0 +1,6 @@
/* tslint:disable */
/**
* Kundenkartenstatus
*/
export type LoyaltyCardStatus = 0 | 1 | 2 | 4 | 8;

View File

@@ -0,0 +1,6 @@
/* tslint:disable */
import { ResponseArgs } from './response-args';
import { CheckLoyaltyCardResult } from './check-loyalty-card-result';
export interface ResponseArgsOfCheckLoyaltyCardResult extends ResponseArgs{
result?: CheckLoyaltyCardResult;
}

View File

@@ -1,11 +1,9 @@
/* tslint:disable */
import { DialogOfString } from './dialog-of-string';
import { IPublicUserInfo } from './ipublic-user-info';
export interface ResponseArgs {
dialog?: DialogOfString;
error: boolean;
invalidProperties?: {[key: string]: string};
message?: string;
requestId?: number;
userInfo?: IPublicUserInfo;
}

View File

@@ -9,7 +9,7 @@ import { map as __map, filter as __filter } from 'rxjs/operators';
import { ResponseArgsOfIEnumerableOfEntityKeyValueDTOOfStringAndString } from '../models/response-args-of-ienumerable-of-entity-key-value-dtoof-string-and-string';
import { ResponseArgsOfIEnumerableOfKeyValueDTOOfStringAndString } from '../models/response-args-of-ienumerable-of-key-value-dtoof-string-and-string';
import { ResponseArgsOfQuerySettingsDTO } from '../models/response-args-of-query-settings-dto';
import { ResponseArgsOfCheckLoyaltyCardResult } from '../models/response-args-of-check-loyalty-card-result';
@Injectable({
providedIn: 'root',
})
@@ -121,7 +121,7 @@ class LoyaltyCardService extends __BaseService {
*
* - `customerId`: PK Kunde (optional)
*/
LoyaltyCardCheckLoyaltyCardResponse(params: LoyaltyCardService.LoyaltyCardCheckLoyaltyCardParams): __Observable<__StrictHttpResponse<ResponseArgsOfQuerySettingsDTO>> {
LoyaltyCardCheckLoyaltyCardResponse(params: LoyaltyCardService.LoyaltyCardCheckLoyaltyCardParams): __Observable<__StrictHttpResponse<ResponseArgsOfCheckLoyaltyCardResult>> {
let __params = this.newParams();
let __headers = new HttpHeaders();
let __body: any = null;
@@ -141,7 +141,7 @@ class LoyaltyCardService extends __BaseService {
return this.http.request<any>(req).pipe(
__filter(_r => _r instanceof HttpResponse),
__map((_r) => {
return _r as __StrictHttpResponse<ResponseArgsOfQuerySettingsDTO>;
return _r as __StrictHttpResponse<ResponseArgsOfCheckLoyaltyCardResult>;
})
);
}
@@ -155,9 +155,9 @@ class LoyaltyCardService extends __BaseService {
*
* - `customerId`: PK Kunde (optional)
*/
LoyaltyCardCheckLoyaltyCard(params: LoyaltyCardService.LoyaltyCardCheckLoyaltyCardParams): __Observable<ResponseArgsOfQuerySettingsDTO> {
LoyaltyCardCheckLoyaltyCard(params: LoyaltyCardService.LoyaltyCardCheckLoyaltyCardParams): __Observable<ResponseArgsOfCheckLoyaltyCardResult> {
return this.LoyaltyCardCheckLoyaltyCardResponse(params).pipe(
__map(_r => _r.body as ResponseArgsOfQuerySettingsDTO)
__map(_r => _r.body as ResponseArgsOfCheckLoyaltyCardResult)
);
}
}

View File

@@ -0,0 +1,9 @@
import { DebounceSettings, debounce as lodashDebounce } from 'lodash';
export function debounce(wait: number, options?: DebounceSettings): MethodDecorator {
return (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>): TypedPropertyDescriptor<any> => {
const currentMethod = descriptor.value;
descriptor.value = lodashDebounce(currentMethod, wait, options);
return descriptor;
};
}

View File

@@ -1,4 +1,5 @@
export * from './contains-element';
export * from './debounce.decorator';
export * from './geo-distance';
export * from './hash';
export * from './is-array';

View File

@@ -114,6 +114,9 @@
"@shared/directives/*": [
"apps/shared/directives/*/src/public-api.ts"
],
"@shared/services/*": [
"apps/shared/services/*/src/public-api.ts"
],
"@shared/pipes/*": [
"apps/shared/pipes/*/src/public-api.ts"
],