#How to handle cancelled or failed payments?

4 messages · Page 1 of 1 (latest)

short drum
#

I successfully set up a Mollie Payment provider, and I implemented the getWebhookActionAndData as follow:

switch (status) {
  case PaymentStatus.authorized:
    return {
      action: PaymentActions.AUTHORIZED,
      data: baseData,
    };
  case PaymentStatus.paid:
    return {
      action: PaymentActions.SUCCESSFUL,
      data: baseData,
    };
  case PaymentStatus.expired:
  case PaymentStatus.failed:
    return {
      action: PaymentActions.FAILED,
      data: baseData,
    };
  case PaymentStatus.canceled:
    return {
      action: PaymentActions.CANCELED,
      data: baseData,
    };
  case PaymentStatus.pending:
    return {
      action: PaymentActions.PENDING,
      data: baseData,
    };
  case PaymentStatus.open:
    return {
      action: PaymentActions.REQUIRES_MORE,
      data: baseData,
    };
  default:
    return {
      action: PaymentActions.NOT_SUPPORTED,
      data: baseData,
    };
}

For the authorized and captured states everything works great. But for failed and cancelled, this function runs just fine, but Medusa just ignores the result?
I already found the source code that handles the return value of this function here: https://github.com/medusajs/medusa/blob/2e65f7ffc0fa360bbd211d41fac8384c240848cc/packages/medusa/src/subscribers/payment-webhook.ts#L38
And it specifically ignores everything but the authorized or captured states...
How are you supposed to show errors in the UI when the webhook call is ignored for errors and cancel states?

magic trout
#

@short drum Dealing with the same issue, have you resolved somehow?

short drum
#

In getWebhookActionAndData I added this:

  case PaymentStatus.expired:
  case PaymentStatus.failed:
  case PaymentStatus.canceled:
  case PaymentStatus.open:
    /**
     * These are all simply ignored by medusa at the time of writing. See the current
     * version of the time of writing this code:
     * https://github.com/medusajs/medusa/blob/4f7fcd7597b0787102ae0ca28f72d92727434698/packages/medusa/src/subscribers/payment-webhook.ts#L38
     *
     * Check this file here on the latest branch for changes:
     * https://github.com/medusajs/medusa/blob/develop/packages/medusa/src/subscribers/payment-webhook.ts#L38
     *
     * As a workaround, we create our own event to handle these unsupported statuses.
     */
    return await this.notSupportedWebhookAction(baseData, payment);

This calls this method:

  async notSupportedWebhookAction(
    baseData: {
      amount: BigNumber;
      session_id: any;
    },
    payment: Record<string, unknown>,
  ) {
    await this.eventBus.emit(
      {
        name: "payment.webhook_received_with_unsupported_status",
        data: { payment },
      },
      {},
    );
    return {
      action: PaymentActions.NOT_SUPPORTED,
      data: baseData,
    };
  }
#

This triggers a subscriber, that triggers a workflow, that calls this step:

const handleUnsupportedPaymentWebhookStep = createStep(
  "handle-unsupported-payment-webhook",
  async (input: { payment: Payment }, { container }) => {
    const paymentSessionId = paymentMetadataSchema.parse(
      input.payment.metadata,
    ).idempotency_key;

    /**
     * Right now, payment sessions can't be cancelled or set to an error state.
     * Our simple solution for now is to just delete the payment session.
     * If the frontend finds a payment collection on the cart but not a payment session,
     * it will just redirect to the payment step during checkout and display a generic
     * error message.
     */
    await deletePaymentSessionsWorkflow(container).run({
      input: {
        ids: [paymentSessionId],
      },
    });
    return new StepResponse();
  },
);