Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(payments-plugin): Check for eligibility of Mollie method #3200

Merged
merged 1 commit into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 45 additions & 1 deletion packages/payments-plugin/e2e/mollie-payment.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,15 @@ import {
import {
AddItemToOrderMutation,
AddItemToOrderMutationVariables,
AdjustOrderLineMutation,
AdjustOrderLineMutationVariables,
GetOrderByCodeQuery,
GetOrderByCodeQueryVariables,
TestOrderFragmentFragment,
} from './graphql/generated-shop-types';
import {
ADD_ITEM_TO_ORDER,
ADJUST_ORDER_LINE,
APPLY_COUPON_CODE,
GET_ACTIVE_ORDER,
GET_ORDER_BY_CODE,
Expand All @@ -60,6 +63,7 @@ import {
GET_MOLLIE_PAYMENT_METHODS,
refundOrderLine,
setShipping,
testPaymentEligibilityChecker,
} from './payment-helpers';

const mockData = {
Expand Down Expand Up @@ -181,6 +185,9 @@ describe('Mollie payments', () => {
beforeAll(async () => {
const devConfig = mergeConfig(testConfig(), {
plugins: [MolliePlugin.init({ vendureHost: mockData.host })],
paymentOptions: {
paymentMethodEligibilityCheckers: [testPaymentEligibilityChecker],
},
});
const env = createTestEnvironment(devConfig);
serverPort = devConfig.apiOptions.port;
Expand Down Expand Up @@ -224,6 +231,10 @@ describe('Mollie payments', () => {
input: {
code: mockData.methodCode,
enabled: true,
checker: {
code: testPaymentEligibilityChecker.code,
arguments: [],
},
handler: {
code: molliePaymentHandler.code,
arguments: [
Expand Down Expand Up @@ -390,7 +401,41 @@ describe('Mollie payments', () => {
});
});

it('Should not allow creating intent if payment method is not eligible', async () => {
// Set quantity to 9, which is not allowe by our test eligibility checker
await shopClient.query<AdjustOrderLineMutation, AdjustOrderLineMutationVariables>(
ADJUST_ORDER_LINE,
{
orderLineId: order.lines[0].id,
quantity: 9,
},
);
let mollieRequest: any | undefined;
nock('https://api.mollie.com/')
.post('/v2/orders', body => {
mollieRequest = body;
return true;
})
.reply(200, mockData.mollieOrderResponse);
const { createMolliePaymentIntent } = await shopClient.query(CREATE_MOLLIE_PAYMENT_INTENT, {
input: {
paymentMethodCode: mockData.methodCode,
redirectUrl: 'given-storefront-redirect-url',
},
});
expect(createMolliePaymentIntent.errorCode).toBe('INELIGIBLE_PAYMENT_METHOD_ERROR');
expect(createMolliePaymentIntent.message).toContain('is not eligible for order');
});

it('Should get payment url with deducted amount if a payment is already made', async () => {
// Change quantity back to 10
await shopClient.query<AdjustOrderLineMutation, AdjustOrderLineMutationVariables>(
ADJUST_ORDER_LINE,
{
orderLineId: order.lines[0].id,
quantity: 10,
},
);
let mollieRequest: any | undefined;
nock('https://api.mollie.com/')
.post('/v2/orders', body => {
Expand Down Expand Up @@ -702,7 +747,6 @@ describe('Mollie payments', () => {
>(CREATE_PAYMENT_METHOD, {
input: {
code: mockData.methodCodeBroken,

enabled: true,
handler: {
code: molliePaymentHandler.code,
Expand Down
20 changes: 20 additions & 0 deletions packages/payments-plugin/e2e/payment-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import { ID } from '@vendure/common/lib/shared-types';
import {
ChannelService,
ErrorResult,
LanguageCode,
OrderService,
PaymentMethodEligibilityChecker,
PaymentService,
RequestContext,
assertFound,
Expand Down Expand Up @@ -189,6 +191,24 @@ export async function createFreeShippingCoupon(
}
}

/**
* Test payment eligibility checker that doesn't allow orders with quantity 9 on an order line,
* just so that we can easily mock non-eligibility
*/
export const testPaymentEligibilityChecker = new PaymentMethodEligibilityChecker({
code: 'test-payment-eligibility-checker',
description: [{ languageCode: LanguageCode.en, value: 'Do not allow 9 items' }],
args: {},
check: (ctx, order, args) => {
const hasLineWithQuantity9 = order.lines.find(line => line.quantity === 9);
if (hasLineWithQuantity9) {
return false;
} else {
return true;
}
},
});

export const CREATE_MOLLIE_PAYMENT_INTENT = gql`
mutation createMolliePaymentIntent($input: MolliePaymentIntentInput!) {
createMolliePaymentIntent(input: $input) {
Expand Down
41 changes: 28 additions & 13 deletions packages/payments-plugin/src/mollie/mollie.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
EntityHydrator,
ErrorResult,
ID,
idsAreEqual,
Injector,
LanguageCode,
Logger,
Expand Down Expand Up @@ -94,16 +95,33 @@ export class MollieService {
if (order instanceof PaymentIntentError) {
return order;
}
await this.entityHydrator.hydrate(ctx, order, {
relations: [
'customer',
'surcharges',
'lines.productVariant',
'lines.productVariant.translations',
'shippingLines.shippingMethod',
'payments',
],
});
if (!paymentMethod) {
return new PaymentIntentError(`No paymentMethod found with code ${String(paymentMethodCode)}`);
}
const [eligiblePaymentMethods] = await Promise.all([
this.orderService.getEligiblePaymentMethods(ctx, order.id),
await this.entityHydrator.hydrate(ctx, order, {
relations: [
'customer',
'surcharges',
'lines.productVariant',
'lines.productVariant.translations',
'shippingLines.shippingMethod',
'payments',
],
}),
]);
if (
!eligiblePaymentMethods.find(
eligibleMethod =>
idsAreEqual(eligibleMethod.id, paymentMethod?.id) && eligibleMethod.isEligible,
)
) {
// Given payment method code is not eligible for this order
return new InvalidInputError(
`Payment method ${paymentMethod?.code} is not eligible for order ${order.code}`,
);
}
if (order.state !== 'ArrangingPayment' && order.state !== 'ArrangingAdditionalPayment') {
// Pre-check if order is transitionable to ArrangingPayment, because that will happen after Mollie payment
try {
Expand All @@ -125,9 +143,6 @@ export class MollieService {
'Cannot create payment intent for order with customer that has no lastName set',
);
}
if (!paymentMethod) {
return new PaymentIntentError(`No paymentMethod found with code ${String(paymentMethodCode)}`);
}
let redirectUrl = input.redirectUrl;
if (!redirectUrl) {
// Use fallback redirect if no redirectUrl is given
Expand Down
Loading