mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-31 09:37:15 +01:00
Merged PR 1226: #3061 Remission List Performance
#3061 Remission List Performance
This commit is contained in:
committed by
Andreas Schickinger
parent
08fefb1c4b
commit
ec2bd0bd5d
@@ -86,23 +86,29 @@
|
||||
|
||||
<ng-container *ngIf="!!returnDto; else removeItem">
|
||||
<div class="grid grid-flow-col justify-self-end gap-2 items-center">
|
||||
<button *ngIf="enableChangeRemissionQuantity" class="text-brand text-base font-bold px-6 py-3" (click)="addProductToShippingDocument()">
|
||||
Remi-Menge / Platzierung ändern
|
||||
<button
|
||||
[disabled]="loading$ | async"
|
||||
*ngIf="enableChangeRemissionQuantity"
|
||||
class="text-brand text-base font-bold px-6 py-3"
|
||||
(click)="addProductToShippingDocument()"
|
||||
>
|
||||
<ui-spinner [show]="loading$ | async">Remi-Menge / Platzierung ändern</ui-spinner>
|
||||
</button>
|
||||
<button
|
||||
*ngIf="enableToRemit"
|
||||
[disabled]="loading$ | async"
|
||||
class="bg-white border-brand border-solid border-2 text-brand font-bold text-base px-6 py-3 rounded-full h-12"
|
||||
(click)="remit()"
|
||||
>
|
||||
Remittieren
|
||||
<ui-spinner [show]="loading$ | async">Remittieren</ui-spinner>
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-template #removeItem>
|
||||
<div *ngIf="item?.dto?.source === 'manually-added'" class="grid grid-flow-col justify-self-end gap-2">
|
||||
<button class="text-brand text-base font-bold px-6 py-3" (click)="removeReturnItem()">
|
||||
Entfernen
|
||||
<button [disabled]="loading$ | async" class="text-brand text-base font-bold px-6 py-3" (click)="removeReturnItem()">
|
||||
<ui-spinner [show]="loading$ | async">Entfernen</ui-spinner>
|
||||
</button>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
import { Component, ChangeDetectionStrategy, Input, OnDestroy, EventEmitter, Output } from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy, Input, OnDestroy } from '@angular/core';
|
||||
import { DomainRemissionService, RemissionListItem } from '@domain/remission';
|
||||
import { RemissionPlacementType } from '@isa/remission';
|
||||
import { ReturnDTO } from '@swagger/remi';
|
||||
import {
|
||||
ReturnDTO,
|
||||
ValueTupleOfReceiptItemDTOAndReturnItemDTO,
|
||||
ValueTupleOfReceiptItemDTOAndReturnSuggestionDTO,
|
||||
ReturnItemDTO,
|
||||
ReturnSuggestionDTO,
|
||||
} from '@swagger/remi';
|
||||
import { UiDialogModalComponent, UiErrorModalComponent, UiModalService } from '@ui/modal';
|
||||
import { Subject } from 'rxjs';
|
||||
import { mapFromReturnItemDTO, mapFromReturnSuggestionDTO } from 'apps/domain/remission/src/lib/mappings';
|
||||
import { BehaviorSubject, Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { AddProductToShippingDocumentModalComponent } from '../../modals/add-product-to-shipping-document-modal/add-product-to-shipping-document-modal.component';
|
||||
import { RemissionListComponentStore } from '../remission-list.component-store';
|
||||
@@ -39,6 +46,8 @@ export class RemissionListItemComponent implements OnDestroy {
|
||||
return this.enableToRemit ? this.item.inStock > 0 && this.item.remissionQuantity > 0 : this.item.remissionQuantity > 0;
|
||||
}
|
||||
|
||||
loading$ = new BehaviorSubject<boolean>(false);
|
||||
|
||||
constructor(
|
||||
private _modal: UiModalService,
|
||||
private _remissionService: DomainRemissionService,
|
||||
@@ -99,19 +108,20 @@ export class RemissionListItemComponent implements OnDestroy {
|
||||
}
|
||||
|
||||
async removeReturnItem() {
|
||||
this.loading$.next(true);
|
||||
try {
|
||||
this._store.clearItems();
|
||||
this._store.setFetching(true);
|
||||
await this._remissionService.removeReturnItemFromList({ itemId: this.item?.dto?.id }).toPromise();
|
||||
this._store.removeItem(this.item);
|
||||
} catch (err) {
|
||||
this._modal.open({
|
||||
content: UiErrorModalComponent,
|
||||
title: 'Fehler beim entfernen eines Artikels von der Remissionsliste',
|
||||
data: err?.status === 404 ? { message: 'Artikel wurde bereits entfernt.' } : err,
|
||||
});
|
||||
}
|
||||
this.reload();
|
||||
}
|
||||
this.loading$.next(false);
|
||||
}
|
||||
|
||||
async addReturnItemOrSuggestion({
|
||||
quantity,
|
||||
@@ -124,13 +134,13 @@ export class RemissionListItemComponent implements OnDestroy {
|
||||
impedimentComment?: string;
|
||||
remainingQuantity?: number;
|
||||
}) {
|
||||
this.loading$.next(true);
|
||||
try {
|
||||
this._store.clearItems();
|
||||
this._store.setFetching(true);
|
||||
let response: ValueTupleOfReceiptItemDTOAndReturnItemDTO | ValueTupleOfReceiptItemDTOAndReturnSuggestionDTO;
|
||||
|
||||
// Pflichtremission
|
||||
if (this.item.dtoType === 'return') {
|
||||
await this._remissionService
|
||||
response = await this._remissionService
|
||||
.addReturnItem({
|
||||
returnId: this.returnDto.id,
|
||||
receiptId: this.firstReceipt.id,
|
||||
@@ -143,7 +153,7 @@ export class RemissionListItemComponent implements OnDestroy {
|
||||
}
|
||||
// Abteilungsremission
|
||||
else if (this.item.dtoType === 'suggestion') {
|
||||
await this._remissionService
|
||||
response = await this._remissionService
|
||||
.addReturnSuggestion({
|
||||
returnId: this.returnDto.id,
|
||||
receiptId: this.firstReceipt.id,
|
||||
@@ -155,23 +165,29 @@ export class RemissionListItemComponent implements OnDestroy {
|
||||
remainingQuantity,
|
||||
})
|
||||
.toPromise();
|
||||
} else {
|
||||
throw new Error('Item hat keinen passenden DTO Typ');
|
||||
}
|
||||
|
||||
this._store.removeItem(this.item);
|
||||
if (response && !!response?.item2) {
|
||||
this.addItem(response.item2);
|
||||
}
|
||||
this._store.updateCache();
|
||||
} catch (err) {
|
||||
this._modal.open({
|
||||
content: UiErrorModalComponent,
|
||||
title: 'Fehler beim remittieren',
|
||||
data: err?.status === 409 ? { message: 'Artikel wurde bereits remittiert.' } : err,
|
||||
});
|
||||
}
|
||||
|
||||
this.reload();
|
||||
}
|
||||
this.loading$.next(false);
|
||||
}
|
||||
|
||||
async returnImpediment() {
|
||||
this.loading$.next(true);
|
||||
try {
|
||||
this._store.clearItems();
|
||||
this._store.setFetching(true);
|
||||
|
||||
// Pflichtremission
|
||||
if (this.item.dtoType === 'return') {
|
||||
await this._remissionService.returnImpediment(this.item.dto?.id).toPromise();
|
||||
@@ -181,17 +197,32 @@ export class RemissionListItemComponent implements OnDestroy {
|
||||
await this._remissionService.returnSuggestion(this.item.dto?.id).toPromise();
|
||||
}
|
||||
|
||||
this.reload();
|
||||
this._store.removeItem(this.item);
|
||||
this._store.updateCache();
|
||||
} catch (err) {
|
||||
this._modal.open({
|
||||
content: UiErrorModalComponent,
|
||||
title: 'Fehler bei Artikel nicht gefunden',
|
||||
data: err,
|
||||
});
|
||||
this.reload();
|
||||
}
|
||||
this.loading$.next(false);
|
||||
}
|
||||
|
||||
reload() {
|
||||
this._store.search({ newSearch: true });
|
||||
}
|
||||
|
||||
addItem(responseItem: ReturnItemDTO | ReturnSuggestionDTO) {
|
||||
let item: RemissionListItem;
|
||||
if (this.item.dtoType === 'return') {
|
||||
item = mapFromReturnItemDTO(responseItem);
|
||||
} else if (this.item.dtoType === 'suggestion') {
|
||||
item = mapFromReturnSuggestionDTO(responseItem);
|
||||
} else {
|
||||
throw new Error('Fehler beim Mapping der DTO');
|
||||
}
|
||||
this._store.addItems([item]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,11 +7,13 @@ import { RemissionPipeModule } from '../../pipes';
|
||||
import { UiTooltipModule } from '@ui/tooltip';
|
||||
import { UiCommonModule } from '@ui/common';
|
||||
import { AddProductToShippingDocumentModalModule } from '../../modals/add-product-to-shipping-document-modal/add-product-to-shipping-document-modal.module';
|
||||
import { UiSpinnerModule } from '@ui/spinner';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
UiCommonModule,
|
||||
UiSpinnerModule,
|
||||
ProductImageModule,
|
||||
RemissionPipeModule,
|
||||
UiTooltipModule,
|
||||
|
||||
@@ -7,7 +7,7 @@ import { ComponentStore, tapResponse } from '@ngrx/component-store';
|
||||
import { SupplierDTO } from '@swagger/remi';
|
||||
import { UiFilter } from '@ui/filter';
|
||||
import { BehaviorSubject, combineLatest, Observable, Subject } from 'rxjs';
|
||||
import { debounceTime, filter, switchMap, takeLast, takeUntil, tap, withLatestFrom } from 'rxjs/operators';
|
||||
import { debounceTime, filter, switchMap, takeUntil, tap, withLatestFrom } from 'rxjs/operators';
|
||||
|
||||
export interface RemissionState {
|
||||
suppliers: SupplierDTO[];
|
||||
@@ -159,7 +159,6 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
.subscribe(([change, filter]) => {
|
||||
const data = this.getCachedData();
|
||||
if (change || data.items?.length === 0 || filter) {
|
||||
this.clearItems();
|
||||
this.search({ newSearch: true });
|
||||
}
|
||||
});
|
||||
@@ -168,7 +167,7 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
// tslint:disable: member-ordering
|
||||
loadSuppliers = this.effect(($) =>
|
||||
$.pipe(
|
||||
tap((_) => this.setFetching(true)),
|
||||
tap((_) => (this.getCachedData()?.hits === 0 ? this.setFetching(true) : null)),
|
||||
switchMap((_) =>
|
||||
this._domainRemissionService.getSuppliers().pipe(
|
||||
tapResponse(
|
||||
@@ -182,7 +181,7 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
|
||||
loadSources = this.effect(($) =>
|
||||
$.pipe(
|
||||
tap((_) => this.setFetching(true)),
|
||||
tap((_) => (this.getCachedData()?.hits === 0 ? this.setFetching(true) : null)),
|
||||
switchMap((_) =>
|
||||
this._domainRemissionService.getSources().pipe(
|
||||
tapResponse(
|
||||
@@ -196,7 +195,7 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
|
||||
loadRequiredCapacities = this.effect(($) =>
|
||||
$.pipe(
|
||||
tap((_) => this.setFetching(true)),
|
||||
tap((_) => (this.getCachedData()?.hits === 0 ? this.setFetching(true) : null)),
|
||||
withLatestFrom(this.selectedSupplier$, this.filter$),
|
||||
switchMap(([_, supplier, filter]) => {
|
||||
let departments = [];
|
||||
@@ -216,7 +215,7 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
|
||||
loadFilter = this.effect(($) =>
|
||||
$.pipe(
|
||||
tap((_) => this.setFetching(true)),
|
||||
tap((_) => (this.getCachedData()?.hits === 0 ? this.setFetching(true) : null)),
|
||||
withLatestFrom(this.selectedSupplier$, this.selectedSource$, this._activatedRoute.queryParams),
|
||||
filter(([, selectedSupplier, selectedSource]) => !!selectedSupplier?.id && !!selectedSource),
|
||||
switchMap(([, selectedSupplier, selectedSource, queryParams]) =>
|
||||
@@ -247,7 +246,10 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
|
||||
search = this.effect((options$: Observable<{ newSearch?: boolean }>) =>
|
||||
options$.pipe(
|
||||
tap((_) => this.setFetching(true)),
|
||||
tap((options) => {
|
||||
this.setFetching(true);
|
||||
options?.newSearch ? this.setSearchResult({ result: [], hits: 0 }) : null;
|
||||
}),
|
||||
withLatestFrom(this.filter$, this.selectedSource$, this.selectedSupplier$, this.searchOptions$, this.items$),
|
||||
filter(([, filter, source, supplier]) => !!supplier?.id && !!source && !!filter),
|
||||
switchMap(([options, filter, source, supplier, searchOptions, items]) =>
|
||||
@@ -256,7 +258,7 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
queryToken: {
|
||||
...filter?.getQueryToken(),
|
||||
skip: options?.newSearch ? 0 : searchOptions?.skip ?? items?.length,
|
||||
take: searchOptions?.take ?? 20,
|
||||
take: searchOptions?.take ?? 40,
|
||||
},
|
||||
source,
|
||||
supplierId: supplier.id,
|
||||
@@ -268,6 +270,7 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
? { result: [...res.result], hits: res.hits ?? 0 }
|
||||
: { result: [...(items ?? []), ...(res.result ?? [])], hits: res.hits ?? 0 };
|
||||
this.setSearchResult(results);
|
||||
this.setFetching(false);
|
||||
this._searchCompleted.next(this.get());
|
||||
},
|
||||
(err) => {}
|
||||
@@ -286,7 +289,6 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
...state,
|
||||
items: result,
|
||||
hits,
|
||||
fetching: false,
|
||||
}));
|
||||
|
||||
setSuppliers = this.updater<SupplierDTO[]>((state, suppliers) => ({
|
||||
@@ -333,9 +335,16 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
hits,
|
||||
}));
|
||||
|
||||
addItems = this.updater<RemissionListItem[]>((state, items) => ({
|
||||
...state,
|
||||
items: [...state.items, ...items],
|
||||
hits: state.hits + items.length,
|
||||
}));
|
||||
|
||||
removeItem = this.updater<RemissionListItem>((state, item) => ({
|
||||
...state,
|
||||
items: state.items.filter((i) => i.dto?.id !== item.dto?.id),
|
||||
hits: state.hits - 1,
|
||||
}));
|
||||
|
||||
setRequiredCapacities = this.updater<any>((state, requiredCapacities) => ({
|
||||
@@ -366,9 +375,9 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
this._cache.delete({ processId: String(this.processId) });
|
||||
}
|
||||
|
||||
clearItems() {
|
||||
this.setFetching(true);
|
||||
this.setSearchResult({ result: [], hits: 0 });
|
||||
updateCache() {
|
||||
this.clearCache();
|
||||
this.cacheCurrentData();
|
||||
}
|
||||
|
||||
async applyFilter(filter: UiFilter) {
|
||||
|
||||
@@ -70,6 +70,11 @@ export class RemissionListComponent implements OnInit, OnDestroy {
|
||||
return this._remissionStore.return$;
|
||||
}
|
||||
|
||||
listEmpty$ = combineLatest([this.fetching$, this.hits$]).pipe(
|
||||
map(([loading, hits]) => !loading && hits === 0),
|
||||
shareReplay()
|
||||
);
|
||||
|
||||
get queryParams$() {
|
||||
return this._activatedRoute.queryParams.pipe(
|
||||
withLatestFrom(this._remissionListStore.filter$, this.selectedSupplierId$, this.selectedSource$),
|
||||
@@ -87,7 +92,7 @@ export class RemissionListComponent implements OnInit, OnDestroy {
|
||||
return this._remissionStore.returnCount$;
|
||||
}
|
||||
|
||||
showStartRemissionAction$ = combineLatest([this.hits$, this.return$]).pipe(map(([hits, r]) => hits > 0 && !r));
|
||||
showStartRemissionAction$ = combineLatest([this.listEmpty$, this.return$]).pipe(map(([empty, r]) => !empty && !r));
|
||||
|
||||
filteredSuppliers$ = combineLatest([this._remissionStore.uncompleted$, this.suppliers$, this.selectedSupplier$]).pipe(
|
||||
map(([uncompleted, suppliers, selectedSupplier]) => {
|
||||
@@ -98,11 +103,6 @@ export class RemissionListComponent implements OnInit, OnDestroy {
|
||||
})
|
||||
);
|
||||
|
||||
listEmpty$ = combineLatest([this.fetching$, this.hits$]).pipe(
|
||||
map(([loading, hits]) => !loading && hits === 0),
|
||||
shareReplay()
|
||||
);
|
||||
|
||||
trackByItemId = (item: RemissionListItem) => item?.dto?.id;
|
||||
|
||||
showScrollArrow$ = new BehaviorSubject<boolean>(false);
|
||||
|
||||
Reference in New Issue
Block a user