Skip to content

Commit

Permalink
fix(core): Ensure all Orders have a ShippingMethod before payment
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelbromley committed Dec 2, 2021
1 parent a232b4c commit 9b9e547
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 1 deletion.
27 changes: 26 additions & 1 deletion packages/core/e2e/shop-order.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -807,7 +807,32 @@ describe('Shop orders', () => {
expect(customer!.addresses).toEqual([]);
});

it('can transition to ArrangingPayment once Customer has been set', async () => {
it('attempting to transition to ArrangingPayment returns error result when Order has no ShippingMethod', async () => {
const { transitionOrderToState } = await shopClient.query<
TransitionToState.Mutation,
TransitionToState.Variables
>(TRANSITION_TO_STATE, { state: 'ArrangingPayment' });
orderResultGuard.assertErrorResult(transitionOrderToState);

expect(transitionOrderToState!.transitionError).toBe(
`Cannot transition Order to the "ArrangingPayment" state without a ShippingMethod`,
);
expect(transitionOrderToState!.errorCode).toBe(ErrorCode.ORDER_STATE_TRANSITION_ERROR);
});

it('can transition to ArrangingPayment once Customer and ShippingMethod has been set', async () => {
const { eligibleShippingMethods } = await shopClient.query<GetShippingMethods.Query>(
GET_ELIGIBLE_SHIPPING_METHODS,
);

const { setOrderShippingMethod } = await shopClient.query<
SetShippingMethod.Mutation,
SetShippingMethod.Variables
>(SET_SHIPPING_METHOD, {
id: eligibleShippingMethods[0].id,
});
orderResultGuard.assertSuccess(setOrderShippingMethod);

const { transitionOrderToState } = await shopClient.query<
TransitionToState.Mutation,
TransitionToState.Variables
Expand Down
16 changes: 16 additions & 0 deletions packages/core/e2e/stock-control.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@ import {
AddPaymentToOrder,
ErrorCode,
GetProductStockLevel,
GetShippingMethods,
PaymentInput,
SetShippingAddress,
SetShippingMethod,
TestOrderFragmentFragment,
TestOrderWithPaymentsFragment,
TransitionToState,
Expand All @@ -52,8 +54,10 @@ import {
import {
ADD_ITEM_TO_ORDER,
ADD_PAYMENT,
GET_ELIGIBLE_SHIPPING_METHODS,
GET_PRODUCT_WITH_STOCK_LEVEL,
SET_SHIPPING_ADDRESS,
SET_SHIPPING_METHOD,
TRANSITION_TO_STATE,
} from './graphql/shop-definitions';
import { assertThrowsWithMessage } from './utils/assert-throws-with-message';
Expand Down Expand Up @@ -86,6 +90,15 @@ describe('Stock control', () => {
return product;
}

async function setFirstEligibleShippingMethod() {
const { eligibleShippingMethods } = await shopClient.query<GetShippingMethods.Query>(
GET_ELIGIBLE_SHIPPING_METHODS,
);
await shopClient.query<SetShippingMethod.Mutation, SetShippingMethod.Variables>(SET_SHIPPING_METHOD, {
id: eligibleShippingMethods[0].id,
});
}

beforeAll(async () => {
await server.init({
initialData: {
Expand Down Expand Up @@ -259,6 +272,7 @@ describe('Stock control', () => {
} as CreateAddressInput,
},
);
await setFirstEligibleShippingMethod();
await shopClient.query<TransitionToState.Mutation, TransitionToState.Variables>(
TRANSITION_TO_STATE,
{ state: 'ArrangingPayment' as OrderState },
Expand Down Expand Up @@ -440,6 +454,7 @@ describe('Stock control', () => {
} as CreateAddressInput,
},
);
await setFirstEligibleShippingMethod();
await shopClient.query<TransitionToState.Mutation, TransitionToState.Variables>(
TRANSITION_TO_STATE,
{ state: 'ArrangingPayment' as OrderState },
Expand Down Expand Up @@ -1091,6 +1106,7 @@ describe('Stock control', () => {
} as CreateAddressInput,
},
);
await setFirstEligibleShippingMethod();
await shopClient.query<TransitionToState.Mutation, TransitionToState.Variables>(
TRANSITION_TO_STATE,
{
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/i18n/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
"cannot-transition-no-additional-payments-needed": "Cannot transition Order to the \"ArrangingAdditionalPayment\" state as no additional payments are needed",
"cannot-transition-to-shipping-when-order-is-empty": "Cannot transition Order to the \"ArrangingShipping\" state when it is empty",
"cannot-transition-to-payment-without-customer": "Cannot transition Order to the \"ArrangingPayment\" state without Customer details",
"cannot-transition-to-payment-without-shipping-method": "Cannot transition Order to the \"ArrangingPayment\" state without a ShippingMethod",
"cannot-transition-unless-all-cancelled": "Cannot transition Order to the \"Cancelled\" state unless all OrderItems are cancelled",
"cannot-transition-unless-all-order-items-delivered": "Cannot transition Order to the \"Delivered\" state unless all OrderItems are delivered",
"cannot-transition-unless-some-order-items-delivered": "Cannot transition Order to the \"PartiallyDelivered\" state unless some OrderItems are delivered",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ export class OrderStateMachine {
if (!data.order.customer) {
return `message.cannot-transition-to-payment-without-customer`;
}
if (!data.order.shippingLines || data.order.shippingLines.length === 0) {
return `message.cannot-transition-to-payment-without-shipping-method`;
}
}
if (toState === 'PaymentAuthorized') {
const hasAnAuthorizedPayment = !!data.order.payments.find(p => p.state === 'Authorized');
Expand Down

0 comments on commit 9b9e547

Please sign in to comment.