Merge branch 'develop' into feature/rd-navigation-shell

This commit is contained in:
Lorenz Hilpert
2023-04-18 14:11:34 +02:00
187 changed files with 1102 additions and 724 deletions

View File

@@ -45,6 +45,8 @@ export class DomainInStockService {
const key = this.getKey({ itemId, branchId });
this._addToInStockQueue({ itemId, branchId });
let _previousValue: InStock;
const sub = combineLatest([this._inStockMap, this._inStockFetchingMap])
.pipe(distinctUntilChanged(isEqual))
.subscribe(([inStockMap, inStockFetchingMap]) => {
@@ -54,7 +56,12 @@ export class DomainInStockService {
inStock: inStockMap[key],
fetching: inStockFetchingMap[key] ?? false,
};
obs.next(inStock);
if (!isEqual(inStock, _previousValue)) {
obs.next(inStock);
}
_previousValue = inStock;
});
return () => {
sub.unsubscribe();

View File

@@ -447,7 +447,7 @@ export class DomainRemissionService {
* Create a new receipt for the given return/remission
* @param returnId Return ID
* @param receiptNumber Receipt number
* @returns ReturnDTO - ShippingDocument
* @returns ReceiptDTO
*/
async createReceipt(returnDTO: ReturnDTO, receiptNumber?: string): Promise<ReceiptDTO> {
const stock = await this._getStock();
@@ -471,14 +471,41 @@ export class DomainRemissionService {
return receipt;
}
async completeReceipt(returnId: number, receiptId: number, packageCode: string): Promise<ReceiptDTO> {
/**
* Create a new Package and assign it to a receipt
* @param returnId Return ID
* @param receiptId Receipt ID
* @param packageNumber Packagenumber
* @returns ReceiptDTO
*/
async createReceiptAndAssignPackage({
returnId,
receiptId,
packageNumber,
}: {
returnId: number;
receiptId: number;
packageNumber: string;
}): Promise<ReceiptDTO> {
const response = await this._returnService
.ReturnCreateAndAssignPackage({
returnId,
receiptId,
data: {
packageNumber,
},
})
.toPromise();
const receipt: ReceiptDTO = response.result;
return receipt;
}
async completeReceipt(returnId: number, receiptId: number): Promise<ReceiptDTO> {
const res = await this._returnService
.ReturnFinalizeReceipt({
returnId,
receiptId,
data: {
packageCode,
},
data: {},
})
.toPromise();

View File

@@ -41,7 +41,7 @@
"rootUrl": "https://filialinformationsystem-test.paragon-systems.de/eiswebapi/v1"
},
"@swagger/remi": {
"rootUrl": "https://isa-test.paragon-data.net/inv/v1"
"rootUrl": "https://isa-test.paragon-data.net/inv/v6"
},
"@swagger/wws": {
"rootUrl": "https://isa-test.paragon-data.net/wws/v1"

View File

@@ -8,9 +8,8 @@
},
"@core/auth": {
"issuer": "https://sso-test.paragon-data.de",
"clientId": "hug-isa",
"responseType": "id_token token",
"oidc": true,
"clientId": "isa-client",
"responseType": "code",
"scope": "openid profile cmf_user isa-isa-webapi isa-checkout-webapi isa-cat-webapi isa-ava-webapi isa-crm-webapi isa-review-webapi isa-kpi-webapi isa-oms-webapi isa-nbo-webapi isa-print-webapi eis-service isa-inv-webapi isa-wws-webapi"
},
"@core/logger": {
@@ -41,7 +40,7 @@
"rootUrl": "https://filialinformationsystem-integration.paragon-systems.de/eiswebapi/v1"
},
"@swagger/remi": {
"rootUrl": "https://isa-integration.paragon-data.net/inv/v1"
"rootUrl": "https://isa-integration.paragon-data.net/inv/v6"
},
"@swagger/wws": {
"rootUrl": "https://isa-integration.paragon-data.net/wws/v1"

View File

@@ -42,7 +42,7 @@
"rootUrl": "https://filialinformationsystem-test.paragon-systems.de/eiswebapi/v1"
},
"@swagger/remi": {
"rootUrl": "https://isa-test.paragon-data.net/inv/v1"
"rootUrl": "https://isa-test.paragon-data.net/inv/v6"
},
"@swagger/wws": {
"rootUrl": "https://isa-test.paragon-data.net/wws/v1"

View File

@@ -41,7 +41,7 @@
"rootUrl": "https://filialinformationsystem.paragon-systems.de/eiswebapi/v1"
},
"@swagger/remi": {
"rootUrl": "https://isa.paragon-systems.de/inv/v1"
"rootUrl": "https://isa.paragon-systems.de/inv/v6"
},
"@swagger/wws": {
"rootUrl": "https://isa.paragon-data.net/wws/v1"
@@ -69,6 +69,6 @@
},
"checkForUpdates": 3600000,
"licence": {
"scandit": ""
"scandit": "AfHi/mY+RbwJD5nC7SuWn3I14pFUOfSbQ2QG//4aV3zWQjwix30kHqsqraA8ZiipDBql8YlwIyV6VPBMUiAX4s9YHDxHHsWwq2BUB3ImzDEcU1jmMH/5yakGUYpCQ68D0iZ8SG9sS0QBb3iFdCHc1r9DFr1cMTxM7zOvb/AUoIVmieHZXnx9ioUgCvczsLiuX3hwvTW3lhbvJ4uUyqTWK4sWFVwoY4AIWSFrPwwrkV2DksMKT5fMJT3GWgPypvTIGwWvpRfLWwKlc1Z3ckyb84khsnaWD2wr+hdgu/K8YIMmgGszm5KIZ/G05YfDNZtQ4jby+5RZvQwWR8rxM35rJgf73OkMSpuL9jw3T0TTAlvpkGRLzVVuCw9VjlBLqfPNEZ6VsEwFuAla9IYUvFHCsjypg2J6UpxHXrTYmbsSu5Jm8frVfS5znPPTO9D/4rF6ZVv2PxY9PgUgJUvwMa/VMc/nse3RRRf8RGT4rUItfJDFO8pujD76vVEWq/KixQRoMdLgDLyxhsFVftkxqhZhyEfFZzsEy49LSojJ28vpHpBWLeCQBmnZ7JZ4C5yOQiqSQV/assBq2zJN2q+vCDp8qy5j1rED1SX5Ec7JpgpgnU4chLIf5Zn7bP/hNGT3pEYBuXeDXXN8ke1pcc3fc3m0FysDG0o56XVCUqImZ8Ezi8eujZciKDrWbtljhKTj7cnfuJx0sVHF6Bh5i4YfgA/Z+NL+MtH2EVIF67e6hEz6PWYTcoh3ybBaJfxb2FNvGJutNKg04GwMhYq6K2IddBt0fDiBt0SGM0oSBlUP3DKCUmXcf2a6ASbrcqv6Wz1jHt0pY4U8bEpg7qSbW3VDyvdPgyQ="
}
}

View File

@@ -41,7 +41,7 @@
"rootUrl": "https://filialinformationsystem-staging.paragon-systems.de/eiswebapi/v1"
},
"@swagger/remi": {
"rootUrl": "https://isa-staging.paragon-systems.de/inv/v1"
"rootUrl": "https://isa-staging.paragon-systems.de/inv/v6"
},
"@swagger/wws": {
"rootUrl": "https://isa-staging.paragon-systems.de/wws/v1"
@@ -69,6 +69,6 @@
},
"checkForUpdates": 3600000,
"licence": {
"scandit": ""
"scandit": "AfHi/mY+RbwJD5nC7SuWn3I14pFUOfSbQ2QG//4aV3zWQjwix30kHqsqraA8ZiipDBql8YlwIyV6VPBMUiAX4s9YHDxHHsWwq2BUB3ImzDEcU1jmMH/5yakGUYpCQ68D0iZ8SG9sS0QBb3iFdCHc1r9DFr1cMTxM7zOvb/AUoIVmieHZXnx9ioUgCvczsLiuX3hwvTW3lhbvJ4uUyqTWK4sWFVwoY4AIWSFrPwwrkV2DksMKT5fMJT3GWgPypvTIGwWvpRfLWwKlc1Z3ckyb84khsnaWD2wr+hdgu/K8YIMmgGszm5KIZ/G05YfDNZtQ4jby+5RZvQwWR8rxM35rJgf73OkMSpuL9jw3T0TTAlvpkGRLzVVuCw9VjlBLqfPNEZ6VsEwFuAla9IYUvFHCsjypg2J6UpxHXrTYmbsSu5Jm8frVfS5znPPTO9D/4rF6ZVv2PxY9PgUgJUvwMa/VMc/nse3RRRf8RGT4rUItfJDFO8pujD76vVEWq/KixQRoMdLgDLyxhsFVftkxqhZhyEfFZzsEy49LSojJ28vpHpBWLeCQBmnZ7JZ4C5yOQiqSQV/assBq2zJN2q+vCDp8qy5j1rED1SX5Ec7JpgpgnU4chLIf5Zn7bP/hNGT3pEYBuXeDXXN8ke1pcc3fc3m0FysDG0o56XVCUqImZ8Ezi8eujZciKDrWbtljhKTj7cnfuJx0sVHF6Bh5i4YfgA/Z+NL+MtH2EVIF67e6hEz6PWYTcoh3ybBaJfxb2FNvGJutNKg04GwMhYq6K2IddBt0fDiBt0SGM0oSBlUP3DKCUmXcf2a6ASbrcqv6Wz1jHt0pY4U8bEpg7qSbW3VDyvdPgyQ="
}
}

View File

@@ -42,7 +42,7 @@
"rootUrl": "https://filialinformationsystem-test.paragon-systems.de/eiswebapi/v1"
},
"@swagger/remi": {
"rootUrl": "https://isa-test.paragon-data.net/inv/v1"
"rootUrl": "https://isa-test.paragon-data.net/inv/v6"
},
"@swagger/wws": {
"rootUrl": "https://isa-test.paragon-data.net/wws/v1"

View File

@@ -5,8 +5,9 @@ import { EnvironmentService } from '@core/environment';
import { DomainAvailabilityService, DomainInStockService } from '@domain/availability';
import { ProductListItemDTO } from '@swagger/wws';
import { DateAdapter } from '@ui/common';
import { debounceTime, map, shareReplay, switchMap } from 'rxjs/operators';
import { debounceTime, filter, map, shareReplay, switchMap } from 'rxjs/operators';
import { PriceUpdateComponentStore } from '../price-update.component.store';
import { ReplaySubject, combineLatest } from 'rxjs';
@Component({
selector: 'page-price-update-item',
@@ -16,8 +17,18 @@ import { PriceUpdateComponentStore } from '../price-update.component.store';
providers: [DatePipe],
})
export class PriceUpdateItemComponent {
private _item$ = new ReplaySubject<ProductListItemDTO>(1);
private _item: ProductListItemDTO;
@Input()
item: ProductListItemDTO;
get item() {
return this._item;
}
set item(value) {
this._item = value;
this._item$.next(value);
}
get publicationDate() {
if (!!this.item?.product?.publicationDate) {
@@ -40,21 +51,14 @@ export class PriceUpdateItemComponent {
defaultBranch$ = this._availability.getDefaultBranch();
inStock$ = this.defaultBranch$.pipe(
inStock$ = combineLatest([this.defaultBranch$, this._item$]).pipe(
debounceTime(100),
switchMap(
(defaultBranch) =>
this._stockService.getInStock$({
itemId: Number(this.item?.product?.catalogProductNumber),
branchId: defaultBranch?.id,
})
// TODO: Bugfixing INSTOCK
// .pipe(
// map((instock) => {
// this.item.product.ean === '9783551775559' ? console.log({ item: this.item, instock }) : '';
// return instock;
// })
// )
filter(([defaultBranch, item]) => !!defaultBranch && !!item),
switchMap(([defaultBranch, item]) =>
this._stockService.getInStock$({
itemId: Number(item?.product?.catalogProductNumber),
branchId: defaultBranch?.id,
})
),
shareReplay(1)
);

View File

@@ -224,7 +224,7 @@
<div class="product-actions">
<button *ngIf="!(store.isDownload$ | async)" class="cta-availabilities" (click)="showAvailabilities()">
Vorrätig in anderer Filiale
Vorrätig in anderer Filiale?
</button>
<button
class="cta-continue"

View File

@@ -7,7 +7,7 @@ import { ItemDTO } from '@swagger/cat';
import { DateAdapter } from '@ui/common';
import { isEqual } from 'lodash';
import { combineLatest } from 'rxjs';
import { debounceTime, switchMap, map, tap, shareReplay } from 'rxjs/operators';
import { debounceTime, switchMap, map, shareReplay, filter } from 'rxjs/operators';
import { ArticleSearchService } from '../article-search.store';
export interface SearchResultItemComponentState {
@@ -110,9 +110,11 @@ export class SearchResultItemComponent extends ComponentStore<SearchResultItemCo
inStock$ = combineLatest([this.item$, this.selectedBranchId$, this.defaultBranch$]).pipe(
debounceTime(100),
filter(([item, branch, defaultBranch]) => !!item && !!defaultBranch),
switchMap(([item, branch, defaultBranch]) =>
this._stockService.getInStock$({ itemId: item.id, branchId: branch?.id ?? defaultBranch?.id })
)
),
shareReplay(1)
);
constructor(

View File

@@ -1,5 +1,11 @@
<shared-breadcrumb class="my-4" [key]="activatedProcessId$ | async" [tags]="['catalog']">
<shared-branch-selector [branchType]="1" [value]="selectedBranch$ | async" (valueChange)="patchProcessData($event)">
<shared-branch-selector
[filterCurrentBranch]="!!auth.hasRole('Store')"
[orderBy]="auth.hasRole('Store') ? 'distance' : 'name'"
[branchType]="1"
[value]="selectedBranch$ | async"
(valueChange)="patchProcessData($event)"
>
</shared-branch-selector>
</shared-breadcrumb>
<router-outlet></router-outlet>

View File

@@ -1,5 +1,6 @@
import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, OnDestroy, OnInit, Renderer2, ViewChild } from '@angular/core';
import { ApplicationService } from '@core/application';
import { AuthService } from '@core/auth';
import { EnvironmentService } from '@core/environment';
import { BranchSelectorComponent } from '@shared/components/branch-selector';
import { BreadcrumbComponent } from '@shared/components/breadcrumb';
@@ -30,11 +31,13 @@ export class PageCatalogComponent implements OnInit, AfterViewInit, OnDestroy {
constructor(
public application: ApplicationService,
private _uiModal: UiModalService,
public auth: AuthService,
private _environmentService: EnvironmentService,
private _renderer: Renderer2
) {}
ngOnInit() {
// this.auth.getClaims();
this.activatedProcessId$ = this.application.activatedProcessId$.pipe(map((processId) => String(processId)));
this.selectedBranch$ = this.activatedProcessId$.pipe(switchMap((processId) => this.application.getSelectedBranch$(Number(processId))));

View File

@@ -271,7 +271,7 @@ export class CheckoutReviewComponent extends ComponentStore<CheckoutReviewCompon
shoppingCart,
shoppingCartItems,
});
this.checkQuantityErrors(shoppingCartItems);
// this.checkQuantityErrors(shoppingCartItems);
},
(err) => {},
() => {}
@@ -282,15 +282,15 @@ export class CheckoutReviewComponent extends ComponentStore<CheckoutReviewCompon
)
);
checkQuantityErrors(shoppingCartItems: ShoppingCartItemDTO[]) {
shoppingCartItems.forEach((item) => {
if (item.features?.orderType === 'Abholung') {
this.setQuantityError(item, item.availability, item.quantity > item.availability?.inStock);
} else {
this.setQuantityError(item, item.availability, false);
}
});
}
// checkQuantityErrors(shoppingCartItems: ShoppingCartItemDTO[]) {
// shoppingCartItems.forEach((item) => {
// if (item.features?.orderType === 'Abholung') {
// this.setQuantityError(item, item.availability, item.quantity > item.availability?.inStock);
// } else {
// this.setQuantityError(item, item.availability, false);
// }
// });
// }
async updateBreadcrumb() {
await this.breadcrumb.addOrUpdateBreadcrumbIfNotExists({
@@ -485,7 +485,7 @@ export class CheckoutReviewComponent extends ComponentStore<CheckoutReviewCompon
})
.toPromise();
this.setQuantityError(shoppingCartItem, availability, availability?.inStock < quantity);
// this.setQuantityError(shoppingCartItem, availability, availability?.inStock < quantity);
break;
case 'Abholung':
availability = await this.availabilityService
@@ -563,7 +563,7 @@ export class CheckoutReviewComponent extends ComponentStore<CheckoutReviewCompon
},
})
.toPromise();
this.setQuantityError(shoppingCartItem, availability, false);
// this.setQuantityError(shoppingCartItem, availability, false);
} else if (availability) {
// Wenn das Ergebnis der Availability Abfrage keinen Preis zurückliefert (z.B. HFI Geschenkkarte), wird der Preis aus der
// Availability vor der Abfrage verwendet
@@ -594,16 +594,16 @@ export class CheckoutReviewComponent extends ComponentStore<CheckoutReviewCompon
this.loadingOnQuantityChangeById$.next(undefined);
}
setQuantityError(item: ShoppingCartItemDTO, availability: AvailabilityDTO, error: boolean) {
const quantityErrors: { [key: string]: string } = this.quantityError$.value;
if (error) {
quantityErrors[item.product.catalogProductNumber] = `${availability.inStock} Exemplar(e) sofort lieferbar`;
this.quantityError$.next({ ...quantityErrors });
} else {
delete quantityErrors[item.product.catalogProductNumber];
this.quantityError$.next({ ...quantityErrors });
}
}
// setQuantityError(item: ShoppingCartItemDTO, availability: AvailabilityDTO, error: boolean) {
// const quantityErrors: { [key: string]: string } = this.quantityError$.value;
// if (error) {
// quantityErrors[item.product.catalogProductNumber] = `${availability.inStock} Exemplar(e) sofort lieferbar`;
// this.quantityError$.next({ ...quantityErrors });
// } else {
// delete quantityErrors[item.product.catalogProductNumber];
// this.quantityError$.next({ ...quantityErrors });
// }
// }
// Bei unbekannten Kunden und DIG Bestellung findet ein Vergleich der Preise statt
compareDeliveryAndCatalogPrice(availability: AvailabilityDTO, orderType: string, shoppingCartItemPrice: number) {

View File

@@ -1,6 +1,7 @@
import { Component, ChangeDetectionStrategy, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { ApplicationService } from '@core/application';
import { AuthService } from '@core/auth';
import { BreadcrumbService } from '@core/breadcrumb';
import { BranchDTO } from '@swagger/checkout';
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
@@ -24,7 +25,8 @@ export class CustomerOrderComponent implements OnInit {
public application: ApplicationService,
private _activatedRoute: ActivatedRoute,
private _uiModal: UiModalService,
private _breadcrumb: BreadcrumbService
private _breadcrumb: BreadcrumbService,
public auth: AuthService
) {}
ngOnInit(): void {

View File

@@ -42,7 +42,7 @@ export class CreateB2BCustomerComponent extends AbstractCreateCustomer {
deviatingNameRequiredMarks: (keyof NameFormBlockData)[] = ['gender', 'firstName', 'lastName'];
deviatingNameValidationFns: Record<string, ValidatorFn[]> = {
gender: [Validators.required],
gender: [Validators.required, Validators.min(1)],
firstName: [Validators.required],
lastName: [Validators.required],
};

View File

@@ -26,7 +26,7 @@ export class CreateGuestCustomerComponent extends AbstractCreateCustomer {
nameValidationFns: Record<keyof NameFormBlockData, ValidatorFn[]> = {
firstName: [Validators.required],
lastName: [Validators.required],
gender: [Validators.required],
gender: [Validators.required, Validators.min(1)],
title: [],
};
@@ -45,7 +45,7 @@ export class CreateGuestCustomerComponent extends AbstractCreateCustomer {
deviatingNameRequiredMarks: (keyof NameFormBlockData)[] = ['gender', 'firstName', 'lastName'];
deviatingNameValidationFns: Record<string, ValidatorFn[]> = {
gender: [Validators.required],
gender: [Validators.required, Validators.min(1)],
firstName: [Validators.required],
lastName: [Validators.required],
};

View File

@@ -36,7 +36,7 @@ export class CreateP4MCustomerComponent extends AbstractCreateCustomer implement
nameValidationFns: Record<keyof NameFormBlockData, ValidatorFn[]> = {
firstName: [Validators.required],
lastName: [Validators.required],
gender: [Validators.required],
gender: [Validators.required, Validators.min(1)],
title: [],
};

View File

@@ -35,7 +35,7 @@ export class CreateStoreCustomerComponent extends AbstractCreateCustomer {
nameRequiredMarks: (keyof NameFormBlockData)[] = ['gender', 'firstName', 'lastName'];
nameValidationFns: Record<string, ValidatorFn[]> = {
gender: [Validators.required],
gender: [Validators.required, Validators.min(1)],
firstName: [Validators.required],
lastName: [Validators.required],
};

View File

@@ -25,7 +25,7 @@ export class CreateWebshopCustomerComponent extends AbstractCreateCustomer {
nameValidationFns: Record<keyof NameFormBlockData, ValidatorFn[]> = {
firstName: [Validators.required],
lastName: [Validators.required],
gender: [Validators.required],
gender: [Validators.required, Validators.min(1)],
title: [],
};

View File

@@ -29,7 +29,7 @@ export class UpdateP4MWebshopCustomerComponent extends AbstractCreateCustomer im
nameValidationFns: Record<keyof NameFormBlockData, ValidatorFn[]> = {
firstName: [Validators.required],
lastName: [Validators.required],
gender: [Validators.required],
gender: [Validators.required, Validators.min(1)],
title: [],
};

View File

@@ -24,7 +24,7 @@
</div>
</div>
<div class="package-details-list-item__product-details-2">
<div class="package-details-list-item__product-details-2" *ngIf="showStockInfos$ | async">
<div class="package-details-list-item__inventory-quantity py-2">
<div class="grow">
<ng-container *ngIf="showStockInfoTooltip$ | async">
@@ -52,7 +52,7 @@
Filialbestand
</div>
<div class="w-16">
<span class="filialbestand isa-label bg-accent-green px-2 font-bold">{{ inStock$ | async }} x</span>
<span class="filialbestand isa-label bg-accent-green px-2 font-bold">{{ inStock$ | async | max: 0 }} x</span>
</div>
</div>
<div class="package-details-list-item__package-quantity">

View File

@@ -1,6 +1,7 @@
import { fakeAsync } from '@angular/core/testing';
import { ProductImagePipe } from '@cdn/product-image';
import { createComponentFactory, Spectator } from '@ngneat/spectator';
import { MathPipesModule } from '@shared/pipes/math';
import { ArrivalStatus } from '@swagger/wws';
import { UiCommonModule } from '@ui/common';
import { UiTooltipModule } from '@ui/tooltip';
@@ -16,7 +17,7 @@ describe('PackageDetailsListItemComponent', () => {
const createComponent = createComponentFactory({
component: PackageDetailsListItemComponent,
imports: [UiCommonModule, UiTooltipModule],
imports: [UiCommonModule, UiTooltipModule, MathPipesModule],
declarations: [MockPipe(ProductImagePipe, (value) => `base/karma/assets/unit-test.svg#${value}`)],
});

View File

@@ -26,6 +26,8 @@ export class PackageDetailsListItemComponent implements OnChanges {
showStockInfoTooltip$ = this._store.arrivalStatus$.pipe(map((arrivalStatus) => arrivalStatus === 0));
showStockInfos$ = this._store.arrivalStatus$.pipe(map((arrivalStatus) => arrivalStatus !== 8));
constructor(private _store: PackageDetailsListStore) {}
ngOnChanges({ item }: SimpleChanges): void {

View File

@@ -5,7 +5,7 @@
class="mb-[2px]"
[item]="item"
*cdkVirtualFor="let item of items$ | async; trackBy: trackByItemId; let first = first"
[light]="!first"
[light]="!first || arrivalStatus == 8"
></page-package-details-list-item>
<div class="h-[100px]" *ngIf="hasActions"></div>
</cdk-virtual-scroll-viewport>

View File

@@ -36,13 +36,6 @@ describe('PackageDetailsListComponent', () => {
expect(spectator.component.items).toEqual(items);
});
it('should call store.setItems and loadStockInfos when items are set', () => {
const items = [{ id: '1' }, { id: '2' }] as PackageItemDTO[];
const setItemsSpy = spyOn(packageDetailsListStore, 'setItems');
spectator.component.items = items;
expect(setItemsSpy).toHaveBeenCalledWith(items);
});
it('should not call patchState and loadStockInfos when items are set to the same value', () => {
const items = [{ id: '1' }, { id: '2' }] as PackageItemDTO[];
spyOnProperty(spectator.component, 'items', 'get').and.returnValue(items);

View File

@@ -30,7 +30,6 @@ export class PackageDetailsListComponent implements OnChanges {
}
set items(value: PackageItemDTO[]) {
if (isEqual(this.items, value)) return;
this._store.setItems(value ?? []);
}
@Input()
@@ -48,10 +47,14 @@ export class PackageDetailsListComponent implements OnChanges {
constructor(private _store: PackageDetailsListStore) {}
ngOnChanges({ height }: SimpleChanges) {
ngOnChanges({ height, arrivalStatus, items }: SimpleChanges) {
if (height) {
this.checkViewportSize();
}
if (arrivalStatus && items) {
this._store.setItems(items.currentValue ?? [], arrivalStatus.currentValue !== 8);
}
}
checkViewportSize() {

View File

@@ -8,9 +8,18 @@ import { ScrollingModule } from '@angular/cdk/scrolling';
import { UiTooltipModule } from '@ui/tooltip';
import { UiCommonModule } from '@ui/common';
import { PackageInspectionPipesModule } from '@shared/pipes/package-inspection';
import { MathPipesModule } from '@shared/pipes/math';
@NgModule({
imports: [CommonModule, ProductImageModule, PackageInspectionPipesModule, ScrollingModule, UiTooltipModule, UiCommonModule],
imports: [
CommonModule,
ProductImageModule,
PackageInspectionPipesModule,
ScrollingModule,
UiTooltipModule,
UiCommonModule,
MathPipesModule,
],
exports: [PackageDetailsListComponent, PackageDetailsListItemComponent],
declarations: [PackageDetailsListComponent, PackageDetailsListItemComponent],
})

View File

@@ -124,10 +124,13 @@ export class PackageDetailsListStore extends ComponentStore<PackageDetailsListSt
console.error(error);
};
setItems(items: PackageItemDTO[]) {
setItems(items: PackageItemDTO[], loadStockInfos: boolean) {
this.patchState({ items });
if (items.length === 0) return;
this.loadStockInfos(items);
if (loadStockInfos) {
this.loadStockInfos(items);
}
}
setArrivalStatus(arrivalStatus: ArrivalStatus) {

View File

@@ -21,7 +21,7 @@
korrekt?
</p>
</div>
<div class="bg-white" *ngSwitchCase="'Fehlt'">
<div class="bg-white" *ngSwitchCa se="'Fehlt'">
<p class="text-center text-xl py-10">
Prüfen Sie bitte stichprobenartig den Filialbestand <br />
des dargestellten Artikels. Ist der angezeigte Filialbestand <br />
@@ -39,10 +39,18 @@
{{ packageDetails.package.deliveryNoteNumber }}
</div>
<div class="col-span-3">
Filialstopp
<span class="font-bold ml-2">
{{ packageDetails.package.area }}
</span>
<ng-container *ngIf="packageDetails.package.arrivalStatus !== 8; else irrlauferTmplt">
Filialstopp
<span class="font-bold ml-2">
{{ packageDetails.package.area }}
</span>
</ng-container>
<ng-template #irrlauferTmplt>
Filiale
<span class="font-bold ml-2">
{{ packageDetails.package.misrouted | split: ':' | at: 1 }}
</span>
</ng-template>
</div>
<div class="text-right">
<ng-container *ngIf="(packageDetails.package.arrivalStatus | arrivalStatus) === 'Fehlt'">

View File

@@ -8,6 +8,8 @@ import { UiTooltipModule } from '@ui/tooltip';
import { UiCommonModule } from '@ui/common';
import { ElementLifecycleModule } from '@shared/directives/element-lifecycle';
import { PackageInspectionPipesModule } from '@shared/pipes/package-inspection';
import { StringPipesModule } from '@shared/pipes/string';
import { ArrayPipesModule } from '@shared/pipes/array';
@NgModule({
imports: [
@@ -18,6 +20,8 @@ import { PackageInspectionPipesModule } from '@shared/pipes/package-inspection';
UiTooltipModule,
UiCommonModule,
ElementLifecycleModule,
StringPipesModule,
ArrayPipesModule,
],
exports: [PackageDetailsComponent],
declarations: [PackageDetailsComponent],

View File

@@ -3,7 +3,7 @@ import { ActivatedRoute, Router } from '@angular/router';
import { BreadcrumbService } from '@core/breadcrumb';
import { Config } from '@core/config';
import { DomainRemissionService } from '@domain/remission';
import { ReturnDTO } from '@swagger/remi';
import { ReceiptDTO, ReturnDTO } from '@swagger/remi';
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
import { UiSearchboxNextComponent } from '@ui/searchbox';
import { Subject } from 'rxjs';
@@ -52,10 +52,9 @@ export class CreateRemissionComponent implements OnInit {
const returnGroup = this._activatedRoute.snapshot.params?.returnGroup;
const supplier = await this.getSupplier();
const returnDTO = await this.createReturn(supplier.id, returnGroup);
const receipt = await this.createReceipt({ returnDTO, receiptNumber });
if (receipt) {
await this.navigateToFinishShippingDocument(returnDTO.id, receipt.id);
const returnReceipt = await this.createReturnAndReceipt(supplier.id, returnGroup, receiptNumber);
if (returnReceipt) {
await this.navigateToFinishShippingDocument(returnReceipt);
} else {
return undefined;
}
@@ -71,16 +70,25 @@ export class CreateRemissionComponent implements OnInit {
return suppliers.find((s) => s.id === this.supplierId);
}
async createReturn(supplierId: number, returnGroup: string) {
return await this._domainRemissionService.createReturn(supplierId, returnGroup);
async createReturnAndReceipt(
supplierId: number,
returnGroup: string,
receiptNumber: string
): Promise<{ returnDto: ReturnDTO; receiptDto: ReceiptDTO }> {
try {
const returnDto = await this._domainRemissionService.createReturn(supplierId, returnGroup);
const receiptDto = await this._domainRemissionService.createReceipt(returnDto, receiptNumber);
return {
returnDto,
receiptDto,
};
} catch (error) {
this._modal.error('Fehler beim Erstellen der Remission', error);
}
}
async createReceipt({ returnDTO, receiptNumber }: { returnDTO: ReturnDTO; receiptNumber?: string }) {
return await this._domainRemissionService.createReceipt(returnDTO, receiptNumber);
}
async navigateToFinishShippingDocument(returnId: number, receiptId: number) {
await this._router.navigate(['/filiale', 'remission', returnId, 'finish-shipping-document', receiptId], {
async navigateToFinishShippingDocument({ returnDto, receiptDto }: { returnDto: ReturnDTO; receiptDto: ReceiptDTO }) {
await this._router.navigate(['/filiale', 'remission', returnDto.id, 'finish-shipping-document', receiptDto.id], {
queryParams: { ...this._activatedRoute.snapshot.queryParams, supplier: this.supplierId, source: this.source },
});
}

View File

@@ -2,10 +2,11 @@ import { ChangeDetectionStrategy, Component, OnDestroy, OnInit, ViewChild } from
import { ActivatedRoute, Router } from '@angular/router';
import { BreadcrumbService } from '@core/breadcrumb';
import { Config } from '@core/config';
import { DomainRemissionService } from '@domain/remission';
import { DialogModel, UiDialogModalComponent, UiModalService } from '@ui/modal';
import { UiSearchboxNextComponent } from '@ui/searchbox';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { first, takeUntil } from 'rxjs/operators';
@Component({
selector: 'page-finish-shipping-document',
@@ -35,12 +36,17 @@ export class FinishShippingDocumentComponent implements OnInit, OnDestroy {
return Number(this._activatedRoute?.snapshot?.params?.returnId);
}
get receiptId(): number {
return Number(this._activatedRoute?.snapshot?.params?.receiptId);
}
constructor(
private _activatedRoute: ActivatedRoute,
private _modal: UiModalService,
private _router: Router,
private _breadcrumb: BreadcrumbService,
private _config: Config
private _config: Config,
private _remissionService: DomainRemissionService
) {}
ngOnInit() {
@@ -53,6 +59,7 @@ export class FinishShippingDocumentComponent implements OnInit, OnDestroy {
}
search(query: string) {
this.hint$.next('');
if (!query) {
this.hint$.next('Ungültige Eingabe');
return;
@@ -77,6 +84,7 @@ export class FinishShippingDocumentComponent implements OnInit, OnDestroy {
modal.afterClosed$.pipe(takeUntil(this._onDestroy$)).subscribe(async (result) => {
if (result?.data === 'correct') {
await this.createReceiptAndAssignPackageNumber(query);
await this.navigateToRemissionList(query);
} else if (result?.data === 'rescan') {
this.searchboxComponent.clear();
@@ -90,14 +98,28 @@ export class FinishShippingDocumentComponent implements OnInit, OnDestroy {
});
}
async createReceiptAndAssignPackageNumber(packageNumber: string) {
const returnDTO = await this._remissionService.getReturn(this.returnId).pipe(first()).toPromise();
// const receipt = await this._remissionService.createReceipt(returnDTO, this.receiptId);
try {
return await this._remissionService.createReceiptAndAssignPackage({
returnId: returnDTO.id,
receiptId: this.receiptId,
packageNumber,
});
} catch (error) {
this._modal.error('Fehler beim Speichern der Wannennummer', error);
}
}
addBreadcrumbIfNotExists() {
const returnId = +this._activatedRoute.snapshot.params?.returnId;
const receiptId = +this._activatedRoute.snapshot.params?.receiptId;
const receiptNumber = this._activatedRoute.snapshot.params?.receiptNumber;
this._breadcrumb.addBreadcrumbIfNotExists({
key: this._config.get('process.ids.remission'),
name: 'Wannennummer scannen',
path: `/filiale/remission/${returnId}/finish-shipping-document/${receiptId}`,
path: `/filiale/remission/${returnId}/finish-shipping-document/${receiptNumber}`,
params: this._activatedRoute.snapshot.queryParams,
section: 'branch',
tags: ['remission', 'finish-shipping-document'],

View File

@@ -1,4 +1,4 @@
import { Component, ChangeDetectionStrategy, Input, OnDestroy } from '@angular/core';
import { Component, ChangeDetectionStrategy, Input, OnDestroy, Host } from '@angular/core';
import { DomainRemissionService, RemissionListItem } from '@domain/remission';
import { RemissionPlacementType } from '@isa/remission';
import {
@@ -8,12 +8,13 @@ import {
ReturnItemDTO,
ReturnSuggestionDTO,
} from '@swagger/remi';
import { DialogModel, UiDialogModalComponent, UiErrorModalComponent, UiModalService } from '@ui/modal';
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
import { mapFromReturnItemDTO, mapFromReturnSuggestionDTO } from 'apps/domain/remission/src/lib/mappings';
import { BehaviorSubject, Subject } from 'rxjs';
import { first, takeUntil } from 'rxjs/operators';
import { AddProductToShippingDocumentModalComponent } from '../../modals/add-product-to-shipping-document-modal/add-product-to-shipping-document-modal.component';
import { RemissionListComponentStore } from '../remission-list.component-store';
import { RemissionListComponent } from '../remission-list.component';
@Component({
selector: 'page-remission-list-item',
@@ -52,12 +53,13 @@ export class RemissionListItemComponent implements OnDestroy {
return !!this.returnDto && (returnItem?.descendantOf?.enabled || this.item?.dto?.impediment);
}
loading$ = new BehaviorSubject<boolean>(false);
loading$ = this._listComponent.remittingItem$.asObservable();
constructor(
private _modal: UiModalService,
private _remissionService: DomainRemissionService,
private _store: RemissionListComponentStore
private _store: RemissionListComponentStore,
@Host() private _listComponent: RemissionListComponent
) {}
ngOnDestroy() {
@@ -90,32 +92,14 @@ export class RemissionListItemComponent implements OnDestroy {
}
remit() {
const modal = this._modal.open({
content: UiDialogModalComponent,
title: 'Remittieren',
data: {
content: `Sie sind gerade dabei alle ${this.item.remissionQuantity} Exemplare von einem ${
this.item.placementType && this.item.placementType === 'Stapel' ? 'Stapel' : 'Leistungsplatz'
} zu\nremittieren. Sind wirklich alle Exemplare in ${
this.item.placementType && this.item.placementType === 'Stapel' ? 'dem Stapel' : 'der Leistung'
}?`,
handleCommand: false,
actions: [
{ label: 'Ja', selected: true, command: 'remit' },
{ label: 'Abbrechen', command: 'close' },
],
} as DialogModel,
});
modal.afterClosed$.pipe(takeUntil(this._onDestroy$)).subscribe((result) => {
if (result?.data === 'remit') {
this.addReturnItemOrSuggestion({ quantity: this.item.remissionQuantity });
}
});
this.addReturnItemOrSuggestion({ quantity: this.item.remissionQuantity });
}
async removeReturnItem() {
this.loading$.next(true);
if (this._listComponent.remittingItem$.value) {
return;
}
this._listComponent.remittingItem$.next(true);
try {
await this._remissionService.removeReturnItemFromList({ itemId: this.item?.dto?.id }).toPromise();
this._store.removeItem(this.item);
@@ -127,7 +111,7 @@ export class RemissionListItemComponent implements OnDestroy {
});
this.reload();
}
this.loading$.next(false);
this._listComponent.remittingItem$.next(true);
}
async addReturnItemOrSuggestion({
@@ -141,7 +125,10 @@ export class RemissionListItemComponent implements OnDestroy {
impedimentComment?: string;
remainingQuantity?: number;
}) {
this.loading$.next(true);
if (this._listComponent.remittingItem$.value) {
return;
}
this._listComponent.remittingItem$.next(true);
try {
let response: ValueTupleOfReceiptItemDTOAndReturnItemDTO | ValueTupleOfReceiptItemDTOAndReturnSuggestionDTO;
@@ -205,11 +192,14 @@ export class RemissionListItemComponent implements OnDestroy {
});
this.reload();
}
this.loading$.next(false);
this._listComponent.remittingItem$.next(false);
}
async returnImpediment() {
this.loading$.next(true);
if (this._listComponent.remittingItem$.value) {
return;
}
this._listComponent.remittingItem$.next(true);
let updatedDto: ReturnItemDTO | ReturnSuggestionDTO;
@@ -239,7 +229,7 @@ export class RemissionListItemComponent implements OnDestroy {
});
this.reload();
}
this.loading$.next(false);
this._listComponent.remittingItem$.next(false);
}
reload() {

View File

@@ -125,6 +125,8 @@ export class RemissionListComponent implements OnInit, OnDestroy {
showScrollArrow$ = new BehaviorSubject<boolean>(false);
remittingItem$ = new BehaviorSubject<boolean>(false);
constructor(
private readonly _remissionListStore: RemissionListComponentStore,
private readonly _remissionStore: RemissionComponentStore,

View File

@@ -23,10 +23,18 @@ const routes: Routes = [
path: 'list',
component: RemissionListComponent,
},
{
path: ':returnId/list',
component: RemissionListComponent,
},
{
path: ':returnId/:packageNumber/list',
component: RemissionListComponent,
},
{
path: ':returnId/shipping-document',
component: ShippingDocumentDetailsComponent,
},
{
path: ':returnId/:packageNumber/shipping-document',
component: ShippingDocumentDetailsComponent,

View File

@@ -16,7 +16,7 @@
<div class="text-center mt-8">
<a
[routerLink]="['/filiale', 'remission', returnId$ | async, 'list']"
[routerLink]="['/filiale', 'remission', returnId$ | async, packageNumber$ | async, 'list']"
class="bg-brand text-white font-bold text-lg outline-none rounded-full px-6 py-3"
>
Warenbegleitschein öffnen
@@ -27,7 +27,7 @@
<div class="actions">
<ng-container *ngIf="remissionStarted$ | async">
<a
[routerLink]="['/filiale', 'remission', returnId$ | async, packageNumber, 'list']"
[routerLink]="['/filiale', 'remission', returnId$ | async, packageNumber$ | async, 'list']"
[queryParams]="queryParams$ | async"
class="flex items-center bg-white font-bold text-lg px-6 py-3 rounded-full shadow-cta whitespace-nowrap"
>

View File

@@ -15,6 +15,7 @@ import { RemissionListComponentStore } from '../../remission-list/remission-list
export interface ShippingDocumentDetailsState {
remissionStarted?: boolean;
return: ReturnDTO;
packageNumber?: string;
}
@Component({
@@ -57,8 +58,8 @@ export class ShippingDocumentDetailsComponent extends ComponentStore<ShippingDoc
return this.select((s) => s.return).pipe(shareReplay());
}
get packageNumber() {
return this._activatedRoute?.snapshot?.params?.packageNumber;
get packageNumber$() {
return this.select((s) => s.packageNumber).pipe(shareReplay());
}
scrollPosition$ = this._breadcrumb.getBreadcrumbsByKeyAndTags$(this.processId, ['remission']).pipe(
@@ -124,7 +125,7 @@ export class ShippingDocumentDetailsComponent extends ComponentStore<ShippingDoc
}
async addOrUpdateBreadcrumbIfNotExists(returnDto: ReturnDTO) {
const packageNumber = returnDto?.receipts?.find((_) => true)?.data?.receiptNumber;
const packageNumber = await this.packageNumber$.pipe(first()).toPromise();
const params = await this.queryParams$.pipe(first()).toPromise();
if (packageNumber) {
const shortPackageNumber = this._shortReceiptNumberPipe.transform(packageNumber);
@@ -158,18 +159,18 @@ export class ShippingDocumentDetailsComponent extends ComponentStore<ShippingDoc
}
async complete() {
if (await this.completeReceipt(this.packageNumber)) {
if (await this.completeReceipt()) {
await this.completeReturn();
}
}
async completeReceipt(packageCode: string) {
async completeReceipt() {
const returnId = this.return?.id;
const receiptId = this.firstReceipt?.id;
if (receiptId) {
try {
await this._remissionService.completeReceipt(returnId, receiptId, packageCode);
await this._remissionService.completeReceipt(returnId, receiptId);
return true;
} catch (err) {
this._modal.open({
@@ -250,7 +251,12 @@ export class ShippingDocumentDetailsComponent extends ComponentStore<ShippingDoc
switchMap((id) => this._remissionService.getReturn(id)),
tapResponse(
(r: ReturnDTO) => {
const firstReceipt = r?.receipts?.find((_) => true)?.data;
const packageNumber =
firstReceipt?.packages?.find((_) => true)?.data?.packageNumber ?? this._activatedRoute?.snapshot?.params?.packageNumber ?? '';
this.setPackageNumber(packageNumber);
this.setReturn(r);
this.addOrUpdateBreadcrumbIfNotExists(r);
},
(err) => {
@@ -265,6 +271,11 @@ export class ShippingDocumentDetailsComponent extends ComponentStore<ShippingDoc
)
);
setPackageNumber = this.updater<string>((state, packageNumber) => ({
...state,
packageNumber,
}));
setReturn = this.updater<ReturnDTO>((state, r) => ({
...state,
return: r,

View File

@@ -1,6 +1,7 @@
import { CommonModule } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { FormsModule } from '@angular/forms';
import { AuthService } from '@core/auth';
import { DomainAvailabilityService } from '@domain/availability';
import { createComponentFactory, Spectator } from '@ngneat/spectator';
import { UiAutocompleteModule } from '@ui/autocomplete';
@@ -17,7 +18,7 @@ describe('BranchSelectorComponent', () => {
const createComponent = createComponentFactory({
component: BranchSelectorComponent,
imports: [UiCommonModule, CommonModule, FormsModule, UiIconModule, UiAutocompleteModule],
mocks: [IconRegistry, DomainAvailabilityService, UiModalService, HttpClient],
mocks: [IconRegistry, DomainAvailabilityService, UiModalService, HttpClient, AuthService],
});
beforeEach(() => {
@@ -46,13 +47,13 @@ describe('BranchSelectorComponent', () => {
});
});
describe('branchType', () => {
it('should set branchType based on Input value', () => {
const branchType = 4;
spectator.setInput('branchType', branchType);
expect(spectator.component.branchType).toBe(branchType);
});
});
// describe('branchType', () => {
// it('should set branchType based on Input value', () => {
// const branchType = 4;
// spectator.setInput('branchType', branchType);
// expect(spectator.component.branchType).toBe(branchType);
// });
// });
describe('registerOnChange()', () => {
it('should assign new fn to onChange', () => {
@@ -79,12 +80,6 @@ describe('BranchSelectorComponent', () => {
});
describe('ngOnInit()', () => {
it('should call initBranchType()', () => {
const initBranchTypeSpye = spyOn(spectator.component, 'initBranchType');
spectator.component.ngOnInit();
expect(initBranchTypeSpye).toHaveBeenCalled();
});
it('should call store.loadBranches()', () => {
spyOn(branchSelectorStoreMock, 'loadBranches');
spectator.component.ngOnInit();
@@ -100,16 +95,6 @@ describe('BranchSelectorComponent', () => {
});
});
describe('initBranchType()', () => {
it('should call store.setBranchType(this.branchType)', () => {
const branchType = 4;
spectator.setInput('branchType', branchType);
spyOn(branchSelectorStoreMock, 'setBranchType');
spectator.component.initBranchType();
expect(branchSelectorStoreMock.setBranchType).toHaveBeenCalledWith(branchType);
});
});
describe('initAutocomplete()', () => {
// it('should call complete.asObservable()', () => {
// const completeSpy = spyOn(spectator.component.complete, 'asObservable').and.returnValue(of('test'));

View File

@@ -20,9 +20,10 @@ import { UiAutocompleteComponent, UiAutocompleteModule } from '@ui/autocomplete'
import { UiCommonModule } from '@ui/common';
import { UiIconModule } from '@ui/icon';
import { isNaN } from 'lodash';
import { asapScheduler, combineLatest, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { asapScheduler, Subject } from 'rxjs';
import { takeUntil, withLatestFrom } from 'rxjs/operators';
import { BranchSelectorStore } from './branch-selector.store';
import { AuthService } from '@core/auth';
@Component({
selector: 'shared-branch-selector',
@@ -53,6 +54,38 @@ export class BranchSelectorComponent implements OnInit, OnDestroy, AfterViewInit
query$ = this.store.query$;
@Input()
set online(online: boolean) {
this.store.setOnline(online);
}
@Input()
set orderingEnabled(orderingEnabled: boolean) {
this.store.setOrderingEnabled(orderingEnabled);
}
@Input()
set shippingEnabled(shippingEnabled: boolean) {
this.store.setShippingEnabled(shippingEnabled);
}
@Input()
set filterCurrentBranch(filterCurrentBranch: boolean) {
this.store.setFilterCurrentBranch(filterCurrentBranch);
}
@Input()
set orderBy(orderBy: 'name' | 'distance') {
this.store.setOrderBy(orderBy);
}
// Für Zielfilialen dürfen nur BranchType === 1 Filialen in der Liste erscheinen
// Für Bestellfilialen und Zielfilialen gelten auch alle BranchTypes und kann undefined gelassen werden
@Input()
set branchType(branchType: BranchType) {
this.store.setBranchType(branchType);
}
@Input()
get value(): BranchDTO {
return this._value;
@@ -66,10 +99,6 @@ export class BranchSelectorComponent implements OnInit, OnDestroy, AfterViewInit
@Output() valueChange = new EventEmitter<BranchDTO>();
// Für Zielfilialen dürfen nur BranchType === 1 Filialen in der Liste erscheinen
// Für Bestellfilialen und Zielfilialen gelten auch alle BranchTypes und kann undefined gelassen werden
@Input() branchType?: BranchType;
@Input()
disabled = false;
@@ -86,7 +115,7 @@ export class BranchSelectorComponent implements OnInit, OnDestroy, AfterViewInit
return this.autocompleteComponent?.open ?? false;
}
constructor(public store: BranchSelectorStore, private _elementRef: ElementRef) {}
constructor(public store: BranchSelectorStore, private _auth: AuthService, private _elementRef: ElementRef) {}
writeValue(obj: any): void {
if (obj?.id) {
@@ -109,7 +138,6 @@ export class BranchSelectorComponent implements OnInit, OnDestroy, AfterViewInit
}
ngOnInit(): void {
this.initBranchType();
this.store.loadBranches();
}
@@ -122,20 +150,16 @@ export class BranchSelectorComponent implements OnInit, OnDestroy, AfterViewInit
this._onDestroy$.complete();
}
initBranchType() {
this.store.setBranchType(this.branchType);
}
initAutocomplete() {
combineLatest([this.complete, this.store.branches$])
.pipe(takeUntil(this._onDestroy$))
this.complete
.pipe(takeUntil(this._onDestroy$), withLatestFrom(this.store.branches$))
.subscribe(([query, branches]) =>
query?.length > 1 ? this.filterBranchesFn({ query, branches }) : this.store.setFilteredBranches(branches)
);
}
filterBranchesFn({ query, branches }: { query: string; branches: BranchDTO[] }) {
const filteredBranches = branches?.filter((branch) => this.filterFn({ query, branch }));
let filteredBranches = branches?.filter((branch) => this.filterFn({ query, branch }));
if (filteredBranches?.length > 0) {
this.store.setFilteredBranches(filteredBranches);
return;

View File

@@ -1,3 +1,4 @@
import { AuthService } from '@core/auth';
import { DomainAvailabilityService } from '@domain/availability';
import { OpenStreetMap } from '@external/openstreetmap';
import { createServiceFactory, createSpyObject, SpectatorService, SpyObject } from '@ngneat/spectator';
@@ -13,7 +14,7 @@ describe('BranchSelectorStore', () => {
const createService = createServiceFactory({
service: BranchSelectorStore,
mocks: [OpenStreetMap],
mocks: [OpenStreetMap, AuthService],
});
beforeEach(() => {
@@ -79,26 +80,26 @@ describe('BranchSelectorStore', () => {
});
});
describe('get branches', () => {
it('should return the branches', () => {
const branches = [{}, {}];
spectator.service.setBranches(branches);
expect(spectator.service.branches).toBe(branches);
});
});
// describe('get branches', () => {
// it('should return the branches', () => {
// const branches = [{}, {}];
// spectator.service.setBranches(branches);
// expect(spectator.service.branches).toBe(branches);
// });
// });
describe('get branches$', () => {
it('should return the branches$', () => {
const branches = [{}, {}];
spectator.service.setBranches(branches);
// describe('get branches$', () => {
// it('should return the branches$', () => {
// const branches = [{}, {}];
// spectator.service.setBranches(branches);
spectator.service.branches$
.subscribe((b) => {
expect(b).toBe(branches);
})
.unsubscribe();
});
});
// spectator.service.branches$
// .subscribe((b) => {
// expect(b).toBe(branches);
// })
// .unsubscribe();
// });
// });
describe('get selectedBranch', () => {
it('should return the selectedBranch', () => {
@@ -121,26 +122,26 @@ describe('BranchSelectorStore', () => {
});
});
describe('get branchType', () => {
it('should return the branchType', () => {
const branchType = 1;
spectator.service.setBranchType(branchType);
expect(spectator.service.branchType).toEqual(branchType);
});
});
// describe('get branchType', () => {
// it('should return the branchType', () => {
// const branchType = 1;
// spectator.service.setBranchType(branchType);
// expect(spectator.service.branchType).toEqual(branchType);
// });
// });
describe('get branchType$', () => {
it('should return the branchType$', () => {
const branchType = 1;
spectator.service.setBranchType(branchType);
// describe('get branchType$', () => {
// it('should return the branchType$', () => {
// const branchType = 1;
// spectator.service.setBranchType(branchType);
spectator.service.branchType$
.subscribe((bt) => {
expect(bt).toEqual(branchType);
})
.unsubscribe();
});
});
// spectator.service.branchType$
// .subscribe((bt) => {
// expect(bt).toEqual(branchType);
// })
// .unsubscribe();
// });
// });
describe('loadBranches', () => {
const branches = [{ id: 1 }, { id: 2 }];
@@ -160,14 +161,16 @@ describe('BranchSelectorStore', () => {
expect(availabilityServiceMock.getBranches).toHaveBeenCalled();
});
it('should call loadBranchesResponseFn({ response, selectedBranch, branchType })', () => {
it('should call loadBranchesResponseFn({ response, selectedBranch, branchType, currentBranch })', () => {
const selectedBranch = { id: 123 };
const branchType = 1;
const currentBranch = { id: 9 };
availabilityServiceMock.getDefaultBranch.and.returnValue(of(currentBranch));
spectator.service.setSelectedBranch(selectedBranch);
spectator.service.setBranchType(branchType);
const loadBranchesResponseFnSpy = spyOn(spectator.service, 'loadBranchesResponseFn');
spectator.service.loadBranches();
expect(loadBranchesResponseFnSpy).toHaveBeenCalledWith({ response: branches, selectedBranch, branchType });
expect(loadBranchesResponseFnSpy).toHaveBeenCalledWith({ response: branches, selectedBranch });
});
it('should call loadBranchesErrorFn(error) if error got thrown', () => {
@@ -191,42 +194,42 @@ describe('BranchSelectorStore', () => {
branchType = 1;
});
it('should call _filterBranches({ branches: response, branchType })', () => {
const filterBranchesSpy = spyOn<any>(spectator.service, '_filterBranches');
spectator.service.loadBranchesResponseFn({ response: branches, branchType });
expect(filterBranchesSpy).toHaveBeenCalledWith({ branches, branchType });
});
// it('should call _filter({ branches: response })', () => {
// const filterBranchesSpy = spyOn<any>(spectator.service, '_filter');
// spectator.service.loadBranchesResponseFn({ response: branches });
// expect(filterBranchesSpy).toHaveBeenCalledWith({ branches });
// });
it('should call setBranches() with branches after filtering', () => {
spyOn<any>(spectator.service, '_filterBranches').and.returnValue([{ id: 1 }]);
const setBranchesSpy = spyOn(spectator.service, 'setBranches');
spectator.service.loadBranchesResponseFn({ response: branches, branchType });
expect(setBranchesSpy).toHaveBeenCalledWith([{ id: 1 }]);
});
// it('should call setBranches() with branches after filtering', () => {
// spyOn<any>(spectator.service, '_filter').and.returnValue([{ id: 1 }]);
// const setBranchesSpy = spyOn(spectator.service, 'setBranches');
// spectator.service.loadBranchesResponseFn({ response: branches });
// expect(setBranchesSpy).toHaveBeenCalledWith([{ id: 1 }]);
// });
it('should call setBranches() with default [] if getBranches() return undefined', () => {
spyOn<any>(spectator.service, '_filterBranches').and.returnValue([]);
const setBranchesSpy = spyOn(spectator.service, 'setBranches');
spectator.service.loadBranchesResponseFn({ response: branches, branchType });
expect(setBranchesSpy).toHaveBeenCalledWith([]);
});
// it('should call setBranches() with default [] if getBranches() return undefined', () => {
// spyOn<any>(spectator.service, '_filter').and.returnValue([]);
// const setBranchesSpy = spyOn(spectator.service, 'setBranches');
// spectator.service.loadBranchesResponseFn({ response: branches });
// expect(setBranchesSpy).toHaveBeenCalledWith([]);
// });
it('should call setSelectedBranchId(selectedBranchId) if selectedBranch is set', () => {
const selectedBranch = { id: 123 };
const setSelectedBranchSpy = spyOn(spectator.service, 'setSelectedBranch');
spectator.service.loadBranchesResponseFn({ response: branches, selectedBranch, branchType });
spectator.service.loadBranchesResponseFn({ response: branches, selectedBranch });
expect(setSelectedBranchSpy).toHaveBeenCalledWith(selectedBranch);
});
it('should not call setSelectedBranch(selectedBranch) if selectedBranch is not set', () => {
const setSelectedBranchSpy = spyOn(spectator.service, 'setSelectedBranch');
spectator.service.loadBranchesResponseFn({ response: branches, branchType });
spectator.service.loadBranchesResponseFn({ response: branches });
expect(setSelectedBranchSpy).not.toHaveBeenCalled();
});
it('should call setFetching(false)', () => {
const setFetchingSpy = spyOn(spectator.service, 'setFetching');
spectator.service.loadBranchesResponseFn({ response: branches, branchType });
spectator.service.loadBranchesResponseFn({ response: branches });
expect(setFetchingSpy).toHaveBeenCalledWith(false);
});
});
@@ -321,24 +324,24 @@ describe('BranchSelectorStore', () => {
});
});
describe('_filterBranches()', () => {
it('should return branches based on filter criterias', () => {
const branches = [
{
id: 1,
branchType: 2 as BranchType,
},
{
id: 2,
isOnline: true,
isShippingEnabled: true,
isOrderingEnabled: true,
branchType: 1 as BranchType,
},
];
const branchType: BranchType = 1;
// describe('_filter()', () => {
// it('should return branches based on filter criterias', () => {
// const branches = [
// {
// id: 1,
// branchType: 2 as BranchType,
// },
// {
// id: 2,
// isOnline: true,
// isShippingEnabled: true,
// isOrderingEnabled: true,
// branchType: 1 as BranchType,
// },
// ];
// const branchType: BranchType = 1;
expect(spectator.service['_filterBranches']({ branches, branchType })).toEqual([branches[1]]);
});
});
// expect(spectator.service['_filter']({ branches, branchType })).toEqual([branches[1]]);
// });
// });
});

View File

@@ -1,4 +1,5 @@
import { Injectable } from '@angular/core';
import { AuthService } from '@core/auth';
import { DomainAvailabilityService } from '@domain/availability';
import { OpenStreetMap, OpenStreetMapParams, PlaceDto } from '@external/openstreetmap';
import { ComponentStore, tapResponse } from '@ngrx/component-store';
@@ -13,7 +14,62 @@ export interface BranchSelectorState {
branches: BranchDTO[];
filteredBranches: BranchDTO[];
selectedBranch?: BranchDTO;
branchType?: BranchType;
online?: boolean;
orderingEnabled?: boolean;
shippingEnabled?: boolean;
filterCurrentBranch?: boolean;
currentBranchNumber?: string;
orderBy?: 'name' | 'distance';
branchType?: number;
}
function branchSorterFn(a: BranchDTO, b: BranchDTO, userBranch: BranchDTO) {
return (
geoDistance(userBranch?.address?.geoLocation, a?.address?.geoLocation) -
geoDistance(userBranch?.address?.geoLocation, b?.address?.geoLocation)
);
}
function selectBranches(state: BranchSelectorState) {
if (!state?.branches) {
return [];
}
let branches = state.branches;
if (typeof state.online === 'boolean') {
branches = branches.filter((branch) => !!branch?.isOnline === state.online);
}
if (typeof state.orderingEnabled === 'boolean') {
branches = branches.filter((branch) => !!branch?.isOrderingEnabled === state.orderingEnabled);
}
if (typeof state.shippingEnabled === 'boolean') {
branches = branches.filter((branch) => !!branch?.isShippingEnabled === state.shippingEnabled);
}
if (typeof state.filterCurrentBranch === 'boolean' && typeof state.currentBranchNumber === 'string') {
branches = branches.filter((branch) => branch?.branchNumber !== state.currentBranchNumber);
}
if (typeof state.orderBy === 'string' && typeof state.currentBranchNumber === 'string') {
switch (state.orderBy) {
case 'name':
branches?.sort((branchA, branchB) => branchA?.name?.localeCompare(branchB?.name));
break;
case 'distance':
const currentBranch = state.branches?.find((b) => b?.branchNumber === state.currentBranchNumber);
branches?.sort((a: BranchDTO, b: BranchDTO) => branchSorterFn(a, b, currentBranch));
break;
}
}
if (typeof state.branchType === 'number') {
branches = branches.filter((branch) => branch?.branchType === state.branchType);
}
return branches;
}
@Injectable()
@@ -31,10 +87,10 @@ export class BranchSelectorStore extends ComponentStore<BranchSelectorState> {
readonly fetching$ = this.select((s) => s.fetching);
get branches() {
return this.get((s) => s.branches);
return this.get(selectBranches);
}
readonly branches$ = this.select((s) => s.branches);
readonly branches$ = this.select(selectBranches);
get filteredBranches() {
return this.get((s) => s.filteredBranches);
@@ -48,22 +104,24 @@ export class BranchSelectorStore extends ComponentStore<BranchSelectorState> {
readonly selectedBranch$ = this.select((s) => s.selectedBranch);
get branchType() {
return this.get((s) => s.branchType);
}
readonly branchType$ = this.select((s) => s.branchType);
constructor(
private _availabilityService: DomainAvailabilityService,
private _uiModal: UiModalService,
private _openStreetMap: OpenStreetMap
private _openStreetMap: OpenStreetMap,
auth: AuthService
) {
super({
query: '',
fetching: false,
filteredBranches: [],
branches: [],
online: true,
orderingEnabled: true,
shippingEnabled: true,
filterCurrentBranch: undefined,
currentBranchNumber: auth.getClaimByKey('branch_no'),
orderBy: 'name',
branchType: undefined,
});
}
@@ -72,9 +130,9 @@ export class BranchSelectorStore extends ComponentStore<BranchSelectorState> {
tap((_) => this.setFetching(true)),
switchMap(() =>
this._availabilityService.getBranches().pipe(
withLatestFrom(this.selectedBranch$, this.branchType$),
withLatestFrom(this.selectedBranch$),
tapResponse(
([response, selectedBranch, branchType]) => this.loadBranchesResponseFn({ response, selectedBranch, branchType }),
([response, selectedBranch]) => this.loadBranchesResponseFn({ response, selectedBranch }),
(error: Error) => this.loadBranchesErrorFn(error)
)
)
@@ -111,7 +169,7 @@ export class BranchSelectorStore extends ComponentStore<BranchSelectorState> {
perimeterSearchResponseFn = ({ response, branches }: { response: PlaceDto[]; branches: BranchDTO[] }) => {
const place = response?.find((_) => true);
const branch = this._findNearestBranchByPlace({ place, branches });
const filteredBranches = [...branches]?.sort((a: BranchDTO, b: BranchDTO) => this._branchSorterFn(a, b, branch))?.slice(0, 10);
const filteredBranches = [...branches]?.sort((a: BranchDTO, b: BranchDTO) => branchSorterFn(a, b, branch))?.slice(0, 10);
this.setFilteredBranches(filteredBranches ?? []);
};
@@ -120,18 +178,8 @@ export class BranchSelectorStore extends ComponentStore<BranchSelectorState> {
console.error('OpenStreetMap Request Failed! ', error);
};
loadBranchesResponseFn = ({
response,
selectedBranch,
branchType,
}: {
response: BranchDTO[];
selectedBranch?: BranchDTO;
branchType?: BranchType;
}) => {
const branches = this._filterBranches({ branches: response, branchType });
branches?.sort((branchA, branchB) => branchA?.name?.localeCompare(branchB?.name));
this.setBranches(branches ?? []);
loadBranchesResponseFn = ({ response, selectedBranch }: { response: BranchDTO[]; selectedBranch?: BranchDTO }) => {
this.setBranches(response ?? []);
if (selectedBranch) {
this.setSelectedBranch(selectedBranch);
}
@@ -178,10 +226,6 @@ export class BranchSelectorStore extends ComponentStore<BranchSelectorState> {
this.patchState({ fetching });
}
setBranchType(branchType: BranchType) {
this.patchState({ branchType });
}
formatBranch(branch?: BranchDTO) {
return branch ? (branch.key ? branch.key + ' - ' + branch.name : branch.name) : '';
}
@@ -195,25 +239,31 @@ export class BranchSelectorStore extends ComponentStore<BranchSelectorState> {
);
}
private _branchSorterFn(a: BranchDTO, b: BranchDTO, userBranch: BranchDTO) {
return (
geoDistance(userBranch?.address?.geoLocation, a?.address?.geoLocation) -
geoDistance(userBranch?.address?.geoLocation, b?.address?.geoLocation)
);
}
// Frontend-Seitige Filterung der Branches vom Backend (Filterkriterien wie bei PDP - Weitere Verfügbarkeiten Modal)
private _filterBranches({ branches, branchType }: { branches: BranchDTO[]; branchType: BranchType }): BranchDTO[] {
return branches?.filter((branch) => {
if (!!branchType) {
return branch && branch?.isOnline && branch?.isShippingEnabled && branch?.isOrderingEnabled && branch?.branchType === branchType;
} else {
return branch && branch?.isOnline && branch?.isShippingEnabled && branch?.isOrderingEnabled;
}
});
}
getBranchById(id: number): BranchDTO {
return this.branches.find((branch) => branch.id === id);
}
setOnline(online: boolean) {
this.patchState({ online });
}
setOrderingEnabled(orderingEnabled: boolean) {
this.patchState({ orderingEnabled });
}
setShippingEnabled(shippingEnabled: boolean) {
this.patchState({ shippingEnabled });
}
setFilterCurrentBranch(filterCurrentBranch: boolean) {
this.patchState({ filterCurrentBranch });
}
setOrderBy(orderBy: 'name' | 'distance') {
this.patchState({ orderBy });
}
setBranchType(branchType: BranchType) {
this.patchState({ branchType });
}
}

View File

@@ -81,7 +81,7 @@
<div class="value">{{ orderItem?.clientChannel | environmentChannel }}</div>
</div>
<div class="detail justify-space-between" [ngSwitch]="orderItem.processingStatus" data-detail-id="Geaendert">
<ng-container *ifRole="'Store'">
<ng-container *ifRole="'Store'; else dateCallCenter">
<ng-container *ngSwitchCase="16">
<ng-container *ngTemplateOutlet="vslLieferdatum"></ng-container>
</ng-container>
@@ -91,26 +91,48 @@
<ng-container *ngSwitchCase="128">
<ng-container *ngTemplateOutlet="abholfrist"></ng-container>
</ng-container>
<ng-container *ngSwitchDefault>
<div class="label">Geändert</div>
<div class="value">{{ orderItem?.processingStatusDate | date: 'dd.MM.yy | HH:mm' }} Uhr</div>
</ng-container>
</ng-container>
<ng-container *ngSwitchDefault>
<div class="label">Geändert</div>
<div class="value">{{ orderItem?.processingStatusDate | date: 'dd.MM.yy | HH:mm' }} Uhr</div>
</ng-container>
<ng-template #dateCallCenter>
<!-- orderType 1 === Abholung / Rücklage; orderType 2 === Versand / B2B-Versand; orderType 4 === Download (ist manchmal auch orderType 2) -->
<ng-container *ngIf="orderItem.orderType === 1; else changeDate">
<ng-container *ngSwitchCase="16">
<ng-container *ngTemplateOutlet="vslLieferdatum"></ng-container>
</ng-container>
<ng-container *ngSwitchCase="8192">
<ng-container *ngTemplateOutlet="vslLieferdatum"></ng-container>
</ng-container>
<ng-container *ngSwitchCase="128">
<ng-container *ngTemplateOutlet="abholfrist"></ng-container>
</ng-container>
</ng-container>
<ng-template #changeDate>
<div class="label">Geändert</div>
<div class="value">{{ orderItem?.processingStatusDate | date: 'dd.MM.yy | HH:mm' }} Uhr</div>
</ng-template>
</ng-template>
</div>
<div *ifRole="'Store'" class="detail" data-detail-id="Benachrichtigung">
<div class="label">Benachrichtigung</div>
<div class="value">{{ (notificationsChannel | notificationsChannel) || '-' }}</div>
</div>
<ng-container *ifRole="'CallCenter'">
<div *ngIf="!!digOrderNumber" class="detail" data-detail-id="Dig-Bestellnummer">
<div class="label">Dig-Bestell Nr.</div>
<div class="value">{{ digOrderNumber }}</div>
<ng-container *ifRole="'Store'; else notificationCallCenter">
<div class="detail" data-detail-id="Benachrichtigung">
<div class="label">Benachrichtigung</div>
<div class="value">{{ (notificationsChannel | notificationsChannel) || '-' }}</div>
</div>
</ng-container>
<ng-container *ifRole="'Store'">
<ng-template #notificationCallCenter>
<div *ngIf="orderItem.orderType === 1" class="detail" data-detail-id="Benachrichtigung">
<div class="label">Benachrichtigung</div>
<div class="value">{{ (notificationsChannel | notificationsChannel) || '-' }}</div>
</div>
</ng-template>
<ng-container *ifRole="'Store'; else preferredPickUpDateCallCenter">
<div
class="detail justify-space-between"
data-detail-id="Wunschdatum"
@@ -119,6 +141,23 @@
<ng-container *ngTemplateOutlet="preferredPickUpDate"></ng-container>
</div>
</ng-container>
<ng-template #preferredPickUpDateCallCenter>
<div
class="detail justify-space-between"
data-detail-id="Wunschdatum"
*ngIf="orderItem.orderType === 1 && (orderItem.processingStatus === 16 || orderItem.processingStatus === 8192)"
>
<ng-container *ngTemplateOutlet="preferredPickUpDate"></ng-container>
</div>
</ng-template>
<ng-container *ifRole="'CallCenter'">
<div *ngIf="!!digOrderNumber && orderItem.orderType !== 1" class="detail" data-detail-id="Dig-Bestellnummer">
<div class="label">Dig-Bestell Nr.</div>
<div class="value">{{ digOrderNumber }}</div>
</div>
</ng-container>
</div>
</div>

View File

@@ -13,7 +13,7 @@
}
.scroll-container {
max-height: 800px;
max-height: calc(100vh - 250px);
}
.log-entry {

View File

@@ -5,3 +5,8 @@
.package-count {
height: 53px;
}
a.read-only {
pointer-events: none;
cursor: default;
}

View File

@@ -8,8 +8,9 @@
class="h-[calc(100vh-420px)] scroll-bar"
(scrolledIndexChange)="scrollIndexChange.emit($event)"
>
<a [routerLink]="[package.id]" *cdkVirtualFor="let package of packages; trackBy: trackByFn">
<a [routerLink]="[package.id]" *cdkVirtualFor="let package of packages; trackBy: trackByFn" [class.read-only]="!navigationEnabled">
<page-package-list-item class="pt-px-2" [package]="package"></page-package-list-item>
</a>
<page-package-list-item-loader *ngIf="fetching"> </page-package-list-item-loader>
</cdk-virtual-scroll-viewport>

View File

@@ -3,6 +3,7 @@ import { PackageDTO2 } from '@swagger/wws';
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
import { asapScheduler, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';
@Component({
selector: 'page-package-list',
@@ -39,6 +40,16 @@ export class PackageListComponent implements AfterViewInit, OnDestroy {
@ViewChild(CdkVirtualScrollViewport, { static: true, read: CdkVirtualScrollViewport })
cdkVirtualScrollViewport: CdkVirtualScrollViewport;
private _navigationEnabled: BooleanInput = true;
@Input()
get navigationEnabled(): BooleanInput {
return coerceBooleanProperty(this._navigationEnabled);
}
set navigationEnabled(value: BooleanInput) {
this._navigationEnabled = value;
}
private _onDestroy$ = new Subject<void>();
constructor() {}

View File

@@ -28,10 +28,10 @@ export class PurchaseOptionsListHeaderComponent {
constructor(public store: PurchaseOptionsStore) {}
selectAll() {
// this.store.setSelectedForSelectableItems(true);
this.store.selectSelectableItems();
}
unselectAll() {
// this._store.setSelectedForSelectableItems(false);
this.store.resetSelectedItems();
}
}

View File

@@ -99,7 +99,16 @@
</div>
</div>
<ui-quantity-dropdown class="mt-2" [formControl]="quantityFormControl" [range]="maxSelectableQuantity$ | async"> </ui-quantity-dropdown>
<input *ngIf="(canAddResult$ | async)?.canAdd" class="fancy-checkbox mt-7" [formControl]="selectedFormControl" type="checkbox" />
<div class="pt-7">
<input
*ngIf="(canAddResult$ | async)?.canAdd"
class="fancy-checkbox"
[class.checked]="selectedFormControl?.value"
[formControl]="selectedFormControl"
type="checkbox"
/>
</div>
<span *ngIf="showMaxAvailableQuantity$ | async" class="font-bold text-[#BE8100] mt-[14px]">
{{ (availability$ | async)?.inStock }} Exemplare sofort lieferbar
</span>

View File

@@ -1,4 +1,4 @@
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy, TrackByFunction } from '@angular/core';
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy, TrackByFunction, HostBinding } from '@angular/core';
import { UiModalRef } from '@ui/modal';
import { PurchaseOptionsModalData } from './purchase-options-modal.data';
@@ -37,6 +37,11 @@ export class PurchaseOptionsModalComponent implements OnInit, OnDestroy {
return this._uiModalRef.data.type;
}
@HostBinding('attr.data-loading')
get fetchingData() {
return this.store.fetchingAvailabilities.length > 0;
}
items$ = this.store.items$;
purchasingOptions$ = this.store.getPurchaseOptionsInAvailabilities$;

View File

@@ -20,5 +20,6 @@
[ngModel]="undefined"
(ngModelChange)="setInStoreBranch($event)"
[branchType]="1"
[orderBy]="auth.hasRole('Store') ? 'distance' : 'name'"
></shared-branch-selector>
</div>

View File

@@ -1,5 +1,5 @@
import { CommonModule } from '@angular/common';
import { Component, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { Component, ChangeDetectionStrategy, ChangeDetectorRef, ElementRef } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { BranchSelectorComponent } from '@shared/components/branch-selector';
import { BranchNamePipe } from '@shared/pipes/branch';
@@ -7,6 +7,7 @@ import { BranchDTO } from '@swagger/checkout';
import { UiIconModule } from '@ui/icon';
import { PurchaseOptionsStore } from '../store';
import { BasePurchaseOptionDirective } from './base-purchase-option.directive';
import { AuthService } from '@core/auth';
@Component({
selector: 'app-in-store-purchase-options-tile',
@@ -15,15 +16,23 @@ import { BasePurchaseOptionDirective } from './base-purchase-option.directive';
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [CommonModule, UiIconModule, BranchSelectorComponent, FormsModule, BranchNamePipe],
host: { tabindex: '-1' },
})
export class InStorePurchaseOptionTileComponent extends BasePurchaseOptionDirective {
inStoreBranch$ = this.store.inStoreBranch$;
constructor(protected store: PurchaseOptionsStore, protected cdr: ChangeDetectorRef) {
constructor(
protected store: PurchaseOptionsStore,
protected cdr: ChangeDetectorRef,
public auth: AuthService,
private elementRef: ElementRef
) {
super('in-store');
}
setInStoreBranch(branch?: BranchDTO) {
this.setPurchaseOptions();
this.store.setInStoreBranch(branch);
this.elementRef.nativeElement.focus();
}
}

View File

@@ -20,5 +20,6 @@
[ngModel]="undefined"
(ngModelChange)="setPickupBranch($event)"
[branchType]="1"
[orderBy]="auth.hasRole('Store') ? 'distance' : 'name'"
></shared-branch-selector>
</div>

View File

@@ -1,5 +1,5 @@
import { CommonModule } from '@angular/common';
import { Component, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { Component, ChangeDetectionStrategy, ChangeDetectorRef, ElementRef } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { BranchSelectorComponent } from '@shared/components/branch-selector';
import { BranchNamePipe } from '@shared/pipes/branch';
@@ -7,6 +7,7 @@ import { BranchDTO } from '@swagger/checkout';
import { UiIconModule } from '@ui/icon';
import { PurchaseOptionsStore } from '../store';
import { BasePurchaseOptionDirective } from './base-purchase-option.directive';
import { AuthService } from '@core/auth';
@Component({
selector: 'app-pickup-purchase-options-tile',
@@ -15,15 +16,23 @@ import { BasePurchaseOptionDirective } from './base-purchase-option.directive';
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [CommonModule, UiIconModule, BranchSelectorComponent, FormsModule, BranchNamePipe],
host: { tabindex: '-1' },
})
export class PickupPurchaseOptionTileComponent extends BasePurchaseOptionDirective {
pickupBranch$ = this.store.pickupBranch$;
constructor(protected store: PurchaseOptionsStore, protected cdr: ChangeDetectorRef) {
constructor(
protected store: PurchaseOptionsStore,
protected cdr: ChangeDetectorRef,
public auth: AuthService,
private elementRef: ElementRef
) {
super('pickup');
}
setPickupBranch(branch?: BranchDTO) {
this.setPurchaseOptions();
this.store.setPickupBranch(branch);
this.elementRef.nativeElement.focus();
}
}

View File

@@ -2,6 +2,10 @@
@apply border border-solid border-[#C6CBD0] p-2 rounded w-[192px] h-[158px] grid grid-rows-3 cursor-pointer;
}
:host:focus {
@apply outline-none;
}
:host.selected {
@apply bg-[#D8DFE5] border-[#0556B4];
}

View File

@@ -38,11 +38,14 @@ export function getSelectedItemIds(state: PurchaseOptionsState): number[] {
}
export function getDefaultBranch(state: PurchaseOptionsState): Branch {
if (state.defaultBranch?.isOrderingEnabled === false) {
return undefined;
}
return state.defaultBranch;
}
export function getPickupBranch(state: PurchaseOptionsState): Branch {
const branch = state.pickupBranch || state.defaultBranch;
const branch = state.pickupBranch || getDefaultBranch(state);
if (branch?.branchType === 1) {
return branch;
@@ -52,7 +55,7 @@ export function getPickupBranch(state: PurchaseOptionsState): Branch {
}
export function getInStoreBranch(state: PurchaseOptionsState): Branch {
const branch = state.inStoreBranch || state.defaultBranch;
const branch = state.inStoreBranch || getDefaultBranch(state);
if (branch?.branchType === 1) {
return branch;
@@ -234,9 +237,9 @@ export function getPriceForPurchaseOption(itemId: number, purchaseOption: Purcha
const type = getType(state);
if (isItemDTO(item, type)) {
return item.catalogAvailability?.price ?? DEFAULT_PRICE_DTO;
return item?.catalogAvailability?.price ?? DEFAULT_PRICE_DTO;
} else {
return item.unitPrice ?? DEFAULT_PRICE_DTO;
return item?.unitPrice ?? DEFAULT_PRICE_DTO;
}
};
}

View File

@@ -1,5 +1,4 @@
import { Injectable } from '@angular/core';
import { ApplicationService } from '@core/application';
import { DomainAvailabilityService } from '@domain/availability';
import { DomainCheckoutService } from '@domain/checkout';
import {
@@ -12,27 +11,32 @@ import {
UpdateShoppingCartItemDTO,
} from '@swagger/checkout';
import { Observable } from 'rxjs';
import { map, shareReplay, take } from 'rxjs/operators';
import { map, shareReplay, switchMap, take, tap } from 'rxjs/operators';
import { Branch, ItemData } from './purchase-options.types';
import { memorize } from '@utils/common';
import { AuthService } from '@core/auth';
import { ApplicationService } from '@core/application';
@Injectable({ providedIn: 'root' })
export class PurchaseOptionsService {
constructor(
private _availabilityService: DomainAvailabilityService,
private _checkoutService: DomainCheckoutService,
private _appService: ApplicationService
private _auth: AuthService,
private _app: ApplicationService
) {}
getSelectedBranchForProcess(processId: number): Observable<Branch> {
return this._appService.getSelectedBranch$(processId).pipe(take(1), shareReplay(1));
return this._app.getSelectedBranch$(processId).pipe(take(1), shareReplay(1));
}
getCustomerFeatures(processId: number): Observable<Record<string, string>> {
return this._checkoutService.getCustomerFeatures({ processId }).pipe(take(1), shareReplay(1));
}
@memorize()
fetchDefaultBranch(): Observable<Branch> {
return this._availabilityService.getDefaultBranch();
return this.getBranch({ branchNumber: this._auth.getClaimByKey('branchNo') }).pipe(take(1), shareReplay(1));
}
fetchPickupAvailability(item: ItemData, quantity: number, branch: Branch): Observable<AvailabilityDTO> {
@@ -42,7 +46,7 @@ export class PurchaseOptionsService {
quantity,
item,
})
.pipe(map((res) => res[0]));
.pipe(map((res) => (Array.isArray(res) ? res[0] : undefined)));
}
fetchInStoreAvailability(item: ItemData, quantity: number, branch: Branch): Observable<AvailabilityDTO> {
@@ -143,4 +147,26 @@ export class PurchaseOptionsService {
update: payload,
});
}
@memorize({ comparer: (_) => true })
getBranches(): Observable<Branch[]> {
return this._availabilityService.getBranches().pipe(
map((branches) => {
return branches.filter((branch) => branch.isShippingEnabled == true);
}),
shareReplay(1)
);
}
getBranch(params: { id: number }): Observable<Branch>;
getBranch(params: { branchNumber: string }): Observable<Branch>;
getBranch(params: { id: number; branchNumber: string }): Observable<Branch>;
getBranch(params: { id?: number; branchNumber?: string }): Observable<Branch> {
return this.getBranches().pipe(
map((branches) => {
const branch = branches.find((branch) => branch.id == params.id || branch.branchNumber == params.branchNumber);
return branch;
})
);
}
}

View File

@@ -28,7 +28,7 @@ import { Observable } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { DEFAULT_PRICE_DTO, DEFAULT_PRICE_VALUE } from '../constants';
import { AddToShoppingCartDTO, EntityDTOContainerOfDestinationDTO, UpdateShoppingCartItemDTO } from '@swagger/checkout';
import { isEqual } from 'lodash';
import { isEqual, uniqueId } from 'lodash';
@Injectable()
export class PurchaseOptionsStore extends ComponentStore<PurchaseOptionsState> {
@@ -146,46 +146,41 @@ export class PurchaseOptionsStore extends ComponentStore<PurchaseOptionsState> {
});
}
addFetchingAvailability = this.updater((state, fetchState: FetchingAvailability) => ({
...state,
fetching: [...state.fetchingAvailabilities, fetchState],
}));
addFetchingAvailability = this.updater((state, fetchState: FetchingAvailability) => {
return {
...state,
fetchingAvailabilities: [...state.fetchingAvailabilities, fetchState],
};
});
removeFetchingAvailability = this.updater((state, fetchState: FetchingAvailability) => ({
...state,
fetching: state.fetchingAvailabilities.filter((item) => !isEqual(item, fetchState)),
}));
removeFetchingAvailability = this.updater((state, fetchState: FetchingAvailability) => {
return {
...state,
fetchingAvailabilities: state.fetchingAvailabilities.filter((f) => f.id !== fetchState.id),
};
});
async initialize({ items, processId, type }: PurchaseOptionsModalData) {
const branch = await this._service.getSelectedBranchForProcess(processId).toPromise();
const selectedBranch = await this._service.getSelectedBranchForProcess(processId).toPromise();
const defaultBranch = await this._service.fetchDefaultBranch().toPromise();
const customerFeatures = await this._service.getCustomerFeatures(processId).toPromise();
this.patchState({
processId: processId,
type: type,
items: items.map((item) => ({ ...item, quantity: item['quantity'] ?? 1 })),
defaultBranch: undefined,
pickupBranch: branch,
inStoreBranch: branch,
defaultBranch: selectedBranch ?? defaultBranch,
pickupBranch: selectedBranch,
inStoreBranch: selectedBranch,
customerFeatures,
});
await this._loadDefaultBranch();
await this._loadAvailabilities();
await this._loadCanAdd();
}
// #region Private funtions for loading and setting Branches and Availabilities
private async _loadDefaultBranch(): Promise<void> {
try {
const branch = await this._service.fetchDefaultBranch().toPromise();
this.patchState({ defaultBranch: branch });
} catch (err) {
console.error('_loadDefaultBranchError', err);
}
}
private async _loadAvailabilities() {
const items = this.items;
@@ -241,8 +236,9 @@ export class PurchaseOptionsStore extends ComponentStore<PurchaseOptionsState> {
const branch = this.pickupBranch;
if (!branch) return Promise.resolve();
const id = uniqueId('availability_');
try {
this.addFetchingAvailability({ itemId: itemData.sourceId, purchaseOption: 'pickup' });
this.addFetchingAvailability({ id, itemId: itemData.sourceId, purchaseOption: 'pickup' });
const res = await this._service.fetchPickupAvailability(itemData, itemData.quantity, branch).toPromise();
const availability: Availability = {
@@ -256,15 +252,16 @@ export class PurchaseOptionsStore extends ComponentStore<PurchaseOptionsState> {
console.error('_loadPickupAvailability', err);
}
this.removeFetchingAvailability({ itemId: itemData.sourceId, purchaseOption: 'pickup' });
this.removeFetchingAvailability({ id, itemId: itemData.sourceId, purchaseOption: 'pickup' });
}
private async _loadInStoreAvailability(itemData: ItemData) {
const branch = this.inStoreBranch;
if (!branch) return Promise.resolve();
const id = uniqueId('availability_');
try {
this.addFetchingAvailability({ itemId: itemData.sourceId, purchaseOption: 'in-store' });
this.addFetchingAvailability({ id, itemId: itemData.sourceId, purchaseOption: 'in-store' });
const res = await this._service.fetchInStoreAvailability(itemData, itemData.quantity, branch).toPromise();
const availability: Availability = {
@@ -278,12 +275,13 @@ export class PurchaseOptionsStore extends ComponentStore<PurchaseOptionsState> {
console.error('_loadInStoreAvailability', err);
}
this.removeFetchingAvailability({ itemId: itemData.sourceId, purchaseOption: 'in-store' });
this.removeFetchingAvailability({ id, itemId: itemData.sourceId, purchaseOption: 'in-store' });
}
private async _loadDeliveryAvailability(itemData: ItemData) {
const id = uniqueId('availability_');
try {
this.addFetchingAvailability({ itemId: itemData.sourceId, purchaseOption: 'delivery' });
this.addFetchingAvailability({ id, itemId: itemData.sourceId, purchaseOption: 'delivery' });
const res = await this._service.fetchDeliveryAvailability(itemData, itemData.quantity).toPromise();
const availability: Availability = {
@@ -297,12 +295,13 @@ export class PurchaseOptionsStore extends ComponentStore<PurchaseOptionsState> {
console.error('_loadDeliveryAvailability', error);
}
this.removeFetchingAvailability({ itemId: itemData.sourceId, purchaseOption: 'delivery' });
this.removeFetchingAvailability({ id, itemId: itemData.sourceId, purchaseOption: 'delivery' });
}
private async _loadDigDeliveryAvailability(itemData: ItemData) {
const id = uniqueId('availability_');
try {
this.addFetchingAvailability({ itemId: itemData.sourceId, purchaseOption: 'dig-delivery' });
this.addFetchingAvailability({ id, itemId: itemData.sourceId, purchaseOption: 'dig-delivery' });
const res = await this._service.fetchDigDeliveryAvailability(itemData, itemData.quantity).toPromise();
const availability: Availability = {
@@ -316,12 +315,13 @@ export class PurchaseOptionsStore extends ComponentStore<PurchaseOptionsState> {
console.error('_loadDigDeliveryAvailability', error);
}
this.removeFetchingAvailability({ itemId: itemData.sourceId, purchaseOption: 'dig-delivery' });
this.removeFetchingAvailability({ id, itemId: itemData.sourceId, purchaseOption: 'dig-delivery' });
}
private async _loadB2bDeliveryAvailability(itemData: ItemData) {
const id = uniqueId('availability_');
try {
this.addFetchingAvailability({ itemId: itemData.sourceId, purchaseOption: 'b2b-delivery' });
this.addFetchingAvailability({ id, itemId: itemData.sourceId, purchaseOption: 'b2b-delivery' });
const res = await this._service.fetchB2bDeliveryAvailability(itemData, itemData.quantity).toPromise();
const availability: Availability = {
@@ -335,12 +335,13 @@ export class PurchaseOptionsStore extends ComponentStore<PurchaseOptionsState> {
console.error('_loadB2bDeliveryAvailability', error);
}
this.removeFetchingAvailability({ itemId: itemData.sourceId, purchaseOption: 'b2b-delivery' });
this.removeFetchingAvailability({ id, itemId: itemData.sourceId, purchaseOption: 'b2b-delivery' });
}
private async _loadDownloadAvailability(itemData: ItemData) {
const id = uniqueId('availability_');
try {
this.addFetchingAvailability({ itemId: itemData.sourceId, purchaseOption: 'download' });
this.addFetchingAvailability({ id, itemId: itemData.sourceId, purchaseOption: 'download' });
const res = await this._service.fetchDownloadAvailability(itemData).toPromise();
const availability: Availability = {
@@ -354,7 +355,7 @@ export class PurchaseOptionsStore extends ComponentStore<PurchaseOptionsState> {
console.error('_loadDownloadAvailability', error);
}
this.removeFetchingAvailability({ itemId: itemData.sourceId, purchaseOption: 'download' });
this.removeFetchingAvailability({ id, itemId: itemData.sourceId, purchaseOption: 'download' });
}
private _checkAndSetAvailability(availability: Availability) {
@@ -490,6 +491,23 @@ export class PurchaseOptionsStore extends ComponentStore<PurchaseOptionsState> {
}
}
selectSelectableItems() {
const items = this.items.filter((i) => this.canAddItem(i.id));
this.patchState({ selectedItemIds: items.map((item) => item.id) });
}
canAddItem(itemId: number): boolean {
const purchaseOption = this.purchaseOption;
const canAdd = this.canAddResults.find((c) => c.itemId === itemId && c.purchaseOption === purchaseOption);
if (canAdd) {
return canAdd.canAdd;
}
return false;
}
resetSelectedItems() {
this.patchState({ selectedItemIds: [] });
}
@@ -687,7 +705,7 @@ export class PurchaseOptionsStore extends ComponentStore<PurchaseOptionsState> {
availability: { ...availability.data, price },
destination,
itemType: item.type,
product: item.product,
product: { ...item.product, catalogProductNumber: item?.product?.catalogProductNumber ?? String(item.id) },
promotion: { points: item.promoPoints },
// retailPrice: {
// value: price.value.value,

View File

@@ -26,4 +26,4 @@ export type ItemPayloadWithSourceId = ItemPayload & { sourceId: number };
export type CanAdd = { itemId: number; purchaseOption: PurchaseOption; canAdd: boolean; message?: string };
export type FetchingAvailability = { itemId: number; purchaseOption?: PurchaseOption };
export type FetchingAvailability = { id: string; itemId: number; purchaseOption?: PurchaseOption };

View File

@@ -3,5 +3,5 @@ page-package-inspection-wrong-destination-modal .page-package-list {
}
::ng-deep page-package-inspection-wrong-destination-modal .page-package-list cdk-virtual-scroll-viewport {
@apply h-[17.25rem];
height: 24.5rem !important;
}

View File

@@ -3,7 +3,7 @@
Stellen Sie diese Packstücke für die anderen Filialen bereit. <br />
Der Spediteur holt Sie zum nächstmöglichsten Zeitpunkt ab.
</p>
<page-package-list [packages]="packages" [showHeader]="false"></page-package-list>
<page-package-list [packages]="packages" [showHeader]="false" navigationEnabled="false"></page-package-list>
<div class="text-center my-7">
<button class="isa-cta-button" (click)="close()">Später</button>
<button class="isa-cta-button isa-button-primary ml-6" (click)="done()">Erledigt</button>

View File

@@ -18,7 +18,7 @@ export class WrongDestinationModalComponent {
const packages = this._ref.data?.packages ?? [];
// return top 5 packages
return packages.slice(0, 5);
return packages.slice(0, 10);
}
get packageCount(): number {

View File

@@ -0,0 +1,10 @@
import { NgModule } from '@angular/core';
import { AtPipe } from './at.pipe';
@NgModule({
imports: [],
exports: [AtPipe],
declarations: [AtPipe],
providers: [],
})
export class ArrayPipesModule {}

View File

@@ -0,0 +1,10 @@
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'at',
})
export class AtPipe implements PipeTransform {
transform<T>(value: Array<T>, index: number): T | undefined {
return value?.[index];
}
}

View File

@@ -0,0 +1,2 @@
export * from './lib/array-pipes.module';
export * from './lib/at.pipe';

View File

@@ -0,0 +1,11 @@
import { NgModule } from '@angular/core';
import { MaxPipe } from './max.pipe';
import { MinPipe } from './min.pipe';
@NgModule({
imports: [],
exports: [MinPipe, MaxPipe],
declarations: [MinPipe, MaxPipe],
providers: [],
})
export class MathPipesModule {}

View File

@@ -0,0 +1,11 @@
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'max',
pure: true,
})
export class MaxPipe implements PipeTransform {
transform(value: number, ...args: number[]): any {
return Math.max(value, ...args);
}
}

View File

@@ -0,0 +1,11 @@
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'min',
pure: true,
})
export class MinPipe implements PipeTransform {
transform(value: number, ...args: number[]): any {
return Math.min(value, ...args);
}
}

View File

@@ -0,0 +1,3 @@
export * from './lib/math-pipes.modules';
export * from './lib/min.pipe';
export * from './lib/max.pipe';

View File

@@ -0,0 +1,11 @@
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'split',
pure: true,
})
export class SplitPipe implements PipeTransform {
transform(value: string, splitter: string, limit?: number): any {
return value?.split(splitter, limit) ?? [];
}
}

View File

@@ -0,0 +1,10 @@
import { NgModule } from '@angular/core';
import { SplitPipe } from './split.pipe';
@NgModule({
imports: [],
exports: [SplitPipe],
declarations: [SplitPipe],
providers: [],
})
export class StringPipesModule {}

View File

@@ -0,0 +1,2 @@
export * from './lib/string-pipes.module';
export * from './lib/split.pipe';

View File

@@ -13,26 +13,27 @@ export { PackageDTO } from './models/package-dto';
export { EntityDTOContainerOfUserDTO } from './models/entity-dtocontainer-of-user-dto';
export { UserDTO } from './models/user-dto';
export { Gender } from './models/gender';
export { EntityDTOOfUserDTOAndIReadOnlyUser } from './models/entity-dtoof-user-dtoand-iread-only-user';
export { ReadOnlyEntityDTOOfUserDTOAndIReadOnlyUser } from './models/read-only-entity-dtoof-user-dtoand-iread-only-user';
export { EntityDTOBaseOfUserDTOAndIUser } from './models/entity-dtobase-of-user-dtoand-iuser';
export { EntityDTOBase } from './models/entity-dtobase';
export { EntityDTO } from './models/entity-dto';
export { EntityStatus } from './models/entity-status';
export { CRUDA } from './models/cruda';
export { TouchedBase } from './models/touched-base';
export { EntityDTOReferenceContainer } from './models/entity-dtoreference-container';
export { ExternalReferenceDTO } from './models/external-reference-dto';
export { EntityDTOContainerOfLabelDTO } from './models/entity-dtocontainer-of-label-dto';
export { LabelDTO } from './models/label-dto';
export { ReadOnlyEntityDTOOfLabelDTOAndIReadOnlyLabel } from './models/read-only-entity-dtoof-label-dtoand-iread-only-label';
export { EntityDTOBaseOfLabelDTOAndILabel } from './models/entity-dtobase-of-label-dtoand-ilabel';
export { WeightOfAvoirdupois } from './models/weight-of-avoirdupois';
export { Avoirdupois } from './models/avoirdupois';
export { AddresseeDTO } from './models/addressee-dto';
export { OrganisationDTO } from './models/organisation-dto';
export { OrganisationNamesDTO } from './models/organisation-names-dto';
export { PersonNamesDTO } from './models/person-names-dto';
export { AddressDTO } from './models/address-dto';
export { GeoLocation } from './models/geo-location';
export { CommunicationDetailsDTO } from './models/communication-details-dto';
export { EntityDTOOfPackageDTOAndIPackage } from './models/entity-dtoof-package-dtoand-ipackage';
export { ReadOnlyEntityDTOOfPackageDTOAndIPackage } from './models/read-only-entity-dtoof-package-dtoand-ipackage';
export { EntityDTOBaseOfPackageDTOAndIPackage } from './models/entity-dtobase-of-package-dtoand-ipackage';
export { ResponseArgsOfPackageDTO } from './models/response-args-of-package-dto';
export { ResponseArgsOfNullableBoolean } from './models/response-args-of-nullable-boolean';
export { ListResponseArgsOfReturnItemDTO } from './models/list-response-args-of-return-item-dto';
@@ -42,16 +43,13 @@ export { EntityDTOContainerOfStockDTO } from './models/entity-dtocontainer-of-st
export { StockDTO } from './models/stock-dto';
export { EntityDTOContainerOfBranchDTO } from './models/entity-dtocontainer-of-branch-dto';
export { BranchDTO } from './models/branch-dto';
export { Address } from './models/address';
export { BranchType } from './models/branch-type';
export { ReadOnlyEntityDTOOfBranchDTOAndIReadOnlyBranch } from './models/read-only-entity-dtoof-branch-dtoand-iread-only-branch';
export { EntityDTOOfStockDTOAndIStock } from './models/entity-dtoof-stock-dtoand-istock';
export { ReadOnlyEntityDTOOfStockDTOAndIStock } from './models/read-only-entity-dtoof-stock-dtoand-istock';
export { EntityDTOBaseOfBranchDTOAndIBranch } from './models/entity-dtobase-of-branch-dtoand-ibranch';
export { EntityDTOBaseOfStockDTOAndIStock } from './models/entity-dtobase-of-stock-dtoand-istock';
export { EntityDTOContainerOfStockCompartmentDTO } from './models/entity-dtocontainer-of-stock-compartment-dto';
export { StockCompartmentDTO } from './models/stock-compartment-dto';
export { SizeOfString } from './models/size-of-string';
export { EntityDTOOfStockCompartmentDTOAndIStockCompartment } from './models/entity-dtoof-stock-compartment-dtoand-istock-compartment';
export { ReadOnlyEntityDTOOfStockCompartmentDTOAndIStockCompartment } from './models/read-only-entity-dtoof-stock-compartment-dtoand-istock-compartment';
export { EntityDTOBaseOfStockCompartmentDTOAndIStockCompartment } from './models/entity-dtobase-of-stock-compartment-dtoand-istock-compartment';
export { EntityDTOContainerOfStockItemDTO } from './models/entity-dtocontainer-of-stock-item-dto';
export { StockItemDTO } from './models/stock-item-dto';
export { EntityDTOContainerOfItemDTO } from './models/entity-dtocontainer-of-item-dto';
@@ -60,11 +58,9 @@ export { ProductDTO } from './models/product-dto';
export { QuantityUnitType } from './models/quantity-unit-type';
export { EntityDTOContainerOfTenantDTO } from './models/entity-dtocontainer-of-tenant-dto';
export { TenantDTO } from './models/tenant-dto';
export { ReadOnlyEntityDTOOfTenantDTOAndIReadOnlyTenant } from './models/read-only-entity-dtoof-tenant-dtoand-iread-only-tenant';
export { EntityDTOOfItemDTOAndIItem } from './models/entity-dtoof-item-dtoand-iitem';
export { ReadOnlyEntityDTOOfItemDTOAndIItem } from './models/read-only-entity-dtoof-item-dtoand-iitem';
export { EntityDTOOfStockItemDTOAndIStockItem } from './models/entity-dtoof-stock-item-dtoand-istock-item';
export { ReadOnlyEntityDTOOfStockItemDTOAndIStockItem } from './models/read-only-entity-dtoof-stock-item-dtoand-istock-item';
export { EntityDTOBaseOfTenantDTOAndITenant } from './models/entity-dtobase-of-tenant-dtoand-itenant';
export { EntityDTOBaseOfItemDTOAndIItem } from './models/entity-dtobase-of-item-dtoand-iitem';
export { EntityDTOBaseOfStockItemDTOAndIStockItem } from './models/entity-dtobase-of-stock-item-dtoand-istock-item';
export { PriceDTO } from './models/price-dto';
export { PriceValueDTO } from './models/price-value-dto';
export { VATValueDTO } from './models/vatvalue-dto';
@@ -72,8 +68,7 @@ export { VATType } from './models/vattype';
export { EntityDTOContainerOfSupplierDTO } from './models/entity-dtocontainer-of-supplier-dto';
export { SupplierDTO } from './models/supplier-dto';
export { SupplierType } from './models/supplier-type';
export { EntityDTOOfSupplierDTOAndISupplier } from './models/entity-dtoof-supplier-dtoand-isupplier';
export { ReadOnlyEntityDTOOfSupplierDTOAndISupplier } from './models/read-only-entity-dtoof-supplier-dtoand-isupplier';
export { EntityDTOBaseOfSupplierDTOAndISupplier } from './models/entity-dtobase-of-supplier-dtoand-isupplier';
export { EntityDTOContainerOfStockEntryDTO } from './models/entity-dtocontainer-of-stock-entry-dto';
export { StockEntryDTO } from './models/stock-entry-dto';
export { StockEntryType } from './models/stock-entry-type';
@@ -81,35 +76,27 @@ export { EntityDTOContainerOfStockOrderItemDTO } from './models/entity-dtocontai
export { StockOrderItemDTO } from './models/stock-order-item-dto';
export { EntityDTOContainerOfStockOrderDTO } from './models/entity-dtocontainer-of-stock-order-dto';
export { StockOrderDTO } from './models/stock-order-dto';
export { EntityDTOOfStockOrderDTOAndIStockOrder } from './models/entity-dtoof-stock-order-dtoand-istock-order';
export { ReadOnlyEntityDTOOfStockOrderDTOAndIStockOrder } from './models/read-only-entity-dtoof-stock-order-dtoand-istock-order';
export { EntityDTOBaseOfStockOrderDTOAndIStockOrder } from './models/entity-dtobase-of-stock-order-dtoand-istock-order';
export { EntityDTOContainerOfSupplierStatusCodeDTO } from './models/entity-dtocontainer-of-supplier-status-code-dto';
export { SupplierStatusCodeDTO } from './models/supplier-status-code-dto';
export { AvailabilityType } from './models/availability-type';
export { EntityDTOOfSupplierStatusCodeDTOAndISupplierStatusCode } from './models/entity-dtoof-supplier-status-code-dtoand-isupplier-status-code';
export { ReadOnlyEntityDTOOfSupplierStatusCodeDTOAndISupplierStatusCode } from './models/read-only-entity-dtoof-supplier-status-code-dtoand-isupplier-status-code';
export { EntityDTOBaseOfSupplierStatusCodeDTOAndIStockStatusCode } from './models/entity-dtobase-of-supplier-status-code-dtoand-istock-status-code';
export { EntityDTOContainerOfStockOrderItemStatusDTO } from './models/entity-dtocontainer-of-stock-order-item-status-dto';
export { StockOrderItemStatusDTO } from './models/stock-order-item-status-dto';
export { StockOrderItemProcessingStatus } from './models/stock-order-item-processing-status';
export { EntityDTOOfStockOrderItemStatusDTOAndIStockOrderItemStatus } from './models/entity-dtoof-stock-order-item-status-dtoand-istock-order-item-status';
export { ReadOnlyEntityDTOOfStockOrderItemStatusDTOAndIStockOrderItemStatus } from './models/read-only-entity-dtoof-stock-order-item-status-dtoand-istock-order-item-status';
export { EntityDTOOfStockOrderItemDTOAndIStockOrderItem } from './models/entity-dtoof-stock-order-item-dtoand-istock-order-item';
export { ReadOnlyEntityDTOOfStockOrderItemDTOAndIStockOrderItem } from './models/read-only-entity-dtoof-stock-order-item-dtoand-istock-order-item';
export { EntityDTOBaseOfStockOrderItemStatusDTOAndIStockOrderItemStatus } from './models/entity-dtobase-of-stock-order-item-status-dtoand-istock-order-item-status';
export { EntityDTOBaseOfStockOrderItemDTOAndIStockOrderItem } from './models/entity-dtobase-of-stock-order-item-dtoand-istock-order-item';
export { EntityDTOContainerOfStockReservationItemDTO } from './models/entity-dtocontainer-of-stock-reservation-item-dto';
export { StockReservationItemDTO } from './models/stock-reservation-item-dto';
export { EntityDTOContainerOfStockReservationDTO } from './models/entity-dtocontainer-of-stock-reservation-dto';
export { StockReservationDTO } from './models/stock-reservation-dto';
export { EntityDTOOfStockReservationDTOAndIStockReservation } from './models/entity-dtoof-stock-reservation-dtoand-istock-reservation';
export { ReadOnlyEntityDTOOfStockReservationDTOAndIStockReservation } from './models/read-only-entity-dtoof-stock-reservation-dtoand-istock-reservation';
export { EntityDTOBaseOfStockReservationDTOAndIStockReservation } from './models/entity-dtobase-of-stock-reservation-dtoand-istock-reservation';
export { EntityDTOContainerOfStockReservationItemStatusDTO } from './models/entity-dtocontainer-of-stock-reservation-item-status-dto';
export { StockReservationItemStatusDTO } from './models/stock-reservation-item-status-dto';
export { StockReservationItemProcessingStatus } from './models/stock-reservation-item-processing-status';
export { EntityDTOOfStockReservationItemStatusDTOAndIStockReservationItemStatus } from './models/entity-dtoof-stock-reservation-item-status-dtoand-istock-reservation-item-status';
export { ReadOnlyEntityDTOOfStockReservationItemStatusDTOAndIStockReservationItemStatus } from './models/read-only-entity-dtoof-stock-reservation-item-status-dtoand-istock-reservation-item-status';
export { EntityDTOOfStockReservationItemDTOAndIStockReservationItem } from './models/entity-dtoof-stock-reservation-item-dtoand-istock-reservation-item';
export { ReadOnlyEntityDTOOfStockReservationItemDTOAndIStockReservationItem } from './models/read-only-entity-dtoof-stock-reservation-item-dtoand-istock-reservation-item';
export { EntityDTOOfStockEntryDTOAndIStockEntry } from './models/entity-dtoof-stock-entry-dtoand-istock-entry';
export { ReadOnlyEntityDTOOfStockEntryDTOAndIStockEntry } from './models/read-only-entity-dtoof-stock-entry-dtoand-istock-entry';
export { EntityDTOBaseOfStockReservationItemStatusDTOAndIStockReservationItemStatus } from './models/entity-dtobase-of-stock-reservation-item-status-dtoand-istock-reservation-item-status';
export { EntityDTOBaseOfStockReservationItemDTOAndIStockReservationItem } from './models/entity-dtobase-of-stock-reservation-item-dtoand-istock-reservation-item';
export { EntityDTOBaseOfStockEntryDTOAndIStockEntry } from './models/entity-dtobase-of-stock-entry-dtoand-istock-entry';
export { EntityDTOContainerOfReturnDTO } from './models/entity-dtocontainer-of-return-dto';
export { ReturnDTO } from './models/return-dto';
export { EntityDTOContainerOfReceiptDTO } from './models/entity-dtocontainer-of-receipt-dto';
@@ -118,16 +105,12 @@ export { StockReceiptType } from './models/stock-receipt-type';
export { EntityDTOContainerOfReceiptItemDTO } from './models/entity-dtocontainer-of-receipt-item-dto';
export { ReceiptItemDTO } from './models/receipt-item-dto';
export { EntityDTOContainerOfPackageDTO } from './models/entity-dtocontainer-of-package-dto';
export { EntityDTOOfReceiptItemDTOAndIStockReceiptItem } from './models/entity-dtoof-receipt-item-dtoand-istock-receipt-item';
export { ReadOnlyEntityDTOOfReceiptItemDTOAndIStockReceiptItem } from './models/read-only-entity-dtoof-receipt-item-dtoand-istock-receipt-item';
export { EntityDTOOfReceiptDTOAndIStockReceipt } from './models/entity-dtoof-receipt-dtoand-istock-receipt';
export { ReadOnlyEntityDTOOfReceiptDTOAndIStockReceipt } from './models/read-only-entity-dtoof-receipt-dtoand-istock-receipt';
export { EntityDTOOfReturnDTOAndIReturn } from './models/entity-dtoof-return-dtoand-ireturn';
export { ReadOnlyEntityDTOOfReturnDTOAndIReturn } from './models/read-only-entity-dtoof-return-dtoand-ireturn';
export { EntityDTOBaseOfReceiptItemDTOAndIStockReceiptItem } from './models/entity-dtobase-of-receipt-item-dtoand-istock-receipt-item';
export { EntityDTOBaseOfReceiptDTOAndIStockReceipt } from './models/entity-dtobase-of-receipt-dtoand-istock-receipt';
export { EntityDTOBaseOfReturnDTOAndIReturn } from './models/entity-dtobase-of-return-dtoand-ireturn';
export { EntityDTOContainerOfReturnItemDTO } from './models/entity-dtocontainer-of-return-item-dto';
export { ImpedimentDTO } from './models/impediment-dto';
export { EntityDTOOfReturnItemDTOAndIReturnItem } from './models/entity-dtoof-return-item-dtoand-ireturn-item';
export { ReadOnlyEntityDTOOfReturnItemDTOAndIReturnItem } from './models/read-only-entity-dtoof-return-item-dtoand-ireturn-item';
export { EntityDTOBaseOfReturnItemDTOAndIReturnItem } from './models/entity-dtobase-of-return-item-dtoand-ireturn-item';
export { RemiQueryTokenDTO } from './models/remi-query-token-dto';
export { QueryTokenDTO } from './models/query-token-dto';
export { OrderByDTO } from './models/order-by-dto';
@@ -140,8 +123,7 @@ export { ResponseArgsOfInteger } from './models/response-args-of-integer';
export { ListResponseArgsOfReturnSuggestionDTO } from './models/list-response-args-of-return-suggestion-dto';
export { ResponseArgsOfIEnumerableOfReturnSuggestionDTO } from './models/response-args-of-ienumerable-of-return-suggestion-dto';
export { ReturnSuggestionDTO } from './models/return-suggestion-dto';
export { EntityDTOOfReturnSuggestionDTOAndIReturnSuggestion } from './models/entity-dtoof-return-suggestion-dtoand-ireturn-suggestion';
export { ReadOnlyEntityDTOOfReturnSuggestionDTOAndIReturnSuggestion } from './models/read-only-entity-dtoof-return-suggestion-dtoand-ireturn-suggestion';
export { EntityDTOBaseOfReturnSuggestionDTOAndIReturnSuggestion } from './models/entity-dtobase-of-return-suggestion-dtoand-ireturn-suggestion';
export { BatchResponseArgsOfReturnSuggestionDTOAndReturnSuggestionDTO } from './models/batch-response-args-of-return-suggestion-dtoand-return-suggestion-dto';
export { KeyValuePairOfReturnSuggestionDTOAndReturnSuggestionDTO } from './models/key-value-pair-of-return-suggestion-dtoand-return-suggestion-dto';
export { ReturnValueOfReturnSuggestionDTO } from './models/return-value-of-return-suggestion-dto';
@@ -191,9 +173,9 @@ export { QuadrupelDTO } from './models/quadrupel-dto';
export { ResponseArgsOfBranchDTO } from './models/response-args-of-branch-dto';
export { ResponseArgsOfStockDTO } from './models/response-args-of-stock-dto';
export { ResponseArgsOfIEnumerableOfStockDTO } from './models/response-args-of-ienumerable-of-stock-dto';
export { ResponseArgsOfIEnumerableOfSupplierDTO } from './models/response-args-of-ienumerable-of-supplier-dto';
export { ResponseArgsOfIEnumerableOfStockEntryDTO } from './models/response-args-of-ienumerable-of-stock-entry-dto';
export { ResponseArgsOfIEnumerableOfStockItemDTO } from './models/response-args-of-ienumerable-of-stock-item-dto';
export { ResponseArgsOfIEnumerableOfStockOrderDTO } from './models/response-args-of-ienumerable-of-stock-order-dto';
export { ResponseArgsOfIEnumerableOfStockReservationDTO } from './models/response-args-of-ienumerable-of-stock-reservation-dto';
export { ListResponseArgsOfSupplierDTO } from './models/list-response-args-of-supplier-dto';
export { ResponseArgsOfIEnumerableOfSupplierDTO } from './models/response-args-of-ienumerable-of-supplier-dto';

View File

@@ -1,6 +1,7 @@
/* tslint:disable */
import { TouchedBase } from './touched-base';
import { GeoLocation } from './geo-location';
export interface AddressDTO {
export interface AddressDTO extends TouchedBase{
apartment?: string;
careOf?: string;
city?: string;

View File

@@ -1,17 +0,0 @@
/* tslint:disable */
import { GeoLocation } from './geo-location';
export interface Address {
apartment?: string;
careOf?: string;
city?: string;
country?: string;
district?: string;
geoLocation?: GeoLocation;
info?: string;
po?: string;
region?: string;
state?: string;
street?: string;
streetNumber?: string;
zipCode?: string;
}

View File

@@ -1,9 +1,10 @@
/* tslint:disable */
import { TouchedBase } from './touched-base';
import { AddressDTO } from './address-dto';
import { CommunicationDetailsDTO } from './communication-details-dto';
import { OrganisationDTO } from './organisation-dto';
import { PersonNamesDTO } from './person-names-dto';
export interface AddresseeDTO {
export interface AddresseeDTO extends TouchedBase{
address?: AddressDTO;
communicationDetails?: CommunicationDetailsDTO;
locale?: string;

View File

@@ -1,10 +1,12 @@
/* tslint:disable */
import { ReturnValueOfReturnItemDTO } from './return-value-of-return-item-dto';
import { ReturnItemDTO } from './return-item-dto';
import { KeyValuePairOfReturnItemDTOAndInteger } from './key-value-pair-of-return-item-dtoand-integer';
import { ReturnValueOfReturnItemDTO } from './return-value-of-return-item-dto';
import { KeyValuePairOfReturnItemDTOAndReturnItemDTO } from './key-value-pair-of-return-item-dtoand-return-item-dto';
export interface BatchResponseArgsOfReturnItemDTOAndReturnItemDTO {
alreadyProcessed?: Array<ReturnValueOfReturnItemDTO>;
ambiguous?: Array<ReturnItemDTO>;
completed: boolean;
duplicates?: Array<KeyValuePairOfReturnItemDTOAndInteger>;
error: boolean;
failed?: Array<ReturnValueOfReturnItemDTO>;
@@ -12,5 +14,6 @@ export interface BatchResponseArgsOfReturnItemDTOAndReturnItemDTO {
message?: string;
requestId?: number;
successful?: Array<KeyValuePairOfReturnItemDTOAndReturnItemDTO>;
total: number;
unknown?: Array<ReturnValueOfReturnItemDTO>;
}

View File

@@ -1,10 +1,12 @@
/* tslint:disable */
import { ReturnValueOfReturnSuggestionDTO } from './return-value-of-return-suggestion-dto';
import { ReturnSuggestionDTO } from './return-suggestion-dto';
import { KeyValuePairOfReturnSuggestionDTOAndInteger } from './key-value-pair-of-return-suggestion-dtoand-integer';
import { ReturnValueOfReturnSuggestionDTO } from './return-value-of-return-suggestion-dto';
import { KeyValuePairOfReturnSuggestionDTOAndReturnSuggestionDTO } from './key-value-pair-of-return-suggestion-dtoand-return-suggestion-dto';
export interface BatchResponseArgsOfReturnSuggestionDTOAndReturnSuggestionDTO {
alreadyProcessed?: Array<ReturnValueOfReturnSuggestionDTO>;
ambiguous?: Array<ReturnSuggestionDTO>;
completed: boolean;
duplicates?: Array<KeyValuePairOfReturnSuggestionDTOAndInteger>;
error: boolean;
failed?: Array<ReturnValueOfReturnSuggestionDTO>;
@@ -12,5 +14,6 @@ export interface BatchResponseArgsOfReturnSuggestionDTOAndReturnSuggestionDTO {
message?: string;
requestId?: number;
successful?: Array<KeyValuePairOfReturnSuggestionDTOAndReturnSuggestionDTO>;
total: number;
unknown?: Array<ReturnValueOfReturnSuggestionDTO>;
}

View File

@@ -1,17 +1,20 @@
/* tslint:disable */
import { ReadOnlyEntityDTOOfBranchDTOAndIReadOnlyBranch } from './read-only-entity-dtoof-branch-dtoand-iread-only-branch';
import { Address } from './address';
import { EntityDTOBaseOfBranchDTOAndIBranch } from './entity-dtobase-of-branch-dtoand-ibranch';
import { AddressDTO } from './address-dto';
import { BranchType } from './branch-type';
import { EntityDTOContainerOfLabelDTO } from './entity-dtocontainer-of-label-dto';
export interface BranchDTO extends ReadOnlyEntityDTOOfBranchDTOAndIReadOnlyBranch{
address?: Address;
import { EntityDTOContainerOfBranchDTO } from './entity-dtocontainer-of-branch-dto';
export interface BranchDTO extends EntityDTOBaseOfBranchDTOAndIBranch{
address?: AddressDTO;
branchNumber?: string;
branchType?: BranchType;
isDefault?: string;
isOnline?: boolean;
isOrderingEnabled?: boolean;
isShippingEnabled?: boolean;
key?: string;
label?: EntityDTOContainerOfLabelDTO;
name?: string;
parent?: number;
parent?: EntityDTOContainerOfBranchDTO;
shortName?: string;
}

View File

@@ -1,5 +1,6 @@
/* tslint:disable */
export interface CommunicationDetailsDTO {
import { TouchedBase } from './touched-base';
export interface CommunicationDetailsDTO extends TouchedBase{
email?: string;
fax?: string;
mobile?: string;

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

@@ -0,0 +1,4 @@
/* tslint:disable */
import { EntityDTOBase } from './entity-dtobase';
export interface EntityDTOBaseOfBranchDTOAndIBranch extends EntityDTOBase{
}

View File

@@ -0,0 +1,4 @@
/* tslint:disable */
import { EntityDTOBase } from './entity-dtobase';
export interface EntityDTOBaseOfItemDTOAndIItem extends EntityDTOBase{
}

View File

@@ -0,0 +1,4 @@
/* tslint:disable */
import { EntityDTOBase } from './entity-dtobase';
export interface EntityDTOBaseOfLabelDTOAndILabel extends EntityDTOBase{
}

View File

@@ -0,0 +1,4 @@
/* tslint:disable */
import { EntityDTOBase } from './entity-dtobase';
export interface EntityDTOBaseOfPackageDTOAndIPackage extends EntityDTOBase{
}

View File

@@ -0,0 +1,4 @@
/* tslint:disable */
import { EntityDTOBase } from './entity-dtobase';
export interface EntityDTOBaseOfReceiptDTOAndIStockReceipt extends EntityDTOBase{
}

View File

@@ -0,0 +1,4 @@
/* tslint:disable */
import { EntityDTOBase } from './entity-dtobase';
export interface EntityDTOBaseOfReceiptItemDTOAndIStockReceiptItem extends EntityDTOBase{
}

View File

@@ -0,0 +1,4 @@
/* tslint:disable */
import { EntityDTOBase } from './entity-dtobase';
export interface EntityDTOBaseOfReturnDTOAndIReturn extends EntityDTOBase{
}

View File

@@ -0,0 +1,4 @@
/* tslint:disable */
import { EntityDTOBase } from './entity-dtobase';
export interface EntityDTOBaseOfReturnItemDTOAndIReturnItem extends EntityDTOBase{
}

View File

@@ -0,0 +1,4 @@
/* tslint:disable */
import { EntityDTOBase } from './entity-dtobase';
export interface EntityDTOBaseOfReturnSuggestionDTOAndIReturnSuggestion extends EntityDTOBase{
}

View File

@@ -0,0 +1,4 @@
/* tslint:disable */
import { EntityDTOBase } from './entity-dtobase';
export interface EntityDTOBaseOfStockCompartmentDTOAndIStockCompartment extends EntityDTOBase{
}

View File

@@ -0,0 +1,4 @@
/* tslint:disable */
import { EntityDTOBase } from './entity-dtobase';
export interface EntityDTOBaseOfStockDTOAndIStock extends EntityDTOBase{
}

View File

@@ -0,0 +1,4 @@
/* tslint:disable */
import { EntityDTOBase } from './entity-dtobase';
export interface EntityDTOBaseOfStockEntryDTOAndIStockEntry extends EntityDTOBase{
}

View File

@@ -0,0 +1,4 @@
/* tslint:disable */
import { EntityDTOBase } from './entity-dtobase';
export interface EntityDTOBaseOfStockItemDTOAndIStockItem extends EntityDTOBase{
}

View File

@@ -0,0 +1,4 @@
/* tslint:disable */
import { EntityDTOBase } from './entity-dtobase';
export interface EntityDTOBaseOfStockOrderDTOAndIStockOrder extends EntityDTOBase{
}

View File

@@ -0,0 +1,4 @@
/* tslint:disable */
import { EntityDTOBase } from './entity-dtobase';
export interface EntityDTOBaseOfStockOrderItemDTOAndIStockOrderItem extends EntityDTOBase{
}

View File

@@ -0,0 +1,4 @@
/* tslint:disable */
import { EntityDTOBase } from './entity-dtobase';
export interface EntityDTOBaseOfStockOrderItemStatusDTOAndIStockOrderItemStatus extends EntityDTOBase{
}

View File

@@ -0,0 +1,4 @@
/* tslint:disable */
import { EntityDTOBase } from './entity-dtobase';
export interface EntityDTOBaseOfStockReservationDTOAndIStockReservation extends EntityDTOBase{
}

View File

@@ -0,0 +1,4 @@
/* tslint:disable */
import { EntityDTOBase } from './entity-dtobase';
export interface EntityDTOBaseOfStockReservationItemDTOAndIStockReservationItem extends EntityDTOBase{
}

Some files were not shown because too many files have changed in this diff Show More