mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-31 09:37:15 +01:00
Merged PR 247: #264 Bearbeiten Detail Seite + Various Bug Fixes
Related work items: #264
This commit is contained in:
@@ -1,37 +1,22 @@
|
||||
<div class="filter-wrapper">
|
||||
<div class="filter-nav">
|
||||
<button
|
||||
*ngFor="let filter of value; trackBy: trackByKeyOrName; let first = first"
|
||||
type="button"
|
||||
(click)="selected = filter"
|
||||
class="isa-btn isa-btn-block isa-btn-default isa-btn-l"
|
||||
[class.customer]="module === 'Customer'"
|
||||
[class.isa-mt-10]="!first"
|
||||
[class.is-active]="filter === selected"
|
||||
[class.isa-font-weight-emphasis]="filter !== selected"
|
||||
[class.isa-font-weight-bold]="filter === selected"
|
||||
>
|
||||
<button *ngFor="let filter of value; trackBy: trackByKeyOrName; let first = first" type="button"
|
||||
(click)="selected = filter" class="isa-btn isa-btn-block isa-btn-default-bg isa-btn-large"
|
||||
[class.customer]="module === 'Customer'" [class.isa-mt-10]="!first" [class.is-active]="filter === selected"
|
||||
[class.isa-font-weight-emphasis]="filter !== selected" [class.isa-font-weight-bold]="filter === selected">
|
||||
<span>{{ filter.name }}</span>
|
||||
<lib-icon
|
||||
[name]="
|
||||
<lib-icon [name]="
|
||||
filter === selected
|
||||
? 'Arrow_Next_Dark'
|
||||
: module === 'Customer'
|
||||
? 'Arrow_Next'
|
||||
: 'Arrow_Next_Grey'
|
||||
"
|
||||
height="17px"
|
||||
></lib-icon>
|
||||
" height="17px"></lib-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div class="filter-content isa-ml-10" [ngSwitch]="selected?.type">
|
||||
<app-select-filter
|
||||
*ngSwitchCase="'select'"
|
||||
[options]="selected.options"
|
||||
[module]="module"
|
||||
[max]="selected.max"
|
||||
(optionsChanged)="emitOnChange($event)"
|
||||
>
|
||||
<app-select-filter *ngSwitchCase="'select'" [options]="selected.options" [module]="module" [max]="selected.max"
|
||||
(optionsChanged)="emitOnChange($event)">
|
||||
</app-select-filter>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
<button
|
||||
*ngIf="canScroll"
|
||||
class="scroll-btn isa-btn isa-btn-circle isa-btn-default"
|
||||
class="scroll-btn isa-btn isa-btn-circle isa-btn-default-bg"
|
||||
[class.up]="scrollPositionPersantage >= 20"
|
||||
[class.down]="scrollPositionPersantage < 20"
|
||||
[class.no-shadow]="module === 'Customer'"
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
// start:ng42.barrel
|
||||
export * from './shelf-edit-actions.component';
|
||||
export * from './shelf-edit-actions.module';
|
||||
// end:ng42.barrel
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<div class="actions">
|
||||
<button (click)="cancel.emit()"
|
||||
class="isa-btn isa-btn-pill isa-btn-secondary isa-btn-shadow isa-btn-red-border isa-btn-medium">
|
||||
Abbrechen</button><button (click)="save.emit()"
|
||||
class="isa-btn isa-btn-pill isa-btn-primary isa-btn-shadow isa-btn-medium" [disabled]="disabled">
|
||||
Speichern
|
||||
</button>
|
||||
</div>
|
||||
@@ -0,0 +1,16 @@
|
||||
:host {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
& > .isa-btn {
|
||||
margin: 0 31px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import {
|
||||
Component,
|
||||
ChangeDetectionStrategy,
|
||||
Output,
|
||||
EventEmitter,
|
||||
Input,
|
||||
} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-shelf-edit-actions',
|
||||
templateUrl: 'shelf-edit-actions.component.html',
|
||||
styleUrls: ['./shelf-edit-actions.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ShelfEditActionsComponent {
|
||||
@Input() disabled = false;
|
||||
|
||||
@Output() save = new EventEmitter<void>();
|
||||
@Output() cancel = new EventEmitter<void>();
|
||||
|
||||
constructor() {}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ShelfEditActionsComponent } from './shelf-edit-actions.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule],
|
||||
exports: [ShelfEditActionsComponent],
|
||||
declarations: [ShelfEditActionsComponent],
|
||||
providers: [],
|
||||
})
|
||||
export class ShelfEditActionsModule {}
|
||||
@@ -0,0 +1,67 @@
|
||||
<ng-container *ngIf="orderItemForm">
|
||||
<app-shelf-edit-order-item-header
|
||||
[src]="orderItemForm.get('ean')?.value | createImageSourceFromEan"
|
||||
[title]="orderItemForm.get('title')?.value"
|
||||
(expand)="expandGroup($event)"
|
||||
[isOpen]="isGroupOpen"
|
||||
>
|
||||
</app-shelf-edit-order-item-header>
|
||||
|
||||
<hr class="isa-content-spacer last" />
|
||||
<form [formGroup]="orderItemForm" *ngIf="isGroupOpen">
|
||||
<app-ui-text-input
|
||||
formControlName="quantity"
|
||||
label="Menge"
|
||||
suffix="x"
|
||||
></app-ui-text-input>
|
||||
<hr class="isa-content-spacer" />
|
||||
|
||||
<app-ui-text-input
|
||||
formControlName="price"
|
||||
label="Preis"
|
||||
suffix="EUR"
|
||||
></app-ui-text-input>
|
||||
<hr class="isa-content-spacer" />
|
||||
|
||||
<app-ui-text-input
|
||||
formControlName="ean"
|
||||
label="ISBN/EAN"
|
||||
></app-ui-text-input>
|
||||
<hr class="isa-content-spacer" />
|
||||
|
||||
<app-ui-text-input
|
||||
formControlName="targetBranch"
|
||||
label="Zielfiliale"
|
||||
></app-ui-text-input>
|
||||
<hr class="isa-content-spacer" />
|
||||
|
||||
<app-ui-text-input
|
||||
formControlName="supplier"
|
||||
label="Lieferant"
|
||||
></app-ui-text-input>
|
||||
<hr class="isa-content-spacer" />
|
||||
|
||||
<app-ui-text-input
|
||||
formControlName="ssc"
|
||||
label="Meldenummer"
|
||||
></app-ui-text-input>
|
||||
<hr class="isa-content-spacer" />
|
||||
|
||||
<app-ui-select-input
|
||||
*ngIf="vatLabelPipe"
|
||||
formControlName="vat"
|
||||
[options]="vatOptions"
|
||||
[optionsPipe]="vatOptionsPipe"
|
||||
[labelPipe]="{ transform: vatLabelTransform }"
|
||||
[valuePipe]="valuePipe"
|
||||
label="MwSt"
|
||||
>
|
||||
</app-ui-select-input>
|
||||
<hr class="isa-content-spacer" />
|
||||
|
||||
<app-ui-text-input
|
||||
formControlName="comment"
|
||||
label="Anmerkung"
|
||||
></app-ui-text-input>
|
||||
</form>
|
||||
</ng-container>
|
||||
@@ -0,0 +1,35 @@
|
||||
import { ShelfEditOrderItemComponent } from '.';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { CreateImageSourceFromEanPipe } from '../../pipes';
|
||||
import { ShelfEditOrderItemHeaderComponent } from './header';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
|
||||
fdescribe('ShelfEditOrderItemComponent', () => {
|
||||
let fixture: ComponentFixture<ShelfEditOrderItemComponent>;
|
||||
let component: ShelfEditOrderItemComponent;
|
||||
|
||||
beforeEach(async () => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [CommonModule, ReactiveFormsModule],
|
||||
declarations: [
|
||||
ShelfEditOrderItemComponent,
|
||||
ShelfEditOrderItemHeaderComponent,
|
||||
CreateImageSourceFromEanPipe,
|
||||
],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ShelfEditOrderItemComponent);
|
||||
component = fixture.componentInstance;
|
||||
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(component instanceof ShelfEditOrderItemComponent).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,53 @@
|
||||
import {
|
||||
Component,
|
||||
ChangeDetectionStrategy,
|
||||
Input,
|
||||
OnInit,
|
||||
SimpleChanges,
|
||||
OnChanges,
|
||||
ChangeDetectorRef,
|
||||
SimpleChange,
|
||||
} from '@angular/core';
|
||||
import { FormGroup } from '@angular/forms';
|
||||
import { VATDTO } from '@swagger/oms';
|
||||
import { VatTypeToDisplayNamePipe } from '../../pipes/vat-type-to-display-name.pipe';
|
||||
import { VatDtoToVatValuePipe } from '../../pipes/vat-dto-to-vat-value.pipe';
|
||||
import { VatDtoToVatTypePipe } from '../../pipes/vat-dto-to-vat-type.pipe';
|
||||
|
||||
@Component({
|
||||
selector: 'app-shelf-edit-order-item',
|
||||
templateUrl: 'edit-order-item.component.html',
|
||||
styleUrls: ['./edit-order-item.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ShelfEditOrderItemComponent implements OnInit, OnChanges {
|
||||
@Input() orderItemForm: FormGroup;
|
||||
@Input() onlyChild: boolean;
|
||||
@Input() firstChild: boolean;
|
||||
@Input() vatOptions: VATDTO[];
|
||||
|
||||
vatLabelPipe: VatTypeToDisplayNamePipe;
|
||||
vatOptionsPipe = new VatDtoToVatValuePipe();
|
||||
valuePipe = new VatDtoToVatTypePipe();
|
||||
isGroupOpen: boolean;
|
||||
|
||||
vatLabelTransform = (value) => {
|
||||
return this.vatLabelPipe.transform(value, this.vatOptions);
|
||||
};
|
||||
|
||||
constructor() {}
|
||||
|
||||
ngOnChanges({ vatOptions }: SimpleChanges) {
|
||||
if (vatOptions.currentValue) {
|
||||
this.vatLabelPipe = new VatTypeToDisplayNamePipe();
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.isGroupOpen = this.onlyChild || this.firstChild;
|
||||
}
|
||||
|
||||
expandGroup(shouldExpand: boolean) {
|
||||
this.isGroupOpen = shouldExpand;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { IconModule } from '@libs/ui';
|
||||
import { UiTextInputModule } from '@isa-ui/text-input';
|
||||
import { ShelfEditOrderItemComponent } from './edit-order-item.component';
|
||||
import { ShelfEditOrderItemHeaderComponent } from './header';
|
||||
import { ShelfPipesModule } from '../../pipes';
|
||||
import { UiSelectInputModule } from '@isa-ui/select-input';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
ReactiveFormsModule,
|
||||
IconModule,
|
||||
UiTextInputModule,
|
||||
UiSelectInputModule,
|
||||
ShelfPipesModule,
|
||||
],
|
||||
exports: [ShelfEditOrderItemComponent, ShelfEditOrderItemHeaderComponent],
|
||||
declarations: [
|
||||
ShelfEditOrderItemComponent,
|
||||
ShelfEditOrderItemHeaderComponent,
|
||||
],
|
||||
providers: [],
|
||||
})
|
||||
export class ShelfEditOrderItemModule {}
|
||||
@@ -0,0 +1,24 @@
|
||||
<div class="header">
|
||||
<div>
|
||||
<img
|
||||
*ngIf="src"
|
||||
class="isa-thumbnail"
|
||||
[src]="src"
|
||||
alt="item.product.name"
|
||||
/>
|
||||
</div>
|
||||
<div class="title isa-font-weight-bold">{{ title }}</div>
|
||||
<div
|
||||
class="collapse"
|
||||
*ngIf="showCollapseArrow"
|
||||
(click)="expand.emit(!isOpen)"
|
||||
>
|
||||
<lib-icon
|
||||
class="isa-accordion-arrow"
|
||||
[class.arrow-up]="!isOpen"
|
||||
[class.arrow-down]="isOpen"
|
||||
name="Arrow_right"
|
||||
[height]="'16px'"
|
||||
></lib-icon>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,13 @@
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 30px 0;
|
||||
|
||||
.title {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.collapse {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import {
|
||||
Component,
|
||||
ChangeDetectionStrategy,
|
||||
Input,
|
||||
Output,
|
||||
EventEmitter,
|
||||
} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-shelf-edit-order-item-header',
|
||||
templateUrl: 'edit-order-item-header.component.html',
|
||||
styleUrls: ['./edit-order-item-header.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ShelfEditOrderItemHeaderComponent {
|
||||
@Input() showCollapseArrow = true;
|
||||
@Input() isOpen = false;
|
||||
|
||||
@Input() src: string;
|
||||
@Input() title: string;
|
||||
|
||||
@Output() expand = new EventEmitter<boolean>();
|
||||
|
||||
constructor() {}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// start:ng42.barrel
|
||||
export * from './edit-order-item-header.component';
|
||||
// end:ng42.barrel
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
// start:ng42.barrel
|
||||
export * from './edit-order-item.component';
|
||||
export * from './edit-order-item.module';
|
||||
// end:ng42.barrel
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { OrderItemProcessingStatusValue, EnvironmentChannel } from '@swagger/oms';
|
||||
import {
|
||||
OrderItemProcessingStatusValue,
|
||||
EnvironmentChannel,
|
||||
} from '@swagger/oms';
|
||||
|
||||
export interface OrderDetailsCardInput {
|
||||
firstName?: string;
|
||||
@@ -12,4 +15,5 @@ export interface OrderDetailsCardInput {
|
||||
pickupDeadline?: Date;
|
||||
compartmentCode?: string;
|
||||
compartmentInfo?: string;
|
||||
processingStatusDate?: Date;
|
||||
}
|
||||
|
||||
@@ -1,83 +1,173 @@
|
||||
<h2 class="isa-flex isa-justify-content-space-between">
|
||||
<span>{{ orderDetails?.firstName }} {{ orderDetails?.lastName }}</span>
|
||||
<span>{{ orderDetails?.compartmentCode }} {{ orderDetails?.compartmentInfo }}</span>
|
||||
<h2 class="isa-flex isa-justify-content-space-between">
|
||||
<span>{{ orderDetails?.firstName }} {{ orderDetails?.lastName }}</span>
|
||||
<span
|
||||
>{{ orderDetails?.compartmentCode }}
|
||||
{{ orderDetails?.compartmentInfo }}</span
|
||||
>
|
||||
</h2>
|
||||
<div class="isa-flex isa-justify-content-space-between">
|
||||
<div class="isa-flex isa-flex-direction-column">
|
||||
<div class="detail">
|
||||
<div class="name">Vorgang-ID</div>
|
||||
<div class="value">{{ orderDetails?.orderNumber }}</div>
|
||||
</div>
|
||||
<div class="detail">
|
||||
<div class="name">Bestelldatum</div>
|
||||
<div class="value">{{ orderDetails?.orderDate | date:'dd.MM.yy | HH:mm' }} Uhr</div>
|
||||
</div>
|
||||
<div class="detail">
|
||||
<div class="name">Bestellkanal</div>
|
||||
<div class="value">{{ orderDetails?.orderChannel | environmentChannel }}</div>
|
||||
</div>
|
||||
<div class="isa-flex isa-flex-direction-column">
|
||||
<div class="detail">
|
||||
<div class="name">Vorgang-ID</div>
|
||||
<div class="value">{{ orderDetails?.orderNumber }}</div>
|
||||
</div>
|
||||
<div class="isa-flex isa-flex-direction-column">
|
||||
<div class="detail">
|
||||
<div class="name">Kundennummer</div>
|
||||
<div class="value isa-text-right">{{ orderDetails?.customerNumber }}</div>
|
||||
</div>
|
||||
<div class="detail">
|
||||
<div class="name">Status</div>
|
||||
<div class="value">
|
||||
<button class="isa-btn isa-p-0 isa-btn-block isa-text-right" (click)="statusDropdown.toggle()">
|
||||
<lib-icon class="isa-mr-8" [ngClass]="icon"
|
||||
*ngIf="orderDetails?.processingStatus | processingStatus:'icon'; let icon" [name]="icon">
|
||||
</lib-icon>
|
||||
<strong>{{ orderDetails?.processingStatus | processingStatus }}</strong>
|
||||
<lib-icon class="dp-button-icon" [class.up]="statusDropdown.visible"
|
||||
[class.down]="!statusDropdown.visible" name="Arrow_right" [height]="'16px'"></lib-icon>
|
||||
</button>
|
||||
<app-ui-dropdown #statusDropdown [value]="orderDetails?.processingStatus"
|
||||
(valueChange)="changeProcessingStatus.emit($event)">
|
||||
<ng-container *ngFor="let status of processingKeys | keyvalue">
|
||||
<button appUiDropdownItem class="isa-btn isa-text-left isa-p-16" [value]="status.key"
|
||||
*ngIf="status.key !== orderDetails?.processingStatus">
|
||||
{{ status.value }}
|
||||
</button>
|
||||
</ng-container>
|
||||
</app-ui-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail" *ngIf="orderDetails?.processingStatus === 16 || orderDetails?.processingStatus === 8192">
|
||||
<div class="name">vsl. Lieferdatum</div>
|
||||
<div class="value">
|
||||
<button class="isa-btn isa-p-0 isa-btn-block isa-text-right" (click)="uiDatepicker.toggle()">
|
||||
<strong>
|
||||
{{ orderDetails?.estimatedShippingDate | date:'dd.MM.yy' }}
|
||||
</strong>
|
||||
<lib-icon class="dp-button-icon" [class.up]="uiDatepicker.opened"
|
||||
[class.down]="!uiDatepicker.opened" name="Arrow_right" [height]="'16px'"></lib-icon>
|
||||
</button>
|
||||
<app-ui-datepicker #uiDatepicker [right]="'-1rem'" [selected]="orderDetails?.estimatedShippingDate"
|
||||
(save)="changeEstimatedDeliveryDate.emit($event); uiDatepicker.close()">
|
||||
</app-ui-datepicker>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail" *ngIf="orderDetails?.processingStatus === 128">
|
||||
<div class="name">Abholfrist</div>
|
||||
<div class="value">
|
||||
<button class="isa-btn isa-p-0 isa-btn-block isa-text-right" (click)="deadlineDropdown.toggle()">
|
||||
<strong>
|
||||
{{ orderDetails?.pickupDeadline | date:'dd.MM.yy' }}
|
||||
</strong>
|
||||
<lib-icon class="dp-button-icon" [class.up]="deadlineDropdown.visible"
|
||||
[class.down]="!deadlineDropdown.visible" name="Arrow_right" [height]="'16px'"></lib-icon>
|
||||
</button>
|
||||
<app-ui-dropdown #deadlineDropdown [value]="orderDetails?.pickupDeadline"
|
||||
(valueChange)="changePickUpDeadline.emit($event)">
|
||||
<ng-container *ngFor="let dl of pickupDeadlines | keyvalue">
|
||||
<button appUiDropdownItem class="isa-btn isa-text-left isa-p-16" [value]="dl.value">
|
||||
{{ dl.key }}
|
||||
</button>
|
||||
</ng-container>
|
||||
</app-ui-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail">
|
||||
<div class="name">Bestelldatum</div>
|
||||
<div class="value">
|
||||
{{ orderDetails?.orderDate | date: 'dd.MM.yy | HH:mm' }} Uhr
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail">
|
||||
<div class="name">Bestellkanal</div>
|
||||
<div class="value">
|
||||
{{ orderDetails?.orderChannel | environmentChannel }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="isa-flex isa-flex-direction-column">
|
||||
<div class="detail">
|
||||
<div class="name">Kundennummer</div>
|
||||
<div class="value isa-text-right">{{ orderDetails?.customerNumber }}</div>
|
||||
</div>
|
||||
<div class="detail">
|
||||
<div class="name">Status</div>
|
||||
<div class="value">
|
||||
<button
|
||||
class="isa-btn isa-p-0 isa-btn-block isa-text-right"
|
||||
(click)="statusDropdown.toggle()"
|
||||
>
|
||||
<lib-icon
|
||||
class="isa-mr-8"
|
||||
[ngClass]="icon"
|
||||
*ngIf="
|
||||
orderDetails?.processingStatus | processingStatus: 'icon';
|
||||
let icon
|
||||
"
|
||||
[name]="icon"
|
||||
>
|
||||
</lib-icon>
|
||||
<strong>{{
|
||||
orderDetails?.processingStatus | processingStatus
|
||||
}}</strong>
|
||||
<lib-icon
|
||||
class="dp-button-icon"
|
||||
[class.up]="statusDropdown.visible"
|
||||
[class.down]="!statusDropdown.visible"
|
||||
name="Arrow_right"
|
||||
[height]="'16px'"
|
||||
></lib-icon>
|
||||
</button>
|
||||
<app-ui-dropdown
|
||||
#statusDropdown
|
||||
[value]="orderDetails?.processingStatus"
|
||||
(valueChange)="changeProcessingStatus.emit($event)"
|
||||
>
|
||||
<ng-container
|
||||
*ngFor="
|
||||
let status of processingKeys
|
||||
| keyvalue
|
||||
| processingStatusOptionsKeyValuePipe
|
||||
"
|
||||
>
|
||||
<button
|
||||
appUiDropdownItem
|
||||
class="isa-btn isa-text-left isa-p-16"
|
||||
[value]="status.key"
|
||||
*ngIf="status.key !== orderDetails?.processingStatus"
|
||||
>
|
||||
{{ status?.value?.value }}
|
||||
</button>
|
||||
</ng-container>
|
||||
</app-ui-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
<ng-container [ngSwitch]="orderDetails?.processingStatus">
|
||||
<ng-container *ngSwitchCase="16">
|
||||
<ng-container *ngTemplateOutlet="vslLieferdatum"></ng-container>
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="8192">
|
||||
<ng-container *ngTemplateOutlet="vslLieferdatum"></ng-container>
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="128">
|
||||
<ng-container *ngTemplateOutlet="abholfrist"></ng-container>
|
||||
</ng-container>
|
||||
<div class="detail" *ngSwitchDefault>
|
||||
<div class="name">Geändert</div>
|
||||
<div class="value isa-text-right">
|
||||
{{ orderDetails?.processingStatusDate | date: 'dd.MM.yy | HH:mm' }}
|
||||
Uhr
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-template #vslLieferdatum>
|
||||
<div class="detail">
|
||||
<div class="name">vsl. Lieferdatum</div>
|
||||
<div class="value">
|
||||
<button
|
||||
class="isa-btn isa-p-0 isa-btn-block isa-text-right"
|
||||
(click)="uiDatepicker.toggle()"
|
||||
>
|
||||
<strong>
|
||||
{{ orderDetails?.estimatedShippingDate | date: 'dd.MM.yy' }}
|
||||
</strong>
|
||||
<lib-icon
|
||||
class="dp-button-icon"
|
||||
[class.up]="uiDatepicker.opened"
|
||||
[class.down]="!uiDatepicker.opened"
|
||||
name="Arrow_right"
|
||||
[height]="'16px'"
|
||||
></lib-icon>
|
||||
</button>
|
||||
<app-ui-datepicker
|
||||
#uiDatepicker
|
||||
[right]="'-1rem'"
|
||||
[min]="minDate"
|
||||
[disabledDaysOfWeek]="[0]"
|
||||
[selected]="orderDetails?.estimatedShippingDate"
|
||||
(save)="changeEstimatedDeliveryDate.emit($event); uiDatepicker.close()"
|
||||
>
|
||||
</app-ui-datepicker>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #abholfrist>
|
||||
<div class="detail">
|
||||
<div class="name">Abholfrist</div>
|
||||
<div class="value">
|
||||
<button
|
||||
class="isa-btn isa-p-0 isa-btn-block isa-text-right"
|
||||
(click)="deadlineDropdown.toggle()"
|
||||
>
|
||||
<strong>
|
||||
{{ orderDetails?.pickupDeadline | date: 'dd.MM.yy' }}
|
||||
</strong>
|
||||
<lib-icon
|
||||
class="dp-button-icon"
|
||||
[class.up]="deadlineDropdown.visible"
|
||||
[class.down]="!deadlineDropdown.visible"
|
||||
name="Arrow_right"
|
||||
[height]="'16px'"
|
||||
></lib-icon>
|
||||
</button>
|
||||
<app-ui-dropdown
|
||||
#deadlineDropdown
|
||||
[value]="orderDetails?.pickupDeadline"
|
||||
(valueChange)="changePickUpDeadline.emit($event)"
|
||||
>
|
||||
<ng-container *ngFor="let dl of pickupDeadlines | keyvalue">
|
||||
<button
|
||||
appUiDropdownItem
|
||||
class="isa-btn isa-text-left isa-p-16"
|
||||
[value]="dl.value"
|
||||
>
|
||||
{{ dl.key }}
|
||||
</button>
|
||||
</ng-container>
|
||||
</app-ui-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
@@ -2,8 +2,7 @@ import { Component, OnInit, ChangeDetectionStrategy, Input, Output, EventEmitter
|
||||
import { OrderDetailsCardInput } from './order-details-card-input';
|
||||
import { ProcessingStatusNameMap } from '../../constants';
|
||||
import { OrderItemProcessingStatusValue } from '@swagger/oms';
|
||||
import { DetailsFacade } from '@shelf-store/details';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { DateAdapter } from '@isa-ui/core/date';
|
||||
|
||||
@Component({
|
||||
selector: 'app-shelf-order-details-card',
|
||||
@@ -12,6 +11,8 @@ import { map } from 'rxjs/operators';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ShelfOrderDetailsCardComponent implements OnInit {
|
||||
minDate = this.dateAdapter.addCalendarDays(new Date(), -1);
|
||||
|
||||
get processingKeys() {
|
||||
const copy = new Map(ProcessingStatusNameMap);
|
||||
|
||||
@@ -19,6 +20,9 @@ export class ShelfOrderDetailsCardComponent implements OnInit {
|
||||
if (this.orderDetails.processingStatus === 16 || this.orderDetails.processingStatus === 8192) {
|
||||
copy.delete(128);
|
||||
}
|
||||
if (this.orderDetails.processingStatus >= 0) {
|
||||
copy.delete(this.orderDetails.processingStatus);
|
||||
}
|
||||
}
|
||||
|
||||
return copy;
|
||||
@@ -56,7 +60,7 @@ export class ShelfOrderDetailsCardComponent implements OnInit {
|
||||
@Output()
|
||||
changePickUpDeadline = new EventEmitter<Date>();
|
||||
|
||||
constructor() {}
|
||||
constructor(private dateAdapter: DateAdapter<Date>) {}
|
||||
|
||||
ngOnInit() {}
|
||||
}
|
||||
|
||||
@@ -1,114 +1,114 @@
|
||||
<div class="wrapper">
|
||||
|
||||
<div class="product-image">
|
||||
<img class="thumbnail"
|
||||
src="https://produktbilder.ihugendubel.de/{{orderItemListItem?.product.ean}}.jpg?showDummy=true"
|
||||
alt="item.product.name">
|
||||
</div>
|
||||
<div class="product-details isa-flex-fill isa-flex isa-flex-row">
|
||||
<div class="isa-flex-fill">
|
||||
<h4 class="product-name">{{ orderItemListItem?.product?.name }}</h4>
|
||||
<h4 class="isa-mb-6 isa-mt-12">Bestellung</h4>
|
||||
<div class="detail">
|
||||
<div class="name">
|
||||
Format
|
||||
</div>
|
||||
<div class="value">
|
||||
{{ orderItemListItem?.product?.format }} {{ orderItemListItem?.product?.formatDetail }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail">
|
||||
<div class="name">
|
||||
Menge
|
||||
</div>
|
||||
<div class="value">
|
||||
<button class="isa-btn btn-quantity isa-text-left isa-p-0" [disabled]="!selectable"
|
||||
(click)="quantityDropdown.toggle()">
|
||||
{{ orderItemListItem?.quantity }}x
|
||||
|
||||
<lib-icon class="isa-ml-5" *ngIf="selectable" [class.up]="quantityDropdown.visible"
|
||||
[class.down]="!quantityDropdown.visible" name="Arrow_right" [height]="'16px'"></lib-icon>
|
||||
</button>
|
||||
<app-ui-dropdown #quantityDropdown [(ngModel)]="orderItemListItem.quantity"
|
||||
(ngModelChange)="quantityChange.emit($event);quantityDropdown.close()">
|
||||
<button appUiDropdownItem class="isa-btn isa-text-left isa-p-16"
|
||||
*ngFor="let val of dropdownValues" [value]="val">
|
||||
{{ val }}x
|
||||
</button>
|
||||
</app-ui-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail">
|
||||
<div class="name">
|
||||
Preis
|
||||
</div>
|
||||
<div class="value">
|
||||
{{ orderItemListItem?.price | currency:'EUR' }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail ">
|
||||
<div class="name">
|
||||
ISBN/EAN
|
||||
</div>
|
||||
<div class="value">
|
||||
{{ orderItemListItem?.product?.ean }}
|
||||
</div>
|
||||
</div>
|
||||
<ng-container *ngIf="more">
|
||||
<div class="detail ">
|
||||
<div class="name">
|
||||
Zielfiliale
|
||||
</div>
|
||||
<div class="value">
|
||||
{{ orderItemListItem?.targetBranch }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail ">
|
||||
<div class="name">
|
||||
Lieferant
|
||||
</div>
|
||||
<div class="value">
|
||||
{{ orderItemListItem?.supplier }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail ">
|
||||
<div class="name">
|
||||
Meldenummer
|
||||
</div>
|
||||
<div class="value">
|
||||
{{ orderItemListItem?.ssc }} - {{ orderItemListItem?.sscText }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail ">
|
||||
<div class="name">
|
||||
MwSt
|
||||
</div>
|
||||
<div class="value">
|
||||
{{ orderItemListItem['vatType'] | vatType }}
|
||||
</div>
|
||||
</div>
|
||||
<button class="isa-btn isa-btn-default isa-p-0 isa-flex isa-align-items-center" (click)="more = false">
|
||||
<lib-icon name="Arrow_back" height="15px" class="isa-flex isa-mr-5"></lib-icon>
|
||||
<strong>Weniger</strong>
|
||||
</button>
|
||||
</ng-container>
|
||||
<div class="product-image">
|
||||
<img class="thumbnail"
|
||||
src="https://produktbilder.ihugendubel.de/{{orderItemListItem?.product.ean}}.jpg?showDummy=true"
|
||||
alt="item.product.name">
|
||||
</div>
|
||||
<div class="product-details isa-flex-fill isa-flex isa-flex-row">
|
||||
<div class="isa-flex-fill">
|
||||
<h4 class="product-name">{{ orderItemListItem?.product?.name }}</h4>
|
||||
<h4 class="isa-mb-6 isa-mt-12">Bestellung</h4>
|
||||
<div class="detail">
|
||||
<div class="name">
|
||||
Format
|
||||
</div>
|
||||
<div class="isa-flex isa-flex-direction-column isa-justify-content-flex-end isa-text-right">
|
||||
<div class="isa-flex-fill"></div>
|
||||
<div *ngIf="selectable">
|
||||
<label class="checkbox-wrapper">
|
||||
<input type="checkbox" [ngModel]="selected" (ngModelChange)="selectedChange($event)">
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
<div class="value">
|
||||
{{ orderItemListItem?.product?.format }} {{ orderItemListItem?.product?.formatDetail }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail">
|
||||
<div class="name">
|
||||
Menge
|
||||
</div>
|
||||
<div class="value">
|
||||
<button class="isa-btn btn-quantity isa-text-left isa-p-0" [disabled]="!selectable"
|
||||
(click)="quantityDropdown.toggle()">
|
||||
{{ orderItemListItem?.quantity }}x
|
||||
|
||||
</div>
|
||||
<div class="isa-flex-fill"></div>
|
||||
<button class="isa-btn isa-btn-default isa-p-0 isa-flex isa-align-items-center" (click)="more = true"
|
||||
*ngIf="!more">
|
||||
<strong>Mehr</strong>
|
||||
<lib-icon name="Arrow_More" height="15px" class="isa-flex isa-ml-5"></lib-icon>
|
||||
<lib-icon class="isa-ml-5" *ngIf="selectable" [class.up]="quantityDropdown.visible"
|
||||
[class.down]="!quantityDropdown.visible" name="Arrow_right" [height]="'16px'"></lib-icon>
|
||||
</button>
|
||||
<app-ui-dropdown #quantityDropdown [(ngModel)]="orderItemListItem.quantity"
|
||||
(ngModelChange)="quantityChange.emit($event);quantityDropdown.close()">
|
||||
<button appUiDropdownItem class="isa-btn isa-text-left isa-p-16" *ngFor="let val of dropdownValues"
|
||||
[value]="val">
|
||||
{{ val }}x
|
||||
</button>
|
||||
</app-ui-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail">
|
||||
<div class="name">
|
||||
Preis
|
||||
</div>
|
||||
<div class="value">
|
||||
{{ orderItemListItem?.price | currency:'EUR' }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail ">
|
||||
<div class="name">
|
||||
ISBN/EAN
|
||||
</div>
|
||||
<div class="value">
|
||||
{{ orderItemListItem?.product?.ean }}
|
||||
</div>
|
||||
</div>
|
||||
<ng-container *ngIf="more">
|
||||
<div class="detail ">
|
||||
<div class="name">
|
||||
Zielfiliale
|
||||
</div>
|
||||
<div class="value">
|
||||
{{ orderItemListItem?.targetBranch }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail ">
|
||||
<div class="name">
|
||||
Lieferant
|
||||
</div>
|
||||
<div class="value">
|
||||
{{ orderItemListItem?.supplier }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail ">
|
||||
<div class="name">
|
||||
Meldenummer
|
||||
</div>
|
||||
<div class="value">
|
||||
{{ orderItemListItem?.ssc }} - {{ orderItemListItem?.sscText }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail ">
|
||||
<div class="name">
|
||||
MwSt
|
||||
</div>
|
||||
<div class="value">
|
||||
{{ orderItemListItem['vatType'] | vatType }}
|
||||
</div>
|
||||
</div>
|
||||
<button class="isa-btn isa-btn-default isa-p-0 isa-flex isa-align-items-center" (click)="more = false">
|
||||
<lib-icon name="Arrow_back" height="15px" class="isa-flex isa-mr-5"></lib-icon>
|
||||
<strong>Weniger</strong>
|
||||
</button>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="isa-flex isa-flex-direction-column isa-justify-content-flex-end isa-text-right">
|
||||
<div class="isa-flex-fill"></div>
|
||||
<div *ngIf="selectable">
|
||||
<label class="checkbox-wrapper">
|
||||
<input type="checkbox" [ngModel]="selected" (ngModelChange)="selectedChange($event)">
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
|
||||
</div>
|
||||
<div class="isa-flex-fill"></div>
|
||||
<button class="isa-btn isa-btn-default isa-p-0 isa-flex isa-align-items-center" (click)="more = true"
|
||||
*ngIf="!more">
|
||||
<strong>Mehr</strong>
|
||||
<lib-icon name="Arrow_More" height="15px" class="isa-flex isa-ml-5"></lib-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1,49 +1,76 @@
|
||||
<div class="tags" *ngIf="item.features?.prebooked">
|
||||
<lib-icon name="tag_icon_preorder" width="30px"></lib-icon>
|
||||
<div class="tags" *ngIf="item.features">
|
||||
<lib-icon
|
||||
*ngIf="item.features?.prebooked"
|
||||
name="tag_icon_preorder"
|
||||
height="48px"
|
||||
></lib-icon>
|
||||
</div>
|
||||
<div class="isa-text-right isa-mb-9" *ngIf="item.compartmentCode">
|
||||
<strong>{{ item.compartmentCode }} {{ item.compartmentInfo }} </strong>
|
||||
<div class="feature-spacing" *ngIf="item.features"></div>
|
||||
<div
|
||||
class="isa-text-right isa-mb-9 isa-font-size-24"
|
||||
*ngIf="item.compartmentCode && displayCompartmentCode"
|
||||
>
|
||||
<strong>{{ item.compartmentCode }} {{ item.compartmentInfo }} </strong>
|
||||
</div>
|
||||
<div class="paid isa-mt-9 isa-mb-9" *ngIf="item.features?.paid">
|
||||
<lib-icon height="24px" width="24px" name="Check_green_circle" class="isa-mr-10"></lib-icon>
|
||||
<strong> {{ item.features?.paid }} </strong>
|
||||
<lib-icon
|
||||
height="24px"
|
||||
width="24px"
|
||||
name="Check_green_circle"
|
||||
class="isa-mr-10"
|
||||
></lib-icon>
|
||||
<strong> {{ item.features?.paid }} </strong>
|
||||
</div>
|
||||
<div class="grid-container">
|
||||
<div class="cover">
|
||||
<img class="thumbnail" src="https://produktbilder.ihugendubel.de/{{item.product.ean}}.jpg?showDummy=true"
|
||||
alt="item.product.name">
|
||||
<div class="cover">
|
||||
<img
|
||||
class="thumbnail"
|
||||
src="https://produktbilder.ihugendubel.de/{{
|
||||
item.product.ean
|
||||
}}.jpg?showDummy=true"
|
||||
alt="item.product.name"
|
||||
/>
|
||||
</div>
|
||||
<div class="title">
|
||||
<strong class="product-name">
|
||||
{{ [item.product.contributors, item.product.name] | title }}</strong
|
||||
>
|
||||
<strong class="processing-status">
|
||||
<lib-icon
|
||||
class="isa-mr-9"
|
||||
*ngIf="item.processingStatus | processingStatus: 'icon'; let icon"
|
||||
[name]="icon"
|
||||
[ngClass]="icon"
|
||||
>
|
||||
</lib-icon>
|
||||
{{ item.processingStatus | processingStatus }}
|
||||
</strong>
|
||||
</div>
|
||||
<div class="details">
|
||||
<div class="item-type">
|
||||
<lib-icon
|
||||
class="isa-mr-9"
|
||||
name="Icon_{{ item.product.format }}"
|
||||
></lib-icon>
|
||||
<strong>{{ item.product.formatDetail }}</strong>
|
||||
</div>
|
||||
<div class="title">
|
||||
<strong class="product-name"> {{ [ item.product.contributors, item.product.name] | title }}</strong>
|
||||
<strong class="processing-status">
|
||||
<lib-icon class="isa-mr-9" *ngIf="item.processingStatus | processingStatus:'icon'; let icon" [name]="icon"
|
||||
[ngClass]="icon">
|
||||
</lib-icon>
|
||||
{{ item.processingStatus | processingStatus }}
|
||||
</strong>
|
||||
<div class="order-date spec">
|
||||
<span>Bestelldatum</span>
|
||||
<strong>{{ item.orderDate | date }}</strong>
|
||||
</div>
|
||||
<div class="details">
|
||||
<div class="item-type">
|
||||
<lib-icon class="isa-mr-9" name="Icon_{{item.product.format}}"></lib-icon>
|
||||
<strong>{{ item.product.formatDetail }}</strong>
|
||||
</div>
|
||||
<div class="order-date spec">
|
||||
<span>Bestelldatum</span>
|
||||
<strong>{{ item.orderDate | date }}</strong>
|
||||
</div>
|
||||
<div class="item-number">
|
||||
<strong>{{ item.product.ean }}</strong>
|
||||
</div>
|
||||
<div class="quantity spec">
|
||||
<span>Menge</span>
|
||||
<strong>{{ item.quantity }}x</strong>
|
||||
</div>
|
||||
<div class="price">
|
||||
<strong>{{ item.price | currency:'EUR':'code' }}</strong>
|
||||
</div>
|
||||
<div class="target-branch spec">
|
||||
<span>Zielfiliale</span>
|
||||
<strong>{{ item.targetBranch }}</strong>
|
||||
</div>
|
||||
<div class="item-number">
|
||||
<strong>{{ item.product.ean }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
<div class="quantity spec">
|
||||
<span>Menge</span>
|
||||
<strong>{{ item.quantity }}x</strong>
|
||||
</div>
|
||||
<div class="price">
|
||||
<strong>{{ item.price | currency: 'EUR':'code' }}</strong>
|
||||
</div>
|
||||
<div class="target-branch spec">
|
||||
<span>Zielfiliale</span>
|
||||
<strong>{{ item.targetBranch }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -101,5 +101,9 @@
|
||||
.tags {
|
||||
position: absolute;
|
||||
top: -16px;
|
||||
right: 150px;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.feature-spacing {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import { Component, OnInit, ChangeDetectionStrategy, Input } from '@angular/core';
|
||||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
ChangeDetectionStrategy,
|
||||
Input,
|
||||
} from '@angular/core';
|
||||
import { OrderItemListItemDTO } from '@swagger/oms';
|
||||
|
||||
@Component({
|
||||
@@ -11,6 +16,9 @@ export class SearchResultGroupItemComponent implements OnInit {
|
||||
@Input()
|
||||
item: OrderItemListItemDTO;
|
||||
|
||||
@Input()
|
||||
displayCompartmentCode = true;
|
||||
|
||||
constructor() {}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
@@ -2,23 +2,38 @@
|
||||
<h3 class="heading">
|
||||
{{ group.items[0].firstName }} {{ group.items[0].lastName }}
|
||||
</h3>
|
||||
<ng-container *ngFor="
|
||||
<ng-container
|
||||
*ngFor="
|
||||
let byOrderNumber of group.items | groupBy: byOrderNumberFn;
|
||||
let lastOrder = last
|
||||
">
|
||||
<ng-container *ngFor="
|
||||
"
|
||||
>
|
||||
<ng-container
|
||||
*ngFor="
|
||||
let byProcessingStatus of byOrderNumber.items
|
||||
| groupBy: byProcessingStatusFn;
|
||||
let lastStatus = last
|
||||
">
|
||||
<ng-container *ngFor="
|
||||
"
|
||||
>
|
||||
<ng-container
|
||||
*ngFor="
|
||||
let groupedBy of byProcessingStatus.items
|
||||
| groupBy: byCompartmentCodeFn;
|
||||
let lastCompartment = last
|
||||
">
|
||||
"
|
||||
>
|
||||
<div class="isa-mb-12 isa-mt-12">
|
||||
<app-search-result-group-item *ngFor="let item of groupedBy.items; let lastItem = last" [item]="item"
|
||||
[class.group-item-bottom-space]="!lastItem" (click)="selectOrderItemListItem.emit(item)">
|
||||
<app-search-result-group-item
|
||||
*ngFor="
|
||||
let item of groupedBy.items;
|
||||
let firstItem = first;
|
||||
let lastItem = last
|
||||
"
|
||||
[item]="item"
|
||||
[class.group-item-bottom-space]="!lastItem"
|
||||
(click)="selectOrderItemListItem.emit(item)"
|
||||
[displayCompartmentCode]="firstItem"
|
||||
>
|
||||
</app-search-result-group-item>
|
||||
</div>
|
||||
<div class="divider" *ngIf="!lastCompartment"></div>
|
||||
@@ -27,4 +42,4 @@
|
||||
</ng-container>
|
||||
<div class="divider" *ngIf="!lastOrder"></div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
export const ProcessingStatusNameMap = new Map<number, string>([
|
||||
// [1, 'bestellt'],
|
||||
// [2, 'Placed'],
|
||||
// [4, 'Accepted'],
|
||||
// [8, 'Parked'],
|
||||
[16, 'bestellt'],
|
||||
// [32, 'Vorbereitung Versand'],
|
||||
[64, 'versendet'],
|
||||
[128, 'eingetroffen'],
|
||||
[256, 'abgeholt'],
|
||||
[512, 'storniert (Kunde)'],
|
||||
[1024, 'storniert'],
|
||||
[2048, 'storniert (Lieferant)'],
|
||||
// [4096, 'NotAvailable'],
|
||||
[8192, 'nachbestellt'],
|
||||
// [16384, 'ReturnedByBuyer'],
|
||||
// [32768, 'AvailableForDownload'],
|
||||
// [65536, 'Downloaded'],
|
||||
[131072, 'ans Lager (nicht abgeholt)'],
|
||||
// [262144, 'Zurück zum Lager'],
|
||||
[524288, 'angefragt'],
|
||||
[1048576, 'weitergeleitet intern'],
|
||||
// [2097152, 'Overdue'],
|
||||
[4194304, 'zugestellt'],
|
||||
[8388608, 'Lieferant wird ermittelt'],
|
||||
[16777216, 'derzeit nicht lieferbar'],
|
||||
[33554432, 'reserviert'],
|
||||
// [67108864, 'Assembled'],
|
||||
// [134217728, 'Packed'],
|
||||
export const ProcessingStatusNameMap = new Map<number, { value: string; disabled: boolean }>([
|
||||
[1, { value: 'neu', disabled: true }],
|
||||
[2, { value: '', disabled: true }],
|
||||
[4, { value: '', disabled: true }],
|
||||
[8, { value: 'geparkt', disabled: true }],
|
||||
[16, { value: 'bestellt', disabled: false }],
|
||||
[32, { value: 'Vorbereitung Versand', disabled: true }],
|
||||
[64, { value: 'versendet', disabled: false }],
|
||||
[128, { value: 'eingetroffen', disabled: false }],
|
||||
[256, { value: 'abgeholt', disabled: false }],
|
||||
[512, { value: 'storniert (Kunde)', disabled: false }],
|
||||
[1024, { value: 'storniert', disabled: false }],
|
||||
[2048, { value: 'storniert (Lieferant)', disabled: false }],
|
||||
[4096, { value: 'nicht lieferbar', disabled: false }],
|
||||
[8192, { value: 'nachbestellt', disabled: false }],
|
||||
[16384, { value: 'zurückgegeben', disabled: true }],
|
||||
[32768, { value: 'steht zum Download zur Verfügung', disabled: true }],
|
||||
[65536, { value: 'downloaded', disabled: true }],
|
||||
[131072, { value: 'nicht abgeholt', disabled: true }],
|
||||
[262144, { value: 'ans Lager (nicht abgeholt)', disabled: false }],
|
||||
[524288, { value: 'angefragt', disabled: false }],
|
||||
[1048576, { value: 'weitergeleitet intern', disabled: false }],
|
||||
[2097152, { value: 'überfällig', disabled: true }],
|
||||
[4194304, { value: 'zugestellt', disabled: false }],
|
||||
[8388608, { value: 'Lieferant ermittelt', disabled: false }],
|
||||
[16777216, { value: 'derzeit nicht lieferbar', disabled: false }],
|
||||
[33554432, { value: 'reserviert', disabled: true }],
|
||||
[67108864, { value: 'zusammengestellt', disabled: true }],
|
||||
[134217728, { value: 'verpackt', disabled: true }],
|
||||
]);
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
// start:ng42.barrel
|
||||
export * from './shelf-edit-compartment.component';
|
||||
export * from './shelf-edit-compartment.module';
|
||||
// end:ng42.barrel
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
<div class="wrapper">
|
||||
<div class="container layout-container">
|
||||
<div class="isa-form-header sticky header">
|
||||
{{ customerName?.firstName }} {{ customerName?.lastName }}
|
||||
<hr class="isa-content-spacer" />
|
||||
</div>
|
||||
<div class="layout-content">
|
||||
<ng-container *ngIf="form">
|
||||
<form [formGroup]="form">
|
||||
<app-ui-text-input
|
||||
formControlName="compartmentCode"
|
||||
label="Abholfachnummer"
|
||||
></app-ui-text-input>
|
||||
<hr class="isa-content-spacer" />
|
||||
|
||||
<app-ui-text-input
|
||||
formControlName="orderNumber"
|
||||
label="Vorgang-ID"
|
||||
></app-ui-text-input>
|
||||
<hr class="isa-content-spacer" />
|
||||
|
||||
<app-ui-text-input
|
||||
formControlName="orderDate"
|
||||
label="Bestelldatum"
|
||||
></app-ui-text-input>
|
||||
<hr class="isa-content-spacer" />
|
||||
|
||||
<app-ui-text-input
|
||||
formControlName="clientChannel"
|
||||
label="Bestellkanal"
|
||||
></app-ui-text-input>
|
||||
<hr class="isa-content-spacer" />
|
||||
|
||||
<app-ui-text-input
|
||||
formControlName="buyerNumber"
|
||||
label="Kundennummer"
|
||||
></app-ui-text-input>
|
||||
<hr class="isa-content-spacer" />
|
||||
|
||||
<app-ui-select-input
|
||||
formControlName="processingStatus"
|
||||
label="Status"
|
||||
[options]="
|
||||
formService.processingStatus | processingStatusOptionsPipe
|
||||
"
|
||||
[labelPipe]="processingStatusPipe"
|
||||
[optionsPipe]="processingStatusPipe"
|
||||
></app-ui-select-input>
|
||||
<hr class="isa-content-spacer" />
|
||||
|
||||
<ng-container
|
||||
*ngIf="
|
||||
+form.get('processingStatus').value === 16 ||
|
||||
+form.get('processingStatus').value === 8192
|
||||
"
|
||||
>
|
||||
<app-ui-select-input
|
||||
formControlName="estimatedShippingDate"
|
||||
label="Vsl. Lieferdatum"
|
||||
[options]="
|
||||
form.get('estimatedShippingDate').value | getExtendPickUpOptions
|
||||
"
|
||||
[labelPipe]="datePipe"
|
||||
[optionsPipe]="dateOptionsPipe"
|
||||
></app-ui-select-input>
|
||||
<hr class="isa-content-spacer" />
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="+form.get('processingStatus').value === 128">
|
||||
<app-ui-select-input
|
||||
formControlName="pickUpDeadline"
|
||||
label="Abholfrist"
|
||||
[options]="
|
||||
form.get('pickUpDeadline').value | getExtendPickUpOptions
|
||||
"
|
||||
[labelPipe]="datePipe"
|
||||
[optionsPipe]="dateOptionsPipe"
|
||||
></app-ui-select-input>
|
||||
<hr class="isa-content-spacer" />
|
||||
</ng-container>
|
||||
|
||||
<div formArrayName="items">
|
||||
<ng-container
|
||||
*ngFor="let item of items.controls; let index = index"
|
||||
>
|
||||
<app-shelf-edit-order-item
|
||||
[orderItemForm]="item"
|
||||
[onlyChild]="items.controls.length === 1"
|
||||
[firstChild]="index === 1"
|
||||
[vatOptions]="formService.vats$ | async"
|
||||
></app-shelf-edit-order-item>
|
||||
</ng-container>
|
||||
</div>
|
||||
</form>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="spacing"></div>
|
||||
</div>
|
||||
<app-shelf-edit-actions
|
||||
[disabled]="!form || !form.valid"
|
||||
(cancel)="onAbortEdit()"
|
||||
(save)="onSubmit()"
|
||||
>
|
||||
</app-shelf-edit-actions>
|
||||
</div>
|
||||
@@ -0,0 +1,31 @@
|
||||
@import 'variables';
|
||||
|
||||
.wrapper {
|
||||
overflow: scroll;
|
||||
height: 105%;
|
||||
background: $isa-branch-bg;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.container {
|
||||
.layout-content {
|
||||
margin-bottom: 0;
|
||||
padding: 0 0.3rem 0;
|
||||
}
|
||||
.header {
|
||||
//offset page layout padding
|
||||
padding: 20px 0.3rem 0 4%;
|
||||
position: sticky;
|
||||
background: inherit;
|
||||
top: -1px;
|
||||
|
||||
margin-bottom: 0;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
|
||||
.spacing {
|
||||
display: flex;
|
||||
height: 130px;
|
||||
background: $isa-branch-bg;
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
} from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { Observable, from } from 'rxjs';
|
||||
import {
|
||||
filter,
|
||||
map,
|
||||
distinctUntilChanged,
|
||||
shareReplay,
|
||||
take,
|
||||
withLatestFrom,
|
||||
first,
|
||||
} from 'rxjs/operators';
|
||||
import { isNullOrUndefined } from 'util';
|
||||
import { ShelfEditFormService } from '../../services';
|
||||
import { FormGroup, FormArray } from '@angular/forms';
|
||||
import {
|
||||
ProcessingStatusPipe,
|
||||
PickUpDateOptionsToDisplayValuesPipe,
|
||||
ProcessingStatusOptionsPipe,
|
||||
} from '../../pipes';
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { ShelfNavigationService } from '../../shared/services';
|
||||
import { OrderItemProcessingStatusValue } from '@swagger/oms/lib';
|
||||
|
||||
@Component({
|
||||
selector: 'app-shelf-edit-compartment',
|
||||
templateUrl: 'shelf-edit-compartment.component.html',
|
||||
styleUrls: ['./shelf-edit-compartment.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ShelfEditCompartmentComponent implements OnInit {
|
||||
// Form Information
|
||||
customerName: { firstName: string; lastName: string };
|
||||
form: FormGroup;
|
||||
items: FormArray;
|
||||
|
||||
// Pipes for Mapping Values to display names
|
||||
processingStatusPipe = new ProcessingStatusPipe();
|
||||
processingStatusOptionsPipe = new ProcessingStatusOptionsPipe();
|
||||
dateOptionsPipe = new PickUpDateOptionsToDisplayValuesPipe();
|
||||
datePipe = new DatePipe('de');
|
||||
|
||||
constructor(
|
||||
private activatedRoute: ActivatedRoute,
|
||||
protected formService: ShelfEditFormService,
|
||||
private shelfNavigationService: ShelfNavigationService,
|
||||
private cdr: ChangeDetectorRef
|
||||
) {}
|
||||
|
||||
get compartmentCode$(): Observable<string> {
|
||||
return this.activatedRoute.params.pipe(
|
||||
filter((params) => !isNullOrUndefined(params)),
|
||||
map((params) => params.compartmentCode),
|
||||
distinctUntilChanged(),
|
||||
shareReplay()
|
||||
);
|
||||
}
|
||||
|
||||
get processingStatus$() {
|
||||
return this.activatedRoute.params.pipe(
|
||||
map(
|
||||
(params) =>
|
||||
Number(params.processingStatus) as OrderItemProcessingStatusValue
|
||||
),
|
||||
distinctUntilChanged(),
|
||||
shareReplay()
|
||||
);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.loadCompartmentAndInitForm();
|
||||
}
|
||||
|
||||
async loadCompartmentAndInitForm() {
|
||||
const compartmentCode = await this.compartmentCode$
|
||||
.pipe(take(1))
|
||||
.toPromise();
|
||||
const processingStatus = await this.processingStatus$
|
||||
.pipe(take(1))
|
||||
.toPromise();
|
||||
|
||||
this.populateFormData(compartmentCode, processingStatus);
|
||||
}
|
||||
|
||||
async onSubmit() {
|
||||
console.log(this.form.valid);
|
||||
|
||||
const compartmentCode = await this.compartmentCode$
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
const processingStatus = await this.processingStatus$
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
const submitResult = await this.formService.submit(
|
||||
this.form,
|
||||
processingStatus
|
||||
);
|
||||
|
||||
let newValues;
|
||||
if (submitResult) {
|
||||
newValues = {
|
||||
compartmentCode:
|
||||
this.form.get('compartmentCode').value || compartmentCode,
|
||||
processingStatus:
|
||||
this.form.get('processingStatus').value || processingStatus,
|
||||
};
|
||||
|
||||
this.shelfNavigationService.navigateBackToDetails(newValues, {
|
||||
compartmentCode,
|
||||
processingStatus,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onAbortEdit() {
|
||||
return this.compartmentCode$
|
||||
.pipe(take(1), withLatestFrom(this.processingStatus$))
|
||||
.subscribe(([compartmentCode, processingStatus]) =>
|
||||
this.shelfNavigationService.navigateToDetails({
|
||||
compartmentCode,
|
||||
processingStatus,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private async populateFormData(
|
||||
compartmentCode: string,
|
||||
processingStatus: OrderItemProcessingStatusValue
|
||||
) {
|
||||
this.form = await this.formService.createFormByCompartmentCode(
|
||||
compartmentCode,
|
||||
processingStatus
|
||||
);
|
||||
this.items = this.formService.getItemsForm(compartmentCode);
|
||||
this.customerName = this.formService.getCustomerName(compartmentCode);
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { ShelfEditCompartmentComponent } from './shelf-edit-compartment.component';
|
||||
import { ShelfEditActionsModule } from '../../components/edit-actions';
|
||||
import { UiDropdownModule } from '@isa-ui/dropdown';
|
||||
import { UiTextInputModule } from '@isa-ui/text-input';
|
||||
import { UiSelectInputModule } from '@isa-ui/select-input';
|
||||
import { ShelfPipesModule } from '../../pipes';
|
||||
import { ShelfEditOrderItemModule } from '../../components/edit-order-item';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
ShelfEditActionsModule,
|
||||
ShelfEditOrderItemModule,
|
||||
UiDropdownModule,
|
||||
UiTextInputModule,
|
||||
UiSelectInputModule,
|
||||
ReactiveFormsModule,
|
||||
ShelfPipesModule,
|
||||
],
|
||||
exports: [ShelfEditCompartmentComponent],
|
||||
declarations: [ShelfEditCompartmentComponent],
|
||||
providers: [],
|
||||
})
|
||||
export class ShelfEditCompartmentModule {}
|
||||
@@ -0,0 +1,4 @@
|
||||
// start:ng42.barrel
|
||||
export * from './shelf-edit-order.component';
|
||||
// end:ng42.barrel
|
||||
|
||||
@@ -1,21 +1,104 @@
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<app-button (action)="done()" type="small">Fertig</app-button>
|
||||
</div>
|
||||
<div class="content" *ngIf="order && order.items">
|
||||
<app-order-overview-edit
|
||||
[_order]="order"
|
||||
(statusChanged)="statusChanged($event)"
|
||||
(compartmentCodeChanged)="compartmentCodeChanged($event)"
|
||||
[compartmentCode]="type === 'c' ? compartmentCode : ''"
|
||||
></app-order-overview-edit>
|
||||
<app-order-item-edit
|
||||
*ngFor="let item of order.items"
|
||||
[orderItem]="item.data"
|
||||
[logistician]="order.logistician"
|
||||
[clientChannel]="order.clientChannel"
|
||||
[targetBranch]="order.targetBranch"
|
||||
[multi]="multi"
|
||||
></app-order-item-edit>
|
||||
<div class="wrapper">
|
||||
<div class="container layout-container">
|
||||
<div class="isa-form-header sticky header">
|
||||
{{ customerName?.firstName }} {{ customerName?.lastName }}
|
||||
<hr class="isa-content-spacer" />
|
||||
</div>
|
||||
<div class="layout-content">
|
||||
<ng-container *ngIf="form">
|
||||
<form [formGroup]="form">
|
||||
<app-ui-text-input
|
||||
formControlName="compartmentCode"
|
||||
label="Abholfachnummer"
|
||||
></app-ui-text-input>
|
||||
<hr class="isa-content-spacer" />
|
||||
|
||||
<app-ui-text-input
|
||||
formControlName="orderNumber"
|
||||
label="Vorgang-ID"
|
||||
></app-ui-text-input>
|
||||
<hr class="isa-content-spacer" />
|
||||
|
||||
<app-ui-text-input
|
||||
formControlName="orderDate"
|
||||
label="Bestelldatum"
|
||||
></app-ui-text-input>
|
||||
<hr class="isa-content-spacer" />
|
||||
|
||||
<app-ui-text-input
|
||||
formControlName="clientChannel"
|
||||
label="Bestellkanal"
|
||||
></app-ui-text-input>
|
||||
<hr class="isa-content-spacer" />
|
||||
|
||||
<app-ui-text-input
|
||||
formControlName="buyerNumber"
|
||||
label="Kundennummer"
|
||||
></app-ui-text-input>
|
||||
<hr class="isa-content-spacer" />
|
||||
|
||||
<app-ui-select-input
|
||||
formControlName="processingStatus"
|
||||
label="Status"
|
||||
[options]="
|
||||
formService.processingStatus | processingStatusOptionsPipe
|
||||
"
|
||||
[labelPipe]="processingStatusPipe"
|
||||
[optionsPipe]="processingStatusPipe"
|
||||
></app-ui-select-input>
|
||||
<hr class="isa-content-spacer" />
|
||||
|
||||
<ng-container
|
||||
*ngIf="
|
||||
+form.get('processingStatus').value === 16 ||
|
||||
+form.get('processingStatus').value === 8192
|
||||
"
|
||||
>
|
||||
<app-ui-select-input
|
||||
formControlName="estimatedShippingDate"
|
||||
label="Vsl. Lieferdatum"
|
||||
[options]="
|
||||
form.get('estimatedShippingDate').value | getExtendPickUpOptions
|
||||
"
|
||||
[labelPipe]="datePipe"
|
||||
[optionsPipe]="dateOptionsPipe"
|
||||
></app-ui-select-input>
|
||||
<hr class="isa-content-spacer" />
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="+form.get('processingStatus').value === 128">
|
||||
<app-ui-select-input
|
||||
formControlName="pickUpDeadline"
|
||||
label="Abholfrist"
|
||||
[options]="
|
||||
form.get('pickUpDeadline').value | getExtendPickUpOptions
|
||||
"
|
||||
[labelPipe]="datePipe"
|
||||
[optionsPipe]="dateOptionsPipe"
|
||||
></app-ui-select-input>
|
||||
<hr class="isa-content-spacer" />
|
||||
</ng-container>
|
||||
<div formArrayName="items">
|
||||
<ng-container
|
||||
*ngFor="let item of items.controls; let index = index"
|
||||
>
|
||||
<app-shelf-edit-order-item
|
||||
[orderItemForm]="item"
|
||||
[onlyChild]="items.controls.length === 1"
|
||||
[firstChild]="index === 0"
|
||||
[vatOptions]="formService.vats$ | async"
|
||||
></app-shelf-edit-order-item>
|
||||
</ng-container>
|
||||
</div>
|
||||
</form>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="spacing"></div>
|
||||
</div>
|
||||
<app-shelf-edit-actions
|
||||
[disabled]="!form || !form.valid"
|
||||
(cancel)="onAbortEdit()"
|
||||
(save)="onSubmit()"
|
||||
>
|
||||
</app-shelf-edit-actions>
|
||||
</div>
|
||||
|
||||
@@ -1,18 +1,31 @@
|
||||
.container {
|
||||
background-color: white;
|
||||
background-color: white;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0px 0px 10px 0px #dce2e9;
|
||||
height: calc(100% - 70px);
|
||||
margin-top: 10px;
|
||||
overflow-y: scroll;
|
||||
padding-top: 15px;
|
||||
scroll-behavior: smooth;
|
||||
@import 'variables';
|
||||
|
||||
.wrapper {
|
||||
overflow: scroll;
|
||||
height: 105%;
|
||||
background: $isa-branch-bg;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.container {
|
||||
.layout-content {
|
||||
margin-bottom: 0;
|
||||
padding: 0 0.3rem 0;
|
||||
}
|
||||
.header {
|
||||
margin-bottom: 10px;
|
||||
margin-right: 10px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
//offset page layout padding
|
||||
padding: 20px 0.3rem 0 4%;
|
||||
position: sticky;
|
||||
background: inherit;
|
||||
top: -1px;
|
||||
|
||||
margin-bottom: 0;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
|
||||
.spacing {
|
||||
display: flex;
|
||||
height: 130px;
|
||||
background: $isa-branch-bg;
|
||||
}
|
||||
|
||||
@@ -1,107 +1,136 @@
|
||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
import { Select, Store } from '@ngxs/store';
|
||||
import { CollectingShelfSelectors } from 'apps/sales/src/app/core/store/selectors/collecting-shelf.selector';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { OrderDTO } from '@swagger/oms';
|
||||
import { takeUntil, filter, take, map } from 'rxjs/operators';
|
||||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
} from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { FormGroup, FormArray } from '@angular/forms';
|
||||
import { ShelfEditFormService } from '../../services';
|
||||
import { ShelfNavigationService } from '../../shared/services';
|
||||
import {
|
||||
filter,
|
||||
map,
|
||||
distinctUntilChanged,
|
||||
shareReplay,
|
||||
take,
|
||||
withLatestFrom,
|
||||
first,
|
||||
} from 'rxjs/operators';
|
||||
import { isNullOrUndefined } from 'util';
|
||||
import { Router, ActivatedRoute, Params } from '@angular/router';
|
||||
import { ChangeCurrentRoute } from 'apps/sales/src/app/core/store/actions/process.actions';
|
||||
import { PopBreadcrumbsAfterCurrent } from 'apps/sales/src/app/core/store/actions/breadcrumb.actions';
|
||||
import { CollectingShelfService } from 'apps/sales/src/app/core/services/collecting-shelf.service';
|
||||
import { SetBranchProcessCurrentPath } from 'apps/sales/src/app/core/store/actions/branch-process.actions';
|
||||
|
||||
import {
|
||||
ProcessingStatusPipe,
|
||||
PickUpDateOptionsToDisplayValuesPipe,
|
||||
ProcessingStatusOptionsPipe,
|
||||
} from '../../pipes';
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { OrderItemProcessingStatusValue } from '@swagger/oms/lib';
|
||||
import { from } from 'rxjs';
|
||||
@Component({
|
||||
selector: 'app-shelf-edit-order',
|
||||
templateUrl: './shelf-edit-order.component.html',
|
||||
styleUrls: ['./shelf-edit-order.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ShelfEditOrderComponent implements OnInit, OnDestroy {
|
||||
@Select(CollectingShelfSelectors.getShelfEditOrder) order$: Observable<OrderDTO>;
|
||||
destroy$ = new Subject();
|
||||
order: OrderDTO;
|
||||
compartmentCode: string;
|
||||
type: string;
|
||||
status: string;
|
||||
orderId: number;
|
||||
origin: string;
|
||||
customerId: number;
|
||||
itemId: number;
|
||||
multi = false;
|
||||
constructor(private store: Store, private router: Router, private route: ActivatedRoute, private shelfService: CollectingShelfService) {}
|
||||
export class ShelfEditOrderComponent implements OnInit {
|
||||
// Form Information
|
||||
customerName: { firstName: string; lastName: string };
|
||||
form: FormGroup;
|
||||
items: FormArray;
|
||||
|
||||
// Pipes for Mapping Values to display names
|
||||
processingStatusPipe = new ProcessingStatusPipe();
|
||||
processingStatusOptionsPipe = new ProcessingStatusOptionsPipe();
|
||||
dateOptionsPipe = new PickUpDateOptionsToDisplayValuesPipe();
|
||||
datePipe = new DatePipe('de');
|
||||
|
||||
constructor(
|
||||
private activatedRoute: ActivatedRoute,
|
||||
protected formService: ShelfEditFormService,
|
||||
private shelfNavigationService: ShelfNavigationService,
|
||||
private cdr: ChangeDetectorRef
|
||||
) {}
|
||||
|
||||
get orderNumber$() {
|
||||
return this.activatedRoute.params.pipe(
|
||||
filter((params) => !isNullOrUndefined(params)),
|
||||
map((params) => params.orderNumber),
|
||||
distinctUntilChanged(),
|
||||
shareReplay()
|
||||
);
|
||||
}
|
||||
|
||||
get processingStatus$() {
|
||||
return this.activatedRoute.params.pipe(
|
||||
map(
|
||||
(params) =>
|
||||
Number(params.processingStatus) as OrderItemProcessingStatusValue
|
||||
),
|
||||
distinctUntilChanged(),
|
||||
shareReplay()
|
||||
);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.route.params.pipe(take(1)).subscribe(this.routeParamsSubscriber$);
|
||||
this.loadOrderNumberAndInitForm();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
async loadOrderNumberAndInitForm() {
|
||||
const orderNumber = await this.orderNumber$.pipe(take(1)).toPromise();
|
||||
const processingStatus = await this.processingStatus$
|
||||
.pipe(take(1))
|
||||
.toPromise();
|
||||
console.log('loadOrderNumberAndInitForm', {
|
||||
orderNumber,
|
||||
processingStatus,
|
||||
});
|
||||
this.populateFormData(orderNumber, processingStatus);
|
||||
}
|
||||
|
||||
routeParamsSubscriber$ = (params: Params) => {
|
||||
if (params['id'] && params['status'] && params['type'] && params['orderId'] && params['origin'] && params['customerId']) {
|
||||
this.status = params['status'];
|
||||
this.type = params['type'];
|
||||
this.compartmentCode = params['id'];
|
||||
this.orderId = params['orderId'];
|
||||
this.origin = params['origin'];
|
||||
this.customerId = params['customerId'];
|
||||
this.itemId = +params['itemId'];
|
||||
}
|
||||
async onSubmit() {
|
||||
const orderNumber = await this.orderNumber$.pipe(first()).toPromise();
|
||||
const processingStatus = await this.processingStatus$
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
|
||||
this.order$
|
||||
.pipe(
|
||||
takeUntil(this.destroy$),
|
||||
filter((data) => !isNullOrUndefined(data)),
|
||||
map((order) => ({
|
||||
...order,
|
||||
items:
|
||||
this.itemId === 0 || isNullOrUndefined(this.itemId)
|
||||
? order.items
|
||||
: order.items.filter((item) => item.data.subsetItems.some((subsetItem) => subsetItem.id === this.itemId)),
|
||||
}))
|
||||
)
|
||||
.subscribe(this.orderSubscriber$);
|
||||
};
|
||||
const submitResult = await this.formService.submit(
|
||||
this.form,
|
||||
processingStatus
|
||||
);
|
||||
|
||||
orderSubscriber$ = (order: OrderDTO) => {
|
||||
this.order = order;
|
||||
if (order.items && order.items && order.items.length > 1) {
|
||||
this.multi = true;
|
||||
} else {
|
||||
this.multi = false;
|
||||
}
|
||||
};
|
||||
|
||||
done() {
|
||||
if (this.compartmentCode || this.orderId) {
|
||||
if (this.origin === 'shelf') {
|
||||
const path = `/shelf/details/${this.compartmentCode ? this.compartmentCode : this.orderId}/${this.orderId}/${this.status}/${
|
||||
this.type
|
||||
}`;
|
||||
this.store.dispatch(new PopBreadcrumbsAfterCurrent(path));
|
||||
this.store.dispatch(new ChangeCurrentRoute(path, true));
|
||||
this.router.navigate([path]);
|
||||
}
|
||||
if (this.origin === 'customer') {
|
||||
const path = `/customer/${this.customerId}/order/${this.orderId}`;
|
||||
this.store.dispatch(new PopBreadcrumbsAfterCurrent(path));
|
||||
this.store.dispatch(new ChangeCurrentRoute(path, true));
|
||||
this.router.navigate([path]);
|
||||
}
|
||||
if (this.origin === 'goodsin') {
|
||||
const path = `/goodsin/details/${this.orderId}/${this.itemId}/${this.status}`;
|
||||
this.store.dispatch(new SetBranchProcessCurrentPath(path, true));
|
||||
this.router.navigate([path]);
|
||||
}
|
||||
if (submitResult) {
|
||||
this.shelfNavigationService.navigateBackToDetails({
|
||||
orderNumber,
|
||||
processingStatus:
|
||||
this.form.get('processingStatus').value || processingStatus,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
statusChanged(processingStatus: string) {
|
||||
this.status = processingStatus;
|
||||
onAbortEdit() {
|
||||
return this.orderNumber$
|
||||
.pipe(take(1), withLatestFrom(this.processingStatus$))
|
||||
|
||||
.subscribe(([orderNumber, processingStatus]) =>
|
||||
this.shelfNavigationService.navigateToDetails({
|
||||
orderNumber,
|
||||
processingStatus,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
compartmentCodeChanged(compartmentCode: string) {
|
||||
this.compartmentCode = compartmentCode;
|
||||
private async populateFormData(
|
||||
orderNumber: string,
|
||||
processingStatus: OrderItemProcessingStatusValue
|
||||
) {
|
||||
this.form = await this.formService.createFormByOrderNumber(
|
||||
orderNumber,
|
||||
processingStatus
|
||||
);
|
||||
console.log({ form: this.form });
|
||||
|
||||
this.items = this.formService.getItemsForm(orderNumber);
|
||||
this.customerName = this.formService.getCustomerName(orderNumber);
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { ShelfEditActionsModule } from '../../components/edit-actions';
|
||||
import { ShelfEditOrderComponent } from './shelf-edit-order.component';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ShelfEditOrderItemModule } from '../../components/edit-order-item';
|
||||
import { UiDropdownModule } from '@isa-ui/dropdown';
|
||||
import { UiTextInputModule } from '@isa-ui/text-input';
|
||||
import { UiSelectInputModule } from '@isa-ui/select-input';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { ShelfPipesModule } from '../../pipes';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
ShelfEditActionsModule,
|
||||
ShelfEditOrderItemModule,
|
||||
UiDropdownModule,
|
||||
UiTextInputModule,
|
||||
UiSelectInputModule,
|
||||
ReactiveFormsModule,
|
||||
ShelfPipesModule,
|
||||
],
|
||||
exports: [ShelfEditOrderComponent],
|
||||
declarations: [ShelfEditOrderComponent],
|
||||
providers: [],
|
||||
})
|
||||
export class ShelfEditOrderModule {}
|
||||
@@ -1,17 +1,11 @@
|
||||
<div class="header-container">
|
||||
<h2 class="headline isa-text-center isa-font-weight-bold">Historie</h2>
|
||||
<div class="content">
|
||||
<ng-template
|
||||
[ngTemplateOutlet]="headerTemplate || defaultHeaderTemplate"
|
||||
[ngTemplateOutletContext]="{ $implicit: orderItemSubsetId }"
|
||||
></ng-template>
|
||||
<app-shelf-order-details-card
|
||||
[orderDetails]="details$ | async"
|
||||
(changeEstimatedDeliveryDate)="updateEstimatedShippingDate($event)"
|
||||
(changePickUpDeadline)="changePickUpDate($event)"
|
||||
(changeProcessingStatus)="changeProcessingStatus($event)"
|
||||
></app-shelf-order-details-card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-template let-orderItemSubsetId #defaultHeaderTemplate>
|
||||
<p class="default-template">
|
||||
Es liegen keine Detailinformation zum Produkt (Bestell-Id:
|
||||
<span>{{ orderItemSubsetId }}</span
|
||||
>) vor.
|
||||
</p>
|
||||
</ng-template>
|
||||
|
||||
@@ -16,3 +16,7 @@
|
||||
.default-template {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.content {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -3,8 +3,17 @@ import {
|
||||
ChangeDetectionStrategy,
|
||||
Input,
|
||||
TemplateRef,
|
||||
OnInit,
|
||||
} from '@angular/core';
|
||||
import { HistoryStateFacade } from '@shelf-store/history';
|
||||
import { DetailsFacade } from '@shelf-store/details';
|
||||
import { OrderDetailsCardInput } from '../../../components/order-details-card';
|
||||
import {
|
||||
OrderItemListItemDTO,
|
||||
OrderItemProcessingStatusValue,
|
||||
} from '@swagger/oms/lib';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map, filter, shareReplay, take } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'app-shelf-history-header',
|
||||
@@ -12,13 +21,126 @@ import { HistoryStateFacade } from '@shelf-store/history';
|
||||
styleUrls: ['./history-header.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ShelfHistoryHeaderComponent {
|
||||
export class ShelfHistoryHeaderComponent implements OnInit {
|
||||
@Input() orderId: any;
|
||||
@Input() compartmentCode: string;
|
||||
@Input() orderItemId: number;
|
||||
@Input() orderItemSubsetId: number;
|
||||
@Input() headerTemplate: TemplateRef<any>;
|
||||
|
||||
constructor(private historyStateFacade: HistoryStateFacade) {}
|
||||
details$: Observable<OrderDetailsCardInput & { orderId: number }>;
|
||||
|
||||
orderItems$: Observable<OrderItemListItemDTO[]>;
|
||||
|
||||
constructor(
|
||||
private detailsFacade: DetailsFacade,
|
||||
private historyStateFacade: HistoryStateFacade,
|
||||
private detailsStoreFacade: DetailsFacade
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
if (this.compartmentCode) {
|
||||
this.orderItems$ = this.detailsFacade.getOrderItemsByCompartmentCode$(
|
||||
this.compartmentCode
|
||||
);
|
||||
} else if (this.orderId) {
|
||||
this.orderItems$ = this.detailsFacade.getOrderItemsByOrderNumber$(
|
||||
this.orderId
|
||||
);
|
||||
}
|
||||
|
||||
this.details$ = this.orderItems$.pipe(
|
||||
map((items) => {
|
||||
if (items.length > 0) {
|
||||
const item = items[0];
|
||||
return {
|
||||
firstName: item.firstName,
|
||||
lastName: item.lastName,
|
||||
customerNumber: item.buyerNumber,
|
||||
estimatedShippingDate: item.estimatedShippingDate
|
||||
? new Date(item.estimatedShippingDate)
|
||||
: undefined,
|
||||
orderDate: new Date(item.orderDate),
|
||||
orderNumber: item.orderNumber,
|
||||
processingStatus: item.processingStatus,
|
||||
processingStatusDate: new Date(item.processingStatusDate),
|
||||
orderChannel: item.clientChannel,
|
||||
compartmentCode: item.compartmentCode,
|
||||
compartmentInfo: item.compartmentInfo,
|
||||
pickupDeadline: new Date(item.pickUpDeadline),
|
||||
orderId: item.orderId,
|
||||
} as OrderDetailsCardInput & { orderId: number };
|
||||
}
|
||||
return undefined;
|
||||
}),
|
||||
filter((details) => !!details),
|
||||
shareReplay()
|
||||
);
|
||||
}
|
||||
|
||||
updateHistory() {
|
||||
this.historyStateFacade.reloadHistory(this.orderItemSubsetId);
|
||||
}
|
||||
|
||||
async updateEstimatedShippingDate(date: Date) {
|
||||
const orderId = await this.getOrderId();
|
||||
|
||||
await this.detailsStoreFacade.setEstimatedShippingDate({
|
||||
items: [
|
||||
{
|
||||
orderItemSubsetId: this.orderItemSubsetId,
|
||||
orderItemId: this.orderItemId,
|
||||
orderId: orderId,
|
||||
},
|
||||
],
|
||||
estimatedShippingDate: date,
|
||||
});
|
||||
|
||||
this.updateHistory();
|
||||
}
|
||||
|
||||
async changePickUpDate(date: Date) {
|
||||
const orderId = await this.getOrderId();
|
||||
|
||||
await this.detailsStoreFacade.setPickUpDeadline({
|
||||
items: [
|
||||
{
|
||||
orderItemSubsetId: this.orderItemSubsetId,
|
||||
orderItemId: this.orderItemId,
|
||||
orderId: orderId,
|
||||
},
|
||||
],
|
||||
pickUpDeadline: date,
|
||||
});
|
||||
|
||||
this.updateHistory();
|
||||
}
|
||||
|
||||
async changeProcessingStatus(
|
||||
processingStatus: OrderItemProcessingStatusValue
|
||||
) {
|
||||
const orderId = await this.getOrderId();
|
||||
|
||||
await this.detailsStoreFacade.changeStatus([
|
||||
{
|
||||
orderItemSubsetId: this.orderItemSubsetId,
|
||||
orderItemId: this.orderItemId,
|
||||
orderId,
|
||||
data: {
|
||||
processingStatus,
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
this.updateHistory();
|
||||
}
|
||||
|
||||
private async getOrderId() {
|
||||
return this.details$
|
||||
.pipe(
|
||||
map((details) => details.orderId),
|
||||
take(1)
|
||||
)
|
||||
.toPromise();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
<div class="layout-container">
|
||||
<div class="layout-content">
|
||||
<app-shelf-history-header
|
||||
[orderItemSubsetId]="orderItemSubsetId"
|
||||
></app-shelf-history-header>
|
||||
<app-shelf-history-header [orderItemSubsetId]="orderItemSubsetId" [orderId]="orderId" [orderItemId]="orderItemId"
|
||||
[compartmentCode]="compartmentCode"></app-shelf-history-header>
|
||||
|
||||
<hr class="isa-content-spacer" />
|
||||
|
||||
<app-shelf-history-log
|
||||
*ngFor="
|
||||
<app-shelf-history-log *ngFor="
|
||||
let history of history$ | async;
|
||||
let first = first;
|
||||
let last = last
|
||||
"
|
||||
[history]="history"
|
||||
[first]="first"
|
||||
[last]="last"
|
||||
></app-shelf-history-log>
|
||||
" [history]="history" [first]="first" [last]="last"></app-shelf-history-log>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,9 +1,4 @@
|
||||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
ChangeDetectionStrategy,
|
||||
Input,
|
||||
} from '@angular/core';
|
||||
import { Component, OnInit, ChangeDetectionStrategy, Input } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { HistoryDTO } from '@cmf/trade-api';
|
||||
import { HistoryStateFacade } from '@shelf-store/history';
|
||||
@@ -15,6 +10,9 @@ import { HistoryStateFacade } from '@shelf-store/history';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ShelfHistoryLogsComponent implements OnInit {
|
||||
@Input() orderId: number;
|
||||
@Input() compartmentCode: string;
|
||||
@Input() orderItemId: number;
|
||||
@Input() orderItemSubsetId: number;
|
||||
history$: Observable<HistoryDTO[]>;
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<app-shelf-history-logs
|
||||
*ngIf="(status$ | async) === 2; else loading"
|
||||
[orderItemSubsetId]="orderItemSubsetId$ | async"
|
||||
></app-shelf-history-logs>
|
||||
<app-shelf-history-logs *ngIf="(status$ | async) === 2; else loading" [orderItemSubsetId]="orderItemSubsetId$ | async"
|
||||
[orderId]="orderId$ | async" [compartmentCode]="compartmentCode$ | async" [orderItemId]="orderItemId$ | async">
|
||||
</app-shelf-history-logs>
|
||||
|
||||
<ng-template #loading>
|
||||
<div class="spinner"></div>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
shareReplay,
|
||||
} from 'rxjs/operators';
|
||||
import { isNullOrUndefined } from 'util';
|
||||
import { HistoryDTO } from '@cmf/trade-api';
|
||||
import { HistoryStateFacade } from '@shelf-store/history';
|
||||
import { OrderHistoryStatus } from '@shelf-store/defs';
|
||||
|
||||
@@ -22,6 +21,9 @@ import { OrderHistoryStatus } from '@shelf-store/defs';
|
||||
})
|
||||
export class ShelfHistoryComponent implements OnInit {
|
||||
status$: Observable<OrderHistoryStatus>;
|
||||
orderId$: Observable<number>;
|
||||
compartmentCode$: Observable<string>;
|
||||
orderItemId$: Observable<number>;
|
||||
orderItemSubsetId$: Observable<number>;
|
||||
|
||||
constructor(
|
||||
@@ -32,6 +34,9 @@ export class ShelfHistoryComponent implements OnInit {
|
||||
ngOnInit() {
|
||||
this.status$ = this.getStatus();
|
||||
this.orderItemSubsetId$ = this.getOrderItemSubsetId$();
|
||||
this.orderId$ = this.getOrderId$();
|
||||
this.orderItemId$ = this.getOrderItemId$();
|
||||
this.compartmentCode$ = this.getCompartmentCode$();
|
||||
}
|
||||
|
||||
fetchHistory = (orderItemSubsetId: number) => {
|
||||
@@ -46,6 +51,34 @@ export class ShelfHistoryComponent implements OnInit {
|
||||
);
|
||||
}
|
||||
|
||||
getOrderId$(): Observable<number> {
|
||||
return this.activatedRoute.params.pipe(
|
||||
filter(
|
||||
(params) =>
|
||||
!isNullOrUndefined(params) && !isNullOrUndefined(params.orderId)
|
||||
),
|
||||
map((params) => params.orderId)
|
||||
);
|
||||
}
|
||||
|
||||
getCompartmentCode$(): Observable<string> {
|
||||
return this.activatedRoute.params.pipe(
|
||||
filter(
|
||||
(params) =>
|
||||
!isNullOrUndefined(params) &&
|
||||
!isNullOrUndefined(params.compartmentCode)
|
||||
),
|
||||
map((params) => params.compartmentCode)
|
||||
);
|
||||
}
|
||||
|
||||
getOrderItemId$(): Observable<number> {
|
||||
return this.activatedRoute.params.pipe(
|
||||
filter((params) => !isNullOrUndefined(params)),
|
||||
map((params) => Number(params.orderItemId))
|
||||
);
|
||||
}
|
||||
|
||||
getOrderItemSubsetId$(): Observable<number> {
|
||||
return this.activatedRoute.params.pipe(
|
||||
filter((params) => !isNullOrUndefined(params)),
|
||||
|
||||
@@ -5,21 +5,12 @@ import { ShelfHistoryComponent } from './shelf-history.component';
|
||||
import { ShelfHistoryLogsComponent } from './history-logs';
|
||||
import { FilterHistoriesWithStatusChangePipe } from './pipes';
|
||||
import { ShelfHistoryHeaderComponent } from './header';
|
||||
import { ShelfOrderDetailsCardModule } from '../../components/order-details-card';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, ShelfHistoryLogModule],
|
||||
exports: [
|
||||
ShelfHistoryComponent,
|
||||
ShelfHistoryHeaderComponent,
|
||||
ShelfHistoryLogsComponent,
|
||||
FilterHistoriesWithStatusChangePipe,
|
||||
],
|
||||
declarations: [
|
||||
ShelfHistoryComponent,
|
||||
ShelfHistoryHeaderComponent,
|
||||
ShelfHistoryLogsComponent,
|
||||
FilterHistoriesWithStatusChangePipe,
|
||||
],
|
||||
imports: [CommonModule, ShelfHistoryLogModule, ShelfOrderDetailsCardModule],
|
||||
exports: [ShelfHistoryComponent, ShelfHistoryHeaderComponent, ShelfHistoryLogsComponent, FilterHistoriesWithStatusChangePipe],
|
||||
declarations: [ShelfHistoryComponent, ShelfHistoryHeaderComponent, ShelfHistoryLogsComponent, FilterHistoriesWithStatusChangePipe],
|
||||
providers: [],
|
||||
})
|
||||
export class ShelfHistoryModule {}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Component, ChangeDetectionStrategy, Input } from '@angular/core';
|
||||
import { CustomerService } from '@swagger/crm';
|
||||
import { ReplaySubject, of, NEVER } from 'rxjs';
|
||||
import { switchMap, catchError, map, flatMap, filter, throttleTime, distinctUntilChanged } from 'rxjs/operators';
|
||||
import { isNullOrUndefined } from 'util';
|
||||
|
||||
@Component({
|
||||
selector: 'app-shelf-details-customer-features',
|
||||
@@ -12,7 +13,9 @@ import { switchMap, catchError, map, flatMap, filter, throttleTime, distinctUnti
|
||||
export class CustomerFeaturesComponent {
|
||||
@Input()
|
||||
set customerNumber(value: string) {
|
||||
this.customernumber$.next(value);
|
||||
if (!isNullOrUndefined(value)) {
|
||||
this.customernumber$.next(value);
|
||||
}
|
||||
}
|
||||
|
||||
customernumber$ = new ReplaySubject<string>();
|
||||
|
||||
@@ -1,84 +1,156 @@
|
||||
<div class="isa-card isa-border-bottom-radius-0">
|
||||
<div class="isa-flex isa-align-items-center isa-justify-content-space-between">
|
||||
<app-shelf-details-customer-features [customerNumber]="(orderDetailsCard$ | async)?.customerNumber">
|
||||
</app-shelf-details-customer-features>
|
||||
<button type="button" class="isa-btn isa-btn-secondary isa-mr-n10"
|
||||
(click)="navigateToDetails()">Bearbeiten</button>
|
||||
</div>
|
||||
<app-shelf-order-details-card [orderDetails]="orderDetailsCard$ | async"
|
||||
(changeEstimatedDeliveryDate)="changeEstimatedShippingDate($event)"
|
||||
(changeProcessingStatus)="changeProcessingStatus($event)" (changePickUpDeadline)="changePickupDeadline($event)">
|
||||
</app-shelf-order-details-card>
|
||||
<div class="isa-flex isa-flex-direction-row-reverse isa-mb-n10" *ngIf="partialPickup">
|
||||
<div class="isa-flex isa-flex-direction-column" *ngIf="orderItems$ | async; let orderItems">
|
||||
<button type="button" class="isa-btn isa-btn-secondary isa-mr-n10 isa-mb-7" (click)="selectAllForPickUp()"
|
||||
*ngIf="orderItems.length !== selectedForPartialPickup.size">Alle auswählen</button>
|
||||
<button type="button" class="isa-btn isa-btn-secondary isa-mr-n10 isa-mb-7" (click)="unselectAllForPickUp()"
|
||||
*ngIf="orderItems.length === selectedForPartialPickup.size">Alle entfernen</button>
|
||||
<span class="isa-text-right">
|
||||
{{ selectedForPartialPickup.size }} von {{ orderItems?.length }} Titel
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="isa-flex isa-align-items-center isa-justify-content-space-between"
|
||||
>
|
||||
<app-shelf-details-customer-features
|
||||
[customerNumber]="(orderDetailsCard$ | async)?.customerNumber"
|
||||
>
|
||||
</app-shelf-details-customer-features>
|
||||
<button
|
||||
type="button"
|
||||
class="isa-btn isa-btn-secondary isa-mr-n10"
|
||||
(click)="navigateToDetails()"
|
||||
>
|
||||
Bearbeiten
|
||||
</button>
|
||||
</div>
|
||||
<app-shelf-order-details-card
|
||||
[orderDetails]="orderDetailsCard$ | async"
|
||||
(changeEstimatedDeliveryDate)="changeEstimatedShippingDate($event)"
|
||||
(changeProcessingStatus)="changeProcessingStatus($event)"
|
||||
(changePickUpDeadline)="changePickupDeadline($event)"
|
||||
>
|
||||
</app-shelf-order-details-card>
|
||||
<div
|
||||
class="isa-flex isa-flex-direction-row-reverse isa-mb-n10"
|
||||
*ngIf="partialPickup"
|
||||
>
|
||||
<div
|
||||
class="isa-flex isa-flex-direction-column"
|
||||
*ngIf="orderItems$ | async; let orderItems"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="isa-btn isa-btn-secondary isa-mr-n10 isa-mb-7"
|
||||
(click)="selectAllForPickUp()"
|
||||
*ngIf="orderItems.length !== selectedForPartialPickup.size"
|
||||
>
|
||||
Alle auswählen
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="isa-btn isa-btn-secondary isa-mr-n10 isa-mb-7"
|
||||
(click)="unselectAllForPickUp()"
|
||||
*ngIf="orderItems.length === selectedForPartialPickup.size"
|
||||
>
|
||||
Alle entfernen
|
||||
</button>
|
||||
<span class="isa-text-right">
|
||||
{{ selectedForPartialPickup.size }} von {{ orderItems?.length }} Titel
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ng-container *ngFor="let orderItem of orderItems$ | async">
|
||||
<div class="isa-card isa-mt-2 isa-border-radius-0">
|
||||
<app-shelf-order-item-details [orderItemListItem]="orderItem" [selectable]="partialPickup"
|
||||
[selected]="selectedForPartialPickup.has(orderItem.orderItemId)"
|
||||
(select)="selectOrderItem(orderItem, $event)" (quantityChange)="setOrderItemQuanity(orderItem, $event)">
|
||||
</app-shelf-order-item-details>
|
||||
<div class="isa-flex isa-justify-content-flex-end isa-mt-7">
|
||||
<button class="isa-btn isa-btn-secondary isa-p-0" (click)="navigateToHistory(orderItem)">
|
||||
Historie
|
||||
</button>
|
||||
</div>
|
||||
<div class="isa-card isa-mt-2 isa-border-radius-0">
|
||||
<app-shelf-order-item-details
|
||||
[orderItemListItem]="orderItem"
|
||||
[selectable]="partialPickup"
|
||||
[selected]="selectedForPartialPickup.has(orderItem.orderItemId)"
|
||||
(select)="selectOrderItem(orderItem, $event)"
|
||||
(quantityChange)="setOrderItemQuanity(orderItem, $event)"
|
||||
>
|
||||
</app-shelf-order-item-details>
|
||||
<div class="isa-flex isa-justify-content-flex-end isa-mt-7">
|
||||
<button
|
||||
class="isa-btn isa-btn-secondary isa-p-0"
|
||||
(click)="navigateToHistory(orderItem)"
|
||||
>
|
||||
Historie
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="isa-card isa-mt-2 isa-border-radius-0" [class.isa-border-radius-0]="showArrivedAndPrintCta$ | async"
|
||||
[class.isa-border-top-radius-0]="(showArrivedAndPrintCta$ | async) === false">
|
||||
<app-shelf-order-details-comment [comment]="orderItem.specialComment"
|
||||
(saveComment)="saveComment(orderItem, $event)"></app-shelf-order-details-comment>
|
||||
</div>
|
||||
<div
|
||||
class="isa-card isa-mt-2 isa-border-radius-0"
|
||||
[class.isa-border-radius-0]="showArrivedAndPrintCta$ | async"
|
||||
[class.isa-border-top-radius-0]="
|
||||
(showArrivedAndPrintCta$ | async) === false
|
||||
"
|
||||
>
|
||||
<app-shelf-order-details-comment
|
||||
[comment]="orderItem.specialComment"
|
||||
(saveComment)="saveComment(orderItem, $event)"
|
||||
></app-shelf-order-details-comment>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<!-- CTAs für Bestellt -->
|
||||
<ng-container *ngIf="showArrivedAndPrintCta$ | async">
|
||||
<div class="isa-card isa-mt-2 isa-border-top-radius-0">
|
||||
<app-shelf-order-details-shelf-tags #shelfDetailsTag></app-shelf-order-details-shelf-tags>
|
||||
</div>
|
||||
<div class="isa-card isa-mt-2 isa-border-top-radius-0">
|
||||
<app-shelf-order-details-shelf-tags
|
||||
#shelfDetailsTag
|
||||
></app-shelf-order-details-shelf-tags>
|
||||
</div>
|
||||
|
||||
<div class="cta-sticky isa-my-28 isa-text-center">
|
||||
<button type="button" class="isa-btn isa-btn-primary isa-btn-pill isa-btn-medium"
|
||||
(click)="changeProcessingStatus(128, { compartmentInfo: shelfDetailsTag.selected })">
|
||||
eingetroffen und Drucken
|
||||
</button>
|
||||
</div>
|
||||
<div class="cta-sticky isa-my-28 isa-text-center">
|
||||
<button
|
||||
type="button"
|
||||
class="isa-btn isa-btn-primary isa-btn-pill isa-btn-medium"
|
||||
[disabled]="
|
||||
shelfDetailsTag.selected === shelfDetailsTag.customValue.value &&
|
||||
shelfDetailsTag.customValue.invalid
|
||||
"
|
||||
(click)="
|
||||
changeProcessingStatus(128, {
|
||||
compartmentInfo: shelfDetailsTag.selected
|
||||
})
|
||||
"
|
||||
>
|
||||
eingetroffen und Drucken
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<div class="cta-sticky isa-my-28 isa-text-center">
|
||||
<button *ngIf="(showPickUpPartialCollectCta$ | async) && !partialPickup" type="button"
|
||||
class="isa-btn isa-btn-outline-primary isa-btn-pill isa-btn-medium isa-mr-10" (click)="activatePartialPickup()">
|
||||
Teilabholung
|
||||
</button>
|
||||
<button *ngIf="showPickUpCta$ | async" type="button" class="isa-btn isa-btn-primary isa-btn-pill isa-btn-medium"
|
||||
(click)="changeProcessingStatus(256)">
|
||||
abgeholt
|
||||
</button>
|
||||
<!-- <button *ngIf="showAddToRemissionListCta$ | async" type="button"
|
||||
<button
|
||||
*ngIf="(showPickUpPartialCollectCta$ | async) && !partialPickup"
|
||||
type="button"
|
||||
class="isa-btn isa-btn-outline-primary isa-btn-pill isa-btn-medium isa-mr-10"
|
||||
(click)="activatePartialPickup()"
|
||||
>
|
||||
Teilabholung
|
||||
</button>
|
||||
<button
|
||||
*ngIf="showPickUpCta$ | async"
|
||||
type="button"
|
||||
class="isa-btn isa-btn-primary isa-btn-pill isa-btn-medium"
|
||||
(click)="changeProcessingStatus(256)"
|
||||
>
|
||||
abgeholt
|
||||
</button>
|
||||
<!-- <button *ngIf="showAddToRemissionListCta$ | async" type="button"
|
||||
class="isa-btn isa-btn-outline-primary isa-btn-pill isa-btn-medium isa-mr-10" (click)="addToRemissionList()">
|
||||
Remissionsliste hinzufügen
|
||||
</button> -->
|
||||
<button *ngIf="showBackToStoreCta$ | async" type="button"
|
||||
class="isa-btn isa-btn-primary isa-btn-pill isa-btn-medium" (click)="changeProcessingStatus(131072)">
|
||||
ans Lager
|
||||
</button>
|
||||
<button *ngIf="showReOrderCta$ | async" type="button" class="isa-btn isa-btn-primary isa-btn-pill isa-btn-medium"
|
||||
(click)="changeProcessingStatus(8192)">
|
||||
nachbestellen
|
||||
</button>
|
||||
<button
|
||||
*ngIf="showBackToStoreCta$ | async"
|
||||
type="button"
|
||||
class="isa-btn isa-btn-primary isa-btn-pill isa-btn-medium"
|
||||
(click)="changeProcessingStatus(262144)"
|
||||
>
|
||||
ans Lager
|
||||
</button>
|
||||
<button
|
||||
*ngIf="showReOrderCta$ | async"
|
||||
type="button"
|
||||
class="isa-btn isa-btn-primary isa-btn-pill isa-btn-medium"
|
||||
(click)="changeProcessingStatus(8192)"
|
||||
>
|
||||
nachbestellen
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="cta-spacer"></div>
|
||||
|
||||
<app-printer-selection></app-printer-selection>
|
||||
<app-printer-selection></app-printer-selection>
|
||||
|
||||
@@ -1,7 +1,18 @@
|
||||
import { ChangeDetectionStrategy, Component, ViewChild } from '@angular/core';
|
||||
import { DetailsFacade } from '@shelf-store/details';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { map, switchMap, first, filter, flatMap, distinctUntilChanged, shareReplay, tap, take, takeUntil } from 'rxjs/operators';
|
||||
import {
|
||||
map,
|
||||
switchMap,
|
||||
first,
|
||||
filter,
|
||||
flatMap,
|
||||
distinctUntilChanged,
|
||||
shareReplay,
|
||||
take,
|
||||
takeUntil,
|
||||
withLatestFrom,
|
||||
} from 'rxjs/operators';
|
||||
import { OrderDetailsCardInput } from '../../components/order-details-card';
|
||||
import {
|
||||
OrderItemProcessingStatusValue,
|
||||
@@ -10,11 +21,9 @@ import {
|
||||
ResponseArgsOfValueTupleOfOrderItemSubsetDTOAndOrderItemSubsetDTO,
|
||||
} from '@swagger/oms';
|
||||
import { ShelfNavigationService } from '../../shared/services';
|
||||
import { race, combineLatest, Observable } from 'rxjs';
|
||||
import { RemissionService } from '@isa/remission';
|
||||
import { ProcessingStatusNameMap } from '../../constants';
|
||||
import { race, combineLatest } from 'rxjs';
|
||||
import { AppService } from '@sales/core-services';
|
||||
import { OMSPrintService } from '@swagger/print';
|
||||
import { OMSPrintService, PrintService } from '@swagger/print';
|
||||
import { PrinterSelectionComponent } from 'apps/sales/src/app/components/printer-selection/printer-selection.component';
|
||||
|
||||
@Component({
|
||||
@@ -24,10 +33,15 @@ import { PrinterSelectionComponent } from 'apps/sales/src/app/components/printer
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ShelfOrderDetailsComponent {
|
||||
@ViewChild(PrinterSelectionComponent, { read: PrinterSelectionComponent, static: true })
|
||||
@ViewChild(PrinterSelectionComponent, {
|
||||
read: PrinterSelectionComponent,
|
||||
static: true,
|
||||
})
|
||||
printerSlectionComponent: PrinterSelectionComponent;
|
||||
|
||||
processingStatus$ = this.activatedRoute.params.pipe(map((params) => params['processingStatus']));
|
||||
processingStatus$ = this.activatedRoute.params.pipe(
|
||||
map((params) => params['processingStatus'])
|
||||
);
|
||||
|
||||
partialPickup = false;
|
||||
|
||||
@@ -48,14 +62,24 @@ export class ShelfOrderDetailsComponent {
|
||||
);
|
||||
|
||||
orderItems$ = race(
|
||||
this.orderNumber$.pipe(switchMap((orderNumber) => this.detailsFacade.getOrderItemsByOrderNumber$(orderNumber))),
|
||||
this.compartmentCode$.pipe(switchMap((compartmentCode) => this.detailsFacade.getOrderItemsByCompartmentCode$(compartmentCode)))
|
||||
this.orderNumber$.pipe(
|
||||
switchMap((orderNumber) =>
|
||||
this.detailsFacade.getOrderItemsByOrderNumber$(orderNumber)
|
||||
)
|
||||
),
|
||||
this.compartmentCode$.pipe(
|
||||
switchMap((compartmentCode) =>
|
||||
this.detailsFacade.getOrderItemsByCompartmentCode$(compartmentCode)
|
||||
)
|
||||
)
|
||||
).pipe(
|
||||
flatMap((items) =>
|
||||
this.processingStatus$.pipe(
|
||||
map((processingStatus) => {
|
||||
if (!!processingStatus) {
|
||||
return items.filter((item) => item.processingStatus === +processingStatus);
|
||||
return items.filter(
|
||||
(item) => item.processingStatus === +processingStatus
|
||||
);
|
||||
}
|
||||
return items;
|
||||
})
|
||||
@@ -72,10 +96,13 @@ export class ShelfOrderDetailsComponent {
|
||||
firstName: item.firstName,
|
||||
lastName: item.lastName,
|
||||
customerNumber: item.buyerNumber,
|
||||
estimatedShippingDate: item.estimatedShippingDate ? new Date(item.estimatedShippingDate) : undefined,
|
||||
estimatedShippingDate: item.estimatedShippingDate
|
||||
? new Date(item.estimatedShippingDate)
|
||||
: undefined,
|
||||
orderDate: new Date(item.orderDate),
|
||||
orderNumber: item.orderNumber,
|
||||
processingStatus: item.processingStatus,
|
||||
processingStatusDate: new Date(item.processingStatusDate),
|
||||
orderChannel: item.clientChannel,
|
||||
compartmentCode: item.compartmentCode,
|
||||
compartmentInfo: item.compartmentInfo,
|
||||
@@ -88,34 +115,52 @@ export class ShelfOrderDetailsComponent {
|
||||
);
|
||||
|
||||
showArrivedAndPrintCta$ = this.orderDetailsCard$.pipe(
|
||||
map((details) => details.processingStatus === 16 || details.processingStatus === 8192) // wenn bestellt(=16) oder nachbestellt(=8192)
|
||||
map(
|
||||
(details) =>
|
||||
details.processingStatus === 16 || details.processingStatus === 8192
|
||||
) // wenn bestellt(=16) oder nachbestellt(=8192)
|
||||
);
|
||||
|
||||
showPickUpCta$ = this.orderDetailsCard$.pipe(
|
||||
map((details) => details.processingStatus === 128) // wenn eingetroffen(=128)
|
||||
);
|
||||
|
||||
showPickUpPartialCollectCta$ = combineLatest([this.orderDetailsCard$, this.orderItems$]).pipe(
|
||||
showPickUpPartialCollectCta$ = combineLatest([
|
||||
this.orderDetailsCard$,
|
||||
this.orderItems$,
|
||||
]).pipe(
|
||||
map(([details, items]) => {
|
||||
return details.processingStatus === 128 && (items.length > 1 || items.some((i) => i.quantity > 1));
|
||||
return (
|
||||
details.processingStatus === 128 &&
|
||||
(items.length > 1 || items.some((i) => i.quantity > 1))
|
||||
);
|
||||
}) // wenn eingetroffen(=128) und mehr als 1 Artikel
|
||||
);
|
||||
|
||||
showBackToStoreCta$ = this.orderDetailsCard$.pipe(
|
||||
map((details) => details.processingStatus === 1024 || details.processingStatus === 512)
|
||||
map(
|
||||
(details) =>
|
||||
details.processingStatus === 1024 || details.processingStatus === 512
|
||||
)
|
||||
);
|
||||
|
||||
showAddToRemissionListCta$ = this.orderDetailsCard$.pipe(
|
||||
map((details) => details.processingStatus === 1024 || details.processingStatus === 512)
|
||||
map(
|
||||
(details) =>
|
||||
details.processingStatus === 1024 || details.processingStatus === 512
|
||||
)
|
||||
);
|
||||
|
||||
showReOrderCta$ = this.orderDetailsCard$.pipe(map((details) => details.processingStatus === 2048));
|
||||
showReOrderCta$ = this.orderDetailsCard$.pipe(
|
||||
map((details) => details.processingStatus === 2048)
|
||||
);
|
||||
|
||||
constructor(
|
||||
private activatedRoute: ActivatedRoute,
|
||||
private detailsFacade: DetailsFacade,
|
||||
private shelfNavigationService: ShelfNavigationService,
|
||||
private printService: OMSPrintService,
|
||||
private omsPrintService: OMSPrintService,
|
||||
private printerService: PrintService,
|
||||
private appService: AppService
|
||||
) {}
|
||||
|
||||
@@ -138,29 +183,43 @@ export class ShelfOrderDetailsComponent {
|
||||
});
|
||||
}
|
||||
|
||||
async changeProcessingStatus(status: OrderItemProcessingStatusValue, data: { compartmentInfo?: string } = {}) {
|
||||
async changeProcessingStatus(
|
||||
status: OrderItemProcessingStatusValue,
|
||||
data: { compartmentInfo?: string } = {}
|
||||
) {
|
||||
let items = await this.orderItems$.pipe(first()).toPromise();
|
||||
let results: ResponseArgsOfValueTupleOfOrderItemSubsetDTOAndOrderItemSubsetDTO[];
|
||||
const navigate = this.partialPickup ? items.length === this.selectedForPartialPickup.size : true;
|
||||
const navigate = this.partialPickup
|
||||
? items.length === this.selectedForPartialPickup.size
|
||||
: true;
|
||||
if (status === 256) {
|
||||
if (this.partialPickup) {
|
||||
items = items.filter(({ orderItemId }) => this.selectedForPartialPickup.has(orderItemId));
|
||||
items = items.filter(({ orderItemId }) =>
|
||||
this.selectedForPartialPickup.has(orderItemId)
|
||||
);
|
||||
}
|
||||
results = await this.detailsFacade.pickedUp(items, this.quantityForPartialPickup);
|
||||
} else if (status === 131072) {
|
||||
results = await this.detailsFacade.pickedUp(
|
||||
items,
|
||||
this.quantityForPartialPickup
|
||||
);
|
||||
} else if (status === 262144) {
|
||||
results = await this.detailsFacade.backToStock(items);
|
||||
} else if (status === 8192) {
|
||||
results = await this.detailsFacade.reorder(items);
|
||||
} else if (status === 128) {
|
||||
results = await this.detailsFacade.arrived(items, data.compartmentInfo);
|
||||
this.printAbholfachetikett(items.map(({ orderItemSubsetId }) => orderItemSubsetId));
|
||||
this.printAbholfachetikett(
|
||||
items.map(({ orderItemSubsetId }) => orderItemSubsetId)
|
||||
);
|
||||
} else {
|
||||
const payloads = items.map(({ orderId, orderItemId, orderItemSubsetId }) => ({
|
||||
orderId,
|
||||
orderItemId,
|
||||
orderItemSubsetId,
|
||||
data: { processingStatus: status } as StatusValues,
|
||||
}));
|
||||
const payloads = items.map(
|
||||
({ orderId, orderItemId, orderItemSubsetId }) => ({
|
||||
orderId,
|
||||
orderItemId,
|
||||
orderItemSubsetId,
|
||||
data: { processingStatus: status } as StatusValues,
|
||||
})
|
||||
);
|
||||
results = await this.detailsFacade.changeStatus(payloads);
|
||||
}
|
||||
|
||||
@@ -171,17 +230,27 @@ export class ShelfOrderDetailsComponent {
|
||||
if (navigate) {
|
||||
const firstItem = items[0];
|
||||
const firstResult = results[0].result;
|
||||
this.shelfNavigationService.updateDetailsNavigation({
|
||||
compartmentCode: firstResult.item1.compartmentCode,
|
||||
orderNumber: firstItem.orderNumber,
|
||||
processingStatus: firstResult.item1.processingStatus,
|
||||
});
|
||||
this.shelfNavigationService.updateDetails(
|
||||
{
|
||||
compartmentCode: firstResult.item1.compartmentCode,
|
||||
orderNumber: firstItem.orderNumber,
|
||||
processingStatus: firstResult.item1.processingStatus,
|
||||
},
|
||||
{
|
||||
compartmentCode: firstItem.compartmentCode,
|
||||
orderNumber: firstItem.orderNumber,
|
||||
processingStatus: firstItem.processingStatus,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
changeEstimatedShippingDate(estimatedShippingDate: Date | string) {
|
||||
this.orderItems$.pipe(first()).subscribe((items) => {
|
||||
this.detailsFacade.setEstimatedShippingDate({ items, estimatedShippingDate });
|
||||
this.detailsFacade.setEstimatedShippingDate({
|
||||
items,
|
||||
estimatedShippingDate,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -191,31 +260,68 @@ export class ShelfOrderDetailsComponent {
|
||||
});
|
||||
}
|
||||
|
||||
printAbholfachetikett(data: number[]) {
|
||||
async printAbholfachetikett(data: number[]) {
|
||||
// tslint:disable-next-line: no-shadowed-variable
|
||||
const print = (printer?: string) =>
|
||||
this.printService
|
||||
this.omsPrintService
|
||||
.OMSPrintAbholfachetikettResponse({
|
||||
data,
|
||||
printer,
|
||||
})
|
||||
.toPromise();
|
||||
|
||||
let printer: string;
|
||||
|
||||
if (this.appService.isIPadEnv()) {
|
||||
this.printerSlectionComponent.openDialog();
|
||||
this.printerSlectionComponent.print.pipe(takeUntil(this.printerSlectionComponent.closed), take(1)).subscribe((printer) => {
|
||||
print(printer);
|
||||
this.printerSlectionComponent.closeModal();
|
||||
});
|
||||
} else {
|
||||
print();
|
||||
printer = await this.printerSlectionComponent.print
|
||||
.pipe(takeUntil(this.printerSlectionComponent.closed), take(1))
|
||||
.toPromise();
|
||||
this.printerSlectionComponent.closeModal();
|
||||
}
|
||||
|
||||
if (!printer) {
|
||||
printer = await this.getDefaultPrinter();
|
||||
}
|
||||
|
||||
try {
|
||||
print(printer);
|
||||
} catch (error) {
|
||||
console.log('Printing Abholfachetikett Failed');
|
||||
}
|
||||
}
|
||||
|
||||
async getDefaultPrinter(): Promise<string> {
|
||||
const printers = await this.printerService.PrintLabelPrinters().toPromise();
|
||||
const selected = printers.result.find((f) => f.selected);
|
||||
|
||||
if (!!selected) {
|
||||
return selected.key;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
activatePartialPickup() {
|
||||
this.partialPickup = true;
|
||||
}
|
||||
|
||||
navigateToDetails() {}
|
||||
async navigateToDetails() {
|
||||
const data = await race(
|
||||
this.orderNumber$.pipe(map((orderNumber) => ({ orderNumber }))),
|
||||
this.compartmentCode$.pipe(
|
||||
map((compartmentCode) => ({ compartmentCode }))
|
||||
)
|
||||
)
|
||||
.pipe(
|
||||
withLatestFrom(this.processingStatus$),
|
||||
map(([d, processingStatus]) => ({ ...d, processingStatus })),
|
||||
first()
|
||||
)
|
||||
.toPromise();
|
||||
|
||||
this.shelfNavigationService.navigateToEdit(data);
|
||||
}
|
||||
|
||||
navigateToHistory(orderItem: OrderItemListItemDTO) {
|
||||
this.shelfNavigationService.navigateToHistory(orderItem);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Component, ChangeDetectionStrategy, Input, EventEmitter, Output, ChangeDetectorRef, OnInit, OnDestroy } from '@angular/core';
|
||||
import { FormControl } from '@angular/forms';
|
||||
import { FormControl, Validators } from '@angular/forms';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
@@ -19,7 +19,7 @@ export class ShelfOrderDetailsShelfTagsComponent implements OnInit, OnDestroy {
|
||||
@Input()
|
||||
tags = ['Maxi', 'Mini', 'Kleinkram', 'Nonbook'];
|
||||
|
||||
customValue = new FormControl('');
|
||||
customValue = new FormControl('', [Validators.required, Validators.maxLength(15)]);
|
||||
|
||||
subscription = new Subscription();
|
||||
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
import { Subject, fromEvent, combineLatest } from 'rxjs';
|
||||
|
||||
import { Component, OnDestroy, OnInit, ViewChild, ElementRef, ChangeDetectionStrategy } from '@angular/core';
|
||||
import {
|
||||
Component,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
ViewChild,
|
||||
ElementRef,
|
||||
ChangeDetectionStrategy,
|
||||
} from '@angular/core';
|
||||
import { SearchStateFacade } from 'apps/sales/src/app/store/customer';
|
||||
import { first, takeUntil, map } from 'rxjs/operators';
|
||||
import { groupBy } from 'apps/sales/src/app/utils';
|
||||
@@ -19,11 +26,16 @@ export class ShelfSearchResultsComponent implements OnInit, OnDestroy {
|
||||
|
||||
destroy$ = new Subject();
|
||||
|
||||
grouped$ = this.searchStateFacade.result$.pipe(map((results) => groupBy(results, (item) => (item ? item.buyerNumber : ''))));
|
||||
grouped$ = this.searchStateFacade.result$.pipe(
|
||||
map((results) => groupBy(results, (item) => (item ? item.buyerNumber : '')))
|
||||
);
|
||||
|
||||
fetching$ = this.searchStateFacade.fetching$;
|
||||
|
||||
constructor(private searchStateFacade: SearchStateFacade, private shelfNavigationService: ShelfNavigationService) {}
|
||||
constructor(
|
||||
private searchStateFacade: SearchStateFacade,
|
||||
private shelfNavigationService: ShelfNavigationService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.initScrollContainer();
|
||||
@@ -43,16 +55,25 @@ export class ShelfSearchResultsComponent implements OnInit, OnDestroy {
|
||||
|
||||
reachedBottom() {
|
||||
const scrollContainer: HTMLElement = this.scrollContainer.nativeElement;
|
||||
return scrollContainer.scrollHeight - (scrollContainer.scrollTop + scrollContainer.clientHeight) - 100 <= 0;
|
||||
return (
|
||||
scrollContainer.scrollHeight -
|
||||
(scrollContainer.scrollTop + scrollContainer.clientHeight) -
|
||||
100 <=
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
async fetch(force = false) {
|
||||
const [hits, result, fetching] = await combineLatest([this.searchStateFacade.hits$, this.searchStateFacade.result$, this.fetching$])
|
||||
const [hits, result, fetching] = await combineLatest([
|
||||
this.searchStateFacade.hits$,
|
||||
this.searchStateFacade.result$,
|
||||
this.fetching$,
|
||||
])
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
|
||||
if (force || !hits || (!result.length && !fetching)) {
|
||||
this.searchStateFacade.fetchResult();
|
||||
this.searchStateFacade.fetchResult({});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -275,6 +275,11 @@ export class ShelfSearchInputComponent
|
||||
take(1)
|
||||
)
|
||||
.subscribe(([_, numberOfHits, searchQuery, result]) => {
|
||||
this.shelfNavigationService.updateResultPageBreadcrumb({
|
||||
numberOfHits,
|
||||
searchQuery,
|
||||
});
|
||||
|
||||
if (this.shouldNavigateToResultList(numberOfHits)) {
|
||||
this.resetSessionStorage();
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import { CreateImageSourceFromEanPipe } from './generate-image-src-from-ean.pipe';
|
||||
|
||||
describe('Pipe: CreateImageSourceFromEanPipe', () => {
|
||||
let pipe: CreateImageSourceFromEanPipe;
|
||||
|
||||
const ean = '123456';
|
||||
|
||||
beforeEach(() => {
|
||||
pipe = new CreateImageSourceFromEanPipe();
|
||||
});
|
||||
|
||||
it('should return the image url for the provided ean', () => {
|
||||
const result = pipe.transform(ean);
|
||||
|
||||
expect(result).toEqual(
|
||||
`https://produktbilder.ihugendubel.de/${ean}.jpg?showDummy=true`
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,12 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
|
||||
@Pipe({
|
||||
name: 'createImageSourceFromEan',
|
||||
})
|
||||
export class CreateImageSourceFromEanPipe implements PipeTransform {
|
||||
transform(ean: string): string {
|
||||
return `https://produktbilder.ihugendubel.de/
|
||||
${ean}
|
||||
.jpg?showDummy=true`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
import { calculateExtendedPickUpDate } from '../shared/utils';
|
||||
|
||||
@Pipe({
|
||||
name: 'getExtendPickUpOptions',
|
||||
})
|
||||
export class GetExtendPickUpOptionsPipe implements PipeTransform {
|
||||
transform(pickUpDate: string): string[] {
|
||||
if (!pickUpDate) {
|
||||
return [];
|
||||
}
|
||||
return [
|
||||
calculateExtendedPickUpDate(pickUpDate, 2),
|
||||
calculateExtendedPickUpDate(pickUpDate, 4),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,11 @@
|
||||
// start:ng42.barrel
|
||||
export * from './environment-channel.pipe';
|
||||
export * from './generate-image-src-from-ean.pipe';
|
||||
export * from './get-extend-pick-up-date-options.pipe';
|
||||
export * from './pick-up-date-option-to-display-value.pipe';
|
||||
export * from './processing-status-options.pipe';
|
||||
export * from './processing-status.pipe';
|
||||
export * from './shelf-pipes.module';
|
||||
export * from './vat-dto-to-vat-value.pipe';
|
||||
export * from './vat-dto-to-vat-type.pipe';
|
||||
// end:ng42.barrel
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
|
||||
@Pipe({
|
||||
name: 'pickUpDateOptionsToDisplayValues',
|
||||
})
|
||||
export class PickUpDateOptionsToDisplayValuesPipe implements PipeTransform {
|
||||
transform(pickUpDate: string, index: number): string {
|
||||
if (!pickUpDate) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (index === 0) {
|
||||
return '2 Wochen verlängern';
|
||||
} else if (index === 1) {
|
||||
return '4 Wochen verlängern';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { ProcessingStatusOptionsPipe } from './processing-status-options.pipe';
|
||||
|
||||
fdescribe('ProcessingStatusOptionsPipe', () => {
|
||||
let pipe: ProcessingStatusOptionsPipe;
|
||||
|
||||
// activated code
|
||||
const bestelltStatuscode = 16;
|
||||
|
||||
// deactivated code
|
||||
const nachbestelltStatusCode = 8192;
|
||||
|
||||
beforeEach(() => {
|
||||
pipe = new ProcessingStatusOptionsPipe();
|
||||
});
|
||||
|
||||
it('should return bestellt (1)', () => {
|
||||
const result = pipe.transform([bestelltStatuscode, nachbestelltStatusCode]);
|
||||
|
||||
expect(result.length).toBe(1);
|
||||
expect(result).toEqual([bestelltStatuscode]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,47 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
import { ProcessingStatusNameMap } from '../constants';
|
||||
import { KeyValue } from '@angular/common';
|
||||
|
||||
@Pipe({
|
||||
name: 'processingStatusOptionsPipe',
|
||||
})
|
||||
export class ProcessingStatusOptionsPipe implements PipeTransform {
|
||||
transform(states: number[]): number[] {
|
||||
return states
|
||||
.filter((state) => {
|
||||
const result = ProcessingStatusNameMap.get(state);
|
||||
|
||||
if (!result || result.disabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
.sort((a, b) => {
|
||||
const aValue = ProcessingStatusNameMap.get(a);
|
||||
const bValue = ProcessingStatusNameMap.get(b);
|
||||
return aValue.value.toUpperCase() === bValue.value.toUpperCase()
|
||||
? 0
|
||||
: aValue.value.toUpperCase() > bValue.value.toUpperCase()
|
||||
? 1
|
||||
: -1;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Pipe({
|
||||
name: 'processingStatusOptionsKeyValuePipe',
|
||||
})
|
||||
export class ProcessingStatusOptionsKeyValuePipe implements PipeTransform {
|
||||
transform(states: KeyValue<number, { value: string; disabled: boolean }>[]): KeyValue<number, { value: string; disabled: boolean }>[] {
|
||||
return states
|
||||
.filter((state) => !state.value.disabled)
|
||||
.sort((a, b) => {
|
||||
return a.value.value.toUpperCase() === b.value.value.toUpperCase()
|
||||
? 0
|
||||
: a.value.value.toUpperCase() > b.value.value.toUpperCase()
|
||||
? 1
|
||||
: -1;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import { ProcessingStatusPipe } from './processing-status.pipe';
|
||||
import { OrderItemProcessingStatusValue } from '@swagger/oms/lib';
|
||||
|
||||
fdescribe('ProcessingStatusPipe', () => {
|
||||
let pipe: ProcessingStatusPipe;
|
||||
|
||||
beforeEach(() => {
|
||||
pipe = new ProcessingStatusPipe();
|
||||
});
|
||||
|
||||
it('should return the status name for status 16 (bestellt)', () => {
|
||||
const bestelltStatusCode = 16;
|
||||
const result = pipe.transform(bestelltStatusCode);
|
||||
|
||||
expect(result).toEqual('bestellt');
|
||||
});
|
||||
|
||||
it('should return an empty string if the status code is not found', () => {
|
||||
const notExistingStatusCode = 17;
|
||||
const result = pipe.transform(
|
||||
notExistingStatusCode as OrderItemProcessingStatusValue
|
||||
);
|
||||
|
||||
expect(result).toEqual('');
|
||||
});
|
||||
});
|
||||
@@ -1,42 +1,11 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
import { OrderItemProcessingStatusValue } from '@swagger/oms';
|
||||
import { ProcessingStatusNameMap } from '../constants';
|
||||
|
||||
@Pipe({
|
||||
name: 'processingStatus',
|
||||
})
|
||||
export class ProcessingStatusPipe implements PipeTransform {
|
||||
map = {
|
||||
0: '',
|
||||
1: 'bestellt',
|
||||
2: 'Placed',
|
||||
4: 'Accepted',
|
||||
8: 'Parked',
|
||||
16: 'bestellt',
|
||||
32: 'Vorbereitung Versand',
|
||||
64: 'versendet',
|
||||
128: 'eingetroffen',
|
||||
256: 'abgeholt',
|
||||
512: 'storniert (Kunde)',
|
||||
1024: 'storniert',
|
||||
2048: 'storniert (Lieferant)',
|
||||
4096: 'NotAvailable',
|
||||
8192: 'nachbestellt ',
|
||||
16384: 'ReturnedByBuyer',
|
||||
32768: 'AvailableForDownload',
|
||||
65536: 'Downloaded',
|
||||
131072: 'NotFetched',
|
||||
262144: 'Zurück zum Lager',
|
||||
524288: 'angefragt',
|
||||
1048576: 'RedirectedInternally',
|
||||
2097152: 'Overdue',
|
||||
4194304: 'Delivered',
|
||||
8388608: 'DetermineSupplier',
|
||||
16777216: 'SupplierTemporarilyOutOfStock',
|
||||
33554432: 'Reserved',
|
||||
67108864: 'Assembled',
|
||||
134217728: 'Packed',
|
||||
};
|
||||
|
||||
icon = {
|
||||
16: 'Check',
|
||||
128: 'Check',
|
||||
@@ -45,7 +14,14 @@ export class ProcessingStatusPipe implements PipeTransform {
|
||||
2048: 'close',
|
||||
};
|
||||
|
||||
transform(value: OrderItemProcessingStatusValue, type: 'icon' | 'text' = 'text'): string {
|
||||
return (type === 'icon' ? this.icon[value] : this.map[value]) || '';
|
||||
transform(
|
||||
value: OrderItemProcessingStatusValue,
|
||||
type: 'icon' | 'text' = 'text'
|
||||
): string {
|
||||
return type === 'icon'
|
||||
? this.icon[value]
|
||||
: ProcessingStatusNameMap.get(value)
|
||||
? ProcessingStatusNameMap.get(value).value
|
||||
: '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,42 @@ import { NgModule } from '@angular/core';
|
||||
import { ProcessingStatusPipe } from './processing-status.pipe';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { EnvironmentChannelPipe } from './environment-channel.pipe';
|
||||
import { GetExtendPickUpOptionsPipe } from './get-extend-pick-up-date-options.pipe';
|
||||
import { PickUpDateOptionsToDisplayValuesPipe } from './pick-up-date-option-to-display-value.pipe';
|
||||
import { CreateImageSourceFromEanPipe } from './generate-image-src-from-ean.pipe';
|
||||
import { VatDtoToVatValuePipe } from './vat-dto-to-vat-value.pipe';
|
||||
import { VatTypeToDisplayNamePipe } from './vat-type-to-display-name.pipe';
|
||||
import { VatDtoToVatTypePipe } from './vat-dto-to-vat-type.pipe';
|
||||
import { VatTypePipe } from './vat-type.pipe';
|
||||
import { ProcessingStatusOptionsPipe, ProcessingStatusOptionsKeyValuePipe } from './processing-status-options.pipe';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule],
|
||||
exports: [ProcessingStatusPipe, EnvironmentChannelPipe, VatTypePipe],
|
||||
declarations: [ProcessingStatusPipe, EnvironmentChannelPipe, VatTypePipe],
|
||||
providers: [],
|
||||
exports: [
|
||||
VatTypeToDisplayNamePipe,
|
||||
ProcessingStatusPipe,
|
||||
ProcessingStatusOptionsPipe,
|
||||
EnvironmentChannelPipe,
|
||||
GetExtendPickUpOptionsPipe,
|
||||
PickUpDateOptionsToDisplayValuesPipe,
|
||||
CreateImageSourceFromEanPipe,
|
||||
VatDtoToVatValuePipe,
|
||||
VatDtoToVatTypePipe,
|
||||
VatTypePipe,
|
||||
ProcessingStatusOptionsKeyValuePipe,
|
||||
],
|
||||
declarations: [
|
||||
VatTypeToDisplayNamePipe,
|
||||
ProcessingStatusPipe,
|
||||
ProcessingStatusOptionsPipe,
|
||||
EnvironmentChannelPipe,
|
||||
GetExtendPickUpOptionsPipe,
|
||||
PickUpDateOptionsToDisplayValuesPipe,
|
||||
CreateImageSourceFromEanPipe,
|
||||
VatDtoToVatValuePipe,
|
||||
VatDtoToVatTypePipe,
|
||||
VatTypePipe,
|
||||
ProcessingStatusOptionsKeyValuePipe,
|
||||
],
|
||||
})
|
||||
export class ShelfPipesModule {}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { VatDtoToVatTypePipe } from './vat-dto-to-vat-type.pipe';
|
||||
import { vatDtosMock } from '../shared/mockdata';
|
||||
|
||||
fdescribe('Pipe: VatDtoToVatTypePipe', () => {
|
||||
let pipe: VatDtoToVatTypePipe;
|
||||
|
||||
beforeEach(() => {
|
||||
pipe = new VatDtoToVatTypePipe();
|
||||
});
|
||||
|
||||
it('should return the vat type (8)', () => {
|
||||
const mock = vatDtosMock.find((vat) => vat.vatType === 8);
|
||||
|
||||
const result = pipe.transform(mock);
|
||||
expect(result).toBe(8);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
import { VATDTO } from '@swagger/checkout/lib';
|
||||
|
||||
@Pipe({
|
||||
name: 'vatDtoToVatType',
|
||||
})
|
||||
export class VatDtoToVatTypePipe implements PipeTransform {
|
||||
transform(vatDTO: VATDTO): number {
|
||||
return vatDTO.vatType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { VATDTO } from '@swagger/oms';
|
||||
import { VatDtoToVatValuePipe } from './vat-dto-to-vat-value.pipe';
|
||||
import { vatDtosMock } from '../shared/mockdata';
|
||||
|
||||
fdescribe('Pipe: VatDtoToVatValuePipe', () => {
|
||||
let pipe: VatDtoToVatValuePipe;
|
||||
|
||||
beforeEach(() => {
|
||||
pipe = new VatDtoToVatValuePipe();
|
||||
});
|
||||
|
||||
it('should return 5%', () => {
|
||||
const mock: VATDTO = vatDtosMock.find((vat) => vat.name === '5');
|
||||
const result = pipe.transform(mock);
|
||||
|
||||
const expected = '5%';
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
import { VATDTO } from '@swagger/oms';
|
||||
|
||||
@Pipe({
|
||||
name: 'vatDtoToVatValue',
|
||||
})
|
||||
export class VatDtoToVatValuePipe implements PipeTransform {
|
||||
transform(vatDTO: VATDTO): string {
|
||||
if (!vatDTO) {
|
||||
return;
|
||||
}
|
||||
return `${vatDTO.value.toFixed()}%`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { VatTypeToDisplayNamePipe } from './vat-type-to-display-name.pipe';
|
||||
import { vatDtosMock } from '../shared/mockdata';
|
||||
|
||||
fdescribe('Pipe: VatTypeToDisplayNamePipe', () => {
|
||||
let pipe: VatTypeToDisplayNamePipe;
|
||||
|
||||
beforeEach(() => {
|
||||
pipe = new VatTypeToDisplayNamePipe();
|
||||
});
|
||||
|
||||
it('should return 5%', () => {
|
||||
const mock = vatDtosMock.find((vat) => vat.name === '5').vatType;
|
||||
|
||||
const result = pipe.transform(mock, vatDtosMock);
|
||||
|
||||
const expected = '5%';
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
import { VatDtoToVatValuePipe } from './vat-dto-to-vat-value.pipe';
|
||||
import { VATDTO } from '@swagger/oms';
|
||||
|
||||
@Pipe({
|
||||
name: 'vatTypeToDisplayName',
|
||||
})
|
||||
export class VatTypeToDisplayNamePipe implements PipeTransform {
|
||||
constructor() {}
|
||||
|
||||
transform(vatType: number, vatOptions: VATDTO[]) {
|
||||
const match = vatOptions && vatOptions.find((vat) => vat.vatType === vatType);
|
||||
if (match) {
|
||||
return new VatDtoToVatValuePipe().transform(match);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Pipe, PipeTransform, ChangeDetectorRef, OnDestroy } from '@angular/core';
|
||||
import { Pipe, PipeTransform, ChangeDetectorRef, OnDestroy, Injectable } from '@angular/core';
|
||||
import { VATType } from '@swagger/oms';
|
||||
import { VatService } from '../../../core/services/vat.service';
|
||||
import { first, take, takeUntil } from 'rxjs/operators';
|
||||
import { take, takeUntil } from 'rxjs/operators';
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
@Pipe({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// start:ng42.barrel
|
||||
export * from './shelf-filter.service';
|
||||
export * from './shelf-overlay.service';
|
||||
export * from './shelf-edit-form.service';
|
||||
// end:ng42.barrel
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { ShelfEditFormService } from './shelf-edit-form.service';
|
||||
import { DetailsFacade } from '@shelf-store/details';
|
||||
|
||||
fdescribe('ShelfEditFormService', () => {
|
||||
let service: ShelfEditFormService;
|
||||
let facade: jasmine.SpyObj<DetailsFacade>;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [CommonModule, FormsModule, ReactiveFormsModule],
|
||||
providers: [
|
||||
ShelfEditFormService,
|
||||
{
|
||||
provide: DetailsFacade,
|
||||
useValue: jasmine.createSpy('detailsFacade'),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
service = TestBed.get(ShelfEditFormService);
|
||||
facade = TestBed.get(DetailsFacade);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service instanceof ShelfEditFormService).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,399 @@
|
||||
import { Injectable, ɵbypassSanitizationTrustResourceUrl } from '@angular/core';
|
||||
import {
|
||||
FormBuilder,
|
||||
FormGroup,
|
||||
Validators,
|
||||
FormArray,
|
||||
AbstractControl,
|
||||
} from '@angular/forms';
|
||||
import { Observable, of, from } from 'rxjs';
|
||||
import {
|
||||
OrderItemListItemDTO,
|
||||
VATDTO,
|
||||
OrderItemDTO,
|
||||
OrderItemProcessingStatusValue,
|
||||
StatusValues,
|
||||
EnvironmentChannel,
|
||||
VATType,
|
||||
OrderItemSubsetDTO,
|
||||
} from '@swagger/oms';
|
||||
import { DetailsFacade } from '@shelf-store/details';
|
||||
import { take, filter } from 'rxjs/operators';
|
||||
import { isNullOrUndefined } from 'util';
|
||||
import { EnvironmentChannelPipe } from '../pipes/environment-channel.pipe';
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { ProcessingStatusNameMap } from '../constants';
|
||||
import { Select } from '@ngxs/store';
|
||||
import { VatState } from '../../../core/store/state/vat.state';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ShelfEditFormService {
|
||||
@Select(VatState.getVats) vats$: Observable<VATDTO[]>;
|
||||
forms = new Map<string, FormGroup>();
|
||||
|
||||
public get processingStatus(): number[] {
|
||||
return Array.from(ProcessingStatusNameMap.keys());
|
||||
}
|
||||
|
||||
public get availableProcessingStatus(): number[] {
|
||||
return this.processingStatus.filter((status) => {
|
||||
const result = ProcessingStatusNameMap.get(status);
|
||||
if (!result || !result.disabled) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public get vatOptions$(): Observable<VATDTO[]> {
|
||||
return this.vats$.pipe(filter((vats) => !!vats.length));
|
||||
}
|
||||
|
||||
constructor(
|
||||
private formBuilder: FormBuilder,
|
||||
private detailsStoreFacade: DetailsFacade
|
||||
) {}
|
||||
|
||||
public getItemsForm(compartmentCode: string): FormArray {
|
||||
if (!this.forms.has(compartmentCode)) {
|
||||
return new FormArray([]);
|
||||
}
|
||||
return this.forms.get(compartmentCode).get('items') as FormArray;
|
||||
}
|
||||
|
||||
public getCustomerName(
|
||||
compartmentCode: string
|
||||
): { firstName: string; lastName: string } {
|
||||
if (!this.forms.has(compartmentCode)) {
|
||||
return {
|
||||
firstName: 'unbekannt',
|
||||
lastName: '',
|
||||
};
|
||||
}
|
||||
|
||||
const form = this.forms.get(compartmentCode);
|
||||
return {
|
||||
firstName: form.get('firstName').value || '',
|
||||
lastName: form.get('lastName').value || '',
|
||||
};
|
||||
}
|
||||
|
||||
async createFormByOrderNumber(
|
||||
orderNumber: string,
|
||||
processingStatus: OrderItemProcessingStatusValue
|
||||
): Promise<FormGroup> {
|
||||
const controlsConfig = await this.getControlsConfigForOrder(
|
||||
orderNumber,
|
||||
processingStatus
|
||||
);
|
||||
|
||||
const form = this.formBuilder.group(controlsConfig);
|
||||
this.forms.set(orderNumber, form);
|
||||
|
||||
return this.forms.get(orderNumber);
|
||||
}
|
||||
|
||||
async createFormByCompartmentCode(
|
||||
compartmentCode: string,
|
||||
processingStatus: OrderItemProcessingStatusValue
|
||||
): Promise<FormGroup> {
|
||||
const controlsConfig = await this.getControlsConfigForCompartment(
|
||||
compartmentCode,
|
||||
processingStatus
|
||||
);
|
||||
|
||||
const form = this.formBuilder.group(controlsConfig);
|
||||
this.forms.set(compartmentCode, form);
|
||||
|
||||
return this.forms.get(compartmentCode);
|
||||
}
|
||||
|
||||
async getControlsConfigForOrder(
|
||||
orderNumber: string,
|
||||
processingStatus: OrderItemProcessingStatusValue
|
||||
): Promise<{ [key: string]: any }> {
|
||||
const orderItems$: Observable<
|
||||
OrderItemListItemDTO[]
|
||||
> = this.detailsStoreFacade.getOrderItemsByOrderNumberAndProcessingStatus$(
|
||||
orderNumber,
|
||||
processingStatus
|
||||
);
|
||||
|
||||
return this.createControlConfig(orderItems$);
|
||||
}
|
||||
|
||||
async getControlsConfigForCompartment(
|
||||
compartmentCode: string,
|
||||
processingStatus: OrderItemProcessingStatusValue
|
||||
): Promise<{ [key: string]: any }> {
|
||||
const orderItems$: Observable<
|
||||
OrderItemListItemDTO[]
|
||||
> = this.detailsStoreFacade.getOrderItemsByCompartmentCodeAndProcessingStatus$(
|
||||
compartmentCode,
|
||||
processingStatus
|
||||
);
|
||||
return this.createControlConfig(orderItems$);
|
||||
}
|
||||
|
||||
private async createControlConfig(
|
||||
orderItems$: Observable<OrderItemListItemDTO[]>
|
||||
): Promise<{ [key: string]: any }> {
|
||||
const orderItems = await orderItems$
|
||||
.pipe(
|
||||
filter((items) => !isNullOrUndefined(items) && !!items.length),
|
||||
take(1)
|
||||
)
|
||||
.toPromise();
|
||||
|
||||
const vats = await this.vats$.pipe(take(1)).toPromise();
|
||||
|
||||
return {
|
||||
...this.getGeneralForm(orderItems),
|
||||
items: this.formBuilder.array(
|
||||
orderItems.map((orderItem) => this.getItemForm(orderItem, vats))
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
getGeneralForm(orderItems: OrderItemListItemDTO[]): { [key: string]: any } {
|
||||
const baseOrderItem = orderItems[0];
|
||||
return {
|
||||
firstName: baseOrderItem.firstName,
|
||||
lastName: baseOrderItem.lastName,
|
||||
compartmentCode: [
|
||||
{ value: baseOrderItem.compartmentCode, disabled: false },
|
||||
],
|
||||
orderId: [{ value: baseOrderItem.orderId, disabled: true }],
|
||||
orderNumber: [
|
||||
{
|
||||
value: baseOrderItem.orderNumber,
|
||||
disabled: true,
|
||||
},
|
||||
],
|
||||
orderDate: [
|
||||
{
|
||||
value: new DatePipe('de').transform(baseOrderItem.orderDate),
|
||||
disabled: true,
|
||||
},
|
||||
],
|
||||
clientChannel: [
|
||||
{
|
||||
value: new EnvironmentChannelPipe().transform(
|
||||
baseOrderItem.clientChannel
|
||||
),
|
||||
disabled: true,
|
||||
},
|
||||
],
|
||||
buyerNumber: [{ value: baseOrderItem.buyerNumber, disabled: true }],
|
||||
processingStatus: [
|
||||
{ value: baseOrderItem.processingStatus, disabled: false },
|
||||
],
|
||||
estimatedShippingDate: [
|
||||
{ value: baseOrderItem.estimatedShippingDate, disabled: false },
|
||||
],
|
||||
pickUpDeadline: [
|
||||
{
|
||||
value: baseOrderItem.pickUpDeadline,
|
||||
disabled: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
getDataFromGeneralForm(form: FormGroup) {
|
||||
return {
|
||||
firstName: form.get('firstName').value,
|
||||
lastName: form.get('lastName').value,
|
||||
compartmentCode: form.get('compartmentCode').value,
|
||||
orderId: Number(form.get('orderId').value),
|
||||
orderNumber: form.get('orderNumber').value,
|
||||
orderDate: new Date(form.get('orderDate').value),
|
||||
clientChannel: Number(
|
||||
form.get('clientChannel').value
|
||||
) as EnvironmentChannel,
|
||||
buyerNumber: form.get('buyerNumber').value,
|
||||
processingStatus: Number(
|
||||
form.get('processingStatus').value
|
||||
) as OrderItemProcessingStatusValue,
|
||||
pickUpDeadline: String(form.get('pickUpDeadline').value || ''),
|
||||
estimatedShippingDate: String(
|
||||
form.get('estimatedShippingDate').value || ''
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
getItemForm(orderItem: OrderItemListItemDTO, vats: VATDTO[]): FormGroup {
|
||||
return this.formBuilder.group({
|
||||
orderId: [{ value: orderItem.orderId, disabled: true }],
|
||||
orderItemId: [{ value: orderItem.orderItemId, disabled: true }],
|
||||
orderItemSubsetId: [
|
||||
{ value: orderItem.orderItemSubsetId, disabled: true },
|
||||
],
|
||||
quantity: [{ value: orderItem.quantity, disabled: true }],
|
||||
price: [
|
||||
{ value: String(orderItem.price).replace('.', ','), disabled: false },
|
||||
[Validators.required, Validators.pattern(/^\d+(,\d{1,2})?$/)],
|
||||
],
|
||||
ean: [
|
||||
{
|
||||
value: orderItem.product.ean,
|
||||
disabled: false,
|
||||
},
|
||||
],
|
||||
supplier: [{ value: orderItem.supplier, disabled: true }],
|
||||
title: [{ value: orderItem.product.name, disabled: true }],
|
||||
ssc: [
|
||||
{
|
||||
value: orderItem.ssc
|
||||
? orderItem.ssc + ' - ' + orderItem.sscText
|
||||
: '-',
|
||||
disabled: false,
|
||||
},
|
||||
],
|
||||
clientChannel: [{ value: orderItem.clientChannel, disabled: true }],
|
||||
targetBranch: [{ value: orderItem.targetBranch, disabled: true }],
|
||||
vat: [
|
||||
{
|
||||
value: orderItem.vatType,
|
||||
disabled: false,
|
||||
},
|
||||
],
|
||||
comment: [{ value: orderItem.specialComment, disabled: false }],
|
||||
});
|
||||
}
|
||||
|
||||
getOrderItemFromItemForm(form: AbstractControl): OrderItemDTO {
|
||||
return {
|
||||
id: Number(form.get('orderItemId').value),
|
||||
quantity: Number(form.get('quantity').value),
|
||||
grossPrice: {
|
||||
vat: { vatType: Number(form.get('vat').value) as VATType },
|
||||
value: { value: Number(form.get('price').value.replace(',', '.')) },
|
||||
},
|
||||
product: { ean: String(form.get('ean').value) },
|
||||
};
|
||||
}
|
||||
|
||||
getOrderItemSubsetFromItemForm(
|
||||
ctrl: AbstractControl,
|
||||
form: FormGroup
|
||||
): OrderItemSubsetDTO & { orderItemId: number } {
|
||||
const sscFull: string = ctrl.get('ssc').value;
|
||||
let ssc = sscFull.split('-')[0];
|
||||
let sscText = sscFull.substr(ssc.length + 1);
|
||||
|
||||
ssc = ssc.trim();
|
||||
sscText = sscText.trim();
|
||||
|
||||
return {
|
||||
id: Number(ctrl.get('orderItemSubsetId').value),
|
||||
orderItemId: Number(ctrl.get('orderItemId').value),
|
||||
orderItemSubsetNumber: ctrl.get('orderItemSubsetId').value,
|
||||
processingStatus: form.get('processingStatus').value,
|
||||
estimatedShippingDate: String(form.get('estimatedShippingDate').value),
|
||||
compartmentCode: !!form.get('compartmentCode').value
|
||||
? String(form.get('compartmentCode').value)
|
||||
: null,
|
||||
specialComment: String(ctrl.get('comment').value || ''),
|
||||
ssc,
|
||||
sscText,
|
||||
};
|
||||
}
|
||||
|
||||
async submit(
|
||||
form: FormGroup,
|
||||
processingStatus: OrderItemProcessingStatusValue
|
||||
): Promise<boolean> {
|
||||
const formData = this.getDataFromGeneralForm(form);
|
||||
|
||||
console.log({ formData });
|
||||
|
||||
const orderItemsToPatch = this.prepareOrderItems(form);
|
||||
const orderItemSubsetsToPatch = this.prepareOrderItemSubsets(form);
|
||||
|
||||
const newProcessingStatus = Number(
|
||||
form.get('processingStatus').value
|
||||
) as OrderItemProcessingStatusValue;
|
||||
|
||||
try {
|
||||
await this.detailsStoreFacade.patchOrderItems(orderItemsToPatch);
|
||||
await this.detailsStoreFacade.patchOrderItemSubsets(
|
||||
orderItemSubsetsToPatch
|
||||
);
|
||||
|
||||
if (newProcessingStatus !== processingStatus) {
|
||||
const changeStatusData = this.prepareStatusChange(
|
||||
form,
|
||||
newProcessingStatus
|
||||
);
|
||||
if (newProcessingStatus === 128) {
|
||||
await this.detailsStoreFacade.arrived(changeStatusData, undefined);
|
||||
} else {
|
||||
await this.detailsStoreFacade.changeStatus(changeStatusData);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('%cSubmit Error: ', 'color: red; font-weight: bold', error);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private prepareOrderItems(form: FormGroup) {
|
||||
const orderItems = (form.get(
|
||||
'items'
|
||||
) as FormArray).controls.map((control) =>
|
||||
this.getOrderItemFromItemForm(control)
|
||||
);
|
||||
|
||||
return orderItems.map((orderItem) => ({
|
||||
orderId: Number(form.get('orderId').value),
|
||||
orderItemId: orderItem.id,
|
||||
orderItem,
|
||||
}));
|
||||
}
|
||||
|
||||
private prepareOrderItemSubsets(
|
||||
form: FormGroup
|
||||
): {
|
||||
orderId: number;
|
||||
orderItemId: number;
|
||||
orderItemSubsetId: number;
|
||||
orderItemSubset: Partial<OrderItemSubsetDTO>;
|
||||
}[] {
|
||||
const subsetItems = (form.get(
|
||||
'items'
|
||||
) as FormArray).controls.map((control) =>
|
||||
this.getOrderItemSubsetFromItemForm(control, form)
|
||||
);
|
||||
|
||||
return subsetItems.map((item) => ({
|
||||
orderId: form.get('orderId').value,
|
||||
orderItemId: item.orderItemId,
|
||||
orderItemSubsetId: item.id,
|
||||
orderItemSubset: { ...item },
|
||||
}));
|
||||
}
|
||||
|
||||
private prepareStatusChange(
|
||||
form: FormGroup,
|
||||
processingStatus: OrderItemProcessingStatusValue
|
||||
): {
|
||||
orderItemSubsetId: number;
|
||||
orderItemId: number;
|
||||
orderId: number;
|
||||
data: StatusValues;
|
||||
}[] {
|
||||
const items = (form.get('items') as FormArray).controls.map((itemForm) =>
|
||||
this.getOrderItemSubsetFromItemForm(itemForm, form)
|
||||
);
|
||||
|
||||
return items.map((item) => ({
|
||||
orderId: Number(form.get('orderId').value),
|
||||
orderItemId: item.orderItemId,
|
||||
orderItemSubsetId: Number(item.orderItemSubsetNumber),
|
||||
data: { processingStatus } as StatusValues,
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,14 @@
|
||||
import { Injectable, OnDestroy } from '@angular/core';
|
||||
import { Observable, BehaviorSubject, Subject, combineLatest } from 'rxjs';
|
||||
import { SelectFilter, Filter, SelectFilterOption } from '../../filter';
|
||||
import { tap, startWith, map, filter, takeUntil } from 'rxjs/operators';
|
||||
import {
|
||||
startWith,
|
||||
map,
|
||||
filter,
|
||||
takeUntil,
|
||||
take,
|
||||
distinctUntilChanged,
|
||||
} from 'rxjs/operators';
|
||||
import { SearchStateFacade } from '../../../store/customer';
|
||||
import { flatten } from '../../../shared/utils';
|
||||
import { isNullOrUndefined } from 'util';
|
||||
@@ -60,13 +67,11 @@ export class ShelfFilterService implements OnDestroy {
|
||||
|
||||
get pendingFiltersShouldUpdate$() {
|
||||
return combineLatest([
|
||||
this.filters$.pipe(filter((filters) => !isNullOrUndefined(filters))),
|
||||
this.resetFilters$.pipe(
|
||||
startWith(),
|
||||
tap(() => {
|
||||
this.pendingFilters = null;
|
||||
})
|
||||
this.filters$.pipe(
|
||||
filter((filters) => !isNullOrUndefined(filters)),
|
||||
distinctUntilChanged((a, b) => this.isJsonEqual(a, b))
|
||||
),
|
||||
this.resetFilters$.pipe(startWith()),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -81,12 +86,14 @@ export class ShelfFilterService implements OnDestroy {
|
||||
}
|
||||
|
||||
initPendingFilters() {
|
||||
this.setInitialPendingFilters();
|
||||
|
||||
this.pendingFiltersShouldUpdate$
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(([filters]) => {
|
||||
this.pendingFilters = filters.map(cloneFilter);
|
||||
this.setInitialFilterGroupLastChanged(filters);
|
||||
});
|
||||
.pipe(
|
||||
takeUntil(this.destroy$),
|
||||
map(([filters]) => filters)
|
||||
)
|
||||
.subscribe(this.updatePendingFilters);
|
||||
}
|
||||
|
||||
updateFilters(updatedFilters: SelectFilter[]) {
|
||||
@@ -106,6 +113,21 @@ export class ShelfFilterService implements OnDestroy {
|
||||
this.overlayClosed$.next();
|
||||
}
|
||||
|
||||
private setInitialPendingFilters() {
|
||||
this.filters$
|
||||
.pipe(
|
||||
filter((filters) => !isNullOrUndefined(filters)),
|
||||
take(1),
|
||||
takeUntil(this.destroy$)
|
||||
)
|
||||
.subscribe(this.updatePendingFilters);
|
||||
}
|
||||
|
||||
private updatePendingFilters = (filters: SelectFilter[]) => {
|
||||
this.pendingFilters = filters.map(cloneFilter);
|
||||
this.setInitialFilterGroupLastChanged(filters);
|
||||
};
|
||||
|
||||
private setInitialFilterGroupLastChanged(filters: SelectFilter[]) {
|
||||
if (!this.lastFilterGroupChanged$.value) {
|
||||
this.lastFilterGroupChanged$.next(filters[0]);
|
||||
@@ -123,4 +145,8 @@ export class ShelfFilterService implements OnDestroy {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private isJsonEqual(oldValue: any, newValue: any): boolean {
|
||||
return JSON.stringify(oldValue) === JSON.stringify(newValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// start:ng42.barrel
|
||||
export * from './focus.directive';
|
||||
// end:ng42.barrel
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// start:ng42.barrel
|
||||
export * from './historyDto.mock';
|
||||
export * from './filters.mock';
|
||||
export * from './historyDto.mock';
|
||||
export * from './primary-filters.mock';
|
||||
export * from './select-filter-option.mock';
|
||||
export * from './vat-dtos.mock';
|
||||
// end:ng42.barrel
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { VATDTO } from '@swagger/oms';
|
||||
|
||||
export const vatDtosMock: VATDTO[] = [
|
||||
{
|
||||
name: '0',
|
||||
value: 0.0,
|
||||
country: { id: 1243, enabled: true },
|
||||
vatType: 1,
|
||||
start: '2020-06-01T00:00:00',
|
||||
stop: '2021-01-01T00:00:00',
|
||||
id: 1041,
|
||||
created: '2020-06-18T07:19:07Z',
|
||||
changed: '2020-06-18T07:19:07Z',
|
||||
version: 1,
|
||||
status: 1,
|
||||
},
|
||||
{
|
||||
name: '5',
|
||||
value: 5.0,
|
||||
country: { id: 1243, enabled: true },
|
||||
vatType: 8,
|
||||
start: '2020-06-01T00:00:00',
|
||||
stop: '2021-01-01T00:00:00',
|
||||
id: 1042,
|
||||
created: '2020-06-18T07:19:08Z',
|
||||
changed: '2020-06-18T07:19:08Z',
|
||||
version: 1,
|
||||
status: 1,
|
||||
},
|
||||
{
|
||||
name: '16',
|
||||
value: 16.0,
|
||||
country: { id: 1243, enabled: true },
|
||||
vatType: 2,
|
||||
start: '2020-06-01T00:00:00',
|
||||
stop: '2021-01-01T00:00:00',
|
||||
id: 1043,
|
||||
created: '2020-06-18T07:19:08Z',
|
||||
changed: '2020-06-18T07:19:08Z',
|
||||
version: 1,
|
||||
status: 1,
|
||||
},
|
||||
];
|
||||
@@ -1,8 +1,17 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { Store } from '@ngxs/store';
|
||||
import { AddBreadcrumb, UpdateCurrentBreadcrumbName } from 'apps/sales/src/app/core/store/actions/breadcrumb.actions';
|
||||
import { ChangeCurrentRoute, AddProcess } from 'apps/sales/src/app/core/store/actions/process.actions';
|
||||
import {
|
||||
AddBreadcrumb,
|
||||
UpdateCurrentBreadcrumbName,
|
||||
PopLastBreadcrumbs,
|
||||
ClearBreadcrumbs,
|
||||
DeleteBreadcrumbsForProcess,
|
||||
} from 'apps/sales/src/app/core/store/actions/breadcrumb.actions';
|
||||
import {
|
||||
ChangeCurrentRoute,
|
||||
AddProcess,
|
||||
} from 'apps/sales/src/app/core/store/actions/process.actions';
|
||||
import { Breadcrumb } from 'apps/sales/src/app/core/models/breadcrumb.model';
|
||||
import { OrderItemListItemDTO } from '@swagger/oms/lib';
|
||||
import { ProcessSelectors } from 'apps/sales/src/app/core/store/selectors/process.selectors';
|
||||
@@ -12,7 +21,11 @@ import { Process } from 'apps/sales/src/app/core/models/process.model';
|
||||
export class ShelfNavigationService {
|
||||
constructor(private store: Store, private router: Router) {}
|
||||
|
||||
navigateToDetails(order: { orderNumber?: string; compartmentCode?: string; processingStatus?: number }) {
|
||||
navigateToDetails(order: {
|
||||
orderNumber?: string;
|
||||
compartmentCode?: string;
|
||||
processingStatus?: number;
|
||||
}) {
|
||||
this.createTab();
|
||||
const path = this.getDetailsPath(order);
|
||||
const breadcrumb = this.getDetailsBreadcrumb(order);
|
||||
@@ -20,7 +33,23 @@ export class ShelfNavigationService {
|
||||
this.navigateToRoute(path, breadcrumb);
|
||||
}
|
||||
|
||||
updateDetailsNavigation(order: { orderNumber?: string; compartmentCode?: string; processingStatus?: number }) {
|
||||
navigateToEdit(order: {
|
||||
orderNumber?: string;
|
||||
compartmentCode?: string;
|
||||
processingStatus?: number;
|
||||
}) {
|
||||
this.createTab();
|
||||
const path = this.getDetailsPath({ ...order, edit: true });
|
||||
const breadcrumb = this.getEditBreadCrumb();
|
||||
|
||||
this.navigateToRoute(path, breadcrumb);
|
||||
}
|
||||
|
||||
updateDetailsNavigation(order: {
|
||||
orderNumber?: string;
|
||||
compartmentCode?: string;
|
||||
processingStatus?: number;
|
||||
}) {
|
||||
const path = this.getDetailsPath(order);
|
||||
const breadcrumb = this.getDetailsBreadcrumb(order);
|
||||
this.replaceRoute(path, breadcrumb);
|
||||
@@ -32,7 +61,13 @@ export class ShelfNavigationService {
|
||||
this.replaceRoute(path, breadcrumb);
|
||||
}
|
||||
|
||||
navigateToResultList({ searchQuery, numberOfHits }: { searchQuery: string; numberOfHits: number }) {
|
||||
navigateToResultList({
|
||||
searchQuery,
|
||||
numberOfHits,
|
||||
}: {
|
||||
searchQuery: string;
|
||||
numberOfHits: number;
|
||||
}) {
|
||||
this.createTab();
|
||||
const path = '/shelf/results';
|
||||
const breadcrumb = this.getResultListBreadcrumb(searchQuery, numberOfHits);
|
||||
@@ -40,12 +75,56 @@ export class ShelfNavigationService {
|
||||
}
|
||||
|
||||
navigateToHistory(orderitem: OrderItemListItemDTO) {
|
||||
this.navigateToRoute(`shelf/history/${orderitem.orderItemSubsetId}`, `Historie ${orderitem.orderItemSubsetId}`);
|
||||
this.navigateToRoute(
|
||||
this.getHistoryPath(orderitem),
|
||||
`Historie ${orderitem.orderItemSubsetId}`
|
||||
);
|
||||
}
|
||||
|
||||
getHistoryPath(data: {
|
||||
orderId?: number;
|
||||
compartmentCode?: string;
|
||||
orderItemId?: number;
|
||||
orderItemSubsetId?: number;
|
||||
orderNumber?: string;
|
||||
}) {
|
||||
if (data.compartmentCode) {
|
||||
return `/shelf/details/compartment/${data.compartmentCode}/item/${data.orderItemId}/subset/${data.orderItemSubsetId}/history`;
|
||||
} else if (data.orderId) {
|
||||
return `/shelf/details/order/${data.orderNumber}/item/${data.orderItemId}/subset/${data.orderItemSubsetId}/history`;
|
||||
}
|
||||
}
|
||||
|
||||
updateResultPageBreadcrumb(data: {
|
||||
numberOfHits: number;
|
||||
searchQuery: string;
|
||||
}) {
|
||||
this.store.dispatch(new DeleteBreadcrumbsForProcess(1));
|
||||
this.store.dispatch(
|
||||
new AddBreadcrumb(
|
||||
{ name: 'Warenausgabe', path: '/shelf/search' },
|
||||
'shelf'
|
||||
)
|
||||
);
|
||||
const path = '/shelf/results';
|
||||
this.store.dispatch(
|
||||
new AddBreadcrumb(
|
||||
{
|
||||
name: `${data.searchQuery} (${data.numberOfHits} ${
|
||||
data.numberOfHits > 1 ? 'Ergebnisse' : 'Ergebnis'
|
||||
})`,
|
||||
path,
|
||||
},
|
||||
'shelf'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private replaceRoute(route: string, breadcrumbName: string) {
|
||||
this.router.navigate([route]);
|
||||
this.store.dispatch(new UpdateCurrentBreadcrumbName(breadcrumbName, 'shelf'));
|
||||
this.store.dispatch(
|
||||
new UpdateCurrentBreadcrumbName(breadcrumbName, 'shelf')
|
||||
);
|
||||
}
|
||||
|
||||
private navigateToRoute(route: string, breadcrumbName: string) {
|
||||
@@ -62,18 +141,75 @@ export class ShelfNavigationService {
|
||||
this.router.navigate([route]);
|
||||
}
|
||||
|
||||
private getResultListBreadcrumb(searchQuery: string, numberOfHits: number): string {
|
||||
public navigateBackToDetails(
|
||||
data: {
|
||||
orderNumber?: string;
|
||||
compartmentCode?: string;
|
||||
processingStatus?: number;
|
||||
},
|
||||
previous?: {
|
||||
orderNumber?: string;
|
||||
compartmentCode?: string;
|
||||
processingStatus?: number;
|
||||
}
|
||||
) {
|
||||
this.store.dispatch(new PopLastBreadcrumbs(this.getEditBreadCrumb()));
|
||||
|
||||
if (previous) {
|
||||
this.store.dispatch(
|
||||
new PopLastBreadcrumbs(this.getDetailsBreadcrumb(previous))
|
||||
);
|
||||
}
|
||||
this.navigateToDetails(data);
|
||||
}
|
||||
|
||||
public updateDetails(
|
||||
data: {
|
||||
orderNumber?: string;
|
||||
compartmentCode?: string;
|
||||
processingStatus?: number;
|
||||
},
|
||||
previous?: {
|
||||
orderNumber?: string;
|
||||
compartmentCode?: string;
|
||||
processingStatus?: number;
|
||||
}
|
||||
) {
|
||||
if (previous) {
|
||||
this.store.dispatch(
|
||||
new PopLastBreadcrumbs(this.getDetailsBreadcrumb(previous))
|
||||
);
|
||||
}
|
||||
this.navigateToDetails(data);
|
||||
}
|
||||
|
||||
private getResultListBreadcrumb(
|
||||
searchQuery: string,
|
||||
numberOfHits: number
|
||||
): string {
|
||||
return `${searchQuery} (${numberOfHits} Ergebnisse)`;
|
||||
}
|
||||
|
||||
getDetailsBreadcrumb(data: { orderNumber?: string; compartmentCode?: string }): string {
|
||||
getDetailsBreadcrumb(data: {
|
||||
orderNumber?: string;
|
||||
compartmentCode?: string;
|
||||
}): string {
|
||||
if (data.compartmentCode) {
|
||||
return `${data.compartmentCode}`;
|
||||
}
|
||||
return `${data.orderNumber}`;
|
||||
}
|
||||
|
||||
private getDetailsPath(data: { orderNumber?: string; compartmentCode?: string; processingStatus?: number }): string {
|
||||
getEditBreadCrumb(): string {
|
||||
return 'Bearbeiten';
|
||||
}
|
||||
|
||||
private getDetailsPath(data: {
|
||||
orderNumber?: string;
|
||||
compartmentCode?: string;
|
||||
processingStatus?: number;
|
||||
edit?: boolean;
|
||||
}): string {
|
||||
let url = '';
|
||||
if (data.compartmentCode) {
|
||||
url = `/shelf/details/compartment/${data.compartmentCode}/${data.processingStatus}`;
|
||||
@@ -81,11 +217,16 @@ export class ShelfNavigationService {
|
||||
url = `/shelf/details/order/${data.orderNumber}/${data.processingStatus}`;
|
||||
}
|
||||
|
||||
if (data.edit) {
|
||||
url += '/edit';
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
private createTab() {
|
||||
const processExists = this.store.selectSnapshot(ProcessSelectors.getProcessesCount) > 0;
|
||||
const processExists =
|
||||
this.store.selectSnapshot(ProcessSelectors.getProcessesCount) > 0;
|
||||
if (!processExists) {
|
||||
this.createProcess();
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ export class ShelfSearchFacadeService {
|
||||
}
|
||||
|
||||
this.searchStateFacade.setInput(searchQuery);
|
||||
return this.requestSearch();
|
||||
return this.requestSearch(true);
|
||||
}
|
||||
|
||||
searchWithBarcode(barcode: string) {
|
||||
@@ -49,7 +49,7 @@ export class ShelfSearchFacadeService {
|
||||
}
|
||||
|
||||
this.searchStateFacade.setInput(searchQuery);
|
||||
return this.requestSearch();
|
||||
return this.requestSearch(true);
|
||||
}
|
||||
|
||||
searchForAutocomplete(
|
||||
@@ -72,8 +72,8 @@ export class ShelfSearchFacadeService {
|
||||
return this.requestAutocompleteSearch(autoCompleteQuery);
|
||||
}
|
||||
|
||||
private requestSearch() {
|
||||
return this.searchStateFacade.fetchResult();
|
||||
private requestSearch(isNewSearch: boolean = false) {
|
||||
return this.searchStateFacade.fetchResult({ isNewSearch });
|
||||
}
|
||||
|
||||
private generateAutocompleteToken(params: {
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import { calculateExtendedPickUpDate } from './calculate-extended-pick-up-date';
|
||||
|
||||
fdescribe('calculateExtendedPickUpDate', () => {
|
||||
const basePickUpDate = '2020-07-17T11:16:50.4404048Z';
|
||||
|
||||
it('should return the extended pick up date by 2 weeks', () => {
|
||||
const result = calculateExtendedPickUpDate(basePickUpDate);
|
||||
expect(result.slice(0, 10)).toBe('2020-07-31');
|
||||
|
||||
const result2 = calculateExtendedPickUpDate(basePickUpDate, 2);
|
||||
expect(result2.slice(0, 10)).toBe('2020-07-31');
|
||||
});
|
||||
|
||||
it('should return the extended pick up date by 4 weeks', () => {
|
||||
const result = calculateExtendedPickUpDate(basePickUpDate, 4);
|
||||
expect(result.slice(0, 10)).toBe('2020-08-14');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,8 @@
|
||||
export function calculateExtendedPickUpDate(
|
||||
pickUpdate: string,
|
||||
weeks: number = 2
|
||||
): string {
|
||||
const baseDate = new Date(pickUpdate);
|
||||
baseDate.setDate(baseDate.getDate() + 7 * weeks);
|
||||
return baseDate.toISOString();
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { calculateExtendedPickUpDate } from '.';
|
||||
|
||||
export function extendPickUpDate(currentPickUpdate: string): string[] {
|
||||
return [
|
||||
calculateExtendedPickUpDate(currentPickUpdate, 2),
|
||||
calculateExtendedPickUpDate(currentPickUpdate, 4),
|
||||
];
|
||||
}
|
||||
4
apps/sales/src/app/modules/shelf/shared/utils/index.ts
Normal file
4
apps/sales/src/app/modules/shelf/shared/utils/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
// start:ng42.barrel
|
||||
export * from './calculate-extended-pick-up-date';
|
||||
// end:ng42.barrel
|
||||
|
||||
@@ -6,6 +6,7 @@ import { ShelfOrderDetailsComponent } from './pages/shelf-order-details/shelf-or
|
||||
import { ShelfEditOrderComponent } from './pages/shelf-edit-order/shelf-edit-order.component';
|
||||
import { ShelfHistoryComponent } from './pages/shelf-history';
|
||||
import { ShelfOrderDetailsModule } from './pages/shelf-order-details';
|
||||
import { ShelfEditCompartmentComponent } from './pages/shelf-edit-compartment';
|
||||
|
||||
export const routes: Routes = [
|
||||
{
|
||||
@@ -25,11 +26,19 @@ export const routes: Routes = [
|
||||
component: ShelfOrderDetailsComponent,
|
||||
},
|
||||
{
|
||||
path: 'edit/:id/:orderId/:status/:type/:origin/:customerId/:itemId',
|
||||
path: 'details/order/:orderNumber/:processingStatus/edit',
|
||||
component: ShelfEditOrderComponent,
|
||||
},
|
||||
{
|
||||
path: 'history/:orderItemSubsetId',
|
||||
path: 'details/compartment/:compartmentCode/:processingStatus/edit',
|
||||
component: ShelfEditCompartmentComponent,
|
||||
},
|
||||
{
|
||||
path: 'details/order/:orderId/item/:orderItemId/subset/:orderItemSubsetId/history',
|
||||
component: ShelfHistoryComponent,
|
||||
},
|
||||
{
|
||||
path: 'details/compartment/:compartmentCode/item/:orderItemId/subset/:orderItemSubsetId/history',
|
||||
component: ShelfHistoryComponent,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -5,7 +5,15 @@ import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { ButtonModule, CardModule, IconModule, InputModule, LoadingModule, SearchInputModule, DropdownModule } from '@libs/ui';
|
||||
import {
|
||||
ButtonModule,
|
||||
CardModule,
|
||||
IconModule,
|
||||
InputModule,
|
||||
LoadingModule,
|
||||
SearchInputModule,
|
||||
DropdownModule,
|
||||
} from '@libs/ui';
|
||||
|
||||
import { SharedModule } from '../../shared/shared.module';
|
||||
import {
|
||||
@@ -14,18 +22,19 @@ import {
|
||||
ShelfCustomerOrderComponent,
|
||||
ShelfOrderTagComponent,
|
||||
ShelfPartialCollectionModalComponent,
|
||||
OrderItemEditComponent,
|
||||
OrderOverviewEditComponent,
|
||||
} from './components';
|
||||
|
||||
import { ShelfRoutingModule } from './shelf-routing.module';
|
||||
import { OrderStatusPipe } from '../../pipes/order-status.pipe';
|
||||
import { OrderLoadingComponent } from './components/order-loading/order-loading.component';
|
||||
import { ShelfEditOrderComponent } from './pages/shelf-edit-order/shelf-edit-order.component';
|
||||
import { OrderItemEditComponent } from './components/order-item-edit/order-item-edit.component';
|
||||
import { OrderOverviewEditComponent } from './components/order-overview-edit/order-overview-edit.component';
|
||||
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
|
||||
|
||||
import { ShelfSearchResultsModule } from './pages/shelf-search-results/shelf-search-results.module';
|
||||
import { ShelfSearchModule } from './pages/shelf-search';
|
||||
import { ShelfHistoryModule } from './pages/shelf-history';
|
||||
import { ShelfEditOrderModule } from './pages/shelf-edit-order/shelf-edit-order.module';
|
||||
import { ShelfEditCompartmentModule } from './pages/shelf-edit-compartment';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
@@ -36,7 +45,6 @@ import { ShelfHistoryModule } from './pages/shelf-history';
|
||||
ShelfPartialCollectionModalComponent,
|
||||
OrderStatusPipe,
|
||||
OrderLoadingComponent,
|
||||
ShelfEditOrderComponent,
|
||||
OrderItemEditComponent,
|
||||
OrderOverviewEditComponent,
|
||||
],
|
||||
@@ -46,6 +54,8 @@ import { ShelfHistoryModule } from './pages/shelf-history';
|
||||
ShelfRoutingModule,
|
||||
ShelfSearchModule,
|
||||
ShelfHistoryModule,
|
||||
ShelfEditOrderModule,
|
||||
ShelfEditCompartmentModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
RouterModule,
|
||||
|
||||
@@ -33,6 +33,8 @@ export abstract class DateAdapter<TDate> {
|
||||
|
||||
abstract getDifferenceInDays(first: TDate, second: TDate): number;
|
||||
|
||||
abstract getDayOfWeek(date: TDate): number;
|
||||
|
||||
compareDate(first: TDate, second: TDate) {
|
||||
if (isNullOrUndefined(first) || isNullOrUndefined(second)) {
|
||||
return null;
|
||||
@@ -49,6 +51,9 @@ export abstract class DateAdapter<TDate> {
|
||||
if (isNullOrUndefined(first) || isNullOrUndefined(second)) {
|
||||
return null;
|
||||
}
|
||||
return this.getYear(first) - this.getYear(second) || this.getMonth(first) - this.getMonth(second);
|
||||
return (
|
||||
this.getYear(first) - this.getYear(second) ||
|
||||
this.getMonth(first) - this.getMonth(second)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,10 +23,18 @@ export class NativeDateAdapter extends DateAdapter<Date> {
|
||||
return this.getDate(date).toString();
|
||||
}
|
||||
addCalendarMonths(date: Date, months: number): Date {
|
||||
return this.createDate(this.getYear(date), this.getMonth(date) + months, this.getDate(date));
|
||||
return this.createDate(
|
||||
this.getYear(date),
|
||||
this.getMonth(date) + months,
|
||||
this.getDate(date)
|
||||
);
|
||||
}
|
||||
addCalendarDays(date: Date, days: number): Date {
|
||||
return this.createDate(this.getYear(date), this.getMonth(date), this.getDate(date) + days);
|
||||
return this.createDate(
|
||||
this.getYear(date),
|
||||
this.getMonth(date),
|
||||
this.getDate(date) + days
|
||||
);
|
||||
}
|
||||
|
||||
getFirstDateOfWeek(date: Date): Date {
|
||||
@@ -55,6 +63,10 @@ export class NativeDateAdapter extends DateAdapter<Date> {
|
||||
return (first.getTime() - second.getTime()) / (1000 * 3600 * 24);
|
||||
}
|
||||
|
||||
getDayOfWeek(date: Date) {
|
||||
return date.getDay();
|
||||
}
|
||||
|
||||
createDate(year: number, month: number, date: number): Date {
|
||||
const result = new Date(year, month, date);
|
||||
// abbreviations for 19xx.
|
||||
|
||||
@@ -18,7 +18,14 @@ th {
|
||||
height: 41px;
|
||||
}
|
||||
|
||||
.cell-not-in-range {
|
||||
.cell-is-today {
|
||||
border: 1px dashed $datepicker-selected-cell-bg-color;
|
||||
border-radius: 50%;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.cell-not-in-range,
|
||||
.cell-is-disabled-day-of-week {
|
||||
color: $datepicker-cell-not-in-range-color;
|
||||
}
|
||||
|
||||
@@ -29,4 +36,5 @@ th {
|
||||
.cell-selected {
|
||||
background-color: $datepicker-selected-cell-bg-color;
|
||||
border-radius: 22px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,19 @@
|
||||
import { Directive, Input, HostBinding, OnDestroy, OnInit, HostListener } from '@angular/core';
|
||||
import {
|
||||
Directive,
|
||||
Input,
|
||||
HostBinding,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
HostListener,
|
||||
} from '@angular/core';
|
||||
import { Datepicker } from '@isa-ui/datepicker/datepicker';
|
||||
import { DateAdapter } from '@isa-ui/core/date';
|
||||
import { Subscription, ReplaySubject, combineLatest, BehaviorSubject } from 'rxjs';
|
||||
import {
|
||||
Subscription,
|
||||
ReplaySubject,
|
||||
combineLatest,
|
||||
BehaviorSubject,
|
||||
} from 'rxjs';
|
||||
|
||||
@Directive({ selector: '[appUiDatepickerCell]' })
|
||||
export class UiDatepickerCellDirective<TDate> implements OnInit, OnDestroy {
|
||||
@@ -30,19 +42,34 @@ export class UiDatepickerCellDirective<TDate> implements OnInit, OnDestroy {
|
||||
@HostBinding('class.cell-not-in-range')
|
||||
notInRange: boolean;
|
||||
|
||||
@HostBinding('class.cell-is-today')
|
||||
isToday: boolean;
|
||||
|
||||
@HostBinding('class.cell-is-disabled-day-of-week')
|
||||
isDisabledDayOfWeek: boolean;
|
||||
|
||||
private subscription = new Subscription();
|
||||
|
||||
constructor(private datepicker: Datepicker<TDate>, private dateAdapter: DateAdapter<TDate>) {}
|
||||
constructor(
|
||||
private datepicker: Datepicker<TDate>,
|
||||
private dateAdapter: DateAdapter<TDate>
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.initDisplayed$();
|
||||
this.initSelected$();
|
||||
this.initRange$();
|
||||
this.initToday$();
|
||||
this.initDisabledDayOfWeek$();
|
||||
}
|
||||
|
||||
initDisplayed$() {
|
||||
const sub = combineLatest([this.dateSubject, this.datepicker.displayed$]).subscribe(([date, displayed]) => {
|
||||
this.inDisplayedMonth = this.dateAdapter.compareYearAndMonth(date, displayed) === 0;
|
||||
const sub = combineLatest([
|
||||
this.dateSubject,
|
||||
this.datepicker.displayed$,
|
||||
]).subscribe(([date, displayed]) => {
|
||||
this.inDisplayedMonth =
|
||||
this.dateAdapter.compareYearAndMonth(date, displayed) === 0;
|
||||
this.notInDisplayedMonth = !this.inDisplayedMonth;
|
||||
});
|
||||
|
||||
@@ -50,7 +77,10 @@ export class UiDatepickerCellDirective<TDate> implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
initSelected$() {
|
||||
const sub = combineLatest([this.dateSubject, this.datepicker.selected$]).subscribe(([date, selected]) => {
|
||||
const sub = combineLatest([
|
||||
this.dateSubject,
|
||||
this.datepicker.selected$,
|
||||
]).subscribe(([date, selected]) => {
|
||||
this.selected = this.dateAdapter.compareDate(date, selected) === 0;
|
||||
});
|
||||
|
||||
@@ -58,9 +88,17 @@ export class UiDatepickerCellDirective<TDate> implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
initRange$() {
|
||||
const sub = combineLatest([this.dateSubject, this.datepicker.min$, this.datepicker.max$]).subscribe(([date, min, max]) => {
|
||||
const minInRange = !!min ? this.dateAdapter.compareDate(date, min) > 0 : true;
|
||||
const maxInRange = !!max ? this.dateAdapter.compareDate(max, date) > 0 : true;
|
||||
const sub = combineLatest([
|
||||
this.dateSubject,
|
||||
this.datepicker.min$,
|
||||
this.datepicker.max$,
|
||||
]).subscribe(([date, min, max]) => {
|
||||
const minInRange = !!min
|
||||
? this.dateAdapter.compareDate(date, min) > 0
|
||||
: true;
|
||||
const maxInRange = !!max
|
||||
? this.dateAdapter.compareDate(max, date) > 0
|
||||
: true;
|
||||
|
||||
this.inRange = minInRange && maxInRange;
|
||||
this.notInRange = !this.inRange;
|
||||
@@ -69,6 +107,27 @@ export class UiDatepickerCellDirective<TDate> implements OnInit, OnDestroy {
|
||||
this.subscription.add(sub);
|
||||
}
|
||||
|
||||
initToday$() {
|
||||
const sub = this.dateSubject.subscribe((date) => {
|
||||
this.isToday =
|
||||
this.dateAdapter.compareDate(date, this.dateAdapter.today()) === 0;
|
||||
});
|
||||
this.subscription.add(sub);
|
||||
}
|
||||
|
||||
initDisabledDayOfWeek$() {
|
||||
const sub = combineLatest([
|
||||
this.dateSubject,
|
||||
this.datepicker.disabledDaysOfWeek$,
|
||||
]).subscribe(([date, disabledDayOfWeek]) => {
|
||||
this.isDisabledDayOfWeek =
|
||||
disabledDayOfWeek &&
|
||||
disabledDayOfWeek.includes(this.dateAdapter.getDayOfWeek(date));
|
||||
});
|
||||
|
||||
this.subscription.add(sub);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.subscription.unsubscribe();
|
||||
this.dateSubject.complete();
|
||||
@@ -76,7 +135,7 @@ export class UiDatepickerCellDirective<TDate> implements OnInit, OnDestroy {
|
||||
|
||||
@HostListener('click')
|
||||
select() {
|
||||
if (this.inRange && this.inDisplayedMonth) {
|
||||
if (this.inRange && this.inDisplayedMonth && !this.isDisabledDayOfWeek) {
|
||||
this.datepicker.setSelected(this.date);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,10 +45,22 @@ export abstract class Datepicker<TDate> {
|
||||
this.setMax(val);
|
||||
}
|
||||
|
||||
@Input()
|
||||
get disabledDaysOfWeek() {
|
||||
return this.disableDayOfWeekSubject.value;
|
||||
}
|
||||
set disabledDaysOfWeek(value: number[]) {
|
||||
// 0 = Sunday, 1 = Monday, ... 6 = Saturday
|
||||
this.disableDayOfWeekSubject.next(value);
|
||||
}
|
||||
|
||||
protected selectedSubject = new BehaviorSubject<TDate>(undefined);
|
||||
protected displayedSubject = new BehaviorSubject<TDate>(this.dateAdapter.today());
|
||||
protected displayedSubject = new BehaviorSubject<TDate>(
|
||||
this.dateAdapter.today()
|
||||
);
|
||||
protected minSubject = new BehaviorSubject<TDate>(undefined);
|
||||
protected maxSubject = new BehaviorSubject<TDate>(undefined);
|
||||
protected disableDayOfWeekSubject = new BehaviorSubject<number[]>(undefined);
|
||||
|
||||
get selected$() {
|
||||
return this.selectedSubject.asObservable();
|
||||
@@ -62,6 +74,9 @@ export abstract class Datepicker<TDate> {
|
||||
get max$() {
|
||||
return this.maxSubject.asObservable();
|
||||
}
|
||||
get disabledDaysOfWeek$() {
|
||||
return this.disableDayOfWeekSubject.asObservable();
|
||||
}
|
||||
|
||||
constructor(private dateAdapter: DateAdapter<TDate>) {}
|
||||
|
||||
@@ -73,7 +88,10 @@ export abstract class Datepicker<TDate> {
|
||||
this.setDisplayed(this.dateAdapter.addCalendarMonths(this.displayed, -1));
|
||||
}
|
||||
|
||||
setSelected(date: TDate, { emit: emitChanged }: SetPropertyOptions = { emit: true }) {
|
||||
setSelected(
|
||||
date: TDate,
|
||||
{ emit: emitChanged }: SetPropertyOptions = { emit: true }
|
||||
) {
|
||||
if (!this.dateAdapter.isValid(date)) {
|
||||
this.selectedSubject.next(undefined);
|
||||
return;
|
||||
@@ -87,7 +105,10 @@ export abstract class Datepicker<TDate> {
|
||||
}
|
||||
}
|
||||
|
||||
setDisplayed(date: TDate, { emit: emitChanged }: SetPropertyOptions = { emit: true }) {
|
||||
setDisplayed(
|
||||
date: TDate,
|
||||
{ emit: emitChanged }: SetPropertyOptions = { emit: true }
|
||||
) {
|
||||
if (!this.dateAdapter.isValid(date)) {
|
||||
this.displayedSubject.next(undefined);
|
||||
return;
|
||||
|
||||
@@ -16,25 +16,34 @@ import { trigger, transition, style, animate } from '@angular/animations';
|
||||
import { UiDropdownItemDirective } from './dropdown-item.directive';
|
||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
import { fromEvent, Subscription } from 'rxjs';
|
||||
import { throttleTime } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'app-ui-dropdown',
|
||||
templateUrl: 'dropdown.component.html',
|
||||
styleUrls: ['dropdown.component.scss'],
|
||||
exportAs: 'uiDropdown',
|
||||
providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => UiDropdownComponent), multi: true }],
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: forwardRef(() => UiDropdownComponent),
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
animations: [
|
||||
trigger('dropdownAnimation', [
|
||||
transition(':enter', [
|
||||
style({ transform: 'translateY(-60px)', opacity: 0 }),
|
||||
animate('200ms', style({ transform: 'translateY(0)', opacity: 1 })),
|
||||
]),
|
||||
transition(':leave', [style({ opacity: '*' }), animate('200ms', style({ opacity: 0 }))]),
|
||||
transition(':leave', [
|
||||
style({ opacity: '*' }),
|
||||
animate('200ms', style({ opacity: 0 })),
|
||||
]),
|
||||
]),
|
||||
],
|
||||
})
|
||||
export class UiDropdownComponent implements OnInit, OnDestroy, ControlValueAccessor, AfterContentInit {
|
||||
export class UiDropdownComponent
|
||||
implements OnInit, OnDestroy, ControlValueAccessor, AfterContentInit {
|
||||
visible = false;
|
||||
|
||||
@ContentChildren(UiDropdownItemDirective)
|
||||
@@ -70,11 +79,13 @@ export class UiDropdownComponent implements OnInit, OnDestroy, ControlValueAcces
|
||||
option.registerOnSelect((value) => this.selectValue(value));
|
||||
});
|
||||
|
||||
this.optionChangesSubscription = this.options.changes.subscribe((changes) => {
|
||||
this.options.forEach((option) => {
|
||||
option.registerOnSelect((value) => this.selectValue(value));
|
||||
});
|
||||
});
|
||||
this.optionChangesSubscription = this.options.changes.subscribe(
|
||||
(changes) => {
|
||||
this.options.forEach((option) => {
|
||||
option.registerOnSelect((value) => this.selectValue(value));
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
toggle(visible?: boolean) {
|
||||
@@ -86,7 +97,10 @@ export class UiDropdownComponent implements OnInit, OnDestroy, ControlValueAcces
|
||||
|
||||
if (this.visible) {
|
||||
this.subscribeKeyboardEvents();
|
||||
this.options.first.focus();
|
||||
|
||||
if (!!this.options.first) {
|
||||
this.options.first.focus();
|
||||
}
|
||||
} else {
|
||||
this.unsubscribeKeyboardEvents();
|
||||
}
|
||||
@@ -96,26 +110,32 @@ export class UiDropdownComponent implements OnInit, OnDestroy, ControlValueAcces
|
||||
if (this.windowKeyEventsSubscription) {
|
||||
this.unsubscribeKeyboardEvents();
|
||||
}
|
||||
this.windowKeyEventsSubscription = this.windowKeyEvents$.subscribe((event: KeyboardEvent) => {
|
||||
const activeElementIndex = this.options.toArray().findIndex((o) => o.focused);
|
||||
this.windowKeyEventsSubscription = this.windowKeyEvents$.subscribe(
|
||||
(event: KeyboardEvent) => {
|
||||
const activeElementIndex = this.options
|
||||
.toArray()
|
||||
.findIndex((o) => o.focused);
|
||||
|
||||
if (event.code === 'ArrowUp' || event.code === 'ArrowDown') {
|
||||
let nextElementIndex = activeElementIndex;
|
||||
if (event.code === 'ArrowUp') {
|
||||
if (activeElementIndex > 0) {
|
||||
nextElementIndex--;
|
||||
if (event.code === 'ArrowUp' || event.code === 'ArrowDown') {
|
||||
let nextElementIndex = activeElementIndex;
|
||||
if (event.code === 'ArrowUp') {
|
||||
if (activeElementIndex > 0) {
|
||||
nextElementIndex--;
|
||||
}
|
||||
} else if (event.code === 'ArrowDown') {
|
||||
if (activeElementIndex + 1 < this.options.length) {
|
||||
nextElementIndex++;
|
||||
}
|
||||
}
|
||||
} else if (event.code === 'ArrowDown') {
|
||||
if (activeElementIndex + 1 < this.options.length) {
|
||||
nextElementIndex++;
|
||||
const option = this.options.find(
|
||||
(item, index) => nextElementIndex === index
|
||||
);
|
||||
if (option) {
|
||||
option.focus();
|
||||
}
|
||||
}
|
||||
const option = this.options.find((item, index) => nextElementIndex === index);
|
||||
if (option) {
|
||||
option.focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
unsubscribeKeyboardEvents() {
|
||||
|
||||
5
apps/sales/src/app/modules/ui/select-input/index.ts
Normal file
5
apps/sales/src/app/modules/ui/select-input/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
// start:ng42.barrel
|
||||
export * from './select-input.component';
|
||||
export * from './select-input.module';
|
||||
// end:ng42.barrel
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<div class="isa-form-field">
|
||||
<div class="d-flex" (click)="dropdown.toggle()">
|
||||
<label>
|
||||
{{ label }}
|
||||
</label>
|
||||
|
||||
<span
|
||||
class="selected isa-font-weight-bold isa-white-space-nowrap">{{ labelPipe ? labelPipe.transform(value) : value }}
|
||||
</span>
|
||||
<lib-icon class="isa-accordion-arrow" [class.arrow-up]="dropdown.visible" [class.arrow-down]="!dropdown.visible"
|
||||
name="Arrow_right" [height]="'16px'"></lib-icon>
|
||||
</div>
|
||||
<app-ui-dropdown #dropdown>
|
||||
<button (click)="handleSelect({ selectedOption: option, dropdown: dropdown })" (blur)="handleBlur()"
|
||||
class="isa-btn isa-text-left isa-p-16" [class.selected]="value === option"
|
||||
*ngFor="let option of options; let index = index">
|
||||
{{ optionsPipe ? optionsPipe.transform(option, index) : option }}
|
||||
</button>
|
||||
</app-ui-dropdown>
|
||||
</div>
|
||||
@@ -0,0 +1,31 @@
|
||||
@import 'variables';
|
||||
|
||||
.isa-form-field {
|
||||
.selected {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
label {
|
||||
width: max-content;
|
||||
}
|
||||
}
|
||||
|
||||
:host ::ng-deep {
|
||||
app-ui-dropdown {
|
||||
margin-left: 20px;
|
||||
.dropdown {
|
||||
left: 0;
|
||||
width: fit-content;
|
||||
max-height: 250px;
|
||||
|
||||
button {
|
||||
padding: none;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.selected {
|
||||
background: $isa-light-blue-platinum;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import { Component, ChangeDetectionStrategy, Input, forwardRef, Pipe, PipeTransform } from '@angular/core';
|
||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
import { UiDropdownComponent } from '@isa-ui/dropdown';
|
||||
|
||||
@Component({
|
||||
selector: 'app-ui-select-input',
|
||||
templateUrl: 'select-input.component.html',
|
||||
styleUrls: ['./select-input.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: forwardRef(() => UiSelectInputComponent),
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
})
|
||||
export class UiSelectInputComponent implements ControlValueAccessor {
|
||||
@Input() public options: string[] = [];
|
||||
@Input() label = '';
|
||||
@Input() labelPipe: PipeTransform;
|
||||
@Input() optionsPipe: PipeTransform;
|
||||
@Input() valuePipe: PipeTransform;
|
||||
|
||||
constructor() {}
|
||||
|
||||
public value: string;
|
||||
public editable = true;
|
||||
|
||||
private onChange: (value: string) => void;
|
||||
private onBlur: () => void;
|
||||
|
||||
handleSelect({ selectedOption, dropdown }: { selectedOption: string; dropdown: UiDropdownComponent }) {
|
||||
this.value = this.valuePipe ? this.valuePipe.transform(selectedOption) : selectedOption;
|
||||
this.onChange(this.value);
|
||||
dropdown.close();
|
||||
}
|
||||
|
||||
handleBlur() {
|
||||
this.onBlur();
|
||||
}
|
||||
|
||||
writeValue(val: string): void {
|
||||
this.value = val;
|
||||
}
|
||||
|
||||
registerOnChange(fn: any): void {
|
||||
this.onChange = fn;
|
||||
}
|
||||
registerOnTouched(fn: any): void {
|
||||
this.onBlur = fn;
|
||||
}
|
||||
setDisabledState(isDisabled: boolean): void {
|
||||
this.editable = !isDisabled;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { UiSelectInputComponent } from './select-input.component';
|
||||
import { UiDropdownModule } from '@isa-ui/dropdown';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { IconModule } from '@libs/ui';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, FormsModule, UiDropdownModule, IconModule],
|
||||
exports: [UiSelectInputComponent],
|
||||
declarations: [UiSelectInputComponent],
|
||||
providers: [],
|
||||
})
|
||||
export class UiSelectInputModule {}
|
||||
5
apps/sales/src/app/modules/ui/text-input/index.ts
Normal file
5
apps/sales/src/app/modules/ui/text-input/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
// start:ng42.barrel
|
||||
export * from './text-input.component.component';
|
||||
export * from './text-input.component.module';
|
||||
// end:ng42.barrel
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
import {
|
||||
Component,
|
||||
ChangeDetectionStrategy,
|
||||
forwardRef,
|
||||
Input,
|
||||
ChangeDetectorRef,
|
||||
} from '@angular/core';
|
||||
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
|
||||
import { asyncScheduler } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'app-ui-text-input',
|
||||
templateUrl: './text-input.component.html',
|
||||
styleUrls: ['./text-input.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: forwardRef(() => UiTextInputComponent),
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
})
|
||||
export class UiTextInputComponent implements ControlValueAccessor {
|
||||
@Input() label = '';
|
||||
@Input() suffix: string;
|
||||
@Input() placeholder = '';
|
||||
|
||||
constructor(private cdr: ChangeDetectorRef) {}
|
||||
|
||||
public value: string;
|
||||
public editable = true;
|
||||
public touched = false;
|
||||
public focussed = false;
|
||||
|
||||
private onChange: (value: string) => void;
|
||||
private onTouched: () => void;
|
||||
|
||||
handleInput() {
|
||||
this.onChange(this.value);
|
||||
}
|
||||
|
||||
handleBlur() {
|
||||
asyncScheduler.schedule(() => this.handleFocus(false));
|
||||
this.onTouched();
|
||||
}
|
||||
|
||||
handleFocus(isFocussed: boolean) {
|
||||
if (isFocussed) {
|
||||
this.touched = true;
|
||||
}
|
||||
this.focussed = isFocussed;
|
||||
// this.cdr.detectChanges();
|
||||
}
|
||||
|
||||
writeValue(val: string): void {
|
||||
this.value = val;
|
||||
}
|
||||
registerOnChange(fn: any): void {
|
||||
this.onChange = fn;
|
||||
}
|
||||
registerOnTouched(fn: any): void {
|
||||
this.onTouched = fn;
|
||||
}
|
||||
setDisabledState(isDisabled: boolean): void {
|
||||
this.editable = !isDisabled;
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.writeValue('');
|
||||
this.onChange('');
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user