merge branch 'release/1.5'

This commit is contained in:
Michael Auer
2021-12-22 11:21:34 +01:00
107 changed files with 1383 additions and 425 deletions

View File

@@ -17,7 +17,7 @@ export class DomainGoodsService {
getItemByOrderNumber(orderNumber: string) {
return this.abholfachService.AbholfachWareneingang({
filter: { all_branches: 'true' },
filter: { all_branches: 'true', archive: 'true' },
input: {
qs: orderNumber,
},
@@ -26,7 +26,7 @@ export class DomainGoodsService {
getItemByCompartment(compartmentCode: string) {
return this.abholfachService.AbholfachWareneingang({
filter: { all_branches: 'true' },
filter: { all_branches: 'true', archive: 'true' },
input: {
qs: compartmentCode,
},
@@ -63,6 +63,11 @@ export class DomainGoodsService {
return this.abholfachService.AbholfachWareneingangsliste(queryToken);
}
@memorize()
goodsInListQuerySettings() {
return this.abholfachService.AbholfachWareneingangslisteQuerySettings().pipe(shareReplay());
}
goodsInCleanupList() {
return this.abholfachService.AbholfachAbholfachbereinigungsliste();
}

View File

@@ -198,6 +198,13 @@ export class DomainOmsService {
.pipe(map((res) => res.result));
}
generateNotifications({ orderId, taskTypes }: { orderId: number; taskTypes: string[] }) {
return this.orderService.OrderRegenerateOrderItemStatusTasks({
orderId,
taskTypes,
});
}
getCompletedTasks({
orderId,
orderItemId,

View File

@@ -67,7 +67,7 @@
</div>
<div *ngIf="item?.product?.volume">Band/Reihe {{ item?.product?.volume }}</div>
<div>{{ item.product?.publicationDate | date: 'MMMM y' }}</div>
<div>{{ publicationDate$ | async }}</div>
</div>
<div class="right">

View File

@@ -17,6 +17,8 @@ import { ModalAvailabilitiesComponent } from '@modal/availabilities';
import { slideYAnimation } from './slide.animation';
import { BreadcrumbService } from '@core/breadcrumb';
import { ItemDTO } from '@swagger/cat';
import { DateAdapter } from '@ui/common';
import { DatePipe } from '@angular/common';
@Component({
selector: 'page-article-details',
@@ -67,6 +69,19 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
contributors$ = this.store.item$.pipe(map((item) => item?.product?.contributors?.split(';').map((m) => m.trim())));
publicationDate$ = this.store.item$.pipe(
filter((item) => !!item?.product?.publicationDate),
map((item) => {
const date = this._dateAdapter.parseDate(item.product.publicationDate);
if (this._dateAdapter.getDate(date) === 1 && this._dateAdapter.getMonth(date) === 0) {
return this._datePipe.transform(date, 'y');
}
return this._datePipe.transform(date, 'dd. MMMM y');
})
);
constructor(
private applicationService: ApplicationService,
private activatedRoute: ActivatedRoute,
@@ -76,6 +91,8 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
private productImageService: ProductImageService,
private application: ApplicationService,
private breadcrumb: BreadcrumbService,
private _dateAdapter: DateAdapter,
private _datePipe: DatePipe,
public elementRef: ElementRef
) {}

View File

@@ -233,9 +233,9 @@ export class ArticleDetailsStore extends ComponentStore<ArticleDetailsState> {
const availability = isDownload ? downloadAvailability : pickupAvailability || deliveryDigAvailability;
return item?.catalogAvailability?.supplier === 'S' && !isDownload
? `${item?.catalogAvailability?.ssc} - ${item?.catalogAvailability?.sscText}`
: availability
: availability.ssc || availability.sscText
? `${availability.ssc} - ${availability.sscText}`
: '';
: 'Keine Lieferanten vorhanden';
})
);

View File

@@ -1,16 +0,0 @@
<div class="grw"></div>
<div class="order-by-filter-button-wrapper">
<button class="order-by-filter-button" type="button" *ngFor="let by of orderByKeys" (click)="setActive(by)">
<span>
{{ by }}
</span>
<ui-icon
[class.asc]="by === activeOrderBy?.by && !activeOrderBy.desc"
[class.desc]="by === activeOrderBy?.by && activeOrderBy.desc"
icon="arrow"
size="14px"
></ui-icon>
</button>
</div>
<div class="grw"></div>
<div *ngIf="hits" class="hits">{{ hits }} Titel</div>

View File

@@ -1,38 +0,0 @@
:host {
@apply box-border flex justify-center items-center;
min-height: 30px;
}
.order-by-filter-button-wrapper {
@apply flex flex-row items-center justify-center;
}
.order-by-filter-button {
@apply bg-transparent outline-none border-none text-regular font-bold text-active-customer flex flex-row justify-center items-center m-2;
}
::ng-deep .tablet page-order-by-filter .order-by-filter-button {
@apply mx-0;
}
ui-icon {
@apply hidden transform ml-2 bg-active-customer rounded-full p-1;
transition: 250ms all ease-in-out;
}
ui-icon.asc,
ui-icon.desc {
@apply flex bg-active-customer rounded-full visible text-white;
}
ui-icon.asc {
@apply -rotate-90;
}
ui-icon.desc {
@apply rotate-90;
}
.hits {
@apply absolute right-0 bg-transparent text-regular font-semibold text-inactive-customer;
}

View File

@@ -48,6 +48,6 @@
<div class="item-misc">
{{ item?.product?.manufacturer | substr: 18 }} | {{ item?.product?.ean }} <br />
{{ item?.product?.volume }} <span *ngIf="item?.product?.volume && item?.product?.publicationDate">|</span>
{{ item?.product?.publicationDate | date: 'MMMM yyyy' }}
{{ publicationDate }}
</div>
</a>

View File

@@ -1,5 +1,7 @@
import { DatePipe } from '@angular/common';
import { Component, ChangeDetectionStrategy, Input } from '@angular/core';
import { ItemDTO } from '@swagger/cat';
import { DateAdapter } from '@ui/common';
@Component({
selector: 'search-result-item',
@@ -15,5 +17,18 @@ export class SearchResultItemComponent {
return this.item?.product?.contributors?.split(';').map((val) => val.trim());
}
constructor() {}
get publicationDate() {
if (!!this.item?.product?.publicationDate) {
const date = this._dateAdapter.parseDate(this.item.product.publicationDate);
if (this._dateAdapter.getDate(date) === 1 && this._dateAdapter.getMonth(date) === 0) {
return this._datePipe.transform(date, 'y');
}
return this._datePipe.transform(date, 'dd. MMMM y');
}
return '';
}
constructor(private _dateAdapter: DateAdapter, private _datePipe: DatePipe) {}
}

View File

@@ -1,8 +1,7 @@
<page-order-by-filter
[hits]="hits$ | async"
[orderBy]="(filter$ | async)?.orderBy"
(selectedOrderByChange)="search(); updateBreadcrumbs()"
></page-order-by-filter>
<div class="filter-wrapper">
<div class="hits" *ngIf="hits$ | async; let hits">{{ hits }} Titel</div>
<ui-order-by-filter [orderBy]="(filter$ | async)?.orderBy" (selectedOrderByChange)="search(); updateBreadcrumbs()"> </ui-order-by-filter>
</div>
<cdk-virtual-scroll-viewport
#scrollContainer

View File

@@ -14,3 +14,15 @@
height: 155px;
max-height: 155px;
}
.filter-wrapper {
@apply block relative;
.hits {
@apply text-inactive-branch font-semibold absolute top-2 right-0;
}
ui-order-by-filter {
@apply mx-auto;
}
}

View File

@@ -7,7 +7,7 @@ import { ItemDTO } from '@swagger/cat';
import { UiFilter } from '@ui/filter';
import { CacheService } from 'apps/core/cache/src/public-api';
import { isEqual } from 'lodash';
import { BehaviorSubject, combineLatest, Subscription } from 'rxjs';
import { combineLatest, Subscription } from 'rxjs';
import { debounceTime, first } from 'rxjs/operators';
import { ArticleSearchService } from '../article-search.store';

View File

@@ -5,22 +5,16 @@ import { RouterModule } from '@angular/router';
import { DomainCatalogModule } from '@domain/catalog';
import { UiCommonModule } from '@ui/common';
import { UiIconModule } from '@ui/icon';
import { OrderByFilterComponent } from './order-by-filter/order-by-filter.component';
import { UiOrderByFilterModule } from 'apps/ui/filter/src/lib/next/order-by-filter/order-by-filter.module';
import { StockInfosPipe } from './order-by-filter/stick-infos.pipe';
import { SearchResultItemLoadingComponent } from './search-result-item-loading.component';
import { SearchResultItemComponent } from './search-result-item.component';
import { ArticleSearchResultsComponent } from './search-results.component';
@NgModule({
imports: [CommonModule, RouterModule, DomainCatalogModule, UiCommonModule, UiIconModule, ScrollingModule],
exports: [ArticleSearchResultsComponent, SearchResultItemComponent, OrderByFilterComponent],
declarations: [
ArticleSearchResultsComponent,
SearchResultItemComponent,
OrderByFilterComponent,
StockInfosPipe,
SearchResultItemLoadingComponent,
],
imports: [CommonModule, RouterModule, DomainCatalogModule, UiCommonModule, UiIconModule, UiOrderByFilterModule, ScrollingModule],
exports: [ArticleSearchResultsComponent, SearchResultItemComponent],
declarations: [ArticleSearchResultsComponent, SearchResultItemComponent, StockInfosPipe, SearchResultItemLoadingComponent],
providers: [],
})
export class SearchResultsModule {}

View File

@@ -1,10 +1,9 @@
:host {
@apply block overflow-y-scroll;
max-height: calc(100vh - 135px - 80px);
}
.wrapper {
@apply block bg-white shadow-card rounded-card pt-6 pb-10 mb-40;
@apply block bg-white shadow-card rounded-card pt-6;
.header {
@apply text-right;
@@ -59,8 +58,7 @@
}
.actions {
@apply absolute flex items-center justify-center left-0 right-0 bottom-0;
margin-bottom: 18px;
@apply flex items-center justify-center pt-8;
}
.cta-primary {

View File

@@ -1,15 +1,12 @@
import { ChangeDetectionStrategy, Component, Inject, OnDestroy, OnInit, Optional } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { ApplicationService } from '@core/application';
import { BreadcrumbService } from '@core/breadcrumb';
import { Router } from '@angular/router';
import { ItemDTO } from '@swagger/cat';
import { DateAdapter } from '@ui/common';
import { UiFilterScanProvider } from '@ui/filter';
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
import { UiErrorModalComponent, UiModalRef, UiModalService } from '@ui/modal';
import { Subject } from 'rxjs';
import { first, shareReplay, takeUntil } from 'rxjs/operators';
import { threadId } from 'worker_threads';
import { CheckoutDummyScanProvider } from './checkout-dummy-scan.provider';
import { CheckoutDummyStore } from './checkout-dummy.store';
@@ -49,26 +46,21 @@ export class CheckoutDummyComponent implements OnInit, OnDestroy {
vats$ = this._store.vats$;
suppliers$ = this._store.suppliers$;
params: Params;
_onDestroy$ = new Subject<void>();
constructor(
@Inject(UiFilterScanProvider) @Optional() private scanProviders: UiFilterScanProvider[],
private _router: Router,
private _route: ActivatedRoute,
private _application: ApplicationService,
private _breadcrumb: BreadcrumbService,
private _fb: FormBuilder,
private _dateAdapter: DateAdapter,
private _modal: UiModalService,
private _store: CheckoutDummyStore
private _store: CheckoutDummyStore,
private _ref: UiModalRef<any, any>
) {}
ngOnInit() {
this._scanProvider = this.scanProviders?.find((provider) => provider.for === 'dummy');
this.initForm();
this.updateBreadcrumb();
this._store.item$.pipe(takeUntil(this._onDestroy$)).subscribe((item) => {
if (item) {
@@ -77,21 +69,20 @@ export class CheckoutDummyComponent implements OnInit, OnDestroy {
}
});
const params = this._route.snapshot.queryParams;
if (Object.keys(params).length !== 0) {
this.params = params;
if (!!this._ref?.data && Object.keys(this._ref?.data).length !== 0) {
const data = this._ref?.data;
const item = {
ean: params.ean || '',
name: params.name || '',
quantity: params.quantity || '',
estimatedShippingDate: params.estimatedShippingDate || this._dateAdapter.today().toISOString(),
contributors: params.contributors || '',
manufacturer: params.manufacturer || '',
supplier: params.supplier || 5,
price: params.price || '',
vat: params.vat || '',
ean: data.ean || '',
name: data.name || '',
quantity: data.quantity || '',
estimatedShippingDate: data.estimatedShippingDate || this._dateAdapter.today().toISOString(),
contributors: data.contributors || '',
manufacturer: data.manufacturer || '',
supplier: data.supplier || 5,
price: data.price || '',
vat: data.vat || '',
};
this.populateFormFromParams(item);
this.populateFormFromModalData(item);
}
}
@@ -100,27 +91,15 @@ export class CheckoutDummyComponent implements OnInit, OnDestroy {
this._onDestroy$.complete();
}
async updateBreadcrumb() {
await this._breadcrumb.addOrUpdateBreadcrumbIfNotExists({
key: this._application.activatedProcessId,
name: 'Neuanlage',
path: '/cart/dummy',
tags: ['checkout', 'cart', 'dummy'],
section: 'customer',
});
}
setQuery(ean: string) {
if (ean) {
this._store.query = ean;
}
}
search(ean: string) {
this.setQuery(ean);
async search(ean: string) {
this._store.query = ean;
this._store.search();
}
setQuery(query: string) {
this._store.query = query;
}
changeEstimatedShippingDate(date: Date) {
if (!date) {
return;
@@ -157,7 +136,7 @@ export class CheckoutDummyComponent implements OnInit, OnDestroy {
this.control.get('vat').setValue(item?.catalogAvailability?.price?.vat?.vatType);
}
populateFormFromParams(item: any) {
populateFormFromModalData(item: any) {
this.control.get('name').setValue(item.name);
this.control.get('contributors').setValue(item.contributors);
this.control.get('manufacturer').setValue(item.manufacturer);
@@ -195,12 +174,12 @@ export class CheckoutDummyComponent implements OnInit, OnDestroy {
try {
const branch = await this._store.currentBranch$.pipe(first()).toPromise();
if (!this.params) {
await this._store.createAddToCartItem(this.control, branch);
this._store.addToCart(() => {});
} else {
if (!!this._ref?.data && Object.keys(this._ref?.data).length !== 0) {
await this._store.createAddToCartItem(this.control, branch, true);
this._store.updateCart(() => {});
} else {
await this._store.createAddToCartItem(this.control, branch);
this._store.addToCart(() => {});
}
} catch (error) {
this._modal.open({
@@ -224,21 +203,7 @@ export class CheckoutDummyComponent implements OnInit, OnDestroy {
try {
const branch = await this._store.currentBranch$.pipe(first()).toPromise();
if (!this.params) {
await this._store.createAddToCartItem(this.control, branch);
this._store.addToCart(async () => {
// Set filter for navigation to customer search if customer is not set
const customer = await this._store.customer$.pipe(first()).toPromise();
const customerFilter = await this._store.customerFilter$.pipe(first()).toPromise();
let filter: { [key: string]: string };
if (!customer) {
filter = customerFilter;
this._router.navigate(['/customer', 'search'], { queryParams: { customertype: filter.customertype } });
} else {
this._router.navigate(['/cart', 'review']);
}
});
} else {
if (!!this._ref?.data && Object.keys(this._ref?.data).length !== 0) {
await this._store.createAddToCartItem(this.control, branch, true);
this._store.updateCart(async () => {
// Set filter for navigation to customer search if customer is not set
@@ -251,6 +216,22 @@ export class CheckoutDummyComponent implements OnInit, OnDestroy {
} else {
this._router.navigate(['/cart', 'review']);
}
this._ref?.close();
});
} else {
await this._store.createAddToCartItem(this.control, branch);
this._store.addToCart(async () => {
// Set filter for navigation to customer search if customer is not set
const customer = await this._store.customer$.pipe(first()).toPromise();
const customerFilter = await this._store.customerFilter$.pipe(first()).toPromise();
let filter: { [key: string]: string };
if (!customer) {
filter = customerFilter;
this._router.navigate(['/customer', 'search'], { queryParams: { customertype: filter.customertype } });
} else {
this._router.navigate(['/cart', 'review']);
}
this._ref?.close();
});
}
} catch (error) {

View File

@@ -249,6 +249,7 @@ export class CheckoutDummyStore extends ComponentStore<CheckoutDummyState> {
qs: ean,
},
take: 1,
friendlyName: ean,
doNotTrack: true,
};
return this._catalogService.search({ queryToken });

View File

@@ -14,7 +14,7 @@
<div class="btn-wrapper">
<a class="cta-primary" [routerLink]="['/product', 'search']">Artikel suchen</a>
<a class="cta-secondary" [routerLink]="['/cart', 'dummy']">Neuanlage</a>
<button class="cta-secondary" (click)="openDummyModal()">Neuanlage</button>
</div>
</div>
</div>
@@ -79,12 +79,8 @@
"
></ui-icon>
<div class="label" [class.dummy]="group.orderType === 'Dummy'">
<ng-container [ngSwitch]="group.orderType">
<ng-container *ngSwitchCase="'Dummy'">Manuelle Anlage / Dummy Bestellung</ng-container>
<ng-container *ngSwitchCase="'DIG-Versand'">Versand</ng-container>
<ng-container *ngSwitchDefault> {{ group.orderType }} </ng-container>
</ng-container>
<a *ngIf="group.orderType === 'Dummy'" class="cta-secondary" [routerLink]="['/cart', 'dummy']">Hinzufügen</a>
{{ group.orderType !== 'Dummy' ? group.orderType : 'Manuelle Anlage / Dummy Bestellung' }}
<button *ngIf="group.orderType === 'Dummy'" class="cta-secondary" (click)="openDummyModal()">Hinzufügen</button>
</div>
</div>
<ng-container *ngIf="group.orderType === 'Versand' || group.orderType === 'B2B-Versand' || group.orderType === 'DIG-Versand'">
@@ -131,7 +127,11 @@
>
<div class="product-misc">
<img class="book-icon" [src]="'/assets/images/Icon_' + item?.product?.format + '.svg'" alt="book-icon" />
{{ item?.product?.manufacturer + ' | ' + item?.product?.contributors | trim: 30 }}
{{ item?.product?.manufacturer }}
<ng-container *ngIf="item?.product?.contributors">
{{ ' | ' + item?.product?.contributors | trim: 30 }}
</ng-container>
</div>
<div
*ngIf="group.orderType !== 'Rücklage' && group.orderType !== 'Download' && group.orderType !== 'Dummy'"

View File

@@ -67,7 +67,7 @@
}
.cta-secondary {
@apply bg-white text-brand border-brand font-bold text-lg outline-none px-6 py-3 mt-4;
@apply bg-white text-brand border-none font-bold text-lg outline-none px-6 py-3 mt-4;
}
.cta-order.special-comment-dirty {
@@ -109,7 +109,6 @@ hr {
.cta-secondary {
@apply mt-0 pr-0;
text-decoration: none;
}
}

View File

@@ -14,6 +14,7 @@ import { Subject, NEVER } from 'rxjs';
import { DomainCatalogService } from '@domain/catalog';
import { BreadcrumbService } from '@core/breadcrumb';
import { DomainPrinterService } from '@domain/printer';
import { CheckoutDummyComponent } from '../checkout-dummy/checkout-dummy.component';
import { ResponseArgsOfItemDTO } from '@swagger/cat';
@Component({
@@ -179,22 +180,28 @@ export class CheckoutReviewComponent implements OnInit {
});
}
changeDummyItem(shoppingCartItem: ShoppingCartItemDTO) {
this.router.navigate(['/cart', 'dummy'], {
queryParams: {
price: shoppingCartItem?.availability?.price?.value?.value,
vat: shoppingCartItem?.availability?.price?.vat?.vatType,
supplier: shoppingCartItem?.availability?.supplier?.id,
estimatedShippingDate: shoppingCartItem?.estimatedShippingDate,
manufacturer: shoppingCartItem?.product?.manufacturer,
name: shoppingCartItem?.product?.name,
contributors: shoppingCartItem?.product?.contributors,
ean: shoppingCartItem?.product?.ean,
quantity: shoppingCartItem?.quantity,
},
openDummyModal(data?: any) {
this.uiModal.open({
content: CheckoutDummyComponent,
data,
});
}
changeDummyItem(shoppingCartItem: ShoppingCartItemDTO) {
const data = {
price: shoppingCartItem?.availability?.price?.value?.value,
vat: shoppingCartItem?.availability?.price?.vat?.vatType,
supplier: shoppingCartItem?.availability?.supplier?.id,
estimatedShippingDate: shoppingCartItem?.estimatedShippingDate,
manufacturer: shoppingCartItem?.product?.manufacturer,
name: shoppingCartItem?.product?.name,
contributors: shoppingCartItem?.product?.contributors,
ean: shoppingCartItem?.product?.ean,
quantity: shoppingCartItem?.quantity,
};
this.openDummyModal(data);
}
async changeItem(shoppingCartItem: ShoppingCartItemDTO) {
this.showChangeButtonSpinnerItemId = shoppingCartItem.id;

View File

@@ -68,8 +68,10 @@
<div class="info-row">
<img class="order-icon" [src]="'/assets/images/Icon_' + order?.product?.format + '.svg'" alt="book-icon" />
<span class="format">{{ order.product?.format }}</span>
<span class="separator">|</span>
<span class="contributors">{{ order?.product?.contributors }}</span>
<ng-container *ngIf="order?.product?.contributors">
<span class="separator">|</span>
<span class="contributors">{{ order?.product?.contributors }}</span>
</ng-container>
</div>
<div class="delivery-row" [ngSwitch]="order?.features?.orderType">
<ng-container *ngSwitchCase="'Abholung'">

View File

@@ -181,7 +181,10 @@ export class PurchasingOptionsModalComponent {
this.purchasingOptionsModalStore.setOption(this.modalRef.data.option);
this.purchasingOptionsModalStore.setAvailableOptions(this.modalRef.data.availableOptions);
if (this.modalRef.data.availableOptions?.some((option) => option === 'pick-up' || option === 'take-away')) {
if (
this.modalRef.data.availableOptions?.some((option) => option === 'pick-up' || option === 'take-away') ||
['take-away', 'pick-up'].includes(this.modalRef.data.option)
) {
this.purchasingOptionsModalStore.loadBranches(this.modalRef?.data?.branchId);
}
}

View File

@@ -1,6 +1,5 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { CheckoutDummyComponent } from './checkout-dummy/checkout-dummy.component';
import { CheckoutReviewComponent } from './checkout-review/checkout-review.component';
import { CheckoutSummaryComponent } from './checkout-summary/checkout-summary.component';
import { PageCheckoutComponent } from './page-checkout.component';
@@ -12,7 +11,6 @@ const routes: Routes = [
children: [
{ path: 'summary', component: CheckoutSummaryComponent },
{ path: 'review', component: CheckoutReviewComponent },
{ path: 'dummy', component: CheckoutDummyComponent },
{ path: '', pathMatch: 'full', redirectTo: 'review' },
],
},

View File

@@ -5,7 +5,7 @@ import { ApplicationService } from '@core/application';
import { BreadcrumbService } from '@core/breadcrumb';
import { CrmCustomerService } from '@domain/crm';
import { AddressDTO, CustomerDTO } from '@swagger/crm';
import { UiModalService } from '@ui/modal';
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
import { AddressSelectionModalService } from '../modals/address-selection-modal/address-selection-modal.service';
import { CustomerCreateComponentBase } from './customer-create.component';
import { validateEmail } from '../validators/email-validator';
@@ -14,6 +14,7 @@ import { DomainCheckoutService } from '@domain/checkout';
import { UiValidators } from '@ui/validators';
import { isStringEmpty } from '@utils/common';
import { HttpErrorResponse } from '@angular/common/http';
import { map } from 'rxjs/operators';
@Component({
selector: 'page-customer-create-branch',
@@ -47,7 +48,8 @@ export class CustomerCreateBranchComponent extends CustomerCreateComponentBase i
public application: ApplicationService,
public addressSelectionModal: AddressSelectionModalService,
public checkoutService: DomainCheckoutService,
public cdr: ChangeDetectorRef
public cdr: ChangeDetectorRef,
private _modal: UiModalService
) {
super();
}
@@ -55,6 +57,14 @@ export class CustomerCreateBranchComponent extends CustomerCreateComponentBase i
ngOnInit() {
this.init();
if (!!this.p4mUser) {
this.cusotmers$ = this.cusotmers$.pipe(
map((data) => ({
values: data.values.filter((f) => f.value === 'store'),
}))
);
}
this.shippingAddressGroup.disable();
this.shippingAddressSubscription = this.control.get('differentShippingAddress').valueChanges.subscribe((isChecked) => {
if (isChecked) {
@@ -219,7 +229,12 @@ export class CustomerCreateBranchComponent extends CustomerCreateComponentBase i
}
try {
const response = await this.customerService.createBranchCustomer(this.control.value).toPromise();
let newCustomer: CustomerDTO = this.control.value;
if (!!this.p4mUser) {
newCustomer.features = newCustomer.features ? [...newCustomer.features, this.p4mUser] : [this.p4mUser];
}
const response = await this.customerService.createBranchCustomer(newCustomer).toPromise();
if (this.control.value.differentShippingAddress) {
try {
@@ -243,6 +258,7 @@ export class CustomerCreateBranchComponent extends CustomerCreateComponentBase i
}
} catch (error) {
this.setValidationError(error.error?.invalidProperties, this.control);
this._modal.open({ content: UiErrorModalComponent, data: error, title: 'Fehler beim Anlegen eines Filialkunden' });
}
}

View File

@@ -96,7 +96,7 @@
</div>
</ng-container>
<ui-form-control label="Geburtsdatum (TT.MM.JJJJ)">
<ui-form-control label="Geburtsdatum (TT.MM.JJJJ)" [requiredMark]="!!p4mUser ? '*' : ''">
<input uiDateInput type="text" formControlName="dateOfBirth" tabindex="15" />
</ui-form-control>

View File

@@ -7,7 +7,7 @@ import { DomainCheckoutService } from '@domain/checkout';
import { CrmCustomerService } from '@domain/crm';
import { CustomerDTO } from '@swagger/crm';
import { UiValidators } from '@ui/validators';
import { UiModalService } from '@ui/modal';
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
import { map } from 'rxjs/operators';
import { AddressSelectionModalService } from '../modals/address-selection-modal/address-selection-modal.service';
import { validateEmail } from '../validators/email-validator';
@@ -54,7 +54,8 @@ export class CustomerCreateOnlineComponent extends CustomerCreateComponentBase i
public application: ApplicationService,
public addressSelectionModal: AddressSelectionModalService,
public checkoutService: DomainCheckoutService,
public cdr: ChangeDetectorRef
public cdr: ChangeDetectorRef,
private _modal: UiModalService
) {
super();
}
@@ -65,7 +66,7 @@ export class CustomerCreateOnlineComponent extends CustomerCreateComponentBase i
this.countries$ = this.countries$.pipe(map((countries) => countries.filter((country) => country.name === 'Deutschland')));
this.upgradeCustomerId = Number(this.activatedRoute.snapshot.queryParams.upgradeCustomerId);
if (!!this.upgradeCustomerId) {
if (!!this.upgradeCustomerId || !!this.p4mUser) {
this.cusotmers$ = this.cusotmers$.pipe(
map((data) => ({
...data,
@@ -129,7 +130,7 @@ export class CustomerCreateOnlineComponent extends CustomerCreateComponentBase i
title: fb.control(customer?.title),
lastName: fb.control(customer?.lastName, [Validators.required]),
firstName: fb.control(customer?.firstName, [Validators.required]),
dateOfBirth: fb.control(customer?.dateOfBirth, [UiValidators.date]),
dateOfBirth: fb.control(customer?.dateOfBirth, [!!this.p4mUser ? Validators.required : () => null, UiValidators.date]),
communicationDetails: fb.group({
email: fb.control(
customer?.communicationDetails?.email,
@@ -248,6 +249,10 @@ export class CustomerCreateOnlineComponent extends CustomerCreateComponentBase i
];
}
if (!!this.p4mUser) {
newCustomer.features = newCustomer.features ? [...newCustomer.features, this.p4mUser] : [this.p4mUser];
}
const response = await this.customerService.createOnlineCustomer(newCustomer).toPromise();
if (response.error) {
@@ -264,6 +269,7 @@ export class CustomerCreateOnlineComponent extends CustomerCreateComponentBase i
} else {
this.setValidationError(error?.error?.invalidProperties, this.control);
}
this._modal.open({ content: UiErrorModalComponent, data: error, title: 'Fehler beim Anlegen eines Onlinekunden' });
}
this.control.markAllAsTouched();

View File

@@ -1,7 +1,7 @@
import { AbstractControl, AsyncValidatorFn, FormArray, FormGroup, ValidationErrors, Validators } from '@angular/forms';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { CrmCustomerService } from '@domain/crm';
import { CountryDTO, CustomerDTO, InputOptionsDTO } from '@swagger/crm';
import { CountryDTO, CustomerDTO, InputOptionsDTO, KeyValueDTOOfStringAndString } from '@swagger/crm';
import { Observable } from 'rxjs';
import { first, map } from 'rxjs/operators';
import { UiModalService } from '@ui/modal';
@@ -42,6 +42,15 @@ export abstract class CustomerCreateComponentBase {
abstract cdr: ChangeDetectorRef;
cusotmers$: Observable<InputOptionsDTO>;
private _p4mUser: KeyValueDTOOfStringAndString;
get p4mUser() {
return this._p4mUser;
}
set p4mUser(data: KeyValueDTOOfStringAndString) {
this._p4mUser = data;
}
get organisationGroup(): AbstractControl {
return this.control?.get('organisation');
@@ -130,6 +139,10 @@ export abstract class CustomerCreateComponentBase {
return undefined;
}
if (query.card) {
this.p4mUser = JSON.parse(decodeURIComponent(query.card));
}
return {
gender: (+query.gender || 0) as any,
title: query.title,

View File

@@ -90,8 +90,11 @@ export abstract class CustomerDataEditComponent implements OnInit {
const { fb } = this;
const customerDTO = await this.customer$.pipe(first()).toPromise();
const customerType = await this.customerType$.pipe(first()).toPromise();
const customerFeatures = await this.customerFeatures$.pipe(first()).toPromise();
const isB2b = customerType === 'b2b';
const isBranch = customerType === 'store';
const isWebshop = customerType === 'webshop';
const isCard = customerFeatures.find((feature) => feature.key === 'p4muser');
this.control = fb.group(
{
@@ -99,7 +102,7 @@ export abstract class CustomerDataEditComponent implements OnInit {
title: fb.control(customerDTO?.title),
lastName: fb.control(customerDTO?.lastName, [Validators.required]),
firstName: fb.control(customerDTO?.firstName, [Validators.required]),
dateOfBirth: fb.control(customerDTO?.dateOfBirth, UiValidators.date),
dateOfBirth: fb.control(customerDTO?.dateOfBirth, [isWebshop && isCard ? Validators.required : () => null, UiValidators.date]),
communicationDetails: fb.group({
email: fb.control(customerDTO?.communicationDetails?.email, [validateEmail]),
phone: fb.control(customerDTO?.communicationDetails?.phone),

View File

@@ -315,7 +315,9 @@ export abstract class CustomerSearch implements OnInit, OnDestroy {
result: r.result.map((a) => ({ ...a, loaded: true })),
});
if (this.searchState === 'result') {
if (hits === 1) {
if (Number(r?.result[0]?.id) < 0) {
this.navgateToCreateCustomer(r.result[0]);
} else if (hits === 1) {
this.navigateToDetails(r.result[0].id);
} else {
this.navigateToResults();
@@ -421,6 +423,32 @@ export abstract class CustomerSearch implements OnInit, OnDestroy {
}
}
navgateToCreateCustomer(customer: CustomerInfoDTO) {
const customerCreateQueryParams = {
gender: customer?.gender,
title: customer?.title,
firstName: customer?.firstName,
lastName: customer?.lastName,
email: customer?.communicationDetails?.email,
phone: customer?.communicationDetails?.phone,
mobile: customer?.communicationDetails?.mobile,
street: customer?.address?.street,
streetNumber: customer?.address?.streetNumber,
zipCode: customer?.address?.zipCode,
city: customer?.address?.city,
country: customer?.address?.country,
info: customer?.address?.info,
name: customer?.organisation?.name,
department: customer?.organisation?.department,
vatId: customer?.organisation?.vatId,
dateOfBirth: customer?.dateOfBirth,
card: encodeURIComponent(JSON.stringify(customer?.features[0])),
};
this.router.navigate(['customer', 'create', customer?.features?.find((feature) => feature.key === 'webshop') ? 'webshop' : 'store'], {
queryParams: customerCreateQueryParams,
});
}
navigateToDetails(customerId: number) {
this.router.navigate(['customer', customerId]);
}

View File

@@ -1,4 +1,4 @@
<a class="card-create-customer" [routerLink]="['/customer', 'create']">
<a class="card-create-customer" [routerLink]="['/customer', 'create']" [queryParams]="customerCreateQueryParams">
<span class="title"> Kundendaten erfassen </span>
</a>
<div class="card-search-customer" *ngIf="search.searchState$ | async as searchState">
@@ -7,5 +7,5 @@
Wie lautet Ihr Name oder <br />
Ihre E-Mail-Adresse?
</p>
<page-customer-searchbox></page-customer-searchbox>
<page-customer-searchbox (valueChanged)="updateCustomerCreateQueryParams($event)"></page-customer-searchbox>
</div>

View File

@@ -21,6 +21,8 @@ export class CustomerSearchMainComponent implements OnInit, OnDestroy {
subscriptions = new Subscription();
customerCreateQueryParams?: Record<string, string>;
constructor(
public search: CustomerSearch,
public cdr: ChangeDetectorRef,
@@ -70,4 +72,16 @@ export class CustomerSearchMainComponent implements OnInit, OnDestroy {
this.isMobile = await this.environmentService.isMobile();
this.cdr.detectChanges();
}
updateCustomerCreateQueryParams(value: string) {
if (this.isValidEmail(value)) {
this.customerCreateQueryParams = { email: value };
} else {
this.customerCreateQueryParams = { lastName: value };
}
}
isValidEmail(email: string) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
}

View File

@@ -30,6 +30,9 @@ export class CustomerSearchboxComponent implements OnInit, OnDestroy {
@Output()
searchStarted = new EventEmitter<void>();
@Output()
valueChanged = new EventEmitter<string>();
constructor(
public search: CustomerSearch,
private environmentService: EnvironmentService,
@@ -53,7 +56,10 @@ export class CustomerSearchboxComponent implements OnInit, OnDestroy {
});
});
this.queryControl.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((value) => this.search.setQuery(value));
this.queryControl.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((value) => {
this.search.setQuery(value);
this.valueChanged.emit(value);
});
}
ngOnDestroy() {}

View File

@@ -32,6 +32,7 @@
(selectedChange)="setSelectedItem(item, $event)"
[selectable]="item | goodsInCleanupSelectable: selectionRules:selectedItems"
[selected]="item | goodsInCleanupSelected: selectedOrderItemSubsetIds"
(click)="navigateToDetails(item)"
[showSupplier]="true"
[quantityEditable]="item.overallQuantity > 1 && (selectedOrderItemSubsetIds$ | async)?.includes(item.orderItemSubsetId)"
></shared-goods-in-out-order-group-item>

View File

@@ -52,3 +52,7 @@
@apply bg-white text-brand;
}
}
shared-goods-in-out-order-group-item {
@apply cursor-pointer;
}

View File

@@ -1,10 +1,12 @@
import { ChangeDetectionStrategy, Component, OnDestroy, OnInit, QueryList, ViewChildren } from '@angular/core';
import { ChangeDetectionStrategy, Component, OnDestroy, OnInit, QueryList, ViewChild, ViewChildren } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { BreadcrumbService } from '@core/breadcrumb';
import { CommandService } from '@core/command';
import { OrderItemsContext } from '@domain/oms';
import { GoodsInOutOrderGroupItemComponent } from '@shared/goods-in-out';
import { KeyValueDTOOfStringAndString, OrderItemListItemDTO } from '@swagger/oms';
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
import { UiScrollContainerComponent } from '@ui/scroll-container';
import { BehaviorSubject, combineLatest, Subject } from 'rxjs';
import { first, map, shareReplay, takeUntil } from 'rxjs/operators';
import { GoodsInCleanupListStore } from './goods-in-cleanup-list.store';
@@ -17,8 +19,11 @@ import { GoodsInCleanupListStore } from './goods-in-cleanup-list.store';
providers: [GoodsInCleanupListStore],
})
export class GoodsInCleanupListComponent implements OnInit, OnDestroy {
@ViewChild(UiScrollContainerComponent) scrollContainer: UiScrollContainerComponent;
@ViewChildren(GoodsInOutOrderGroupItemComponent) listItems: QueryList<GoodsInOutOrderGroupItemComponent>;
private _scrollPosition: number;
items$ = this._store.results$;
itemLength$ = this.items$.pipe(map((items) => items?.length));
@@ -68,20 +73,24 @@ export class GoodsInCleanupListComponent implements OnInit, OnDestroy {
private _breadcrumb: BreadcrumbService,
private _store: GoodsInCleanupListStore,
private _commandService: CommandService,
private _modal: UiModalService
private _modal: UiModalService,
private _route: ActivatedRoute,
private _router: Router
) {}
ngOnInit(): void {
this.initInitialSearch();
this.updateBreadcrumb();
this.createBreadcrumb();
this.removeBreadcrumbs();
}
ngOnDestroy(): void {
this._onDestroy$.next();
this._onDestroy$.complete();
this.updateBreadcrumb();
}
async updateBreadcrumb() {
async createBreadcrumb() {
await this._breadcrumb.addOrUpdateBreadcrumbIfNotExists({
key: 'goods-in',
name: 'Abholfachbereinigungsliste',
@@ -91,13 +100,42 @@ export class GoodsInCleanupListComponent implements OnInit, OnDestroy {
});
}
async updateBreadcrumb() {
const crumbs = await this._breadcrumb.getBreadcrumbsByKeyAndTags$('goods-in', ['goods-in', 'cleanup']).pipe(first()).toPromise();
for (const crumb of crumbs) {
this._breadcrumb.patchBreadcrumb(crumb.id, {
name: crumb.name,
params: { scroll_position: this.scrollContainer.scrollPos },
});
}
}
async removeBreadcrumbs() {
const detailsCrumbs = await this._breadcrumb.getBreadcrumbsByKeyAndTags$('goods-in', ['goods-in', 'details']).pipe(first()).toPromise();
const editCrumbs = await this._breadcrumb.getBreadcrumbsByKeyAndTags$('goods-in', ['goods-in', 'edit']).pipe(first()).toPromise();
detailsCrumbs.forEach((crumb) => {
this._breadcrumb.removeBreadcrumb(crumb.id, true);
});
editCrumbs.forEach((crumb) => {
this._breadcrumb.removeBreadcrumb(crumb.id, true);
});
}
initInitialSearch() {
if (this._store.hits === 0) {
this._store.searchResult$.pipe(takeUntil(this._onDestroy$)).subscribe(async (result) => {
await this.updateBreadcrumb();
await this.createBreadcrumb();
if (this._scrollPosition) {
this.scrollContainer.scrollTo(Number(this._scrollPosition ?? 0));
this._scrollPosition = undefined;
}
});
}
this._scrollPosition = this._route.snapshot.queryParams?.scroll_position;
this._store.search();
}
@@ -124,6 +162,14 @@ export class GoodsInCleanupListComponent implements OnInit, OnDestroy {
return action.enabled !== false;
}
navigateToDetails(orderItem: OrderItemListItemDTO) {
const orderNumber = orderItem.orderNumber;
const processingStatus = orderItem.processingStatus;
const orderItemId = orderItem.orderItemId;
this._router.navigate([`/goods/in/details/order/${encodeURIComponent(orderNumber)}/item/${orderItemId}/${processingStatus}`]);
}
async handleAction(action: KeyValueDTOOfStringAndString) {
this.changeActionLoader$.next(true);

View File

@@ -125,7 +125,7 @@ export class GoodsInDetailsComponent extends ComponentStore<GoodsInDetailsCompon
items: res.result.map((item) => ({
...item,
// Anzeige von Teilabholung in Wareneingang ausblenden
actions: item.actions.filter((action) => action.command !== 'FETCHED_PARTIAL'),
actions: item?.actions?.filter((action) => action.command !== 'FETCHED_PARTIAL') ?? [],
})),
orderId: res.result[0].orderId,
});

View File

@@ -7,9 +7,17 @@
bestellen Sie Artikel nach
</p>
</div>
<div class="list-count">{{ hits$ | async }} Titel</div>
<div class="filter-wrapper">
<div class="hits" *ngIf="hits$ | async; let hits">{{ hits }} Titel</div>
<ui-order-by-filter
[orderBy]="(filter$ | async)?.orderBy"
(selectedOrderByChange)="store.search({ clear: true }); updateBreadcrumb()"
></ui-order-by-filter>
</div>
<ui-scroll-container
#scrollContainer
*ngIf="!(listEmpty$ | async); else emptyMessage"
[loading]="loading$ | async"
(reachEnd)="loadMore()"

View File

@@ -11,7 +11,19 @@
}
.goods-in-list-paragraph {
@apply text-2xl m-0 mt-1;
@apply text-2xl m-0 mb-6 mt-1;
}
}
.filter-wrapper {
@apply block relative;
.hits {
@apply text-inactive-branch font-semibold mb-3 absolute right-0 top-2;
}
ui-order-by-filter {
@apply mx-auto;
}
}
@@ -19,8 +31,8 @@
@apply cursor-pointer;
}
.list-count {
@apply text-active-branch text-right mb-3 font-semibold text-base;
ui-order-by-filter {
@apply mb-2;
}
::ng-deep page-goods-in-list ui-scroll-container {

View File

@@ -1,10 +1,13 @@
import { AfterViewInit, ChangeDetectionStrategy, Component, OnDestroy, OnInit, QueryList, ViewChildren } from '@angular/core';
import { Router } from '@angular/router';
import { AfterViewInit, ChangeDetectionStrategy, Component, OnDestroy, OnInit, QueryList, ViewChild, ViewChildren } from '@angular/core';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { BreadcrumbService } from '@core/breadcrumb';
import { DomainOmsService } from '@domain/oms';
import { OrderItemListItemDTO } from '@swagger/oms';
import { UiFilter } from '@ui/filter';
import { UiScrollContainerComponent } from '@ui/scroll-container';
import { isEqual } from 'lodash';
import { BehaviorSubject, combineLatest, Observable, Subject } from 'rxjs';
import { first, map, shareReplay, takeUntil } from 'rxjs/operators';
import { debounceTime, first, map, shareReplay, takeUntil, tap } from 'rxjs/operators';
import { GoodsInListItemComponent } from './goods-in-list-item/goods-in-list-item.component';
import { GoodsInListStore } from './goods-in-list.store';
@@ -18,13 +21,18 @@ import { GoodsInListStore } from './goods-in-list.store';
export class GoodsInListComponent implements OnInit, AfterViewInit, OnDestroy {
@ViewChildren(GoodsInListItemComponent) listItems: QueryList<GoodsInListItemComponent>;
items$ = this._store.results$;
@ViewChild('scrollContainer', { static: false })
scrollContainer: UiScrollContainerComponent;
items$ = this.store.results$;
itemLength$ = this.items$.pipe(map((items) => items?.length));
hits$ = this._store.hits$;
hits$ = this.store.hits$;
loading$ = this._store.loading$.pipe(shareReplay());
loading$ = this.store.loading$.pipe(shareReplay());
filter$ = this.store.filter$;
listEmpty$ = combineLatest([this.loading$, this.hits$]).pipe(
map(([loading, hits]) => !loading && hits === 0),
@@ -42,19 +50,76 @@ export class GoodsInListComponent implements OnInit, AfterViewInit, OnDestroy {
constructor(
private _breadcrumb: BreadcrumbService,
private _domainOmsService: DomainOmsService,
private _store: GoodsInListStore,
private _router: Router
public store: GoodsInListStore,
private _router: Router,
private _route: ActivatedRoute
) {}
ngOnInit() {
this.initInitialSearch();
this.updateBreadcrumb();
this.removeBreadcrumbs();
this.store.setTake(Number(this._route.snapshot.queryParams.take ?? 25));
this._route.queryParams.pipe(takeUntil(this._onDestroy$), debounceTime(0)).subscribe(async (params) => {
const scrollPos = Number(params.scroll_position ?? 0);
// Initial Search - Always Search If No Params Are Set
if (
(Object.keys(params).length === 0 || this.store.results.length === 0) &&
Object.keys(this.cleanupQueryParams(params)).length === 0
) {
this.store.search({
cb: () => {
setTimeout(() => {
this.scrollContainer?.scrollTo(scrollPos);
}, 0);
},
});
}
if (this.store.filter instanceof UiFilter) {
await this.updateBreadcrumb(this.store.filter.getQueryParams());
} else {
this.store.setDefaultFilter();
}
const cleanQueryParams = this.cleanupQueryParams(params);
if (!isEqual(cleanQueryParams, this.cleanupQueryParams(this.store?.filter?.getQueryParams()))) {
this.store?.filter?.fromQueryParams(params);
this.store.search({
cb: () => {
setTimeout(() => {
this.scrollContainer?.scrollTo(scrollPos);
}, 0);
},
});
}
await this.updateBreadcrumb({ queryParams: params });
await this.createBreadcrumb({ queryParams: params });
await this.removeBreadcrumbs();
});
}
ngOnDestroy(): void {
this._onDestroy$.next();
this._onDestroy$.complete();
this.updateBreadcrumb(this.store.filter.getQueryParams());
}
cleanupQueryParams(params: Record<string, string> = {}) {
const clean = { ...params };
delete clean['scroll_position'];
delete clean['take'];
for (const key in clean) {
if (Object.prototype.hasOwnProperty.call(clean, key)) {
if (clean[key] == undefined) {
delete clean[key];
}
}
}
return clean;
}
ngAfterViewInit(): void {
@@ -87,12 +152,29 @@ export class GoodsInListComponent implements OnInit, AfterViewInit, OnDestroy {
});
}
async updateBreadcrumb() {
async updateBreadcrumb(queryParams: Record<string, string> | Params = this.store.filter?.getQueryParams()) {
const scroll_position = this.scrollContainer?.scrollPos;
const take = this._route?.snapshot?.queryParams?.take;
if (queryParams) {
const crumbs = await this._breadcrumb.getBreadcrumbsByKeyAndTags$('goods-in', ['goods-in', 'list']).pipe(first()).toPromise();
const params = { ...queryParams, scroll_position, take };
for (const crumb of crumbs) {
this._breadcrumb.patchBreadcrumb(crumb.id, {
params,
});
}
}
}
async createBreadcrumb(queryParams: Params) {
await this._breadcrumb.addOrUpdateBreadcrumbIfNotExists({
key: 'goods-in',
name: 'Wareneingangsliste',
path: '/goods/in/list',
section: 'branch',
params: queryParams,
tags: ['goods-in', 'list'],
});
}
@@ -104,19 +186,9 @@ export class GoodsInListComponent implements OnInit, AfterViewInit, OnDestroy {
]).pipe(map(([sscInvalid, sscChanged]) => sscInvalid.includes(true) || sscChanged.every((item) => !item)));
}
initInitialSearch() {
if (this._store.hits === 0) {
this._store.searchResult$.pipe(takeUntil(this._onDestroy$)).subscribe(async (result) => {
await this.updateBreadcrumb();
});
}
this._store.search();
}
async loadMore() {
if (this._store.hits > this._store.results.length && !this._store.loading) {
this._store.search();
if (this.store.hits > this.store.results.length && !this.store.loading) {
this.store.search({});
}
}
@@ -146,6 +218,6 @@ export class GoodsInListComponent implements OnInit, AfterViewInit, OnDestroy {
}
refreshList() {
this._store.reload();
this.store.reload();
}
}

View File

@@ -1,6 +1,7 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { UiCommonModule } from '@ui/common';
import { UiOrderByFilterModule } from '@ui/filter';
import { UiIconModule } from '@ui/icon';
import { UiScrollContainerModule } from '@ui/scroll-container';
import { UiSpinnerModule } from 'apps/ui/spinner/src/lib/ui-spinner.module';
@@ -9,7 +10,15 @@ import { GoodsInListItemModule } from './goods-in-list-item/goods-in-list-item.m
import { GoodsInListComponent } from './goods-in-list.component';
@NgModule({
imports: [CommonModule, UiCommonModule, UiIconModule, GoodsInListItemModule, UiScrollContainerModule, UiSpinnerModule],
imports: [
CommonModule,
UiCommonModule,
UiIconModule,
GoodsInListItemModule,
UiScrollContainerModule,
UiOrderByFilterModule,
UiSpinnerModule,
],
exports: [],
declarations: [GoodsInListComponent],
providers: [],

View File

@@ -1,18 +1,21 @@
import { HttpErrorResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { DomainAvailabilityService } from '@domain/availability';
import { Router } from '@angular/router';
import { DomainGoodsService } from '@domain/oms';
import { ComponentStore, tapResponse } from '@ngrx/component-store';
import { ListResponseArgsOfOrderItemListItemDTO, OrderItemListItemDTO, QueryTokenDTO } from '@swagger/oms';
import { UiFilter } from '@ui/filter';
import { isResponseArgs } from '@utils/object';
import { Subject } from 'rxjs';
import { switchMap, tap, withLatestFrom } from 'rxjs/operators';
import { Observable, Subject } from 'rxjs';
import { map, switchMap, tap, withLatestFrom } from 'rxjs/operators';
export interface GoodsInListState {
message?: string;
loading: boolean;
hits: number;
take: number;
results: OrderItemListItemDTO[];
filter: UiFilter;
}
@Injectable()
@@ -27,6 +30,17 @@ export class GoodsInListStore extends ComponentStore<GoodsInListState> {
}
readonly hits$ = this.select((s) => s.hits);
get take() {
return this.get((s) => s.take);
}
readonly take$ = this.select((s) => s.take);
filter$ = this.select((s) => s.filter);
get filter() {
return this.get((s) => s.filter);
}
get loading() {
return this.get((s) => s.loading);
}
@@ -36,29 +50,55 @@ export class GoodsInListStore extends ComponentStore<GoodsInListState> {
readonly searchResult$ = this._searchResultSubject.asObservable();
constructor(private _domainGoodsInService: DomainGoodsService) {
constructor(private _domainGoodsInService: DomainGoodsService, private _router: Router) {
super({
loading: false,
hits: 0,
take: 25,
results: [],
filter: undefined,
});
this.setDefaultFilter();
}
search = this.effect(($) =>
$.pipe(
tap((_) => this.patchState({ loading: true })),
withLatestFrom(this.results$),
switchMap(([_, _results]) =>
this.searchRequest().pipe(
search = this.effect((options$: Observable<{ clear?: boolean; cb?: Function }>) =>
options$.pipe(
tap((options) => this.patchState({ loading: true, results: options.clear ? [] : this.results })),
withLatestFrom(this.results$, this.take$, this.filter$),
switchMap(([options, _results, _take, _filter]) =>
this.searchRequest({
skip: _results?.length,
take: _take,
filter: _filter,
}).pipe(
tapResponse(
(res) => {
const results = [...(_results ?? []), ...(res.result ?? [])];
this.patchState({
hits: res.hits,
results,
loading: false,
});
if (options.clear) {
this.patchState({
hits: res.hits,
results: res.result,
take: 25,
loading: false,
});
} else {
const items = this.get((s) => s.results);
this.patchState({
hits: res.hits,
results: [...items, ...res.result],
take: 25,
loading: false,
});
}
this._searchResultSubject.next(res);
if (res.hits > 1) {
const path = '/goods/in/list/';
if (!this._router.isActive(path, false)) {
this._router.navigate([path], {
queryParams: { ...this.filter.getQueryParams(), take: res.result.length + _results?.length },
});
}
}
options?.cb?.call(undefined);
},
(err: Error) => {
if (err instanceof HttpErrorResponse && isResponseArgs(err.error)) {
@@ -81,9 +121,9 @@ export class GoodsInListStore extends ComponentStore<GoodsInListState> {
reload = this.effect(($) =>
$.pipe(
tap((_) => this.patchState({ loading: true })),
withLatestFrom(this.results$),
switchMap(([_, results]) =>
this.searchRequest({ take: results?.length ?? 0, skip: 0 }).pipe(
withLatestFrom(this.results$, this.filter$),
switchMap(([_, results, filter]) =>
this.searchRequest({ take: results?.length ?? 0, skip: 0, filter }).pipe(
tapResponse(
(res) => {
this.patchState({
@@ -112,6 +152,23 @@ export class GoodsInListStore extends ComponentStore<GoodsInListState> {
)
);
async setDefaultFilter() {
const filter = await this._domainGoodsInService
.goodsInListQuerySettings()
.pipe(map((settings) => UiFilter.create(settings.result)))
.toPromise();
this.setFilter(filter);
}
setFilter(filter: UiFilter) {
this.patchState({ filter });
}
setTake(take: number) {
this.patchState({ take });
}
clearResults() {
this.patchState({
loading: false,
@@ -121,8 +178,9 @@ export class GoodsInListStore extends ComponentStore<GoodsInListState> {
});
}
searchRequest(options?: { take?: number; skip?: number }) {
searchRequest(options?: { take?: number; skip?: number; filter: UiFilter }) {
const queryToken: QueryTokenDTO = {
...options?.filter?.getQueryToken(),
skip: options?.skip ?? this.results.length,
take: options?.take ?? 20,
};

View File

@@ -1,11 +1,12 @@
import { ChangeDetectionStrategy, Component, OnDestroy, OnInit, QueryList, ViewChildren } from '@angular/core';
import { Router } from '@angular/router';
import { ChangeDetectionStrategy, Component, OnDestroy, OnInit, QueryList, ViewChild, ViewChildren } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { BreadcrumbService } from '@core/breadcrumb';
import { CommandService } from '@core/command';
import { OrderItemsContext } from '@domain/oms';
import { GoodsInOutOrderGroupItemComponent } from '@shared/goods-in-out';
import { KeyValueDTOOfStringAndString, OrderItemListItemDTO } from '@swagger/oms';
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
import { UiScrollContainerComponent } from '@ui/scroll-container';
import { BehaviorSubject, combineLatest, Subject } from 'rxjs';
import { map, shareReplay, takeUntil, first } from 'rxjs/operators';
import { GoodsInReservationStore } from './goods-in-reservation.store';
@@ -18,6 +19,7 @@ import { GoodsInReservationStore } from './goods-in-reservation.store';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class GoodsInReservationComponent implements OnInit, OnDestroy {
@ViewChild(UiScrollContainerComponent) scrollContainer: UiScrollContainerComponent;
@ViewChildren(GoodsInOutOrderGroupItemComponent) listItems: QueryList<GoodsInOutOrderGroupItemComponent>;
items$ = this._store.results$;
@@ -71,22 +73,24 @@ export class GoodsInReservationComponent implements OnInit, OnDestroy {
private _breadcrumb: BreadcrumbService,
private _store: GoodsInReservationStore,
private _commandService: CommandService,
private _route: ActivatedRoute,
private _router: Router,
private _modal: UiModalService
) {}
ngOnInit() {
this.initInitialSearch();
this.updateBreadcrumb();
this.createBreadcrumb();
this.removeBreadcrumbs();
}
ngOnDestroy(): void {
this._onDestroy$.next();
this._onDestroy$.complete();
this.updateBreadcrumb();
}
async updateBreadcrumb() {
async createBreadcrumb() {
await this._breadcrumb.addOrUpdateBreadcrumbIfNotExists({
key: 'goods-in',
name: 'Reservierungen',
@@ -96,6 +100,16 @@ export class GoodsInReservationComponent implements OnInit, OnDestroy {
});
}
async updateBreadcrumb() {
const crumbs = await this._breadcrumb.getBreadcrumbsByKeyAndTags$('goods-in', ['goods-in', 'reservation']).pipe(first()).toPromise();
for (const crumb of crumbs) {
this._breadcrumb.patchBreadcrumb(crumb.id, {
name: crumb.name,
params: { scroll_position: this.scrollContainer.scrollPos, take: this._store.results?.length },
});
}
}
async removeBreadcrumbs() {
const detailsCrumbs = await this._breadcrumb.getBreadcrumbsByKeyAndTags$('goods-in', ['goods-in', 'details']).pipe(first()).toPromise();
const editCrumbs = await this._breadcrumb.getBreadcrumbsByKeyAndTags$('goods-in', ['goods-in', 'edit']).pipe(first()).toPromise();
@@ -120,13 +134,22 @@ export class GoodsInReservationComponent implements OnInit, OnDestroy {
initInitialSearch() {
if (this._store.hits === 0) {
this._store.searchResult$.pipe(takeUntil(this._onDestroy$)).subscribe(async (result) => {
await this.updateBreadcrumb();
await this.createBreadcrumb();
if (result.hits === 1) {
this.navigateToDetails(result.result[0]);
} else {
if (!!this._store.searchOptions?.take) {
this._store.searchOptions = undefined;
this.scrollContainer.scrollTo(Number(scroll_position ?? 0));
}
}
});
}
const { scroll_position, take } = this._route.snapshot.queryParams;
if (!!take && !!scroll_position) {
this._store.searchOptions = { take: Number(take) };
}
this._store.search();
}

View File

@@ -14,6 +14,7 @@ export interface GoodsInReservationState {
hits: number;
results: OrderItemListItemDTO[];
selectedOrderItemSubsetIds: number[];
searchOptions?: { take?: number; skip?: number };
}
@Injectable()
@@ -38,6 +39,13 @@ export class GoodsInReservationStore extends ComponentStore<GoodsInReservationSt
}
selectedOrderItemSubsetIds$ = this.select((s) => s.selectedOrderItemSubsetIds);
get searchOptions() {
return this.get((s) => s.searchOptions);
}
set searchOptions(searchOptions: { take?: number; skip?: number }) {
this.patchState({ searchOptions });
}
private _searchResultSubject = new Subject<ListResponseArgsOfOrderItemListItemDTO>();
readonly searchResult$ = this._searchResultSubject.asObservable();
@@ -63,7 +71,7 @@ export class GoodsInReservationStore extends ComponentStore<GoodsInReservationSt
tap((_) => this.patchState({ loading: true })),
withLatestFrom(this.results$),
switchMap(([_, _results]) =>
this.searchRequest().pipe(
this.searchRequest(this.searchOptions).pipe(
tapResponse(
(res) => {
const results = [...(_results ?? []), ...(res.result ?? [])];

View File

@@ -6,7 +6,7 @@ import { ListResponseArgsOfOrderItemListItemDTO, OrderItemListItemDTO, QuerySett
import { UiFilter } from '@ui/filter';
import { isResponseArgs } from '@utils/object';
import { Subject } from 'rxjs';
import { delay, filter, first, mergeMap, switchMap, take, tap, withLatestFrom } from 'rxjs/operators';
import { filter, mergeMap, switchMap, take, tap, withLatestFrom } from 'rxjs/operators';
export interface GoodsInSearchState {
defaultSettings?: QuerySettingsDTO;
@@ -16,6 +16,7 @@ export interface GoodsInSearchState {
fetching: boolean;
hits: number;
results: OrderItemListItemDTO[];
searchOptions?: { take?: number; skip?: number };
}
@Injectable()
@@ -56,6 +57,13 @@ export class GoodsInSearchStore extends ComponentStore<GoodsInSearchState> {
readonly queryParams$ = this.select((s) => s.queryParams);
get searchOptions() {
return this.get((s) => s.searchOptions);
}
set searchOptions(searchOptions: { take?: number; skip?: number }) {
this.patchState({ searchOptions });
}
private _searchResultSubject = new Subject<ListResponseArgsOfOrderItemListItemDTO>();
readonly searchResult$ = this._searchResultSubject.asObservable();
@@ -129,15 +137,15 @@ export class GoodsInSearchStore extends ComponentStore<GoodsInSearchState> {
}
}
searchRequest() {
searchRequest(options?: { take?: number; skip?: number }) {
return this.filter$.pipe(
filter((f) => f instanceof UiFilter),
take(1),
mergeMap((filter) =>
this._domainGoodsInService.search({
...filter.getQueryToken(),
skip: this.results.length,
take: 50,
skip: options?.skip ?? this.results.length,
take: options?.take ?? 50,
})
)
);
@@ -148,7 +156,7 @@ export class GoodsInSearchStore extends ComponentStore<GoodsInSearchState> {
tap((_) => this.patchState({ fetching: true })),
withLatestFrom(this.results$),
switchMap(([_, _results]) =>
this.searchRequest().pipe(
this.searchRequest(this.searchOptions).pipe(
tapResponse(
(res) => {
const results = [...(_results ?? []), ...(res.result ?? [])];

View File

@@ -1,10 +1,11 @@
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy } from '@angular/core';
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { first, map, shareReplay, takeUntil } from 'rxjs/operators';
import { OrderItemListItemDTO } from '@swagger/oms';
import { ActivatedRoute, Router } from '@angular/router';
import { GoodsInSearchStore } from '../goods-in-search.store';
import { combineLatest, Subject } from 'rxjs';
import { BreadcrumbService } from '@core/breadcrumb';
import { UiScrollContainerComponent } from '@ui/scroll-container';
@Component({
selector: 'page-goods-in-search-results',
@@ -13,6 +14,8 @@ import { BreadcrumbService } from '@core/breadcrumb';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class GoodsInSearchResultsComponent implements OnInit, OnDestroy {
@ViewChild(UiScrollContainerComponent) scrollContainer: UiScrollContainerComponent;
items$ = this._goodsInSearchStore.results$.pipe(shareReplay());
hits$ = this._goodsInSearchStore.hits$;
@@ -45,13 +48,15 @@ export class GoodsInSearchResultsComponent implements OnInit, OnDestroy {
this._goodsInSearchStore.setQueryParams(this._activatedRoute.snapshot.queryParams);
this.initInitialSearch();
this.updateBreadcrumb();
this.createBreadcrumb();
this.removeBreadcrumbs();
}
ngOnDestroy() {
this._onDestroy$.next();
this._onDestroy$.complete();
this.updateBreadcrumb(this._goodsInSearchStore.queryParams);
}
async removeBreadcrumbs() {
@@ -67,7 +72,7 @@ export class GoodsInSearchResultsComponent implements OnInit, OnDestroy {
});
}
async updateBreadcrumb() {
async createBreadcrumb() {
await this._breadcrumb.addOrUpdateBreadcrumbIfNotExists({
key: 'goods-in',
name: this.getBreadcrumbName(),
@@ -78,6 +83,28 @@ export class GoodsInSearchResultsComponent implements OnInit, OnDestroy {
});
}
async updateBreadcrumb(queryParams: Record<string, string> = this._goodsInSearchStore.filter?.getQueryParams()) {
const scroll_position = this.scrollContainer?.scrollPos;
const take = this._goodsInSearchStore.results?.length;
if (queryParams) {
const crumbs = await this._breadcrumb
.getBreadcrumbsByKeyAndTags$('goods-in', ['goods-in', 'results', 'filter'])
.pipe(first())
.toPromise();
const name = queryParams.main_qs ? queryParams.main_qs : 'Alle Artikel';
const params = { ...queryParams, scroll_position, take };
for (const crumb of crumbs) {
this._breadcrumb.patchBreadcrumb(crumb.id, {
name,
params,
});
}
}
}
getBreadcrumbName() {
const input = this._goodsInSearchStore.filter?.getQueryParams()?.main_qs;
@@ -90,14 +117,23 @@ export class GoodsInSearchResultsComponent implements OnInit, OnDestroy {
if (result.hits === 0) {
await this._router.navigate(['/goods/in'], { queryParams: this._goodsInSearchStore.filter.getQueryParams() });
} else {
await this.updateBreadcrumb();
await this.createBreadcrumb();
if (result.hits === 1) {
await this.navigateToDetails(result.result[0]);
} else {
if (!!this._goodsInSearchStore.searchOptions?.take) {
this._goodsInSearchStore.searchOptions = undefined;
this.scrollContainer.scrollTo(Number(scroll_position ?? 0));
}
}
}
});
}
const { scroll_position, take } = this._goodsInSearchStore.queryParams;
if (!!take && !!scroll_position) {
this._goodsInSearchStore.searchOptions = { take: Number(take) };
}
this._goodsInSearchStore.search();
}

View File

@@ -16,6 +16,7 @@ export interface GoodsOutSearchState {
fetching: boolean;
hits: number;
results: OrderItemListItemDTO[];
searchOptions?: { take?: number; skip?: number };
}
@Injectable()
@@ -56,6 +57,13 @@ export class GoodsOutSearchStore extends ComponentStore<GoodsOutSearchState> {
readonly queryParams$ = this.select((s) => s.queryParams);
get searchOptions() {
return this.get((s) => s.searchOptions);
}
set searchOptions(searchOptions: { take?: number; skip?: number }) {
this.patchState({ searchOptions });
}
private _searchResultSubject = new Subject<ListResponseArgsOfOrderItemListItemDTO>();
readonly searchResult$ = this._searchResultSubject.asObservable();
@@ -153,7 +161,7 @@ export class GoodsOutSearchStore extends ComponentStore<GoodsOutSearchState> {
tap((_) => this.patchState({ fetching: true })),
withLatestFrom(this.results$),
switchMap(([_, _results]) =>
this.searchRequest().pipe(
this.searchRequest(this.searchOptions).pipe(
tapResponse(
(res) => {
const results = [...(_results ?? []), ...(res.result ?? [])];

View File

@@ -1,4 +1,4 @@
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy } from '@angular/core';
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { first, map, shareReplay, takeUntil } from 'rxjs/operators';
import { KeyValueDTOOfStringAndString, OrderItemListItemDTO } from '@swagger/oms';
import { ActivatedRoute, Router } from '@angular/router';
@@ -9,6 +9,7 @@ import { ComponentStore } from '@ngrx/component-store';
import { CommandService } from '@core/command';
import { OrderItemsContext } from '@domain/oms';
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
import { UiScrollContainerComponent } from '@ui/scroll-container';
export interface GoodsOutSearchResultsState {
selectedOrderItemSubsetIds: number[];
@@ -21,6 +22,8 @@ export interface GoodsOutSearchResultsState {
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearchResultsState> implements OnInit, OnDestroy {
@ViewChild(UiScrollContainerComponent) scrollContainer: UiScrollContainerComponent;
items$ = this._goodsOutSearchStore.results$;
itemLength$ = this.items$.pipe(map((items) => items?.length));
@@ -82,7 +85,7 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
this._goodsOutSearchStore.setQueryParams(this._activatedRoute.snapshot.queryParams);
this.initInitialSearch();
this.updateBreadcrumb();
this.createBreadcrumb();
this.removeBreadcrumbs();
this._goodsOutSearchStore.searchResultCleared.pipe(takeUntil(this._onDestroy$)).subscribe((_) => this.clearSelectedItems());
@@ -91,6 +94,8 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
ngOnDestroy() {
this._onDestroy$.next();
this._onDestroy$.complete();
this.updateBreadcrumb(this._goodsOutSearchStore.queryParams);
}
async removeBreadcrumbs() {
@@ -110,7 +115,7 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
});
}
async updateBreadcrumb() {
async createBreadcrumb() {
await this._breadcrumb.addOrUpdateBreadcrumbIfNotExists({
key: 'goods-out',
name: this.getBreadcrumbName(),
@@ -121,6 +126,28 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
});
}
async updateBreadcrumb(queryParams: Record<string, string> = this._goodsOutSearchStore.filter?.getQueryParams()) {
const scroll_position = this.scrollContainer.scrollPos;
const take = this._goodsOutSearchStore.results?.length;
if (queryParams) {
const crumbs = await this._breadcrumb
.getBreadcrumbsByKeyAndTags$('goods-out', ['goods-out', 'results', 'filter'])
.pipe(first())
.toPromise();
const name = queryParams.main_qs ? queryParams.main_qs : 'Alle Artikel';
const params = { ...queryParams, scroll_position, take };
for (const crumb of crumbs) {
this._breadcrumb.patchBreadcrumb(crumb.id, {
name,
params,
});
}
}
}
getBreadcrumbName() {
const input = this._goodsOutSearchStore.filter?.getQueryParams()?.main_qs;
@@ -133,14 +160,23 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
if (result.hits === 0) {
await this._router.navigate(['/goods/out'], { queryParams: this._goodsOutSearchStore.filter.getQueryParams() });
} else {
await this.updateBreadcrumb();
await this.createBreadcrumb();
if (result.hits === 1) {
await this.navigateToDetails(result.result[0]);
} else {
if (!!this._goodsOutSearchStore.searchOptions?.take) {
this._goodsOutSearchStore.searchOptions = undefined;
this.scrollContainer.scrollTo(Number(scroll_position ?? 0));
}
}
}
});
}
const { scroll_position, take } = this._goodsOutSearchStore.queryParams;
if (!!take && !!scroll_position) {
this._goodsOutSearchStore.searchOptions = { take: Number(take) };
}
this._goodsOutSearchStore.search();
}

View File

@@ -65,9 +65,9 @@
</div>
</div>
</div>
<div *ngIf="product.inStock > 0 && product.remissionQuantity > 0" class="actions">
<div class="actions" *ngIf="product.remissionQuantity > 0">
<app-button (action)="openRemitProductPartiallyDialog()">Remi-Menge / Platzierung ändern</app-button>
<app-button outline="true" (action)="openRemitProductDialog()">Remittieren</app-button>
<app-button *ngIf="product.inStock > 0" outline="true" (action)="openRemitProductDialog()">Remittieren</app-button>
</div>
</div>
<app-remission-add-product-to-shipping-document-dialog

View File

@@ -16,7 +16,7 @@
<ng-container *ngIf="emptyOrInvalidBarcode">
<!-- <app-barcode-scanner *ngIf="isSafari" (scan)="handleScanResult($event)"></app-barcode-scanner> -->
<lib-remission-container-scanner *ngIf="isNative" (scan)="handleScanResult($event)"></lib-remission-container-scanner>
<ui-searchbox *ngIf="isDesktop" placeholder="Wannennummer scannen" (search)="handleScanResult($event)"></ui-searchbox>
<ui-searchbox *ngIf="!isNative" placeholder="Wannennummer scannen" (search)="handleScanResult($event)"></ui-searchbox>
</ng-container>
</div>

View File

@@ -23,7 +23,6 @@ import { Breadcrumb } from 'apps/sales/src/app/core/models/breadcrumb.model';
import { AppService } from '@sales/core-services';
// tslint:disable-next-line: max-line-length
import { RemissionScanProductInvalidBarcodeComponent } from '../../components/remission-scan-product-invalid-barcode/remission-scan-product-invalid-barcode.component';
import { NativeContainerService } from 'shared/lib/remission-container-scanner/native-container.service';
// tslint:disable-next-line: max-line-length
import { RemissionScanShippingDocumentClosedComponent } from '../../components/remission-scan-shipping-document-closed/remission-scan-shipping-document-closed.component';
import { RemissionProcessStatuses } from 'apps/sales/src/app/core/models/remission-process-statuses.model';
@@ -37,6 +36,7 @@ import { isResponseArgs } from '@utils/object';
import { HttpErrorResponse } from '@angular/common/http';
import { ResponseArgs } from '@swagger/cat';
import { RemissionContainerScannerScanditComponent } from 'shared/public_api';
import { NativeContainerService } from 'native-container';
@Component({
selector: 'app-remission-finish',

View File

@@ -1,5 +1,4 @@
.shipping-document {
position: relative;
margin-top: 40px;
min-height: 700px;
}

View File

@@ -29,9 +29,7 @@ export class RemissionShippingDocumentContainerComponent implements AfterViewIni
constructor(private store: Store, private renderer: Renderer2, @Inject(DOCUMENT) private document: Document) {}
ngAfterViewInit() {
this.updateMinHeight();
}
ngAfterViewInit() {}
updateShippingDocument() {
this.currentRemissionProcess$
@@ -42,12 +40,4 @@ export class RemissionShippingDocumentContainerComponent implements AfterViewIni
)
.subscribe((remissionProcessId) => this.store.dispatch(new UpdateShippingDocuent(remissionProcessId)));
}
updateMinHeight() {
if (this.shippingDocumentContainer && this.document.body.clientHeight) {
const height = this.document.body.clientHeight;
this.renderer.setStyle(this.shippingDocumentContainer.nativeElement, 'min-height', `${height * 0.6}px`);
}
}
}

View File

@@ -1,5 +1,5 @@
<ng-container *ngIf="orderItem$ | async; let orderItem">
<div class="goods-in-out-order-details-features">
<div #features class="goods-in-out-order-details-features">
<ng-container *ngIf="orderItem?.features?.prebooked">
<img [uiOverlayTrigger]="prebookedTooltip" src="/assets/images/tag_icon_preorder.svg" [alt]="orderItem?.features?.prebooked" />
<ui-tooltip yPosition="above" xPosition="after" [yOffset]="-11" [xOffset]="-8" #prebookedTooltip [closeable]="true">
@@ -32,7 +32,9 @@
<img [src]="orderItem.product?.ean | productImage" [alt]="orderItem.product?.title" />
</div>
<div class="goods-in-out-order-details-item-details">
<h3>{{ [orderItem.product?.contributors, orderItem.product?.name] | title }}</h3>
<h3 [uiElementDistance]="features" #elementDistance="uiElementDistance" [style.max-width.px]="elementDistance.distanceChange | async">
{{ [orderItem.product?.contributors, orderItem.product?.name] | title }}
</h3>
<strong>Bestellung</strong>
<div class="detail">
<div class="label">Format</div>

View File

@@ -18,7 +18,12 @@
<input uiInput formControlName="clientChannel" />
</ui-form-control>
<shared-notification-channel-control formGroupName="notificationChannel"></shared-notification-channel-control>
<shared-notification-channel-control
(channelActionEvent)="generateNotification($event)"
[channelActionName]="'Erneut senden'"
[channelActionLoading]="notificationChannelLoading$ | async"
formGroupName="notificationChannel"
></shared-notification-channel-control>
<ui-form-control label="Kundennummer" variant="inline" statusLabel="Nicht Änderbar">
<input uiInput formControlName="buyerNumber" />
@@ -148,8 +153,11 @@
<input class="ssc-text" uiInput formControlName="sscText" />
</div>
<ui-form-control label="Vormerker" variant="inline" statusLabel="Nicht Änderbar">
<input uiInput formControlName="isPrebooked" />
<ui-form-control label="Vormerker" variant="inline">
<ui-select formControlName="isPrebooked">
<ui-select-option label="Ja" [value]="true"></ui-select-option>
<ui-select-option label="Nein" [value]="false"></ui-select-option>
</ui-select>
</ui-form-control>
<ui-form-control label="MwSt" variant="inline">

View File

@@ -13,11 +13,11 @@ import {
import { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { DomainOmsService } from '@domain/oms';
import { emailNotificationValidator, mobileNotificationValidator } from '@shared/notification-channel-control';
import { NotificationChannel, OrderDTO, OrderItemListItemDTO, StockStatusCodeDTO, VATDTO } from '@swagger/oms';
import { NotificationChannel, OrderItemListItemDTO, StockStatusCodeDTO, VATDTO } from '@swagger/oms';
import { DateAdapter } from '@ui/common';
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
import { UiSelectOptionComponent } from '@ui/select';
import { Observable, Subscription } from 'rxjs';
import { BehaviorSubject, Observable, Subscription } from 'rxjs';
import { first, shareReplay } from 'rxjs/operators';
import { ProcessingStatusNameMap } from '../constants/processing-status-name.map';
import { EnvironmentChannelPipe } from '../pipes/environment-channel.pipe';
@@ -38,9 +38,6 @@ export class SharedGoodsInOutOrderEditComponent implements OnChanges, OnDestroy
@Input()
items: OrderItemListItemDTO[];
@Input()
order: OrderDTO;
expanded: boolean[];
showTagsComponent: boolean[];
@@ -57,6 +54,8 @@ export class SharedGoodsInOutOrderEditComponent implements OnChanges, OnDestroy
vats$: Observable<VATDTO[]> = this.omsService.getVATs().pipe(shareReplay());
notificationChannelLoading$ = new BehaviorSubject<boolean>(false);
private _subscriptions = new Subscription();
displayDate = (option: UiSelectOptionComponent) => {
@@ -147,7 +146,7 @@ export class SharedGoodsInOutOrderEditComponent implements OnChanges, OnDestroy
supplier: fb.control({ value: item.supplier, disabled: true }),
ssc: fb.control(item.ssc, [Validators.required, validateSsc(statusCodes)]),
sscText: fb.control({ value: '', disabled: true }),
isPrebooked: fb.control({ value: item.isPrebooked ? 'Ja' : 'Nein', disabled: true }),
isPrebooked: fb.control(!!item.isPrebooked),
vat: fb.control(item.vatType),
specialComment: fb.control(item.specialComment),
});
@@ -182,6 +181,12 @@ export class SharedGoodsInOutOrderEditComponent implements OnChanges, OnDestroy
}
}
async patchNotifications() {
const control = this.control.getRawValue();
const orderId = control.orderId;
await this.omsService.updateNotifications(orderId, this.notificationsGroup.getRawValue()).toPromise();
}
changeEstimatedDeliveryDate(date: Date, item: OrderItemListItemDTO) {
if (!date) {
return;
@@ -202,6 +207,36 @@ export class SharedGoodsInOutOrderEditComponent implements OnChanges, OnDestroy
processingStatus ? this.navigation.emit({ options: { processingStatus } }) : this.navigation.emit({});
}
async generateNotification(notificationChannels: NotificationChannel[]) {
if (!notificationChannels || notificationChannels.length === 0) {
return;
}
this.notificationChannelLoading$.next(true);
try {
await this.patchNotifications();
await this.omsService
.generateNotifications({
orderId: this.items[0].orderId,
taskTypes:
notificationChannels.length === 2
? ['email', 'sms']
: notificationChannels[0] === 1
? ['email']
: notificationChannels[0] === 2
? ['sms']
: [],
})
.pipe(first())
.toPromise();
} catch (error) {
this._modal.open({ content: UiErrorModalComponent, data: error, title: 'Fehler beim erneut Benachrichtigen' });
throw error;
}
this.notificationChannelLoading$.next(false);
}
async submit() {
if (this.control.invalid || this.control.disabled) {
return;
@@ -215,7 +250,7 @@ export class SharedGoodsInOutOrderEditComponent implements OnChanges, OnDestroy
if (this.notificationsGroup.dirty) {
try {
await this.omsService.updateNotifications(orderId, this.notificationsGroup.getRawValue()).toPromise();
await this.patchNotifications();
} catch (error) {
this._modal.open({ content: UiErrorModalComponent, data: error, title: 'Fehler beim Aktualisieren der Benachrichtigung' });
throw error;
@@ -223,9 +258,10 @@ export class SharedGoodsInOutOrderEditComponent implements OnChanges, OnDestroy
}
let newProcessingStatus: number;
for (const itemCtrl of control.items) {
for (let itemCtrl of control.items) {
const orderItemId = itemCtrl.orderItemId;
const orderItemSubsetId = itemCtrl.orderItemSubsetId;
const formGroup = this.getFormGroupByOrderItemSubsetId(orderItemSubsetId);
try {
const currentItem = this.items?.find((i) => i.orderItemSubsetId === orderItemSubsetId);
@@ -234,6 +270,11 @@ export class SharedGoodsInOutOrderEditComponent implements OnChanges, OnDestroy
.changeStockStatusCode([{ id: orderItemSubsetId, ssc: itemCtrl.ssc, quantity: currentItem.quantity }])
.toPromise();
newProcessingStatus = response[0].item1.processingStatus;
itemCtrl = {
...itemCtrl,
estimatedShippingDate: response[0].item1.estimatedShippingDate,
isPrebooked: response[0].item1.isPrebooked,
};
}
} catch (error) {
this._modal.open({ content: UiErrorModalComponent, data: error, title: 'Fehler beim Aktualisieren der Meldenummer' });
@@ -241,46 +282,51 @@ export class SharedGoodsInOutOrderEditComponent implements OnChanges, OnDestroy
}
try {
await this.omsService
.patchOrderItem({
orderId,
orderItemId,
orderItem: {
product: { ean: itemCtrl.ean },
grossPrice: {
vat: { vatType: itemCtrl.vat },
value: { value: Number(String(itemCtrl.price).replace(',', '.')) },
if (this.isOrderItemDirty(formGroup)) {
await this.omsService
.patchOrderItem({
orderId,
orderItemId,
orderItem: {
product: { ean: itemCtrl.ean },
grossPrice: {
vat: { vatType: itemCtrl.vat },
value: { value: Number(String(itemCtrl.price).replace(',', '.')) },
},
},
},
})
.pipe(first())
.toPromise();
})
.pipe(first())
.toPromise();
}
} catch (error) {
this._modal.open({ content: UiErrorModalComponent, data: error, title: 'Fehler beim Aktualisieren des Bestellpostens' });
throw error;
}
try {
await this.omsService
.patchOrderItemSubset({
orderId,
orderItemId,
orderItemSubsetId,
orderItemSubset: {
compartmentCode:
itemCtrl.compartmentInfo && itemCtrl.compartmentCode
? itemCtrl.compartmentCode.replace('_' + itemCtrl.compartmentInfo, '')
: itemCtrl.compartmentCode,
compartmentInfo: itemCtrl.compartmentInfo || '',
estimatedShippingDate: itemCtrl.estimatedShippingDate || null,
compartmentStop: itemCtrl.pickUpDeadline || null,
specialComment: itemCtrl.specialComment || '',
ssc: itemCtrl.ssc,
sscText: itemCtrl.sscText !== '' ? itemCtrl.sscText.substring(3) : '',
},
})
.pipe(first())
.toPromise();
if (this.isOrderItemSubsetDirty(formGroup)) {
await this.omsService
.patchOrderItemSubset({
orderId,
orderItemId,
orderItemSubsetId,
orderItemSubset: {
compartmentCode:
itemCtrl.compartmentInfo && itemCtrl.compartmentCode
? itemCtrl.compartmentCode.replace('_' + itemCtrl.compartmentInfo, '')
: itemCtrl.compartmentCode,
compartmentInfo: itemCtrl.compartmentInfo || '',
estimatedShippingDate: itemCtrl.estimatedShippingDate || null,
compartmentStop: itemCtrl.pickUpDeadline || null,
specialComment: itemCtrl.specialComment || '',
ssc: itemCtrl.ssc,
sscText: itemCtrl.sscText !== '' ? itemCtrl.sscText.substring(3) : '',
isPrebooked: itemCtrl.isPrebooked,
},
})
.pipe(first())
.toPromise();
}
} catch (error) {
this._modal.open({ content: UiErrorModalComponent, data: error, title: 'Fehler beim Aktualisieren des Bestellpostens' });
throw error;
@@ -293,6 +339,26 @@ export class SharedGoodsInOutOrderEditComponent implements OnChanges, OnDestroy
}
}
getFormGroupByOrderItemSubsetId(orderItemSubsetId: number): FormGroup {
const arr = this.control.get('items') as FormArray;
return arr.controls.find((c) => (c as FormGroup).controls.orderItemSubsetId.value === orderItemSubsetId) as FormGroup;
}
isOrderItemDirty(group: FormGroup) {
return group.controls.ean.dirty || group.controls.vat.dirty || group.controls.price.dirty;
}
isOrderItemSubsetDirty(group: FormGroup) {
return (
group.controls.compartmentCode.dirty ||
group.controls.compartmentInfo.dirty ||
group.controls.estimatedShippingDate.dirty ||
group.controls.pickUpDeadline.dirty ||
group.controls.specialComment.dirty ||
group.controls.isPrebooked.dirty
);
}
// this.control.enable() would enable initially disabled fields too
enableControlFields() {
this.itemsControl.controls.forEach((ctrl) => {

View File

@@ -1,7 +1,7 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { NotificationChannelControlModule } from '@shared/notification-channel-control';
import { SharedNotificationChannelControlModule } from '@shared/notification-channel-control';
import { UiCommonModule } from '@ui/common';
import { UiDatepickerModule } from '@ui/datepicker';
import { UiDropdownModule } from '@ui/dropdown';
@@ -29,7 +29,7 @@ import { SharedGoodsInOutOrderEditComponent } from './goods-in-out-order-edit.co
UiDatepickerModule,
UiDropdownModule,
SharedGoodsInOutOrderDetailsModule,
NotificationChannelControlModule,
SharedNotificationChannelControlModule,
],
exports: [SharedGoodsInOutOrderEditComponent],
declarations: [SharedGoodsInOutOrderEditComponent],

View File

@@ -10,29 +10,34 @@
<ui-checkbox [value]="1" design="filled">E-Mail</ui-checkbox>
<ui-checkbox [value]="2" design="filled">SMS</ui-checkbox>
</ui-checkbox-group>
<div class="nc-generate">
<button [disabled]="channelActionLoading" type="button" (click)="channelActionEvent.emit(notificationChannels)">
{{ channelActionName }}
</button>
</div>
<div class="expand"></div>
<button *ngIf="displayToggle" type="button" class="more-toggle" (click)="toggle()" [class.open]="open$ | async">
<ui-icon icon="arrow_head" size="16px"></ui-icon>
</button>
</div>
<div class="nc-content" [class.open]="open$ | async">
<div class="nc-control-wrapper" *ngIf="displayEmail">
<div class="nc-control-wrapper" *ngIf="displayEmail && open$ | async">
<label for="email">E-Mail</label>
<div class="input-wrapper" [class.has-error]="emailControl.touched && emailControl?.errors">
<input type="email" name="email" id="email" [formControl]="emailControl" placeholder="E-Mail*" />
<ng-container *ngIf="emailControl.touched && emailControl?.errors; let errors">
<span class="error" *ngIf="errors.required">Das Fehld E-Mail ist ein Pflichtfeld</span>
<span class="error" *ngIf="errors.required">Das Feld E-Mail ist ein Pflichtfeld</span>
<span class="error" *ngIf="errors.pattern">Keine gültige E-Mail Adresse</span>
</ng-container>
</div>
</div>
<div class="nc-control-wrapper" *ngIf="displayMobile">
<div class="nc-control-wrapper" *ngIf="displayMobile && open$ | async">
<label for="mobile">SMS</label>
<div class="input-wrapper" [class.has-error]="mobileControl.touched && mobileControl?.errors">
<input type="tel" name="mobile" id="mobile" [formControl]="mobileControl" placeholder="SMS*" />
<ng-container *ngIf="mobileControl.touched && mobileControl?.errors; let errors">
<span class="error" *ngIf="errors.required">Das Fehld SMS ist ein Pflichtfeld</span>
<span class="error" *ngIf="errors.required">Das Feld SMS ist ein Pflichtfeld</span>
<span class="error" *ngIf="errors.pattern">Keine gültige Mobilnummer</span>
</ng-container>
</div>

View File

@@ -1,5 +1,5 @@
:host {
@apply block;
@apply block relative;
}
.nc-heading {
@@ -15,6 +15,7 @@
.more-toggle {
@apply bg-transparent outline-none border-none;
margin-top: 2px;
ui-icon {
@apply transition-all transform rotate-90;
@@ -65,6 +66,14 @@
}
}
.nc-generate {
@apply absolute right-16;
button {
@apply text-base font-bold text-brand outline-none border-none bg-transparent;
}
}
::ng-deep .customer shared-notification-channel-control {
.nc-control-wrapper {
.input-wrapper {
@@ -73,6 +82,12 @@
}
}
}
.nc-generate {
button:disabled {
@apply text-disabled-customer;
}
}
}
::ng-deep .branch shared-notification-channel-control {
@@ -87,4 +102,10 @@
}
}
}
.nc-generate {
button:disabled {
@apply text-disabled-branch;
}
}
}

View File

@@ -0,0 +1,23 @@
import { CommonModule } from '@angular/common';
import { FormBuilder } from '@angular/forms';
import { createComponentFactory, Spectator } from '@ngneat/spectator';
import { SharedNotificationChannelControlComponent } from '@shared/notification-channel-control';
import { UiIconModule } from '@ui/icon';
describe('SharedNotificationChannelControlComponent', () => {
let spectator: Spectator<SharedNotificationChannelControlComponent>;
const createComponent = createComponentFactory({
component: SharedNotificationChannelControlComponent,
imports: [CommonModule, UiIconModule],
providers: [FormBuilder],
});
beforeEach(() => {
spectator = createComponent();
});
it('should create', () => {
expect(spectator.component).toBeTruthy();
});
});

View File

@@ -1,11 +1,13 @@
import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { ControlContainer, FormGroup } from '@angular/forms';
import { DomainOmsService } from '@domain/oms';
import { ComponentStore } from '@ngrx/component-store';
import { NotificationChannel } from '@swagger/oms';
import { UiModalService } from '@ui/modal';
import { NEVER, Observable } from 'rxjs';
import { map, startWith, tap } from 'rxjs/operators';
import { map, shareReplay, startWith, tap } from 'rxjs/operators';
export interface NotificationChannelControlComponentState {
export interface SharedNotificationChannelControlComponentState {
open: boolean;
}
@@ -14,9 +16,19 @@ export interface NotificationChannelControlComponentState {
templateUrl: './notification-channel-control.component.html',
styleUrls: ['./notification-channel-control.component.scss'],
})
export class NotificationChannelControlComponent extends ComponentStore<NotificationChannelControlComponentState> implements OnInit {
export class SharedNotificationChannelControlComponent extends ComponentStore<SharedNotificationChannelControlComponentState>
implements OnInit {
notificationGroup: FormGroup;
@Input()
channelActionName?: string; // z.B. Erneut senden
@Input()
channelActionLoading?: boolean;
@Output()
channelActionEvent = new EventEmitter<NotificationChannel[]>();
get notificationChannelControl() {
return this.notificationGroup.get('selected');
}
@@ -45,7 +57,7 @@ export class NotificationChannelControlComponent extends ComponentStore<Notifica
return !!(this.mobileControl?.errors || this.emailControl?.errors);
}
readonly open$ = this.select((s) => s.open);
readonly open$ = this.select((s) => s.open).pipe(shareReplay());
readonly options: NotificationChannel[] = [1, 2];
@@ -64,7 +76,12 @@ export class NotificationChannelControlComponent extends ComponentStore<Notifica
notificationChannels$: Observable<NotificationChannel[]>;
constructor(private _notificationsGroup: ControlContainer, private _cdr: ChangeDetectorRef) {
constructor(
private _notificationsGroup: ControlContainer,
private _cdr: ChangeDetectorRef,
private _omsService: DomainOmsService,
private _modal: UiModalService
) {
super({
open: false,
});

View File

@@ -3,11 +3,11 @@ import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { UiCheckboxModule } from '@ui/checkbox';
import { UiIconModule } from '@ui/icon';
import { NotificationChannelControlComponent } from './notification-channel-control.component';
import { SharedNotificationChannelControlComponent } from './notification-channel-control.component';
@NgModule({
declarations: [NotificationChannelControlComponent],
declarations: [SharedNotificationChannelControlComponent],
imports: [CommonModule, UiCheckboxModule, FormsModule, ReactiveFormsModule, UiIconModule],
exports: [NotificationChannelControlComponent],
exports: [SharedNotificationChannelControlComponent],
})
export class NotificationChannelControlModule {}
export class SharedNotificationChannelControlModule {}

View File

@@ -4,6 +4,10 @@ export { InputType } from './models/input-type';
export { InputOptionsDTO } from './models/input-options-dto';
export { OptionDTO } from './models/option-dto';
export { ResponseArgs } from './models/response-args';
export { DialogOfString } from './models/dialog-of-string';
export { DialogSettings } from './models/dialog-settings';
export { DialogContentType } from './models/dialog-content-type';
export { KeyValueDTOOfStringAndString } from './models/key-value-dtoof-string-and-string';
export { IPublicUserInfo } from './models/ipublic-user-info';
export { ProblemDetails } from './models/problem-details';
export { ResponseArgsOfIEnumerableOfInputDTO } from './models/response-args-of-ienumerable-of-input-dto';
@@ -19,6 +23,7 @@ export { TenantDTO } from './models/tenant-dto';
export { ReadOnlyEntityDTOOfTenantDTOAndIReadOnlyTenant } from './models/read-only-entity-dtoof-tenant-dtoand-iread-only-tenant';
export { EntityDTO } from './models/entity-dto';
export { EntityStatus } from './models/entity-status';
export { TouchedBase } from './models/touched-base';
export { EntityDTOReferenceContainer } from './models/entity-dtoreference-container';
export { ExternalReferenceDTO } from './models/external-reference-dto';
export { ReadOnlyEntityDTOOfLabelDTOAndIReadOnlyLabel } from './models/read-only-entity-dtoof-label-dtoand-iread-only-label';
@@ -59,7 +64,6 @@ export { AttributeDTO } from './models/attribute-dto';
export { DataFormat } from './models/data-format';
export { EntityDTOOfAttributeDTOAndIAttribute } from './models/entity-dtoof-attribute-dtoand-iattribute';
export { ReadOnlyEntityDTOOfAttributeDTOAndIAttribute } from './models/read-only-entity-dtoof-attribute-dtoand-iattribute';
export { KeyValueDTOOfStringAndString } from './models/key-value-dtoof-string-and-string';
export { LinkedRecordDTO } from './models/linked-record-dto';
export { EntityDTOOfCustomerDTOAndICustomer } from './models/entity-dtoof-customer-dtoand-icustomer';
export { ReadOnlyEntityDTOOfCustomerDTOAndICustomer } from './models/read-only-entity-dtoof-customer-dtoand-icustomer';

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,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 DialogContentType = 0 | 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128;

View File

@@ -0,0 +1,16 @@
/* tslint:disable */
import { KeyValueDTOOfStringAndString } from './key-value-dtoof-string-and-string';
import { DialogContentType } from './dialog-content-type';
import { DialogSettings } from './dialog-settings';
export interface DialogOfString {
actions?: Array<KeyValueDTOOfStringAndString>;
actionsRequired?: number;
area?: string;
content?: string;
contentType: DialogContentType;
description?: string;
displayTimeout?: number;
settings: DialogSettings;
subtitle?: string;
title?: string;
}

View File

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

View File

@@ -1,6 +1,7 @@
/* tslint:disable */
import { TouchedBase } from './touched-base';
import { EntityStatus } from './entity-status';
export interface EntityDTO {
export interface EntityDTO extends TouchedBase{
changed?: string;
created?: string;
id?: number;

View File

@@ -1,6 +1,7 @@
/* tslint:disable */
import { TouchedBase } from './touched-base';
import { ExternalReferenceDTO } from './external-reference-dto';
export interface EntityDTOReferenceContainer {
export interface EntityDTOReferenceContainer extends TouchedBase{
displayLabel?: string;
enabled?: boolean;
externalReference?: ExternalReferenceDTO;

View File

@@ -1,6 +1,7 @@
/* tslint:disable */
import { TouchedBase } from './touched-base';
import { EntityStatus } from './entity-status';
export interface ExternalReferenceDTO {
export interface ExternalReferenceDTO extends TouchedBase{
externalChanged?: string;
externalCreated?: string;
externalNumber?: string;

View File

@@ -1,5 +1,6 @@
/* tslint:disable */
export interface GeoLocation {
import { TouchedBase } from './touched-base';
export interface GeoLocation extends TouchedBase{
altitude?: number;
latitude?: number;
longitude?: number;

View File

@@ -1,5 +1,6 @@
/* tslint:disable */
export interface OrganisationDTO {
import { TouchedBase } from './touched-base';
export interface OrganisationDTO extends TouchedBase{
costUnit?: string;
department?: string;
gln?: string;

View File

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

View File

@@ -0,0 +1,3 @@
/* tslint:disable */
export interface TouchedBase {
}

View File

@@ -83,7 +83,7 @@ class CustomerService extends __BaseService {
if (params.locale != null) __params = __params.set('locale', params.locale.toString());
let req = new HttpRequest<any>(
'GET',
this.rootUrl + `/customer/${encodeURIComponent(String(params.customerId))}/canextend`,
this.rootUrl + `/customer/${encodeURIComponent(params.customerId)}/canextend`,
__body,
{
headers: __headers,
@@ -197,7 +197,7 @@ class CustomerService extends __BaseService {
if (params.eagerLoading != null) __params = __params.set('eagerLoading', params.eagerLoading.toString());
let req = new HttpRequest<any>(
'GET',
this.rootUrl + `/customer/${encodeURIComponent(String(params.customerId))}`,
this.rootUrl + `/customer/${encodeURIComponent(params.customerId)}`,
__body,
{
headers: __headers,
@@ -242,7 +242,7 @@ class CustomerService extends __BaseService {
__body = params.customer;
let req = new HttpRequest<any>(
'PUT',
this.rootUrl + `/customer/${encodeURIComponent(String(params.customerId))}`,
this.rootUrl + `/customer/${encodeURIComponent(params.customerId)}`,
__body,
{
headers: __headers,
@@ -290,7 +290,7 @@ class CustomerService extends __BaseService {
if (params.eagerLoading != null) __params = __params.set('eagerLoading', params.eagerLoading.toString());
let req = new HttpRequest<any>(
'PATCH',
this.rootUrl + `/customer/${encodeURIComponent(String(params.customerId))}`,
this.rootUrl + `/customer/${encodeURIComponent(params.customerId)}`,
__body,
{
headers: __headers,
@@ -339,7 +339,7 @@ class CustomerService extends __BaseService {
if (params.deletionComment != null) __params = __params.set('deletionComment', params.deletionComment.toString());
let req = new HttpRequest<any>(
'DELETE',
this.rootUrl + `/customer/${encodeURIComponent(String(params.customerId))}`,
this.rootUrl + `/customer/${encodeURIComponent(params.customerId)}`,
__body,
{
headers: __headers,
@@ -422,7 +422,7 @@ class CustomerService extends __BaseService {
let req = new HttpRequest<any>(
'POST',
this.rootUrl + `/customer/${encodeURIComponent(String(params.customerId))}/shippingaddress`,
this.rootUrl + `/customer/${encodeURIComponent(params.customerId)}/shippingaddress`,
__body,
{
headers: __headers,
@@ -469,7 +469,7 @@ class CustomerService extends __BaseService {
if (params.skip != null) __params = __params.set('skip', params.skip.toString());
let req = new HttpRequest<any>(
'GET',
this.rootUrl + `/customer/${encodeURIComponent(String(params.customerId))}/shippingaddress`,
this.rootUrl + `/customer/${encodeURIComponent(params.customerId)}/shippingaddress`,
__body,
{
headers: __headers,
@@ -557,7 +557,7 @@ class CustomerService extends __BaseService {
if (params.eagerLoading != null) __params = __params.set('eagerLoading', params.eagerLoading.toString());
let req = new HttpRequest<any>(
'POST',
this.rootUrl + `/customer/${encodeURIComponent(String(params.customerId))}/payer`,
this.rootUrl + `/customer/${encodeURIComponent(params.customerId)}/payer`,
__body,
{
headers: __headers,
@@ -606,7 +606,7 @@ class CustomerService extends __BaseService {
if (params.deactivationComment != null) __params = __params.set('deactivationComment', params.deactivationComment.toString());
let req = new HttpRequest<any>(
'PATCH',
this.rootUrl + `/customer/${encodeURIComponent(String(params.customerId))}/deactivate`,
this.rootUrl + `/customer/${encodeURIComponent(params.customerId)}/deactivate`,
__body,
{
headers: __headers,
@@ -682,7 +682,7 @@ class CustomerService extends __BaseService {
let req = new HttpRequest<any>(
'GET',
this.rootUrl + `/customer/${encodeURIComponent(String(customerId))}/bonuscard`,
this.rootUrl + `/customer/${encodeURIComponent(customerId)}/bonuscard`,
__body,
{
headers: __headers,
@@ -854,7 +854,7 @@ class CustomerService extends __BaseService {
let req = new HttpRequest<any>(
'PUT',
this.rootUrl + `/customer/${encodeURIComponent(String(params.customerId))}/shippingaddress/${encodeURIComponent(String(params.shippingAddressId))}`,
this.rootUrl + `/customer/${encodeURIComponent(params.customerId)}/shippingaddress/${encodeURIComponent(params.shippingAddressId)}`,
__body,
{
headers: __headers,
@@ -892,16 +892,19 @@ class CustomerService extends __BaseService {
* - `shippingAddressId`: Lieferadresse PK
*
* - `customerId`: Kunde PK
*
* - `deletionComment`: Bemerkung zur Löschung
*/
CustomerDeleteShippingAddressResponse(params: CustomerService.CustomerDeleteShippingAddressParams): __Observable<__StrictHttpResponse<ResponseArgsOfShippingAddressDTO>> {
CustomerDeleteShippingAddressResponse(params: CustomerService.CustomerDeleteShippingAddressParams): __Observable<__StrictHttpResponse<ResponseArgsOfBoolean>> {
let __params = this.newParams();
let __headers = new HttpHeaders();
let __body: any = null;
if (params.deletionComment != null) __params = __params.set('deletionComment', params.deletionComment.toString());
let req = new HttpRequest<any>(
'DELETE',
this.rootUrl + `/customer/${encodeURIComponent(String(params.customerId))}/shippingaddress/${encodeURIComponent(String(params.shippingAddressId))}`,
this.rootUrl + `/customer/${encodeURIComponent(params.customerId)}/shippingaddress/${encodeURIComponent(params.shippingAddressId)}`,
__body,
{
headers: __headers,
@@ -912,7 +915,7 @@ class CustomerService extends __BaseService {
return this.http.request<any>(req).pipe(
__filter(_r => _r instanceof HttpResponse),
__map((_r) => {
return _r as __StrictHttpResponse<ResponseArgsOfShippingAddressDTO>;
return _r as __StrictHttpResponse<ResponseArgsOfBoolean>;
})
);
}
@@ -923,10 +926,12 @@ class CustomerService extends __BaseService {
* - `shippingAddressId`: Lieferadresse PK
*
* - `customerId`: Kunde PK
*
* - `deletionComment`: Bemerkung zur Löschung
*/
CustomerDeleteShippingAddress(params: CustomerService.CustomerDeleteShippingAddressParams): __Observable<ResponseArgsOfShippingAddressDTO> {
CustomerDeleteShippingAddress(params: CustomerService.CustomerDeleteShippingAddressParams): __Observable<ResponseArgsOfBoolean> {
return this.CustomerDeleteShippingAddressResponse(params).pipe(
__map(_r => _r.body as ResponseArgsOfShippingAddressDTO)
__map(_r => _r.body as ResponseArgsOfBoolean)
);
}
@@ -982,7 +987,7 @@ class CustomerService extends __BaseService {
if (params.skip != null) __params = __params.set('skip', params.skip.toString());
let req = new HttpRequest<any>(
'GET',
this.rootUrl + `/customer/${encodeURIComponent(String(params.customerId))}/assignedpayers`,
this.rootUrl + `/customer/${encodeURIComponent(params.customerId)}/assignedpayers`,
__body,
{
headers: __headers,
@@ -1033,7 +1038,7 @@ class CustomerService extends __BaseService {
if (params.eagerLoading != null) __params = __params.set('eagerLoading', params.eagerLoading.toString());
let req = new HttpRequest<any>(
'PATCH',
this.rootUrl + `/customer/${encodeURIComponent(String(params.customerId))}/payer/${encodeURIComponent(String(params.payerId))}/modifydefaultflag`,
this.rootUrl + `/customer/${encodeURIComponent(params.customerId)}/payer/${encodeURIComponent(params.payerId)}/modifydefaultflag`,
__body,
{
headers: __headers,
@@ -1080,7 +1085,7 @@ class CustomerService extends __BaseService {
if (params.locale != null) __params = __params.set('locale', params.locale.toString());
let req = new HttpRequest<any>(
'GET',
this.rootUrl + `/customer/${encodeURIComponent(String(params.customerId))}/history`,
this.rootUrl + `/customer/${encodeURIComponent(params.customerId)}/history`,
__body,
{
headers: __headers,
@@ -1118,7 +1123,7 @@ class CustomerService extends __BaseService {
let req = new HttpRequest<any>(
'GET',
this.rootUrl + `/customer/shippingaddress/${encodeURIComponent(String(shippingaddressId))}`,
this.rootUrl + `/customer/shippingaddress/${encodeURIComponent(shippingaddressId)}`,
__body,
{
headers: __headers,
@@ -1160,7 +1165,7 @@ class CustomerService extends __BaseService {
if (params.isDefault != null) __params = __params.set('isDefault', params.isDefault.toString());
let req = new HttpRequest<any>(
'PATCH',
this.rootUrl + `/customer/${encodeURIComponent(String(params.customerId))}/shippingaddress/${encodeURIComponent(String(params.shippingAddressId))}/modifydefaultflag`,
this.rootUrl + `/customer/${encodeURIComponent(params.customerId)}/shippingaddress/${encodeURIComponent(params.shippingAddressId)}/modifydefaultflag`,
__body,
{
headers: __headers,
@@ -1208,7 +1213,7 @@ class CustomerService extends __BaseService {
if (params.locale != null) __params = __params.set('locale', params.locale.toString());
let req = new HttpRequest<any>(
'GET',
this.rootUrl + `/customer/${encodeURIComponent(String(params.customerId))}/shippingaddress/${encodeURIComponent(String(params.shippingAddressId))}/history`,
this.rootUrl + `/customer/${encodeURIComponent(params.customerId)}/shippingaddress/${encodeURIComponent(params.shippingAddressId)}/history`,
__body,
{
headers: __headers,
@@ -1437,6 +1442,11 @@ module CustomerService {
* Kunde PK
*/
customerId: number;
/**
* Bemerkung zur Löschung
*/
deletionComment?: null | string;
}
/**

View File

@@ -35,7 +35,7 @@ class OptInService extends __BaseService {
let req = new HttpRequest<any>(
'GET',
this.rootUrl + `/optin/${encodeURIComponent(String(optInId))}`,
this.rootUrl + `/optin/${encodeURIComponent(optInId)}`,
__body,
{
headers: __headers,
@@ -74,7 +74,7 @@ class OptInService extends __BaseService {
__body = params.optIn;
let req = new HttpRequest<any>(
'PUT',
this.rootUrl + `/optin/${encodeURIComponent(String(params.optInId))}`,
this.rootUrl + `/optin/${encodeURIComponent(params.optInId)}`,
__body,
{
headers: __headers,
@@ -112,7 +112,7 @@ class OptInService extends __BaseService {
let req = new HttpRequest<any>(
'DELETE',
this.rootUrl + `/optin/${encodeURIComponent(String(optInId))}`,
this.rootUrl + `/optin/${encodeURIComponent(optInId)}`,
__body,
{
headers: __headers,

View File

@@ -81,7 +81,7 @@ class PayerService extends __BaseService {
__body = params.payer;
let req = new HttpRequest<any>(
'PUT',
this.rootUrl + `/payer/${encodeURIComponent(String(params.payerId))}`,
this.rootUrl + `/payer/${encodeURIComponent(params.payerId)}`,
__body,
{
headers: __headers,
@@ -120,7 +120,7 @@ class PayerService extends __BaseService {
let req = new HttpRequest<any>(
'GET',
this.rootUrl + `/payer/${encodeURIComponent(String(payerId))}`,
this.rootUrl + `/payer/${encodeURIComponent(payerId)}`,
__body,
{
headers: __headers,
@@ -160,7 +160,7 @@ class PayerService extends __BaseService {
if (params.deactivationComment != null) __params = __params.set('deactivationComment', params.deactivationComment.toString());
let req = new HttpRequest<any>(
'PATCH',
this.rootUrl + `/payer/${encodeURIComponent(String(params.payerId))}/deactivate`,
this.rootUrl + `/payer/${encodeURIComponent(params.payerId)}/deactivate`,
__body,
{
headers: __headers,
@@ -207,7 +207,7 @@ class PayerService extends __BaseService {
if (params.deletionComment != null) __params = __params.set('deletionComment', params.deletionComment.toString());
let req = new HttpRequest<any>(
'DELETE',
this.rootUrl + `/payer/${encodeURIComponent(String(params.payerId))}/delete`,
this.rootUrl + `/payer/${encodeURIComponent(params.payerId)}/delete`,
__body,
{
headers: __headers,
@@ -253,7 +253,7 @@ class PayerService extends __BaseService {
if (params.locale != null) __params = __params.set('locale', params.locale.toString());
let req = new HttpRequest<any>(
'GET',
this.rootUrl + `/payer/${encodeURIComponent(String(params.payerId))}/history`,
this.rootUrl + `/payer/${encodeURIComponent(params.payerId)}/history`,
__body,
{
headers: __headers,

View File

@@ -199,6 +199,7 @@ export { ResponseArgsOfOrderDTO } from './models/response-args-of-order-dto';
export { ListResponseArgsOfOrderListItemDTO } from './models/list-response-args-of-order-list-item-dto';
export { ResponseArgsOfIEnumerableOfOrderListItemDTO } from './models/response-args-of-ienumerable-of-order-list-item-dto';
export { OrderListItemDTO } from './models/order-list-item-dto';
export { ResponseArgsOfInteger } from './models/response-args-of-integer';
export { ResponseArgsOfBoolean } from './models/response-args-of-boolean';
export { ResponseArgsOfOrderItemDTO } from './models/response-args-of-order-item-dto';
export { ResponseArgsOfIEnumerableOfOrderItemDTO } from './models/response-args-of-ienumerable-of-order-item-dto';

View File

@@ -0,0 +1,5 @@
/* tslint:disable */
import { ResponseArgs } from './response-args';
export interface ResponseArgsOfInteger extends ResponseArgs{
result: number;
}

View File

@@ -45,7 +45,7 @@ class OrderCheckoutService extends __BaseService {
if (params.locale != null) __params = __params.set('locale', params.locale.toString());
let req = new HttpRequest<any>(
'POST',
this.rootUrl + `/order/checkout/${encodeURIComponent(params.checkoutId)}`,
this.rootUrl + `/order/checkout/${encodeURIComponent(String(params.checkoutId))}`,
__body,
{
headers: __headers,
@@ -92,7 +92,7 @@ class OrderCheckoutService extends __BaseService {
if (params.locale != null) __params = __params.set('locale', params.locale.toString());
let req = new HttpRequest<any>(
'PUT',
this.rootUrl + `/order/checkout/${encodeURIComponent(params.checkoutId)}`,
this.rootUrl + `/order/checkout/${encodeURIComponent(String(params.checkoutId))}`,
__body,
{
headers: __headers,
@@ -145,7 +145,7 @@ class OrderCheckoutService extends __BaseService {
__body = params.data;
let req = new HttpRequest<any>(
'POST',
this.rootUrl + `/order/${encodeURIComponent(params.orderId)}/orderitem/${encodeURIComponent(params.orderItemId)}/orderitemsubset/${encodeURIComponent(params.orderItemSubsetId)}/reorder`,
this.rootUrl + `/order/${encodeURIComponent(String(params.orderId))}/orderitem/${encodeURIComponent(String(params.orderItemId))}/orderitemsubset/${encodeURIComponent(String(params.orderItemSubsetId))}/reorder`,
__body,
{
headers: __headers,
@@ -191,7 +191,7 @@ class OrderCheckoutService extends __BaseService {
let req = new HttpRequest<any>(
'POST',
this.rootUrl + `/order/${encodeURIComponent(orderId)}`,
this.rootUrl + `/order/${encodeURIComponent(String(orderId))}`,
__body,
{
headers: __headers,
@@ -238,7 +238,7 @@ class OrderCheckoutService extends __BaseService {
let req = new HttpRequest<any>(
'POST',
this.rootUrl + `/order/${encodeURIComponent(params.orderId)}/orderitem/${encodeURIComponent(params.orderItemId)}/orderitemsubset/${encodeURIComponent(params.orderItemSubsetId)}`,
this.rootUrl + `/order/${encodeURIComponent(String(params.orderId))}/orderitem/${encodeURIComponent(String(params.orderItemId))}/orderitemsubset/${encodeURIComponent(String(params.orderItemSubsetId))}`,
__body,
{
headers: __headers,

View File

@@ -16,6 +16,7 @@ import { ResponseArgsOfOrderItemSubsetDTO } from '../models/response-args-of-ord
import { ResponseArgsOfIEnumerableOfOrderDTO } from '../models/response-args-of-ienumerable-of-order-dto';
import { ListResponseArgsOfOrderListItemDTO } from '../models/list-response-args-of-order-list-item-dto';
import { QueryTokenDTO } from '../models/query-token-dto';
import { ResponseArgsOfInteger } from '../models/response-args-of-integer';
import { ListResponseArgsOfOrderItemListItemDTO } from '../models/list-response-args-of-order-item-list-item-dto';
import { ResponseArgsOfIEnumerableOfOrderItemDTO } from '../models/response-args-of-ienumerable-of-order-item-dto';
import { OrderItemDTO } from '../models/order-item-dto';
@@ -51,6 +52,7 @@ class OrderService extends __BaseService {
static readonly OrderGetOrdersByCompartmentPath = '/order/compartment';
static readonly OrderGetOrdersByBuyerNumberPath = '/buyer/order';
static readonly OrderQueryOrdersPath = '/order/s';
static readonly OrderRegenerateOrderItemStatusTasksPath = '/order/{orderId}/orderItem/orderItemSubset/task/regenerate';
static readonly OrderQueryOrderItemPath = '/order/item/s';
static readonly OrderGetOrderItemPath = '/order/orderitem/{orderItemId}';
static readonly OrderGetOrderItemsPath = '/order/orderitem';
@@ -94,7 +96,7 @@ class OrderService extends __BaseService {
let req = new HttpRequest<any>(
'GET',
this.rootUrl + `/order/${encodeURIComponent(orderId)}`,
this.rootUrl + `/order/${encodeURIComponent(String(orderId))}`,
__body,
{
headers: __headers,
@@ -133,7 +135,7 @@ class OrderService extends __BaseService {
__body = params.order;
let req = new HttpRequest<any>(
'PUT',
this.rootUrl + `/order/${encodeURIComponent(params.orderId)}`,
this.rootUrl + `/order/${encodeURIComponent(String(params.orderId))}`,
__body,
{
headers: __headers,
@@ -179,7 +181,7 @@ class OrderService extends __BaseService {
if (params.eagerLoading != null) __params = __params.set('eagerLoading', params.eagerLoading.toString());
let req = new HttpRequest<any>(
'PATCH',
this.rootUrl + `/order/${encodeURIComponent(params.orderId)}`,
this.rootUrl + `/order/${encodeURIComponent(String(params.orderId))}`,
__body,
{
headers: __headers,
@@ -224,7 +226,7 @@ class OrderService extends __BaseService {
if (params.deletionComment != null) __params = __params.set('deletionComment', params.deletionComment.toString());
let req = new HttpRequest<any>(
'DELETE',
this.rootUrl + `/order/${encodeURIComponent(params.orderId)}`,
this.rootUrl + `/order/${encodeURIComponent(String(params.orderId))}`,
__body,
{
headers: __headers,
@@ -273,7 +275,7 @@ class OrderService extends __BaseService {
let req = new HttpRequest<any>(
'PUT',
this.rootUrl + `/order/${encodeURIComponent(params.orderId)}/orderitem/${encodeURIComponent(params.orderItemId)}/orderitemsubset/${encodeURIComponent(params.orderItemSubsetId)}`,
this.rootUrl + `/order/${encodeURIComponent(String(params.orderId))}/orderitem/${encodeURIComponent(String(params.orderItemId))}/orderitemsubset/${encodeURIComponent(String(params.orderItemSubsetId))}`,
__body,
{
headers: __headers,
@@ -326,7 +328,7 @@ class OrderService extends __BaseService {
let req = new HttpRequest<any>(
'PATCH',
this.rootUrl + `/order/${encodeURIComponent(params.orderId)}/orderitem/${encodeURIComponent(params.orderItemId)}/orderitemsubset/${encodeURIComponent(params.orderItemSubsetId)}`,
this.rootUrl + `/order/${encodeURIComponent(String(params.orderId))}/orderitem/${encodeURIComponent(String(params.orderItemId))}/orderitemsubset/${encodeURIComponent(String(params.orderItemSubsetId))}`,
__body,
{
headers: __headers,
@@ -474,6 +476,51 @@ class OrderService extends __BaseService {
);
}
/**
* Letzte Aufgaben erneut erzeugen
* @param params The `OrderService.OrderRegenerateOrderItemStatusTasksParams` containing the following parameters:
*
* - `orderId`: Bestellung PK
*
* - `taskTypes`: Aufgaben-Arten
*/
OrderRegenerateOrderItemStatusTasksResponse(params: OrderService.OrderRegenerateOrderItemStatusTasksParams): __Observable<__StrictHttpResponse<ResponseArgsOfInteger>> {
let __params = this.newParams();
let __headers = new HttpHeaders();
let __body: any = null;
__body = params.taskTypes;
let req = new HttpRequest<any>(
'POST',
this.rootUrl + `/order/${encodeURIComponent(String(params.orderId))}/orderItem/orderItemSubset/task/regenerate`,
__body,
{
headers: __headers,
params: __params,
responseType: 'json'
});
return this.http.request<any>(req).pipe(
__filter(_r => _r instanceof HttpResponse),
__map((_r) => {
return _r as __StrictHttpResponse<ResponseArgsOfInteger>;
})
);
}
/**
* Letzte Aufgaben erneut erzeugen
* @param params The `OrderService.OrderRegenerateOrderItemStatusTasksParams` containing the following parameters:
*
* - `orderId`: Bestellung PK
*
* - `taskTypes`: Aufgaben-Arten
*/
OrderRegenerateOrderItemStatusTasks(params: OrderService.OrderRegenerateOrderItemStatusTasksParams): __Observable<ResponseArgsOfInteger> {
return this.OrderRegenerateOrderItemStatusTasksResponse(params).pipe(
__map(_r => _r.body as ResponseArgsOfInteger)
);
}
/**
* @param queryToken undefined
*/
@@ -518,7 +565,7 @@ class OrderService extends __BaseService {
let req = new HttpRequest<any>(
'GET',
this.rootUrl + `/order/orderitem/${encodeURIComponent(orderItemId)}`,
this.rootUrl + `/order/orderitem/${encodeURIComponent(String(orderItemId))}`,
__body,
{
headers: __headers,
@@ -594,7 +641,7 @@ class OrderService extends __BaseService {
let req = new HttpRequest<any>(
'PUT',
this.rootUrl + `/order/${encodeURIComponent(params.orderId)}/orderitem/${encodeURIComponent(params.orderItemId)}`,
this.rootUrl + `/order/${encodeURIComponent(String(params.orderId))}/orderitem/${encodeURIComponent(String(params.orderItemId))}`,
__body,
{
headers: __headers,
@@ -642,7 +689,7 @@ class OrderService extends __BaseService {
let req = new HttpRequest<any>(
'PATCH',
this.rootUrl + `/order/${encodeURIComponent(params.orderId)}/orderitem/${encodeURIComponent(params.orderItemId)}`,
this.rootUrl + `/order/${encodeURIComponent(String(params.orderId))}/orderitem/${encodeURIComponent(String(params.orderItemId))}`,
__body,
{
headers: __headers,
@@ -687,7 +734,7 @@ class OrderService extends __BaseService {
if (params.locale != null) __params = __params.set('locale', params.locale.toString());
let req = new HttpRequest<any>(
'GET',
this.rootUrl + `/order/orderitem/${encodeURIComponent(params.orderItemId)}/history`,
this.rootUrl + `/order/orderitem/${encodeURIComponent(String(params.orderItemId))}/history`,
__body,
{
headers: __headers,
@@ -725,7 +772,7 @@ class OrderService extends __BaseService {
let req = new HttpRequest<any>(
'GET',
this.rootUrl + `/order/orderitem/orderitemsubset/${encodeURIComponent(orderItemSubsetId)}`,
this.rootUrl + `/order/orderitem/orderitemsubset/${encodeURIComponent(String(orderItemSubsetId))}`,
__body,
{
headers: __headers,
@@ -764,7 +811,7 @@ class OrderService extends __BaseService {
if (params.locale != null) __params = __params.set('locale', params.locale.toString());
let req = new HttpRequest<any>(
'GET',
this.rootUrl + `/order/orderitem/orderitemsubset/${encodeURIComponent(params.orderItemSubsetId)}/history`,
this.rootUrl + `/order/orderitem/orderitemsubset/${encodeURIComponent(String(params.orderItemSubsetId))}/history`,
__body,
{
headers: __headers,
@@ -813,7 +860,7 @@ class OrderService extends __BaseService {
__body = params.data;
let req = new HttpRequest<any>(
'PATCH',
this.rootUrl + `/order/${encodeURIComponent(params.orderId)}/orderitem/${encodeURIComponent(params.orderItemId)}/orderitemsubset/${encodeURIComponent(params.orderItemSubsetId)}/changestatus`,
this.rootUrl + `/order/${encodeURIComponent(String(params.orderId))}/orderitem/${encodeURIComponent(String(params.orderItemId))}/orderitemsubset/${encodeURIComponent(String(params.orderItemSubsetId))}/changestatus`,
__body,
{
headers: __headers,
@@ -983,7 +1030,7 @@ class OrderService extends __BaseService {
if (params.completed != null) __params = __params.set('completed', params.completed.toString());
let req = new HttpRequest<any>(
'GET',
this.rootUrl + `/order/${encodeURIComponent(params.orderId)}/item/${encodeURIComponent(params.orderItemId)}/subset/${encodeURIComponent(params.orderItemSubsetId)}/task`,
this.rootUrl + `/order/${encodeURIComponent(String(params.orderId))}/item/${encodeURIComponent(String(params.orderItemId))}/subset/${encodeURIComponent(String(params.orderItemSubsetId))}/task`,
__body,
{
headers: __headers,
@@ -1029,7 +1076,7 @@ class OrderService extends __BaseService {
let req = new HttpRequest<any>(
'GET',
this.rootUrl + `/order/payer/${encodeURIComponent(payerId)}`,
this.rootUrl + `/order/payer/${encodeURIComponent(String(payerId))}`,
__body,
{
headers: __headers,
@@ -1071,7 +1118,7 @@ class OrderService extends __BaseService {
let req = new HttpRequest<any>(
'PUT',
this.rootUrl + `/order/${encodeURIComponent(params.orderId)}/payer/${encodeURIComponent(params.payerId)}`,
this.rootUrl + `/order/${encodeURIComponent(String(params.orderId))}/payer/${encodeURIComponent(String(params.payerId))}`,
__body,
{
headers: __headers,
@@ -1111,7 +1158,7 @@ class OrderService extends __BaseService {
let req = new HttpRequest<any>(
'GET',
this.rootUrl + `/order/shippingaddress/${encodeURIComponent(shippingAddressId)}`,
this.rootUrl + `/order/shippingaddress/${encodeURIComponent(String(shippingAddressId))}`,
__body,
{
headers: __headers,
@@ -1153,7 +1200,7 @@ class OrderService extends __BaseService {
let req = new HttpRequest<any>(
'PUT',
this.rootUrl + `/order/${encodeURIComponent(params.orderId)}/shippingaddress/${encodeURIComponent(params.shippingAddressId)}`,
this.rootUrl + `/order/${encodeURIComponent(String(params.orderId))}/shippingaddress/${encodeURIComponent(String(params.shippingAddressId))}`,
__body,
{
headers: __headers,
@@ -1254,7 +1301,7 @@ class OrderService extends __BaseService {
if (params.code != null) __params = __params.set('code', params.code.toString());
let req = new HttpRequest<any>(
'GET',
this.rootUrl + `/order/ssc/${encodeURIComponent(params.supplierId)}`,
this.rootUrl + `/order/ssc/${encodeURIComponent(String(params.supplierId))}`,
__body,
{
headers: __headers,
@@ -1337,7 +1384,7 @@ class OrderService extends __BaseService {
let req = new HttpRequest<any>(
'GET',
this.rootUrl + `/order/supplier/${encodeURIComponent(supplierId)}`,
this.rootUrl + `/order/supplier/${encodeURIComponent(String(supplierId))}`,
__body,
{
headers: __headers,
@@ -1414,7 +1461,7 @@ class OrderService extends __BaseService {
let req = new HttpRequest<any>(
'GET',
this.rootUrl + `/order/vat/${encodeURIComponent(vatId)}`,
this.rootUrl + `/order/vat/${encodeURIComponent(String(vatId))}`,
__body,
{
headers: __headers,
@@ -1491,7 +1538,7 @@ class OrderService extends __BaseService {
let req = new HttpRequest<any>(
'GET',
this.rootUrl + `/order/logistician/${encodeURIComponent(logisticianId)}`,
this.rootUrl + `/order/logistician/${encodeURIComponent(String(logisticianId))}`,
__body,
{
headers: __headers,
@@ -1572,6 +1619,22 @@ module OrderService {
buyerNumber?: null | string;
}
/**
* Parameters for OrderRegenerateOrderItemStatusTasks
*/
export interface OrderRegenerateOrderItemStatusTasksParams {
/**
* Bestellung PK
*/
orderId: number;
/**
* Aufgaben-Arten
*/
taskTypes?: Array<string>;
}
/**
* Parameters for OrderUpdateOrderItem
*/

View File

@@ -46,7 +46,7 @@ class ReceiptService extends __BaseService {
if (params.receiptType != null) __params = __params.set('receiptType', params.receiptType.toString());
let req = new HttpRequest<any>(
'GET',
this.rootUrl + `/receipt/order/${encodeURIComponent(params.orderId)}`,
this.rootUrl + `/receipt/order/${encodeURIComponent(String(params.orderId))}`,
__body,
{
headers: __headers,

View File

@@ -2,6 +2,7 @@ import { NgModule } from '@angular/core';
import { UiAutofocusDirective } from './autofocus.directive';
import { BlobImageDirective } from './blob-image.directive';
import { UiClickOutsideDirective } from './click-outside.directive';
import { UiElementDistanceDirective } from './element-distance';
import { UiFocusDirective } from './focus';
import { IsInViewportDirective } from './is-in-viewport.directive';
import { UiOverlayTriggerDirective } from './overlay-trigger';
@@ -19,6 +20,7 @@ const directives = [
UiAutofocusDirective,
UiFocusDirective,
UiOverlayTriggerDirective,
UiElementDistanceDirective,
];
const pipes = [StripHtmlTagsPipe, SubstrPipe, GroupByPipe, ReplacePipe];
@NgModule({

View File

@@ -0,0 +1,70 @@
import { AfterContentInit, AfterViewInit, Directive, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
import { interval, Subscription } from 'rxjs';
@Directive({ selector: '[uiElementDistance]', exportAs: 'uiElementDistance' })
export class UiElementDistanceDirective implements OnInit, OnDestroy, AfterViewInit {
private _subscriptions = new Subscription();
private _distance: number;
get distance() {
return this._distance;
}
get nativeElement() {
return this._elementRef.nativeElement;
}
@Input('uiElementDistance') targetElement: HTMLElement | ElementRef;
@Output() distanceChange = new EventEmitter<number>();
constructor(private _elementRef: ElementRef) {}
ngOnInit() {
this._subscriptions.add(
interval(500).subscribe(() => {
this.calculateDistance();
})
);
}
ngOnDestroy() {
this._subscriptions.unsubscribe();
}
ngAfterViewInit() {
this.calculateDistance();
}
getHtmlElement(element: HTMLElement | ElementRef): HTMLElement {
return element instanceof HTMLElement ? element : element.nativeElement;
}
getElementDistance(): number {
const startElement = this.getHtmlElement(this.nativeElement);
const endElement = this.getHtmlElement(this.targetElement);
const startRect = startElement.getBoundingClientRect();
const endRect = endElement.getBoundingClientRect();
const startTop = startRect.top;
const startLeft = startRect.left;
const endTop = endRect.top;
const endLeft = endRect.left;
const distance = Math.sqrt(Math.pow(startTop - endTop, 2) + Math.pow(startLeft - endLeft, 2));
return Math.floor(distance);
}
calculateDistance() {
const distance = this.getElementDistance();
if (this._distance !== distance) {
console.log(distance);
this._distance = distance;
this.distanceChange.emit(this._distance);
}
}
}

View File

@@ -0,0 +1,3 @@
// start:ng42.barrel
export * from './element-distance.directive';
// end:ng42.barrel

View File

@@ -1,10 +1,15 @@
// start:ng42.barrel
export * from './autofocus.directive';
export * from './blob-image.directive';
export * from './click-outside.directive';
export * from './common.module';
export * from './is-in-viewport.directive';
export * from './date';
export * from './skeleton-loader';
export * from './defs';
export * from './element-distance';
export * from './focus';
export * from './overlay-trigger';
export * from './pipes';
export * from './scroll-position';
export * from './skeleton-loader';
// end:ng42.barrel

View File

@@ -0,0 +1,6 @@
// start:ng42.barrel
export * from './group-by.pipe';
export * from './replace.pipe';
export * from './strip-html-tags.pipe';
export * from './substr.pipe';
// end:ng42.barrel

View File

@@ -0,0 +1,3 @@
// start:ng42.barrel
export * from './scroll-position.service';
// end:ng42.barrel

View File

@@ -4,6 +4,7 @@ export * from './ui-filter.module';
export * from './filter-group/filter-filter-group-filter';
export * from './filter-group/filter-filter-group-main';
export * from './filter-group/filter-input-group-main';
export * from './order-by-filter';
export * from './pipe';
export * from './providers';
export * from './shared/filter-input-chip';

View File

@@ -0,0 +1,4 @@
// start:ng42.barrel
export * from './order-by-filter.component';
export * from './order-by-filter.module';
// end:ng42.barrel

View File

@@ -0,0 +1,13 @@
<div class="order-by-filter-button-wrapper">
<button class="order-by-filter-button" type="button" *ngFor="let label of orderByKeys" (click)="setActive(label)">
<span>
{{ label }}
</span>
<ui-icon
[class.asc]="label === activeOrderBy?.label && !activeOrderBy.desc"
[class.desc]="label === activeOrderBy?.label && activeOrderBy.desc"
icon="arrow"
size="14px"
></ui-icon>
</button>
</div>

View File

@@ -0,0 +1,54 @@
:host {
@apply box-border flex justify-center items-center;
min-height: 30px;
}
.order-by-filter-button-wrapper {
@apply flex flex-row items-center justify-center;
}
.order-by-filter-button {
@apply bg-transparent outline-none border-none text-regular font-bold flex flex-row justify-center items-center m-0 py-2 px-2;
}
::ng-deep .tablet ui-order-by-filter .order-by-filter-button {
@apply mx-0;
}
ui-icon {
@apply hidden transform ml-2 rounded-full p-1;
transition: 250ms all ease-in-out;
}
ui-icon.asc,
ui-icon.desc {
@apply flex rounded-full visible text-white;
}
ui-icon.asc {
@apply -rotate-90;
}
ui-icon.desc {
@apply rotate-90;
}
::ng-deep .customer ui-order-by-filter {
ui-icon {
@apply bg-active-customer;
}
.order-by-filter-button {
@apply text-active-customer;
}
}
::ng-deep .branch ui-order-by-filter {
ui-icon {
@apply bg-active-branch;
}
.order-by-filter-button {
@apply text-active-branch;
}
}

View File

@@ -1,24 +1,21 @@
import { Component, ChangeDetectionStrategy, Input, ChangeDetectorRef, Output, EventEmitter } from '@angular/core';
import { Component, ChangeDetectionStrategy, Input, ChangeDetectorRef, Output, EventEmitter, OnInit } from '@angular/core';
import { UiOrderBy } from '@ui/filter';
@Component({
selector: 'page-order-by-filter',
selector: 'ui-order-by-filter',
templateUrl: 'order-by-filter.component.html',
styleUrls: ['order-by-filter.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class OrderByFilterComponent {
export class UiOrderByFilterComponent implements OnInit {
@Input()
orderBy: UiOrderBy[];
@Input()
hits: number;
@Output()
selectedOrderByChange = new EventEmitter<UiOrderBy>();
get orderByKeys() {
return this.orderBy?.map((ob) => ob.by).filter((key, idx, self) => self.indexOf(key) === idx);
return this.orderBy?.map((ob) => ob.label).filter((key, idx, self) => self.indexOf(key) === idx);
}
get activeOrderBy() {
@@ -27,13 +24,17 @@ export class OrderByFilterComponent {
constructor(private cdr: ChangeDetectorRef) {}
ngOnInit() {
setTimeout(() => this.cdr.markForCheck(), 0);
}
setActive(orderBy: string) {
const active = this.activeOrderBy;
const orderBys = this.orderBy?.filter((f) => f.by === orderBy);
const orderBys = this.orderBy?.filter((f) => f.label === orderBy);
let next: UiOrderBy;
if (orderBys?.length) {
if (active?.by !== orderBy) {
if (active?.label !== orderBy) {
next = orderBys?.find((f) => !f.desc);
} else if (!active.desc) {
next = orderBys?.find((f) => f.desc);

View File

@@ -0,0 +1,13 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { UiIconModule } from '@ui/icon';
import { UiOrderByFilterComponent } from './order-by-filter.component';
@NgModule({
imports: [CommonModule, UiIconModule],
exports: [UiOrderByFilterComponent],
declarations: [UiOrderByFilterComponent],
providers: [],
})
export class UiOrderByFilterModule {}

View File

@@ -15,6 +15,7 @@
@apply text-brand text-base font-bold;
}
::ng-deep ui-input-option-number-range ui-form-control input {
width: 200px;
ui-form-control input {
max-width: 200px;
@apply px-0 rounded-none;
}

View File

@@ -1,6 +1,7 @@
import { OverlayConfig } from '@angular/cdk/overlay';
export class UiModalConfig extends OverlayConfig {
canClose?: boolean;
backdropClose?: boolean;
showScrollbarX?: boolean;
showScrollbarY?: boolean;

View File

@@ -0,0 +1,10 @@
<h2 class="subtitle" *ngIf="modalRef.data.subtitle; let subtitle">{{ subtitle }}</h2>
<p class="content" *ngIf="modalRef.data.content; let content">
{{ content }}
</p>
<div class="actions" *ngIf="modalRef.data.actions; let actions">
<button *ngFor="let action of actions" [class.selected]="action.selected" (click)="handleCommand(action.command)">
{{ action.label }}
</button>
</div>

View File

@@ -0,0 +1,27 @@
:host {
@apply flex flex-col;
}
.title {
@apply text-xl text-center;
}
.subtitle {
@apply text-lg text-center;
}
.content {
@apply text-base text-center whitespace-pre;
}
.actions {
@apply text-center;
button {
@apply border-2 border-solid border-brand bg-white text-brand rounded-full py-3 px-6 font-bold text-lg outline-none self-end whitespace-nowrap;
&.selected {
@apply bg-brand text-white;
}
}
}

View File

@@ -0,0 +1,21 @@
import { Component, OnInit } from '@angular/core';
import { UiModalRef } from '@ui/modal';
import { DialogModel } from './dialog.model';
@Component({
selector: 'ui-dialog-modal',
templateUrl: './dialog-modal.component.html',
styleUrls: ['./dialog-modal.component.scss'],
})
export class UiDialogModalComponent implements OnInit {
constructor(public modalRef: UiModalRef<any, DialogModel>) {}
ngOnInit() {}
handleCommand(command: string) {
if (command === 'CLOSE') {
this.modalRef.close();
return;
}
}
}

View File

@@ -0,0 +1,12 @@
import { DialogSettings, KeyValueDTOOfStringAndString } from '@swagger/crm';
export interface DialogModel {
actions?: Array<KeyValueDTOOfStringAndString>;
actionsRequired?: number;
area?: string;
content?: string;
description?: string;
settings: DialogSettings;
subtitle?: string;
title?: string;
}

View File

@@ -0,0 +1,3 @@
// start:ng42.barrel
export * from './dialog-modal.component';
// end:ng42.barrel

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