mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
Merged PR 1481: Gelbe Seiten - Sortiment - Preisänderung Implementation + Init Unit Tests
Gelbe Seiten - Sortiment - Preisänderung Implementation + Init Unit Tests
This commit is contained in:
committed by
Lorenz Hilpert
parent
55a92ad029
commit
1a72c23412
34
angular.json
34
angular.json
@@ -1600,6 +1600,40 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@domain/product-list": {
|
||||
"projectType": "library",
|
||||
"root": "apps/domain/product-list",
|
||||
"sourceRoot": "apps/domain/product-list/src",
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"project": "apps/domain/product-list/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "apps/domain/product-list/tsconfig.lib.prod.json"
|
||||
},
|
||||
"development": {
|
||||
"tsConfig": "apps/domain/product-list/tsconfig.lib.json"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"tsConfig": "apps/domain/product-list/tsconfig.spec.json",
|
||||
"karmaConfig": "karma.conf.js",
|
||||
"polyfills": [
|
||||
"zone.js",
|
||||
"zone.js/testing"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,17 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { StockInfoDTO } from '@swagger/remi';
|
||||
import { groupBy } from 'lodash';
|
||||
import { BehaviorSubject, combineLatest, Observable, OperatorFunction, Subject, timer } from 'rxjs';
|
||||
import { buffer, bufferTime, bufferWhen, debounceTime } from 'rxjs/operators';
|
||||
import { groupBy, isEqual, uniqWith } from 'lodash';
|
||||
import { BehaviorSubject, combineLatest, Observable, Subject } from 'rxjs';
|
||||
import { buffer, debounceTime, distinctUntilChanged } from 'rxjs/operators';
|
||||
import { DomainAvailabilityService } from './availability.service';
|
||||
|
||||
export type ItemBranch = { itemId: number; branchId: number };
|
||||
export type InStock = ItemBranch & { inStock: number; fetching: boolean };
|
||||
export type InStock = ItemBranch & { inStock: number; compartment: string; fetching: boolean };
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class DomainInStockService {
|
||||
private _inStockQueue = new Subject<ItemBranch>();
|
||||
private _inStockMap = new BehaviorSubject<Record<string, number>>({});
|
||||
private _inStockMap = new BehaviorSubject<Record<string, { inStock: number; compartment: string }>>({});
|
||||
private _inStockFetchingMap = new BehaviorSubject<Record<string, boolean>>({});
|
||||
|
||||
constructor(private _availability: DomainAvailabilityService) {
|
||||
@@ -25,8 +25,9 @@ export class DomainInStockService {
|
||||
}
|
||||
|
||||
private _handleStockDataToFetch = (itemBranchData: ItemBranch[]) => {
|
||||
if (itemBranchData?.length > 0) {
|
||||
this._fetchStockData(itemBranchData);
|
||||
const unique = uniqWith(itemBranchData, isEqual);
|
||||
if (unique?.length > 0) {
|
||||
this._fetchStockData(unique);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -44,16 +45,18 @@ export class DomainInStockService {
|
||||
const key = this.getKey({ itemId, branchId });
|
||||
this._addToInStockQueue({ itemId, branchId });
|
||||
|
||||
const sub = combineLatest([this._inStockMap, this._inStockFetchingMap]).subscribe(([inStockMap, inStockFetchingMap]) => {
|
||||
const inStock: InStock = {
|
||||
itemId,
|
||||
branchId,
|
||||
inStock: inStockMap[key],
|
||||
fetching: inStockFetchingMap[key] ?? false,
|
||||
};
|
||||
|
||||
obs.next(inStock);
|
||||
});
|
||||
const sub = combineLatest([this._inStockMap, this._inStockFetchingMap])
|
||||
.pipe(distinctUntilChanged(isEqual))
|
||||
.subscribe(([inStockMap, inStockFetchingMap]) => {
|
||||
const inStock: InStock = {
|
||||
itemId,
|
||||
branchId,
|
||||
inStock: inStockMap[key]?.inStock,
|
||||
compartment: inStockMap[key]?.compartment,
|
||||
fetching: inStockFetchingMap[key] ?? false,
|
||||
};
|
||||
obs.next(inStock);
|
||||
});
|
||||
return () => {
|
||||
sub.unsubscribe();
|
||||
};
|
||||
@@ -71,10 +74,10 @@ export class DomainInStockService {
|
||||
this._inStockFetchingMap.next({ ...current, [key]: value });
|
||||
}
|
||||
|
||||
private _setInStock({ itemId, branchId }: ItemBranch, value: number) {
|
||||
private _setInStock({ itemId, branchId }: ItemBranch, inStock: number, compartment: string) {
|
||||
const key = this.getKey({ itemId, branchId });
|
||||
const current = this._inStockMap.getValue();
|
||||
this._inStockMap.next({ ...current, [key]: value });
|
||||
this._inStockMap.next({ ...current, [key]: { inStock, compartment } });
|
||||
}
|
||||
|
||||
private _fetchStockData(itemBranchData: ItemBranch[]) {
|
||||
@@ -92,18 +95,23 @@ export class DomainInStockService {
|
||||
itemIds.forEach((itemId) => {
|
||||
const stockInfo = stockInfos.find((stockInfo) => stockInfo.itemId === itemId && stockInfo.branchId === branchId);
|
||||
let inStock = 0;
|
||||
let compartment = '';
|
||||
if (stockInfo?.inStock) {
|
||||
inStock = stockInfo.inStock;
|
||||
}
|
||||
|
||||
if (stockInfo?.compartment) {
|
||||
compartment = stockInfo.compartment;
|
||||
}
|
||||
this._setInStockFetching({ itemId, branchId }, false);
|
||||
this._setInStock({ itemId, branchId }, inStock);
|
||||
this._setInStock({ itemId, branchId }, inStock, compartment);
|
||||
});
|
||||
};
|
||||
|
||||
private _fetchStockDataError = ({ itemIds, branchId }: { itemIds: number[]; branchId: number }) => (error: Error) => {
|
||||
itemIds.forEach((itemId) => {
|
||||
this._setInStockFetching({ itemId, branchId }, false);
|
||||
this._setInStock({ itemId, branchId }, 0);
|
||||
this._setInStock({ itemId, branchId }, 0, '');
|
||||
});
|
||||
console.error('DomainInStockService._fetchStockData()', error);
|
||||
};
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
CheckoutPrintService,
|
||||
ItemDTO,
|
||||
OMSPrintService,
|
||||
PriceQRCodeDTO,
|
||||
PrintRequestOfIEnumerableOfItemDTO,
|
||||
PrintRequestOfIEnumerableOfLong,
|
||||
PrintRequestOfIEnumerableOfPriceQRCodeDTO,
|
||||
@@ -13,6 +12,12 @@ import {
|
||||
ResponseArgs,
|
||||
LoyaltyCardPrintService,
|
||||
} from '@swagger/print';
|
||||
import {
|
||||
DocumentPayloadOfIEnumerableOfProductListItemDTO,
|
||||
ProductListItemDTO,
|
||||
ProductListService,
|
||||
ResponseArgsOfString,
|
||||
} from '@swagger/wws';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { catchError, filter, map, switchMap, timeout } from 'rxjs/operators';
|
||||
import { Printer } from './defs/printer.model';
|
||||
@@ -27,7 +32,8 @@ export class DomainPrinterService {
|
||||
private catalogPrintService: CatalogPrintService,
|
||||
private checkoutPrintService: CheckoutPrintService,
|
||||
private eisPublicDocumentService: EISPublicDocumentService,
|
||||
private _loyaltyCardPrintService: LoyaltyCardPrintService
|
||||
private _loyaltyCardPrintService: LoyaltyCardPrintService,
|
||||
private _productListService: ProductListService
|
||||
) {}
|
||||
|
||||
getAvailablePrinters(): Observable<Printer[] | { error: string }> {
|
||||
@@ -202,6 +208,29 @@ export class DomainPrinterService {
|
||||
});
|
||||
}
|
||||
|
||||
printProductListItemsResponse(payload: DocumentPayloadOfIEnumerableOfProductListItemDTO): Observable<ResponseArgsOfString> {
|
||||
return this._productListService.ProductListProductListItemPdfAsBase64(payload);
|
||||
}
|
||||
|
||||
printProductListItems({
|
||||
data,
|
||||
printer,
|
||||
title,
|
||||
}: {
|
||||
data: ProductListItemDTO[];
|
||||
printer: string;
|
||||
title?: string;
|
||||
}): Observable<ResponseArgs> {
|
||||
return this.printProductListItemsResponse({ data, title }).pipe(
|
||||
switchMap((res) => {
|
||||
if (!res.error) {
|
||||
return this.printPdf({ printer, data: res.result });
|
||||
}
|
||||
return of(res);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
printDisplayInfoDTOArticles({
|
||||
articles,
|
||||
printer,
|
||||
|
||||
25
apps/domain/product-list/README.md
Normal file
25
apps/domain/product-list/README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# ProductList
|
||||
|
||||
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 15.0.0.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name --project product-list` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project product-list`.
|
||||
|
||||
> Note: Don't forget to add `--project product-list` or else it will be added to the default project in your `angular.json` file.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build product-list` to build the project. The build artifacts will be stored in the `dist/` directory.
|
||||
|
||||
## Publishing
|
||||
|
||||
After building your library with `ng build product-list`, go to the dist folder `cd dist/product-list` and run `npm publish`.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test product-list` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
|
||||
7
apps/domain/product-list/ng-package.json
Normal file
7
apps/domain/product-list/ng-package.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"dest": "../../../dist/domain/product-list",
|
||||
"lib": {
|
||||
"entryFile": "src/public-api.ts"
|
||||
}
|
||||
}
|
||||
11
apps/domain/product-list/package.json
Normal file
11
apps/domain/product-list/package.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "@domain/product-list",
|
||||
"version": "0.0.1",
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^15.0.0",
|
||||
"@angular/core": "^15.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
}
|
||||
}
|
||||
4
apps/domain/product-list/src/lib/product-list.module.ts
Normal file
4
apps/domain/product-list/src/lib/product-list.module.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
@NgModule({})
|
||||
export class ProductListModule {}
|
||||
52
apps/domain/product-list/src/lib/product-list.service.ts
Normal file
52
apps/domain/product-list/src/lib/product-list.service.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import {
|
||||
BatchResponseArgsOfProductListItemDTOAndString,
|
||||
ListResponseArgsOfProductListItemDTO,
|
||||
ProductListItemDTO,
|
||||
ProductListService,
|
||||
QuerySettingsDTO,
|
||||
QueryTokenDTO,
|
||||
ResponseArgsOfProductListItemDTO,
|
||||
ResponseArgsOfQuerySettingsDTO,
|
||||
} from '@swagger/wws';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class DomainProductListService {
|
||||
constructor(private _productList: ProductListService) {}
|
||||
|
||||
getQuerySettingsResponse(): Observable<ResponseArgsOfQuerySettingsDTO> {
|
||||
return this._productList.ProductListQueryProductListItemsSettings();
|
||||
}
|
||||
|
||||
getQuerySettings(): Observable<QuerySettingsDTO> {
|
||||
return this.getQuerySettingsResponse().pipe(map((response) => response.result));
|
||||
}
|
||||
|
||||
queryProductListResponse(queryToken: QueryTokenDTO): Observable<ListResponseArgsOfProductListItemDTO> {
|
||||
return this._productList.ProductListQueryProductListItem(queryToken);
|
||||
}
|
||||
|
||||
queryProductList(queryToken: QueryTokenDTO): Observable<ProductListItemDTO[]> {
|
||||
return this.queryProductListResponse(queryToken).pipe(map((response) => response.result));
|
||||
}
|
||||
|
||||
completeProductListItemResponse(productListItemUId: string): Observable<ResponseArgsOfProductListItemDTO> {
|
||||
return this._productList.ProductListProductListItemCompleted(productListItemUId);
|
||||
}
|
||||
|
||||
completeProductListItem(productListItemUId: string): Observable<ProductListItemDTO> {
|
||||
return this.completeProductListItemResponse(productListItemUId).pipe(map((response) => response.result));
|
||||
}
|
||||
|
||||
completeProductListItemsResponse(uids: string[]): Observable<BatchResponseArgsOfProductListItemDTOAndString> {
|
||||
return this._productList.ProductListProductListItemsCompleted(uids);
|
||||
}
|
||||
|
||||
completeProductListItems(uids: string[]): Observable<BatchResponseArgsOfProductListItemDTOAndString> {
|
||||
return this.completeProductListItemsResponse(uids);
|
||||
}
|
||||
}
|
||||
6
apps/domain/product-list/src/public-api.ts
Normal file
6
apps/domain/product-list/src/public-api.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
/*
|
||||
* Public API Surface of product-list
|
||||
*/
|
||||
|
||||
export * from './lib/product-list.service';
|
||||
export * from './lib/product-list.module';
|
||||
14
apps/domain/product-list/tsconfig.lib.json
Normal file
14
apps/domain/product-list/tsconfig.lib.json
Normal file
@@ -0,0 +1,14 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/lib",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
"types": []
|
||||
},
|
||||
"exclude": [
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
10
apps/domain/product-list/tsconfig.lib.prod.json
Normal file
10
apps/domain/product-list/tsconfig.lib.prod.json
Normal file
@@ -0,0 +1,10 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "./tsconfig.lib.json",
|
||||
"compilerOptions": {
|
||||
"declarationMap": false
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"compilationMode": "partial"
|
||||
}
|
||||
}
|
||||
14
apps/domain/product-list/tsconfig.spec.json
Normal file
14
apps/domain/product-list/tsconfig.spec.json
Normal file
@@ -0,0 +1,14 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/spec",
|
||||
"types": [
|
||||
"jasmine"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
CanActivateTaskCalendarGuard,
|
||||
IsAuthenticatedGuard,
|
||||
} from './guards';
|
||||
import { CanActivateAssortmentGuard } from './guards/can-activate-assortment.guard';
|
||||
import { CanActivatePackageInspectionGuard } from './guards/can-activate-package-inspection.guard';
|
||||
import { PreviewComponent } from './preview';
|
||||
import { BranchSectionResolver, CustomerSectionResolver, ProcessIdResolver } from './resolvers';
|
||||
@@ -115,6 +116,11 @@ const routes: Routes = [
|
||||
loadChildren: () => import('@page/package-inspection').then((m) => m.PackageInspectionModule),
|
||||
canActivate: [CanActivatePackageInspectionGuard],
|
||||
},
|
||||
{
|
||||
path: 'assortment',
|
||||
loadChildren: () => import('@page/assortment').then((m) => m.AssortmentModule),
|
||||
canActivate: [CanActivateAssortmentGuard],
|
||||
},
|
||||
{ path: '**', redirectTo: 'task-calendar', pathMatch: 'full' },
|
||||
],
|
||||
resolve: { section: BranchSectionResolver },
|
||||
|
||||
24
apps/isa-app/src/app/guards/can-activate-assortment.guard.ts
Normal file
24
apps/isa-app/src/app/guards/can-activate-assortment.guard.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot } from '@angular/router';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { Config } from '@core/config';
|
||||
import { first } from 'rxjs/operators';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CanActivateAssortmentGuard implements CanActivate {
|
||||
constructor(private readonly _applicationService: ApplicationService, private readonly _config: Config) {}
|
||||
|
||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
const process = await this._applicationService.getProcessById$(this._config.get('process.ids.assortment')).pipe(first()).toPromise();
|
||||
if (!process) {
|
||||
await this._applicationService.createProcess({
|
||||
id: this._config.get('process.ids.assortment'),
|
||||
type: 'assortment',
|
||||
section: 'branch',
|
||||
name: 'Sortiment',
|
||||
});
|
||||
}
|
||||
this._applicationService.activateProcess(this._config.get('process.ids.assortment'));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -53,6 +53,10 @@
|
||||
</a>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="section === 'branch'">
|
||||
<a [routerLink]="['/filiale/assortment']" routerLinkActive="active">
|
||||
<ui-svg-icon icon="shape-outline" [size]="24"></ui-svg-icon>
|
||||
Sortiment
|
||||
</a>
|
||||
<a [routerLink]="['/filiale/task-calendar']" routerLinkActive="active">
|
||||
<ui-icon icon="calendar_check" size="24px"></ui-icon>
|
||||
Tätigkeitskalender
|
||||
|
||||
@@ -16,7 +16,7 @@ import { DashboardComponent } from '@page/dashboard';
|
||||
import { ShellFooterComponent } from '@shell/footer';
|
||||
import { ShellHeaderComponent } from '@shell/header';
|
||||
import { ShellProcessComponent, ShellProcessTabComponent } from '@shell/process';
|
||||
import { UiIconComponent } from '@ui/icon';
|
||||
import { IconRegistry, UiIconComponent, UiIconModule } from '@ui/icon';
|
||||
import { UiModalService } from '@ui/modal';
|
||||
import { EnvelopeDTO, MessageBoardItemDTO } from 'apps/hub/notifications/src/lib/defs';
|
||||
import { MockComponent } from 'ng-mocks';
|
||||
@@ -46,6 +46,7 @@ describe('ShellComponent', () => {
|
||||
const createComponent = createComponentFactory({
|
||||
component: ShellComponent,
|
||||
imports: [
|
||||
UiIconModule,
|
||||
RouterTestingModule.withRoutes([
|
||||
{ path: 'kunde', component: DummyComponent },
|
||||
{ path: 'kunde/dashboard', component: DashboardComponent },
|
||||
@@ -56,9 +57,16 @@ describe('ShellComponent', () => {
|
||||
MockComponent(ShellFooterComponent),
|
||||
MockComponent(ShellProcessComponent),
|
||||
MockComponent(ShellProcessTabComponent),
|
||||
MockComponent(UiIconComponent),
|
||||
],
|
||||
mocks: [BreadcrumbService, DomainAvailabilityService, AuthService, DomainDashboardService, Config, WrongDestinationModalService],
|
||||
mocks: [
|
||||
BreadcrumbService,
|
||||
DomainAvailabilityService,
|
||||
AuthService,
|
||||
DomainDashboardService,
|
||||
Config,
|
||||
WrongDestinationModalService,
|
||||
IconRegistry,
|
||||
],
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -193,12 +201,16 @@ describe('ShellComponent', () => {
|
||||
spectator.detectComponentChanges();
|
||||
|
||||
const anchors = spectator.queryAll('shell-footer a');
|
||||
expect(anchors[0]).toHaveText('Tätigkeitskalender');
|
||||
expect(anchors[0]).toHaveAttribute('href', '/filiale/task-calendar');
|
||||
expect(anchors[1]).toHaveText('Abholfach');
|
||||
expect(anchors[1]).toHaveAttribute('href', '/filiale/goods/in');
|
||||
expect(anchors[2]).toHaveText('Remission');
|
||||
expect(anchors[2]).toHaveAttribute('href', '/filiale/remission');
|
||||
expect(anchors[0]).toHaveText('Sortiment');
|
||||
expect(anchors[0]).toHaveAttribute('href', '/filiale/assortment');
|
||||
expect(anchors[1]).toHaveText('Tätigkeitskalender');
|
||||
expect(anchors[1]).toHaveAttribute('href', '/filiale/task-calendar');
|
||||
expect(anchors[2]).toHaveText('Abholfach');
|
||||
expect(anchors[2]).toHaveAttribute('href', '/filiale/goods/in');
|
||||
expect(anchors[3]).toHaveText('Remission');
|
||||
expect(anchors[3]).toHaveAttribute('href', '/filiale/remission');
|
||||
expect(anchors[4]).toHaveText('Wareneingang');
|
||||
expect(anchors[4]).toHaveAttribute('href', '/filiale/package-inspection');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -60,7 +60,8 @@
|
||||
"goodsIn": 2000,
|
||||
"taskCalendar": 3000,
|
||||
"remission": 4000,
|
||||
"packageInspection": 5000
|
||||
"packageInspection": 5000,
|
||||
"assortment": 6000
|
||||
}
|
||||
},
|
||||
"checkForUpdates": 3600000,
|
||||
|
||||
@@ -60,7 +60,8 @@
|
||||
"goodsIn": 2000,
|
||||
"taskCalendar": 3000,
|
||||
"remission": 4000,
|
||||
"packageInspection": 5000
|
||||
"packageInspection": 5000,
|
||||
"assortment": 6000
|
||||
}
|
||||
},
|
||||
"checkForUpdates": 3600000,
|
||||
|
||||
@@ -60,7 +60,8 @@
|
||||
"goodsIn": 2000,
|
||||
"taskCalendar": 3000,
|
||||
"remission": 4000,
|
||||
"packageInspection": 5000
|
||||
"packageInspection": 5000,
|
||||
"assortment": 6000
|
||||
}
|
||||
},
|
||||
"checkForUpdates": 3600000,
|
||||
|
||||
@@ -60,7 +60,8 @@
|
||||
"goodsIn": 2000,
|
||||
"taskCalendar": 3000,
|
||||
"remission": 4000,
|
||||
"packageInspection": 5000
|
||||
"packageInspection": 5000,
|
||||
"assortment": 6000
|
||||
}
|
||||
},
|
||||
"checkForUpdates": 3600000,
|
||||
|
||||
@@ -60,7 +60,8 @@
|
||||
"goodsIn": 2000,
|
||||
"taskCalendar": 3000,
|
||||
"remission": 4000,
|
||||
"packageInspection": 5000
|
||||
"packageInspection": 5000,
|
||||
"assortment": 6000
|
||||
}
|
||||
},
|
||||
"checkForUpdates": 3600000,
|
||||
|
||||
@@ -60,7 +60,8 @@
|
||||
"goodsIn": 2000,
|
||||
"taskCalendar": 3000,
|
||||
"remission": 4000,
|
||||
"packageInspection": 5000
|
||||
"packageInspection": 5000,
|
||||
"assortment": 6000
|
||||
}
|
||||
},
|
||||
"checkForUpdates": 3600000,
|
||||
|
||||
7
apps/page/assortment/ng-package.json
Normal file
7
apps/page/assortment/ng-package.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"dest": "../../../dist/page/yellow-pages",
|
||||
"lib": {
|
||||
"entryFile": "src/public-api.ts"
|
||||
}
|
||||
}
|
||||
3
apps/page/assortment/src/lib/assortment.component.css
Normal file
3
apps/page/assortment/src/lib/assortment.component.css
Normal file
@@ -0,0 +1,3 @@
|
||||
:host {
|
||||
@apply block;
|
||||
}
|
||||
3
apps/page/assortment/src/lib/assortment.component.html
Normal file
3
apps/page/assortment/src/lib/assortment.component.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<shared-breadcrumb class="my-4" [key]="breadcrumbKey"></shared-breadcrumb>
|
||||
|
||||
<router-outlet></router-outlet>
|
||||
67
apps/page/assortment/src/lib/assortment.component.spec.ts
Normal file
67
apps/page/assortment/src/lib/assortment.component.spec.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { Config } from '@core/config';
|
||||
import { Spectator, createComponentFactory } from '@ngneat/spectator';
|
||||
import { BreadcrumbComponent } from '@shared/components/breadcrumb';
|
||||
import { MockComponent } from 'ng-mocks';
|
||||
import { AssortmentComponent } from './assortment.component';
|
||||
|
||||
describe('AssortmentComponent', () => {
|
||||
let spectator: Spectator<AssortmentComponent>;
|
||||
const createComponent = createComponentFactory({
|
||||
component: AssortmentComponent,
|
||||
imports: [RouterTestingModule],
|
||||
mocks: [Config, BreadcrumbService],
|
||||
declarations: [MockComponent(BreadcrumbComponent)],
|
||||
});
|
||||
|
||||
let configMock: jasmine.SpyObj<Config>;
|
||||
let breadcrumbServiceMock: jasmine.SpyObj<BreadcrumbService>;
|
||||
|
||||
beforeEach(async () => {
|
||||
spectator = createComponent();
|
||||
await spectator.fixture.whenStable();
|
||||
|
||||
configMock = spectator.inject(Config);
|
||||
breadcrumbServiceMock = spectator.inject(BreadcrumbService);
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(spectator.component).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('get breadcrumbKey(): string', () => {
|
||||
it('should call Config.get("process.ids.assortment") and return the result', () => {
|
||||
const expected = 'expected';
|
||||
configMock.get.and.returnValue(expected);
|
||||
|
||||
const actual = spectator.component.breadcrumbKey;
|
||||
|
||||
expect(configMock.get).toHaveBeenCalledWith('process.ids.assortment');
|
||||
expect(actual).toBe(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ngOnInit()', () => {
|
||||
it('should call createBreadcrumbIfNotExists()', () => {
|
||||
const spy = spyOn(spectator.component, 'createBreadcrumbIfNotExists');
|
||||
|
||||
spectator.component.ngOnInit();
|
||||
|
||||
expect(spy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('template', () => {
|
||||
it('should render the ShellBreadcrumbComponent and pass the breadcrumbKey as @Input() key', () => {
|
||||
const expected = 'expected';
|
||||
configMock.get.and.returnValue(expected);
|
||||
|
||||
spectator.detectComponentChanges();
|
||||
|
||||
const shellBreadcrumb = spectator.query(BreadcrumbComponent);
|
||||
expect(shellBreadcrumb).toBeTruthy();
|
||||
expect(shellBreadcrumb.key).toBe(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
33
apps/page/assortment/src/lib/assortment.component.ts
Normal file
33
apps/page/assortment/src/lib/assortment.component.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
||||
import { Breadcrumb, BreadcrumbService } from '@core/breadcrumb';
|
||||
import { Config } from '@core/config';
|
||||
|
||||
@Component({
|
||||
selector: 'page-assortment',
|
||||
templateUrl: 'assortment.component.html',
|
||||
styleUrls: ['assortment.component.css'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class AssortmentComponent implements OnInit {
|
||||
get breadcrumbKey(): string {
|
||||
return this._config.get('process.ids.assortment');
|
||||
}
|
||||
|
||||
constructor(private _config: Config, private _breadcrumb: BreadcrumbService) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.createBreadcrumbIfNotExists();
|
||||
}
|
||||
|
||||
async createBreadcrumbIfNotExists(): Promise<void> {
|
||||
const crumb: Breadcrumb = {
|
||||
key: this.breadcrumbKey,
|
||||
name: 'Sortiment',
|
||||
path: '/filiale/assortment',
|
||||
section: 'branch',
|
||||
tags: ['main'],
|
||||
};
|
||||
|
||||
await this._breadcrumb.addBreadcrumbIfNotExists(crumb);
|
||||
}
|
||||
}
|
||||
16
apps/page/assortment/src/lib/assortment.module.ts
Normal file
16
apps/page/assortment/src/lib/assortment.module.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { BreadcrumbModule } from '@shared/components/breadcrumb';
|
||||
import { routes } from './routes';
|
||||
|
||||
import { AssortmentComponent } from './assortment.component';
|
||||
import { PriceUpdateModule } from './price-update/price-update.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, RouterModule.forChild(routes), BreadcrumbModule, PriceUpdateModule],
|
||||
exports: [AssortmentComponent],
|
||||
declarations: [AssortmentComponent],
|
||||
providers: [],
|
||||
})
|
||||
export class AssortmentModule {}
|
||||
7
apps/page/assortment/src/lib/price-update/index.ts
Normal file
7
apps/page/assortment/src/lib/price-update/index.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
// start:ng42.barrel
|
||||
export * from './price-update.component.state';
|
||||
export * from './price-update.component.store';
|
||||
export * from './price-update.component';
|
||||
export * from './price-update.module';
|
||||
export * from './price-update-list';
|
||||
// end:ng42.barrel
|
||||
@@ -0,0 +1,6 @@
|
||||
// start:ng42.barrel
|
||||
export * from './price-update-item-loader.component';
|
||||
export * from './price-update-item.component';
|
||||
export * from './price-update-list.component';
|
||||
export * from './price-update-list.module';
|
||||
// end:ng42.barrel
|
||||
@@ -0,0 +1,9 @@
|
||||
:host {
|
||||
@apply flex flex-row items-center bg-white rounded px-4 mt-px-2;
|
||||
height: 53px;
|
||||
}
|
||||
|
||||
.skeleton {
|
||||
@apply block bg-gray-300 h-6;
|
||||
animation: load 1s ease-in-out infinite;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<div class="skeleton w-44"></div>
|
||||
<div class="skeleton w-28 ml-8"></div>
|
||||
<div class="skeleton w-28 ml-8"></div>
|
||||
<div class="grow"></div>
|
||||
<div class="skeleton w-32"></div>
|
||||
@@ -0,0 +1,17 @@
|
||||
import { createComponentFactory, Spectator } from '@ngneat/spectator';
|
||||
import { PriceUpdateItemLoaderComponent } from './price-update-item-loader.component';
|
||||
|
||||
describe('PriceUpdateItemLoaderComponent', () => {
|
||||
let spectator: Spectator<PriceUpdateItemLoaderComponent>;
|
||||
const createComponent = createComponentFactory({
|
||||
component: PriceUpdateItemLoaderComponent,
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
spectator = createComponent();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(spectator.component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'page-price-update-item-loader',
|
||||
templateUrl: 'price-update-item-loader.component.html',
|
||||
styleUrls: ['price-update-item-loader.component.css'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PriceUpdateItemLoaderComponent implements OnInit {
|
||||
constructor() {}
|
||||
|
||||
ngOnInit() {}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
:host {
|
||||
@apply flex flex-col w-full;
|
||||
height: 267px;
|
||||
}
|
||||
|
||||
.page-price-update-item__item-card {
|
||||
@apply grid grid-flow-col;
|
||||
grid-template-columns: 63px auto minmax(230px, auto);
|
||||
box-shadow: 0px 0px 10px rgba(220, 226, 233, 0.5);
|
||||
}
|
||||
|
||||
.page-price-update-item__item-details {
|
||||
@apply grid grid-flow-row;
|
||||
grid-template-rows: 27px 70px 27px 27px auto;
|
||||
}
|
||||
|
||||
.page-price-update-item__item-image {
|
||||
box-shadow: 0px 6px 18px rgba(0, 0, 0, 0.197935);
|
||||
}
|
||||
|
||||
.page-price-update-item__item-addition {
|
||||
@apply grid grid-flow-row justify-items-end;
|
||||
grid-template-rows: 27px 27px 41px 52px auto;
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<div
|
||||
class="page-price-update-item__item-header flex flex-row w-full items-center justify-between bg-[rgba(0,128,121,0.15)] mb-px-2 px-5 h-[53px] rounded-t-card"
|
||||
>
|
||||
<p class="page-price-update-item__item-instruction font-bold text-lg">{{ item?.task?.instruction }}</p>
|
||||
<p class="page-price-update-item__item-due-date text-base">
|
||||
gültig ab <span class="font-bold ml-2">{{ item?.task?.dueDate | date }}</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="page-price-update-item__item-card p-5 h-[212px] bg-white">
|
||||
<div class="page-price-update-item__item-thumbnail text-center mr-4 w-[47px] h-[73px]">
|
||||
<img
|
||||
class="page-price-update-item__item-image w-[47px] h-[73px]"
|
||||
loading="lazy"
|
||||
*ngIf="item?.product?.ean | productImage; let productImage"
|
||||
[src]="productImage"
|
||||
[alt]="item?.product?.name"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="page-price-update-item__item-details">
|
||||
<div class="page-price-update-item__item-contributors flex flex-row">
|
||||
{{ environment.isTablet() ? (item?.product?.contributors | substr: 42) : item?.product?.contributors }}
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="page-price-update-item__item-title font-bold text-2xl"
|
||||
[class.text-xl]="item?.product?.name?.length >= 35"
|
||||
[class.text-lg]="item?.product?.name?.length >= 40"
|
||||
[class.text-md]="item?.product?.name?.length >= 50"
|
||||
[class.text-sm]="item?.product?.name?.length >= 60"
|
||||
[class.text-xs]="item?.product?.name?.length >= 100"
|
||||
>
|
||||
{{ item?.product?.name }}
|
||||
</div>
|
||||
|
||||
<div class="page-price-update-item__item-format">
|
||||
<div *ngIf="item?.product?.format && item?.product?.formatDetail" class="font-bold flex flex-row">
|
||||
<img
|
||||
class="mr-3"
|
||||
*ngIf="item?.product?.format !== '--'"
|
||||
loading="lazy"
|
||||
src="assets/images/Icon_{{ item?.product?.format }}.svg"
|
||||
[alt]="item?.product?.formatDetail"
|
||||
/>
|
||||
{{ item?.product?.formatDetail }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-price-update-item__item-misc">
|
||||
{{ environment.isTablet() ? (item?.product?.manufacturer | substr: 18) : item?.product?.manufacturer }} | {{ item?.product?.ean }}
|
||||
<br />
|
||||
{{ item?.product?.volume }} <span *ngIf="item?.product?.volume && item?.product?.publicationDate">|</span>
|
||||
{{ publicationDate }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-price-update-item__item-addition">
|
||||
<div class="page-price-update-item__item-product-group-details">{{ item?.product?.productGroupDetails }}</div>
|
||||
<div class="page-price-update-item__item-compartment">
|
||||
<span
|
||||
*ngIf="inStock$ | async; let stock"
|
||||
[class.skeleton]="stock?.compartment === undefined"
|
||||
class="min-w-[2rem] text-right inline-block"
|
||||
>{{ stock?.compartment }}</span
|
||||
>
|
||||
</div>
|
||||
<div class="page-price-update-item__item-price font-bold">
|
||||
{{ item?.product?.price?.value?.value | currency: 'EUR':'code' }}
|
||||
</div>
|
||||
|
||||
<div class="page-price-update-item__item-select-bullet">
|
||||
<input *ngIf="isSelectable" [ngModel]="selected$ | async" (ngModelChange)="setSelected()" class="isa-select-bullet" type="checkbox" />
|
||||
</div>
|
||||
|
||||
<div class="page-price-update-item__item-stock flex flex-row font-bold">
|
||||
<ui-icon class="mt-px-2 mr-1" icon="home" size="1em"></ui-icon>
|
||||
<span
|
||||
*ngIf="inStock$ | async; let stock"
|
||||
[class.skeleton]="stock?.inStock === undefined"
|
||||
class="min-w-[1rem] text-right inline-block"
|
||||
>{{ stock?.inStock }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,22 @@
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { DomainAvailabilityService } from '@domain/availability';
|
||||
import { createComponentFactory, Spectator } from '@ngneat/spectator';
|
||||
import { DateAdapter } from '@ui/common';
|
||||
import { PriceUpdateComponentStore } from '../price-update.component.store';
|
||||
import { PriceUpdateItemComponent } from './price-update-item.component';
|
||||
|
||||
xdescribe('PriceUpdateItemComponent', () => {
|
||||
let spectator: Spectator<PriceUpdateItemComponent>;
|
||||
const createComponent = createComponentFactory({
|
||||
component: PriceUpdateItemComponent,
|
||||
mocks: [DateAdapter, DomainAvailabilityService, ApplicationService, PriceUpdateComponentStore],
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
spectator = createComponent();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(spectator.component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,76 @@
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
import { DomainAvailabilityService, DomainInStockService } from '@domain/availability';
|
||||
import { ProductListItemDTO } from '@swagger/wws';
|
||||
import { DateAdapter } from '@ui/common';
|
||||
import { debounceTime, map, shareReplay, switchMap } from 'rxjs/operators';
|
||||
import { PriceUpdateComponentStore } from '../price-update.component.store';
|
||||
|
||||
@Component({
|
||||
selector: 'page-price-update-item',
|
||||
templateUrl: 'price-update-item.component.html',
|
||||
styleUrls: ['price-update-item.component.css'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
providers: [DatePipe],
|
||||
})
|
||||
export class PriceUpdateItemComponent {
|
||||
@Input()
|
||||
item: ProductListItemDTO;
|
||||
|
||||
get publicationDate() {
|
||||
if (!!this.item?.product?.publicationDate) {
|
||||
const date = this._dateAdapter.parseDate(this.item.product.publicationDate);
|
||||
|
||||
if (this._dateAdapter.getDate(date) === 1 && this._dateAdapter.getMonth(date) === 0) {
|
||||
return this._datePipe.transform(date, 'y');
|
||||
}
|
||||
|
||||
return this._datePipe.transform(date, 'dd. MMMM y');
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
get isSelectable() {
|
||||
return this._store.isSelectable(this.item);
|
||||
}
|
||||
|
||||
selected$ = this._store.selectedItemUids$.pipe(map((selectedItemUids) => selectedItemUids.includes(this.item?.uId)));
|
||||
|
||||
defaultBranch$ = this._availability.getDefaultBranch();
|
||||
|
||||
inStock$ = this.defaultBranch$.pipe(
|
||||
debounceTime(100),
|
||||
switchMap(
|
||||
(defaultBranch) =>
|
||||
this._stockService.getInStock$({
|
||||
itemId: Number(this.item?.product?.catalogProductNumber),
|
||||
branchId: defaultBranch?.id,
|
||||
})
|
||||
// TODO: Bugfixing INSTOCK
|
||||
// .pipe(
|
||||
// map((instock) => {
|
||||
// this.item.product.ean === '9783551775559' ? console.log({ item: this.item, instock }) : '';
|
||||
// return instock;
|
||||
// })
|
||||
// )
|
||||
),
|
||||
shareReplay(1)
|
||||
);
|
||||
|
||||
constructor(
|
||||
private _dateAdapter: DateAdapter,
|
||||
private _datePipe: DatePipe,
|
||||
private _availability: DomainAvailabilityService,
|
||||
public applicationService: ApplicationService,
|
||||
public environment: EnvironmentService,
|
||||
private _stockService: DomainInStockService,
|
||||
private _store: PriceUpdateComponentStore
|
||||
) {}
|
||||
|
||||
setSelected() {
|
||||
const isSelected = this._store.selectedItemUids.includes(this.item?.uId);
|
||||
this._store.setSelected({ selected: !isSelected, itemUid: this.item?.uId });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
:host {
|
||||
@apply block;
|
||||
}
|
||||
|
||||
cdk-virtual-scroll-viewport {
|
||||
height: calc(100vh - 445px);
|
||||
}
|
||||
|
||||
.page-price-update-list__action-wrapper {
|
||||
@apply grid grid-flow-col gap-4 justify-center my-6 fixed bottom-24 inset-x-0;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<div class="page-price-update-list__header bg-background-liste flex flex-col items-end py-4">
|
||||
<button (click)="print()" type="button" class="page-price-update-list__print-cta text-lg font-bold text-[#F70400] pr-5 mb-3">
|
||||
Drucken
|
||||
</button>
|
||||
<div class="flex flex-row items-center justify-end">
|
||||
<div class="text-[#0556B4] font-bold text-sm mr-5">
|
||||
<ng-container *ngIf="selectedItemUids$ | async; let selectedItems">
|
||||
<button class="page-price-update-list__cta-unselect-all" *ngIf="selectedItems?.length > 0" type="button" (click)="unselectAll()">
|
||||
Alle entfernen ({{ selectedItems?.length }})
|
||||
</button>
|
||||
<button class="page-price-update-list__cta-select-all" type="button" (click)="selectAll()" *ngIf="selectedItems?.length === 0">
|
||||
Alle auswählen ({{ getSelectableItems().length }})
|
||||
</button>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="page-price-update-list__items-count inline-flex flex-row items-center pr-5 text-sm">{{ items?.length ?? 0 }} Titel</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<cdk-virtual-scroll-viewport #scrollContainer [itemSize]="267" minBufferPx="1200" maxBufferPx="1200">
|
||||
<page-price-update-item
|
||||
*cdkVirtualFor="let item of items; let first; trackBy: trackByFn"
|
||||
[item]="item"
|
||||
[class.mt-px-10]="!first"
|
||||
></page-price-update-item>
|
||||
|
||||
<page-price-update-item-loader *ngIf="fetching"> </page-price-update-item-loader>
|
||||
</cdk-virtual-scroll-viewport>
|
||||
|
||||
<div class="page-price-update-list__action-wrapper">
|
||||
<button
|
||||
*ngIf="!fetching"
|
||||
[disabled]="(selectedItemUids$ | async).length === 0 || (loading$ | async)"
|
||||
class="page-price-update-list__complete-items isa-button isa-cta-button isa-button-primary px-11"
|
||||
type="button"
|
||||
(click)="onComplete()"
|
||||
>
|
||||
<ui-spinner [show]="loading$ | async">Erledigt</ui-spinner>
|
||||
</button>
|
||||
</div>
|
||||
@@ -0,0 +1,42 @@
|
||||
import { createComponentFactory, Spectator } from '@ngneat/spectator';
|
||||
import { MockComponent } from 'ng-mocks';
|
||||
import { PriceUpdateComponentStore } from '../price-update.component.store';
|
||||
import { PriceUpdateItemComponent } from './price-update-item.component';
|
||||
import { PriceUpdateListComponent } from './price-update-list.component';
|
||||
|
||||
xdescribe('PriceUpdateListComponent', () => {
|
||||
let spectator: Spectator<PriceUpdateListComponent>;
|
||||
let priceUpdateStoreMock: jasmine.SpyObj<PriceUpdateComponentStore>;
|
||||
const createComponent = createComponentFactory({
|
||||
component: PriceUpdateListComponent,
|
||||
declarations: [MockComponent(PriceUpdateItemComponent)],
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
spectator = createComponent();
|
||||
priceUpdateStoreMock = spectator.inject(PriceUpdateComponentStore, true);
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(spectator.component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should render the length of the items in .page-price-update-list__items-count', () => {
|
||||
spectator.setInput('items', [{ uId: '1' }, { uId: '2' }]);
|
||||
|
||||
spectator.detectChanges();
|
||||
|
||||
expect(spectator.query('.page-price-update-list__items-count')).toHaveText('2 Titel');
|
||||
});
|
||||
|
||||
it('should render the PriceUpdateItemComponent for each item', () => {
|
||||
spectator.setInput('items', [{ uId: '1' }, { uId: '2' }]);
|
||||
|
||||
spectator.detectChanges();
|
||||
|
||||
const listItem = spectator.queryAll(PriceUpdateItemComponent);
|
||||
expect(listItem).toHaveLength(2);
|
||||
expect(listItem[0].item).toEqual({ uId: '1' });
|
||||
expect(listItem[1].item).toEqual({ uId: '2' });
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,50 @@
|
||||
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
|
||||
import { ChangeDetectionStrategy, Component, Input, ViewChild } from '@angular/core';
|
||||
import { ProductListItemDTO } from '@swagger/wws';
|
||||
import { PriceUpdateComponentStore } from '../price-update.component.store';
|
||||
|
||||
@Component({
|
||||
selector: 'page-price-update-list',
|
||||
templateUrl: 'price-update-list.component.html',
|
||||
styleUrls: ['price-update-list.component.css'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PriceUpdateListComponent {
|
||||
@ViewChild('scrollContainer', { static: true })
|
||||
scrollContainer: CdkVirtualScrollViewport;
|
||||
|
||||
@Input()
|
||||
items: ProductListItemDTO[] = [];
|
||||
|
||||
@Input()
|
||||
fetching: boolean = false;
|
||||
|
||||
selectedItemUids$ = this._store.selectedItemUids$;
|
||||
|
||||
loading$ = this._store.loading$;
|
||||
|
||||
trackByFn = (index: number, item: ProductListItemDTO) => item.uId;
|
||||
|
||||
constructor(private _store: PriceUpdateComponentStore) {}
|
||||
|
||||
getSelectableItems() {
|
||||
return this._store.items.filter((item) => this._store.isSelectable(item)) ?? [];
|
||||
}
|
||||
|
||||
selectAll() {
|
||||
const selectedItemUids = this.getSelectableItems().map((item) => item.uId);
|
||||
this._store.patchState({ selectedItemUids });
|
||||
}
|
||||
|
||||
unselectAll() {
|
||||
this._store.patchState({ selectedItemUids: [] });
|
||||
}
|
||||
|
||||
print() {
|
||||
this._store.print();
|
||||
}
|
||||
|
||||
onComplete() {
|
||||
this._store.complete();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { ScrollingModule } from '@angular/cdk/scrolling';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { ProductImageModule } from '@cdn/product-image';
|
||||
import { UiCommonModule } from '@ui/common';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { UiSpinnerModule } from '@ui/spinner';
|
||||
import { PriceUpdateItemLoaderComponent } from './price-update-item-loader.component';
|
||||
import { PriceUpdateItemComponent } from './price-update-item.component';
|
||||
import { PriceUpdateListComponent } from './price-update-list.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [FormsModule, CommonModule, UiCommonModule, UiIconModule, ProductImageModule, ScrollingModule, UiSpinnerModule],
|
||||
exports: [PriceUpdateListComponent, PriceUpdateItemComponent, PriceUpdateItemLoaderComponent],
|
||||
declarations: [PriceUpdateListComponent, PriceUpdateItemComponent, PriceUpdateItemLoaderComponent],
|
||||
providers: [],
|
||||
})
|
||||
export class PriceUpdateListModule {}
|
||||
@@ -0,0 +1,3 @@
|
||||
:host {
|
||||
@apply block;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<div class="flex flex-row items-center h-14 bg-white relative rounded-t font-bold shadow-lg">
|
||||
<h3 class="text-center grow font-bold text-2xl">Preisänderung</h3>
|
||||
<button
|
||||
(click)="filterOverlay.open()"
|
||||
class="absolute right-0 top-0 h-14 rounded px-5 text-lg bg-cadet-blue grid grid-flow-col gap-2 items-center"
|
||||
type="button"
|
||||
>
|
||||
<ui-svg-icon icon="filter-variant"></ui-svg-icon>
|
||||
Filter
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<page-price-update-list *ngIf="showList$ | async; else noResults" [items]="store.items$ | async" [fetching]="store.fetching$ | async">
|
||||
</page-price-update-list>
|
||||
|
||||
<shell-filter-overlay #filterOverlay class="relative">
|
||||
<div class="relative">
|
||||
<button type="button" class="absolute top-4 right-4 text-cadet" (click)="closeFilterOverlay()">
|
||||
<ui-svg-icon [icon]="'close'" [size]="28"></ui-svg-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<h3 class="text-3xl text-center font-bold mt-8">Filter</h3>
|
||||
|
||||
<ui-filter
|
||||
#filter
|
||||
class="mx-4"
|
||||
[filter]="store.pendingFilter$ | async"
|
||||
(search)="applyFilter()"
|
||||
[loading]="store.fetching$ | async"
|
||||
[hint]="hint$ | async"
|
||||
></ui-filter>
|
||||
|
||||
<div class="absolute bottom-8 left-0 right-0 grid grid-flow-col gap-4 justify-center">
|
||||
<button
|
||||
type="button"
|
||||
class="px-6 py-4 font-bold bg-white text-brand border-2 border-solid border-brand rounded-full"
|
||||
(click)="store.resetPendingFilter()"
|
||||
>
|
||||
Filter zurücksetzen
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="px-6 py-4 font-bold bg-brand text-white border-2 border-solid border-brand rounded-full disabled:bg-cadet-blue disabled:cursor-progress disabled:border-cadet-blue"
|
||||
(click)="applyFilter()"
|
||||
[disabled]="store.fetching$ | async"
|
||||
>
|
||||
<ui-spinner [show]="store.fetching$ | async">
|
||||
Filter anwenden
|
||||
</ui-spinner>
|
||||
</button>
|
||||
</div>
|
||||
</shell-filter-overlay>
|
||||
|
||||
<ng-template #noResults>
|
||||
<div class="bg-white text-2xl text-center pt-10 font-bold rounded-b h-[calc(100vh_-_370px)]">Keine Preisänderungen vorhanden.</div>
|
||||
</ng-template>
|
||||
@@ -0,0 +1,44 @@
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { Config } from '@core/config';
|
||||
import { DomainProductListService } from '@domain/product-list';
|
||||
import { createComponentFactory, Spectator } from '@ngneat/spectator';
|
||||
import { ProductListItemDTO } from '@swagger/wws';
|
||||
import { UISvgIconComponent } from '@ui/icon';
|
||||
import { UiModalService } from '@ui/modal';
|
||||
import { MockComponent } from 'ng-mocks';
|
||||
import { PriceUpdateListComponent } from './price-update-list';
|
||||
import { PriceUpdateComponent } from './price-update.component';
|
||||
import { PriceUpdateComponentStore } from './price-update.component.store';
|
||||
|
||||
xdescribe('PriceUpdateComponent', () => {
|
||||
let spectator: Spectator<PriceUpdateComponent>;
|
||||
let priceUpdateStoreMock: jasmine.SpyObj<PriceUpdateComponentStore>;
|
||||
const createComponent = createComponentFactory({
|
||||
component: PriceUpdateComponent,
|
||||
mocks: [DomainProductListService, UiModalService, ActivatedRoute, Config, BreadcrumbService],
|
||||
declarations: [MockComponent(PriceUpdateListComponent), MockComponent(UISvgIconComponent)],
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
spectator = createComponent();
|
||||
priceUpdateStoreMock = spectator.inject(PriceUpdateComponentStore, true);
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(spectator.component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should render the PriceUpdateListComponent', () => {
|
||||
expect(spectator.query(PriceUpdateListComponent)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should set the input package of the PriceUpdateListComponent', () => {
|
||||
const items: ProductListItemDTO[] = [{ uId: '1' }, { uId: '2' }];
|
||||
spectator.component.store.setItems(items);
|
||||
|
||||
spectator.detectChanges();
|
||||
|
||||
expect(spectator.query(PriceUpdateListComponent).items).toEqual(items);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
import { ProductListItemDTO } from '@swagger/wws';
|
||||
import { UiFilter } from '@ui/filter';
|
||||
|
||||
export interface PriceUpdateComponentState {
|
||||
showFilter: boolean;
|
||||
fetching: boolean;
|
||||
filter: UiFilter | undefined;
|
||||
pendingFilter: UiFilter | undefined;
|
||||
defaultFilter: UiFilter | undefined;
|
||||
items: ProductListItemDTO[];
|
||||
selectedItemUids: string[];
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
export const INITIAL_PRICE_UPDATE_COMPONENT_STATE: PriceUpdateComponentState = {
|
||||
showFilter: false,
|
||||
fetching: false,
|
||||
filter: undefined,
|
||||
pendingFilter: undefined,
|
||||
defaultFilter: undefined,
|
||||
items: [],
|
||||
selectedItemUids: [],
|
||||
loading: false,
|
||||
};
|
||||
@@ -0,0 +1,185 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { DomainPrinterService } from '@domain/printer';
|
||||
import { DomainProductListService } from '@domain/product-list';
|
||||
import { PrintModalComponent, PrintModalData } from '@modal/printer';
|
||||
import { ComponentStore, OnStoreInit, tapResponse } from '@ngrx/component-store';
|
||||
import { ListResponseArgsOfProductListItemDTO, ProductListItemDTO, QuerySettingsDTO } from '@swagger/wws';
|
||||
import { UiFilter } from '@ui/filter';
|
||||
import { UiModalService } from '@ui/modal';
|
||||
import { Subject } from 'rxjs';
|
||||
import { debounceTime, switchMap, tap, withLatestFrom } from 'rxjs/operators';
|
||||
import { INITIAL_PRICE_UPDATE_COMPONENT_STATE, PriceUpdateComponentState } from './price-update.component.state';
|
||||
|
||||
@Injectable()
|
||||
export class PriceUpdateComponentStore extends ComponentStore<PriceUpdateComponentState> implements OnStoreInit {
|
||||
showFilter$ = this.select((state) => state.showFilter);
|
||||
|
||||
fetching$ = this.select((state) => state.fetching);
|
||||
|
||||
loading$ = this.select((state) => state.loading);
|
||||
|
||||
filter$ = this.select((state) => state.filter);
|
||||
|
||||
get filter(): UiFilter {
|
||||
return this.get((f) => f.filter);
|
||||
}
|
||||
|
||||
pendingFilter$ = this.select((state) => state.pendingFilter);
|
||||
|
||||
defaultFilter$ = this.select((state) => state.defaultFilter);
|
||||
|
||||
items$ = this.select((state) => state.items);
|
||||
|
||||
get items() {
|
||||
return this.get((s) => s.items);
|
||||
}
|
||||
|
||||
selectedItemUids$ = this.select((s) => s.selectedItemUids);
|
||||
|
||||
get selectedItemUids() {
|
||||
return this.get((s) => s.selectedItemUids);
|
||||
}
|
||||
|
||||
private _onFetchingItemsResponse$ = new Subject<ListResponseArgsOfProductListItemDTO>();
|
||||
|
||||
onFetchingItemsResponse$ = this._onFetchingItemsResponse$.asObservable();
|
||||
|
||||
constructor(
|
||||
private _productListService: DomainProductListService,
|
||||
private _domainPrinterService: DomainPrinterService,
|
||||
private _uiModal: UiModalService
|
||||
) {
|
||||
super(INITIAL_PRICE_UPDATE_COMPONENT_STATE);
|
||||
}
|
||||
|
||||
ngrxOnStoreInit() {
|
||||
this.fetchSettings();
|
||||
}
|
||||
|
||||
setShowFilter = this.updater((state, showFilter: boolean) => ({ ...state, showFilter }));
|
||||
|
||||
setFetching = this.updater((state, fetching: boolean) => ({ ...state, fetching }));
|
||||
|
||||
setLoading = this.updater((state, loading: boolean) => ({ ...state, loading }));
|
||||
|
||||
setFilter = this.updater((state, filter: UiFilter) => ({ ...state, filter }));
|
||||
|
||||
setPendingFilter = this.updater((state, pendingFilter: UiFilter) => ({ ...state, pendingFilter }));
|
||||
|
||||
setDefaultFilter = this.updater((state, defaultFilter: UiFilter) => ({ ...state, defaultFilter }));
|
||||
|
||||
setItems = this.updater((state, items: ProductListItemDTO[]) => ({ ...state, items }));
|
||||
|
||||
setSelected({ selected, itemUid }: { selected: boolean; itemUid: string }) {
|
||||
if (selected) {
|
||||
this.patchState({
|
||||
selectedItemUids: [...this.selectedItemUids, itemUid],
|
||||
});
|
||||
} else if (!selected) {
|
||||
this.patchState({
|
||||
selectedItemUids: this.selectedItemUids.filter((id) => id !== itemUid),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fetchSettings = this.effect(($) =>
|
||||
$.pipe(switchMap((_) => this._productListService.getQuerySettings().pipe(tapResponse(this.onFetchSettingsResponse, this.onFetchError))))
|
||||
);
|
||||
|
||||
fetchItems = this.effect(($) =>
|
||||
$.pipe(
|
||||
tap(() => this.beforeFetchingItems()),
|
||||
debounceTime(250),
|
||||
withLatestFrom(this.filter$),
|
||||
switchMap(([_, filter]) =>
|
||||
this._productListService
|
||||
.queryProductListResponse(filter.getQueryToken())
|
||||
.pipe(tapResponse(this.onFetchingItemsResponse, this.onFetchError))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
complete = this.effect(($) =>
|
||||
$.pipe(
|
||||
tap(() => this.beforeComplete()),
|
||||
withLatestFrom(this.items$, this.selectedItemUids$),
|
||||
switchMap(([_, items, selectedItemUids]) =>
|
||||
this._productListService
|
||||
.completeProductListItems(selectedItemUids)
|
||||
.pipe(tapResponse((response) => this.onCompleteResponse({ selectedItemUids, items }), this.onCompleteError))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
print() {
|
||||
const selectableItems = this.items.filter((item) => this.isSelectable(item));
|
||||
this._uiModal.open({
|
||||
content: PrintModalComponent,
|
||||
data: {
|
||||
printerType: 'Office',
|
||||
print: (printer) =>
|
||||
this._domainPrinterService.printProductListItems({ data: selectableItems, printer, title: 'Preisänderungen' }).toPromise(),
|
||||
} as PrintModalData,
|
||||
config: {
|
||||
panelClass: [],
|
||||
showScrollbarY: false,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
beforeComplete() {
|
||||
this.setLoading(true);
|
||||
}
|
||||
|
||||
beforeFetchingItems() {
|
||||
this.setFetching(true);
|
||||
this.setItems([]);
|
||||
}
|
||||
|
||||
onCompleteResponse = ({ selectedItemUids, items }: { selectedItemUids: string[]; items: ProductListItemDTO[] }) => {
|
||||
let filteredItems: ProductListItemDTO[];
|
||||
for (let uId of selectedItemUids) {
|
||||
filteredItems = items.filter((item) => item.uId !== uId);
|
||||
}
|
||||
this.patchState({ selectedItemUids: [] });
|
||||
this.setItems(filteredItems);
|
||||
this.setLoading(false);
|
||||
};
|
||||
|
||||
onCompleteError = (error: any) => {
|
||||
console.error(error);
|
||||
this._uiModal.error('Setzen der Produkte auf Erledigt fehlgeschlagen.', error);
|
||||
this.setLoading(false);
|
||||
};
|
||||
|
||||
onFetchSettingsResponse = (querySettings: QuerySettingsDTO) => {
|
||||
const filter = UiFilter.create(querySettings);
|
||||
this.setDefaultFilter(UiFilter.create(filter));
|
||||
this.setPendingFilter(UiFilter.create(filter));
|
||||
this.setFilter(UiFilter.create(filter));
|
||||
};
|
||||
|
||||
onFetchingItemsResponse = (response: ListResponseArgsOfProductListItemDTO) => {
|
||||
this.setFetching(false);
|
||||
this.setItems(response.result);
|
||||
this._onFetchingItemsResponse$.next(response);
|
||||
};
|
||||
|
||||
onFetchError = (error: any) => {
|
||||
console.error(error);
|
||||
this._uiModal.error('Laden der Produktliste fehlgeschlagen.', error);
|
||||
this.setFetching(false);
|
||||
this.setItems([]);
|
||||
};
|
||||
|
||||
isSelectable(item: ProductListItemDTO) {
|
||||
// True wenn das Item das aktuelle oder ein älteres Datum beim gültig ab Wert hat
|
||||
return new Date(item?.task?.dueDate) <= new Date(Date.now());
|
||||
}
|
||||
|
||||
restorePendingFilter = this.updater((state) => ({ ...state, pendingFilter: UiFilter.create(state.filter) }));
|
||||
|
||||
resetPendingFilter = this.updater((state) => ({ ...state, pendingFilter: UiFilter.create(state.defaultFilter) }));
|
||||
|
||||
applyPendingFilterToFilter = this.updater((state) => ({ ...state, filter: UiFilter.create(state.pendingFilter) }));
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
import { ChangeDetectionStrategy, Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { Config } from '@core/config';
|
||||
import { provideComponentStore } from '@ngrx/component-store';
|
||||
import { ShellFilterOverlayComponent } from '@shell/filter-overlay';
|
||||
import { UiFilter, UiFilterComponent } from '@ui/filter';
|
||||
import { PriceUpdateComponentStore } from './price-update.component.store';
|
||||
import { combineLatest, Subject, Subscription } from 'rxjs';
|
||||
import { filter, first, map } from 'rxjs/operators';
|
||||
import { ActivatedRoute, Params, Router } from '@angular/router';
|
||||
import { Breadcrumb, BreadcrumbService } from '@core/breadcrumb';
|
||||
import { ListResponseArgsOfProductListItemDTO } from '@swagger/wws';
|
||||
|
||||
@Component({
|
||||
selector: 'page-price-update',
|
||||
templateUrl: 'price-update.component.html',
|
||||
styleUrls: ['price-update.component.css'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
providers: [provideComponentStore(PriceUpdateComponentStore)],
|
||||
})
|
||||
export class PriceUpdateComponent implements OnInit {
|
||||
private _subscription = new Subscription();
|
||||
|
||||
get breadcrumbKey(): string {
|
||||
return this._config.get('process.ids.assortment');
|
||||
}
|
||||
|
||||
hint$ = new Subject<string>();
|
||||
|
||||
@ViewChild(UiFilterComponent)
|
||||
filter: UiFilterComponent;
|
||||
|
||||
@ViewChild(ShellFilterOverlayComponent)
|
||||
filterOverlay: ShellFilterOverlayComponent;
|
||||
|
||||
/**
|
||||
* Zeigt die liste an, wenn entweder keine items geladen werden oder wenn items geladen wurden
|
||||
* und mindestens ein item vorhanden ist.
|
||||
*/
|
||||
showList$ = combineLatest([this.store.fetching$, this.store.items$]).pipe(map(([fetching, items]) => fetching || items.length > 0));
|
||||
|
||||
constructor(
|
||||
public store: PriceUpdateComponentStore,
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
private _config: Config,
|
||||
private _breadcrumb: BreadcrumbService,
|
||||
private _router: Router
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.initFilterSubscription();
|
||||
|
||||
this.initFetchResponseSubscription();
|
||||
|
||||
this.removeBreadcrumbs();
|
||||
}
|
||||
|
||||
initFilterSubscription() {
|
||||
const initialFilter$ = this.store.filter$.pipe(
|
||||
filter((f) => f instanceof UiFilter),
|
||||
first()
|
||||
);
|
||||
const queryParams$ = this._activatedRoute.queryParams;
|
||||
|
||||
const filterSub = combineLatest([initialFilter$, queryParams$]).subscribe(([filter, queryParams]) => {
|
||||
const restored = this.restoreFilterFromQueryParams(filter, queryParams);
|
||||
this.fetchItems(restored);
|
||||
});
|
||||
|
||||
this._subscription.add(filterSub);
|
||||
}
|
||||
|
||||
initFetchResponseSubscription() {
|
||||
const onFetchItemsResponseSub = this.store.onFetchingItemsResponse$.subscribe(this.onFetchingItemsResponse);
|
||||
|
||||
this._subscription.add(onFetchItemsResponseSub);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this._subscription.unsubscribe();
|
||||
}
|
||||
|
||||
restoreFilterFromQueryParams(filter: UiFilter, queryParams: Params): UiFilter {
|
||||
const nextFilter = UiFilter.create(filter);
|
||||
nextFilter.fromQueryParams(queryParams);
|
||||
this.store.setFilter(nextFilter);
|
||||
this.store.setPendingFilter(nextFilter);
|
||||
return nextFilter;
|
||||
}
|
||||
|
||||
applyFilter() {
|
||||
this.store.applyPendingFilterToFilter();
|
||||
this.fetchItems(this.store.filter);
|
||||
}
|
||||
|
||||
fetchItems(filter: UiFilter) {
|
||||
this.hint$.next('');
|
||||
this.store.fetchItems();
|
||||
this.patchLocation(filter);
|
||||
}
|
||||
|
||||
onFetchingItemsResponse = (response: ListResponseArgsOfProductListItemDTO) => {
|
||||
this.createBreadcrumbIfNotExists(this.store.filter);
|
||||
if (response.error) {
|
||||
console.error(response);
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.result.length === 0) {
|
||||
this.hint$.next('Keine Preisänderungen vorhanden');
|
||||
return;
|
||||
}
|
||||
|
||||
this.filterOverlay.close();
|
||||
};
|
||||
|
||||
async patchLocation(filter: UiFilter): Promise<void> {
|
||||
this._router.navigate([], {
|
||||
queryParams: filter.getQueryParams(),
|
||||
});
|
||||
}
|
||||
|
||||
async createBreadcrumbIfNotExists(filter: UiFilter): Promise<void> {
|
||||
const crumb: Breadcrumb = {
|
||||
key: this.breadcrumbKey,
|
||||
name: 'Preisänderung',
|
||||
path: '/filiale/assortment/price-update',
|
||||
section: 'branch',
|
||||
params: filter.getQueryParams(),
|
||||
tags: ['filter'],
|
||||
};
|
||||
|
||||
await this._breadcrumb.addOrUpdateBreadcrumbIfNotExists(crumb);
|
||||
}
|
||||
|
||||
async removeBreadcrumbs(): Promise<void> {
|
||||
const filterCrumbs = await this._breadcrumb.getBreadcrumbsByKeyAndTag$(this.breadcrumbKey, 'filter').pipe(first()).toPromise();
|
||||
const crumbs = [...filterCrumbs];
|
||||
for (let crumb of crumbs) {
|
||||
await this._breadcrumb.removeBreadcrumb(crumb.id);
|
||||
}
|
||||
}
|
||||
|
||||
closeFilterOverlay() {
|
||||
this.filterOverlay.close();
|
||||
this.store.restorePendingFilter();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { ShellFilterOverlayModule } from '@shell/filter-overlay';
|
||||
import { UiFilterNextModule } from '@ui/filter';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { UiSpinnerModule } from '@ui/spinner';
|
||||
import { PriceUpdateListModule } from './price-update-list';
|
||||
import { PriceUpdateComponent } from './price-update.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, PriceUpdateListModule, UiIconModule, UiFilterNextModule, ShellFilterOverlayModule, UiSpinnerModule],
|
||||
exports: [PriceUpdateComponent],
|
||||
declarations: [PriceUpdateComponent],
|
||||
providers: [],
|
||||
})
|
||||
export class PriceUpdateModule {}
|
||||
14
apps/page/assortment/src/lib/routes.ts
Normal file
14
apps/page/assortment/src/lib/routes.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { Routes } from '@angular/router';
|
||||
import { AssortmentComponent } from './assortment.component';
|
||||
import { PriceUpdateComponent } from './price-update/price-update.component';
|
||||
|
||||
export const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: AssortmentComponent,
|
||||
children: [
|
||||
{ path: 'price-update', component: PriceUpdateComponent },
|
||||
{ path: '**', redirectTo: 'price-update' },
|
||||
],
|
||||
},
|
||||
];
|
||||
6
apps/page/assortment/src/public-api.ts
Normal file
6
apps/page/assortment/src/public-api.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
/*
|
||||
* Public API Surface of checkout
|
||||
*/
|
||||
|
||||
export * from './lib/assortment.component';
|
||||
export * from './lib/assortment.module';
|
||||
@@ -11,8 +11,8 @@
|
||||
</div>
|
||||
<div class="shared-breadcrumb__crumbs">
|
||||
<ng-container *ngFor="let crumb of breadcrumbs$ | async; let last = last">
|
||||
<a class="shared-breadcrumb__crumb" [class.font-bold]="last" [routerLink]="crumb.path" [queryParams]="crumb.params">
|
||||
<span>
|
||||
<a class="shared-breadcrumb__crumb" [routerLink]="crumb.path" [queryParams]="crumb.params">
|
||||
<span [class.font-bold]="last">
|
||||
{{ crumb.name }}
|
||||
</span>
|
||||
</a>
|
||||
|
||||
6
apps/shared/components/product-list-item/ng-package.json
Normal file
6
apps/shared/components/product-list-item/ng-package.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"$schema": "../../../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"lib": {
|
||||
"entryFile": "src/public-api.ts"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'shared-product-list-item',
|
||||
templateUrl: 'product-list-item.component.html',
|
||||
})
|
||||
export class ProductListItemComponent implements OnInit {
|
||||
constructor() {}
|
||||
|
||||
ngOnInit() {}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
import { ProductListItemComponent } from './product-list-item.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [],
|
||||
exports: [],
|
||||
declarations: [ProductListItemComponent],
|
||||
providers: [],
|
||||
})
|
||||
export class ProductListItemModule {}
|
||||
@@ -0,0 +1,5 @@
|
||||
/*
|
||||
* Public API Surface of notification-channel-control
|
||||
*/
|
||||
|
||||
export * from './lib/product-list-item.module';
|
||||
@@ -41,10 +41,12 @@ export { InputType } from './models/input-type';
|
||||
export { InputOptionsDTO } from './models/input-options-dto';
|
||||
export { OptionDTO } from './models/option-dto';
|
||||
export { OrderByDTO } from './models/order-by-dto';
|
||||
export { ListResponseArgsOfProductListDTO } from './models/list-response-args-of-product-list-dto';
|
||||
export { ResponseArgsOfIEnumerableOfProductListDTO } from './models/response-args-of-ienumerable-of-product-list-dto';
|
||||
export { ProductListDTO } from './models/product-list-dto';
|
||||
export { ListResponseArgsOfProductListItemDTO } from './models/list-response-args-of-product-list-item-dto';
|
||||
export { ResponseArgsOfIEnumerableOfProductListItemDTO } from './models/response-args-of-ienumerable-of-product-list-item-dto';
|
||||
export { ProductListItemDTO } from './models/product-list-item-dto';
|
||||
export { EntityDTOContainerOfProductListItemDTO } from './models/entity-dtocontainer-of-product-list-item-dto';
|
||||
export { EntityDTOContainerOfProductListDTO } from './models/entity-dtocontainer-of-product-list-dto';
|
||||
export { ProductListDTO } from './models/product-list-dto';
|
||||
export { EntityDTOContainerOfStockDTO } from './models/entity-dtocontainer-of-stock-dto';
|
||||
export { StockDTO } from './models/stock-dto';
|
||||
export { EntityDTOContainerOfBranchDTO } from './models/entity-dtocontainer-of-branch-dto';
|
||||
@@ -62,11 +64,6 @@ export { EntityDTOBaseOfTenantDTOAndITenant } from './models/entity-dtobase-of-t
|
||||
export { TaskDTO } from './models/task-dto';
|
||||
export { UserReference } from './models/user-reference';
|
||||
export { ImpedimentDTO } from './models/impediment-dto';
|
||||
export { QueryTokenDTO } from './models/query-token-dto';
|
||||
export { ListResponseArgsOfProductListItemDTO } from './models/list-response-args-of-product-list-item-dto';
|
||||
export { ResponseArgsOfIEnumerableOfProductListItemDTO } from './models/response-args-of-ienumerable-of-product-list-item-dto';
|
||||
export { ProductListItemDTO } from './models/product-list-item-dto';
|
||||
export { EntityDTOContainerOfProductListItemDTO } from './models/entity-dtocontainer-of-product-list-item-dto';
|
||||
export { EntityDTOContainerOfStockCompartmentDTO } from './models/entity-dtocontainer-of-stock-compartment-dto';
|
||||
export { StockCompartmentDTO } from './models/stock-compartment-dto';
|
||||
export { SizeOfString } from './models/size-of-string';
|
||||
@@ -87,6 +84,18 @@ export { PriceValueDTO } from './models/price-value-dto';
|
||||
export { VATValueDTO } from './models/vatvalue-dto';
|
||||
export { VATType } from './models/vattype';
|
||||
export { QuantityValueDTO } from './models/quantity-value-dto';
|
||||
export { QueryTokenDTO } from './models/query-token-dto';
|
||||
export { ResponseArgsOfString } from './models/response-args-of-string';
|
||||
export { DocumentPayloadOfIEnumerableOfProductListItemDTO } from './models/document-payload-of-ienumerable-of-product-list-item-dto';
|
||||
export { ListResponseArgsOfProductListDTO } from './models/list-response-args-of-product-list-dto';
|
||||
export { ResponseArgsOfIEnumerableOfProductListDTO } from './models/response-args-of-ienumerable-of-product-list-dto';
|
||||
export { ResponseArgsOfProductListDTO } from './models/response-args-of-product-list-dto';
|
||||
export { ResponseArgsOfProductListItemDTO } from './models/response-args-of-product-list-item-dto';
|
||||
export { BatchResponseArgsOfProductListItemDTOAndString } from './models/batch-response-args-of-product-list-item-dtoand-string';
|
||||
export { KeyValuePairOfStringAndProductListItemDTO } from './models/key-value-pair-of-string-and-product-list-item-dto';
|
||||
export { ReturnValueOfString } from './models/return-value-of-string';
|
||||
export { ReturnValue } from './models/return-value';
|
||||
export { KeyValuePairOfStringAndInteger } from './models/key-value-pair-of-string-and-integer';
|
||||
export { ResponseArgsOfIEnumerableOfStockInfoDTO } from './models/response-args-of-ienumerable-of-stock-info-dto';
|
||||
export { StockInfoDTO } from './models/stock-info-dto';
|
||||
export { StockStatus } from './models/stock-status';
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
/* tslint:disable */
|
||||
import { ReturnValueOfString } from './return-value-of-string';
|
||||
import { KeyValuePairOfStringAndInteger } from './key-value-pair-of-string-and-integer';
|
||||
import { KeyValuePairOfStringAndProductListItemDTO } from './key-value-pair-of-string-and-product-list-item-dto';
|
||||
export interface BatchResponseArgsOfProductListItemDTOAndString {
|
||||
alreadyProcessed?: Array<ReturnValueOfString>;
|
||||
ambiguous?: Array<string>;
|
||||
completed: boolean;
|
||||
duplicates?: Array<KeyValuePairOfStringAndInteger>;
|
||||
error: boolean;
|
||||
failed?: Array<ReturnValueOfString>;
|
||||
invalidProperties?: {[key: string]: string};
|
||||
message?: string;
|
||||
requestId?: number;
|
||||
successful?: Array<KeyValuePairOfStringAndProductListItemDTO>;
|
||||
total: number;
|
||||
unknown?: Array<ReturnValueOfString>;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/* tslint:disable */
|
||||
import { ProductListItemDTO } from './product-list-item-dto';
|
||||
|
||||
/**
|
||||
* Payload
|
||||
*/
|
||||
export interface DocumentPayloadOfIEnumerableOfProductListItemDTO {
|
||||
|
||||
/**
|
||||
* Daten
|
||||
*/
|
||||
data?: Array<ProductListItemDTO>;
|
||||
|
||||
/**
|
||||
* Seitentitel
|
||||
*/
|
||||
title?: string;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
/* tslint:disable */
|
||||
export interface KeyValuePairOfStringAndInteger {
|
||||
key: string;
|
||||
value: number;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
/* tslint:disable */
|
||||
import { ProductListItemDTO } from './product-list-item-dto';
|
||||
export interface KeyValuePairOfStringAndProductListItemDTO {
|
||||
key: string;
|
||||
value: ProductListItemDTO;
|
||||
}
|
||||
@@ -9,6 +9,7 @@ export interface PackageArrivalStatusDTO {
|
||||
deliveryTarget?: string;
|
||||
estimatedDeliveryDate?: string;
|
||||
id: string;
|
||||
misrouted?: string;
|
||||
packageNumber?: string;
|
||||
supplier?: string;
|
||||
trackingNumber?: string;
|
||||
|
||||
@@ -14,6 +14,7 @@ export interface ProductDTO extends TouchedBase{
|
||||
manufacturer?: string;
|
||||
name?: string;
|
||||
productGroup?: string;
|
||||
productGroupDetails?: string;
|
||||
publicationDate?: string;
|
||||
serial?: string;
|
||||
size?: SizeOfString;
|
||||
|
||||
@@ -3,6 +3,6 @@ import { TouchedBase } from './touched-base';
|
||||
import { QuantityUnitType } from './quantity-unit-type';
|
||||
export interface QuantityValueDTO extends TouchedBase{
|
||||
quantity?: number;
|
||||
quantityUnit: string;
|
||||
quantityUnit?: string;
|
||||
quantityUnitType?: QuantityUnitType;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/* tslint:disable */
|
||||
import { ResponseArgs } from './response-args';
|
||||
import { ProductListDTO } from './product-list-dto';
|
||||
export interface ResponseArgsOfProductListDTO extends ResponseArgs{
|
||||
result?: ProductListDTO;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
/* tslint:disable */
|
||||
import { ResponseArgs } from './response-args';
|
||||
import { ProductListItemDTO } from './product-list-item-dto';
|
||||
export interface ResponseArgsOfProductListItemDTO extends ResponseArgs{
|
||||
result?: ProductListItemDTO;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
/* tslint:disable */
|
||||
import { ResponseArgs } from './response-args';
|
||||
export interface ResponseArgsOfString extends ResponseArgs{
|
||||
result?: string;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
/* tslint:disable */
|
||||
import { ReturnValue } from './return-value';
|
||||
export interface ReturnValueOfString extends ReturnValue{
|
||||
result?: string;
|
||||
}
|
||||
6
apps/swagger/wws/src/lib/models/return-value.ts
Normal file
6
apps/swagger/wws/src/lib/models/return-value.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
/* tslint:disable */
|
||||
export interface ReturnValue {
|
||||
error: boolean;
|
||||
invalidProperties?: {[key: string]: string};
|
||||
message?: string;
|
||||
}
|
||||
@@ -3,6 +3,9 @@ import { TouchedBase } from './touched-base';
|
||||
import { UserReference } from './user-reference';
|
||||
import { ImpedimentDTO } from './impediment-dto';
|
||||
export interface TaskDTO extends TouchedBase{
|
||||
category?: string;
|
||||
command?: string;
|
||||
commandData?: string;
|
||||
completed?: string;
|
||||
completedBy?: UserReference;
|
||||
description?: string;
|
||||
@@ -10,4 +13,7 @@ export interface TaskDTO extends TouchedBase{
|
||||
impediment?: ImpedimentDTO;
|
||||
instruction?: string;
|
||||
name?: string;
|
||||
notAfter?: string;
|
||||
notBefore?: string;
|
||||
reminder?: string;
|
||||
}
|
||||
|
||||
@@ -8,17 +8,32 @@ import { Observable as __Observable } from 'rxjs';
|
||||
import { map as __map, filter as __filter } from 'rxjs/operators';
|
||||
|
||||
import { ResponseArgsOfQuerySettingsDTO } from '../models/response-args-of-query-settings-dto';
|
||||
import { ListResponseArgsOfProductListDTO } from '../models/list-response-args-of-product-list-dto';
|
||||
import { QueryTokenDTO } from '../models/query-token-dto';
|
||||
import { ListResponseArgsOfProductListItemDTO } from '../models/list-response-args-of-product-list-item-dto';
|
||||
import { QueryTokenDTO } from '../models/query-token-dto';
|
||||
import { ResponseArgsOfString } from '../models/response-args-of-string';
|
||||
import { DocumentPayloadOfIEnumerableOfProductListItemDTO } from '../models/document-payload-of-ienumerable-of-product-list-item-dto';
|
||||
import { ListResponseArgsOfProductListDTO } from '../models/list-response-args-of-product-list-dto';
|
||||
import { ResponseArgsOfProductListDTO } from '../models/response-args-of-product-list-dto';
|
||||
import { ProductListDTO } from '../models/product-list-dto';
|
||||
import { ResponseArgsOfProductListItemDTO } from '../models/response-args-of-product-list-item-dto';
|
||||
import { ProductListItemDTO } from '../models/product-list-item-dto';
|
||||
import { BatchResponseArgsOfProductListItemDTOAndString } from '../models/batch-response-args-of-product-list-item-dtoand-string';
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
class ProductListService extends __BaseService {
|
||||
static readonly ProductListQueryProductListSettingsPath = '/inventory/productlist/s/settings';
|
||||
static readonly ProductListQueryProductListPath = '/inventory/productlist/s';
|
||||
static readonly ProductListGetProductlistItemsPath = '/inventory/productlist/{productlistUId}';
|
||||
static readonly ProductListQueryProductListItemsSettingsPath = '/inventory/productlist/items/s/settings';
|
||||
static readonly ProductListQueryProductListItemPath = '/inventory/productlist/items/s';
|
||||
static readonly ProductListProductListItemPdfAsBase64Path = '/inventory/productlist/items/pdf/base64';
|
||||
static readonly ProductListQueryProductListPath = '/inventory/productlist/s';
|
||||
static readonly ProductListCreateProductListPath = '/inventory/productlist';
|
||||
static readonly ProductListUpdateProductListPath = '/inventory/productlist/{productlistUId}';
|
||||
static readonly ProductListGetProductlistItemsPath = '/inventory/productlist/{productlistUId}';
|
||||
static readonly ProductListProductlistCompletedPath = '/inventory/productlist/{productlistUId}/completed';
|
||||
static readonly ProductListCreateProductListItemPath = '/inventory/productlist/items';
|
||||
static readonly ProductListUpdateProductListItemPath = '/inventory/productlist/items/{productListItemUId}';
|
||||
static readonly ProductListProductListItemCompletedPath = '/inventory/productlist/items/{productListItemUId}/completed';
|
||||
static readonly ProductListProductListItemsCompletedPath = '/inventory/productlist/items/completed';
|
||||
|
||||
constructor(
|
||||
config: __Configuration,
|
||||
@@ -28,15 +43,15 @@ class ProductListService extends __BaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Settings
|
||||
* Settings - Produktlistenpositionen
|
||||
*/
|
||||
ProductListQueryProductListSettingsResponse(): __Observable<__StrictHttpResponse<ResponseArgsOfQuerySettingsDTO>> {
|
||||
ProductListQueryProductListItemsSettingsResponse(): __Observable<__StrictHttpResponse<ResponseArgsOfQuerySettingsDTO>> {
|
||||
let __params = this.newParams();
|
||||
let __headers = new HttpHeaders();
|
||||
let __body: any = null;
|
||||
let req = new HttpRequest<any>(
|
||||
'GET',
|
||||
this.rootUrl + `/inventory/productlist/s/settings`,
|
||||
this.rootUrl + `/inventory/productlist/items/s/settings`,
|
||||
__body,
|
||||
{
|
||||
headers: __headers,
|
||||
@@ -52,14 +67,84 @@ class ProductListService extends __BaseService {
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Settings
|
||||
* Settings - Produktlistenpositionen
|
||||
*/
|
||||
ProductListQueryProductListSettings(): __Observable<ResponseArgsOfQuerySettingsDTO> {
|
||||
return this.ProductListQueryProductListSettingsResponse().pipe(
|
||||
ProductListQueryProductListItemsSettings(): __Observable<ResponseArgsOfQuerySettingsDTO> {
|
||||
return this.ProductListQueryProductListItemsSettingsResponse().pipe(
|
||||
__map(_r => _r.body as ResponseArgsOfQuerySettingsDTO)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param queryTokenDTO undefined
|
||||
*/
|
||||
ProductListQueryProductListItemResponse(queryTokenDTO: QueryTokenDTO): __Observable<__StrictHttpResponse<ListResponseArgsOfProductListItemDTO>> {
|
||||
let __params = this.newParams();
|
||||
let __headers = new HttpHeaders();
|
||||
let __body: any = null;
|
||||
__body = queryTokenDTO;
|
||||
let req = new HttpRequest<any>(
|
||||
'POST',
|
||||
this.rootUrl + `/inventory/productlist/items/s`,
|
||||
__body,
|
||||
{
|
||||
headers: __headers,
|
||||
params: __params,
|
||||
responseType: 'json'
|
||||
});
|
||||
|
||||
return this.http.request<any>(req).pipe(
|
||||
__filter(_r => _r instanceof HttpResponse),
|
||||
__map((_r) => {
|
||||
return _r as __StrictHttpResponse<ListResponseArgsOfProductListItemDTO>;
|
||||
})
|
||||
);
|
||||
}
|
||||
/**
|
||||
* @param queryTokenDTO undefined
|
||||
*/
|
||||
ProductListQueryProductListItem(queryTokenDTO: QueryTokenDTO): __Observable<ListResponseArgsOfProductListItemDTO> {
|
||||
return this.ProductListQueryProductListItemResponse(queryTokenDTO).pipe(
|
||||
__map(_r => _r.body as ListResponseArgsOfProductListItemDTO)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Artikelliste als PDF (base64)
|
||||
* @param payload DocumentPayload mit EANsK
|
||||
*/
|
||||
ProductListProductListItemPdfAsBase64Response(payload: DocumentPayloadOfIEnumerableOfProductListItemDTO): __Observable<__StrictHttpResponse<ResponseArgsOfString>> {
|
||||
let __params = this.newParams();
|
||||
let __headers = new HttpHeaders();
|
||||
let __body: any = null;
|
||||
__body = payload;
|
||||
let req = new HttpRequest<any>(
|
||||
'POST',
|
||||
this.rootUrl + `/inventory/productlist/items/pdf/base64`,
|
||||
__body,
|
||||
{
|
||||
headers: __headers,
|
||||
params: __params,
|
||||
responseType: 'json'
|
||||
});
|
||||
|
||||
return this.http.request<any>(req).pipe(
|
||||
__filter(_r => _r instanceof HttpResponse),
|
||||
__map((_r) => {
|
||||
return _r as __StrictHttpResponse<ResponseArgsOfString>;
|
||||
})
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Artikelliste als PDF (base64)
|
||||
* @param payload DocumentPayload mit EANsK
|
||||
*/
|
||||
ProductListProductListItemPdfAsBase64(payload: DocumentPayloadOfIEnumerableOfProductListItemDTO): __Observable<ResponseArgsOfString> {
|
||||
return this.ProductListProductListItemPdfAsBase64Response(payload).pipe(
|
||||
__map(_r => _r.body as ResponseArgsOfString)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param queryTokenDTO undefined
|
||||
*/
|
||||
@@ -94,6 +179,102 @@ class ProductListService extends __BaseService {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param params The `ProductListService.ProductListCreateProductListParams` containing the following parameters:
|
||||
*
|
||||
* - `data`:
|
||||
*
|
||||
* - `locale`:
|
||||
*/
|
||||
ProductListCreateProductListResponse(params: ProductListService.ProductListCreateProductListParams): __Observable<__StrictHttpResponse<ResponseArgsOfProductListDTO>> {
|
||||
let __params = this.newParams();
|
||||
let __headers = new HttpHeaders();
|
||||
let __body: any = null;
|
||||
__body = params.data;
|
||||
if (params.locale != null) __params = __params.set('locale', params.locale.toString());
|
||||
let req = new HttpRequest<any>(
|
||||
'POST',
|
||||
this.rootUrl + `/inventory/productlist`,
|
||||
__body,
|
||||
{
|
||||
headers: __headers,
|
||||
params: __params,
|
||||
responseType: 'json'
|
||||
});
|
||||
|
||||
return this.http.request<any>(req).pipe(
|
||||
__filter(_r => _r instanceof HttpResponse),
|
||||
__map((_r) => {
|
||||
return _r as __StrictHttpResponse<ResponseArgsOfProductListDTO>;
|
||||
})
|
||||
);
|
||||
}
|
||||
/**
|
||||
* @param params The `ProductListService.ProductListCreateProductListParams` containing the following parameters:
|
||||
*
|
||||
* - `data`:
|
||||
*
|
||||
* - `locale`:
|
||||
*/
|
||||
ProductListCreateProductList(params: ProductListService.ProductListCreateProductListParams): __Observable<ResponseArgsOfProductListDTO> {
|
||||
return this.ProductListCreateProductListResponse(params).pipe(
|
||||
__map(_r => _r.body as ResponseArgsOfProductListDTO)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param params The `ProductListService.ProductListUpdateProductListParams` containing the following parameters:
|
||||
*
|
||||
* - `productlistUId`:
|
||||
*
|
||||
* - `data`:
|
||||
*
|
||||
* - `productListItemUId`:
|
||||
*
|
||||
* - `locale`:
|
||||
*/
|
||||
ProductListUpdateProductListResponse(params: ProductListService.ProductListUpdateProductListParams): __Observable<__StrictHttpResponse<ResponseArgsOfProductListDTO>> {
|
||||
let __params = this.newParams();
|
||||
let __headers = new HttpHeaders();
|
||||
let __body: any = null;
|
||||
|
||||
__body = params.data;
|
||||
if (params.productListItemUId != null) __params = __params.set('productListItemUId', params.productListItemUId.toString());
|
||||
if (params.locale != null) __params = __params.set('locale', params.locale.toString());
|
||||
let req = new HttpRequest<any>(
|
||||
'PATCH',
|
||||
this.rootUrl + `/inventory/productlist/${encodeURIComponent(String(params.productlistUId))}`,
|
||||
__body,
|
||||
{
|
||||
headers: __headers,
|
||||
params: __params,
|
||||
responseType: 'json'
|
||||
});
|
||||
|
||||
return this.http.request<any>(req).pipe(
|
||||
__filter(_r => _r instanceof HttpResponse),
|
||||
__map((_r) => {
|
||||
return _r as __StrictHttpResponse<ResponseArgsOfProductListDTO>;
|
||||
})
|
||||
);
|
||||
}
|
||||
/**
|
||||
* @param params The `ProductListService.ProductListUpdateProductListParams` containing the following parameters:
|
||||
*
|
||||
* - `productlistUId`:
|
||||
*
|
||||
* - `data`:
|
||||
*
|
||||
* - `productListItemUId`:
|
||||
*
|
||||
* - `locale`:
|
||||
*/
|
||||
ProductListUpdateProductList(params: ProductListService.ProductListUpdateProductListParams): __Observable<ResponseArgsOfProductListDTO> {
|
||||
return this.ProductListUpdateProductListResponse(params).pipe(
|
||||
__map(_r => _r.body as ResponseArgsOfProductListDTO)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param params The `ProductListService.ProductListGetProductlistItemsParams` containing the following parameters:
|
||||
*
|
||||
@@ -143,16 +324,16 @@ class ProductListService extends __BaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param queryTokenDTO undefined
|
||||
* @param productlistUId undefined
|
||||
*/
|
||||
ProductListQueryProductListItemResponse(queryTokenDTO: QueryTokenDTO): __Observable<__StrictHttpResponse<ListResponseArgsOfProductListItemDTO>> {
|
||||
ProductListProductlistCompletedResponse(productlistUId: null | string): __Observable<__StrictHttpResponse<ResponseArgsOfProductListDTO>> {
|
||||
let __params = this.newParams();
|
||||
let __headers = new HttpHeaders();
|
||||
let __body: any = null;
|
||||
__body = queryTokenDTO;
|
||||
|
||||
let req = new HttpRequest<any>(
|
||||
'POST',
|
||||
this.rootUrl + `/inventory/productlist/items/s`,
|
||||
this.rootUrl + `/inventory/productlist/${encodeURIComponent(String(productlistUId))}/completed`,
|
||||
__body,
|
||||
{
|
||||
headers: __headers,
|
||||
@@ -163,22 +344,199 @@ class ProductListService extends __BaseService {
|
||||
return this.http.request<any>(req).pipe(
|
||||
__filter(_r => _r instanceof HttpResponse),
|
||||
__map((_r) => {
|
||||
return _r as __StrictHttpResponse<ListResponseArgsOfProductListItemDTO>;
|
||||
return _r as __StrictHttpResponse<ResponseArgsOfProductListDTO>;
|
||||
})
|
||||
);
|
||||
}
|
||||
/**
|
||||
* @param queryTokenDTO undefined
|
||||
* @param productlistUId undefined
|
||||
*/
|
||||
ProductListQueryProductListItem(queryTokenDTO: QueryTokenDTO): __Observable<ListResponseArgsOfProductListItemDTO> {
|
||||
return this.ProductListQueryProductListItemResponse(queryTokenDTO).pipe(
|
||||
__map(_r => _r.body as ListResponseArgsOfProductListItemDTO)
|
||||
ProductListProductlistCompleted(productlistUId: null | string): __Observable<ResponseArgsOfProductListDTO> {
|
||||
return this.ProductListProductlistCompletedResponse(productlistUId).pipe(
|
||||
__map(_r => _r.body as ResponseArgsOfProductListDTO)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param params The `ProductListService.ProductListCreateProductListItemParams` containing the following parameters:
|
||||
*
|
||||
* - `data`:
|
||||
*
|
||||
* - `locale`:
|
||||
*/
|
||||
ProductListCreateProductListItemResponse(params: ProductListService.ProductListCreateProductListItemParams): __Observable<__StrictHttpResponse<ResponseArgsOfProductListItemDTO>> {
|
||||
let __params = this.newParams();
|
||||
let __headers = new HttpHeaders();
|
||||
let __body: any = null;
|
||||
__body = params.data;
|
||||
if (params.locale != null) __params = __params.set('locale', params.locale.toString());
|
||||
let req = new HttpRequest<any>(
|
||||
'POST',
|
||||
this.rootUrl + `/inventory/productlist/items`,
|
||||
__body,
|
||||
{
|
||||
headers: __headers,
|
||||
params: __params,
|
||||
responseType: 'json'
|
||||
});
|
||||
|
||||
return this.http.request<any>(req).pipe(
|
||||
__filter(_r => _r instanceof HttpResponse),
|
||||
__map((_r) => {
|
||||
return _r as __StrictHttpResponse<ResponseArgsOfProductListItemDTO>;
|
||||
})
|
||||
);
|
||||
}
|
||||
/**
|
||||
* @param params The `ProductListService.ProductListCreateProductListItemParams` containing the following parameters:
|
||||
*
|
||||
* - `data`:
|
||||
*
|
||||
* - `locale`:
|
||||
*/
|
||||
ProductListCreateProductListItem(params: ProductListService.ProductListCreateProductListItemParams): __Observable<ResponseArgsOfProductListItemDTO> {
|
||||
return this.ProductListCreateProductListItemResponse(params).pipe(
|
||||
__map(_r => _r.body as ResponseArgsOfProductListItemDTO)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param params The `ProductListService.ProductListUpdateProductListItemParams` containing the following parameters:
|
||||
*
|
||||
* - `productListItemUId`:
|
||||
*
|
||||
* - `data`:
|
||||
*
|
||||
* - `locale`:
|
||||
*/
|
||||
ProductListUpdateProductListItemResponse(params: ProductListService.ProductListUpdateProductListItemParams): __Observable<__StrictHttpResponse<ResponseArgsOfProductListItemDTO>> {
|
||||
let __params = this.newParams();
|
||||
let __headers = new HttpHeaders();
|
||||
let __body: any = null;
|
||||
|
||||
__body = params.data;
|
||||
if (params.locale != null) __params = __params.set('locale', params.locale.toString());
|
||||
let req = new HttpRequest<any>(
|
||||
'PATCH',
|
||||
this.rootUrl + `/inventory/productlist/items/${encodeURIComponent(String(params.productListItemUId))}`,
|
||||
__body,
|
||||
{
|
||||
headers: __headers,
|
||||
params: __params,
|
||||
responseType: 'json'
|
||||
});
|
||||
|
||||
return this.http.request<any>(req).pipe(
|
||||
__filter(_r => _r instanceof HttpResponse),
|
||||
__map((_r) => {
|
||||
return _r as __StrictHttpResponse<ResponseArgsOfProductListItemDTO>;
|
||||
})
|
||||
);
|
||||
}
|
||||
/**
|
||||
* @param params The `ProductListService.ProductListUpdateProductListItemParams` containing the following parameters:
|
||||
*
|
||||
* - `productListItemUId`:
|
||||
*
|
||||
* - `data`:
|
||||
*
|
||||
* - `locale`:
|
||||
*/
|
||||
ProductListUpdateProductListItem(params: ProductListService.ProductListUpdateProductListItemParams): __Observable<ResponseArgsOfProductListItemDTO> {
|
||||
return this.ProductListUpdateProductListItemResponse(params).pipe(
|
||||
__map(_r => _r.body as ResponseArgsOfProductListItemDTO)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param productListItemUId undefined
|
||||
*/
|
||||
ProductListProductListItemCompletedResponse(productListItemUId: null | string): __Observable<__StrictHttpResponse<ResponseArgsOfProductListItemDTO>> {
|
||||
let __params = this.newParams();
|
||||
let __headers = new HttpHeaders();
|
||||
let __body: any = null;
|
||||
|
||||
let req = new HttpRequest<any>(
|
||||
'POST',
|
||||
this.rootUrl + `/inventory/productlist/items/${encodeURIComponent(String(productListItemUId))}/completed`,
|
||||
__body,
|
||||
{
|
||||
headers: __headers,
|
||||
params: __params,
|
||||
responseType: 'json'
|
||||
});
|
||||
|
||||
return this.http.request<any>(req).pipe(
|
||||
__filter(_r => _r instanceof HttpResponse),
|
||||
__map((_r) => {
|
||||
return _r as __StrictHttpResponse<ResponseArgsOfProductListItemDTO>;
|
||||
})
|
||||
);
|
||||
}
|
||||
/**
|
||||
* @param productListItemUId undefined
|
||||
*/
|
||||
ProductListProductListItemCompleted(productListItemUId: null | string): __Observable<ResponseArgsOfProductListItemDTO> {
|
||||
return this.ProductListProductListItemCompletedResponse(productListItemUId).pipe(
|
||||
__map(_r => _r.body as ResponseArgsOfProductListItemDTO)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uids undefined
|
||||
*/
|
||||
ProductListProductListItemsCompletedResponse(uids: Array<string>): __Observable<__StrictHttpResponse<BatchResponseArgsOfProductListItemDTOAndString>> {
|
||||
let __params = this.newParams();
|
||||
let __headers = new HttpHeaders();
|
||||
let __body: any = null;
|
||||
__body = uids;
|
||||
let req = new HttpRequest<any>(
|
||||
'POST',
|
||||
this.rootUrl + `/inventory/productlist/items/completed`,
|
||||
__body,
|
||||
{
|
||||
headers: __headers,
|
||||
params: __params,
|
||||
responseType: 'json'
|
||||
});
|
||||
|
||||
return this.http.request<any>(req).pipe(
|
||||
__filter(_r => _r instanceof HttpResponse),
|
||||
__map((_r) => {
|
||||
return _r as __StrictHttpResponse<BatchResponseArgsOfProductListItemDTOAndString>;
|
||||
})
|
||||
);
|
||||
}
|
||||
/**
|
||||
* @param uids undefined
|
||||
*/
|
||||
ProductListProductListItemsCompleted(uids: Array<string>): __Observable<BatchResponseArgsOfProductListItemDTOAndString> {
|
||||
return this.ProductListProductListItemsCompletedResponse(uids).pipe(
|
||||
__map(_r => _r.body as BatchResponseArgsOfProductListItemDTOAndString)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module ProductListService {
|
||||
|
||||
/**
|
||||
* Parameters for ProductListCreateProductList
|
||||
*/
|
||||
export interface ProductListCreateProductListParams {
|
||||
data: ProductListDTO;
|
||||
locale?: null | string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameters for ProductListUpdateProductList
|
||||
*/
|
||||
export interface ProductListUpdateProductListParams {
|
||||
productlistUId: string;
|
||||
data: ProductListDTO;
|
||||
productListItemUId?: null | string;
|
||||
locale?: null | string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameters for ProductListGetProductlistItems
|
||||
*/
|
||||
@@ -187,6 +545,23 @@ module ProductListService {
|
||||
take?: null | number;
|
||||
skip?: null | number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameters for ProductListCreateProductListItem
|
||||
*/
|
||||
export interface ProductListCreateProductListItemParams {
|
||||
data: ProductListItemDTO;
|
||||
locale?: null | string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameters for ProductListUpdateProductListItem
|
||||
*/
|
||||
export interface ProductListUpdateProductListItemParams {
|
||||
productListItemUId: null | string;
|
||||
data: ProductListItemDTO;
|
||||
locale?: null | string;
|
||||
}
|
||||
}
|
||||
|
||||
export { ProductListService }
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
mdiFilterVariant,
|
||||
mdiClose,
|
||||
mdiClipboardCheckOutline,
|
||||
mdiShapeOutline,
|
||||
} from '@mdi/js';
|
||||
|
||||
export function _rootIconRegistryFactory(config: UiIconConfig): IconRegistry {
|
||||
@@ -45,6 +46,7 @@ const DEFAULT_ICON_CONFIG: UiIconConfig = {
|
||||
{ name: 'filter-variant', data: mdiFilterVariant },
|
||||
{ name: 'close', data: mdiClose },
|
||||
{ name: 'clipboard-check-outline', data: mdiClipboardCheckOutline },
|
||||
{ name: 'shape-outline', data: mdiShapeOutline },
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
@@ -33,5 +33,10 @@ module.exports = plugin(function ({ addComponents, theme }) {
|
||||
width: theme('spacing.7'),
|
||||
height: theme('spacing.7'),
|
||||
},
|
||||
'.isa-button-primary:disabled': {
|
||||
backgroundColor: '#596470',
|
||||
borderColor: '#596470',
|
||||
color: theme('colors.white'),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
51
tailwind-plugins/select-bullet.plugin.js
Normal file
51
tailwind-plugins/select-bullet.plugin.js
Normal file
@@ -0,0 +1,51 @@
|
||||
const plugin = require('tailwindcss/plugin');
|
||||
|
||||
module.exports = plugin(function ({ addComponents, theme }) {
|
||||
addComponents({
|
||||
'.isa-select-bullet': {
|
||||
position: 'relative',
|
||||
appearance: 'none',
|
||||
width: theme('spacing.8'),
|
||||
height: theme('spacing.8'),
|
||||
},
|
||||
'.isa-select-bullet::before': {
|
||||
position: 'absolute',
|
||||
display: 'block',
|
||||
borderRadius: theme('borderRadius.full'),
|
||||
backgroundColor: '#AEB7C1',
|
||||
cursor: 'pointer',
|
||||
transitionProperty: 'all',
|
||||
transitionTimingFunction: 'cubic-bezier(0.4, 0, 0.2, 1)',
|
||||
transitionDuration: '200ms',
|
||||
content: '""',
|
||||
top: '0',
|
||||
left: '0',
|
||||
right: '0',
|
||||
bottom: '0',
|
||||
},
|
||||
'.isa-select-bullet:hover::before': {
|
||||
backgroundColor: '#778490',
|
||||
},
|
||||
'.isa-select-bullet:checked::before': {
|
||||
backgroundColor: '#596470',
|
||||
},
|
||||
'.isa-select-bullet::after': {
|
||||
content: '""',
|
||||
backgroundImage:
|
||||
"url(\"data:image/svg+xml,%3Csvg width='100%25' height='100%25' viewBox='0 0 24 24' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' xml:space='preserve' xmlns:serif='http://www.serif.com/'%3E%3Cpath fill='white' d='M21.432,3.715C21.432,3.715 21.432,3.715 21.432,3.715C21.115,3.76 20.823,3.911 20.604,4.143C16.03,8.727 12.603,12.511 8.244,16.932C8.244,16.932 3.297,12.754 3.297,12.754C2.909,12.424 2.374,12.327 1.895,12.499C1.895,12.499 1.895,12.499 1.895,12.499C1.415,12.672 1.065,13.088 0.975,13.589C0.885,14.091 1.072,14.602 1.463,14.929L7.415,19.966C7.981,20.441 8.818,20.403 9.338,19.877C14.251,14.954 17.761,11.007 22.616,6.141C23.057,5.714 23.172,5.051 22.903,4.499C22.903,4.499 22.903,4.499 22.903,4.499C22.633,3.948 22.04,3.631 21.432,3.715Z'/%3E%3C/svg%3E%0A\")",
|
||||
position: 'absolute',
|
||||
top: '0.4rem',
|
||||
left: '0.4rem',
|
||||
bottom: '0.4rem',
|
||||
right: '0.4rem',
|
||||
cursor: 'pointer',
|
||||
opacity: '0',
|
||||
transitionProperty: 'all',
|
||||
transitionTimingFunction: 'cubic-bezier(0.4, 0, 0.2, 1)',
|
||||
transitionDuration: '200ms',
|
||||
},
|
||||
'.isa-select-bullet:checked::after': {
|
||||
opacity: '1',
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -112,5 +112,9 @@ module.exports = {
|
||||
variants: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [require('./tailwind-plugins/label.plugin.js'), require('./tailwind-plugins/button.plugin.js')],
|
||||
plugins: [
|
||||
require('./tailwind-plugins/label.plugin.js'),
|
||||
require('./tailwind-plugins/button.plugin.js'),
|
||||
require('./tailwind-plugins/select-bullet.plugin.js'),
|
||||
],
|
||||
};
|
||||
|
||||
@@ -60,6 +60,9 @@
|
||||
"@domain/printer": [
|
||||
"apps/domain/printer/src/public-api.ts"
|
||||
],
|
||||
"@domain/product-list": [
|
||||
"apps/domain/product-list/src/public-api.ts"
|
||||
],
|
||||
"@domain/remission": [
|
||||
"apps/domain/remission/src/public-api.ts"
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user