Skip to content

Commit

Permalink
feat: enable the b2b user to enter an order reference id during check…
Browse files Browse the repository at this point in the history
…out (#714)
  • Loading branch information
SGrueber authored Jun 14, 2021
1 parent e6d41ca commit 2cf15f2
Show file tree
Hide file tree
Showing 15 changed files with 328 additions and 54 deletions.
1 change: 1 addition & 0 deletions src/app/core/utils/dev/basket-mock-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export class BasketMockData {
commonShippingMethod: BasketMockData.getShippingMethod(),
payment: BasketMockData.getPayment(),
totals: BasketMockData.getTotals(),
attributes: [{ name: 'orderReferenceID', value: '111-222-333' }],
} as BasketView;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ <h1 class="d-flex flex-wrap align-items-baseline">
<div *ishFeature="'businessCustomerRegistration'" class="row">
<!-- Buyer-->
<ish-info-box heading="checkout.widget.buyer.heading" class="infobox-wrapper col-md-6">
<ish-basket-buyer [object]="basket"></ish-basket-buyer>
<ish-basket-buyer [object]="basket" editRouterLink="/checkout/shipping"></ish-basket-buyer>
</ish-info-box>
</div>
<div class="row d-flex">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,59 +7,65 @@

<div class="col-md-12 col-lg-8">
<!-- shipping method selection -->
<form [formGroup]="shippingForm" class="form-horizontal">
<div *ngIf="shippingMethods.length; else noShippingMethods" class="shipping-methods">
<div *ngIf="nextDisabled && !error" role="alert" class="alert alert-danger">
{{ 'checkout.shipping_method.no_Selection.error' | translate }}
</div>
<h3>{{ 'checkout.shipping_method.selection.heading' | translate }}</h3>
<div class="section">
<form [formGroup]="shippingForm" class="form-horizontal">
<div *ngIf="shippingMethods.length; else noShippingMethods" class="shipping-methods">
<div *ngIf="nextDisabled && !error" role="alert" class="alert alert-danger">
{{ 'checkout.shipping_method.no_Selection.error' | translate }}
</div>
<h3>{{ 'checkout.shipping_method.selection.heading' | translate }}</h3>

<div *ngFor="let shippingMethod of shippingMethods" class="radio">
<label [for]="'ShippingMethod_' + shippingMethod.id">
<input
formControlName="id"
[id]="'ShippingMethod_' + shippingMethod.id"
[value]="shippingMethod.id"
type="radio"
/>
<div *ngFor="let shippingMethod of shippingMethods" class="radio">
<label [for]="'ShippingMethod_' + shippingMethod.id">
<input
formControlName="id"
[id]="'ShippingMethod_' + shippingMethod.id"
[value]="shippingMethod.id"
type="radio"
/>

<span>{{ shippingMethod.name }}:</span>&nbsp;
<strong *ngIf="shippingMethod.shippingCosts">{{ shippingMethod.shippingCosts | ishPrice }}&nbsp;</strong>
<span
*ngIf="shippingMethod.shippingTimeMin && shippingMethod.shippingTimeMax"
class="form-text form-text-inline"
>
{{ 'checkout.shipping.delivery_time.description' | translate }}
<span *ngIf="shippingMethod.shippingTimeMin === 0 && shippingMethod.shippingTimeMax === 1">
{{ 'checkout.shipping.delivery_time.within24' | translate }}
</span>
<span *ngIf="shippingMethod.shippingTimeMin === 0 && shippingMethod.shippingTimeMax > 1">
{{ 'checkout.shipping.delivery_time.within' | translate: { '0': shippingMethod.shippingTimeMax } }}
</span>
<span *ngIf="shippingMethod.shippingTimeMin > 0">
{{
'checkout.shipping.delivery_time'
| translate: { '0': shippingMethod.shippingTimeMin, '1': shippingMethod.shippingTimeMax }
}}
<span>{{ shippingMethod.name }}:</span>&nbsp;
<strong *ngIf="shippingMethod.shippingCosts">{{ shippingMethod.shippingCosts | ishPrice }}&nbsp;</strong>
<span
*ngIf="shippingMethod.shippingTimeMin && shippingMethod.shippingTimeMax"
class="form-text form-text-inline"
>
{{ 'checkout.shipping.delivery_time.description' | translate }}
<span *ngIf="shippingMethod.shippingTimeMin === 0 && shippingMethod.shippingTimeMax === 1">
{{ 'checkout.shipping.delivery_time.within24' | translate }}
</span>
<span *ngIf="shippingMethod.shippingTimeMin === 0 && shippingMethod.shippingTimeMax > 1">
{{ 'checkout.shipping.delivery_time.within' | translate: { '0': shippingMethod.shippingTimeMax } }}
</span>
<span *ngIf="shippingMethod.shippingTimeMin > 0">
{{
'checkout.shipping.delivery_time'
| translate: { '0': shippingMethod.shippingTimeMin, '1': shippingMethod.shippingTimeMax }
}}
</span>
</span>
</span>
<ng-template #ShippingMethodDescription>
<span [innerHTML]="shippingMethod.description"></span>
</ng-template>
<a class="details-tooltip" [ngbPopover]="ShippingMethodDescription" placement="top">
{{ 'checkout.detail.text' | translate }}
<fa-icon [icon]="['fas', 'info-circle']"></fa-icon>
</a>
</label>
<ng-template #ShippingMethodDescription>
<span [innerHTML]="shippingMethod.description"></span>
</ng-template>
<a class="details-tooltip" [ngbPopover]="ShippingMethodDescription" placement="top">
{{ 'checkout.detail.text' | translate }}
<fa-icon [icon]="['fas', 'info-circle']"></fa-icon>
</a>
</label>
</div>
</div>
</div>
<!--- Message because multiple shipment is not supported yet-->
<ng-template #noShippingMethods>
<div role="alert" class="alert alert-danger">{{ 'checkout.shipping.no_methods.message' | translate }}</div>
<!--- Message because multiple shipment is not supported yet-->
<ng-template #noShippingMethods>
<div role="alert" class="alert alert-danger">{{ 'checkout.shipping.no_methods.message' | translate }}</div>

<a routerLink="/basket">{{ 'checkout.general.back_to_cart.button.label' | translate }}</a>
</ng-template>
</form>
</div>

<a routerLink="/basket">{{ 'checkout.general.back_to_cart.button.label' | translate }}</a>
</ng-template>
</form>
<ng-container *ngIf="isBusinessCustomer$ | async">
<ish-basket-order-reference [basket]="basket"></ish-basket-order-reference>
</ng-container>
</div>

<!-- basket summary -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@ import { FaIconComponent } from '@fortawesome/angular-fontawesome';
import { NgbPopover } from '@ng-bootstrap/ng-bootstrap';
import { TranslateModule } from '@ngx-translate/core';
import { MockComponent, MockDirective, MockPipe } from 'ng-mocks';
import { anything, capture, spy, verify } from 'ts-mockito';
import { anything, capture, instance, mock, spy, verify } from 'ts-mockito';

import { ServerHtmlDirective } from 'ish-core/directives/server-html.directive';
import { AccountFacade } from 'ish-core/facades/account.facade';
import { PricePipe } from 'ish-core/models/price/price.pipe';
import { makeHttpError } from 'ish-core/utils/dev/api-service-utils';
import { BasketMockData } from 'ish-core/utils/dev/basket-mock-data';
import { BasketAddressSummaryComponent } from 'ish-shared/components/basket/basket-address-summary/basket-address-summary.component';
import { BasketCostSummaryComponent } from 'ish-shared/components/basket/basket-cost-summary/basket-cost-summary.component';
import { BasketItemsSummaryComponent } from 'ish-shared/components/basket/basket-items-summary/basket-items-summary.component';
import { BasketOrderReferenceComponent } from 'ish-shared/components/basket/basket-order-reference/basket-order-reference.component';
import { BasketValidationResultsComponent } from 'ish-shared/components/basket/basket-validation-results/basket-validation-results.component';
import { ErrorMessageComponent } from 'ish-shared/components/common/error-message/error-message.component';

Expand All @@ -22,14 +24,18 @@ describe('Checkout Shipping Component', () => {
let component: CheckoutShippingComponent;
let fixture: ComponentFixture<CheckoutShippingComponent>;
let element: HTMLElement;
let accountFacade: AccountFacade;

beforeEach(async () => {
accountFacade = mock(AccountFacade);

await TestBed.configureTestingModule({
declarations: [
CheckoutShippingComponent,
MockComponent(BasketAddressSummaryComponent),
MockComponent(BasketCostSummaryComponent),
MockComponent(BasketItemsSummaryComponent),
MockComponent(BasketOrderReferenceComponent),
MockComponent(BasketValidationResultsComponent),
MockComponent(ErrorMessageComponent),
MockComponent(FaIconComponent),
Expand All @@ -38,6 +44,7 @@ describe('Checkout Shipping Component', () => {
MockPipe(PricePipe),
],
imports: [ReactiveFormsModule, TranslateModule.forRoot()],
providers: [{ provide: AccountFacade, useFactory: () => instance(accountFacade) }],
}).compileComponents();
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ import {
SimpleChanges,
} from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { Subject } from 'rxjs';
import { Observable, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

import { AccountFacade } from 'ish-core/facades/account.facade';
import { Basket } from 'ish-core/models/basket/basket.model';
import { HttpError } from 'ish-core/models/http-error/http-error.model';
import { ShippingMethod } from 'ish-core/models/shipping-method/shipping-method.model';
Expand All @@ -30,12 +31,18 @@ export class CheckoutShippingComponent implements OnInit, OnChanges, OnDestroy {
@Output() updateShippingMethod = new EventEmitter<string>();
@Output() nextStep = new EventEmitter<void>();

isBusinessCustomer$: Observable<boolean>;

shippingForm: FormGroup;
submitted = false;

private destroy$ = new Subject();

constructor(private accountFacade: AccountFacade) {}

ngOnInit() {
this.isBusinessCustomer$ = this.accountFacade.isBusinessCustomer$;

this.shippingForm = new FormGroup({
id: new FormControl(this.getCommonShippingMethod()),
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,17 @@
{{ userName }}<br />
{{ object.email || object.invoiceToAddress?.email }}
</p>

<div *ngIf="orderReferenceID" data-testing-id="orderReferenceID">
<a
*ngIf="editRouterLink"
class="float-right btn-tool"
[routerLink]="editRouterLink"
[title]="'checkout.address.update.label' | translate"
>
<fa-icon [icon]="['fas', 'pencil-alt']"></fa-icon>
</a>
<strong>{{ 'checkout.widget.buyer.orderReferenceId' | translate }}</strong>
<p>{{ orderReferenceID }}</p>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
import { TranslateModule } from '@ngx-translate/core';
import { MockComponent } from 'ng-mocks';
import { of } from 'rxjs';
import { instance, mock, when } from 'ts-mockito';

Expand All @@ -20,8 +23,8 @@ describe('Basket Buyer Component', () => {
accountFacade = mock(AccountFacade);

await TestBed.configureTestingModule({
imports: [TranslateModule.forRoot()],
declarations: [BasketBuyerComponent],
imports: [RouterTestingModule, TranslateModule.forRoot()],
declarations: [BasketBuyerComponent, MockComponent(FaIconComponent)],
providers: [{ provide: AccountFacade, useFactory: () => instance(accountFacade) }],
}).compileComponents();
});
Expand Down Expand Up @@ -50,4 +53,10 @@ describe('Basket Buyer Component', () => {
expect(element.querySelector('[data-testing-id="taxationID"]')).toBeTruthy();
expect(element.querySelector('[data-testing-id="taxationID"]').innerHTML).toContain('1234');
});

it('should display the order reference id of the customer', () => {
fixture.detectChanges();
expect(element.querySelector('[data-testing-id="orderReferenceID"]')).toBeTruthy();
expect(element.querySelector('[data-testing-id="orderReferenceID"]').innerHTML).toContain('111-222-333');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,27 @@ import { whenTruthy } from 'ish-core/utils/operators';
})
export class BasketBuyerComponent implements OnInit, OnDestroy {
@Input() object: Basket | Order;
/**
* Router link for editing the order reference id. If a routerLink is given a link is displayed to route to an edit page.
*/
@Input() editRouterLink?: string;

customer$: Observable<Customer>;
user$: Observable<User>;

taxationID: string;
orderReferenceID: string;
userName: string;

private destroy$ = new Subject();

constructor(private accountFacade: AccountFacade) {}

ngOnInit() {
this.taxationID = this.getAttributeValue('taxationID');
this.orderReferenceID = this.getAttributeValue('orderReferenceID');

// default values for anonymous users
this.taxationID = this.object.attributes?.find(attr => attr.name === 'taxationID')?.value as string;
this.userName = `${this.object.invoiceToAddress?.firstName} ${this.object.invoiceToAddress?.lastName}`;

this.customer$ = this.accountFacade.customer$;
Expand All @@ -45,6 +52,10 @@ export class BasketBuyerComponent implements OnInit, OnDestroy {
});
}

private getAttributeValue(attributeName: string): string {
return this.object.attributes?.find(attr => attr.name === attributeName)?.value as string;
}

ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<div class="section">
<h3>{{ 'checkout.orderReferenceId.title' | translate }}</h3>

<form [formGroup]="form" (ngSubmit)="submitForm()">
<div class="row">
<div *ngIf="showSuccessMessage" class="col-md-12">
<ish-success-message message="checkout.orderReferenceId.success.message" [toast]="false"></ish-success-message>
</div>
<div class="col-md-10">
<formly-form [form]="form" [fields]="fields" [model]="model"> </formly-form>
</div>
<div class="col-md-2 pl-md-0">
<button type="submit" class="btn btn-secondary" [disabled]="disabled">
{{ 'checkout.orderReferenceId.apply.button.label' | translate }}
</button>
</div>
</div>
</form>
</div>
Loading

0 comments on commit 2cf15f2

Please sign in to comment.