Skip to content

Commit 8b3acaf

Browse files
haszariRua Haszard
andauthored
add logging when subscription is suspended (#5430)
* add logging when subscription is suspended: - because merchant or subscriber (or ?) changed status to on-hold - because next payment date is 0 * add order (subscription) notes when sub is suspended + + use consistent past tense for logging and notes * log and add order notes after suspending subscription * add some extra checks that subscription is wcpay / non tokenised, log if incorrect * use local wcpay sub id in log message + tidy log message (semicolon between values) * changelong * fix php unit tests: - missing require Logger (doh!) - update test_suspend_subscription mock subscription so it passes the new `is_wcpay_subscription` check * fix / improve docblock comments: - suspend executes a suspend on a given subscription - handle_status handles a specific status transition * fix temporary unhooking of on-hold status change handler: - this PR decouples the handler from what it does, as suspend_subscription is used outside this context, and so we can log the status change explicitly - this commit fixes the places we temporarily unhook the action to refer to new handler * log a stack trace with suspend due to on-hold status * clarify invoice.upcoming suspend note / log Co-authored-by: Rua Haszard <[email protected]>
1 parent 7b8b643 commit 8b3acaf

File tree

4 files changed

+67
-7
lines changed

4 files changed

+67
-7
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Significance: minor
2+
Type: add
3+
4+
Add logging and order notes when WCPay Subscriptions are suspended or put on-hold.

includes/subscriptions/class-wc-payments-subscription-service.php

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ public function __construct(
133133

134134
add_action( 'woocommerce_subscription_status_cancelled', [ $this, 'cancel_subscription' ] );
135135
add_action( 'woocommerce_subscription_status_expired', [ $this, 'cancel_subscription' ] );
136-
add_action( 'woocommerce_subscription_status_on-hold', [ $this, 'suspend_subscription' ] );
136+
add_action( 'woocommerce_subscription_status_on-hold', [ $this, 'handle_subscription_status_on_hold' ] );
137137
add_action( 'woocommerce_subscription_status_pending-cancel', [ $this, 'set_pending_cancel_for_subscription' ] );
138138
add_action( 'woocommerce_subscription_status_pending-cancel_to_active', [ $this, 'reactivate_subscription' ] );
139139
add_action( 'woocommerce_subscription_status_on-hold_to_active', [ $this, 'reactivate_subscription' ] );
@@ -452,13 +452,59 @@ public function cancel_subscription( WC_Subscription $subscription ) {
452452
}
453453

454454
/**
455-
* Suspends the WCPay subscription when a WC subscription is put on-hold.
455+
* Handle subscription status change to on-hold.
456456
*
457-
* @param WC_Subscription $subscription The WC subscription that was suspended.
457+
* @param WC_Subscription $subscription The WC subscription.
458+
*
459+
* @return void
460+
*/
461+
public function handle_subscription_status_on_hold( WC_Subscription $subscription ) {
462+
// Check if the subscription is a WCPay subscription before proceeding.
463+
// In stores that have WC Subscriptions active, or previously had WC S,
464+
// this method may be called with regular tokenised subscriptions.
465+
if ( ! $this->is_wcpay_subscription( $subscription ) ) {
466+
return;
467+
}
468+
469+
$this->suspend_subscription( $subscription );
470+
471+
// Add an order note as a visible record of suspend.
472+
$subscription->add_order_note( __( 'Suspended WCPay Subscription because subscription status changed to on-hold.', 'woocommerce-payments' ) );
473+
474+
// Log that the subscription was suspended.
475+
// Include a brief stack trace to help determine where status change originated.
476+
// For example, admin user action, or a code interaction with customizations.
477+
$e = new Exception();
478+
$trace = $e->getTraceAsString();
479+
Logger::log(
480+
sprintf(
481+
'Suspended WCPay Subscription because subscription status changed to on-hold. WC ID: %d; WCPay ID: %s; stack: %s',
482+
$subscription->get_id(),
483+
self::get_wcpay_subscription_id( $subscription ),
484+
$trace
485+
)
486+
);
487+
}
488+
489+
/**
490+
* Suspends a WCPay subscription.
491+
*
492+
* @param WC_Subscription $subscription The WC subscription to suspend.
458493
*
459494
* @return void
460495
*/
461496
public function suspend_subscription( WC_Subscription $subscription ) {
497+
// Check if the subscription is a WCPay subscription before proceeding.
498+
if ( ! $this->is_wcpay_subscription( $subscription ) ) {
499+
Logger::log(
500+
sprintf(
501+
'Aborting WC_Payments_Subscription_Service::suspend_subscription; subscription is a tokenised (non WCPay) subscription. WC ID: %d.',
502+
$subscription->get_id()
503+
)
504+
);
505+
return;
506+
}
507+
462508
$this->update_subscription( $subscription, [ 'pause_collection' => [ 'behavior' => 'void' ] ] );
463509
}
464510

includes/subscriptions/class-wc-payments-subscriptions-event-handler.php

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* @package WooCommerce\Payments
66
*/
77

8+
use WCPay\Logger;
89
use WCPay\Exceptions\Invalid_Webhook_Data_Exception;
910

1011
/**
@@ -72,6 +73,14 @@ public function handle_invoice_upcoming( array $body ) {
7273
$this->subscription_service->cancel_subscription( $subscription );
7374
} else {
7475
$this->subscription_service->suspend_subscription( $subscription );
76+
$subscription->add_order_note( __( 'Suspended WCPay Subscription in invoice.upcoming webhook handler because subscription next_payment date is 0.', 'woocommerce-payments' ) );
77+
Logger::log(
78+
sprintf(
79+
'Suspended WCPay Subscription in invoice.upcoming webhook handler because subscription next_payment date is 0. WC ID: %d; WCPay ID: %s.',
80+
$subscription->get_id(),
81+
$wcpay_subscription_id
82+
)
83+
);
7584
}
7685
} else {
7786
// Translators: %s Scheduled/upcoming payment date in Y-m-d H:i:s format.
@@ -124,9 +133,9 @@ public function handle_invoice_paid( array $body ) {
124133
* This ensures the downstream effects take place, e.g. a payment status order note is added and the
125134
* 'woocommerce_subscription_payment_complete' action is fired.
126135
*/
127-
remove_action( 'woocommerce_subscription_status_on-hold', [ $this->subscription_service, 'suspend_subscription' ] );
136+
remove_action( 'woocommerce_subscription_status_on-hold', [ $this->subscription_service, 'handle_subscription_status_on_hold' ] );
128137
$subscription->update_status( 'on-hold' );
129-
add_action( 'woocommerce_subscription_status_on-hold', [ $this->subscription_service, 'suspend_subscription' ] );
138+
add_action( 'woocommerce_subscription_status_on-hold', [ $this->subscription_service, 'handle_subscription_status_on_hold' ] );
130139

131140
/*
132141
* Remove the reactivate_subscription callback that occurs when a subscription transitions from on-hold to active.
@@ -190,9 +199,9 @@ public function handle_invoice_payment_failed( array $body ) {
190199
$subscription->add_order_note( sprintf( _n( 'WCPay subscription renewal attempt %d failed.', 'WCPay subscription renewal attempt %d failed.', $attempts, 'woocommerce-payments' ), $attempts ) );
191200

192201
if ( self::MAX_RETRIES > $attempts ) {
193-
remove_action( 'woocommerce_subscription_status_on-hold', [ $this->subscription_service, 'suspend_subscription' ] );
202+
remove_action( 'woocommerce_subscription_status_on-hold', [ $this->subscription_service, 'handle_subscription_status_on_hold' ] );
194203
$subscription->payment_failed();
195-
add_action( 'woocommerce_subscription_status_on-hold', [ $this->subscription_service, 'suspend_subscription' ] );
204+
add_action( 'woocommerce_subscription_status_on-hold', [ $this->subscription_service, 'handle_subscription_status_on_hold' ] );
196205
} else {
197206
$subscription->payment_failed( 'cancelled' );
198207
}

tests/unit/subscriptions/test-class-wc-payments-subscription-service.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,7 @@ public function test_suspend_subscription() {
340340
$input_data = [ 'pause_collection' => [ 'behavior' => 'void' ] ];
341341

342342
$mock_subscription->update_meta_data( self::SUBSCRIPTION_ID_META_KEY, $mock_wcpay_subscription_id );
343+
$mock_subscription->payment_method = 'woocommerce_payments';
343344

344345
$this->mock_api_client->expects( $this->once() )
345346
->method( 'update_subscription' )

0 commit comments

Comments
 (0)