Переглянути джерело

feat(payments-plugin): E2e test fixed

Martijn 1 рік тому
батько
коміт
1e65032d13

+ 26 - 1
packages/payments-plugin/e2e/mollie-payment.e2e-spec.ts

@@ -277,7 +277,7 @@ describe('Mollie payments with useDynamicRedirectUrl=false', () => {
                     },
                 },
             );
-            expect(result.message).toContain('The following variants are out of stock');
+            expect(result.message).toContain('insufficient stock of Pinelab stickers');
             // Set stock back to not tracking
             ({ updateProductVariants } = await adminClient.query(UPDATE_PRODUCT_VARIANTS, {
                 input: {
@@ -335,6 +335,31 @@ describe('Mollie payments with useDynamicRedirectUrl=false', () => {
             });
         });
 
+        it('Should reuse payment url when amount is the same', async () => {
+            // Should only fetch the order from Mollie, not create a new one
+            nock('https://api.mollie.com/')
+                .get('/v2/orders/ord_mockId')
+                .reply(200, {
+                    ...mockData.mollieOrderResponse,
+                    amount: {
+                        value: '1009.90',
+                        currency: 'USD',
+                    },
+                    _links: {
+                        // Mock a new checkout url, to test that this one is actually reused
+                        checkout: {
+                            href: 'https://this-means-reuse-succeeded',
+                        },
+                    },
+                });
+            const { createMolliePaymentIntent } = await shopClient.query(CREATE_MOLLIE_PAYMENT_INTENT, {
+                input: {
+                    paymentMethodCode: mockData.methodCode,
+                },
+            });
+            expect(createMolliePaymentIntent).toEqual({ url: 'https://this-means-reuse-succeeded' });
+        });
+
         it('Should get payment url with deducted amount if a payment is already made', async () => {
             let mollieRequest: any | undefined;
             nock('https://api.mollie.com/')

+ 18 - 30
packages/payments-plugin/src/mollie/mollie.service.ts

@@ -113,30 +113,27 @@ export class MollieService {
                 'payments',
             ],
         });
-        if (!order.lines?.length) {
-            return new PaymentIntentError('Cannot create payment intent for empty order');
-        }
-        if (!order.customer) {
-            return new PaymentIntentError('Cannot create payment intent for order without customer');
+        if (order.state !== 'ArrangingPayment' && order.state !== 'ArrangingAdditionalPayment') {
+            // Pre-check if order is transitionable to ArrangingPayment, because that will happen after Mollie payment
+            try {
+                await this.canTransitionTo(ctx, order.id, 'ArrangingPayment');
+            } catch (e) {
+                if ((e as Error).message) {
+                    return new PaymentIntentError((e as Error).message);
+                }
+                throw e;
+            }
         }
-        if (!order.customer.firstName.length) {
+        if (!order.customer?.firstName.length) {
             return new PaymentIntentError(
                 'Cannot create payment intent for order with customer that has no firstName set',
             );
         }
-        if (!order.customer.lastName.length) {
+        if (!order.customer?.lastName.length) {
             return new PaymentIntentError(
                 'Cannot create payment intent for order with customer that has no lastName set',
             );
         }
-        if (!order.customer.emailAddress.length) {
-            return new PaymentIntentError(
-                'Cannot create payment intent for order with customer that has no emailAddress set',
-            );
-        }
-        if (!order.shippingLines?.length) {
-            return new PaymentIntentError('Cannot create payment intent for order without shippingMethod');
-        }
         if (!paymentMethod) {
             return new PaymentIntentError(`No paymentMethod found with code ${paymentMethodCode}`);
         }
@@ -156,19 +153,6 @@ export class MollieService {
             }
             redirectUrl = paymentMethodRedirectUrl;
         }
-        // FIXME: The manual checks above can be removed, now that we do a canTransition check?
-        if (order.state !== 'ArrangingPayment' && order.state !== 'ArrangingAdditionalPayment') {
-            // Check if order is transitionable to ArrangingPayment, because that will happen after Mollie payment
-            await this.canTransitionTo(ctx, order.id, 'ArrangingPayment');
-        }
-        const variantsWithInsufficientSaleableStock = await this.getVariantsWithInsufficientStock(ctx, order);
-        if (variantsWithInsufficientSaleableStock.length) {
-            return new PaymentIntentError(
-                `The following variants are out of stock: ${variantsWithInsufficientSaleableStock
-                    .map(v => v.name)
-                    .join(', ')}`,
-            );
-        }
         const apiKey = paymentMethod.handler.args.find(arg => arg.name === 'apiKey')?.value;
         if (!apiKey) {
             Logger.warn(
@@ -487,11 +471,15 @@ export class MollieService {
             amountToPay,
             existingMollieOrder.amount,
         );
-        if (checkoutUrl && amountsMatch) {
-            return checkoutUrl;
+        if (amountsMatch) {
+            return checkoutUrl ?? undefined;
         }
     }
 
+    /**
+     * Dry run a transition to a given state.
+     * As long as we don't call 'finalize', the transition never completes.
+     */
     private async canTransitionTo(ctx: RequestContext, orderId: ID, state: OrderState) {
         // Fetch new order object, because `transition()` mutates the order object
         const orderCopy = await assertFound(this.orderService.findOne(ctx, orderId));