diff --git a/changelog/fix-7149-fix-cancel-authorization-flaky-error-response b/changelog/fix-7149-fix-cancel-authorization-flaky-error-response new file mode 100644 index 00000000000..27cbbbbeea7 --- /dev/null +++ b/changelog/fix-7149-fix-cancel-authorization-flaky-error-response @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Corrected an issue causing incorrect responses at the cancel authorization API endpoint. diff --git a/includes/admin/class-wc-rest-payments-orders-controller.php b/includes/admin/class-wc-rest-payments-orders-controller.php index 782c5358762..b5915678ca7 100644 --- a/includes/admin/class-wc-rest-payments-orders-controller.php +++ b/includes/admin/class-wc-rest-payments-orders-controller.php @@ -499,7 +499,7 @@ public function cancel_authorization( WP_REST_Request $request ) { $result = $this->gateway->cancel_authorization( $order ); - if ( Intent_Status::SUCCEEDED !== $result['status'] ) { + if ( Intent_Status::CANCELED !== $result['status'] ) { return new WP_Error( 'wcpay_cancel_error', sprintf( diff --git a/tests/unit/admin/test-class-wc-rest-payments-orders-controller.php b/tests/unit/admin/test-class-wc-rest-payments-orders-controller.php index 680bc81a809..e5f50a01baa 100644 --- a/tests/unit/admin/test-class-wc-rest-payments-orders-controller.php +++ b/tests/unit/admin/test-class-wc-rest-payments-orders-controller.php @@ -1357,6 +1357,207 @@ public function test_create_terminal_intent_invalid_capture_method() { $this->assertSame( 500, $data['status'] ); } + public function test_cancel_authorization_success() { + $order = $this->create_mock_order(); + $request = new WP_REST_Request( 'POST' ); + $request->set_url_params( + [ + 'order_id' => $order->get_id(), + ] + ); + $request->set_body_params( + [ + 'payment_intent_id' => $this->mock_intent_id, + ] + ); + + $this->mock_gateway + ->expects( $this->once() ) + ->method( 'cancel_authorization' ) + ->with( $this->isInstanceOf( WC_Order::class ) ) + ->willReturn( + [ + 'status' => Intent_Status::CANCELED, + 'id' => $this->mock_intent_id, + ] + ); + + $mock_intent = WC_Helper_Intention::create_intention( + [ + 'id' => $this->mock_intent_id, + 'status' => Intent_Status::REQUIRES_CAPTURE, + 'metadata' => [ + 'order_id' => $order->get_id(), + ], + ] + ); + $wcpay_request = $this->mock_wcpay_request( Get_Intention::class, 1, $this->mock_intent_id ); + + $wcpay_request->expects( $this->once() ) + ->method( 'format_response' ) + ->willReturn( $mock_intent ); + $response = $this->controller->cancel_authorization( $request ); + + $response_data = $response->get_data(); + + $this->assertEquals( 200, $response->status ); + $this->assertEquals( + [ + 'status' => Intent_Status::CANCELED, + 'id' => $this->mock_intent_id, + ], + $response_data + ); + } + public function test_cancel_authorization_will_fail_if_order_is_incorrect() { + $order = $this->create_mock_order(); + $request = new WP_REST_Request( 'POST' ); + $request->set_url_params( + [ + 'order_id' => $order->get_id() + 1, + ] + ); + $request->set_body_params( + [ + 'payment_intent_id' => $this->mock_intent_id, + ] + ); + + $this->mock_gateway + ->expects( $this->never() ) + ->method( 'cancel_authorization' ); + + $this->mock_wcpay_request( Get_Intention::class, 0 ); + + $response = $this->controller->cancel_authorization( $request ); + + $this->assertInstanceOf( 'WP_Error', $response ); + $data = $response->get_error_data(); + $this->assertArrayHasKey( 'status', $data ); + $this->assertSame( 404, $data['status'] ); + } + public function test_cancel_authorization_will_fail_if_order_is_refunded() { + $order = $this->create_mock_order(); + wc_create_refund( + [ + 'order_id' => $order->get_id(), + 'amount' => 10.0, + 'line_items' => [], + ] + ); + $request = new WP_REST_Request( 'POST' ); + $request->set_url_params( + [ + 'order_id' => $order->get_id(), + ] + ); + $request->set_body_params( + [ + 'payment_intent_id' => $this->mock_intent_id, + ] + ); + + $this->mock_gateway + ->expects( $this->never() ) + ->method( 'cancel_authorization' ); + + $this->mock_wcpay_request( Get_Intention::class, 0 ); + + $response = $this->controller->cancel_authorization( $request ); + + $this->assertInstanceOf( 'WP_Error', $response ); + $data = $response->get_error_data(); + $this->assertArrayHasKey( 'status', $data ); + $this->assertSame( 400, $data['status'] ); + } + public function test_cancel_authorization_will_fail_if_order_does_not_match_with_payment_intent() { + $order = $this->create_mock_order(); + $request = new WP_REST_Request( 'POST' ); + $request->set_url_params( + [ + 'order_id' => $order->get_id(), + ] + ); + $request->set_body_params( + [ + 'payment_intent_id' => $this->mock_intent_id, + ] + ); + + $mock_intent = WC_Helper_Intention::create_intention( + [ + 'id' => $this->mock_intent_id, + 'status' => Intent_Status::REQUIRES_CAPTURE, + 'metadata' => [ + 'order_id' => $order->get_id() + 1, + ], + ] + ); + $wcpay_request = $this->mock_wcpay_request( Get_Intention::class, 1, $this->mock_intent_id ); + + $wcpay_request->expects( $this->once() ) + ->method( 'format_response' ) + ->willReturn( $mock_intent ); + + $this->mock_gateway + ->expects( $this->never() ) + ->method( 'cancel_authorization' ); + + $response = $this->controller->cancel_authorization( $request ); + + $this->assertInstanceOf( 'WP_Error', $response ); + $data = $response->get_error_data(); + $this->assertArrayHasKey( 'status', $data ); + $this->assertSame( 409, $data['status'] ); + } + + public function test_cancel_authorization_will_fail_if_gateway_fails_to_cancel_authorization() { + $order = $this->create_mock_order(); + $request = new WP_REST_Request( 'POST' ); + $request->set_url_params( + [ + 'order_id' => $order->get_id(), + ] + ); + $request->set_body_params( + [ + 'payment_intent_id' => $this->mock_intent_id, + ] + ); + + $mock_intent = WC_Helper_Intention::create_intention( + [ + 'id' => $this->mock_intent_id, + 'status' => Intent_Status::REQUIRES_CAPTURE, + 'metadata' => [ + 'order_id' => $order->get_id(), + ], + ] + ); + $wcpay_request = $this->mock_wcpay_request( Get_Intention::class, 1, $this->mock_intent_id ); + + $wcpay_request->expects( $this->once() ) + ->method( 'format_response' ) + ->willReturn( $mock_intent ); + + $this->mock_gateway + ->method( 'cancel_authorization' ) + ->with( $this->isInstanceOf( WC_Order::class ) ) + ->willReturn( + [ + 'status' => Intent_Status::REQUIRES_CAPTURE, + 'id' => $this->mock_intent_id, + ] + ); + + $response = $this->controller->cancel_authorization( $request ); + + $this->assertInstanceOf( 'WP_Error', $response ); + $data = $response->get_error_data(); + $this->assertArrayHasKey( 'status', $data ); + $this->assertSame( 502, $data['status'] ); + } + private function create_mock_order() { $charge = $this->create_charge_object();