mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-31 09:37:15 +01:00
Merge branch 'release/1.4' into develop
This commit is contained in:
@@ -53,7 +53,9 @@ export class ArticleDetailsStore extends ComponentStore<ArticleDetailsState> {
|
||||
|
||||
readonly recommendations$ = this.item$.pipe(
|
||||
filter((item) => !!item),
|
||||
switchMap((item) => this.domainCatalogService.getRecommendations({ digId: item.ids['dig'] }).pipe(map((res) => res.result)))
|
||||
switchMap((item) =>
|
||||
item.ids?.dig ? this.domainCatalogService.getRecommendations({ digId: item.ids['dig'] }).pipe(map((res) => res.result)) : of([])
|
||||
)
|
||||
);
|
||||
|
||||
//#region Lesepunkte
|
||||
|
||||
@@ -8,18 +8,24 @@
|
||||
Artikel
|
||||
</span>
|
||||
|
||||
<ui-slider [scrollDistance]="210">
|
||||
<a
|
||||
class="article"
|
||||
*ngFor="let recommendation of store.recommendations$ | async"
|
||||
[routerLink]="['/product', 'details', 'ean', recommendation.product.ean]"
|
||||
(click)="close.emit()"
|
||||
>
|
||||
<img [src]="recommendation.images[0]?.url" alt="product-image" />
|
||||
<ng-container *ngIf="store.recommendations$ | async; let recommendations">
|
||||
<span *ngIf="recommendations.length === 0" class="empty-message">
|
||||
Keine Empfehlungen verfügbar
|
||||
</span>
|
||||
|
||||
<span class="format">{{ recommendation.product?.formatDetail }}</span>
|
||||
<span class="price">{{ recommendation.catalogAvailability?.price?.value?.value | currency: ' ' }} EUR</span>
|
||||
</a>
|
||||
</ui-slider>
|
||||
<ui-slider *ngIf="recommendations.length > 0" [scrollDistance]="210">
|
||||
<a
|
||||
class="article"
|
||||
*ngFor="let recommendation of store.recommendations$ | async"
|
||||
[routerLink]="['/product', 'details', 'ean', recommendation.product.ean]"
|
||||
(click)="close.emit()"
|
||||
>
|
||||
<img [src]="recommendation.images[0]?.url" alt="product-image" />
|
||||
|
||||
<span class="format">{{ recommendation.product?.formatDetail }}</span>
|
||||
<span class="price">{{ recommendation.catalogAvailability?.price?.value?.value | currency: ' ' }} EUR</span>
|
||||
</a>
|
||||
</ui-slider>
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
@@ -26,6 +26,10 @@ p {
|
||||
}
|
||||
}
|
||||
|
||||
.empty-message {
|
||||
@apply flex justify-center text-cta-l mt-12;
|
||||
}
|
||||
|
||||
.article {
|
||||
@apply flex flex-col mr-7 mt-4 no-underline text-black;
|
||||
|
||||
|
||||
@@ -231,11 +231,11 @@ export class CustomerCreateOnlineComponent extends CustomerCreateComponentBase i
|
||||
this.router.navigate(['/customer', response.result.id]);
|
||||
}
|
||||
} catch (error) {
|
||||
if (error?.error?.invalidProperties?.Email) {
|
||||
if (error?.error?.invalidProperties?.Email || error?.error?.invalidProperties?.email) {
|
||||
this.addInvalidDomain(this.control.value.communicationDetails?.email);
|
||||
this.enableControl();
|
||||
} else {
|
||||
this.setValidationError(error.error?.invalidProperties, this.control);
|
||||
this.setValidationError(error?.error?.invalidProperties, this.control);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,21 +55,17 @@ export class BookCardComponent implements OnInit {
|
||||
path: '/dashboard',
|
||||
};
|
||||
|
||||
const path = '/product/details/' + ean;
|
||||
const queryParams = { type: 'ean' };
|
||||
const path = '/product/details/ean/' + ean;
|
||||
const newBread: Breadcrumb = {
|
||||
name: name.substring(0, 12) + (name.length > 12 ? '...' : ''),
|
||||
path,
|
||||
queryParams,
|
||||
};
|
||||
|
||||
this.store.dispatch(new PopBreadcrumbsBeforeCurrent('product'));
|
||||
this.store.dispatch(new AddBreadcrumb(dashboardBread, 'product'));
|
||||
this.store.dispatch(new AddBreadcrumb(newBread, 'product'));
|
||||
this.store.dispatch(new ChangeCurrentRoute(path, false, queryParams));
|
||||
this.router.navigate([path], {
|
||||
queryParams,
|
||||
});
|
||||
this.store.dispatch(new ChangeCurrentRoute(path, false));
|
||||
this.router.navigate([path]);
|
||||
}
|
||||
|
||||
createProcess() {
|
||||
|
||||
@@ -29,10 +29,8 @@
|
||||
>
|
||||
</app-remission-list-card-started>
|
||||
</ng-container>
|
||||
<ng-template #loadingComponent>
|
||||
<app-remission-list-card-loading></app-remission-list-card-loading>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
<app-remission-list-card-loading #loadingComponent *ngIf="!(isLoading$ | async) && !isFullListLoaded"></app-remission-list-card-loading>
|
||||
<ng-template #spinner>
|
||||
<div class="spinner"></div>
|
||||
</ng-template>
|
||||
|
||||
@@ -48,7 +48,7 @@ export class RemissionListComponent implements OnInit, OnDestroy {
|
||||
scrollDistance = 1;
|
||||
scrollUpDistance = 2;
|
||||
page = 0;
|
||||
pageSize = 10;
|
||||
pageSize = 20;
|
||||
totalHits = 0;
|
||||
isItRefetch = false;
|
||||
isFullLoad = false;
|
||||
@@ -98,7 +98,7 @@ export class RemissionListComponent implements OnInit, OnDestroy {
|
||||
|
||||
subscribeToFetchLastProducts() {
|
||||
this.fetchLastProducts$.pipe(takeUntil(this.destroy$)).subscribe((_) => {
|
||||
// Increase number of takes to show all residual products (currently: 10)
|
||||
// Increase number of takes to show all residual products (currently: 20)
|
||||
const takeParam = this.pageSize;
|
||||
const skipParam = Math.max(0, this.totalHits - takeParam);
|
||||
|
||||
|
||||
@@ -349,15 +349,15 @@ export class RemissionProductListComponent implements OnInit, OnDestroy, AfterVi
|
||||
}
|
||||
|
||||
subscribeToIntersectionObservers() {
|
||||
combineLatest(
|
||||
combineLatest([
|
||||
this.isNumberOfHitsVisible$,
|
||||
this.isShippingDocumentVisible$,
|
||||
this.remissionProductsData$.pipe(
|
||||
map((data) => data.hits),
|
||||
distinctUntilChanged()
|
||||
),
|
||||
this.isLoading$
|
||||
)
|
||||
this.isLoading$,
|
||||
])
|
||||
.pipe(
|
||||
map(([isNumberOfHitsVisible, isShippingDocumentVisible, hits, isLoading]) => {
|
||||
if (!hits || hits === -1 || !!isLoading) {
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
@@ -24,7 +24,7 @@
|
||||
<app-ui-text-input formControlName="supplier" label="Lieferant"></app-ui-text-input>
|
||||
<hr class="isa-content-spacer" />
|
||||
|
||||
<app-ui-text-input formControlName="ssc" [suffix]="sscText" label="Meldenummer"></app-ui-text-input>
|
||||
<app-ui-text-input formControlName="ssc" [suffix]="sscText" label="Meldenummer *"></app-ui-text-input>
|
||||
<hr class="isa-content-spacer" />
|
||||
|
||||
<app-ui-select-input
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Component, OnInit, ChangeDetectionStrategy, Input, Inject, Output, EventEmitter, OnDestroy } from '@angular/core';
|
||||
import { OrderItemListItemDTO } from '@swagger/oms';
|
||||
import { CDN_PRODUCT_PICTURES } from 'apps/sales/src/app/tokens';
|
||||
import { isEqual } from 'lodash';
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
@@ -45,12 +46,17 @@ export class SearchResultGroupItemComponent implements OnInit, OnDestroy {
|
||||
return (
|
||||
this.item.processingStatus !== item.processingStatus ||
|
||||
this.item.targetBranchId !== item.targetBranchId ||
|
||||
this.item.paymentStatus != item.paymentStatus
|
||||
this.item.paymentStatus != item.paymentStatus ||
|
||||
!isEqual(this.getQuickActions(this.item), this.getQuickActions(item))
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
getQuickActions(item: OrderItemListItemDTO) {
|
||||
return item?.actions?.filter((a) => a.enabled == undefined && a.command !== 'FETCHED_PARTIAL') || [];
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (this.setSelectionSubscribtion) {
|
||||
this.setSelectionSubscribtion.unsubscribe();
|
||||
|
||||
@@ -19,23 +19,14 @@
|
||||
></app-loading>
|
||||
</div>
|
||||
|
||||
<div class="actions" *ngIf="checkedItems.length > 0">
|
||||
<div class="actions" *ngIf="quickActions.length">
|
||||
<button
|
||||
*ngIf="pickUpAndPrintActionVisible"
|
||||
class="isa-btn isa-btn-primary isa-btn-pill isa-btn-xl"
|
||||
(click)="pickUpAndPrintClick()"
|
||||
(click)="handleAction(action)"
|
||||
[disabled]="statusChangeInProgress$ | async"
|
||||
*ngFor="let action of quickActions"
|
||||
>
|
||||
<span>abgeholt und Lieferschein drucken</span>
|
||||
<div class="spinner isa-btn-loader" *ngIf="statusChangeInProgress$ | async"></div>
|
||||
</button>
|
||||
<button
|
||||
*ngIf="pickUpActionVisible"
|
||||
class="isa-btn isa-btn-primary isa-btn-pill isa-btn-xl"
|
||||
(click)="pickUpClick()"
|
||||
[disabled]="statusChangeInProgress$ | async"
|
||||
>
|
||||
<span>abgeholt</span>
|
||||
<span>{{ action.label }}</span>
|
||||
<div class="spinner isa-btn-loader" *ngIf="statusChangeInProgress$ | async"></div>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -4,13 +4,19 @@ import { Component, OnDestroy, OnInit, ViewChild, ElementRef, ChangeDetectionStr
|
||||
import { SearchStateFacade } from 'apps/sales/src/app/store/customer';
|
||||
import { first, takeUntil, map, withLatestFrom } from 'rxjs/operators';
|
||||
import { Group, groupBy } from 'apps/sales/src/app/utils';
|
||||
import { OrderItemListItemDTO } from '@swagger/oms';
|
||||
import { KeyValueDTOOfStringAndString, OrderItemListItemDTO, ReceiptDTO } from '@swagger/oms';
|
||||
import { ShelfNavigationService } from '../../shared/services';
|
||||
import { Select } from '@ngxs/store';
|
||||
import { ProcessSelectors } from 'apps/sales/src/app/core/store/selectors/process.selectors';
|
||||
import { ORDER_DETAILS_PREFIX } from './order-details-prefix';
|
||||
import { ShelfOrderDetailsService, ShelfShippingNoteService } from '../../services';
|
||||
import {
|
||||
ShelfAbholfachEtikettService,
|
||||
ShelfActionHandlerService,
|
||||
ShelfOrderDetailsService,
|
||||
ShelfShippingNoteService,
|
||||
} from '../../services';
|
||||
import { PrinterSelectionComponent } from 'apps/sales/src/app/components/printer-selection/printer-selection.component';
|
||||
import { UiMessageModalComponent, UiModalService } from '@ui/modal';
|
||||
|
||||
@Component({
|
||||
selector: 'app-shelf-search-results',
|
||||
@@ -67,11 +73,18 @@ export class ShelfSearchResultsComponent implements OnInit, OnDestroy {
|
||||
};
|
||||
}
|
||||
|
||||
get quickActions() {
|
||||
return this.getQuickActions(this.checkedItems?.find((f) => !!f));
|
||||
}
|
||||
|
||||
constructor(
|
||||
private searchStateFacade: SearchStateFacade,
|
||||
private shelfNavigationService: ShelfNavigationService,
|
||||
private orderDetailsService: ShelfOrderDetailsService,
|
||||
private shippingNoteService: ShelfShippingNoteService
|
||||
private shippingNoteService: ShelfShippingNoteService,
|
||||
private actionHandlerService: ShelfActionHandlerService,
|
||||
private abholfachEtikettService: ShelfAbholfachEtikettService,
|
||||
private modal: UiModalService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -80,6 +93,10 @@ export class ShelfSearchResultsComponent implements OnInit, OnDestroy {
|
||||
this.initFetch();
|
||||
}
|
||||
|
||||
getQuickActions(item: OrderItemListItemDTO) {
|
||||
return item?.actions?.filter((a) => a.enabled == undefined && a.command !== 'FETCHED_PARTIAL') || [];
|
||||
}
|
||||
|
||||
refreshCheckedState() {
|
||||
setTimeout(() => {
|
||||
this.checkedItems.forEach((i) => {
|
||||
@@ -151,35 +168,6 @@ export class ShelfSearchResultsComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
async pickUpClick() {
|
||||
if (this.checkedItems.length <= 0) return;
|
||||
this.statusChangeInProgress$.next(true);
|
||||
|
||||
await this.orderDetailsService.setProcessingStatus(this.checkedItems, 256, {});
|
||||
await this.searchStateFacade.reloadResults();
|
||||
|
||||
this.statusChangeInProgress$.next(false);
|
||||
this.checkedItems.splice(0, this.checkedItems.length);
|
||||
}
|
||||
|
||||
async pickUpAndPrintClick() {
|
||||
if (this.checkedItems.length <= 0) return;
|
||||
this.statusChangeInProgress$.next(true);
|
||||
|
||||
await this.orderDetailsService.setProcessingStatus(this.checkedItems, 256, {});
|
||||
|
||||
let receipts = await this.shippingNoteService.create(
|
||||
this.shippingNoteService.getSubsetIdsForWhichToCreateShippingNotes(this.checkedItems),
|
||||
this.printData
|
||||
);
|
||||
|
||||
if (await this.shippingNoteService.print(receipts, this.printData)) {
|
||||
await this.searchStateFacade.reloadResults();
|
||||
}
|
||||
this.statusChangeInProgress$.next(false);
|
||||
this.checkedItems.splice(0, this.checkedItems.length);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
}
|
||||
@@ -191,4 +179,55 @@ export class ShelfSearchResultsComponent implements OnInit, OnDestroy {
|
||||
private isFromSearchPage(): boolean {
|
||||
return !!window && !!window.history && !!window.history.state['fromSearch'];
|
||||
}
|
||||
|
||||
async handleAction(action: KeyValueDTOOfStringAndString) {
|
||||
this.statusChangeInProgress$.next(true);
|
||||
|
||||
try {
|
||||
const groupedByOrderId = groupBy(this.checkedItems, (i) => i.orderId);
|
||||
|
||||
for (const order of groupedByOrderId) {
|
||||
let receipts: ReceiptDTO[];
|
||||
|
||||
for (const command of this.actionHandlerService.getActions(action)) {
|
||||
if (this.actionHandlerService.shouldDetermineSupplier(command)) {
|
||||
await this.orderDetailsService.setDetermineSupplier(order.items);
|
||||
}
|
||||
|
||||
if (this.actionHandlerService.getActionIsStatusChange(command)) {
|
||||
const targetStatus = this.actionHandlerService.getNewProcessingStatus(command);
|
||||
await this.orderDetailsService.setProcessingStatus(order.items, targetStatus, {});
|
||||
}
|
||||
|
||||
if (this.actionHandlerService.shouldCreateShippingNote(command)) {
|
||||
receipts = await this.shippingNoteService.create(
|
||||
this.shippingNoteService.getSubsetIdsForWhichToCreateShippingNotes(order.items),
|
||||
this.printData
|
||||
);
|
||||
}
|
||||
|
||||
if (this.actionHandlerService.shouldPrintShippingNote(command) && receipts?.length) {
|
||||
await this.shippingNoteService.print(receipts, this.printData);
|
||||
}
|
||||
|
||||
if (this.actionHandlerService.shouldPrintAbholfachetikett(command)) {
|
||||
await this.abholfachEtikettService.print(
|
||||
this.abholfachEtikettService.orderSubsetIdsForWhichToPrintAbholfachEtikett(order.items),
|
||||
this.printData
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await this.searchStateFacade.reloadResults();
|
||||
} catch (error) {
|
||||
this.modal.open({
|
||||
content: UiMessageModalComponent,
|
||||
data: { message: 'Fehler beim ändern des Status.' },
|
||||
});
|
||||
}
|
||||
|
||||
this.statusChangeInProgress$.next(false);
|
||||
this.checkedItems.splice(0, this.checkedItems.length);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,13 +11,13 @@ export class ShelfActionHandlerService {
|
||||
}
|
||||
|
||||
public getActionIsStatusChange(command: string) {
|
||||
const match = actionCommands[command];
|
||||
|
||||
return typeof match === 'number';
|
||||
const commands = this.getActions({ command });
|
||||
return commands.map((c) => actionCommands[c]).some((f) => typeof f === 'number');
|
||||
}
|
||||
|
||||
public getNewProcessingStatus(command: string): number {
|
||||
return actionCommands[command];
|
||||
const commands = this.getActions({ command });
|
||||
return commands.map((c) => actionCommands[c]).find((f) => typeof f === 'number');
|
||||
}
|
||||
|
||||
public isPartialPickup(action: KeyValueDTOOfStringAndString): boolean {
|
||||
@@ -37,15 +37,15 @@ export class ShelfActionHandlerService {
|
||||
}
|
||||
|
||||
public shouldCreateShippingNote(command: string): boolean {
|
||||
return command === additionalCommands.CREATE_SHIPPINGNOTE;
|
||||
return command.includes(additionalCommands.CREATE_SHIPPINGNOTE);
|
||||
}
|
||||
|
||||
public shouldDetermineSupplier(command: string): boolean {
|
||||
return command === additionalCommands.ORDER_AT_SUPPLIER;
|
||||
return command.includes(additionalCommands.ORDER_AT_SUPPLIER);
|
||||
}
|
||||
|
||||
public shouldPrintShippingNote(command: string): boolean {
|
||||
return command === additionalCommands.PRINT_SHIPPINGNOTE;
|
||||
return command.includes(additionalCommands.PRINT_SHIPPINGNOTE);
|
||||
}
|
||||
|
||||
public shouldPrintAbholfachetikett(command: string): boolean {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators, FormArray, AbstractControl, ValidationErrors, FormControl } from '@angular/forms';
|
||||
import { Observable } from 'rxjs';
|
||||
import { FormBuilder, FormGroup, Validators, FormArray, AbstractControl, ValidationErrors, FormControl, ValidatorFn } from '@angular/forms';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import {
|
||||
OrderItemListItemDTO,
|
||||
VATDTO,
|
||||
@@ -205,6 +205,7 @@ export class ShelfEditFormService {
|
||||
value: orderItem.product.ean,
|
||||
disabled: false,
|
||||
},
|
||||
[Validators.required],
|
||||
],
|
||||
supplier: [{ value: orderItem.supplier, disabled: true }],
|
||||
title: [{ value: orderItem.product.name, disabled: true }],
|
||||
|
||||
Reference in New Issue
Block a user