Compare commits

...

23 Commits

Author SHA1 Message Date
Lorenz Hilpert
4b10dd96d9 Merge branch 'hotfix/abholfach-zubuchen-und-cover-items' 2024-11-19 13:50:36 +01:00
Lorenz Hilpert
1126e4f0c1 Import tapResponse alongside ComponentStore in pickup-shelf-details.store.ts 2024-11-19 13:50:15 +01:00
Lorenz Hilpert
e9f24a88d6 Refactor PickupShelfInDetailsComponent to use signals for customer number and update fetch logic 2024-11-19 13:48:33 +01:00
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
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
16 changed files with 255 additions and 114 deletions

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

@@ -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,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

@@ -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

@@ -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

@@ -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

@@ -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

@@ -1,4 +1,4 @@
import { Component, ChangeDetectionStrategy, inject, OnInit, AfterViewInit, ViewChild } from '@angular/core';
import { Component, ChangeDetectionStrategy, inject, OnInit, AfterViewInit, ViewChild, effect } from '@angular/core';
import { PickupShelfDetailsBaseComponent } from '../../pickup-shelf-details-base.component';
import { AsyncPipe, NgFor, NgIf } from '@angular/common';
import { PickUpShelfDetailsHeaderComponent } from '../../shared/pickup-shelf-details-header/pickup-shelf-details-header.component';
@@ -11,7 +11,7 @@ import { OnInitDirective } from '@shared/directives/element-lifecycle';
import { PickupShelfInNavigationService } from '@shared/services';
import { BehaviorSubject, asapScheduler, combineLatest } from 'rxjs';
import { distinctUntilChanged, map, shareReplay } from 'rxjs/operators';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
import { DBHOrderItemListItemDTO, KeyValueDTOOfStringAndString } from '@swagger/oms';
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
import { ActivatedRoute } from '@angular/router';
@@ -52,6 +52,8 @@ export class PickupShelfInDetailsComponent extends PickupShelfDetailsBaseCompone
order$ = this.store.order$;
$customerNumber = toSignal(this.store.customerNumber$);
orderItems$ = this.store.orderItems$.pipe(shareReplay(1));
noOrderItemsFound$ = this.store.noOrderItemsFound$;
@@ -105,6 +107,14 @@ export class PickupShelfInDetailsComponent extends PickupShelfDetailsBaseCompone
private _activatedRoute: ActivatedRoute,
) {
super();
effect(() => {
const customerNumber = this.$customerNumber();
if (customerNumber) {
this.store.fetchCoverOrderItems(customerNumber);
}
});
}
ngOnInit() {
@@ -124,11 +134,11 @@ export class PickupShelfInDetailsComponent extends PickupShelfDetailsBaseCompone
});
// Fix #4696 - Always Fetch Cover Order Items
this._activatedRoute.params.pipe(distinctUntilChanged(isEqual), takeUntilDestroyed(this.destroyRef)).subscribe((_) => {
if (!this.store.coverOrderItems || this.store.coverOrderItems.length === 0) {
this.store.fetchCoverOrderItems();
}
});
// this._activatedRoute.params.pipe(distinctUntilChanged(isEqual), takeUntilDestroyed(this.destroyRef)).subscribe((_) => {
// if (!this.store.coverOrderItems || this.store.coverOrderItems.length === 0) {
// this.store.fetchCoverOrderItems();
// }
// });
}
ngAfterViewInit() {

View File

@@ -1,4 +1,5 @@
import { ComponentStore, tapResponse } from '@ngrx/component-store';
import { PickupShelfDetailsState } from './pickup-shelf-details.state';
import { Observable, combineLatest } from 'rxjs';
import {
@@ -702,19 +703,10 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
return this.select(Selectors.selectLatestSmsNotificationDate2(orderItemSubsetId));
};
delayWhenCustomerNumberNotExists = delayWhen(() =>
this.customerNumber$.pipe(
filter((cn) => !!cn),
take(1),
),
);
fetchCoverOrderItems = this.effect((trigger$: Observable<void>) =>
fetchCoverOrderItems = this.effect((trigger$: Observable<string>) =>
trigger$.pipe(
this.delayWhenCustomerNumberNotExists,
tap(() => this.beforeFetchCoverOrderItems()),
withLatestFrom(this.customerNumber$),
switchMap(([_, customerNumber]) =>
switchMap((customerNumber) =>
this._pickupShelfIOService
.getOrderItemsByCustomerNumber({
customerNumber,

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

@@ -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

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