├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── composer.json ├── phpunit.xml.dist ├── src ├── Gateway.php └── Message │ ├── AbstractRequest.php │ ├── AuthorizeRequest.php │ ├── AuthorizeResponse.php │ ├── CaptureRequest.php │ ├── CaptureResponse.php │ ├── CompleteAuthorizeRequest.php │ ├── CompleteAuthorizeResponse.php │ ├── CompletePurchaseRequest.php │ ├── CompletePurchaseResponse.php │ ├── PurchaseRequest.php │ └── PurchaseResponse.php └── tests ├── GatewayTest.php ├── Message └── CompletePurchaseResponseTest.php └── Mock ├── CapturePaymentFailure.txt ├── CapturePaymentSuccess.txt ├── CompletePurchaseFailure.txt └── CompletePurchaseSuccess.txt /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | composer.lock 3 | composer.phar 4 | phpunit.xml 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.3 5 | - 5.4 6 | - 5.5 7 | - 5.6 8 | - hhvm 9 | 10 | before_script: 11 | - composer install -n --dev --prefer-source 12 | 13 | script: vendor/bin/phpcs --standard=PSR2 src && vendor/bin/phpunit --coverage-text 14 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | * Fork the project. 4 | * Make your feature addition or bug fix. 5 | * Add tests for it. This is important so I don't break it in a future version unintentionally. 6 | * Commit just the modifications, do not mess with the composer.json or CHANGELOG.md files. 7 | * Ensure your code is nicely formatted in the [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) 8 | style and that all tests pass. 9 | * Send the pull request. 10 | * Check that the Travis CI build passed. If not, rinse and repeat. 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012-2013 Adrian Macneil 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Omnipay: GoCardless 2 | 3 | **GoCardless driver for the Omnipay PHP payment processing library** 4 | 5 | [![Build Status](https://travis-ci.org/thephpleague/omnipay-gocardless.png?branch=master)](https://travis-ci.org/thephpleague/omnipay-gocardless) 6 | [![Latest Stable Version](https://poser.pugx.org/omnipay/gocardless/version.png)](https://packagist.org/packages/omnipay/gocardless) 7 | [![Total Downloads](https://poser.pugx.org/omnipay/gocardless/d/total.png)](https://packagist.org/packages/omnipay/gocardless) 8 | 9 | [Omnipay](https://github.com/thephpleague/omnipay) is a framework agnostic, multi-gateway payment 10 | processing library for PHP 5.3+. This package implements GoCardless support for Omnipay. 11 | 12 | ## Installation 13 | 14 | Omnipay is installed via [Composer](http://getcomposer.org/). To install, simply add it 15 | to your `composer.json` file: 16 | 17 | ```json 18 | { 19 | "require": { 20 | "omnipay/gocardless": "~2.0" 21 | } 22 | } 23 | ``` 24 | 25 | And run composer to update your dependencies: 26 | 27 | $ curl -s http://getcomposer.org/installer | php 28 | $ php composer.phar update 29 | 30 | ## Basic Usage 31 | 32 | The following gateways are provided by this package: 33 | 34 | * GoCardless 35 | 36 | For general usage instructions, please see the main [Omnipay](https://github.com/thephpleague/omnipay) 37 | repository. 38 | 39 | ## Support 40 | 41 | If you are having general issues with Omnipay, we suggest posting on 42 | [Stack Overflow](http://stackoverflow.com/). Be sure to add the 43 | [omnipay tag](http://stackoverflow.com/questions/tagged/omnipay) so it can be easily found. 44 | 45 | If you want to keep up to date with release anouncements, discuss ideas for the project, 46 | or ask more detailed questions, there is also a [mailing list](https://groups.google.com/forum/#!forum/omnipay) which 47 | you can subscribe to. 48 | 49 | If you believe you have found a bug, please report it using the [GitHub issue tracker](https://github.com/thephpleague/omnipay-gocardless/issues), 50 | or better yet, fork the library and submit a pull request. 51 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "omnipay/gocardless", 3 | "type": "library", 4 | "description": "GoCardless driver for the Omnipay payment processing library", 5 | "keywords": [ 6 | "gateway", 7 | "go cardless", 8 | "gocardless", 9 | "merchant", 10 | "omnipay", 11 | "pay", 12 | "payment" 13 | ], 14 | "homepage": "https://github.com/thephpleague/omnipay-gocardless", 15 | "license": "MIT", 16 | "authors": [ 17 | { 18 | "name": "Adrian Macneil", 19 | "email": "adrian@adrianmacneil.com" 20 | }, 21 | { 22 | "name": "Omnipay Contributors", 23 | "homepage": "https://github.com/thephpleague/omnipay-gocardless/contributors" 24 | } 25 | ], 26 | "autoload": { 27 | "psr-4": { "Omnipay\\GoCardless\\" : "src/" } 28 | }, 29 | "require": { 30 | "omnipay/common": "~2.0" 31 | }, 32 | "require-dev": { 33 | "omnipay/tests": "~2.0" 34 | }, 35 | "extra": { 36 | "branch-alias": { 37 | "dev-master": "2.0.x-dev" 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | ./tests/ 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ./src 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Gateway.php: -------------------------------------------------------------------------------- 1 | '', 25 | 'appSecret' => '', 26 | 'merchantId' => '', 27 | 'accessToken' => '', 28 | 'testMode' => false, 29 | ); 30 | } 31 | 32 | public function getAppId() 33 | { 34 | return $this->getParameter('appId'); 35 | } 36 | 37 | public function setAppId($value) 38 | { 39 | return $this->setParameter('appId', $value); 40 | } 41 | 42 | public function getAppSecret() 43 | { 44 | return $this->getParameter('appSecret'); 45 | } 46 | 47 | public function setAppSecret($value) 48 | { 49 | return $this->setParameter('appSecret', $value); 50 | } 51 | 52 | public function getMerchantId() 53 | { 54 | return $this->getParameter('merchantId'); 55 | } 56 | 57 | public function setMerchantId($value) 58 | { 59 | return $this->setParameter('merchantId', $value); 60 | } 61 | 62 | public function getAccessToken() 63 | { 64 | return $this->getParameter('accessToken'); 65 | } 66 | 67 | public function setAccessToken($value) 68 | { 69 | return $this->setParameter('accessToken', $value); 70 | } 71 | 72 | public function purchase(array $parameters = array()) 73 | { 74 | return $this->createRequest('\Omnipay\GoCardless\Message\PurchaseRequest', $parameters); 75 | } 76 | 77 | public function completePurchase(array $parameters = array()) 78 | { 79 | return $this->createRequest('\Omnipay\GoCardless\Message\CompletePurchaseRequest', $parameters); 80 | } 81 | 82 | public function authorize(array $parameters = array()) 83 | { 84 | return $this->createRequest('\Omnipay\GoCardless\Message\AuthorizeRequest', $parameters); 85 | } 86 | 87 | public function completeAuthorize(array $parameters = array()) 88 | { 89 | return $this->createRequest('\Omnipay\GoCardless\Message\CompleteAuthorizeRequest', $parameters); 90 | } 91 | 92 | public function capture(array $parameters = array()) 93 | { 94 | return $this->createRequest('\Omnipay\GoCardless\Message\CaptureRequest', $parameters); 95 | } 96 | 97 | /** 98 | * Generate a query string for the data array (this is some kind of sick joke) 99 | * 100 | * @link https://github.com/gocardless/gocardless-php/blob/v0.3.3/lib/GoCardless/Utils.php#L39 101 | */ 102 | public static function generateQueryString($data, &$pairs = array(), $namespace = null) 103 | { 104 | if (is_array($data)) { 105 | foreach ($data as $k => $v) { 106 | if (is_int($k)) { 107 | static::generateQueryString($v, $pairs, $namespace.'[]'); 108 | } else { 109 | static::generateQueryString($v, $pairs, $namespace !== null ? $namespace."[$k]" : $k); 110 | } 111 | } 112 | 113 | if ($namespace !== null) { 114 | return $pairs; 115 | } 116 | 117 | if (empty($pairs)) { 118 | return ''; 119 | } 120 | 121 | sort($pairs); 122 | $strs = array_map('implode', array_fill(0, count($pairs), '='), $pairs); 123 | 124 | return implode('&', $strs); 125 | } else { 126 | $pairs[] = array(rawurlencode($namespace), rawurlencode($data)); 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/Message/AbstractRequest.php: -------------------------------------------------------------------------------- 1 | getParameter('appId'); 18 | } 19 | 20 | public function setAppId($value) 21 | { 22 | return $this->setParameter('appId', $value); 23 | } 24 | 25 | public function getAppSecret() 26 | { 27 | return $this->getParameter('appSecret'); 28 | } 29 | 30 | public function setAppSecret($value) 31 | { 32 | return $this->setParameter('appSecret', $value); 33 | } 34 | 35 | public function getMerchantId() 36 | { 37 | return $this->getParameter('merchantId'); 38 | } 39 | 40 | public function setMerchantId($value) 41 | { 42 | return $this->setParameter('merchantId', $value); 43 | } 44 | 45 | public function getAccessToken() 46 | { 47 | return $this->getParameter('accessToken'); 48 | } 49 | 50 | public function setAccessToken($value) 51 | { 52 | return $this->setParameter('accessToken', $value); 53 | } 54 | 55 | public function getChargeCustomerAt() 56 | { 57 | return $this->getParameter('chargeCustomerAt'); 58 | } 59 | 60 | public function setChargeCustomerAt($value) 61 | { 62 | return $this->setParameter('chargeCustomerAt', $value); 63 | } 64 | 65 | public function getState() 66 | { 67 | return $this->getParameter('state'); 68 | } 69 | 70 | public function setState($value) 71 | { 72 | return $this->setParameter('state', $value); 73 | } 74 | 75 | public function getIntervalLength() 76 | { 77 | return $this->getParameter('intervalLength'); 78 | } 79 | 80 | public function setIntervalLength($value) 81 | { 82 | return $this->setParameter('intervalLength', $value); 83 | } 84 | 85 | public function getIntervalUnit() 86 | { 87 | return $this->getParameter('intervalUnit'); 88 | } 89 | 90 | public function setIntervalUnit($value) 91 | { 92 | return $this->setParameter('intervalUnit', $value); 93 | } 94 | 95 | public function getCalendarInterval() 96 | { 97 | return $this->getParameter('calendarInterval'); 98 | } 99 | 100 | public function setCalendarInterval($value) 101 | { 102 | return $this->setParameter('calendarInterval', $value); 103 | } 104 | 105 | public function getSetupFee() 106 | { 107 | return $this->getParameter('setupFee'); 108 | } 109 | 110 | public function setSetupFee($value) 111 | { 112 | return $this->setParameter('setupFee', $value); 113 | } 114 | 115 | public function getPreAuthExpire() 116 | { 117 | return $this->getParameter('preAuthExpire'); 118 | } 119 | 120 | public function setPreAuthExpire($value) 121 | { 122 | return $this->setParameter('preAuthExpire', $value); 123 | } 124 | 125 | public function getIntervalCount() 126 | { 127 | return $this->getParameter('intervalCount'); 128 | } 129 | 130 | public function setIntervalCount($value) 131 | { 132 | return $this->setParameter('intervalCount', $value); 133 | } 134 | 135 | /** 136 | * Generate a signature for the data array 137 | */ 138 | public function generateSignature($data) 139 | { 140 | return hash_hmac('sha256', Gateway::generateQueryString($data), $this->getAppSecret()); 141 | } 142 | 143 | public function getEndpoint() 144 | { 145 | return $this->getTestMode() ? $this->testEndpoint : $this->liveEndpoint; 146 | } 147 | 148 | /** 149 | * Generate a nonce for each request 150 | */ 151 | protected function generateNonce() 152 | { 153 | $nonce = ''; 154 | for ($i = 0; $i < 64; $i++) { 155 | // append random ASCII character 156 | $nonce .= chr(mt_rand(33, 126)); 157 | } 158 | 159 | return base64_encode($nonce); 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/Message/AuthorizeRequest.php: -------------------------------------------------------------------------------- 1 | validate('amount', 'intervalLength', 'intervalUnit'); 32 | 33 | $data = array(); 34 | //Required Items from the API 35 | $data['client_id'] = $this->getAppId(); 36 | $data['nonce'] = $this->generateNonce(); 37 | $data['timestamp'] = gmdate('Y-m-d\TH:i:s\Z'); 38 | 39 | $data['pre_authorization']['max_amount'] = $this->getAmount(); 40 | $data['pre_authorization']['interval_length'] = $this->getIntervalLength(); 41 | $data['pre_authorization']['interval_unit'] = $this->getIntervalUnit(); 42 | $data['pre_authorization']['merchant_id'] = $this->getMerchantId(); 43 | $data['redirect_uri'] = $this->getReturnUrl(); 44 | 45 | //Nice to haves. 46 | if ($this->getCancelUrl()) { 47 | $data['cancel_uri'] = $this->getCancelUrl(); 48 | } 49 | if ($this->getState()) { 50 | $data['state'] = $this->getState(); 51 | } 52 | if ($this->getDescription()) { 53 | $data['name'] = $this->getDescription(); 54 | } 55 | if ($this->getCalendarInterval()) { 56 | $data['pre_authorization']['calendar_intervals'] = $this->getCalendarInterval(); 57 | } 58 | if ($this->getSetupFee()) { 59 | $data['pre_authorization']['setup_fee'] = $this->getSetupFee(); 60 | } 61 | if ($this->getIntervalCount()) { 62 | $data['pre_authorization']['interval_count'] = $this->getIntervalCount(); 63 | } 64 | if ($this->getPreAuthExpire()) { 65 | $data['pre_authorization']['expires_at'] = $this->getPreAuthExpire(); 66 | } 67 | 68 | if ($this->getCard()) { 69 | $data['bill']['user'] = array(); 70 | $data['bill']['user']['first_name'] = $this->getCard()->getFirstName(); 71 | $data['bill']['user']['last_name'] = $this->getCard()->getLastName(); 72 | $data['bill']['user']['email'] = $this->getCard()->getEmail(); 73 | $data['bill']['user']['billing_address1'] = $this->getCard()->getAddress1(); 74 | $data['bill']['user']['billing_address2'] = $this->getCard()->getAddress2(); 75 | $data['bill']['user']['billing_town'] = $this->getCard()->getCity(); 76 | $data['bill']['user']['billing_county'] = $this->getCard()->getCountry(); 77 | $data['bill']['user']['billing_postcode'] = $this->getCard()->getPostcode(); 78 | } 79 | 80 | $data['signature'] = $this->generateSignature($data); 81 | 82 | return $data; 83 | 84 | } 85 | 86 | public function sendData($data) 87 | { 88 | return $this->response = new AuthorizeResponse($this, $data); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/Message/AuthorizeResponse.php: -------------------------------------------------------------------------------- 1 | getRequest()->getEndpoint(). 24 | '/connect/pre_authorizations/new?'. 25 | Gateway::generateQueryString($this->data); 26 | } 27 | 28 | public function getRedirectMethod() 29 | { 30 | return 'GET'; 31 | } 32 | 33 | public function getRedirectData() 34 | { 35 | return null; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Message/CaptureRequest.php: -------------------------------------------------------------------------------- 1 | validate('amount', 'transactionReference'); 25 | 26 | $data = array(); 27 | 28 | $bill = array(); 29 | $bill['amount'] = $this->getAmount(); 30 | $bill['pre_authorization_id'] = $this->getTransactionReference(); 31 | $bill['name'] = $this->getDescription(); 32 | $bill['charge_customer_at'] = $this->getChargeCustomerAt(); 33 | 34 | $data['bill'] = $bill; 35 | 36 | return $data; 37 | } 38 | 39 | public function sendData($data) 40 | { 41 | $httpRequest = $this->httpClient->post( 42 | $this->getEndpoint().'/api/v1/bills', 43 | array('Accept' => 'application/json'), 44 | Gateway::generateQueryString($data) 45 | ); 46 | 47 | $httpResponse = $httpRequest->setHeader('Authorization', 'bearer '.$this->getAccessToken())->send(); 48 | 49 | return $this->response = new CaptureResponse($this, $httpResponse->json()); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Message/CaptureResponse.php: -------------------------------------------------------------------------------- 1 | data['error']); 14 | } 15 | 16 | public function getMessage() 17 | { 18 | if (!$this->isSuccessful()) { 19 | return reset($this->data['error']); 20 | } 21 | 22 | return null; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Message/CompleteAuthorizeRequest.php: -------------------------------------------------------------------------------- 1 | httpRequest->get('resource_uri'); 25 | $data['resource_id'] = $this->httpRequest->get('resource_id'); 26 | $data['resource_type'] = $this->httpRequest->get('resource_type'); 27 | if ($this->httpRequest->get('state')) { 28 | $data['state'] = $this->httpRequest->get('state'); 29 | } 30 | 31 | if ($this->generateSignature($data) !== $this->httpRequest->get('signature')) { 32 | throw new InvalidResponseException; 33 | } 34 | 35 | unset($data['resource_uri']); 36 | 37 | return $data; 38 | } 39 | 40 | public function sendData($data) 41 | { 42 | $httpRequest = $this->httpClient->post( 43 | $this->getEndpoint().'/api/v1/confirm', 44 | array('Accept' => 'application/json'), 45 | Gateway::generateQueryString($data) 46 | ); 47 | $httpResponse = $httpRequest->setAuth($this->getAppId(), $this->getAppSecret())->send(); 48 | 49 | return $this->response = new CompleteAuthorizeResponse( 50 | $this, 51 | $httpResponse->json(), 52 | $this->httpRequest->get('resource_id') 53 | ); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Message/CompleteAuthorizeResponse.php: -------------------------------------------------------------------------------- 1 | transactionReference = $transactionReference; 16 | } 17 | 18 | public function isSuccessful() 19 | { 20 | return !isset($this->data['error']); 21 | } 22 | 23 | public function getTransactionReference() 24 | { 25 | return $this->transactionReference; 26 | } 27 | 28 | public function getMessage() 29 | { 30 | if (!$this->isSuccessful()) { 31 | return reset($this->data['error']); 32 | } 33 | return null; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Message/CompletePurchaseRequest.php: -------------------------------------------------------------------------------- 1 | httpRequest->get('resource_uri'); 17 | $data['resource_id'] = $this->httpRequest->get('resource_id'); 18 | $data['resource_type'] = $this->httpRequest->get('resource_type'); 19 | 20 | if (! is_null($this->httpRequest->get('state'))) { 21 | $data['state'] = $this->httpRequest->get('state'); 22 | } 23 | 24 | 25 | if ($this->generateSignature($data) !== $this->httpRequest->get('signature')) { 26 | throw new InvalidResponseException; 27 | } 28 | 29 | unset($data['resource_uri']); 30 | 31 | return $data; 32 | } 33 | 34 | public function sendData($data) 35 | { 36 | // don't throw exceptions for 4xx errors 37 | $this->httpClient->getEventDispatcher()->addListener( 38 | 'request.error', 39 | function ($event) { 40 | if ($event['response']->isClientError()) { 41 | $event->stopPropagation(); 42 | } 43 | } 44 | ); 45 | 46 | $httpRequest = $this->httpClient->post( 47 | $this->getEndpoint().'/api/v1/confirm', 48 | array('Accept' => 'application/json'), 49 | Gateway::generateQueryString($data) 50 | ); 51 | $httpResponse = $httpRequest->setAuth($this->getAppId(), $this->getAppSecret())->send(); 52 | 53 | return $this->response = new CompletePurchaseResponse( 54 | $this, 55 | $httpResponse->json(), 56 | $this->httpRequest->get('resource_id') 57 | ); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Message/CompletePurchaseResponse.php: -------------------------------------------------------------------------------- 1 | transactionReference = $transactionReference; 19 | } 20 | 21 | public function isSuccessful() 22 | { 23 | return !isset($this->data['error']); 24 | } 25 | 26 | public function getTransactionReference() 27 | { 28 | return $this->transactionReference; 29 | } 30 | 31 | public function getMessage() 32 | { 33 | if (!$this->isSuccessful()) { 34 | return reset($this->data['error']); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Message/PurchaseRequest.php: -------------------------------------------------------------------------------- 1 | validate('amount'); 13 | 14 | $data = array(); 15 | $data['client_id'] = $this->getAppId(); 16 | $data['nonce'] = $this->generateNonce(); 17 | $data['timestamp'] = gmdate('Y-m-d\TH:i:s\Z'); 18 | $data['redirect_uri'] = $this->getReturnUrl(); 19 | $data['cancel_uri'] = $this->getCancelUrl(); 20 | $data['state'] = $this->getState(); 21 | $data['bill'] = array(); 22 | $data['bill']['merchant_id'] = $this->getMerchantId(); 23 | $data['bill']['amount'] = $this->getAmount(); 24 | $data['bill']['name'] = $this->getDescription(); 25 | 26 | if ($this->getCard()) { 27 | $data['bill']['user'] = array(); 28 | $data['bill']['user']['first_name'] = $this->getCard()->getFirstName(); 29 | $data['bill']['user']['last_name'] = $this->getCard()->getLastName(); 30 | $data['bill']['user']['email'] = $this->getCard()->getEmail(); 31 | $data['bill']['user']['billing_address1'] = $this->getCard()->getAddress1(); 32 | $data['bill']['user']['billing_address2'] = $this->getCard()->getAddress2(); 33 | $data['bill']['user']['billing_town'] = $this->getCard()->getCity(); 34 | $data['bill']['user']['billing_county'] = $this->getCard()->getCountry(); 35 | $data['bill']['user']['billing_postcode'] = $this->getCard()->getPostcode(); 36 | } 37 | 38 | $data['signature'] = $this->generateSignature($data); 39 | 40 | return $data; 41 | } 42 | 43 | public function sendData($data) 44 | { 45 | return $this->response = new PurchaseResponse($this, $data); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Message/PurchaseResponse.php: -------------------------------------------------------------------------------- 1 | getRequest()->getEndpoint().'/connect/bills/new?'.Gateway::generateQueryString($this->data); 27 | } 28 | 29 | public function getRedirectMethod() 30 | { 31 | return 'GET'; 32 | } 33 | 34 | public function getRedirectData() 35 | { 36 | return null; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /tests/GatewayTest.php: -------------------------------------------------------------------------------- 1 | gateway = new Gateway($this->getHttpClient(), $this->getHttpRequest()); 14 | $this->gateway->setAppId('abc'); 15 | $this->gateway->setAppSecret('123'); 16 | 17 | $this->options = array( 18 | 'amount' => '10.00', 19 | 'returnUrl' => 'https://www.example.com/return', 20 | ); 21 | } 22 | 23 | public function testPurchase() 24 | { 25 | $response = $this->gateway->purchase($this->options)->send(); 26 | 27 | $this->assertInstanceOf('\Omnipay\GoCardless\Message\PurchaseResponse', $response); 28 | $this->assertTrue($response->isRedirect()); 29 | $this->assertStringStartsWith('https://gocardless.com/connect/bills/new?', $response->getRedirectUrl()); 30 | } 31 | 32 | public function testCompletePurchaseSuccess() 33 | { 34 | $this->getHttpRequest()->request->replace( 35 | array( 36 | 'resource_uri' => 'a', 37 | 'resource_id' => 'b', 38 | 'resource_type' => 'c', 39 | 'state' => 'd', 40 | 'signature' => 'cdc9e0cdb88114976dd18f597cb0a8f46cb26be6c8c17094b6394e76a7fc5732', 41 | ) 42 | ); 43 | 44 | $this->setMockHttpResponse('CompletePurchaseSuccess.txt'); 45 | 46 | $response = $this->gateway->completePurchase($this->options)->send(); 47 | 48 | $this->assertTrue($response->isSuccessful()); 49 | $this->assertEquals('b', $response->getTransactionReference()); 50 | } 51 | 52 | public function testCompletePurchaseSuccessWithEmptyStateVariable() 53 | { 54 | $this->getHttpRequest()->request->replace( 55 | array( 56 | 'resource_uri' => 'a', 57 | 'resource_id' => 'b', 58 | 'resource_type' => 'c', 59 | 'state' => '', 60 | 'signature' => '32189fc3f76bfeacb279a911116256d0ab399ecc33f3c74987564d73bb390c6a', 61 | ) 62 | ); 63 | 64 | $this->setMockHttpResponse('CompletePurchaseSuccess.txt'); 65 | 66 | $response = $this->gateway->completePurchase($this->options)->send(); 67 | 68 | $this->assertTrue($response->isSuccessful()); 69 | $this->assertEquals('b', $response->getTransactionReference()); 70 | } 71 | 72 | public function testCompletePurchaseError() 73 | { 74 | $this->getHttpRequest()->request->replace( 75 | array( 76 | 'resource_uri' => 'a', 77 | 'resource_id' => 'b', 78 | 'resource_type' => 'c', 79 | 'signature' => '416f52e7d287dab49fa8445c1cd0957ca8ddf1c04a6300e00117dc0bedabc7d7', 80 | ) 81 | ); 82 | 83 | $this->setMockHttpResponse('CompletePurchaseFailure.txt'); 84 | 85 | $response = $this->gateway->completePurchase($this->options)->send(); 86 | 87 | $this->assertFalse($response->isSuccessful()); 88 | $this->assertSame('The resource cannot be confirmed', $response->getMessage()); 89 | } 90 | 91 | /** 92 | * @expectedException Omnipay\Common\Exception\InvalidResponseException 93 | */ 94 | public function testCompletePurchaseInvalid() 95 | { 96 | $this->getHttpRequest()->request->replace( 97 | array( 98 | 'resource_uri' => 'a', 99 | 'resource_id' => 'b', 100 | 'resource_type' => 'c', 101 | 'signature' => 'd', 102 | ) 103 | ); 104 | 105 | $response = $this->gateway->completePurchase($this->options)->send(); 106 | } 107 | 108 | public function testAuthorization() 109 | { 110 | $params = array( 111 | 'amount' => '10.00', 112 | 'intervalLength' => 12, 113 | 'intervalUnit' => 'week', 114 | 'returnUrl' => 'foo.bar/baz' 115 | ); 116 | $response = $this->gateway->authorize($params)->send(); 117 | 118 | $this->assertInstanceOf('Omnipay\GoCardless\Message\AuthorizeResponse', $response); 119 | $this->assertStringStartsWith('https://gocardless.com/connect/pre_authorizations/new?', $response->getRedirectUrl()); 120 | 121 | //NB: These are here for a potential refactor. 122 | $this->assertFalse($response->isSuccessful()); 123 | $this->assertTrue($response->isRedirect()); 124 | $this->assertSame('GET', $response->getRedirectMethod()); 125 | $this->assertNull($response->getRedirectData()); 126 | } 127 | 128 | public function testCompleteAuthorizeSuccess() 129 | { 130 | $this->getHttpRequest()->request->replace( 131 | array( 132 | 'resource_uri' => 'a', 133 | 'resource_id' => 'b', 134 | 'resource_type' => 'c', 135 | 'state' => 'd', 136 | 'signature' => 'cdc9e0cdb88114976dd18f597cb0a8f46cb26be6c8c17094b6394e76a7fc5732', 137 | ) 138 | ); 139 | 140 | $this->setMockHttpResponse('CompletePurchaseSuccess.txt'); 141 | 142 | $response = $this->gateway->completeAuthorize($this->options)->send(); 143 | 144 | $this->assertTrue($response->isSuccessful()); 145 | $this->assertEquals('b', $response->getTransactionReference()); 146 | } 147 | 148 | public function testCapture() 149 | { 150 | $response = $this->gateway->capture(array('amount' => '10.00')); 151 | 152 | $this->assertInstanceOf('Omnipay\GoCardless\Message\CaptureRequest', $response); 153 | } 154 | 155 | public function testCaptureSuccess() 156 | { 157 | $params = array( 158 | 'amount' => '10.00', 159 | 'transactionReference' => 'abc', 160 | 'description' => 'fyi' 161 | ); 162 | $transaction = $this->gateway->capture($params); 163 | $transaction->setChargeCustomerAt('2015-12-12'); 164 | 165 | $this->setMockHttpResponse('CapturePaymentSuccess.txt'); 166 | 167 | $response = $transaction->send(); 168 | 169 | $this->assertInstanceOf('Omnipay\GoCardless\Message\CaptureResponse', $response); 170 | $this->assertTrue($response->isSuccessful()); 171 | $this->assertNull($response->getMessage()); 172 | } 173 | 174 | public function testCaptureFailure() 175 | { 176 | $params = array( 177 | 'amount' => '10.00', 178 | 'transactionReference' => '12v' 179 | ); 180 | $this->setMockHttpResponse('CapturePaymentFailure.txt'); 181 | $response = $this->gateway->capture($params)->send(); 182 | 183 | $this->assertInstanceOf('Omnipay\GoCardless\Message\CaptureResponse', $response); 184 | $this->assertFalse($response->isSuccessful()); 185 | $this->assertSame('The authorization cannot be found', $response->getMessage()); 186 | } 187 | 188 | } 189 | -------------------------------------------------------------------------------- /tests/Message/CompletePurchaseResponseTest.php: -------------------------------------------------------------------------------- 1 | getMockHttpResponse('CompletePurchaseSuccess.txt'); 12 | $response = new CompletePurchaseResponse($this->getMockRequest(), $httpResponse->json(), 'abc123'); 13 | 14 | $this->assertTrue($response->isSuccessful()); 15 | $this->assertSame('abc123', $response->getTransactionReference()); 16 | $this->assertNull($response->getMessage()); 17 | } 18 | 19 | public function testCompletePurchaseFailure() 20 | { 21 | $httpResponse = $this->getMockHttpResponse('CompletePurchaseFailure.txt'); 22 | $response = new CompletePurchaseResponse($this->getMockRequest(), $httpResponse->json(), 'abc123'); 23 | 24 | $this->assertFalse($response->isSuccessful()); 25 | $this->assertSame('abc123', $response->getTransactionReference()); 26 | $this->assertSame('The resource cannot be confirmed', $response->getMessage()); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/Mock/CapturePaymentFailure.txt: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | 3 | {"error":["The authorization cannot be found"]} -------------------------------------------------------------------------------- /tests/Mock/CapturePaymentSuccess.txt: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | 3 | {"success":true} 4 | -------------------------------------------------------------------------------- /tests/Mock/CompletePurchaseFailure.txt: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | 3 | {"error":["The resource cannot be confirmed"]} 4 | -------------------------------------------------------------------------------- /tests/Mock/CompletePurchaseSuccess.txt: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | 3 | {"success":true} 4 | --------------------------------------------------------------------------------