Skip to content

Commit

Permalink
fix: use new redirect url
Browse files Browse the repository at this point in the history
  • Loading branch information
fgiesske-intershop committed Oct 22, 2024
1 parent 38928fa commit df68c63
Show file tree
Hide file tree
Showing 5 changed files with 222 additions and 36 deletions.
2 changes: 1 addition & 1 deletion src/app/core/services/basket/basket.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ export class BasketService {
*/
validateBasket(scopes: BasketValidationScopeType[] = ['']): Observable<BasketValidation> {
const body = {
adjustmentsAllowed: !scopes.some(scope => scope === 'All'), // don't allow adjustments for 'All' validation steps, because you cannot show them to the user at once
adjustmentsAllowed: true,
scopes,
};

Expand Down
109 changes: 109 additions & 0 deletions src/app/core/store/customer/basket/basket-validation.effects.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
startCheckoutSuccess,
startFastCheckout,
submitBasket,
updateBasketPaymentRedirectUrl,
validateBasket,
} from './basket.actions';

Expand Down Expand Up @@ -211,6 +212,42 @@ describe('Basket Validation Effects', () => {
complete: done,
});
});

it('should call updateBasketPaymentRedirectUrl if payment redirectUrl is present', done => {
const basketValidationWithRedirect: BasketValidation = {
...basketValidation,
basket: {
...basketValidation.basket,
payment: {
redirectUrl: 'https://redirect.url',
id: '',
paymentInstrument: undefined,
},
},
};
const action = startCheckoutSuccess({ basketValidation: basketValidationWithRedirect });
actions$ = of(action);

when(basketServiceMock.validateBasket(anything())).thenReturn(of(basketValidationWithRedirect));

effects.continueCheckoutWithAcceleration$.subscribe(action => {
expect(action).toEqual(updateBasketPaymentRedirectUrl({ redirectUrl: 'https://redirect.url' }));
done();
});
});

it('should not call updateBasketPaymentRedirectUrl if payment redirectUrl is not present', done => {
const action = startCheckoutSuccess({ basketValidation });
actions$ = of(action);

effects.continueCheckoutWithAcceleration$.subscribe({
next: () => {
verify(updateBasketPaymentRedirectUrl({ redirectUrl: 'https://redirect.url' })).never();
},
error: fail,
complete: done,
});
});
});

describe('validateBasket$', () => {
Expand Down Expand Up @@ -280,6 +317,42 @@ describe('Basket Validation Effects', () => {

expect(effects.validateBasket$).toBeObservable(expected$);
});

it('should call updateBasketPaymentRedirectUrl if payment redirectUrl is present', done => {
const basketValidationWithRedirect: BasketValidation = {
...basketValidation,
basket: {
...basketValidation.basket,
payment: {
redirectUrl: 'https://redirect.url',
id: '',
paymentInstrument: undefined,
},
},
};
const action = validateBasket({ scopes: ['Products'] });
actions$ = of(action);

when(basketServiceMock.validateBasket(anything())).thenReturn(of(basketValidationWithRedirect));

effects.validateBasket$.subscribe(action => {
expect(action).toEqual(updateBasketPaymentRedirectUrl({ redirectUrl: 'https://redirect.url' }));
done();
});
});

it('should not call updateBasketPaymentRedirectUrl if payment redirectUrl is not present', done => {
const action = validateBasket({ scopes: ['Products'] });
actions$ = of(action);

effects.validateBasket$.subscribe({
next: () => {
verify(updateBasketPaymentRedirectUrl({ redirectUrl: 'https://redirect.url' })).never();
},
error: fail,
complete: done,
});
});
});

