diff --git a/src/Message/PaymentIntents/AuthorizeRequest.php b/src/Message/PaymentIntents/AuthorizeRequest.php index fe939d1e..d760f328 100644 --- a/src/Message/PaymentIntents/AuthorizeRequest.php +++ b/src/Message/PaymentIntents/AuthorizeRequest.php @@ -91,7 +91,9 @@ * * // 3DS 2.0 time! * if ($response->isRedirect()) { - * $response->redirect(); + * $response->redirect(); + * } else if ($response->isStripeSDKAction()) { + * $client_secret = $response->getClientSecret(); * } else if ($response->isSuccessful()) { * echo "Authorize transaction was successful!\n"; * $sale_id = $response->getTransactionReference(); @@ -348,8 +350,7 @@ public function getData() $data['confirm'] = $this->getConfirm() ? 'true' : 'false'; - if ($this->getConfirm()) { - $this->validate('returnUrl'); + if ($this->getConfirm() && $this->getReturnUrl()) { $data['return_url'] = $this->getReturnUrl(); } diff --git a/src/Message/PaymentIntents/Response.php b/src/Message/PaymentIntents/Response.php index 38d82a9c..7bbf481a 100644 --- a/src/Message/PaymentIntents/Response.php +++ b/src/Message/PaymentIntents/Response.php @@ -139,8 +139,6 @@ public function isCancelled() public function isRedirect() { if ($this->getStatus() === 'requires_action' || $this->getStatus() === 'requires_source_action') { - // Currently this gateway supports only manual confirmation, so any other - // next action types pretty much mean a failed transaction for us. return (!empty($this->data['next_action']) && $this->data['next_action']['type'] === 'redirect_to_url'); } @@ -155,6 +153,26 @@ public function getRedirectUrl() return $this->isRedirect() ? $this->data['next_action']['redirect_to_url']['url'] : parent::getRedirectUrl(); } + /** + * @return bool + */ + public function isStripeSDKAction() + { + if ($this->getStatus() === 'requires_action' || $this->getStatus() === 'requires_source_action') { + return (!empty($this->data['next_action']) && $this->data['next_action']['type'] === 'use_stripe_sdk'); + } + + return false; + } + + /** + * @return string|null + */ + public function getClientSecret() + { + return isset($this->data['client_secret']) ? $this->data['client_secret'] : null; + } + /** * Get the payment intent reference. * diff --git a/tests/Message/PaymentIntents/AuthorizeRequestTest.php b/tests/Message/PaymentIntents/AuthorizeRequestTest.php index 9e3b8858..e2b73597 100644 --- a/tests/Message/PaymentIntents/AuthorizeRequestTest.php +++ b/tests/Message/PaymentIntents/AuthorizeRequestTest.php @@ -110,17 +110,13 @@ public function testDataWithDestination() } /** - * Confirming a payment intent without a return url would destroy the flow for 3DS 2.0, - * so let's make sure that setting confirm to true and skipping return url is - * not permitted. - * - * @expectedException \Omnipay\Common\Exception\InvalidRequestException - * @expectedExceptionMessage The returnUrl parameter is required + * Return url is only supported when confirming a payment intent. + * When a return url is specified, the response will provide a redirect url that supports 3DS 2.0. */ - public function testReturnUrlMustBeSetWhenConfirming() + public function testReturnUrlWhenConfirming() { - $this->request->setReturnUrl(null); $data = $this->request->getData(); + $this->assertArrayHasKey('return_url', $data); } /** diff --git a/tests/Message/PaymentIntents/ResponseTest.php b/tests/Message/PaymentIntents/ResponseTest.php index ade868e0..349d431b 100644 --- a/tests/Message/PaymentIntents/ResponseTest.php +++ b/tests/Message/PaymentIntents/ResponseTest.php @@ -22,6 +22,14 @@ public function testRequiresConfirmation() $this->assertTrue($response->requiresConfirmation()); } + public function testClientSecret() + { + $httpResponse = $this->getMockHttpResponse('AuthorizeSuccess.txt'); + $response = new Response($this->getMockRequest(), (string) $httpResponse->getBody()); + + $this->assertEquals('pi_1Euf5UFSbr6xR4YAp9PPTxza_secret_QjDdAp77yVbiJoyJ92mXx76F7', $response->getClientSecret()); + } + public function testGetCardReference() { $httpResponse = $this->getMockHttpResponse('AuthorizeSuccess.txt');