@@ -29,6 +29,10 @@ public function __construct() {
2929 // Allow store managers to manually set GoCardless as the payment method on a subscription.
3030 add_filter ( 'woocommerce_subscription_payment_meta ' , array ( $ this , 'add_subscription_payment_meta ' ), 10 , 2 );
3131 add_action ( 'woocommerce_subscription_validate_payment_meta ' , array ( $ this , 'validate_subscription_payment_meta ' ), 10 , 2 );
32+
33+ // Cancel in-progress payment on subscription cancellation.
34+ add_action ( 'woocommerce_subscription_pending-cancel_ ' . $ this ->id , array ( $ this , 'maybe_cancel_subscription_payment ' ) );
35+ add_action ( 'woocommerce_subscription_cancelled_ ' . $ this ->id , array ( $ this , 'maybe_cancel_subscription_payment ' ) );
3236 }
3337
3438 if ( class_exists ( 'WC_Pre_Orders_Order ' ) ) {
@@ -323,4 +327,63 @@ public function validate_subscription_payment_meta( $payment_method_id, $payment
323327 }
324328 }
325329 }
330+
331+ /**
332+ * Cancel the order payment on subscription cancellation.
333+ *
334+ * If the payment is pending submission, we can cancel it.
335+ * Otherwise, update the retry_if_possible to false to avoid the payment being retried (except for paid_out and cancelled payment states).
336+ *
337+ * @since 2.9.7
338+ *
339+ * @param WC_Subscription $subscription Subscription object.
340+ */
341+ public function maybe_cancel_subscription_payment ( $ subscription ) {
342+ if ( ! $ subscription ) {
343+ return ;
344+ }
345+ wc_gocardless ()->log ( sprintf ( '%s - Subscription cancelled/Pending cancellation, checking if payment should be cancelled ' , __METHOD__ ) );
346+
347+ $ last_order = $ subscription ->get_last_order ( 'all ' );
348+ if ( ! $ last_order ) {
349+ return ;
350+ }
351+
352+ $ payment_id = $ this ->get_order_resource ( $ last_order ->get_id (), 'payment ' , 'id ' );
353+ $ payment = WC_GoCardless_API::get_payment ( $ payment_id );
354+ if ( is_wp_error ( $ payment ) || empty ( $ payment ['payments ' ] ) ) {
355+ wc_gocardless ()->log ( sprintf ( '%s - Failed to retrieve payment. ' , __METHOD__ ) );
356+ return ;
357+ }
358+
359+ $ gocardless_status = $ payment ['payments ' ]['status ' ] ?? '' ;
360+ wc_gocardless ()->log ( sprintf ( '%s - GoCardless payment status: %s ' , __METHOD__ , $ gocardless_status ) );
361+
362+ // If the payment is pending submission, we can cancel it.
363+ if ( 'pending_submission ' === $ gocardless_status ) {
364+ $ response = WC_GoCardless_API::cancel_payment ( $ payment_id );
365+ if ( ! is_wp_error ( $ response ) ) {
366+ wc_gocardless ()->log ( sprintf ( '%s - Payment cancelled ' , __METHOD__ ) );
367+ } else {
368+ wc_gocardless ()->log ( sprintf ( '%s - Failed to cancel payment: %s ' , __METHOD__ , $ response ->get_error_message () ) );
369+ }
370+ } elseif (
371+ ! in_array (
372+ $ gocardless_status ,
373+ array (
374+ 'paid_out ' ,
375+ 'cancelled ' ,
376+ ),
377+ true
378+ )
379+ ) {
380+ // We can't cancel the payment, so we update it to not retry if possible to avoid the payment being retried.
381+ $ response = WC_GoCardless_API::update_payment ( $ payment_id , array ( 'retry_if_possible ' => false ) );
382+ if ( ! is_wp_error ( $ response ) ) {
383+ wc_gocardless ()->log ( sprintf ( '%s - Payment updated with retry_if_possible set to false ' , __METHOD__ ) );
384+ } else {
385+ wc_gocardless ()->log ( sprintf ( '%s - Failed to update payment: %s ' , __METHOD__ , $ response ->get_error_message () ) );
386+ }
387+ }
388+ }
326389}
0 commit comments