mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-31 09:37:15 +01:00
Merged PR 229: #805 #659 #841 Bestellpostensplit - Availability is sum of all supplier qtys Fix Disabled Guest Button In Create Customer Component & Set PreferredSupplier Availability for download articles
Related work items: #659, #805, #841
This commit is contained in:
@@ -32,6 +32,10 @@ export function getFormatedPublicationDate(publicationDate: Date): string {
|
||||
);
|
||||
}
|
||||
|
||||
export function allowedAvailabilityStatusCodes(code: number) {
|
||||
return [2, 32, 256, 1024, 2048, 4096].findIndex(allowedCode => allowedCode === code) !== -1;
|
||||
export function allowedAvailabilityStatusCodes(code: number): boolean {
|
||||
return (
|
||||
[2, 32, 256, 1024, 2048, 4096].findIndex(
|
||||
(allowedCode) => allowedCode === code
|
||||
) !== -1
|
||||
);
|
||||
}
|
||||
|
||||
@@ -144,7 +144,6 @@ export class PayMethodComponent implements OnInit, OnDestroy {
|
||||
);
|
||||
}
|
||||
if (deliveryShippingDestionation && !downloadShippingDestionation) {
|
||||
// TODO HERE TTHE ERROR HAPPENS
|
||||
return forkJoin(
|
||||
this.store.dispatch(
|
||||
new SetDestinationToCheckout(
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
<div class="cart-content">
|
||||
<div class="cart-list">
|
||||
<hr />
|
||||
<app-invoice-address [disableAddressChanging]="disableAddressChanging"></app-invoice-address>
|
||||
<app-invoice-address
|
||||
[disableAddressChanging]="disableAddressChanging"
|
||||
></app-invoice-address>
|
||||
<hr />
|
||||
<app-notification-settings
|
||||
*ngIf="showNotificationSettings"
|
||||
@@ -22,33 +24,65 @@
|
||||
></app-notification-settings>
|
||||
<div *ngIf="takeNowCount$ | async" @removeItemCartTrigger>
|
||||
<hr />
|
||||
<app-take-now-cart (editItem)="enableDisableOrder($event)"></app-take-now-cart>
|
||||
<app-take-now-cart
|
||||
(editItem)="enableDisableOrder($event)"
|
||||
></app-take-now-cart>
|
||||
</div>
|
||||
<div *ngIf="deliveryCount$ | async" @removeItemCartTrigger [@cartPaymentType]="getDeliveryDeleteAnimation()">
|
||||
<div
|
||||
*ngIf="deliveryCount$ | async"
|
||||
@removeItemCartTrigger
|
||||
[@cartPaymentType]="getDeliveryDeleteAnimation()"
|
||||
>
|
||||
<hr />
|
||||
<app-delivery-cart [disableAddressChanging]="disableAddressChanging" (editItem)="enableDisableOrder($event)"></app-delivery-cart>
|
||||
<app-delivery-cart
|
||||
[disableAddressChanging]="disableAddressChanging"
|
||||
(editItem)="enableDisableOrder($event)"
|
||||
></app-delivery-cart>
|
||||
</div>
|
||||
<div *ngIf="pickUpCount$ | async" @removeItemCartTrigger [@cartPaymentType]="getPickUpDeleteAnimation()">
|
||||
<div
|
||||
*ngIf="pickUpCount$ | async"
|
||||
@removeItemCartTrigger
|
||||
[@cartPaymentType]="getPickUpDeleteAnimation()"
|
||||
>
|
||||
<hr />
|
||||
<app-pick-up-cart (editItem)="enableDisableOrder($event)"></app-pick-up-cart>
|
||||
<app-pick-up-cart
|
||||
(editItem)="enableDisableOrder($event)"
|
||||
></app-pick-up-cart>
|
||||
</div>
|
||||
<div *ngIf="downloadCount$ | async" @removeItemCartTrigger>
|
||||
<hr />
|
||||
<app-download-cart (editItem)="enableDisableOrder($event)"></app-download-cart>
|
||||
<app-download-cart
|
||||
(editItem)="enableDisableOrder($event)"
|
||||
></app-download-cart>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cart-footer">
|
||||
<div class="overview-container">
|
||||
<span class="items">{{ total.items }} Artikel I {{ (cartData$ | async)?.promotionPoints }} Lesepunkte</span>
|
||||
<span class="items"
|
||||
>{{ total.items }} Artikel I
|
||||
{{ (cartData$ | async)?.promotionPoints }} Lesepunkte</span
|
||||
>
|
||||
<div class="overview">
|
||||
<div class="overview-price-container">
|
||||
<span class="overview-price">Zwischensumme {{ total.price | bookPrice }} EUR</span>
|
||||
<span *ngIf="(deliveryCount$ | async) > 0" class="overview-tax">ohne Versandkosten</span>
|
||||
<span *ngIf="(deliveryCount$ | async) === 0" class="overview-tax"> </span>
|
||||
<span class="overview-price"
|
||||
>Zwischensumme {{ total.price | bookPrice }} EUR</span
|
||||
>
|
||||
<span *ngIf="(deliveryCount$ | async) > 0" class="overview-tax"
|
||||
>ohne Versandkosten</span
|
||||
>
|
||||
<span *ngIf="(deliveryCount$ | async) === 0" class="overview-tax"
|
||||
> </span
|
||||
>
|
||||
</div>
|
||||
<app-button (action)="next()" [disabled]="orderDisabled" [primary]="true" [load]="true" [stayOnPage]="true" #continue
|
||||
<app-button
|
||||
(action)="next()"
|
||||
[disabled]="orderDisabled"
|
||||
[primary]="true"
|
||||
[load]="true"
|
||||
[stayOnPage]="true"
|
||||
#continue
|
||||
>Bestellen</app-button
|
||||
>
|
||||
</div>
|
||||
@@ -58,18 +92,25 @@
|
||||
|
||||
<ng-template #emptyCart>
|
||||
<div class="cart-container-empty">
|
||||
<div class="image-empty"><img src="assets/images/shopping_cart_white.svg" /></div>
|
||||
<div class="image-empty">
|
||||
<img src="assets/images/shopping_cart_white.svg" />
|
||||
</div>
|
||||
<div class="header-empty"><span>Ihr Warenkorb ist leer.</span></div>
|
||||
<div class="content-empty"><span>Sie haben alle Artikel aus dem</span></div>
|
||||
<div class="content-empty"><span>Warenkorb entfernt oder noch</span></div>
|
||||
<div class="content-empty"><span>Artikel hinzugefügt.</span></div>
|
||||
<div class="btn-empty">
|
||||
<app-button [primary]="true" (action)="search()">Artikel suchen</app-button>
|
||||
<app-button [primary]="true" (action)="search()"
|
||||
>Artikel suchen</app-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<app-printer-selection #printModal (print)="print($event)"></app-printer-selection>
|
||||
<app-printer-selection
|
||||
#printModal
|
||||
(print)="print($event)"
|
||||
></app-printer-selection>
|
||||
|
||||
<app-pay-method
|
||||
#payMethod
|
||||
|
||||
@@ -1,20 +1,344 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ProductCheckoutComponent } from './product-checkout.component';
|
||||
import { DeliveryOption } from 'apps/sales/src/app/core/models/delivery-option.model';
|
||||
import {
|
||||
ProductAvailabilityService,
|
||||
BranchService,
|
||||
} from '@sales/core-services';
|
||||
import { of } from 'rxjs';
|
||||
import { CheckoutType } from 'apps/sales/src/app/core/models/checkout-type.enum';
|
||||
import { AvailabilityDTO } from '@swagger/availability';
|
||||
import { NO_ERRORS_SCHEMA, ChangeDetectorRef } from '@angular/core';
|
||||
import { BookPricePipe } from 'apps/sales/src/app/pipes/book-price.pipe';
|
||||
import { ModalService } from '@libs/ui';
|
||||
import { NgxsModule } from '@ngxs/store';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { BranchDTO } from '@swagger/checkout';
|
||||
import { ProductAvailability } from 'apps/sales/src/app/core/models/product-availability.model';
|
||||
|
||||
describe('ProductCheckoutComponent', () => {
|
||||
const mockAvailabilityResponse: {
|
||||
branchId: number;
|
||||
type: CheckoutType;
|
||||
av: AvailabilityDTO[];
|
||||
} = {
|
||||
branchId: 1,
|
||||
type: CheckoutType.store,
|
||||
av: [
|
||||
{
|
||||
itemId: 42455413,
|
||||
requestReference: '0',
|
||||
ean: '9783957260376',
|
||||
shop: 3,
|
||||
price: { value: { value: 16.8, currency: 'EUR' }, vat: { vatType: 8 } },
|
||||
supplier: 'L',
|
||||
supplierId: 3,
|
||||
ssc: '999',
|
||||
sscText: 'Lieferbar in 1-2 Tagen',
|
||||
qty: 9.0,
|
||||
isPrebooked: false,
|
||||
at: '2020-07-16T14:00:00',
|
||||
status: 1024,
|
||||
preferred: 1,
|
||||
requested: '2020-07-15T08:28:39.5751342Z',
|
||||
requestStatusCode: '1',
|
||||
requestMessage: 'OK',
|
||||
},
|
||||
{
|
||||
itemId: 42455413,
|
||||
requestReference: '0',
|
||||
ean: '9783957260376',
|
||||
shop: 3,
|
||||
price: { value: { value: 16.8, currency: 'EUR' }, vat: { vatType: 8 } },
|
||||
supplier: 'K',
|
||||
supplierId: 4,
|
||||
ssc: '999',
|
||||
sscText: 'Lieferbar in 1-2 Tagen',
|
||||
qty: 6.0,
|
||||
isPrebooked: false,
|
||||
at: '2020-07-16T14:00:00',
|
||||
status: 1024,
|
||||
preferred: 0,
|
||||
requested: '2020-07-15T08:28:39.5754585Z',
|
||||
requestStatusCode: '1',
|
||||
requestMessage: 'OK',
|
||||
},
|
||||
{
|
||||
itemId: 42455413,
|
||||
requestReference: '0',
|
||||
ean: '9783957260376',
|
||||
shop: 3,
|
||||
price: { value: { value: 16.8, currency: 'EUR' }, vat: { vatType: 8 } },
|
||||
supplier: 'LV3',
|
||||
supplierId: 13,
|
||||
ssc: '999',
|
||||
sscText: 'Lieferbar in 10-14Tagen',
|
||||
isPrebooked: false,
|
||||
at: '2020-07-29T00:00:00',
|
||||
status: 1024,
|
||||
preferred: 0,
|
||||
requested: '2020-07-15T08:28:39.5757159Z',
|
||||
requestStatusCode: '1',
|
||||
requestMessage: 'OK',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const mockProductAvailabilities: ProductAvailability[] = [
|
||||
{
|
||||
av: {
|
||||
at: '2020-07-15T14:00:00+02:00',
|
||||
ean: '9783957260291',
|
||||
isPrebooked: false,
|
||||
itemId: 38219742,
|
||||
logisticianId: 1002,
|
||||
preferred: 1,
|
||||
price: { value: { value: 9.99, currency: 'EUR' }, vat: { vatType: 2 } },
|
||||
qty: 1,
|
||||
requestMessage: 'Artikel ist lieferbar.',
|
||||
requestReference: '0',
|
||||
requestStatusCode: '1',
|
||||
requested: '2020-07-15T15:19:50.8364336Z',
|
||||
ssc: '005',
|
||||
sscText: 'Sofort lieferbar (Download)',
|
||||
status: 1024,
|
||||
supplier: 'DIG',
|
||||
supplierId: 41,
|
||||
supplierProductNumber: '33161986',
|
||||
},
|
||||
itemId: 38219742,
|
||||
branchId: 123,
|
||||
quantity: 1,
|
||||
status: 1024,
|
||||
type: 3,
|
||||
},
|
||||
{
|
||||
av: {
|
||||
at: '2020-08-15T14:00:00+02:00',
|
||||
ean: '9783957270291',
|
||||
isPrebooked: false,
|
||||
itemId: 38229742,
|
||||
logisticianId: 1002,
|
||||
preferred: 0,
|
||||
price: { value: { value: 3.99, currency: 'EUR' }, vat: { vatType: 2 } },
|
||||
qty: 1,
|
||||
requestMessage: 'Artikel ist lieferbar.',
|
||||
requestReference: '0',
|
||||
requestStatusCode: '1',
|
||||
requested: '2020-07-15T15:19:50.8364336Z',
|
||||
ssc: '005',
|
||||
sscText: 'Sofort lieferbar (Download)',
|
||||
status: 1024,
|
||||
supplier: 'DIG',
|
||||
supplierId: 41,
|
||||
supplierProductNumber: '33161986',
|
||||
},
|
||||
itemId: 38219742,
|
||||
branchId: 456,
|
||||
quantity: 1,
|
||||
status: 1024,
|
||||
type: 3,
|
||||
},
|
||||
];
|
||||
|
||||
fdescribe('ProductCheckoutComponent', () => {
|
||||
let component: ProductCheckoutComponent;
|
||||
let fixture: ComponentFixture<ProductCheckoutComponent>;
|
||||
let productAvailabilityService: jasmine.SpyObj<ProductAvailabilityService>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ProductCheckoutComponent]
|
||||
}).compileComponents();
|
||||
imports: [NgxsModule.forRoot([]), RouterTestingModule],
|
||||
declarations: [ProductCheckoutComponent, BookPricePipe],
|
||||
providers: [
|
||||
{
|
||||
provide: ProductAvailabilityService,
|
||||
useValue: jasmine.createSpyObj('productAvailabilityService', [
|
||||
'getStoreAvailability',
|
||||
]),
|
||||
},
|
||||
{
|
||||
provide: ModalService,
|
||||
useValue: jasmine.createSpy('modalService'),
|
||||
},
|
||||
{
|
||||
provide: BranchService,
|
||||
useValue: jasmine.createSpy('branchService'),
|
||||
},
|
||||
DatePipe,
|
||||
ChangeDetectorRef,
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA],
|
||||
})
|
||||
.overrideTemplate(ProductCheckoutComponent, '<div>Test</div>')
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ProductCheckoutComponent);
|
||||
component = fixture.componentInstance;
|
||||
productAvailabilityService = TestBed.get(ProductAvailabilityService);
|
||||
|
||||
spyOn(component, 'ngOnInit').and.callFake(() => {});
|
||||
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
describe('get preferredDownloadAvailability', () => {
|
||||
let availabilities: ProductAvailability[];
|
||||
|
||||
beforeEach(() => {
|
||||
availabilities = mockProductAvailabilities;
|
||||
|
||||
component.isDownload = true;
|
||||
component.availability = availabilities;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should return the preferred availability', () => {
|
||||
const expected = mockProductAvailabilities[0].av;
|
||||
|
||||
const result = component.preferredDownloadAvailability;
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should return undefined if availability is undefined', () => {
|
||||
component.availability = undefined;
|
||||
|
||||
fixture.detectChanges();
|
||||
const result = component.preferredDownloadAvailability;
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should return undefined if no matching availabilities exist', () => {
|
||||
const availabilitiesWithTakeNowCheckoutType = mockProductAvailabilities.map(
|
||||
(av) => ({ ...av, type: 0 })
|
||||
);
|
||||
|
||||
component.availability = availabilitiesWithTakeNowCheckoutType;
|
||||
fixture.detectChanges();
|
||||
|
||||
const result = component.preferredDownloadAvailability;
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('setQuantityError', () => {
|
||||
let numberOfItems: number;
|
||||
beforeEach(() => {
|
||||
spyOn(component, 'setQuantityError').and.callThrough();
|
||||
numberOfItems = 16;
|
||||
});
|
||||
|
||||
it('should return Exemplar if only 1 item is available', () => {
|
||||
const limit = 1;
|
||||
const expected = `${limit} Exemplar sofort lieferbar.`;
|
||||
component.setQuantityError(numberOfItems, limit);
|
||||
|
||||
expect(component.quantityError).toEqual(expected);
|
||||
});
|
||||
it('should return Exemplar if more than 1 item is available', () => {
|
||||
const limit = 10;
|
||||
const expected = `${limit} Exemplare sofort lieferbar.`;
|
||||
|
||||
component.setQuantityError(numberOfItems, limit);
|
||||
|
||||
expect(component.quantityError).toEqual(expected);
|
||||
});
|
||||
it('should return a error message if requested items is larger than 999', () => {
|
||||
const limit = 10;
|
||||
numberOfItems = 1000;
|
||||
|
||||
const expected = `Achtung, Maximal ${limit} Exemplare bestellbar.`;
|
||||
component.setQuantityError(numberOfItems, limit);
|
||||
|
||||
expect(component.quantityError).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('validateAvailability', () => {
|
||||
beforeEach(() => {
|
||||
spyOn(component, 'validateAvailability').and.callThrough();
|
||||
|
||||
component.book = {
|
||||
product: { ean: 123 },
|
||||
};
|
||||
|
||||
component.selectedBranch = { id: 789 } as BranchDTO;
|
||||
});
|
||||
|
||||
it('should provide the sum of available quantities across all suppliers', async () => {
|
||||
component.deliveryType = DeliveryOption.PICK_UP;
|
||||
productAvailabilityService.getStoreAvailability.and.returnValue(
|
||||
of(mockAvailabilityResponse)
|
||||
);
|
||||
fixture.detectChanges();
|
||||
|
||||
const expected = 15;
|
||||
const result = await component.validateAvailability(9);
|
||||
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should return 0 if no supplier has any quantity available', async () => {
|
||||
component.deliveryType = DeliveryOption.PICK_UP;
|
||||
const responseWithOutQuantity = setMockAvailablityResponse(
|
||||
mockAvailabilityResponse,
|
||||
'qty',
|
||||
0
|
||||
);
|
||||
productAvailabilityService.getStoreAvailability.and.returnValue(
|
||||
of(responseWithOutQuantity)
|
||||
);
|
||||
fixture.detectChanges();
|
||||
|
||||
const expected = 0;
|
||||
const result = await component.validateAvailability(9);
|
||||
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
it('should return 0 if no availabliliy has an eligible (allowed) status code', async () => {
|
||||
component.deliveryType = DeliveryOption.PICK_UP;
|
||||
|
||||
const responseWithFakeStatusCode = setMockAvailablityResponse(
|
||||
mockAvailabilityResponse,
|
||||
'status',
|
||||
5
|
||||
);
|
||||
|
||||
productAvailabilityService.getStoreAvailability.and.returnValue(
|
||||
of(responseWithFakeStatusCode)
|
||||
);
|
||||
fixture.detectChanges();
|
||||
|
||||
const expected = 0;
|
||||
const result = await component.validateAvailability(9);
|
||||
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function setMockAvailablityResponse(
|
||||
mr: {
|
||||
branchId: number;
|
||||
type: CheckoutType;
|
||||
av: AvailabilityDTO[];
|
||||
},
|
||||
property: keyof AvailabilityDTO,
|
||||
value: string | number
|
||||
): {
|
||||
branchId: number;
|
||||
type: CheckoutType;
|
||||
av: AvailabilityDTO[];
|
||||
} {
|
||||
return {
|
||||
...mr,
|
||||
av: (mr.av.map(({ [property]: prop, ...rest }) => ({
|
||||
rest,
|
||||
property: value,
|
||||
})) as unknown) as AvailabilityDTO[],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
import { Component, OnInit, Output, EventEmitter, Input, OnDestroy, ViewChild, ChangeDetectorRef, ViewRef } from '@angular/core';
|
||||
import { ModalService, ButtonComponent, DeleteDropdownComponent } from '@libs/ui';
|
||||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
Output,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnDestroy,
|
||||
ViewChild,
|
||||
ChangeDetectorRef,
|
||||
ViewRef,
|
||||
} from '@angular/core';
|
||||
import { ModalService, DeleteDropdownComponent } from '@libs/ui';
|
||||
import { Router } from '@angular/router';
|
||||
import { Store, Select } from '@ngxs/store';
|
||||
import { ItemDTO } from '@swagger/cat';
|
||||
@@ -7,7 +17,7 @@ import { DeliveryOption } from '../../../../core/models/delivery-option.model';
|
||||
import { ChangeCurrentRoute } from '../../../../core/store/actions/process.actions';
|
||||
import { SetCartEntry } from '../../../../core/store/actions/cart-entry.actions';
|
||||
import { Subject, Observable, of } from 'rxjs';
|
||||
import { takeUntil, tap, map, filter, take } from 'rxjs/operators';
|
||||
import { tap, map, filter, take } from 'rxjs/operators';
|
||||
import { AddBreadcrumb } from '../../../../core/store/actions/breadcrumb.actions';
|
||||
import { Breadcrumb } from '../../../../core/models/breadcrumb.model';
|
||||
import { BranchSelectors } from '../../../../core/store/selectors/branch.selector';
|
||||
@@ -15,7 +25,11 @@ import { ProductAvailability } from '../../../../core/models/product-availabilit
|
||||
import { CheckoutType } from '../../../../core/models/checkout-type.enum';
|
||||
import { BranchDTO } from '@swagger/checkout';
|
||||
import { AvailabilityDTO } from '@swagger/availability';
|
||||
import { mapToIterable, distance, objectNotNull } from '../../../../core/utils/app.utils';
|
||||
import {
|
||||
mapToIterable,
|
||||
distance,
|
||||
objectNotNull,
|
||||
} from '../../../../core/utils/app.utils';
|
||||
import { isNullOrUndefined } from 'util';
|
||||
import { ProductAvailabilityService } from '../../../../core/services/product-availability.service';
|
||||
import { BranchService } from '../../../../core/services/branch.service';
|
||||
@@ -26,7 +40,6 @@ import { SearchDropdownComponent } from '@libs/ui/lib/search-dropdown';
|
||||
import { AddBranchesIfNotLoaded } from 'apps/sales/src/app/core/store/actions/branch.actions';
|
||||
import { allowedAvailabilityStatusCodes } from 'apps/sales/src/app/core/utils/product.util';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-checkout',
|
||||
templateUrl: './product-checkout.component.html',
|
||||
@@ -34,11 +47,17 @@ import { allowedAvailabilityStatusCodes } from 'apps/sales/src/app/core/utils/pr
|
||||
})
|
||||
export class ProductCheckoutComponent implements OnInit, OnDestroy {
|
||||
@Select(SharedSelectors.getCart) cartData$: Observable<ProcessCart>;
|
||||
@Select(SharedSelectors.getBreadcrumbs) getBreadcrumbs$: Observable<Breadcrumb[]>;
|
||||
@Select(BranchSelectors.getBranches) branches$: Observable<{ [key: number]: BranchDTO }>;
|
||||
@Select(SharedSelectors.getBreadcrumbs) getBreadcrumbs$: Observable<
|
||||
Breadcrumb[]
|
||||
>;
|
||||
@Select(BranchSelectors.getBranches) branches$: Observable<{
|
||||
[key: number]: BranchDTO;
|
||||
}>;
|
||||
|
||||
@ViewChild('deleteDropdown', { static: false }) deleteDropdown: DeleteDropdownComponent;
|
||||
@ViewChild('branchesdropdown', { static: false }) branchesdd: SearchDropdownComponent;
|
||||
@ViewChild('deleteDropdown', { static: false })
|
||||
deleteDropdown: DeleteDropdownComponent;
|
||||
@ViewChild('branchesdropdown', { static: false })
|
||||
branchesdd: SearchDropdownComponent;
|
||||
|
||||
id = 'checkout-modal';
|
||||
stepOne = true;
|
||||
@@ -87,7 +106,10 @@ export class ProductCheckoutComponent implements OnInit, OnDestroy {
|
||||
@Input() availability: ProductAvailability[];
|
||||
|
||||
get takeNowAvailable() {
|
||||
if (this.availability.filter((t) => t.type === CheckoutType.takeNow).length > 0) {
|
||||
if (
|
||||
this.availability.filter((t) => t.type === CheckoutType.takeNow).length >
|
||||
0
|
||||
) {
|
||||
return of(true);
|
||||
}
|
||||
return of(false);
|
||||
@@ -98,7 +120,8 @@ export class ProductCheckoutComponent implements OnInit, OnDestroy {
|
||||
this.availability.filter(
|
||||
(t) =>
|
||||
t.type === CheckoutType.store &&
|
||||
(allowedAvailabilityStatusCodes(t.status) || (t.av && t.av.ssc === '830' && t.av.supplier === 'G'))
|
||||
(allowedAvailabilityStatusCodes(t.status) ||
|
||||
(t.av && t.av.ssc === '830' && t.av.supplier === 'G'))
|
||||
).length > 0
|
||||
) {
|
||||
return of(true);
|
||||
@@ -107,7 +130,13 @@ export class ProductCheckoutComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
get shippingAvailable() {
|
||||
if (this.availability.filter((t) => t.type === CheckoutType.delivery && allowedAvailabilityStatusCodes(t.status)).length > 0) {
|
||||
if (
|
||||
this.availability.filter(
|
||||
(t) =>
|
||||
t.type === CheckoutType.delivery &&
|
||||
allowedAvailabilityStatusCodes(t.status)
|
||||
).length > 0
|
||||
) {
|
||||
return of(true);
|
||||
}
|
||||
return of(false);
|
||||
@@ -188,6 +217,25 @@ export class ProductCheckoutComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
get preferredDownloadAvailability(): AvailabilityDTO {
|
||||
if (this.availability) {
|
||||
const downloadAvailabilites = this.availability.filter(
|
||||
(availability) => availability.type === CheckoutType.donwload
|
||||
);
|
||||
|
||||
if (downloadAvailabilites) {
|
||||
const preferredProductAvailability = downloadAvailabilites.find(
|
||||
(productAvailability) =>
|
||||
!!productAvailability.av && !!productAvailability.av.preferred
|
||||
);
|
||||
|
||||
if (preferredProductAvailability) {
|
||||
return preferredProductAvailability.av;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor(
|
||||
private modalService: ModalService,
|
||||
private store: Store,
|
||||
@@ -196,22 +244,21 @@ export class ProductCheckoutComponent implements OnInit, OnDestroy {
|
||||
private branchService: BranchService,
|
||||
private datePipe: DatePipe,
|
||||
private cdrf: ChangeDetectorRef
|
||||
) { }
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
if (this.isDownload) {
|
||||
this.stepTwoImgType = 'download-type';
|
||||
this.possibleItems = [1];
|
||||
this.deliveryType = DeliveryOption.DOWNLOAD;
|
||||
if (this.availability && this.availability.length > 0) {
|
||||
const currAv = this.availability.filter((t) => t && t.type === CheckoutType.donwload);
|
||||
if (currAv && currAv[0] && currAv[0].av) {
|
||||
this.currentAvailability = currAv[0].av;
|
||||
}
|
||||
if (this.preferredDownloadAvailability) {
|
||||
this.currentAvailability = this.preferredDownloadAvailability;
|
||||
}
|
||||
}
|
||||
|
||||
this.currency = this.book.catalogAvailability.price ? this.book.catalogAvailability.price.value.currency : null;
|
||||
this.currency = this.book.catalogAvailability.price
|
||||
? this.book.catalogAvailability.price.value.currency
|
||||
: null;
|
||||
this.currentPoints = this.book.promoPoints + '';
|
||||
|
||||
this.branches$
|
||||
@@ -255,8 +302,12 @@ export class ProductCheckoutComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
|
||||
this.branchList = branches;
|
||||
const userBranchNumber = this.store.selectSnapshot(BranchSelectors.getUserBranch);
|
||||
const userBranch = branches.find((t) => t.branchNumber === userBranchNumber);
|
||||
const userBranchNumber = this.store.selectSnapshot(
|
||||
BranchSelectors.getUserBranch
|
||||
);
|
||||
const userBranch = branches.find(
|
||||
(t) => t.branchNumber === userBranchNumber
|
||||
);
|
||||
if (!!userBranch) {
|
||||
this.selectedBranch = userBranch;
|
||||
this.currentLocation = userBranch.name;
|
||||
@@ -277,29 +328,49 @@ export class ProductCheckoutComponent implements OnInit, OnDestroy {
|
||||
this.filteredBranches = this.branches;
|
||||
if (!!userBranch) {
|
||||
this.filteredBranches = this.branchesData
|
||||
.sort((a: BranchDTO, b: BranchDTO) => this.branchSorterFn(a, b, userBranch))
|
||||
.sort((a: BranchDTO, b: BranchDTO) =>
|
||||
this.branchSorterFn(a, b, userBranch)
|
||||
)
|
||||
.map((t) => t.name);
|
||||
}
|
||||
}
|
||||
|
||||
private branchSorterFn(a: BranchDTO, b: BranchDTO, userBranch: BranchDTO) {
|
||||
const userLat = userBranch.address && userBranch.address.geoLocation ? userBranch.address.geoLocation.latitude : 0;
|
||||
const userLong = userBranch.address && userBranch.address.geoLocation ? userBranch.address.geoLocation.longitude : 0;
|
||||
const aLat = a.address && a.address.geoLocation ? a.address.geoLocation.latitude : 0;
|
||||
const aLong = a.address && a.address.geoLocation ? a.address.geoLocation.longitude : 0;
|
||||
const bLat = b.address && b.address.geoLocation ? b.address.geoLocation.latitude : 0;
|
||||
const bLong = b.address && b.address.geoLocation ? b.address.geoLocation.longitude : 0;
|
||||
const userLat =
|
||||
userBranch.address && userBranch.address.geoLocation
|
||||
? userBranch.address.geoLocation.latitude
|
||||
: 0;
|
||||
const userLong =
|
||||
userBranch.address && userBranch.address.geoLocation
|
||||
? userBranch.address.geoLocation.longitude
|
||||
: 0;
|
||||
const aLat =
|
||||
a.address && a.address.geoLocation ? a.address.geoLocation.latitude : 0;
|
||||
const aLong =
|
||||
a.address && a.address.geoLocation ? a.address.geoLocation.longitude : 0;
|
||||
const bLat =
|
||||
b.address && b.address.geoLocation ? b.address.geoLocation.latitude : 0;
|
||||
const bLong =
|
||||
b.address && b.address.geoLocation ? b.address.geoLocation.longitude : 0;
|
||||
const aDist = distance(userLat, userLong, aLat, aLong);
|
||||
const bDist = distance(userLat, userLong, bLat, bLong);
|
||||
return aDist - bDist;
|
||||
}
|
||||
|
||||
branchSearch(term: string) {
|
||||
const userBranchNumber = this.store.selectSnapshot(BranchSelectors.getUserBranch);
|
||||
const userBranchNumber = this.store.selectSnapshot(
|
||||
BranchSelectors.getUserBranch
|
||||
);
|
||||
const branchList = [...this.branchesData];
|
||||
const userBranch = branchList.find((t) => t.branchNumber === userBranchNumber);
|
||||
const userBranch = branchList.find(
|
||||
(t) => t.branchNumber === userBranchNumber
|
||||
);
|
||||
if (isNullOrUndefined(term) || term.length < 1) {
|
||||
this.filteredBranches = branchList.sort((a: BranchDTO, b: BranchDTO) => this.branchSorterFn(a, b, userBranch)).map((t) => t.name);
|
||||
this.filteredBranches = branchList
|
||||
.sort((a: BranchDTO, b: BranchDTO) =>
|
||||
this.branchSorterFn(a, b, userBranch)
|
||||
)
|
||||
.map((t) => t.name);
|
||||
return;
|
||||
}
|
||||
this.branchService
|
||||
@@ -334,7 +405,9 @@ export class ProductCheckoutComponent implements OnInit, OnDestroy {
|
||||
this.store.dispatch(new AddBranchesIfNotLoaded(branches));
|
||||
if (branches) {
|
||||
branches.forEach((br) => {
|
||||
const existsInBranchData = this.branchesData.find((t) => t.branchNumber === br.branchNumber);
|
||||
const existsInBranchData = this.branchesData.find(
|
||||
(t) => t.branchNumber === br.branchNumber
|
||||
);
|
||||
if (!existsInBranchData) {
|
||||
this.branches.push(br.name);
|
||||
this.branchesData.push(br);
|
||||
@@ -351,26 +424,40 @@ export class ProductCheckoutComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
storeBranches(): Observable<number[]> {
|
||||
return of(this.availability.filter((t) => t.type === CheckoutType.store).map((t) => t.branchId));
|
||||
return of(
|
||||
this.availability
|
||||
.filter((t) => t.type === CheckoutType.store)
|
||||
.map((t) => t.branchId)
|
||||
);
|
||||
}
|
||||
|
||||
// STEP ONE
|
||||
selectLocation(location: string) {
|
||||
this.branchLoad = true;
|
||||
this.searchingNewBranch = true;
|
||||
const branch = this.branchesData.find((b: BranchDTO) => b.name === location);
|
||||
const branch = this.branchesData.find(
|
||||
(b: BranchDTO) => b.name === location
|
||||
);
|
||||
// reset store availability
|
||||
this.availability = [...this.availability.filter((t) => t.type !== CheckoutType.store)];
|
||||
this.availability = [
|
||||
...this.availability.filter((t) => t.type !== CheckoutType.store),
|
||||
];
|
||||
this.productAvailabilityService
|
||||
.getStoreAvailability(this.book, this.book.product.ean, branch.id)
|
||||
.pipe(
|
||||
tap((response) => {
|
||||
if (response.av && response.av.length > 0) {
|
||||
this.currentLocation = location;
|
||||
this.filteredBranches = [location, ...this.branches.filter((t) => t !== location)];
|
||||
this.filteredBranches = [
|
||||
location,
|
||||
...this.branches.filter((t) => t !== location),
|
||||
];
|
||||
this.selectedBranch = branch;
|
||||
const preferedAv = response.av.find((t) => t.preferred === 1);
|
||||
this.currentPickUpDate = this.datePipe.transform(new Date(preferedAv.at), 'dd.MM.yy');
|
||||
this.currentPickUpDate = this.datePipe.transform(
|
||||
new Date(preferedAv.at),
|
||||
'dd.MM.yy'
|
||||
);
|
||||
response.av.forEach((t) => {
|
||||
this.availability.push({
|
||||
itemId: t.itemId,
|
||||
@@ -395,13 +482,19 @@ export class ProductCheckoutComponent implements OnInit, OnDestroy {
|
||||
return;
|
||||
}
|
||||
if (action === DeliveryOption.TAKE_NOW) {
|
||||
this.currentAvailability = this.availability.find((t) => t.type === CheckoutType.takeNow).av;
|
||||
this.currentAvailability = this.availability.find(
|
||||
(t) => t.type === CheckoutType.takeNow
|
||||
).av;
|
||||
this.stepTwoImgType = 'Take_now';
|
||||
this.deliveryType = DeliveryOption.TAKE_NOW;
|
||||
this.confirmationBtnText = 'Reservieren';
|
||||
// Set user branch as selected branch
|
||||
const userBranchNumber = this.store.selectSnapshot(BranchSelectors.getUserBranch);
|
||||
const userBranch = this.branchList.find((t) => t.branchNumber === userBranchNumber);
|
||||
const userBranchNumber = this.store.selectSnapshot(
|
||||
BranchSelectors.getUserBranch
|
||||
);
|
||||
const userBranch = this.branchList.find(
|
||||
(t) => t.branchNumber === userBranchNumber
|
||||
);
|
||||
if (!!userBranch) {
|
||||
this.selectedBranch = userBranch;
|
||||
this.currentLocation = userBranch.name;
|
||||
@@ -410,12 +503,16 @@ export class ProductCheckoutComponent implements OnInit, OnDestroy {
|
||||
if (!this.availability.find((t) => t.type === CheckoutType.store)) {
|
||||
return;
|
||||
}
|
||||
this.currentAvailability = this.availability.find((t) => t.type === CheckoutType.store).av;
|
||||
this.currentAvailability = this.availability.find(
|
||||
(t) => t.type === CheckoutType.store
|
||||
).av;
|
||||
this.stepTwoImgType = 'Package_Icon';
|
||||
this.deliveryType = DeliveryOption.PICK_UP;
|
||||
this.confirmationBtnText = 'Fortfahren';
|
||||
} else {
|
||||
this.currentAvailability = this.availability.find((t) => t.type === CheckoutType.delivery).av;
|
||||
this.currentAvailability = this.availability.find(
|
||||
(t) => t.type === CheckoutType.delivery
|
||||
).av;
|
||||
this.stepTwoImgType = 'truck_Icon';
|
||||
this.deliveryType = DeliveryOption.DELIVERY;
|
||||
this.confirmationBtnText = 'Fortfahren';
|
||||
@@ -442,7 +539,8 @@ export class ProductCheckoutComponent implements OnInit, OnDestroy {
|
||||
this.loading = true;
|
||||
const av = await this.validateAvailability(numberOfItems);
|
||||
this.setQuantityError(numberOfItems, av);
|
||||
const isTakeNowAndSelectedMoreThanInStock = this.deliveryType === DeliveryOption.TAKE_NOW && numberOfItems > av;
|
||||
const isTakeNowAndSelectedMoreThanInStock =
|
||||
this.deliveryType === DeliveryOption.TAKE_NOW && numberOfItems > av;
|
||||
isTakeNowAndSelectedMoreThanInStock.ifFalse(() => {
|
||||
this.addItemsToCartDisabled = false;
|
||||
});
|
||||
@@ -458,7 +556,9 @@ export class ProductCheckoutComponent implements OnInit, OnDestroy {
|
||||
if (numberOfItems > 999) {
|
||||
this.quantityError = `Achtung, Maximal ${limit} Exemplare bestellbar.`;
|
||||
} else if (numberOfItems > limit) {
|
||||
this.quantityError = `${limit} Exemplar sofort lieferbar.`;
|
||||
this.quantityError = `${limit} ${
|
||||
limit > 1 ? 'Exemplare' : 'Exemplar'
|
||||
} sofort lieferbar.`;
|
||||
} else {
|
||||
this.quantityError = null;
|
||||
}
|
||||
@@ -478,24 +578,31 @@ export class ProductCheckoutComponent implements OnInit, OnDestroy {
|
||||
).toPromise();
|
||||
} else if (this.deliveryType === DeliveryOption.PICK_UP) {
|
||||
const storeAvailability = await this.productAvailabilityService
|
||||
.getStoreAvailability(this.book, this.book.product.ean, this.selectedBranch.id, numberOfItems)
|
||||
.getStoreAvailability(
|
||||
this.book,
|
||||
this.book.product.ean,
|
||||
this.selectedBranch.id,
|
||||
numberOfItems
|
||||
)
|
||||
.pipe(
|
||||
map((response) => {
|
||||
if (response && response.av) {
|
||||
const preferedAv = response.av.find((t) => t && t.preferred === 1);
|
||||
let preferredQty = 0;
|
||||
if (preferedAv) {
|
||||
this.currentAvailability = preferedAv;
|
||||
this._pikUpPrice = preferedAv.price.value.value;
|
||||
if (allowedAvailabilityStatusCodes(preferedAv.status)) {
|
||||
preferredQty = preferedAv.qty;
|
||||
}
|
||||
this.detectChanges();
|
||||
}
|
||||
if (preferredQty) {
|
||||
return preferredQty;
|
||||
}
|
||||
return 0;
|
||||
const eligibleAvailabilities = response.av
|
||||
.filter(
|
||||
(availability) =>
|
||||
allowedAvailabilityStatusCodes(availability.status) &&
|
||||
availability.qty
|
||||
)
|
||||
.map((availability) => availability.qty);
|
||||
|
||||
const totalAvailableQuantity = eligibleAvailabilities.reduce(
|
||||
(acc, curr) => acc + curr,
|
||||
0
|
||||
);
|
||||
|
||||
this.detectChanges();
|
||||
|
||||
return totalAvailableQuantity;
|
||||
}
|
||||
return 0;
|
||||
})
|
||||
@@ -505,11 +612,18 @@ export class ProductCheckoutComponent implements OnInit, OnDestroy {
|
||||
return storeAvailability;
|
||||
} else if (this.deliveryType === DeliveryOption.DELIVERY) {
|
||||
const shippingAvailability = await this.productAvailabilityService
|
||||
.getShippingAvailability(this.book, this.book.product.ean, +this.selectedBranch.branchNumber, numberOfItems)
|
||||
.getShippingAvailability(
|
||||
this.book,
|
||||
this.book.product.ean,
|
||||
+this.selectedBranch.branchNumber,
|
||||
numberOfItems
|
||||
)
|
||||
.pipe(
|
||||
map((response) => {
|
||||
if (response && response.av) {
|
||||
const preferedAv = response.av.find((t) => t && t.preferred === 1);
|
||||
const preferedAv = response.av.find(
|
||||
(t) => t && t.preferred === 1
|
||||
);
|
||||
let preferredQty = 0;
|
||||
if (preferedAv) {
|
||||
this.currentAvailability = preferedAv;
|
||||
@@ -572,11 +686,15 @@ export class ProductCheckoutComponent implements OnInit, OnDestroy {
|
||||
|
||||
private redirectRoute() {
|
||||
if (this.customerAlredySet) {
|
||||
this.store.dispatch(new AddBreadcrumb(this.generateBreadcrumb(), 'shoppingCart', true));
|
||||
this.store.dispatch(
|
||||
new AddBreadcrumb(this.generateBreadcrumb(), 'shoppingCart', true)
|
||||
);
|
||||
this.store.dispatch(new ChangeCurrentRoute('/cart/review'));
|
||||
this.router.navigate(['/cart/review']);
|
||||
} else {
|
||||
this.store.dispatch(new AddBreadcrumb(this.generateBreadcrumb(), 'customer', true));
|
||||
this.store.dispatch(
|
||||
new AddBreadcrumb(this.generateBreadcrumb(), 'customer', true)
|
||||
);
|
||||
this.store.dispatch(new ChangeCurrentRoute('/customer/search'));
|
||||
this.router.navigate(['/customer/search']);
|
||||
}
|
||||
@@ -630,7 +748,11 @@ export class ProductCheckoutComponent implements OnInit, OnDestroy {
|
||||
|
||||
detectChanges() {
|
||||
setTimeout(() => {
|
||||
if (this.cdrf !== null && this.cdrf !== undefined && !(this.cdrf as ViewRef).destroyed) {
|
||||
if (
|
||||
this.cdrf !== null &&
|
||||
this.cdrf !== undefined &&
|
||||
!(this.cdrf as ViewRef).destroyed
|
||||
) {
|
||||
this.cdrf.detectChanges();
|
||||
}
|
||||
}, 0);
|
||||
|
||||
Reference in New Issue
Block a user