describe('startFastCheckoutProcess$ - trigger basket validation before redirect', () => {
Expand Down Expand Up @@ -462,6 +535,42 @@ describe('Basket Validation Effects', () => {
expect(effects.validateBasketAndContinueCheckout$).toBeObservable(expected$);
});

it('should call updateBasketPaymentRedirectUrl if payment redirectUrl is present', done => {
const basketValidationWithRedirect: BasketValidation = {
...basketValidation,
basket: {
...basketValidation.basket,
payment: {
redirectUrl: 'https://redirect.url',
id: '',
paymentInstrument: undefined,
},
},
};
const action = continueCheckout({ targetStep: CheckoutStepType.Addresses });
actions$ = of(action);

when(basketServiceMock.validateBasket(anything())).thenReturn(of(basketValidationWithRedirect));

effects.validateBasketAndContinueCheckout$.subscribe(action => {
expect(action).toEqual(updateBasketPaymentRedirectUrl({ redirectUrl: 'https://redirect.url' }));
done();
});
});

it('should not call updateBasketPaymentRedirectUrl if payment redirectUrl is not present', done => {
const action = continueCheckout({ targetStep: CheckoutStepType.Addresses });
actions$ = of(action);

effects.validateBasketAndContinueCheckout$.subscribe({
next: () => {
verify(updateBasketPaymentRedirectUrl({ redirectUrl: 'https://redirect.url' })).never();
},
error: fail,
complete: done,
});
});

describe('handleBasketNotFoundError$', () => {
it('should navigate to (empty) /basket after ContinueCheckoutFail if basket expired or could not be found', done => {
const action = continueCheckoutFail({
Expand Down
117 changes: 83 additions & 34 deletions src/app/core/store/customer/basket/basket-validation.effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Actions, concatLatestFrom, createEffect, ofType } from '@ngrx/effects';
import { Store, select } from '@ngrx/store';
import { intersection } from 'lodash-es';
import { EMPTY, Observable, from } from 'rxjs';
import { concatMap, filter, map, withLatestFrom } from 'rxjs/operators';
import { concatMap, filter, map, mergeMap, withLatestFrom } from 'rxjs/operators';

import { BasketFeedbackView } from 'ish-core/models/basket-feedback/basket-feedback.model';
import {
Expand All @@ -27,11 +27,13 @@ import {
loadBasketEligiblePaymentMethods,
loadBasketEligibleShippingMethods,
loadBasketFail,
navigateBasedOnValidation,
startCheckout,
startCheckoutFail,
startCheckoutSuccess,
startFastCheckout,
submitBasket,
updateBasketPaymentRedirectUrl,
validateBasket,
} from './basket.actions';
import { getCurrentBasket } from './basket.selectors';
Expand Down Expand Up @@ -90,26 +92,30 @@ export class BasketValidationEffects {
/**
* Validates the basket and jumps to the next possible checkout step (basket acceleration)
*/
continueCheckoutWithAcceleration$ = createEffect(
() =>
this.actions$.pipe(
ofType(startCheckoutSuccess),
mapToPayload(),
map(payload => payload.basketValidation.results),
filter(results => results.valid && !results.adjusted),
concatMap(() =>
this.basketService
.validateBasket(this.validationSteps[CheckoutStepType.Review].scopes)
.pipe(
concatMap(basketValidation =>
basketValidation?.results?.valid
? from(this.router.navigate([this.validationSteps[CheckoutStepType.Review].route]))
: this.jumpToTargetRoute('auto', basketValidation?.results)
)
)
continueCheckoutWithAcceleration$ = createEffect(() =>
this.actions$.pipe(
ofType(startCheckoutSuccess),
mapToPayload(),
map(payload => payload.basketValidation.results),
filter(results => results.valid && !results.adjusted),
concatMap(() =>
this.basketService.validateBasket(this.validationSteps[CheckoutStepType.Review].scopes).pipe(
mergeMap(basketValidation => {
const actions = [];

if (basketValidation.basket.payment?.redirectUrl) {
actions.push(
updateBasketPaymentRedirectUrl({ redirectUrl: basketValidation.basket.payment.redirectUrl })
);
}

actions.push(navigateBasedOnValidation({ results: basketValidation.results }));

return actions;
})
)
),
{ dispatch: false }
)
)
);

/**
Expand All @@ -122,11 +128,23 @@ export class BasketValidationEffects {
whenTruthy(),
concatMap(scopes =>
this.basketService.validateBasket(scopes).pipe(
map(basketValidation =>
basketValidation.results.valid
? continueCheckoutSuccess({ targetRoute: undefined, basketValidation })
: continueCheckoutWithIssues({ targetRoute: undefined, basketValidation })
),
mergeMap(basketValidation => {
const actions = [];

if (basketValidation.basket.payment?.redirectUrl) {
actions.push(
updateBasketPaymentRedirectUrl({ redirectUrl: basketValidation.basket.payment.redirectUrl })
);
}

actions.push(
basketValidation.results.valid
? continueCheckoutSuccess({ targetRoute: undefined, basketValidation })
: continueCheckoutWithIssues({ targetRoute: undefined, basketValidation })
);

return actions;
}),
mapErrorToAction(continueCheckoutFail)
)
)
Expand All @@ -146,21 +164,52 @@ export class BasketValidationEffects {

return this.basketService.validateBasket(this.validationSteps[targetStep - 1].scopes).pipe(
withLatestFrom(this.store.pipe(select(getCurrentBasket))),
concatMap(([basketValidation, basket]) =>
basketValidation.results.valid
? targetStep === CheckoutStepType.Receipt && !basketValidation.results.adjusted
? basket.approval?.approvalRequired
? [continueCheckoutSuccess({ targetRoute: undefined, basketValidation }), submitBasket()]
: [continueCheckoutSuccess({ targetRoute: undefined, basketValidation }), createOrder()]
: [continueCheckoutSuccess({ targetRoute, basketValidation })]
: [continueCheckoutWithIssues({ targetRoute, basketValidation })]
),
mergeMap(([basketValidation, basket]) => {
const actions = [];

if (basketValidation.basket.payment?.redirectUrl) {
actions.push(
updateBasketPaymentRedirectUrl({ redirectUrl: basketValidation.basket.payment.redirectUrl })
);
}

if (basketValidation.results.valid) {
if (targetStep === CheckoutStepType.Receipt && !basketValidation.results.adjusted) {
if (basket.approval?.approvalRequired) {
actions.push(continueCheckoutSuccess({ targetRoute: undefined, basketValidation }), submitBasket());
} else {
actions.push(continueCheckoutSuccess({ targetRoute: undefined, basketValidation }), createOrder());
}
} else {
actions.push(continueCheckoutSuccess({ targetRoute, basketValidation }));
}
} else {
actions.push(continueCheckoutWithIssues({ targetRoute, basketValidation }));
}

return actions;
}),
mapErrorToAction(continueCheckoutFail)
);
})
)
);

navigateBasedOnValidation$ = createEffect(
() =>
this.actions$.pipe(
ofType(navigateBasedOnValidation),
map(action => {
if (action.payload.results.valid) {
this.router.navigate([this.validationSteps[CheckoutStepType.Review].route]);
} else {
this.jumpToTargetRoute('auto', action.payload.results);
}
})
),
{ dispatch: false }
);

/**
* Validation the basket before starting the fast checkout effect.
*/
Expand Down
16 changes: 15 additions & 1 deletion src/app/core/store/customer/basket/basket.actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import { createAction } from '@ngrx/store';
import { Address } from 'ish-core/models/address/address.model';
import { Attribute } from 'ish-core/models/attribute/attribute.model';
import { BasketInfo } from 'ish-core/models/basket-info/basket-info.model';
import { BasketValidation, BasketValidationScopeType } from 'ish-core/models/basket-validation/basket-validation.model';
import {
BasketValidation,
BasketValidationResultType,
BasketValidationScopeType,
} from 'ish-core/models/basket-validation/basket-validation.model';
import { Basket } from 'ish-core/models/basket/basket.model';
import { CheckoutStepType } from 'ish-core/models/checkout/checkout-step.type';
import { ErrorFeedback } from 'ish-core/models/http-error/http-error.model';
Expand Down Expand Up @@ -320,3 +324,13 @@ export const setBasketDesiredDeliveryDateFail = createAction(
export const setBasketDesiredDeliveryDateSuccess = createAction(
'[Basket API] Add or Update Basket Desired Delivery Date Success'
);

export const navigateBasedOnValidation = createAction(
'[Basket] Navigate Based On Validation',
payload<{ results: BasketValidationResultType }>()
);

export const updateBasketPaymentRedirectUrl = createAction(
'[Basket] Update Payment Redirect URL',
payload<{ redirectUrl: string }>()
);
14 changes: 14 additions & 0 deletions src/app/core/store/customer/basket/basket.reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ import {
updateBasketItemSuccess,
updateBasketPayment,
updateBasketPaymentFail,
updateBasketPaymentRedirectUrl,
updateBasketPaymentSuccess,
updateBasketShippingMethod,
updateConcardisCvcLastUpdated,
Expand Down Expand Up @@ -358,5 +359,18 @@ export const basketReducer = createReducer(
promotionError: undefined,
validationResults: initialValidationResults,
})
),
on(
updateBasketPaymentRedirectUrl,
(state, { payload: { redirectUrl } }): BasketState => ({
...state,
basket: {
...state.basket,
payment: {
...state.basket.payment,
redirectUrl,
},
},
})
)
);

0 comments on commit df68c63

Please sign in to comment.