diff --git a/src/Message/RestAuthorizeRequest.php b/src/Message/RestAuthorizeRequest.php index 19762f9..321910e 100644 --- a/src/Message/RestAuthorizeRequest.php +++ b/src/Message/RestAuthorizeRequest.php @@ -5,6 +5,8 @@ namespace Omnipay\PayPal\Message; +use Omnipay\Common\Exception\InvalidCreditCardException; + /** * PayPal REST Authorize Request * @@ -259,9 +261,8 @@ public function getData() 'credit_card_id' => $this->getCardReference(), ), ); - } elseif ($this->getCard()) { + } elseif ($this->validCardPresent()) { $this->validate('amount', 'card'); - $this->getCard()->validate(); $data['payer']['funding_instruments'][] = array( 'credit_card' => array( @@ -304,6 +305,32 @@ public function getData() return $data; } + /** + * Has a valid card been passed in the Omnipay parameters. + * + * Omnipay supports details other than card details in the card parameter (e.g. + * billing address) so a generic omnipay integration might set the 'card' when + * there is no number present. In which case the Rest integration should fall + * back to the next method. + */ + public function validCardPresent() + { + $card = $this->getCard(); + if (!$card) { + return false; + } + try { + $card->validate(); + } catch (InvalidCreditCardException $e) { + if (stristr($e->getMessage(), 'is required')) { + return false; + } else { + throw $e; + } + } + return true; + } + /** * Get the experience profile id * diff --git a/tests/Message/RestAuthorizeRequestTest.php b/tests/Message/RestAuthorizeRequestTest.php index 5f0f962..ec04f85 100644 --- a/tests/Message/RestAuthorizeRequestTest.php +++ b/tests/Message/RestAuthorizeRequestTest.php @@ -47,6 +47,33 @@ public function testGetDataWithoutCard() $this->assertSame('https://www.example.com/cancel', $data['redirect_urls']['cancel_url']); } + /** + * This tests that having a card object with no card details acts as 'no card'. + * + * We may have a card object holding billing details but no card details. This + * should be treated as a card-not-present rather than as invalid. + */ + public function testGetDataWitLimitedCard() + { + $this->request->setTransactionId('abc123'); + $this->request->setDescription('Sheep'); + $this->request->setCard(new CreditCard(['firstName' => 'Example'])); + + $data = $this->request->getData(); + + $this->assertSame('authorize', $data['intent']); + $this->assertSame('paypal', $data['payer']['payment_method']); + $this->assertSame('10.00', $data['transactions'][0]['amount']['total']); + $this->assertSame('USD', $data['transactions'][0]['amount']['currency']); + $this->assertSame('abc123 : Sheep', $data['transactions'][0]['description']); + + // Funding instruments must not be set, otherwise paypal API will give error 500. + $this->assertArrayNotHasKey('funding_instruments', $data['payer']); + + $this->assertSame('https://www.example.com/return', $data['redirect_urls']['return_url']); + $this->assertSame('https://www.example.com/cancel', $data['redirect_urls']['cancel_url']); + } + public function testGetDataWithCard() { $card = new CreditCard($this->getValidCard()); diff --git a/tests/Mock/RestGenericSubscriptionSuccess.txt b/tests/Mock/RestGenericSubscriptionSuccess.txt index e099ab1..922bb53 100644 --- a/tests/Mock/RestGenericSubscriptionSuccess.txt +++ b/tests/Mock/RestGenericSubscriptionSuccess.txt @@ -5,3 +5,4 @@ Paypal-Debug-Id: 217a9ddefd384 SERVER_INFO: identitysecuretokenserv:v1.oauth2.token&CalThreadId=91&TopLevelTxnStartTime=146fbfe679a&Host=slcsbidensectoken502.slc.paypal.com&pid=29059 CORRELATION-ID: 217a9ddefd384 Date: Thu, 03 Jul 2014 11:31:32 GMT +