Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: update

Prevent creation of the renewal orders if original order was created in the different WooPayments mode.
1 change: 1 addition & 0 deletions includes/class-wc-payments.php
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,7 @@ public static function init() {
include_once __DIR__ . '/exceptions/class-order-id-mismatch-exception.php';
include_once __DIR__ . '/exceptions/class-rate-limiter-enabled-exception.php';
include_once __DIR__ . '/exceptions/class-invalid-address-exception.php';
include_once __DIR__ . '/exceptions/class-subscription-mode-mismatch-exception.php';
include_once __DIR__ . '/constants/class-base-constant.php';
include_once __DIR__ . '/constants/class-country-code.php';
include_once __DIR__ . '/constants/class-country-test-cards.php';
Expand Down
29 changes: 29 additions & 0 deletions includes/exceptions/class-subscription-mode-mismatch-exception.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php
/**
* Class Subscription_Mode_Mismatch_Exception
*
* @package WooCommerce\Payments
*/

namespace WCPay\Exceptions;

use WCPay\Exceptions\Base_Exception;

defined( 'ABSPATH' ) || exit;

/**
* Subscription_Mode_Mismatch_Exception class.
*/
class Subscription_Mode_Mismatch_Exception extends Base_Exception {

/**
* Subscription_Mode_Mismatch_Exception constructor.
*
* @param string $message The exception message.
* @param int $code The exception code.
* @param \Throwable|null $previous The previous exception.
*/
public function __construct( $message = 'The subscription mode does not match the current WooPayments mode.', $code = 0, $previous = null ) {
parent::__construct( $message, 'subscription_mode_mismatch', $code, $previous );
}
}
34 changes: 34 additions & 0 deletions includes/subscriptions/class-wc-payments-subscription-service.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
* @package WooCommerce\Payments
*/

use WCPay\Constants\Order_Mode;
use WCPay\Exceptions\API_Exception;
use WCPay\Exceptions\Amount_Too_Small_Exception;
use WCPay\Exceptions\Cannot_Combine_Currencies_Exception;
use WCPay\Exceptions\Subscription_Mode_Mismatch_Exception;
use WCPay\Logger;

/**
Expand Down Expand Up @@ -162,6 +164,8 @@ public function __construct(
add_action( 'woocommerce_admin_order_data_after_billing_address', [ $this, 'show_wcpay_subscription_id' ] );

add_action( 'woocommerce_subscription_payment_method_updated_from_' . WC_Payment_Gateway_WCPay::GATEWAY_ID, [ $this, 'maybe_cancel_subscription' ], 10, 2 );

add_action( 'wcs_renewal_order_items', [ $this, 'check_wcpay_mode_for_subscription' ], 10, 3 );
}
}

Expand Down Expand Up @@ -874,6 +878,36 @@ public function maybe_cancel_subscription( $subscription, $new_payment_method )
}
}

/**
* Checks if the original subscription mode matches current WooPayments mode.
*
* If the original subscription was payed with WooPayments, but in the mode, that doesn't
* match the current WooPayments mode, we need to throw an exception, to prevent the renewal
* order from being created, as it would fail to be paid.
*
* @param array $items The items to be added to the renewal order.
* @param WC_Order $order Renewal order.
* @param WC_Subscription $subscription The original subscription.
* @throws Subscription_Mode_Mismatch_Exception
* @return array
*/
public function check_wcpay_mode_for_subscription( array $items, WC_Order $order, WC_Subscription $subscription ): array {
$parent_order = $subscription->get_parent();
if ( false !== $parent_order ) {
$subscription_mode = $parent_order->get_meta( WC_Payments_Order_Service::WCPAY_MODE_META_KEY );
$current_mode = WC_Payments::mode()->is_test() ? Order_Mode::TEST : Order_Mode::PRODUCTION;

if ( is_string( $subscription_mode ) && '' !== $subscription_mode && $subscription_mode !== $current_mode ) {
if ( Order_Mode::TEST === $subscription_mode ) {
throw new Subscription_Mode_Mismatch_Exception( __( 'Subscription was made when WooPayments was in the test mode and cannot be renewed in the live mode.', 'woocommerce-payments' ) );
} else {
throw new Subscription_Mode_Mismatch_Exception( __( 'Subscription was made when WooPayments was in the live mode and cannot be renewed in the test mode.', 'woocommerce-payments' ) );
}
}
}
return $items;
}

/**
* Gets one time item data from a subscription needed to create a WCPay subscription.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
*/

use PHPUnit\Framework\MockObject\MockObject;
use WCPay\Constants\Order_Mode;
use WCPay\Core\Mode;
use WCPay\Exceptions\Subscription_Mode_Mismatch_Exception;

/**
* WC_Payments_Subscription_Service_Test unit tests.
Expand Down Expand Up @@ -773,4 +776,35 @@ public function test_format_item_price_data() {

$this->assertEquals( $expected, $actual );
}

/**
* Test WC_Payments_Subscription_Service->check_wcpay_mode_for_subscription()
*/
public function test_check_wcpay_mode_for_subscription() {
$mock_order = WC_Helper_Order::create_order();
$mock_subscription = new WC_Subscription();
$mock_subscription->set_parent( $mock_order );
$mock_order->update_meta_data( WC_Payments_Order_Service::WCPAY_MODE_META_KEY, Order_Mode::TEST );

WC_Payments::mode()->test();

$items = [ 'item1', 'item2' ];
$result = $this->subscription_service->check_wcpay_mode_for_subscription( $items, $mock_order, $mock_subscription );
$this->assertEquals( $items, $result );

WC_Payments::mode()->live();

$this->expectException( Subscription_Mode_Mismatch_Exception::class );
$this->expectExceptionMessage( 'Subscription was made when WooPayments was in the test mode and cannot be renewed in the live mode.' );
$this->subscription_service->check_wcpay_mode_for_subscription( $items, $mock_order, $mock_subscription );

$mock_order->update_meta_data( WC_Payments_Order_Service::WCPAY_MODE_META_KEY, Order_Mode::PRODUCTION );
$result = $this->subscription_service->check_wcpay_mode_for_subscription( $items, $mock_order, $mock_subscription );
$this->assertEquals( $items, $result );

WC_Payments::mode()->test();
$this->expectException( Subscription_Mode_Mismatch_Exception::class );
$this->expectExceptionMessage( 'Subscription was made when WooPayments was in the live mode and cannot be renewed in the test mode.' );
$this->subscription_service->check_wcpay_mode_for_subscription( $items, $mock_order, $mock_subscription );
}
}
Loading