From acc531f527dd679aa2d7d66c125b213467981f21 Mon Sep 17 00:00:00 2001 From: jessy <32092402+jessy-p@users.noreply.github.com> Date: Wed, 15 Nov 2023 17:49:35 +0530 Subject: [PATCH] Changes to Payment Process to store the working mode of the gateway (#7651) Co-authored-by: Jessy P --- changelog/add-7421-store-working-mode | 4 +++ .../PaymentsServiceProvider.php | 3 +- src/Internal/Payment/PaymentContext.php | 18 ++++++++++ src/Internal/Service/OrderService.php | 28 ++++++++++++++++ .../Service/PaymentProcessingService.php | 18 +++++++++- .../Internal/Payment/PaymentContextTest.php | 7 ++++ .../src/Internal/Service/OrderServiceTest.php | 24 +++++++++++++- .../Service/PaymentProcessingServiceTest.php | 33 ++++++++++++++++--- 8 files changed, 127 insertions(+), 8 deletions(-) create mode 100644 changelog/add-7421-store-working-mode diff --git a/changelog/add-7421-store-working-mode b/changelog/add-7421-store-working-mode new file mode 100644 index 00000000000..7f74cff000b --- /dev/null +++ b/changelog/add-7421-store-working-mode @@ -0,0 +1,4 @@ +Significance: minor +Type: add + +Store the working mode of the gateway (RPP) diff --git a/src/Internal/DependencyManagement/ServiceProvider/PaymentsServiceProvider.php b/src/Internal/DependencyManagement/ServiceProvider/PaymentsServiceProvider.php index 85d0bb1acbd..3443239f879 100644 --- a/src/Internal/DependencyManagement/ServiceProvider/PaymentsServiceProvider.php +++ b/src/Internal/DependencyManagement/ServiceProvider/PaymentsServiceProvider.php @@ -77,7 +77,8 @@ public function register(): void { $container->addShared( PaymentProcessingService::class ) ->addArgument( StateFactory::class ) ->addArgument( LegacyProxy::class ) - ->addArgument( PaymentContextLoggerService::class ); + ->addArgument( PaymentContextLoggerService::class ) + ->addArgument( Mode::class ); $container->addShared( PaymentRequestService::class ); diff --git a/src/Internal/Payment/PaymentContext.php b/src/Internal/Payment/PaymentContext.php index 27c12991953..63fcc90d115 100644 --- a/src/Internal/Payment/PaymentContext.php +++ b/src/Internal/Payment/PaymentContext.php @@ -300,6 +300,24 @@ public function get_transitions(): array { return $this->transitions; } + /** + * Sets the mode (test or prod). + * + * @param string $mode mode. + */ + public function set_mode( string $mode ) { + $this->set( 'mode', $mode ); + } + + /** + * Returns the mode (test or prod). + * + * @return string|null mode. + */ + public function get_mode(): ?string { + return $this->get( 'mode' ); + } + /** * Updates previous transition with the next state and creates new transition. * diff --git a/src/Internal/Service/OrderService.php b/src/Internal/Service/OrderService.php index c10ce3b63bd..24dcde9cc13 100644 --- a/src/Internal/Service/OrderService.php +++ b/src/Internal/Service/OrderService.php @@ -207,12 +207,39 @@ public function update_order_from_successful_intent( $this->legacy_service->attach_transaction_fee_to_order( $order, $charge ); $this->legacy_service->update_order_status_from_intent( $order, $intent ); + $this->set_mode( $order_id, $context->get_mode() ); if ( ! is_null( $charge ) ) { $this->attach_exchange_info_to_order( $order_id, $charge ); } } + /** + * Sets the '_wcpay_mode' meta data on an order. + * + * @param string $order_id The order id. + * @param string $mode Mode from the context. + * @throws Order_Not_Found_Exception + */ + public function set_mode( string $order_id, string $mode ) : void { + $order = $this->get_order( $order_id ); + $order->update_meta_data( '_wcpay_mode', $mode ); + $order->save_meta_data(); + } + + /** + * Gets the '_wcpay_mode' meta data on an order. + * + * @param string $order_id The order id. + * + * @return string The mode. + * @throws Order_Not_Found_Exception + */ + public function get_mode( string $order_id ) : string { + $order = $this->get_order( $order_id ); + return $order->get_meta( '_wcpay_mode', true ); + } + /** * Updates the order with the necessary details whenever an intent requires action. * @@ -421,4 +448,5 @@ protected function get_order( int $order_id ): WC_Order { } return $order; } + } diff --git a/src/Internal/Service/PaymentProcessingService.php b/src/Internal/Service/PaymentProcessingService.php index e2a93aeb23d..4fd974ffce6 100644 --- a/src/Internal/Service/PaymentProcessingService.php +++ b/src/Internal/Service/PaymentProcessingService.php @@ -7,10 +7,12 @@ namespace WCPay\Internal\Service; +use Exception; use WC_Payments_API_Abstract_Intention; use WC_Payments_API_Setup_Intention; use WCPay\Exceptions\Order_Not_Found_Exception; use WCPay\Vendor\League\Container\Exception\ContainerException; +use WCPay\Core\Mode; use WCPay\Internal\Payment\PaymentContext; use WCPay\Internal\Payment\State\InitialState; use WCPay\Internal\Payment\State\StateFactory; @@ -45,6 +47,12 @@ class PaymentProcessingService { */ private $context_logger_service; + /** + * Mode + * + * @var Mode + */ + private $mode; /** * Service constructor. @@ -52,15 +60,18 @@ class PaymentProcessingService { * @param StateFactory $state_factory Factory for payment states. * @param LegacyProxy $legacy_proxy Legacy proxy. * @param PaymentContextLoggerService $context_logger_service Context Logging Service. + * @param Mode $mode Mode. */ public function __construct( StateFactory $state_factory, LegacyProxy $legacy_proxy, - PaymentContextLoggerService $context_logger_service + PaymentContextLoggerService $context_logger_service, + Mode $mode ) { $this->state_factory = $state_factory; $this->legacy_proxy = $legacy_proxy; $this->context_logger_service = $context_logger_service; + $this->mode = $mode; } /** @@ -133,6 +144,11 @@ public function get_authentication_redirect_url( $intent, int $order_id ) { */ protected function create_payment_context( int $order_id, bool $automatic_capture = false ): PaymentContext { $context = new PaymentContext( $order_id ); + try { + $context->set_mode( $this->mode->is_test() ? 'test' : 'prod' ); + } catch ( Exception $e ) { + $context->set_mode( 'unknown' ); + } $context->toggle_automatic_capture( $automatic_capture ); return $context; diff --git a/tests/unit/src/Internal/Payment/PaymentContextTest.php b/tests/unit/src/Internal/Payment/PaymentContextTest.php index c34171136d2..3f70d0ae47e 100644 --- a/tests/unit/src/Internal/Payment/PaymentContextTest.php +++ b/tests/unit/src/Internal/Payment/PaymentContextTest.php @@ -140,6 +140,13 @@ public function test_intent() { $this->assertSame( $intent, $this->sut->get_intent() ); } + public function test_mode() { + $mode = 'prod'; + + $this->sut->set_mode( $mode ); + $this->assertSame( $mode, $this->sut->get_mode() ); + } + public function test_log_state_transition() { $this->sut->log_state_transition( 'First_State' ); // first transition has 'from_state' null and 'to_state' as 'First_State'. diff --git a/tests/unit/src/Internal/Service/OrderServiceTest.php b/tests/unit/src/Internal/Service/OrderServiceTest.php index 1aba6fa24d2..1132d8e3ce5 100644 --- a/tests/unit/src/Internal/Service/OrderServiceTest.php +++ b/tests/unit/src/Internal/Service/OrderServiceTest.php @@ -319,7 +319,7 @@ public function test_update_order_from_successful_intent( $intent ) { // Create a mock order that will be used. $mock_order = $this->createMock( WC_Order::class ); - $this->sut->expects( $this->once() ) + $this->sut->expects( $this->exactly( 2 ) ) ->method( 'get_order' ) ->with( $this->order_id ) ->willReturn( $mock_order ); @@ -355,6 +355,9 @@ public function test_update_order_from_successful_intent( $intent ) { $mock_context->expects( $this->once() ) ->method( 'get_currency' ) ->willReturn( $currency ); + $mock_context->expects( $this->once() ) + ->method( 'get_mode' ) + ->willReturn( 'prod' ); $this->mock_legacy_service->expects( $this->once() ) ->method( 'attach_intent_info_to_order' ) @@ -637,6 +640,24 @@ public function test_delete_order() { $this->assertSame( $expected, $result ); } + public function test_set_mode() { + $this->mock_get_order() + ->expects( $this->once() ) + ->method( 'update_meta_data' ) + ->with( '_wcpay_mode', 'prod' ); + $this->sut->set_mode( $this->order_id, 'prod' ); + } + + public function test_get_mode() { + $this->mock_get_order() + ->expects( $this->once() ) + ->method( 'get_meta' ) + ->with( '_wcpay_mode', true ) + ->willReturn( 'test' ); + $result = $this->sut->get_mode( $this->order_id, true ); + $this->assertSame( 'test', $result ); + } + /** * Mocks order retrieval. * @@ -654,4 +675,5 @@ private function mock_get_order( int $order_id = null ) { return $mock_order; } + } diff --git a/tests/unit/src/Internal/Service/PaymentProcessingServiceTest.php b/tests/unit/src/Internal/Service/PaymentProcessingServiceTest.php index feb7b538a16..b2512762a3e 100644 --- a/tests/unit/src/Internal/Service/PaymentProcessingServiceTest.php +++ b/tests/unit/src/Internal/Service/PaymentProcessingServiceTest.php @@ -7,6 +7,9 @@ namespace WCPay\Tests\Internal\Service; +use Exception; +use WCPAY_UnitTestCase; +use PHPUnit_Utils; use PHPUnit\Framework\MockObject\MockObject; use WC_Helper_Intention; use WC_Payment_Gateway_WCPay; @@ -17,7 +20,7 @@ use WCPay\Internal\Payment\PaymentRequest; use WCPay\Internal\Payment\State\CompletedState; use WCPay\Internal\Payment\State\InitialState; -use WCPAY_UnitTestCase; +use WCPay\Core\Mode; use WCPay\Internal\Proxy\LegacyProxy; use WCPay\Internal\Payment\State\StateFactory; use WCPay\Internal\Service\PaymentProcessingService; @@ -27,6 +30,7 @@ * Payment processing service unit tests. */ class PaymentProcessingServiceTest extends WCPAY_UnitTestCase { + /** * Service under test. * @@ -49,6 +53,11 @@ class PaymentProcessingServiceTest extends WCPAY_UnitTestCase { */ private $mock_context_logger; + /** + * @var Mode|MockObject + */ + private $mock_mode; + /** * Set up the test. */ @@ -58,6 +67,7 @@ protected function setUp(): void { $this->mock_state_factory = $this->createMock( StateFactory::class ); $this->mock_legacy_proxy = $this->createMock( LegacyProxy::class ); $this->mock_context_logger = $this->createMock( PaymentContextLoggerService::class ); + $this->mock_mode = $this->createMock( Mode::class ); $this->sut = $this->getMockBuilder( PaymentProcessingService::class ) ->setConstructorArgs( @@ -65,6 +75,7 @@ protected function setUp(): void { $this->mock_state_factory, $this->mock_legacy_proxy, $this->mock_context_logger, + $this->mock_mode, ] ) ->onlyMethods( [ 'create_payment_context' ] ) @@ -79,7 +90,7 @@ public function test_process_payment_happy_path() { $mock_initial_state = $this->createMock( InitialState::class ); $mock_completed_state = $this->createMock( CompletedState::class ); - $sut = new PaymentProcessingService( $this->mock_state_factory, $this->mock_legacy_proxy, $this->mock_context_logger ); + $sut = new PaymentProcessingService( $this->mock_state_factory, $this->mock_legacy_proxy, $this->mock_context_logger, $this->mock_mode ); $this->mock_state_factory->expects( $this->once() ) ->method( 'create_state' ) @@ -103,7 +114,7 @@ public function test_process_payment_happy_path() { * Test the basic happy path of processing a payment. */ public function test_process_payment_happy_path_without_mock_builder() { - $sut = new PaymentProcessingService( $this->mock_state_factory, $this->mock_legacy_proxy, $this->mock_context_logger ); + $sut = new PaymentProcessingService( $this->mock_state_factory, $this->mock_legacy_proxy, $this->mock_context_logger, $this->mock_mode ); $mock_initial_state = $this->createMock( InitialState::class ); $mock_completed_state = $this->createMock( CompletedState::class ); @@ -126,8 +137,21 @@ public function test_process_payment_happy_path_without_mock_builder() { $this->assertSame( $mock_completed_state, $result ); } + /** + * Test the process payment when mode not initialized. + */ + public function test_process_payment_mode_throws_exception() { + $this->mock_mode + ->expects( $this->once() ) + ->method( 'is_test' ) + ->willThrowException( new Exception( 'Could not initialize' ) ); + $sut = new PaymentProcessingService( $this->mock_state_factory, $this->mock_legacy_proxy, $this->mock_context_logger, $this->mock_mode ); + $context = PHPUnit_Utils::call_method( $sut, 'create_payment_context', [ 123 ] ); + $this->assertEquals( 'unknown', $context->get_mode() ); + } + public function test_get_authentication_redirect_url_will_return_url_from_payment_intent() { - $sut = new PaymentProcessingService( $this->mock_state_factory, $this->mock_legacy_proxy, $this->mock_context_logger ); + $sut = new PaymentProcessingService( $this->mock_state_factory, $this->mock_legacy_proxy, $this->mock_context_logger, $this->mock_mode ); $url = 'localhost'; $intent_data = [ @@ -149,7 +173,6 @@ public function test_get_authentication_redirect_url_will_return_url_from_paymen $result = $sut->get_authentication_redirect_url( $intent, 1 ); $this->assertSame( $url, $result ); - } /**