Merge branch 'develop' into release/1.5

This commit is contained in:
Lorenz Hilpert
2021-09-22 15:10:51 +02:00
53 changed files with 728 additions and 348 deletions

View File

@@ -97,6 +97,27 @@ export class DomainAvailabilityService {
);
}
@memorize({ ttl: 10000 })
getTakeAwayAvailabilityByBranch({
branch,
itemId,
price,
quantity,
}: {
branch: BranchDTO;
itemId: number;
price: PriceDTO;
quantity: number;
}): Observable<AvailabilityDTO> {
return this._stock.StockStockRequest({ stockRequest: { branchIds: [branch.id], itemId } }).pipe(
withLatestFrom(this.getTakeAwaySupplier()),
map(([response, supplier]) => {
return this._mapToTakeAwayAvailability({ response, supplier, branch, quantity, price });
}),
shareReplay()
);
}
getTakeAwayAvailabilityByEan({
eans,
price,

View File

@@ -1,6 +1,5 @@
import { HttpErrorResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { ActionHandler } from '@core/command';
import { OrderItemListItemDTO, StatusValues } from '@swagger/oms';
import { isResponseArgs } from '@utils/object';
import { first } from 'rxjs/operators';
@@ -9,12 +8,19 @@ import { ChangeOrderItemStatusBaseActionHandler } from './change-order-item-stat
import { OrderItemsContext } from './order-items.context';
@Injectable()
export class OrderAtSupplierActionHandler extends ActionHandler<OrderItemsContext> {
export class OrderAtSupplierActionHandler extends ChangeOrderItemStatusBaseActionHandler {
getStatusValues(orderItem: OrderItemListItemDTO, context: OrderItemsContext): StatusValues {
return {
processingStatus: 268435456,
};
}
constructor(private _domainOmsService: DomainOmsService) {
super('ORDER_AT_SUPPLIER');
super(_domainOmsService, 'ORDER_AT_SUPPLIER');
}
async handler(data: OrderItemsContext): Promise<OrderItemsContext> {
data = await super.handler(data);
const orderIds = data?.items.map((item) => item.orderId);
for (const orderId of orderIds) {
@@ -30,7 +36,6 @@ export class OrderAtSupplierActionHandler extends ActionHandler<OrderItemsContex
console.error('OrderAtSupplierActionHandler._domainOmsService.orderAtSupplier', err);
}
}
return data;
}
}

View File

@@ -11,7 +11,5 @@ export interface OrderItemsContext {
receipts?: ReceiptDTO[];
reorder?: boolean;
shippingDelayComment?: string;
}

View File

@@ -4,6 +4,7 @@ import { OrderItemsContext } from './order-items.context';
import { DomainPrinterService, Printer } from '@domain/printer';
import { UiModalService } from '@ui/modal';
import { PrintModalComponent, PrintModalData } from '@modal/printer';
import { groupBy } from '@ui/common';
@Injectable()
export class PrintShippingNoteActionHandler extends ActionHandler<OrderItemsContext> {
@@ -18,8 +19,22 @@ export class PrintShippingNoteActionHandler extends ActionHandler<OrderItemsCont
data: {
printImmediately: true,
printerType: 'Label',
print: (printer) =>
this.domainPrinterService.printShippingNote({ printer, receipts: data?.receipts?.map((r) => r?.id) }).toPromise(),
print: async (printer) => {
try {
for (const group of groupBy(data?.receipts, (receipt) => receipt?.buyer?.buyerNumber)) {
await this.domainPrinterService.printShippingNote({ printer, receipts: group?.items?.map((r) => r?.id) }).toPromise();
}
return {
error: false,
};
} catch (error) {
console.error(error);
return {
error: true,
message: error?.message || error,
};
}
},
} as PrintModalData,
})
.afterClosed$.toPromise();

View File

@@ -1,23 +1,73 @@
import { Injectable } from '@angular/core';
import { ActionHandler } from '@core/command';
import { ActionHandler, CommandService } from '@core/command';
import { OrderItemsContext } from './order-items.context';
import { UiModalService } from '@ui/modal';
import { ReorderModalComponent } from '@modal/reorder';
import { ReorderModalComponent, ReorderResult } from '@modal/reorder';
import { DomainCheckoutService } from '@domain/checkout';
import { AvailabilityDTO2, OrderItemListItemDTO } from '@swagger/oms';
@Injectable()
export class ReOrderActionHandler extends ActionHandler<OrderItemsContext> {
constructor(private _uiModal: UiModalService) {
constructor(private _command: CommandService, private _domainCheckoutService: DomainCheckoutService, private _uiModal: UiModalService) {
super('REORDER');
}
async handler(data: OrderItemsContext): Promise<OrderItemsContext> {
await this._uiModal
.open({
content: ReorderModalComponent,
data: data.items[0],
})
.afterClosed$.toPromise();
const updatedItems: OrderItemListItemDTO[] = [];
for (const orderItem of data.items) {
const result = await this._uiModal
.open<ReorderResult, OrderItemListItemDTO>({
content: ReorderModalComponent,
data: orderItem,
})
.afterClosed$.toPromise();
if (result.data) {
if (result.data.action === 'REORDER') {
const reorderResult = await this.reorder(result.data.item, result.data.availability);
const resItem = reorderResult.item1;
return { ...data, reorder: true };
updatedItems.push({
...result.data.item,
orderItemSubsetId: resItem.id,
compartmentCode: resItem.compartmentCode,
compartmentInfo: resItem.compartmentInfo,
estimatedShippingDate: resItem.estimatedShippingDate,
isPrebooked: resItem.isPrebooked,
processingStatus: 8192,
processingStatusDate: resItem.processingStatusDate,
quantity: resItem.quantity,
specialComment: resItem.specialComment,
ssc: resItem.ssc,
sscText: resItem.sscText,
});
} else if (result.data.action === 'NOTAVAILABLE') {
let context = { ...data, items: [orderItem] };
context = await this._command.handleCommand('NOTAVAILABLE', context);
updatedItems.push(...context.items);
}
}
}
return { ...data, items: updatedItems };
}
async reorder(orderItem: OrderItemListItemDTO, availability: AvailabilityDTO2) {
return await this._domainCheckoutService
.reorder(orderItem.orderId, orderItem.orderItemId, orderItem.orderItemSubsetId, {
quantity: orderItem.quantity,
availability: {
availabilityType: availability.status,
ssc: availability.ssc,
sscText: availability.sscText,
supplier: {
id: availability.supplierId,
},
isPrebooked: availability.isPrebooked,
estimatedShippingDate: availability.at,
price: availability.price,
inStock: availability.qty,
},
})
.toPromise();
}
}

View File

@@ -1,12 +1,11 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { DomainAvailabilityService } from '@domain/availability';
import { DomainCheckoutService } from '@domain/checkout';
import { DomainOmsService } from '@domain/oms';
import { ComponentStore } from '@ngrx/component-store';
import { AvailabilityDTO2, OrderItemListItemDTO } from '@swagger/oms';
import { UiModalRef } from '@ui/modal';
import { combineLatest } from 'rxjs';
import { catchError, map, switchMap, tap } from 'rxjs/operators';
import { ReorderResult } from './reorder.result';
interface GoodsInListReorderModalState {
orderItem: OrderItemListItemDTO;
@@ -109,10 +108,8 @@ export class ReorderModalComponent extends ComponentStore<GoodsInListReorderModa
takeAwayAvailabilityError: boolean;
constructor(
public modalRef: UiModalRef<any, OrderItemListItemDTO>,
private domainCheckoutService: DomainCheckoutService,
private domainAvailabilityService: DomainAvailabilityService,
private domainOmsService: DomainOmsService
public modalRef: UiModalRef<ReorderResult, OrderItemListItemDTO>,
private domainAvailabilityService: DomainAvailabilityService
) {
super({
orderItem: modalRef.data,
@@ -127,41 +124,22 @@ export class ReorderModalComponent extends ComponentStore<GoodsInListReorderModa
this.checkedAvailability = event ? availability : undefined;
}
async reorder() {
reorder() {
if (this.checkedAvailability) {
this.ctaDisabled = true;
await this.domainCheckoutService
.reorder(this.orderItem.orderId, this.orderItem.orderItemId, this.orderItem.orderItemSubsetId, {
quantity: this.orderItem.quantity,
availability: {
availabilityType: this.checkedAvailability.status,
ssc: this.checkedAvailability.ssc,
sscText: this.checkedAvailability.sscText,
supplier: {
id: this.checkedAvailability.supplierId,
},
isPrebooked: this.checkedAvailability.isPrebooked,
estimatedShippingDate: this.checkedAvailability.at,
price: this.checkedAvailability.price,
inStock: this.checkedAvailability.qty,
},
})
.toPromise();
this.ctaDisabled = false;
this.modalRef.close({ refresh: true });
this.modalRef.close({
item: this.orderItem,
availability: this.checkedAvailability,
action: 'REORDER',
});
}
}
async notAvailable() {
notAvailable() {
this.ctaDisabled = true;
await this.domainOmsService
.changeOrderStatus(this.orderItem.orderId, this.orderItem.orderItemId, this.orderItem.orderItemSubsetId, {
processingStatus: 4096,
})
.toPromise();
this.ctaDisabled = false;
this.modalRef.close({ refresh: true });
this.modalRef.close({
item: this.orderItem,
action: 'NOTAVAILABLE',
});
}
}

View File

@@ -0,0 +1,7 @@
import { AvailabilityDTO2, OrderItemListItemDTO } from '@swagger/oms';
export interface ReorderResult {
item: OrderItemListItemDTO;
availability?: AvailabilityDTO2;
action: 'REORDER' | 'NOTAVAILABLE';
}

View File

@@ -2,6 +2,7 @@
* Public API Surface of reorder
*/
export * from './lib/reorder.result';
export * from './lib/supplier-name.pipe';
export * from './lib/reorder.component';
export * from './lib/reorder.module';

View File

@@ -374,9 +374,11 @@ export class PurchasingOptionsModalStore extends ComponentStore<PurchasingOption
this.patchState({ fetchingAvailability: true });
switch (option) {
case 'take-away':
availability$ = this.availabilityService.getTakeAwayAvailability({
item: { itemId: item.id, ean: item.product.ean, price: item.catalogAvailability.price },
availability$ = this.availabilityService.getTakeAwayAvailabilityByBranch({
itemId: item.id,
price: item.catalogAvailability.price,
quantity,
branch,
});
break;
case 'pick-up':

View File

@@ -4,8 +4,8 @@ import { BreadcrumbService } from '@core/breadcrumb';
import { DomainGoodsService, OrderItemsContext } from '@domain/oms';
import { ComponentStore, tapResponse } from '@ngrx/component-store';
import { OrderItemListItemDTO, OrderItemProcessingStatusValue } from '@swagger/oms';
import { combineLatest, Subject, Subscription } from 'rxjs';
import { debounceTime, first, map, switchMap, takeUntil, tap, withLatestFrom } from 'rxjs/operators';
import { combineLatest, Subject } from 'rxjs';
import { debounceTime, first, map, switchMap, takeUntil, tap, throttleTime, withLatestFrom } from 'rxjs/operators';
export interface GoodsInDetailsComponentState {
fetching: boolean;
@@ -22,7 +22,7 @@ export interface GoodsInDetailsComponentState {
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class GoodsInDetailsComponent extends ComponentStore<GoodsInDetailsComponentState> implements OnInit, OnDestroy {
orderNumber$ = this.select((s) => s.orderNumber);
orderNumber$ = this.select((s) => decodeURIComponent(s.orderNumber ?? ''));
selectedOrderItemId$ = this.select((s) => +s.selectedOrderItemId);
@@ -56,21 +56,15 @@ export class GoodsInDetailsComponent extends ComponentStore<GoodsInDetailsCompon
}
ngOnInit() {
this._activatedRoute.params.pipe(takeUntil(this._onDestroy$)).subscribe((params) => {
this._activatedRoute.params.pipe(takeUntil(this._onDestroy$)).subscribe(async (params) => {
const orderNumber: string = params?.orderNumber;
const selectedOrderItemId: number = +params?.orderItemId || undefined;
const processingStatus = +params?.processingStatus as OrderItemProcessingStatusValue;
this.patchState({ orderNumber, selectedOrderItemId, processingStatus });
await this.removeDetailsCrumbs();
this.loadItems();
});
this.itemsWithProcessingStatus$.pipe(takeUntil(this._onDestroy$)).subscribe((items) => {
if (items.length === 0 && this.items?.length > 0) {
this.navigateToDetailsPage(this.items[0]);
}
});
this.removeBreadcrumbs();
}
@@ -87,16 +81,27 @@ export class GoodsInDetailsComponent extends ComponentStore<GoodsInDetailsCompon
});
}
async updateBreadcrumb(item: OrderItemListItemDTO) {
await this._breadcrumb.addOrUpdateBreadcrumbIfNotExists({
key: 'goods-in',
name: item?.orderNumber,
path: `/goods/in/details/order/${item?.orderNumber}/item/${item?.orderItemId}/${item?.processingStatus}`,
section: 'branch',
tags: ['goods-in', 'details', item?.orderNumber],
async removeDetailsCrumbs() {
const detailsCrumbs = await this._breadcrumb.getBreadcrumbsByKeyAndTags$('goods-in', ['goods-in', 'details']).pipe(first()).toPromise();
detailsCrumbs.forEach((crumb) => {
this._breadcrumb.removeBreadcrumb(crumb.id, true);
});
}
async updateBreadcrumb(item: OrderItemListItemDTO) {
if (item) {
await this._breadcrumb.addOrUpdateBreadcrumbIfNotExists({
key: 'goods-in',
name: item?.orderNumber,
path: `/goods/in/details/order/${encodeURIComponent(item?.orderNumber)}/item/${item?.orderItemId}/${item?.processingStatus}`,
section: 'branch',
tags: ['goods-in', 'details', item?.orderNumber],
});
}
}
// tslint:disable-next-line: member-ordering
loadItems = this.effect(($) =>
$.pipe(
tap(() => this.patchState({ fetching: false })),
@@ -117,7 +122,7 @@ export class GoodsInDetailsComponent extends ComponentStore<GoodsInDetailsCompon
res.result.find((item) => item.orderItemId === selectedOrderItemId && item.processingStatus === processingStatus)
);
},
(err) => {},
() => {},
() => {
this.patchState({ fetching: false });
}
@@ -137,13 +142,15 @@ export class GoodsInDetailsComponent extends ComponentStore<GoodsInDetailsCompon
navigateToEditPage(orderItem: OrderItemListItemDTO) {
this._router.navigate([
`/goods/in/details/order/${orderItem?.orderNumber}/item/${orderItem?.orderItemId}/${orderItem?.processingStatus}/edit`,
`/goods/in/details/order/${encodeURIComponent(orderItem?.orderNumber)}/item/${orderItem?.orderItemId}/${
orderItem?.processingStatus
}/edit`,
]);
}
navigateToDetailsPage(orderItem: OrderItemListItemDTO) {
this._router.navigate([
`/goods/in/details/order/${orderItem?.orderNumber}/item/${orderItem?.orderItemId}/${orderItem?.processingStatus}`,
`/goods/in/details/order/${encodeURIComponent(orderItem?.orderNumber)}/item/${orderItem?.orderItemId}/${orderItem?.processingStatus}`,
]);
}
@@ -159,13 +166,12 @@ export class GoodsInDetailsComponent extends ComponentStore<GoodsInDetailsCompon
}
}
actionHandled(handler: { orderItemsContext: OrderItemsContext; navigation: 'details' | 'main' | 'reservation' }) {
async actionHandled(handler: { orderItemsContext: OrderItemsContext; command: string; navigation: 'details' | 'main' | 'reservation' }) {
switch (handler.navigation) {
case 'details':
this.navigateToDetailsPage(handler.orderItemsContext.items.find((_) => true));
if (handler?.orderItemsContext?.reorder) {
this.loadItems();
}
await this.removeDetailsCrumbs();
this.loadItems();
break;
case 'main':
this.navigateToLandingPage();

View File

@@ -12,7 +12,9 @@ import { map, shareReplay, switchMap } from 'rxjs/operators';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class GoodsInEditComponent implements OnInit {
orderNumber$: Observable<string> = this._activatedRoute.params.pipe(map((params) => params?.orderNumber || undefined));
orderNumber$: Observable<string> = this._activatedRoute.params.pipe(
map((params) => decodeURIComponent(params.orderNumber ?? '') || undefined)
);
items$ = this.orderNumber$.pipe(switchMap((orderNumber) => this._domainGoodsInService.getItemByOrderNumber(orderNumber))).pipe(
map((response) => response.result),
@@ -37,7 +39,7 @@ export class GoodsInEditComponent implements OnInit {
await this._breadcrumb.addOrUpdateBreadcrumbIfNotExists({
key: 'goods-in',
name: 'Bearbeiten',
path: `/goods/in/details/order/${orderNumber}/item/${orderItemId}/${processingStatus}/edit`,
path: `/goods/in/details/order/${encodeURIComponent(orderNumber)}/item/${orderItemId}/${processingStatus}/edit`,
section: 'branch',
tags: ['goods-in', 'edit', orderNumber],
});
@@ -47,6 +49,6 @@ export class GoodsInEditComponent implements OnInit {
const orderNumber = this._activatedRoute.snapshot.params.orderNumber;
const orderItemId = this._activatedRoute.snapshot.params.orderItemId;
const processingStatus = this._activatedRoute.snapshot.params.processingStatus;
this._router.navigate([`/goods/in/details/order/${orderNumber}/item/${orderItemId}/${processingStatus}`]);
this._router.navigate([`/goods/in/details/order/${encodeURIComponent(orderNumber)}/item/${orderItemId}/${processingStatus}`]);
}
}

View File

@@ -3,7 +3,7 @@
<h3 class="customer-name">
<span *ngIf="orderItem.organisation != null">{{ orderItem.organisation }}</span>
<span *ngIf="orderItem.organisation != null && orderItem.firstName != null && orderItem.lastName != null"> - </span>
<span *ngIf="orderItem.firstName != null && orderItem.lastName != null">{{ orderItem.firstName }} {{ orderItem.lastName }}</span>
<span *ngIf="orderItem.firstName != null && orderItem.lastName != null">{{ orderItem.lastName }} {{ orderItem.firstName }}</span>
</h3>
<h3 class="ssc" *ngIf="!(editSsc$ | async) && orderItem.ssc && orderItem.sscText">{{ orderItem.ssc }} - {{ orderItem.sscText }}</h3>

View File

@@ -1,9 +1,8 @@
import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnDestroy, Output } from '@angular/core';
import { CommandService } from '@core/command';
import { DomainOmsService } from '@domain/oms';
import { ReorderModalComponent } from '@modal/reorder';
import { ComponentStore } from '@ngrx/component-store';
import { OrderItemListItemDTO } from '@swagger/oms';
import { UiModalService } from '@ui/modal';
import { isEqual } from 'lodash';
import { Subject } from 'rxjs';
import { catchError, first, shareReplay, switchMap, takeUntil } from 'rxjs/operators';
@@ -115,7 +114,7 @@ export class GoodsInListItemComponent extends ComponentStore<GoodsInListItemComp
private _onDestroy$ = new Subject();
constructor(private _omsService: DomainOmsService, private _uiModal: UiModalService) {
constructor(private _omsService: DomainOmsService, private _command: CommandService) {
super({
item: undefined,
editSsc: false,
@@ -153,15 +152,8 @@ export class GoodsInListItemComponent extends ComponentStore<GoodsInListItemComp
this.sscChanged = false;
}
showReorderModal() {
const modal = this._uiModal.open({
content: ReorderModalComponent,
data: this.item,
});
modal.afterClosed$.pipe(takeUntil(this._onDestroy$)).subscribe((modal) => {
if (modal?.data?.refresh) {
this.refresh.emit();
}
});
async showReorderModal() {
await this._command.handleCommand('REORDER', { items: [this.item] });
this.refresh.emit();
}
}

View File

@@ -2,7 +2,13 @@
<div class="hits">{{ hits$ | async }} Titel</div>
</div>
<ui-scroll-container [loading]="loading$ | async" (reachEnd)="loadMore()" [deltaEnd]="150" [itemLength]="itemLength$ | async">
<ui-scroll-container
*ngIf="!(listEmpty$ | async); else emptyMessage"
[loading]="loading$ | async"
(reachEnd)="loadMore()"
[deltaEnd]="150"
[itemLength]="itemLength$ | async"
>
<shared-goods-in-out-order-group *ngFor="let bueryNumberGroup of items$ | async | groupBy: byBuyerNumberFn">
<ng-container *ngFor="let orderNumberGroup of bueryNumberGroup.items | groupBy: byOrderNumberFn; let lastOrderNumber = last">
<ng-container
@@ -31,6 +37,13 @@
</shared-goods-in-out-order-group>
</ui-scroll-container>
<ng-template #emptyMessage>
<div class="empty-message">
Es sind im Moment keine Artikel vorhanden, die<br />
Reserviert werden sollen.
</div>
</ng-template>
<div class="actions" *ngIf="actions$ | async; let actions">
<button
[disabled]="(changeActionLoader$ | async) || (loading$ | async)"

View File

@@ -10,6 +10,10 @@
}
}
.empty-message {
@apply bg-white text-center font-semibold text-inactive-branch py-10 rounded-card;
}
.divider {
@apply h-px-2;
}

View File

@@ -27,6 +27,11 @@ export class GoodsInReservationComponent implements OnInit, OnDestroy {
loading$ = this._store.loading$.pipe(shareReplay());
listEmpty$ = combineLatest([this.loading$, this.hits$]).pipe(
map(([loading, hits]) => !loading && hits === 0),
shareReplay()
);
takeAwayAvailabilities$ = this._store.takeAwayAvailabilities$.pipe(shareReplay());
selectedOrderItemSubsetIds$ = this._store.selectedOrderItemSubsetIds$;
@@ -107,7 +112,7 @@ export class GoodsInReservationComponent implements OnInit, OnDestroy {
const processingStatus = orderItem.processingStatus;
const orderItemId = orderItem.orderItemId;
this._router.navigate([`/goods/in/details/order/${orderNumber}/item/${orderItemId}/${processingStatus}`]);
this._router.navigate([`/goods/in/details/order/${encodeURIComponent(orderNumber)}/item/${orderItemId}/${processingStatus}`]);
}
initInitialSearch() {

View File

@@ -69,7 +69,9 @@ export class GoodsInSearchFilterComponent implements OnInit, OnDestroy {
if (result.hits === 1) {
const orderItem = result.result[0];
this._router.navigate([
`/goods/in/details/order/${orderItem.orderNumber}/item/${orderItem.orderItemId}/${orderItem.processingStatus}`,
`/goods/in/details/order/${encodeURIComponent(orderItem.orderNumber)}/item/${orderItem.orderItemId}/${
orderItem.processingStatus
}`,
]);
} else {
this._router.navigate(['goods', 'in', 'results'], { queryParams: this._goodsInSearchStore.filter.getQueryParams() });

View File

@@ -93,7 +93,9 @@ export class GoodsInSearchMainComponent implements OnInit, OnDestroy {
if (result.hits === 1) {
const orderItem = result.result[0];
this._router.navigate([
`/goods/in/details/order/${orderItem.orderNumber}/item/${orderItem.orderItemId}/${orderItem.processingStatus}`,
`/goods/in/details/order/${encodeURIComponent(orderItem.orderNumber)}/item/${orderItem.orderItemId}/${
orderItem.processingStatus
}`,
]);
} else {
this._router.navigate(['goods', 'in', 'results'], { queryParams: this._goodsInSearchStore.filter.getQueryParams() });

View File

@@ -107,6 +107,6 @@ export class GoodsInSearchResultsComponent implements OnInit, OnDestroy {
const processingStatus = orderItem.processingStatus;
const orderItemId = orderItem.orderItemId;
this._router.navigate([`/goods/in/details/order/${orderNumber}/item/${orderItemId}/${processingStatus}`]);
this._router.navigate([`/goods/in/details/order/${encodeURIComponent(orderNumber)}/item/${orderItemId}/${processingStatus}`]);
}
}

View File

@@ -1,5 +1,8 @@
<shared-goods-in-out-order-details (actionHandled)="actionHandled($event)" [itemsSelectable]="true">
<shared-goods-in-out-order-details-header (editClick)="navigateToEditPage($event)"></shared-goods-in-out-order-details-header>
<shared-goods-in-out-order-details-item *ngFor="let item of items$ | async" [orderItem]="item"></shared-goods-in-out-order-details-item>
<shared-goods-in-out-order-details-item
*ngFor="let item of itemsWithProcessingStatus$ | async"
[orderItem]="item"
></shared-goods-in-out-order-details-item>
<shared-goods-in-out-order-details-tags></shared-goods-in-out-order-details-tags>
</shared-goods-in-out-order-details>

View File

@@ -4,6 +4,7 @@ import { BreadcrumbService } from '@core/breadcrumb';
import { DomainGoodsService, OrderItemsContext } from '@domain/oms';
import { ComponentStore, tapResponse } from '@ngrx/component-store';
import { ListResponseArgsOfOrderItemListItemDTO, OrderItemListItemDTO, OrderItemProcessingStatusValue } from '@swagger/oms';
import { Command } from 'protractor';
import { combineLatest, Observable, Subject, Subscription } from 'rxjs';
import { debounceTime, first, map, switchMap, takeUntil, tap, withLatestFrom } from 'rxjs/operators';
@@ -22,9 +23,9 @@ export interface GoodsOutDetailsComponentState {
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class GoodsOutDetailsComponent extends ComponentStore<GoodsOutDetailsComponentState> implements OnInit, OnDestroy {
orderNumber$ = this.select((s) => s.orderNumber);
orderNumber$ = this.select((s) => decodeURIComponent(s.orderNumber ?? '') || undefined);
compartmentCode$ = this.select((s) => s.compartmentCode);
compartmentCode$ = this.select((s) => decodeURIComponent(s.compartmentCode ?? '') || undefined);
processingStatus$ = this.select((s) => s.processingStatus);
@@ -52,21 +53,16 @@ export class GoodsOutDetailsComponent extends ComponentStore<GoodsOutDetailsComp
}
ngOnInit() {
this._activatedRoute.params.pipe(takeUntil(this._onDestroy$)).subscribe((params) => {
this._activatedRoute.params.pipe(takeUntil(this._onDestroy$)).subscribe(async (params) => {
const orderNumber: string = params?.orderNumber;
const compartmentCode = params?.compartmentCode;
const processingStatus = +params?.processingStatus as OrderItemProcessingStatusValue;
this.patchState({ orderNumber, compartmentCode, processingStatus });
await this.removeDetailsCrumbs();
this.loadItems();
});
this.itemsWithProcessingStatus$.pipe(takeUntil(this._onDestroy$)).subscribe((items) => {
if (items.length === 0 && this.items?.length > 0) {
this.navigateToDetailsPage(this.items[0]);
}
});
this.removeBreadcrumbs();
}
@@ -76,32 +72,37 @@ export class GoodsOutDetailsComponent extends ComponentStore<GoodsOutDetailsComp
}
async updateBreadcrumb(item: OrderItemListItemDTO) {
await this._breadcrumb.addOrUpdateBreadcrumbIfNotExists({
key: 'goods-out',
name: item?.compartmentCode || item?.orderNumber,
path: this.getDetailsPath(item),
section: 'customer',
tags: ['goods-out', 'details', item?.compartmentCode || item?.orderNumber],
});
if (item) {
await this._breadcrumb.addOrUpdateBreadcrumbIfNotExists({
key: 'goods-out',
name: item?.compartmentCode || item?.orderNumber,
path: this.getDetailsPath(item),
section: 'customer',
tags: ['goods-out', 'details', item?.compartmentCode || item?.orderNumber],
});
}
}
async removeBreadcrumbs() {
const detailsCrumbs = await this._breadcrumb
.getBreadcrumbsByKeyAndTags$('goods-out', ['goods-out', 'details'])
.pipe(first())
.toPromise();
const editCrumbs = await this._breadcrumb.getBreadcrumbsByKeyAndTags$('goods-out', ['goods-out', 'edit']).pipe(first()).toPromise();
editCrumbs.forEach((crumb) => {
this._breadcrumb.removeBreadcrumb(crumb.id, true);
});
}
async removeDetailsCrumbs() {
const detailsCrumbs = await this._breadcrumb
.getBreadcrumbsByKeyAndTags$('goods-out', ['goods-out', 'details'])
.pipe(first())
.toPromise();
detailsCrumbs.forEach((crumb) => {
this._breadcrumb.removeBreadcrumb(crumb.id, true);
});
}
// tslint:disable-next-line: member-ordering
loadItems = this.effect(($) =>
$.pipe(
tap(() => this.patchState({ fetching: false })),
@@ -141,22 +142,21 @@ export class GoodsOutDetailsComponent extends ComponentStore<GoodsOutDetailsComp
this._router.navigate([this.getDetailsPath(item)]);
}
actionHandled(handler: { orderItemsContext: OrderItemsContext; navigation: 'details' | 'main' | 'reservation' }) {
async actionHandled(handler: { orderItemsContext: OrderItemsContext; command: string; navigation: 'details' | 'main' | 'reservation' }) {
this.navigateToDetailsPage(handler.orderItemsContext.items.find((_) => true));
if (handler.orderItemsContext.reorder) {
this.loadItems();
}
await this.removeDetailsCrumbs();
this.loadItems();
}
getDetailsPath(item: OrderItemListItemDTO) {
return item?.compartmentCode
? `/goods/out/details/compartment/${item?.compartmentCode}/${item?.processingStatus}`
: `/goods/out/details/order/${item?.orderNumber}/${item?.processingStatus}`;
? `/goods/out/details/compartment/${encodeURIComponent(item?.compartmentCode)}/${item?.processingStatus}`
: `/goods/out/details/order/${encodeURIComponent(item?.orderNumber)}/${item?.processingStatus}`;
}
getEditPath(item: OrderItemListItemDTO) {
return item?.compartmentCode
? `/goods/out/details/compartment/${item?.compartmentCode}/${item?.processingStatus}/edit`
: `/goods/out/details/order/${item?.orderNumber}/${item?.processingStatus}/edit`;
? `/goods/out/details/compartment/${encodeURIComponent(item?.compartmentCode)}/${item?.processingStatus}/edit`
: `/goods/out/details/order/${encodeURIComponent(item?.orderNumber)}/${item?.processingStatus}/edit`;
}
}

View File

@@ -12,11 +12,15 @@ import { map, shareReplay, switchMap, withLatestFrom } from 'rxjs/operators';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class GoodsOutEditComponent implements OnInit {
orderNumber$: Observable<string> = this._activatedRoute.params.pipe(map((params) => params?.orderNumber || undefined));
orderNumber$: Observable<string> = this._activatedRoute.params.pipe(
map((params) => decodeURIComponent(params.orderNumber ?? '') || undefined)
);
processingStatus$ = this._activatedRoute.params.pipe(map((params) => params?.processingStatus || undefined));
compartmentCode$: Observable<string> = this._activatedRoute.params.pipe(map((params) => params?.compartmentCode || undefined));
compartmentCode$: Observable<string> = this._activatedRoute.params.pipe(
map((params) => decodeURIComponent(params?.compartmentCode ?? '') || undefined)
);
items$ = combineLatest([this.orderNumber$, this.compartmentCode$]).pipe(
switchMap(([orderNumber, compartmentCode]) =>
@@ -48,8 +52,8 @@ export class GoodsOutEditComponent implements OnInit {
key: 'goods-out',
name: 'Bearbeiten',
path: compartmentCode
? `/goods/out/details/compartment/${compartmentCode}/${processingStatus}/edit`
: `/goods/out/details/order/${orderNumber}/${processingStatus}/edit`,
? `/goods/out/details/compartment/${encodeURIComponent(compartmentCode)}/${processingStatus}/edit`
: `/goods/out/details/order/${encodeURIComponent(orderNumber)}/${processingStatus}/edit`,
section: 'customer',
tags: ['goods-out', 'edit', compartmentCode || orderNumber],
});
@@ -60,7 +64,7 @@ export class GoodsOutEditComponent implements OnInit {
const compartmentCode = this._activatedRoute.snapshot.params.compartmentCode;
const processingStatus = this._activatedRoute.snapshot.params.processingStatus;
compartmentCode
? this._router.navigate([`/goods/out/details/compartment/${compartmentCode}/${processingStatus}`])
: this._router.navigate([`/goods/out/details/order/${orderNumber}/${processingStatus}`]);
? this._router.navigate([`/goods/out/details/compartment/${encodeURIComponent(compartmentCode)}/${processingStatus}`])
: this._router.navigate([`/goods/out/details/order/${encodeURIComponent(orderNumber)}/${processingStatus}`]);
}
}

View File

@@ -114,7 +114,7 @@ export class GoodsOutSearchMainComponent implements OnInit, OnDestroy {
getDetailsPath(item: OrderItemListItemDTO) {
return item?.compartmentCode
? `/goods/out/details/compartment/${item?.compartmentCode}/${item?.processingStatus}`
: `/goods/out/details/order/${item?.orderNumber}/${item?.processingStatus}`;
? `/goods/out/details/compartment/${encodeURIComponent(item?.compartmentCode)}/${item?.processingStatus}`
: `/goods/out/details/order/${encodeURIComponent(item?.orderNumber)}/${item?.processingStatus}`;
}
}

View File

@@ -149,9 +149,9 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
const compartmentCode = orderItem.compartmentCode;
if (compartmentCode) {
this._router.navigate([`/goods/out/details/compartment/${compartmentCode}/${processingStatus}`]);
this._router.navigate([`/goods/out/details/compartment/${encodeURIComponent(compartmentCode)}/${processingStatus}`]);
} else {
this._router.navigate([`/goods/out/details/order/${orderNumber}/${processingStatus}`]);
this._router.navigate([`/goods/out/details/order/${encodeURIComponent(orderNumber)}/${processingStatus}`]);
}
}

View File

@@ -2,9 +2,12 @@
<h5>
{{ dayOfWeek }}
</h5>
<span class="muted">
<ng-container *ngIf="checkSameDay(); else notToday">{{ date | date: 'EEEE, dd. MMMM yyyy' }}</ng-container>
<ng-template #notToday>{{ date | date: 'dd. MMMM yyyy' }}</ng-template>
<span class="info-header-container">
<span class="muted">
<ng-container *ngIf="checkSameDay(); else notToday">{{ date | date: 'EEEE, dd. MMMM yyyy' }}</ng-container>
<ng-template #notToday>{{ date | date: 'dd. MMMM yyyy' }}</ng-template>
</span>
<div>{{ info?.category | replace: '##':' / ' }}</div>
</span>
</div>
@@ -16,9 +19,9 @@
<div class="task-indicator" *ngIf="type === 'Task'" [style.backgroundColor]="indicatorColor$ | async">&nbsp;</div>
<ui-icon icon="info" size="16px" *ngIf="type !== 'Task'"></ui-icon>
</div>
<div class="teaser" *ngIf="teaser$ | async; let teaser">
<button class="teaser" *ngIf="teaser$ | async; let teaser" (click)="openImage(undefined, teaser)">
<img [isaBlobImage]="teaser" />
</div>
</button>
<div class="content">
<div [innerHTML]="info.text"></div>
<div class="task-date" *ngIf="showTaskDate && !!taskDate">Zu erledigen {{ taskDate }}</div>
@@ -77,6 +80,17 @@
</div>
</ng-container>
<ng-container *ngIf="info?.updateComment">
<hr *ngIf="info?.attachments === 0 || info?.articles?.length === 0" />
<div class="update-comment">
<ui-icon icon="refresh" size="19px"></ui-icon>
<div class="grow">
{{ info.updateComment }}
</div>
</div>
<hr *ngIf="!(showNotes$ | async)" />
</ng-container>
<ng-container *ngIf="showNotes$ | async">
<hr />
<div class="notes">

View File

@@ -9,8 +9,12 @@
@apply font-bold m-0 text-lg;
}
.muted {
@apply ml-4 text-cool-grey text-base font-semibold;
.info-header-container {
@apply ml-4;
.muted {
@apply text-cool-grey text-base font-semibold;
}
}
}
@@ -43,7 +47,7 @@ hr {
}
.teaser {
@apply mx-2;
@apply mx-2 bg-transparent outline-none border-none;
img {
@apply h-px-50;
@@ -102,6 +106,14 @@ hr {
}
}
.update-comment {
@apply flex flex-row items-center text-lg;
ui-icon {
@apply mr-3 text-cool-grey;
}
}
.grow {
@apply flex-grow;
}

View File

@@ -140,16 +140,20 @@ export class TaskInfoComponent implements OnChanges {
} as PdfViewerModalData,
});
} else if (['image/gif', 'image/jpeg', 'image/png', 'image/svg+xml'].includes(file.mime)) {
this.uiModal.open({
content: ImageViewerModalComponent,
data: {
file,
content,
} as ImageViewerModalData,
});
this.openImage(file, content);
}
}
openImage(file: FileDTO, content: Blob) {
this.uiModal.open({
content: ImageViewerModalComponent,
data: {
file,
content,
} as ImageViewerModalData,
});
}
copyArticleList() {
const eanString = this.info.articles.map((article) => article.data.ean).join(',');
this.clipboard.copy(eanString);

View File

@@ -26,7 +26,8 @@
<b>{{ item?.title }}</b>
<ui-icon class="icon" icon="camera" size="16px" *ngIf="item.requiresImageOnConfirmation"></ui-icon>
<ui-icon class="icon" icon="attachment" size="16px" *ngIf="hasAttachments$ | async"></ui-icon>
<ui-icon class="icon icon-update-comment" icon="refresh" size="16px" *ngIf="!!item.updateComment"></ui-icon>
</div>
<div>{{ item?.text | stripHtmlTags | substr: 70 }}</div>
<div>{{ item?.category | replace: '##':' / ' }}</div>
<div class="task-content-text">{{ item?.text | stripHtmlTags | substr: 70 }}</div>
</div>

View File

@@ -17,6 +17,10 @@
}
}
.icon-update-comment {
@apply text-dark-goldenrod;
}
.indicator + .icon {
@apply ml-0;
}
@@ -31,5 +35,9 @@
.task-content-title {
@apply flex flex-row;
}
.task-content-text {
@apply text-cool-grey;
}
}
}

View File

@@ -1,5 +1,5 @@
:host {
@apply flex flex-col relative;
@apply flex flex-col relative items-center;
}
h1 {
@@ -7,7 +7,7 @@ h1 {
}
img {
@apply max-w-full;
@apply max-w-full h-auto;
}
button.close {

View File

@@ -1,4 +1,7 @@
<h3 *ngIf="info?.isSpecial">Sonderinfo</h3>
<h1>{{ info?.title }}</h1>
<div class="header">
<h1>{{ info?.title }}</h1>
<ui-icon *ngIf="info?.updateComment" icon="refresh" size="22px"></ui-icon>
</div>
<page-task-info [info]="info"></page-task-info>
<button type="button" (click)="close()"><ui-icon icon="close" size="16px"></ui-icon></button>

View File

@@ -2,8 +2,16 @@
@apply flex flex-col relative;
}
h1 {
@apply text-xl font-bold text-center;
.header {
@apply flex flex-row justify-center items-center mt-3;
h1 {
@apply text-xl font-bold text-center;
}
ui-icon {
@apply ml-4 text-dark-goldenrod;
}
}
h3 {

View File

@@ -1,4 +1,7 @@
<h3>Vorabinfo</h3>
<h1>{{ info?.title }}</h1>
<div class="header">
<h1>{{ info?.title }}</h1>
<ui-icon *ngIf="info?.updateComment" icon="refresh" size="22px"></ui-icon>
</div>
<page-task-info [info]="info" showTaskDate="true"></page-task-info>
<button type="button" (click)="close()"><ui-icon icon="close" size="16px"></ui-icon></button>

View File

@@ -2,8 +2,16 @@
@apply flex flex-col relative;
}
h1 {
@apply text-xl font-bold text-center;
.header {
@apply flex flex-row justify-center items-center mt-3;
h1 {
@apply text-xl font-bold text-center;
}
ui-icon {
@apply ml-4 text-dark-goldenrod;
}
}
h3 {

View File

@@ -3,6 +3,7 @@
<div class="header">
<ui-tshirt [effort]="info?.effort"></ui-tshirt>
<h1>{{ info?.title }}</h1>
<ui-icon *ngIf="info?.updateComment" icon="refresh" size="22px"></ui-icon>
</div>
<div class="status">
<div class="indicator" [style.backgroundColor]="indicatorColor$ | async"></div>

View File

@@ -8,6 +8,10 @@
h1 {
@apply text-xl font-bold text-center m-0 ml-4;
}
ui-icon {
@apply ml-4 text-dark-goldenrod;
}
}
.status {

View File

@@ -49,7 +49,11 @@ export class SharedGoodsInOutOrderDetailsComponent extends SharedGoodsInOutOrder
changeActionDisabled$ = new BehaviorSubject<boolean>(false);
@Output()
actionHandled = new EventEmitter<{ orderItemsContext: OrderItemsContext; navigation: 'details' | 'main' | 'reservation' }>();
actionHandled = new EventEmitter<{
orderItemsContext: OrderItemsContext;
command: string;
navigation: 'details' | 'main' | 'reservation';
}>();
private _orderDetailsItemComponentsChangeSubscription: Subscription;
@@ -127,7 +131,7 @@ export class SharedGoodsInOutOrderDetailsComponent extends SharedGoodsInOutOrder
if (action.command.includes('ARRIVED')) {
navigateTo = await this.arrivedActionNavigation();
}
this.actionHandled.emit({ orderItemsContext: commandData, navigation: navigateTo });
this.actionHandled.emit({ orderItemsContext: commandData, command: action.command, navigation: navigateTo });
this.updateOrderItems(commandData.items);
} catch (error) {
console.error(error);

View File

@@ -24,7 +24,12 @@
<div class="item-data-wrapper">
<div class="item-data">
<div class="item-format">
<img class="format-icon" [src]="'/assets/images/Icon_' + item.product?.format + '.svg'" alt="format icon" />
<img
class="format-icon"
*ngIf="item?.product?.format"
[src]="'/assets/images/Icon_' + item.product?.format + '.svg'"
[alt]="item.product?.format"
/>
{{ item.product.formatDetail }}
</div>
<ng-container [ngSwitch]="showChangeDate$ | async">

View File

@@ -4,23 +4,27 @@ export { EntityDTOContainerOfInfoDTO } from './models/entity-dtocontainer-of-inf
export { EntityDTOReferenceContainer } from './models/entity-dtoreference-container';
export { ExternalReferenceDTO } from './models/external-reference-dto';
export { EntityStatus } from './models/entity-status';
export { EntityDTOContainerOfDisplayInfoDTO } from './models/entity-dtocontainer-of-display-info-dto';
export { DisplayInfoDTO } from './models/display-info-dto';
export { ProcessingStatus } from './models/processing-status';
export { EntityDTOContainerOfFileDTO } from './models/entity-dtocontainer-of-file-dto';
export { FileDTO } from './models/file-dto';
export { EntityDTOOfFileDTOAndFile } from './models/entity-dtoof-file-dtoand-file';
export { ReadOnlyEntityDTOOfFileDTOAndFile } from './models/read-only-entity-dtoof-file-dtoand-file';
export { EntityDTO } from './models/entity-dto';
export { EntityDTOContainerOfArticleDTO } from './models/entity-dtocontainer-of-article-dto';
export { ArticleDTO } from './models/article-dto';
export { EntityDTOOfArticleDTOAndArticle } from './models/entity-dtoof-article-dtoand-article';
export { ReadOnlyEntityDTOOfArticleDTOAndArticle } from './models/read-only-entity-dtoof-article-dtoand-article';
export { ReadOnlyEntityDTOOfDisplayInfoDTOAndDisplayInfo } from './models/read-only-entity-dtoof-display-info-dtoand-display-info';
export { InfoStatus } from './models/info-status';
export { EntityDTOContainerOfBranchDTO } from './models/entity-dtocontainer-of-branch-dto';
export { BranchDTO } from './models/branch-dto';
export { BranchType } from './models/branch-type';
export { EntityDTOOfBranchDTOAndReadOnlyBranch } from './models/entity-dtoof-branch-dtoand-read-only-branch';
export { ReadOnlyEntityDTOOfBranchDTOAndReadOnlyBranch } from './models/read-only-entity-dtoof-branch-dtoand-read-only-branch';
export { EntityDTO } from './models/entity-dto';
export { InfoType } from './models/info-type';
export { EntityDTOContainerOfFileDTO } from './models/entity-dtocontainer-of-file-dto';
export { FileDTO } from './models/file-dto';
export { EntityDTOOfFileDTOAndFile } from './models/entity-dtoof-file-dtoand-file';
export { ReadOnlyEntityDTOOfFileDTOAndFile } from './models/read-only-entity-dtoof-file-dtoand-file';
export { TaskType } from './models/task-type';
export { EntityDTOContainerOfArticleDTO } from './models/entity-dtocontainer-of-article-dto';
export { ArticleDTO } from './models/article-dto';
export { EntityDTOOfArticleDTOAndArticle } from './models/entity-dtoof-article-dtoand-article';
export { ReadOnlyEntityDTOOfArticleDTOAndArticle } from './models/read-only-entity-dtoof-article-dtoand-article';
export { EntityDTOContainerOfConfirmationDTO } from './models/entity-dtocontainer-of-confirmation-dto';
export { ConfirmationDTO } from './models/confirmation-dto';
export { EntityDTOOfConfirmationDTOAndConfirmation } from './models/entity-dtoof-confirmation-dtoand-confirmation';
@@ -39,10 +43,6 @@ export { ResponseArgsOfIEnumerableOfEntityKeyValueDTOOfStringAndString } from '.
export { EntityKeyValueDTOOfStringAndString } from './models/entity-key-value-dtoof-string-and-string';
export { ListResponseArgsOfDisplayInfoDTO } from './models/list-response-args-of-display-info-dto';
export { ResponseArgsOfIEnumerableOfDisplayInfoDTO } from './models/response-args-of-ienumerable-of-display-info-dto';
export { DisplayInfoDTO } from './models/display-info-dto';
export { EntityDTOContainerOfDisplayInfoDTO } from './models/entity-dtocontainer-of-display-info-dto';
export { ProcessingStatus } from './models/processing-status';
export { ReadOnlyEntityDTOOfDisplayInfoDTOAndDisplayInfo } from './models/read-only-entity-dtoof-display-info-dtoand-display-info';
export { DisplayInfoRequest } from './models/display-info-request';
export { ResponseArgsOfIEnumerableOfInputDTO } from './models/response-args-of-ienumerable-of-input-dto';
export { InputDTO } from './models/input-dto';

View File

@@ -101,6 +101,11 @@ export interface DisplayInfoDTO extends ReadOnlyEntityDTOOfDisplayInfoDTOAndDisp
*/
requiresImageOnConfirmation?: boolean;
/**
* Nachfolger (read only)
*/
successor?: EntityDTOContainerOfDisplayInfoDTO;
/**
* Aufgabenbeginn
*/

View File

@@ -7,6 +7,7 @@ import { EntityDTOContainerOfFileDTO } from './entity-dtocontainer-of-file-dto';
import { InfoStatus } from './info-status';
import { InfoType } from './info-type';
import { EntityDTOContainerOfInfoDTO } from './entity-dtocontainer-of-info-dto';
import { EntityDTOContainerOfDisplayInfoDTO } from './entity-dtocontainer-of-display-info-dto';
import { TaskType } from './task-type';
export interface InfoDTO extends EntityDTOOfInfoDTOAndInfo{
@@ -185,6 +186,11 @@ export interface InfoDTO extends EntityDTOOfInfoDTOAndInfo{
*/
requiresImageOnConfirmation?: boolean;
/**
* Nachfolger (read only)
*/
successor?: EntityDTOContainerOfDisplayInfoDTO;
/**
* Aufgabenbeginn
*/

View File

@@ -3,4 +3,4 @@
/**
* Freigabestatus
*/
export type InfoStatus = 0 | 1 | 2 | 3 | 4 | 5;
export type InfoStatus = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11;

View File

@@ -20,6 +20,8 @@ class EISBackendService extends __BaseService {
static readonly EISBackendCreateInfoPath = '/eis/info';
static readonly EISBackendGetInfosPath = '/eis/info';
static readonly EISBackendDeleteInfoPath = '/eis/delete/{infoId}';
static readonly EISBackendApproveUpdatePath = '/eis/updateapproval/{infoId}';
static readonly EISBackendRejectUpdatePath = '/eis/updatereject/{infoId}';
static readonly EISBackendUpdateInfoPath = '/eis/info/{infoId}';
static readonly EISBackendGetInfoByIdPath = '/eis/info/{infoId}';
static readonly EISBackendApproveInfoPath = '/eis/info/approve/{allowsave}';
@@ -176,6 +178,106 @@ class EISBackendService extends __BaseService {
);
}
/**
* Freigabe eines Updates
* @param params The `EISBackendService.EISBackendApproveUpdateParams` containing the following parameters:
*
* - `infoId`: Info PK
*
* - `infoDTO`: Daten
*
* - `locale`: Lokalisierung
*/
EISBackendApproveUpdateResponse(params: EISBackendService.EISBackendApproveUpdateParams): __Observable<__StrictHttpResponse<ResponseArgsOfInfoDTO>> {
let __params = this.newParams();
let __headers = new HttpHeaders();
let __body: any = null;
__body = params.infoDTO;
if (params.locale != null) __params = __params.set('locale', params.locale.toString());
let req = new HttpRequest<any>(
'PUT',
this.rootUrl + `/eis/updateapproval/${encodeURIComponent(String(params.infoId))}`,
__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<ResponseArgsOfInfoDTO>;
})
);
}
/**
* Freigabe eines Updates
* @param params The `EISBackendService.EISBackendApproveUpdateParams` containing the following parameters:
*
* - `infoId`: Info PK
*
* - `infoDTO`: Daten
*
* - `locale`: Lokalisierung
*/
EISBackendApproveUpdate(params: EISBackendService.EISBackendApproveUpdateParams): __Observable<ResponseArgsOfInfoDTO> {
return this.EISBackendApproveUpdateResponse(params).pipe(
__map(_r => _r.body as ResponseArgsOfInfoDTO)
);
}
/**
* Ablehnen eines Updates
* @param params The `EISBackendService.EISBackendRejectUpdateParams` containing the following parameters:
*
* - `infoId`: Info PK
*
* - `infoDTO`: Daten
*
* - `locale`: Lokalisierung
*/
EISBackendRejectUpdateResponse(params: EISBackendService.EISBackendRejectUpdateParams): __Observable<__StrictHttpResponse<ResponseArgsOfInfoDTO>> {
let __params = this.newParams();
let __headers = new HttpHeaders();
let __body: any = null;
__body = params.infoDTO;
if (params.locale != null) __params = __params.set('locale', params.locale.toString());
let req = new HttpRequest<any>(
'PUT',
this.rootUrl + `/eis/updatereject/${encodeURIComponent(String(params.infoId))}`,
__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<ResponseArgsOfInfoDTO>;
})
);
}
/**
* Ablehnen eines Updates
* @param params The `EISBackendService.EISBackendRejectUpdateParams` containing the following parameters:
*
* - `infoId`: Info PK
*
* - `infoDTO`: Daten
*
* - `locale`: Lokalisierung
*/
EISBackendRejectUpdate(params: EISBackendService.EISBackendRejectUpdateParams): __Observable<ResponseArgsOfInfoDTO> {
return this.EISBackendRejectUpdateResponse(params).pipe(
__map(_r => _r.body as ResponseArgsOfInfoDTO)
);
}
/**
* Info aktualisieren
* @param params The `EISBackendService.EISBackendUpdateInfoParams` containing the following parameters:
@@ -547,6 +649,48 @@ module EISBackendService {
archive?: boolean;
}
/**
* Parameters for EISBackendApproveUpdate
*/
export interface EISBackendApproveUpdateParams {
/**
* Info PK
*/
infoId: number;
/**
* Daten
*/
infoDTO: InfoDTO;
/**
* Lokalisierung
*/
locale?: null | string;
}
/**
* Parameters for EISBackendRejectUpdate
*/
export interface EISBackendRejectUpdateParams {
/**
* Info PK
*/
infoId: number;
/**
* Daten
*/
infoDTO: InfoDTO;
/**
* Lokalisierung
*/
locale?: null | string;
}
/**
* Parameters for EISBackendUpdateInfo
*/

View File

@@ -10,7 +10,7 @@
<ng-container *ngFor="let week of weeks$ | async">
<div class="cell cell-first cell-calendar-week center">KW {{ week.week }}</div>
<div class="cell cell-calendar-day center" [uiCalendarCell]="date" *ngFor="let date of week.dates" (click)="selectDate(date)">
<div class="day center">{{ date | date: 'dd' }}</div>
<div class="day center">{{ date | date: 'd' }}</div>
<div class="indicators">
<div
class="indicator"

View File

@@ -46,6 +46,6 @@
}
}
.invisible {
visibility: hidden;
.faded {
@apply text-disabled-branch;
}

View File

@@ -1,4 +1,4 @@
import { AfterViewInit, Directive, ElementRef, HostBinding, Input, Renderer2, Self } from '@angular/core';
import { Directive, HostBinding, Input } from '@angular/core';
import { DateAdapter } from '@ui/common';
import { UiCalendarComponent } from '../ui-calendar.component';
@@ -17,12 +17,12 @@ export class UiCalendarCellDirective {
return this.date && this.dateAdapter.equals(this.date, this.calendar.selected);
}
@HostBinding('class.invisible')
get isInvisible() {
@HostBinding('class.faded')
get isFaded() {
if (this.date && this.calendar.mode === 'month') {
const firstDateOfMonth = this.dateAdapter.getFirstDateOfMonth(this.calendar.displayed);
const lastDateOfMonth = this.dateAdapter.getLastDateOfMonth(this.calendar.displayed);
return firstDateOfMonth > this.date || this.date > lastDateOfMonth;
return firstDateOfMonth > this.date || this.date > lastDateOfMonth || this.date.getDay() === 0;
}
return false;
}

View File

@@ -5,13 +5,14 @@ import { UiClickOutsideDirective } from './click-outside.directive';
import { UiFocusDirective } from './focus';
import { IsInViewportDirective } from './is-in-viewport.directive';
import { GroupByPipe } from './pipes/group-by.pipe';
import { ReplacePipe } from './pipes/replace.pipe';
import { StripHtmlTagsPipe } from './pipes/strip-html-tags.pipe';
import { SubstrPipe } from './pipes/substr.pipe';
import { SkeletonLoaderComponent } from './skeleton-loader';
const components = [SkeletonLoaderComponent];
const directives = [UiClickOutsideDirective, IsInViewportDirective, BlobImageDirective, UiAutofocusDirective, UiFocusDirective];
const pipes = [StripHtmlTagsPipe, SubstrPipe, GroupByPipe];
const pipes = [StripHtmlTagsPipe, SubstrPipe, GroupByPipe, ReplacePipe];
@NgModule({
imports: [],
exports: [...components, ...directives, ...pipes],

View File

@@ -0,0 +1,10 @@
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'replace',
})
export class ReplacePipe implements PipeTransform {
transform(value: string, replaceStr: string = '', replaceWith: string = ''): string {
return value?.replace(replaceStr, replaceWith);
}
}

View File

@@ -6,7 +6,16 @@
<ui-icon class="r90deg" size="14px" icon="arrow_head"></ui-icon>
</button>
</ui-spinner>
<input #quantity class="current-quantity" type="number" *ngIf="customInput" placeholder="..." />
<input
#quantity
class="current-quantity"
[(ngModel)]="quantityInputValue"
type="number"
[min]="minQuantity"
[max]="range"
*ngIf="customInput"
placeholder="..."
/>
<div class="quantity-list" *ngIf="showDropdown">
<button *ngIf="showTrash" class="quantity-list-item del" type="button" (click)="close()">
<ui-icon size="20px" icon="trash"></ui-icon>
@@ -25,6 +34,12 @@
</button>
</div>
</div>
<button *ngIf="!!customInput" class="action" type="button" (click)="setQuantity(+quantityInput?.nativeElement?.value)">
<button
*ngIf="!!customInput"
class="action"
[disabled]="!quantityInputValue || quantityInputValue < minQuantity || quantityInputValue > range"
type="button"
(click)="setQuantity(quantityInputValue)"
>
Aktualisieren
</button>

View File

@@ -16,6 +16,10 @@
button.action {
@apply bg-white text-brand font-bold text-base outline-none border-none;
&:disabled {
@apply text-inactive-customer;
}
}
button.current-quantity {
@@ -61,3 +65,7 @@ input.current-quantity {
.r-90deg {
@apply transform -rotate-90 text-ucla-blue;
}
::ng-deep .branch ui-quantity-dropdown button.action:disabled {
@apply text-inactive-branch;
}

View File

@@ -26,13 +26,16 @@ export class QuantityDropdownComponent implements ControlValueAccessor, OnInit {
@Input()
quantity: number;
@Input()
minQuantity: number = 1;
showDropdown = false;
customInput = false;
@Input()
disabled: boolean;
@Input() range?: number;
@Input() range?: number = 999;
rangeArray: Array<number>;
@Input() showTrash = true;
@@ -40,6 +43,8 @@ export class QuantityDropdownComponent implements ControlValueAccessor, OnInit {
@Input()
showSpinner: boolean;
quantityInputValue: number;
onChange = (_: number) => {};
onTouched = () => {};

View File

@@ -1,12 +1,13 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { UiIconModule } from '@ui/icon';
import { UiSpinnerModule } from 'apps/ui/spinner/src/lib/ui-spinner.module';
import { QuantityDropdownComponent } from './quantity-dropdown.component';
@NgModule({
declarations: [QuantityDropdownComponent],
imports: [CommonModule, UiIconModule, UiSpinnerModule],
imports: [CommonModule, UiIconModule, UiSpinnerModule, FormsModule],
exports: [QuantityDropdownComponent],
})
export class UiQuantityDropdownModule {}

302
package-lock.json generated
View File

File diff suppressed because it is too large Load Diff