wp-pronamic-pay icon indicating copy to clipboard operation
wp-pronamic-pay copied to clipboard

Empty payment amount `!=` payment status success

Open remcotolsma opened this issue 3 years ago • 4 comments

Currently we give all payments with an empty (€ 0) amount the status success and return early so the payment is not started at the gateway: https://github.com/pronamic/wp-pay-core/blob/develop/src/Plugin.php#L1025-L1045.

This seems less convenient because subscriptions may include a free first period (trial), but with some payment methods / gateways a minimum payment is required to obtain a mandate.

This is the case for a recurring direct debit payment where a mandate is obtained via a first iDEAL payment. Certain gateways must have the chance to throw an exception in that case.

Schermafbeelding 2021-08-20 om 09 46 47 Schermafbeelding 2021-08-20 om 09 47 03

It would be great if the Mollie gateway could throw an exception in case of an € 0 payment for the 'Direct Debit mandate via iDEAL payment method' (DIRECT_DEBIT_IDEAL).

https://help.mollie.com/hc/nl/articles/214072489-Hoe-verkrijg-ik-een-mandaat-van-mijn-klant-customer-voor-Recurring-

I also noted a $maybe_tokenize variable introduced in https://github.com/pronamic/wp-pay-core/commit/8d90f0dba9f3c6ac0d95bf28ffe6598168b54dca that may also be related to this.

Internal HelpScout ticket: https://secure.helpscout.net/conversation/1604745461/22551?folderId=1425710

remcotolsma avatar Aug 20 '21 07:08 remcotolsma

I agree we need to improve on this. We'll be able to set payment method constraints (like minimum amount) with the updated Payment Methods API, which will resolve this issue.

  • https://github.com/pronamic/wp-pronamic-pay/issues/154

rvdsteege avatar Aug 23 '21 09:08 rvdsteege

Further investigation shows that subscriptions for MemberPress memberships with an invalid initial amount for DIRECT_DEBIT_IDEAL are already impossible to start and result in a gateway error "The amount is lower than the minimum". The status of the first payment gets updated to Failed.

Schermafbeelding 2021-08-23 om 11 18 10

In the past, if the first payment failed, the subscription status was updated to Cancelled to prevent unintended reactivation of subscription (if a mandate would become available at a later time, for example if a new subscription had been started successfully by the same user). It seems this has been removed some time ago:

  • https://github.com/pronamic/wp-pay-core/commit/b26ec8237bb0df23c5ea3153c0e1ca382d2667d4

Therefore, recurring payments are still created for these failed subscriptions and the recurring payments result in the "No suitable mandates found for customer" error. For a failed first payment, the subscription should be canceled or put on hold to prevent further payments for the invalid subscription. The error about the required minimum amount should already be sufficient to prevent creating invalid subscriptions, as we can assume this error will be noticed by users during setup testing.

Thoughts, @remcotolsma?

rvdsteege avatar Aug 23 '21 10:08 rvdsteege

I think we should no longer create follow-up payments for subscriptions that have the subscr_failed status:

https://github.com/pronamic/wp-pay-core/blob/develop/src/Subscriptions/SubscriptionsModule.php#L1091-L1093

In the case of a failed direct debit payment, Mollie almost always advises you to contact the customer:

MS03 is used for other reasons. MS03 can sometimes be the result of reasons that already have another reason code, such as insufficient funds. We recommend you to contact the consumer when you see code MS03.

https://help.mollie.com/hc/en-us/articles/115000309865-Why-did-my-direct-debit-payment-fail-

It therefore does not seem desirable to me to initiate follow-up payments if something went wrong earlier.

A problem can also arise when starting the follow-up payment with the payment provider:

https://docs.mollie.com/overview/handling-errors

You do not want the follow-up payments to be stopped completely with for example the following errors:

Status Code Description
401 Unauthorized – Your request was not executed due to failed authentication. Check your API key.
429 Too Many Requests – Your request has hit a rate limit. Please wait for a bit and retry.
500 Internal Server Error – An internal server error occurred while processing your request. Our developers are notified automatically, but if you have any information on how you triggered the problem, please contact us.
502 Bad Gateway – The service is temporarily unavailable, either due to calamity or (planned) maintenance. Please retry the request at a later time.
503 Service Unavailable – The service is temporarily unavailable, either due to calamity or (planned) maintenance. Please retry the request at a later time.
504 Gateway Timeout – Your request is causing an unusually long process time.

The follow-up payments that could not be started could be put in a queue.

We could change https://github.com/wp-pay-gateways/mollie/blob/c17db2ffa9f9c14cf0b1ff6871c35f10bd1fa232/src/Gateway.php#L455-L456 to something like this:


try {
	$result = $this->client->create_payment( $request );
} catch { Exception $e ) {
	if ( ! $payment->is_interactive() ) {
		// Increase number attempts and add payment to retry queue.

		return;
	}

	throw $e;
}

Don't know if is_interactive is the right term, maybe is_recurring or needs_no_interaction.

But for now i think the easiest thing to do is take out subscr_failed. status and implement a retry queue later.

Asynchronous payment flows are complex to manage because they depend on customer interactions that happen outside of your application.

https://stripe.com/docs/payments/intents#intent-statuses

remcotolsma avatar Aug 27 '21 12:08 remcotolsma

I checked how Gravity Forms handles an empty amount (0) by default: https://github.com/wp-premium/gravityforms/blob/2.4.20/includes/addon/class-gf-payment-addon.php#L663-L700

By default a payment amount is valid when the amount is greater than zero. Currently we bypass this check and also start a payment for an empty amount (0). For a creditcard subscription payment via Mollie this is desired.

It is possible to initiate a payment via conditional logic only if the amount is greater than 0. However, for this you need to add a hidden number field with a calculation that can be used within the conditional logic.

Schermafbeelding 2021-08-27 om 15 54 18 Schermafbeelding 2021-08-27 om 15 53 40

We could advice users to setup their forms this way if they don't want to trigger the payment feed for payments of € 0.

But this change will likely result in some support tickets.

remcotolsma avatar Aug 27 '21 13:08 remcotolsma