|
|
@@ -1,6 +1,11 @@
|
|
|
/* tslint:disable:no-non-null-assertion */
|
|
|
import { pick } from '@vendure/common/lib/pick';
|
|
|
-import { createTestEnvironment, SimpleGraphQLClient } from '@vendure/testing';
|
|
|
+import {
|
|
|
+ createErrorResultGuard,
|
|
|
+ createTestEnvironment,
|
|
|
+ ErrorResultGuard,
|
|
|
+ SimpleGraphQLClient,
|
|
|
+} from '@vendure/testing';
|
|
|
import gql from 'graphql-tag';
|
|
|
import path from 'path';
|
|
|
|
|
|
@@ -13,11 +18,15 @@ import {
|
|
|
singleStageRefundablePaymentMethod,
|
|
|
twoStagePaymentMethod,
|
|
|
} from './fixtures/test-payment-methods';
|
|
|
+import { FULFILLMENT_FRAGMENT } from './graphql/fragments';
|
|
|
import {
|
|
|
AddNoteToOrder,
|
|
|
+ CanceledOrderFragment,
|
|
|
CancelOrder,
|
|
|
CreateFulfillment,
|
|
|
DeleteOrderNote,
|
|
|
+ ErrorCode,
|
|
|
+ FulfillmentFragment,
|
|
|
GetCustomerList,
|
|
|
GetOrder,
|
|
|
GetOrderFulfillmentItems,
|
|
|
@@ -28,6 +37,8 @@ import {
|
|
|
GetProductWithVariants,
|
|
|
GetStockMovement,
|
|
|
HistoryEntryType,
|
|
|
+ PaymentFragment,
|
|
|
+ RefundFragment,
|
|
|
RefundOrder,
|
|
|
SettlePayment,
|
|
|
SettleRefund,
|
|
|
@@ -37,7 +48,13 @@ import {
|
|
|
UpdateOrderNote,
|
|
|
UpdateProductVariants,
|
|
|
} from './graphql/generated-e2e-admin-types';
|
|
|
-import { AddItemToOrder, DeletionResult, GetActiveOrder } from './graphql/generated-e2e-shop-types';
|
|
|
+import {
|
|
|
+ AddItemToOrder,
|
|
|
+ DeletionResult,
|
|
|
+ GetActiveOrder,
|
|
|
+ TestOrderFragmentFragment,
|
|
|
+ UpdatedOrder,
|
|
|
+} from './graphql/generated-e2e-shop-types';
|
|
|
import {
|
|
|
CREATE_FULFILLMENT,
|
|
|
GET_CUSTOMER_LIST,
|
|
|
@@ -67,6 +84,19 @@ describe('Orders resolver', () => {
|
|
|
let customers: GetCustomerList.Items[];
|
|
|
const password = 'test';
|
|
|
|
|
|
+ const orderGuard: ErrorResultGuard<
|
|
|
+ TestOrderFragmentFragment | CanceledOrderFragment
|
|
|
+ > = createErrorResultGuard<TestOrderFragmentFragment | CanceledOrderFragment>(input => !!input.lines);
|
|
|
+ const paymentGuard: ErrorResultGuard<PaymentFragment> = createErrorResultGuard<PaymentFragment>(
|
|
|
+ input => !!input.state,
|
|
|
+ );
|
|
|
+ const fulfillmentGuard: ErrorResultGuard<FulfillmentFragment> = createErrorResultGuard<
|
|
|
+ FulfillmentFragment
|
|
|
+ >(input => !!input.method);
|
|
|
+ const refundGuard: ErrorResultGuard<RefundFragment> = createErrorResultGuard<RefundFragment>(
|
|
|
+ input => !!input.items,
|
|
|
+ );
|
|
|
+
|
|
|
beforeAll(async () => {
|
|
|
await server.init({
|
|
|
initialData,
|
|
|
@@ -133,6 +163,7 @@ describe('Orders resolver', () => {
|
|
|
await shopClient.asUserWithCredentials(customers[0].emailAddress, password);
|
|
|
await proceedToArrangingPayment(shopClient);
|
|
|
const order = await addPaymentToOrder(shopClient, failsToSettlePaymentMethod);
|
|
|
+ orderGuard.assertSuccess(order);
|
|
|
|
|
|
expect(order.state).toBe('PaymentAuthorized');
|
|
|
|
|
|
@@ -143,9 +174,11 @@ describe('Orders resolver', () => {
|
|
|
>(SETTLE_PAYMENT, {
|
|
|
id: payment.id,
|
|
|
});
|
|
|
+ paymentGuard.assertErrorResult(settlePayment);
|
|
|
|
|
|
- expect(settlePayment!.id).toBe(payment.id);
|
|
|
- expect(settlePayment!.state).toBe('Authorized');
|
|
|
+ expect(settlePayment.message).toBe('Settling the payment failed');
|
|
|
+ expect(settlePayment.code).toBe(ErrorCode.SETTLE_PAYMENT_ERROR);
|
|
|
+ expect((settlePayment as any).paymentErrorMessage).toBe('Something went horribly wrong');
|
|
|
|
|
|
const result = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
|
|
|
id: order.id,
|
|
|
@@ -159,6 +192,7 @@ describe('Orders resolver', () => {
|
|
|
await shopClient.asUserWithCredentials(customers[1].emailAddress, password);
|
|
|
await proceedToArrangingPayment(shopClient);
|
|
|
const order = await addPaymentToOrder(shopClient, twoStagePaymentMethod);
|
|
|
+ orderGuard.assertSuccess(order);
|
|
|
|
|
|
expect(order.state).toBe('PaymentAuthorized');
|
|
|
expect(onTransitionSpy).toHaveBeenCalledTimes(1);
|
|
|
@@ -172,6 +206,7 @@ describe('Orders resolver', () => {
|
|
|
>(SETTLE_PAYMENT, {
|
|
|
id: payment.id,
|
|
|
});
|
|
|
+ paymentGuard.assertSuccess(settlePayment);
|
|
|
|
|
|
expect(settlePayment!.id).toBe(payment.id);
|
|
|
expect(settlePayment!.state).toBe('Settled');
|
|
|
@@ -240,63 +275,45 @@ describe('Orders resolver', () => {
|
|
|
});
|
|
|
|
|
|
describe('fulfillment', () => {
|
|
|
- it(
|
|
|
- 'throws if Order is not in "PaymentSettled" state',
|
|
|
- assertThrowsWithMessage(async () => {
|
|
|
- const { order } = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
|
|
|
- id: 'T_1',
|
|
|
- });
|
|
|
- expect(order!.state).toBe('PaymentAuthorized');
|
|
|
+ it('return error result if lines is empty', async () => {
|
|
|
+ const { order } = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
|
|
|
+ id: 'T_2',
|
|
|
+ });
|
|
|
+ expect(order!.state).toBe('PaymentSettled');
|
|
|
+ const { addFulfillmentToOrder } = await adminClient.query<
|
|
|
+ CreateFulfillment.Mutation,
|
|
|
+ CreateFulfillment.Variables
|
|
|
+ >(CREATE_FULFILLMENT, {
|
|
|
+ input: {
|
|
|
+ lines: [],
|
|
|
+ method: 'Test',
|
|
|
+ },
|
|
|
+ });
|
|
|
+ fulfillmentGuard.assertErrorResult(addFulfillmentToOrder);
|
|
|
|
|
|
- await adminClient.query<CreateFulfillment.Mutation, CreateFulfillment.Variables>(
|
|
|
- CREATE_FULFILLMENT,
|
|
|
- {
|
|
|
- input: {
|
|
|
- lines: order!.lines.map(l => ({ orderLineId: l.id, quantity: l.quantity })),
|
|
|
- method: 'Test',
|
|
|
- },
|
|
|
- },
|
|
|
- );
|
|
|
- }, 'One or more OrderItems belong to an Order which is in an invalid state'),
|
|
|
- );
|
|
|
+ expect(addFulfillmentToOrder.message).toBe('At least one OrderLine must be specified');
|
|
|
+ expect(addFulfillmentToOrder.code).toBe(ErrorCode.EMPTY_ORDER_LINE_SELECTION_ERROR);
|
|
|
+ });
|
|
|
|
|
|
- it(
|
|
|
- 'throws if lines is empty',
|
|
|
- assertThrowsWithMessage(async () => {
|
|
|
- const { order } = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
|
|
|
- id: 'T_2',
|
|
|
- });
|
|
|
- expect(order!.state).toBe('PaymentSettled');
|
|
|
- await adminClient.query<CreateFulfillment.Mutation, CreateFulfillment.Variables>(
|
|
|
- CREATE_FULFILLMENT,
|
|
|
- {
|
|
|
- input: {
|
|
|
- lines: [],
|
|
|
- method: 'Test',
|
|
|
- },
|
|
|
- },
|
|
|
- );
|
|
|
- }, 'Nothing to fulfill'),
|
|
|
- );
|
|
|
+ it('returns error result if all quantities are zero', async () => {
|
|
|
+ const { order } = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
|
|
|
+ id: 'T_2',
|
|
|
+ });
|
|
|
+ expect(order!.state).toBe('PaymentSettled');
|
|
|
+ const { addFulfillmentToOrder } = await adminClient.query<
|
|
|
+ CreateFulfillment.Mutation,
|
|
|
+ CreateFulfillment.Variables
|
|
|
+ >(CREATE_FULFILLMENT, {
|
|
|
+ input: {
|
|
|
+ lines: order!.lines.map(l => ({ orderLineId: l.id, quantity: 0 })),
|
|
|
+ method: 'Test',
|
|
|
+ },
|
|
|
+ });
|
|
|
+ fulfillmentGuard.assertErrorResult(addFulfillmentToOrder);
|
|
|
|
|
|
- it(
|
|
|
- 'throws if all quantities are zero',
|
|
|
- assertThrowsWithMessage(async () => {
|
|
|
- const { order } = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
|
|
|
- id: 'T_2',
|
|
|
- });
|
|
|
- expect(order!.state).toBe('PaymentSettled');
|
|
|
- await adminClient.query<CreateFulfillment.Mutation, CreateFulfillment.Variables>(
|
|
|
- CREATE_FULFILLMENT,
|
|
|
- {
|
|
|
- input: {
|
|
|
- lines: order!.lines.map(l => ({ orderLineId: l.id, quantity: 0 })),
|
|
|
- method: 'Test',
|
|
|
- },
|
|
|
- },
|
|
|
- );
|
|
|
- }, 'Nothing to fulfill'),
|
|
|
- );
|
|
|
+ expect(addFulfillmentToOrder.message).toBe('At least one OrderLine must be specified');
|
|
|
+ expect(addFulfillmentToOrder.code).toBe(ErrorCode.EMPTY_ORDER_LINE_SELECTION_ERROR);
|
|
|
+ });
|
|
|
|
|
|
it('creates the first fulfillment', async () => {
|
|
|
const { order } = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
|
|
|
@@ -305,7 +322,7 @@ describe('Orders resolver', () => {
|
|
|
expect(order!.state).toBe('PaymentSettled');
|
|
|
const lines = order!.lines;
|
|
|
|
|
|
- const { fulfillOrder } = await adminClient.query<
|
|
|
+ const { addFulfillmentToOrder } = await adminClient.query<
|
|
|
CreateFulfillment.Mutation,
|
|
|
CreateFulfillment.Variables
|
|
|
>(CREATE_FULFILLMENT, {
|
|
|
@@ -315,21 +332,22 @@ describe('Orders resolver', () => {
|
|
|
trackingCode: '111',
|
|
|
},
|
|
|
});
|
|
|
+ fulfillmentGuard.assertSuccess(addFulfillmentToOrder);
|
|
|
|
|
|
- expect(fulfillOrder!.id).toBe('T_1');
|
|
|
- expect(fulfillOrder!.method).toBe('Test1');
|
|
|
- expect(fulfillOrder!.trackingCode).toBe('111');
|
|
|
- expect(fulfillOrder!.state).toBe('Pending');
|
|
|
- expect(fulfillOrder!.orderItems).toEqual([{ id: lines[0].items[0].id }]);
|
|
|
+ expect(addFulfillmentToOrder.id).toBe('T_1');
|
|
|
+ expect(addFulfillmentToOrder.method).toBe('Test1');
|
|
|
+ expect(addFulfillmentToOrder.trackingCode).toBe('111');
|
|
|
+ expect(addFulfillmentToOrder.state).toBe('Pending');
|
|
|
+ expect(addFulfillmentToOrder.orderItems).toEqual([{ id: lines[0].items[0].id }]);
|
|
|
|
|
|
const result = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
|
|
|
id: 'T_2',
|
|
|
});
|
|
|
|
|
|
- expect(result.order!.lines[0].items[0].fulfillment!.id).toBe(fulfillOrder!.id);
|
|
|
+ expect(result.order!.lines[0].items[0].fulfillment!.id).toBe(addFulfillmentToOrder!.id);
|
|
|
expect(
|
|
|
result.order!.lines[1].items.filter(
|
|
|
- i => i.fulfillment && i.fulfillment.id === fulfillOrder.id,
|
|
|
+ i => i.fulfillment && i.fulfillment.id === addFulfillmentToOrder.id,
|
|
|
).length,
|
|
|
).toBe(0);
|
|
|
expect(result.order!.lines[1].items.filter(i => i.fulfillment == null).length).toBe(3);
|
|
|
@@ -346,7 +364,7 @@ describe('Orders resolver', () => {
|
|
|
return items.length > 0 ? true : false;
|
|
|
}) || [];
|
|
|
|
|
|
- const { fulfillOrder } = await adminClient.query<
|
|
|
+ const { addFulfillmentToOrder } = await adminClient.query<
|
|
|
CreateFulfillment.Mutation,
|
|
|
CreateFulfillment.Variables
|
|
|
>(CREATE_FULFILLMENT, {
|
|
|
@@ -359,93 +377,109 @@ describe('Orders resolver', () => {
|
|
|
trackingCode: '222',
|
|
|
},
|
|
|
});
|
|
|
+ fulfillmentGuard.assertSuccess(addFulfillmentToOrder);
|
|
|
|
|
|
- expect(fulfillOrder!.id).toBe('T_2');
|
|
|
- expect(fulfillOrder!.method).toBe('Test2');
|
|
|
- expect(fulfillOrder!.trackingCode).toBe('222');
|
|
|
- expect(fulfillOrder!.state).toBe('Pending');
|
|
|
+ expect(addFulfillmentToOrder.id).toBe('T_2');
|
|
|
+ expect(addFulfillmentToOrder.method).toBe('Test2');
|
|
|
+ expect(addFulfillmentToOrder.trackingCode).toBe('222');
|
|
|
+ expect(addFulfillmentToOrder.state).toBe('Pending');
|
|
|
});
|
|
|
|
|
|
- it(
|
|
|
- 'throws if an OrderItem already part of a Fulfillment',
|
|
|
- assertThrowsWithMessage(async () => {
|
|
|
- const { order } = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
|
|
|
- id: 'T_2',
|
|
|
- });
|
|
|
- await adminClient.query<CreateFulfillment.Mutation, CreateFulfillment.Variables>(
|
|
|
- CREATE_FULFILLMENT,
|
|
|
- {
|
|
|
- input: {
|
|
|
- method: 'Test',
|
|
|
- lines: [
|
|
|
- {
|
|
|
- orderLineId: order!.lines[0].id,
|
|
|
- quantity: 1,
|
|
|
- },
|
|
|
- ],
|
|
|
+ it('returns error result if an OrderItem already part of a Fulfillment', async () => {
|
|
|
+ const { order } = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
|
|
|
+ id: 'T_2',
|
|
|
+ });
|
|
|
+ const { addFulfillmentToOrder } = await adminClient.query<
|
|
|
+ CreateFulfillment.Mutation,
|
|
|
+ CreateFulfillment.Variables
|
|
|
+ >(CREATE_FULFILLMENT, {
|
|
|
+ input: {
|
|
|
+ method: 'Test',
|
|
|
+ lines: [
|
|
|
+ {
|
|
|
+ orderLineId: order!.lines[0].id,
|
|
|
+ quantity: 1,
|
|
|
},
|
|
|
- },
|
|
|
- );
|
|
|
- }, 'One or more OrderItems have already been fulfilled'),
|
|
|
- );
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ });
|
|
|
+ fulfillmentGuard.assertErrorResult(addFulfillmentToOrder);
|
|
|
+
|
|
|
+ expect(addFulfillmentToOrder.message).toBe(
|
|
|
+ 'One or more OrderItems are already part of a Fulfillment',
|
|
|
+ );
|
|
|
+ expect(addFulfillmentToOrder.code).toBe(ErrorCode.ITEMS_ALREADY_FULFILLED_ERROR);
|
|
|
+ });
|
|
|
+
|
|
|
it('transits the first fulfillment from created to Shipped and automatically change the order state to PartiallyShipped', async () => {
|
|
|
- const fulfillment = await adminClient.query<
|
|
|
+ const { transitionFulfillmentToState } = await adminClient.query<
|
|
|
TransitFulfillment.Mutation,
|
|
|
TransitFulfillment.Variables
|
|
|
>(TRANSIT_FULFILLMENT, {
|
|
|
id: 'T_1',
|
|
|
state: 'Shipped',
|
|
|
});
|
|
|
- expect(fulfillment.transitionFulfillmentToState?.id).toBe('T_1');
|
|
|
- expect(fulfillment.transitionFulfillmentToState?.state).toBe('Shipped');
|
|
|
+ fulfillmentGuard.assertSuccess(transitionFulfillmentToState);
|
|
|
+
|
|
|
+ expect(transitionFulfillmentToState.id).toBe('T_1');
|
|
|
+ expect(transitionFulfillmentToState.state).toBe('Shipped');
|
|
|
|
|
|
const { order } = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
|
|
|
id: 'T_2',
|
|
|
});
|
|
|
expect(order?.state).toBe('PartiallyShipped');
|
|
|
});
|
|
|
+
|
|
|
it('transits the second fulfillment from created to Shipped and automatically change the order state to Shipped', async () => {
|
|
|
- const fulfillment = await adminClient.query<
|
|
|
+ const { transitionFulfillmentToState } = await adminClient.query<
|
|
|
TransitFulfillment.Mutation,
|
|
|
TransitFulfillment.Variables
|
|
|
>(TRANSIT_FULFILLMENT, {
|
|
|
id: 'T_2',
|
|
|
state: 'Shipped',
|
|
|
});
|
|
|
- expect(fulfillment.transitionFulfillmentToState?.id).toBe('T_2');
|
|
|
- expect(fulfillment.transitionFulfillmentToState?.state).toBe('Shipped');
|
|
|
+ fulfillmentGuard.assertSuccess(transitionFulfillmentToState);
|
|
|
+
|
|
|
+ expect(transitionFulfillmentToState.id).toBe('T_2');
|
|
|
+ expect(transitionFulfillmentToState.state).toBe('Shipped');
|
|
|
|
|
|
const { order } = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
|
|
|
id: 'T_2',
|
|
|
});
|
|
|
expect(order?.state).toBe('Shipped');
|
|
|
});
|
|
|
+
|
|
|
it('transits the first fulfillment from Shipped to Delivered and change the order state to PartiallyDelivered', async () => {
|
|
|
- const fulfillment = await adminClient.query<
|
|
|
+ const { transitionFulfillmentToState } = await adminClient.query<
|
|
|
TransitFulfillment.Mutation,
|
|
|
TransitFulfillment.Variables
|
|
|
>(TRANSIT_FULFILLMENT, {
|
|
|
id: 'T_1',
|
|
|
state: 'Delivered',
|
|
|
});
|
|
|
- expect(fulfillment.transitionFulfillmentToState?.id).toBe('T_1');
|
|
|
- expect(fulfillment.transitionFulfillmentToState?.state).toBe('Delivered');
|
|
|
+ fulfillmentGuard.assertSuccess(transitionFulfillmentToState);
|
|
|
+
|
|
|
+ expect(transitionFulfillmentToState.id).toBe('T_1');
|
|
|
+ expect(transitionFulfillmentToState.state).toBe('Delivered');
|
|
|
|
|
|
const { order } = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
|
|
|
id: 'T_2',
|
|
|
});
|
|
|
expect(order?.state).toBe('PartiallyDelivered');
|
|
|
});
|
|
|
+
|
|
|
it('transits the second fulfillment from Shipped to Delivered and change the order state to Delivered', async () => {
|
|
|
- const fulfillment = await adminClient.query<
|
|
|
+ const { transitionFulfillmentToState } = await adminClient.query<
|
|
|
TransitFulfillment.Mutation,
|
|
|
TransitFulfillment.Variables
|
|
|
>(TRANSIT_FULFILLMENT, {
|
|
|
id: 'T_2',
|
|
|
state: 'Delivered',
|
|
|
});
|
|
|
- expect(fulfillment.transitionFulfillmentToState?.id).toBe('T_2');
|
|
|
- expect(fulfillment.transitionFulfillmentToState?.state).toBe('Delivered');
|
|
|
+ fulfillmentGuard.assertSuccess(transitionFulfillmentToState);
|
|
|
+
|
|
|
+ expect(transitionFulfillmentToState.id).toBe('T_2');
|
|
|
+ expect(transitionFulfillmentToState.state).toBe('Delivered');
|
|
|
|
|
|
const { order } = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
|
|
|
id: 'T_2',
|
|
|
@@ -642,6 +676,8 @@ describe('Orders resolver', () => {
|
|
|
);
|
|
|
await proceedToArrangingPayment(shopClient);
|
|
|
const order = await addPaymentToOrder(shopClient, failsToSettlePaymentMethod);
|
|
|
+ orderGuard.assertSuccess(order);
|
|
|
+
|
|
|
expect(order.state).toBe('PaymentAuthorized');
|
|
|
|
|
|
const result1 = await adminClient.query<GetStockMovement.Query, GetStockMovement.Variables>(
|
|
|
@@ -665,6 +701,8 @@ describe('Orders resolver', () => {
|
|
|
},
|
|
|
},
|
|
|
);
|
|
|
+ orderGuard.assertSuccess(cancelOrder);
|
|
|
+
|
|
|
expect(
|
|
|
cancelOrder.lines.map(l =>
|
|
|
l.items.map(pick(['id', 'cancelled'])).sort((a, b) => (a.id > b.id ? 1 : -1)),
|
|
|
@@ -729,68 +767,91 @@ describe('Orders resolver', () => {
|
|
|
productVariantId = result.productVariantId;
|
|
|
});
|
|
|
|
|
|
- it(
|
|
|
- 'cannot cancel from AddingItems state',
|
|
|
- assertThrowsWithMessage(async () => {
|
|
|
- const { order } = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
|
|
|
- id: orderId,
|
|
|
- });
|
|
|
- expect(order!.state).toBe('AddingItems');
|
|
|
- await adminClient.query<CancelOrder.Mutation, CancelOrder.Variables>(CANCEL_ORDER, {
|
|
|
+ it('cannot cancel from AddingItems state', async () => {
|
|
|
+ const { order } = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
|
|
|
+ id: orderId,
|
|
|
+ });
|
|
|
+ expect(order!.state).toBe('AddingItems');
|
|
|
+
|
|
|
+ const { cancelOrder } = await adminClient.query<CancelOrder.Mutation, CancelOrder.Variables>(
|
|
|
+ CANCEL_ORDER,
|
|
|
+ {
|
|
|
input: {
|
|
|
orderId,
|
|
|
lines: order!.lines.map(l => ({ orderLineId: l.id, quantity: 1 })),
|
|
|
},
|
|
|
- });
|
|
|
- }, 'Cannot cancel OrderLines from an Order in the "AddingItems" state'),
|
|
|
- );
|
|
|
+ },
|
|
|
+ );
|
|
|
+ orderGuard.assertErrorResult(cancelOrder);
|
|
|
|
|
|
- it(
|
|
|
- 'cannot cancel from ArrangingPayment state',
|
|
|
- assertThrowsWithMessage(async () => {
|
|
|
- await proceedToArrangingPayment(shopClient);
|
|
|
- const { order } = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
|
|
|
- id: orderId,
|
|
|
- });
|
|
|
- expect(order!.state).toBe('ArrangingPayment');
|
|
|
- await adminClient.query<CancelOrder.Mutation, CancelOrder.Variables>(CANCEL_ORDER, {
|
|
|
+ expect(cancelOrder.message).toBe(
|
|
|
+ 'Cannot cancel OrderLines from an Order in the "AddingItems" state',
|
|
|
+ );
|
|
|
+ expect(cancelOrder.code).toBe(ErrorCode.CANCEL_ACTIVE_ORDER_ERROR);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('cannot cancel from ArrangingPayment state', async () => {
|
|
|
+ await proceedToArrangingPayment(shopClient);
|
|
|
+ const { order } = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
|
|
|
+ id: orderId,
|
|
|
+ });
|
|
|
+ expect(order!.state).toBe('ArrangingPayment');
|
|
|
+ const { cancelOrder } = await adminClient.query<CancelOrder.Mutation, CancelOrder.Variables>(
|
|
|
+ CANCEL_ORDER,
|
|
|
+ {
|
|
|
input: {
|
|
|
orderId,
|
|
|
lines: order!.lines.map(l => ({ orderLineId: l.id, quantity: 1 })),
|
|
|
},
|
|
|
- });
|
|
|
- }, 'Cannot cancel OrderLines from an Order in the "ArrangingPayment" state'),
|
|
|
- );
|
|
|
+ },
|
|
|
+ );
|
|
|
+ orderGuard.assertErrorResult(cancelOrder);
|
|
|
|
|
|
- it(
|
|
|
- 'throws if lines are empty',
|
|
|
- assertThrowsWithMessage(async () => {
|
|
|
- const order = await addPaymentToOrder(shopClient, twoStagePaymentMethod);
|
|
|
- expect(order.state).toBe('PaymentAuthorized');
|
|
|
+ expect(cancelOrder.message).toBe(
|
|
|
+ 'Cannot cancel OrderLines from an Order in the "ArrangingPayment" state',
|
|
|
+ );
|
|
|
+ expect(cancelOrder.code).toBe(ErrorCode.CANCEL_ACTIVE_ORDER_ERROR);
|
|
|
+ });
|
|
|
|
|
|
- await adminClient.query<CancelOrder.Mutation, CancelOrder.Variables>(CANCEL_ORDER, {
|
|
|
+ it('returns error result if lines are empty', async () => {
|
|
|
+ const order = await addPaymentToOrder(shopClient, twoStagePaymentMethod);
|
|
|
+ orderGuard.assertSuccess(order);
|
|
|
+
|
|
|
+ expect(order.state).toBe('PaymentAuthorized');
|
|
|
+
|
|
|
+ const { cancelOrder } = await adminClient.query<CancelOrder.Mutation, CancelOrder.Variables>(
|
|
|
+ CANCEL_ORDER,
|
|
|
+ {
|
|
|
input: {
|
|
|
orderId,
|
|
|
lines: [],
|
|
|
},
|
|
|
- });
|
|
|
- }, 'Nothing to cancel'),
|
|
|
- );
|
|
|
+ },
|
|
|
+ );
|
|
|
+ orderGuard.assertErrorResult(cancelOrder);
|
|
|
|
|
|
- it(
|
|
|
- 'throws if all quantities zero',
|
|
|
- assertThrowsWithMessage(async () => {
|
|
|
- const { order } = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
|
|
|
- id: orderId,
|
|
|
- });
|
|
|
- await adminClient.query<CancelOrder.Mutation, CancelOrder.Variables>(CANCEL_ORDER, {
|
|
|
+ expect(cancelOrder.message).toBe('At least one OrderLine must be specified');
|
|
|
+ expect(cancelOrder.code).toBe(ErrorCode.EMPTY_ORDER_LINE_SELECTION_ERROR);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('returns error result if all quantities zero', async () => {
|
|
|
+ const { order } = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
|
|
|
+ id: orderId,
|
|
|
+ });
|
|
|
+ const { cancelOrder } = await adminClient.query<CancelOrder.Mutation, CancelOrder.Variables>(
|
|
|
+ CANCEL_ORDER,
|
|
|
+ {
|
|
|
input: {
|
|
|
orderId,
|
|
|
lines: order!.lines.map(l => ({ orderLineId: l.id, quantity: 0 })),
|
|
|
},
|
|
|
- });
|
|
|
- }, 'Nothing to cancel'),
|
|
|
- );
|
|
|
+ },
|
|
|
+ );
|
|
|
+ orderGuard.assertErrorResult(cancelOrder);
|
|
|
+
|
|
|
+ expect(cancelOrder.message).toBe('At least one OrderLine must be specified');
|
|
|
+ expect(cancelOrder.code).toBe(ErrorCode.EMPTY_ORDER_LINE_SELECTION_ERROR);
|
|
|
+ });
|
|
|
|
|
|
it('partial cancellation', async () => {
|
|
|
const result1 = await adminClient.query<GetStockMovement.Query, GetStockMovement.Variables>(
|
|
|
@@ -823,6 +884,7 @@ describe('Orders resolver', () => {
|
|
|
},
|
|
|
},
|
|
|
);
|
|
|
+ orderGuard.assertSuccess(cancelOrder);
|
|
|
|
|
|
expect(cancelOrder.lines[0].quantity).toBe(1);
|
|
|
expect(cancelOrder.lines[0].items.sort((a, b) => (a.id < b.id ? -1 : 1))).toEqual([
|
|
|
@@ -855,6 +917,27 @@ describe('Orders resolver', () => {
|
|
|
]);
|
|
|
});
|
|
|
|
|
|
+ it('returns error result if attempting to cancel already cancelled item', async () => {
|
|
|
+ const { order } = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
|
|
|
+ id: orderId,
|
|
|
+ });
|
|
|
+ const { cancelOrder } = await adminClient.query<CancelOrder.Mutation, CancelOrder.Variables>(
|
|
|
+ CANCEL_ORDER,
|
|
|
+ {
|
|
|
+ input: {
|
|
|
+ orderId,
|
|
|
+ lines: order!.lines.map(l => ({ orderLineId: l.id, quantity: 2 })),
|
|
|
+ },
|
|
|
+ },
|
|
|
+ );
|
|
|
+ orderGuard.assertErrorResult(cancelOrder);
|
|
|
+
|
|
|
+ expect(cancelOrder.message).toBe(
|
|
|
+ 'The specified quantity is greater than the available OrderItems',
|
|
|
+ );
|
|
|
+ expect(cancelOrder.code).toBe(ErrorCode.QUANTITY_TOO_GREAT_ERROR);
|
|
|
+ });
|
|
|
+
|
|
|
it('complete cancellation', async () => {
|
|
|
const { order } = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
|
|
|
id: orderId,
|
|
|
@@ -968,50 +1051,61 @@ describe('Orders resolver', () => {
|
|
|
productVariantId = result.productVariantId;
|
|
|
});
|
|
|
|
|
|
- it(
|
|
|
- 'cannot refund from PaymentAuthorized state',
|
|
|
- assertThrowsWithMessage(async () => {
|
|
|
- await proceedToArrangingPayment(shopClient);
|
|
|
- const order = await addPaymentToOrder(shopClient, twoStagePaymentMethod);
|
|
|
- expect(order.state).toBe('PaymentAuthorized');
|
|
|
- paymentId = order.payments![0].id;
|
|
|
+ it('cannot refund from PaymentAuthorized state', async () => {
|
|
|
+ await proceedToArrangingPayment(shopClient);
|
|
|
+ const order = await addPaymentToOrder(shopClient, twoStagePaymentMethod);
|
|
|
+ orderGuard.assertSuccess(order);
|
|
|
|
|
|
- await adminClient.query<RefundOrder.Mutation, RefundOrder.Variables>(REFUND_ORDER, {
|
|
|
+ expect(order.state).toBe('PaymentAuthorized');
|
|
|
+ paymentId = order.payments![0].id;
|
|
|
+
|
|
|
+ const { refundOrder } = await adminClient.query<RefundOrder.Mutation, RefundOrder.Variables>(
|
|
|
+ REFUND_ORDER,
|
|
|
+ {
|
|
|
input: {
|
|
|
lines: order.lines.map(l => ({ orderLineId: l.id, quantity: 1 })),
|
|
|
shipping: 0,
|
|
|
adjustment: 0,
|
|
|
paymentId,
|
|
|
},
|
|
|
- });
|
|
|
- }, 'Cannot refund an Order in the "PaymentAuthorized" state'),
|
|
|
- );
|
|
|
+ },
|
|
|
+ );
|
|
|
+ refundGuard.assertErrorResult(refundOrder);
|
|
|
|
|
|
- it(
|
|
|
- 'throws if no lines and no shipping',
|
|
|
- assertThrowsWithMessage(async () => {
|
|
|
- const { order } = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
|
|
|
- id: orderId,
|
|
|
- });
|
|
|
- const { settlePayment } = await adminClient.query<
|
|
|
- SettlePayment.Mutation,
|
|
|
- SettlePayment.Variables
|
|
|
- >(SETTLE_PAYMENT, {
|
|
|
- id: order!.payments![0].id,
|
|
|
- });
|
|
|
+ expect(refundOrder.message).toBe('Cannot refund an Order in the "PaymentAuthorized" state');
|
|
|
+ expect(refundOrder.code).toBe(ErrorCode.REFUND_ORDER_STATE_ERROR);
|
|
|
+ });
|
|
|
|
|
|
- expect(settlePayment!.state).toBe('Settled');
|
|
|
+ it('returns error result if no lines and no shipping', async () => {
|
|
|
+ const { order } = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
|
|
|
+ id: orderId,
|
|
|
+ });
|
|
|
+ const { settlePayment } = await adminClient.query<
|
|
|
+ SettlePayment.Mutation,
|
|
|
+ SettlePayment.Variables
|
|
|
+ >(SETTLE_PAYMENT, {
|
|
|
+ id: order!.payments![0].id,
|
|
|
+ });
|
|
|
+ paymentGuard.assertSuccess(settlePayment);
|
|
|
|
|
|
- await adminClient.query<RefundOrder.Mutation, RefundOrder.Variables>(REFUND_ORDER, {
|
|
|
+ expect(settlePayment!.state).toBe('Settled');
|
|
|
+
|
|
|
+ const { refundOrder } = await adminClient.query<RefundOrder.Mutation, RefundOrder.Variables>(
|
|
|
+ REFUND_ORDER,
|
|
|
+ {
|
|
|
input: {
|
|
|
lines: order!.lines.map(l => ({ orderLineId: l.id, quantity: 0 })),
|
|
|
shipping: 0,
|
|
|
adjustment: 0,
|
|
|
paymentId,
|
|
|
},
|
|
|
- });
|
|
|
- }, 'Nothing to refund'),
|
|
|
- );
|
|
|
+ },
|
|
|
+ );
|
|
|
+ refundGuard.assertErrorResult(refundOrder);
|
|
|
+
|
|
|
+ expect(refundOrder.message).toBe('Nothing to refund');
|
|
|
+ expect(refundOrder.code).toBe(ErrorCode.NOTHING_TO_REFUND_ERROR);
|
|
|
+ });
|
|
|
|
|
|
it(
|
|
|
'throws if paymentId not valid',
|
|
|
@@ -1030,28 +1124,29 @@ describe('Orders resolver', () => {
|
|
|
},
|
|
|
},
|
|
|
);
|
|
|
- }, "No Payment with the id '999' could be found"),
|
|
|
+ }, `No Payment with the id '999' could be found`),
|
|
|
);
|
|
|
|
|
|
- it(
|
|
|
- 'throws if payment and order lines do not belong to the same Order',
|
|
|
- assertThrowsWithMessage(async () => {
|
|
|
- const { order } = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
|
|
|
- id: orderId,
|
|
|
- });
|
|
|
- const { refundOrder } = await adminClient.query<RefundOrder.Mutation, RefundOrder.Variables>(
|
|
|
- REFUND_ORDER,
|
|
|
- {
|
|
|
- input: {
|
|
|
- lines: order!.lines.map(l => ({ orderLineId: l.id, quantity: l.quantity })),
|
|
|
- shipping: 100,
|
|
|
- adjustment: 0,
|
|
|
- paymentId: 'T_1',
|
|
|
- },
|
|
|
+ it('returns error result if payment and order lines do not belong to the same Order', async () => {
|
|
|
+ const { order } = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
|
|
|
+ id: orderId,
|
|
|
+ });
|
|
|
+ const { refundOrder } = await adminClient.query<RefundOrder.Mutation, RefundOrder.Variables>(
|
|
|
+ REFUND_ORDER,
|
|
|
+ {
|
|
|
+ input: {
|
|
|
+ lines: order!.lines.map(l => ({ orderLineId: l.id, quantity: l.quantity })),
|
|
|
+ shipping: 100,
|
|
|
+ adjustment: 0,
|
|
|
+ paymentId: 'T_1',
|
|
|
},
|
|
|
- );
|
|
|
- }, 'The Payment and OrderLines do not belong to the same Order'),
|
|
|
- );
|
|
|
+ },
|
|
|
+ );
|
|
|
+ refundGuard.assertErrorResult(refundOrder);
|
|
|
+
|
|
|
+ expect(refundOrder.message).toBe('The Payment and OrderLines do not belong to the same Order');
|
|
|
+ expect(refundOrder.code).toBe(ErrorCode.PAYMENT_ORDER_MISMATCH_ERROR);
|
|
|
+ });
|
|
|
|
|
|
it('creates a Refund to be manually settled', async () => {
|
|
|
const { order } = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
|
|
|
@@ -1069,6 +1164,7 @@ describe('Orders resolver', () => {
|
|
|
},
|
|
|
},
|
|
|
);
|
|
|
+ refundGuard.assertSuccess(refundOrder);
|
|
|
|
|
|
expect(refundOrder.shipping).toBe(order!.shipping);
|
|
|
expect(refundOrder.items).toBe(order!.subTotal);
|
|
|
@@ -1078,25 +1174,26 @@ describe('Orders resolver', () => {
|
|
|
refundId = refundOrder.id;
|
|
|
});
|
|
|
|
|
|
- it(
|
|
|
- 'throws if attempting to refund the same item more than once',
|
|
|
- assertThrowsWithMessage(async () => {
|
|
|
- const { order } = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
|
|
|
- id: orderId,
|
|
|
- });
|
|
|
- const { refundOrder } = await adminClient.query<RefundOrder.Mutation, RefundOrder.Variables>(
|
|
|
- REFUND_ORDER,
|
|
|
- {
|
|
|
- input: {
|
|
|
- lines: order!.lines.map(l => ({ orderLineId: l.id, quantity: l.quantity })),
|
|
|
- shipping: order!.shipping,
|
|
|
- adjustment: 0,
|
|
|
- paymentId,
|
|
|
- },
|
|
|
+ it('returns error result if attempting to refund the same item more than once', async () => {
|
|
|
+ const { order } = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
|
|
|
+ id: orderId,
|
|
|
+ });
|
|
|
+ const { refundOrder } = await adminClient.query<RefundOrder.Mutation, RefundOrder.Variables>(
|
|
|
+ REFUND_ORDER,
|
|
|
+ {
|
|
|
+ input: {
|
|
|
+ lines: order!.lines.map(l => ({ orderLineId: l.id, quantity: l.quantity })),
|
|
|
+ shipping: order!.shipping,
|
|
|
+ adjustment: 0,
|
|
|
+ paymentId,
|
|
|
},
|
|
|
- );
|
|
|
- }, 'Cannot refund an OrderItem which has already been refunded'),
|
|
|
- );
|
|
|
+ },
|
|
|
+ );
|
|
|
+ refundGuard.assertErrorResult(refundOrder);
|
|
|
+
|
|
|
+ expect(refundOrder.message).toBe('Cannot refund an OrderItem which has already been refunded');
|
|
|
+ expect(refundOrder.code).toBe(ErrorCode.ALREADY_REFUNDED_ERROR);
|
|
|
+ });
|
|
|
|
|
|
it('manually settle a Refund', async () => {
|
|
|
const { settleRefund } = await adminClient.query<SettleRefund.Mutation, SettleRefund.Variables>(
|
|
|
@@ -1108,6 +1205,7 @@ describe('Orders resolver', () => {
|
|
|
},
|
|
|
},
|
|
|
);
|
|
|
+ refundGuard.assertSuccess(settleRefund);
|
|
|
|
|
|
expect(settleRefund.state).toBe('Settled');
|
|
|
expect(settleRefund.transactionId).toBe('aaabbb');
|
|
|
@@ -1356,18 +1454,28 @@ async function createTestOrder(
|
|
|
quantity: 2,
|
|
|
},
|
|
|
);
|
|
|
- const orderId = addItemToOrder!.id;
|
|
|
+ const orderId = (addItemToOrder as UpdatedOrder.Fragment).id;
|
|
|
return { product, productVariantId, orderId };
|
|
|
}
|
|
|
|
|
|
export const SETTLE_PAYMENT = gql`
|
|
|
mutation SettlePayment($id: ID!) {
|
|
|
settlePayment(id: $id) {
|
|
|
- id
|
|
|
- state
|
|
|
- metadata
|
|
|
+ ...Payment
|
|
|
+ ... on ErrorResult {
|
|
|
+ code
|
|
|
+ message
|
|
|
+ }
|
|
|
+ ... on SettlePaymentError {
|
|
|
+ paymentErrorMessage
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
+ fragment Payment on Payment {
|
|
|
+ id
|
|
|
+ state
|
|
|
+ metadata
|
|
|
+ }
|
|
|
`;
|
|
|
|
|
|
export const GET_ORDER_LIST_FULFILLMENTS = gql`
|
|
|
@@ -1393,57 +1501,71 @@ export const GET_ORDER_FULFILLMENT_ITEMS = gql`
|
|
|
id
|
|
|
state
|
|
|
fulfillments {
|
|
|
- id
|
|
|
- state
|
|
|
- orderItems {
|
|
|
- id
|
|
|
- }
|
|
|
+ ...Fulfillment
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ ${FULFILLMENT_FRAGMENT}
|
|
|
`;
|
|
|
|
|
|
export const CANCEL_ORDER = gql`
|
|
|
mutation CancelOrder($input: CancelOrderInput!) {
|
|
|
cancelOrder(input: $input) {
|
|
|
- id
|
|
|
- lines {
|
|
|
- quantity
|
|
|
- items {
|
|
|
- id
|
|
|
- cancelled
|
|
|
- }
|
|
|
+ ...CanceledOrder
|
|
|
+ ... on ErrorResult {
|
|
|
+ code
|
|
|
+ message
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ fragment CanceledOrder on Order {
|
|
|
+ id
|
|
|
+ lines {
|
|
|
+ quantity
|
|
|
+ items {
|
|
|
+ id
|
|
|
+ cancelled
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
`;
|
|
|
|
|
|
+const REFUND_FRAGMENT = gql`
|
|
|
+ fragment Refund on Refund {
|
|
|
+ id
|
|
|
+ state
|
|
|
+ items
|
|
|
+ transactionId
|
|
|
+ shipping
|
|
|
+ total
|
|
|
+ metadata
|
|
|
+ }
|
|
|
+`;
|
|
|
+
|
|
|
export const REFUND_ORDER = gql`
|
|
|
mutation RefundOrder($input: RefundOrderInput!) {
|
|
|
refundOrder(input: $input) {
|
|
|
- id
|
|
|
- state
|
|
|
- items
|
|
|
- transactionId
|
|
|
- shipping
|
|
|
- total
|
|
|
- metadata
|
|
|
+ ...Refund
|
|
|
+ ... on ErrorResult {
|
|
|
+ code
|
|
|
+ message
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
+ ${REFUND_FRAGMENT}
|
|
|
`;
|
|
|
|
|
|
export const SETTLE_REFUND = gql`
|
|
|
mutation SettleRefund($input: SettleRefundInput!) {
|
|
|
settleRefund(input: $input) {
|
|
|
- id
|
|
|
- state
|
|
|
- items
|
|
|
- transactionId
|
|
|
- shipping
|
|
|
- total
|
|
|
- metadata
|
|
|
+ ...Refund
|
|
|
+ ... on ErrorResult {
|
|
|
+ code
|
|
|
+ message
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
+ ${REFUND_FRAGMENT}
|
|
|
`;
|
|
|
|
|
|
export const GET_ORDER_HISTORY = gql`
|