|
|
@@ -1,8 +1,8 @@
|
|
|
import { OrderStatus } from '@mollie/api-client';
|
|
|
-import { ChannelService, mergeConfig, OrderService, RequestContext } from '@vendure/core';
|
|
|
+import { ChannelService, DefaultLogger, LogLevel, mergeConfig, OrderService, RequestContext } from '@vendure/core';
|
|
|
import {
|
|
|
SettlePaymentMutation,
|
|
|
- SettlePaymentMutationVariables,
|
|
|
+ SettlePaymentMutationVariables
|
|
|
} from '@vendure/core/e2e/graphql/generated-e2e-admin-types';
|
|
|
import { SETTLE_PAYMENT } from '@vendure/core/e2e/graphql/shared-definitions';
|
|
|
import { createTestEnvironment, E2E_DEFAULT_CHANNEL_TOKEN, SimpleGraphQLClient, TestServer } from '@vendure/testing';
|
|
|
@@ -12,6 +12,7 @@ import path from 'path';
|
|
|
|
|
|
import { initialData } from '../../../e2e-common/e2e-initial-data';
|
|
|
import { testConfig, TEST_SETUP_TIMEOUT_MS } from '../../../e2e-common/test-config';
|
|
|
+import { UPDATE_PRODUCT_VARIANTS } from '../../core/e2e/graphql/shared-definitions';
|
|
|
import { MolliePlugin } from '../src/mollie';
|
|
|
import { molliePaymentHandler } from '../src/mollie/mollie.handler';
|
|
|
|
|
|
@@ -19,7 +20,7 @@ import { CREATE_PAYMENT_METHOD, GET_CUSTOMER_LIST, GET_ORDER_PAYMENTS } from './
|
|
|
import { CreatePaymentMethod, GetCustomerList, GetCustomerListQuery } from './graphql/generated-admin-types';
|
|
|
import { AddItemToOrder, GetOrderByCode, TestOrderFragmentFragment } from './graphql/generated-shop-types';
|
|
|
import { ADD_ITEM_TO_ORDER, GET_ORDER_BY_CODE } from './graphql/shop-queries';
|
|
|
-import { CREATE_MOLLIE_PAYMENT_INTENT, GET_MOLLIE_PAYMENT_METHODS, refundOne, setShipping } from './payment-helpers';
|
|
|
+import { addManualPayment, CREATE_MOLLIE_PAYMENT_INTENT, GET_MOLLIE_PAYMENT_METHODS, refundOrderLine, setShipping } from './payment-helpers';
|
|
|
|
|
|
describe('Mollie payments', () => {
|
|
|
const mockData = {
|
|
|
@@ -103,7 +104,7 @@ describe('Mollie payments', () => {
|
|
|
const devConfig = mergeConfig(testConfig(), {
|
|
|
plugins: [MolliePlugin.init({ vendureHost: mockData.host })],
|
|
|
// Uncomment next line to debug e2e
|
|
|
- // logger: new DefaultLogger({level: LogLevel.Verbose})
|
|
|
+ logger: new DefaultLogger({level: LogLevel.Verbose})
|
|
|
});
|
|
|
const env = createTestEnvironment(devConfig);
|
|
|
serverPort = devConfig.apiOptions.port;
|
|
|
@@ -159,21 +160,21 @@ describe('Mollie payments', () => {
|
|
|
it('Should add a Mollie paymentMethod', async () => {
|
|
|
const { createPaymentMethod } = await adminClient.query<CreatePaymentMethod.Mutation,
|
|
|
CreatePaymentMethod.Variables>(CREATE_PAYMENT_METHOD, {
|
|
|
- input: {
|
|
|
- code: mockData.methodCode,
|
|
|
- name: 'Mollie payment test',
|
|
|
- description: 'This is a Mollie test payment method',
|
|
|
- enabled: true,
|
|
|
- handler: {
|
|
|
- code: molliePaymentHandler.code,
|
|
|
- arguments: [
|
|
|
- { name: 'redirectUrl', value: mockData.redirectUrl },
|
|
|
- { name: 'apiKey', value: mockData.apiKey },
|
|
|
- { name: 'autoCapture', value: 'false' },
|
|
|
- ],
|
|
|
+ input: {
|
|
|
+ code: mockData.methodCode,
|
|
|
+ name: 'Mollie payment test',
|
|
|
+ description: 'This is a Mollie test payment method',
|
|
|
+ enabled: true,
|
|
|
+ handler: {
|
|
|
+ code: molliePaymentHandler.code,
|
|
|
+ arguments: [
|
|
|
+ { name: 'redirectUrl', value: mockData.redirectUrl },
|
|
|
+ { name: 'apiKey', value: mockData.apiKey },
|
|
|
+ { name: 'autoCapture', value: 'false' },
|
|
|
+ ],
|
|
|
+ },
|
|
|
},
|
|
|
- },
|
|
|
- });
|
|
|
+ });
|
|
|
expect(createPaymentMethod.code).toBe(mockData.methodCode);
|
|
|
});
|
|
|
|
|
|
@@ -199,16 +200,40 @@ describe('Mollie payments', () => {
|
|
|
expect(result.errorCode).toBe('INELIGIBLE_PAYMENT_METHOD_ERROR');
|
|
|
});
|
|
|
|
|
|
+ it('Should fail to get payment url when items are out of stock', async () => {
|
|
|
+ let { updateProductVariants } = await adminClient.query(UPDATE_PRODUCT_VARIANTS, {
|
|
|
+ input: {
|
|
|
+ id: 'T_5',
|
|
|
+ trackInventory: 'TRUE',
|
|
|
+ outOfStockThreshold: 0,
|
|
|
+ stockOnHand: 1,
|
|
|
+ }
|
|
|
+ });
|
|
|
+ expect(updateProductVariants[0].stockOnHand).toBe(1);
|
|
|
+ const { createMolliePaymentIntent: result } = await shopClient.query(CREATE_MOLLIE_PAYMENT_INTENT, {
|
|
|
+ input: {
|
|
|
+ paymentMethodCode: mockData.methodCode,
|
|
|
+ },
|
|
|
+ });
|
|
|
+ expect(result.message).toContain('The following variants are out of stock');
|
|
|
+ // Set stock back to not tracking
|
|
|
+ ({ updateProductVariants } = await adminClient.query(UPDATE_PRODUCT_VARIANTS, {
|
|
|
+ input: {
|
|
|
+ id: 'T_5',
|
|
|
+ trackInventory: 'FALSE',
|
|
|
+ }
|
|
|
+ }));
|
|
|
+ expect(updateProductVariants[0].trackInventory).toBe('FALSE');
|
|
|
+ });
|
|
|
+
|
|
|
it('Should get payment url without Mollie method', async () => {
|
|
|
- let mollieRequest;
|
|
|
+ let mollieRequest: any | undefined;
|
|
|
nock('https://api.mollie.com/')
|
|
|
- .post(/.*/, body => {
|
|
|
+ .post('/v2/orders', body => {
|
|
|
mollieRequest = body;
|
|
|
return true;
|
|
|
})
|
|
|
.reply(200, mockData.mollieOrderResponse);
|
|
|
- await shopClient.asUserWithCredentials(customers[0].emailAddress, 'test');
|
|
|
- await setShipping(shopClient);
|
|
|
const { createMolliePaymentIntent } = await shopClient.query(CREATE_MOLLIE_PAYMENT_INTENT, {
|
|
|
input: {
|
|
|
paymentMethodCode: mockData.methodCode,
|
|
|
@@ -232,12 +257,8 @@ describe('Mollie payments', () => {
|
|
|
});
|
|
|
|
|
|
it('Should get payment url with Mollie method', async () => {
|
|
|
- let mollieRequest;
|
|
|
nock('https://api.mollie.com/')
|
|
|
- .post(/.*/, body => {
|
|
|
- mollieRequest = body;
|
|
|
- return true;
|
|
|
- })
|
|
|
+ .post('/v2/orders')
|
|
|
.reply(200, mockData.mollieOrderResponse);
|
|
|
await shopClient.asUserWithCredentials(customers[0].emailAddress, 'test');
|
|
|
await setShipping(shopClient);
|
|
|
@@ -250,9 +271,32 @@ describe('Mollie payments', () => {
|
|
|
expect(createMolliePaymentIntent).toEqual({ url: 'https://www.mollie.com/payscreen/select-method/mock-payment' });
|
|
|
});
|
|
|
|
|
|
+ it('Should get payment url with deducted amount if a payment is already made', async () => {
|
|
|
+ let mollieRequest: any | undefined;
|
|
|
+ nock('https://api.mollie.com/')
|
|
|
+ .post('/v2/orders', body => {
|
|
|
+ mollieRequest = body;
|
|
|
+ return true;
|
|
|
+ })
|
|
|
+ .reply(200, mockData.mollieOrderResponse);
|
|
|
+ await addManualPayment(server, 1, 10000);
|
|
|
+ await shopClient.query(CREATE_MOLLIE_PAYMENT_INTENT, {
|
|
|
+ input: {
|
|
|
+ paymentMethodCode: mockData.methodCode,
|
|
|
+ },
|
|
|
+ });
|
|
|
+ expect(mollieRequest.amount?.value).toBe('909.90'); // minus 100,00 from manual payment
|
|
|
+ let totalLineAmount = 0;
|
|
|
+ for (const line of mollieRequest?.lines) {
|
|
|
+ totalLineAmount += Number(line.totalAmount.value);
|
|
|
+ }
|
|
|
+ // Sum of lines should equal order total
|
|
|
+ expect(mollieRequest.amount.value).toEqual(totalLineAmount.toFixed(2));
|
|
|
+ });
|
|
|
+
|
|
|
it('Should immediately settle payment for standard payment methods', async () => {
|
|
|
nock('https://api.mollie.com/')
|
|
|
- .get(/.*/)
|
|
|
+ .get('/v2/orders/ord_mockId')
|
|
|
.reply(200, {
|
|
|
...mockData.mollieOrderResponse,
|
|
|
orderNumber: order.code,
|
|
|
@@ -275,7 +319,8 @@ describe('Mollie payments', () => {
|
|
|
});
|
|
|
|
|
|
it('Should have Mollie metadata on payment', async () => {
|
|
|
- const { order: { payments: [{ metadata }] } } = await adminClient.query(GET_ORDER_PAYMENTS, { id: order.id });
|
|
|
+ const { order: { payments } } = await adminClient.query(GET_ORDER_PAYMENTS, { id: order.id });
|
|
|
+ const metadata = payments[1].metadata;
|
|
|
expect(metadata.mode).toBe(mockData.mollieOrderResponse.mode);
|
|
|
expect(metadata.method).toBe(mockData.mollieOrderResponse.method);
|
|
|
expect(metadata.profileId).toBe(mockData.mollieOrderResponse.profileId);
|
|
|
@@ -284,38 +329,37 @@ describe('Mollie payments', () => {
|
|
|
});
|
|
|
|
|
|
it('Should fail to refund', async () => {
|
|
|
- let mollieRequest;
|
|
|
nock('https://api.mollie.com/')
|
|
|
.get('/v2/orders/ord_mockId?embed=payments')
|
|
|
- .twice()
|
|
|
.reply(200, mockData.mollieOrderResponse);
|
|
|
nock('https://api.mollie.com/')
|
|
|
- .post(/.*/, body => {
|
|
|
- mollieRequest = body;
|
|
|
- return true;
|
|
|
- })
|
|
|
+ .post('/v2/payments/tr_mockPayment/refunds')
|
|
|
.reply(200, { status: 'failed', resource: 'payment' });
|
|
|
- const refund = await refundOne(adminClient, order.lines[0].id, order.payments[0].id);
|
|
|
+ // tslint:disable-next-line:no-non-null-assertion
|
|
|
+ const refund = await refundOrderLine(adminClient, order.lines[0].id, 1, order!.payments[1].id);
|
|
|
expect(refund.state).toBe('Failed');
|
|
|
});
|
|
|
|
|
|
- it('Should successfully refund', async () => {
|
|
|
+ it('Should successfully refund the Mollie payment', async () => {
|
|
|
let mollieRequest;
|
|
|
nock('https://api.mollie.com/')
|
|
|
- .post(/.*/, body => {
|
|
|
+ .get('/v2/orders/ord_mockId?embed=payments')
|
|
|
+ .reply(200, mockData.mollieOrderResponse);
|
|
|
+ nock('https://api.mollie.com/')
|
|
|
+ .post('/v2/payments/tr_mockPayment/refunds', body => {
|
|
|
mollieRequest = body;
|
|
|
return true;
|
|
|
})
|
|
|
.reply(200, { status: 'pending', resource: 'payment' });
|
|
|
- const refund = await refundOne(adminClient, order.lines[0].id, order.payments[0].id);
|
|
|
- expect(mollieRequest?.amount.value).toBe('119.99');
|
|
|
- expect(refund.total).toBe(11999);
|
|
|
+ const refund = await refundOrderLine(adminClient, order.lines[0].id, 10, order.payments[1].id);
|
|
|
+ expect(mollieRequest?.amount.value).toBe('909.90'); // Only refund mollie amount, not the gift card
|
|
|
+ expect(refund.total).toBe(90990);
|
|
|
expect(refund.state).toBe('Settled');
|
|
|
});
|
|
|
|
|
|
it('Should get available paymentMethods', async () => {
|
|
|
nock('https://api.mollie.com/')
|
|
|
- .get(/.*/)
|
|
|
+ .get('/v2/methods')
|
|
|
.reply(200, mockData.molliePaymentMethodsResponse);
|
|
|
await shopClient.asUserWithCredentials(customers[0].emailAddress, 'test');
|
|
|
const { molliePaymentMethods } = await shopClient.query(GET_MOLLIE_PAYMENT_METHODS, {
|
|
|
@@ -343,7 +387,7 @@ describe('Mollie payments', () => {
|
|
|
|
|
|
it('Should authorize payment for pay-later payment methods', async () => {
|
|
|
nock('https://api.mollie.com/')
|
|
|
- .get(/.*/)
|
|
|
+ .get('/v2/orders/ord_mockId')
|
|
|
.reply(200, {
|
|
|
...mockData.mollieOrderResponse,
|
|
|
orderNumber: order.code,
|
|
|
@@ -368,7 +412,7 @@ describe('Mollie payments', () => {
|
|
|
it('Should settle payment via settlePayment mutation', async () => {
|
|
|
// Mock the getOrder Mollie call
|
|
|
nock('https://api.mollie.com/')
|
|
|
- .get(/.*/)
|
|
|
+ .get('/v2/orders/ord_mockId')
|
|
|
.reply(200, {
|
|
|
...mockData.mollieOrderResponse,
|
|
|
orderNumber: order.code,
|