├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── runtests.sh ├── tests ├── Mock │ ├── RefundFailure.txt │ ├── PurchaseFailure.txt │ ├── CaptureFailure.txt │ ├── CardFailure.txt │ ├── CustomerFailure.txt │ ├── RefundSuccess.txt │ ├── CardSuccess.txt │ ├── CustomerSuccess.txt │ ├── PurchaseSuccess.txt │ └── CaptureSuccess.txt ├── Message │ ├── CaptureResponseTest.php │ ├── RefundRequestTest.php │ ├── CaptureRequestTest.php │ ├── CreateCardRequestTest.php │ ├── CreateCustomerRequestTest.php │ ├── PurchaseRequestTest.php │ └── ResponseTest.php └── GatewayTest.php ├── src ├── Message │ ├── CaptureResponse.php │ ├── CaptureRequest.php │ ├── RefundRequest.php │ ├── Response.php │ ├── AbstractRequest.php │ ├── CreateCardRequest.php │ ├── CreateCustomerRequest.php │ ├── AuthorizeRequest.php │ └── PurchaseRequest.php └── Gateway.php ├── phpunit.xml.dist ├── LICENSE ├── composer.json ├── README.md └── makedoc.sh /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | composer.lock 3 | composer.phar 4 | phpunit.xml 5 | .directory 6 | /documents/ 7 | .idea/ 8 | dirlist.app 9 | dirlist.cache 10 | dirlist.vendor 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.6 5 | - 7.0 6 | - 7.1 7 | - 7.2 8 | - 7.3 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 | -------------------------------------------------------------------------------- /runtests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Command line runner for unit tests for composer projects 5 | # (c) Del 2015 http://www.babel.com.au/ 6 | # No Rights Reserved 7 | # 8 | 9 | # 10 | # Clean up after any previous test runs 11 | # 12 | mkdir -p documents 13 | rm -rf documents/coverage-html-new 14 | rm -f documents/coverage.xml 15 | 16 | # 17 | # Run phpunit 18 | # 19 | vendor/bin/phpunit --coverage-html documents/coverage-html-new --coverage-clover documents/coverage.xml 20 | 21 | if [ -d documents/coverage-html-new ]; then 22 | rm -rf documents/coverage-html 23 | mv documents/coverage-html-new documents/coverage-html 24 | fi 25 | 26 | -------------------------------------------------------------------------------- /tests/Mock/RefundFailure.txt: -------------------------------------------------------------------------------- 1 | HTTP/1.1 422 Unprocessable Entity 2 | Cache-Control: no-cache 3 | Content-Type: application/json; charset=utf-8 4 | Date: Fri, 15 Feb 2013 15:54:18 GMT 5 | Server: Apache/2.2.20 (Ubuntu) 6 | Status: 422 7 | Strict-Transport-Security: max-age=31536000 8 | Vary: User-Agent 9 | X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.11 10 | X-Rack-Cache: invalidate, pass 11 | X-Request-Id: 293436e475bfc6face410e6ed241efe9 12 | X-Runtime: 0.161746 13 | X-UA-Compatible: IE=Edge,chrome=1 14 | Content-Length: 152 15 | Connection: keep-alive 16 | 17 | {"error": "insufficient_pin_balance","error_description": "Refund amount is more than your available Pin Payments balance."} 18 | -------------------------------------------------------------------------------- /tests/Mock/PurchaseFailure.txt: -------------------------------------------------------------------------------- 1 | HTTP/1.1 422 Unprocessable Entity 2 | Cache-Control: no-cache 3 | Content-Type: application/json; charset=utf-8 4 | Date: Fri, 15 Feb 2013 15:54:18 GMT 5 | Server: Apache/2.2.20 (Ubuntu) 6 | Status: 422 7 | Strict-Transport-Security: max-age=31536000 8 | Vary: User-Agent 9 | X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.11 10 | X-Rack-Cache: invalidate, pass 11 | X-Request-Id: 293436e475bfc6face410e6ed241efe9 12 | X-Runtime: 0.161746 13 | X-UA-Compatible: IE=Edge,chrome=1 14 | Content-Length: 152 15 | Connection: keep-alive 16 | 17 | {"error":"invalid_resource","error_description":"The current resource was deemed invalid.","messages":[{"code":"invalid","message":"Processing error"}]} 18 | -------------------------------------------------------------------------------- /src/Message/CaptureResponse.php: -------------------------------------------------------------------------------- 1 | data['response']['captured'])) { 28 | return $this->data['response']['captured']; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/Mock/CaptureFailure.txt: -------------------------------------------------------------------------------- 1 | HTTP/1.1 400 AUTHORISATION_EXPIRED 2 | Cache-Control: max-age=0, private, must-revalidate 3 | Content-Type: application/json; charset=utf-8 4 | Date: Fri, 15 Feb 2013 15:42:42 GMT 5 | ETag: "e0b6339dc44a19a2901de1447ec94ebb" 6 | Server: Apache/2.2.20 (Ubuntu) 7 | Status: 200 8 | Strict-Transport-Security: max-age=31536000 9 | Vary: Use-Agent 10 | X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.11 11 | X-Rack-Cache: invalidate, pass 12 | X-Request-Id: 6444d2d9467ed2a7ace471522f2d439b 13 | X-Runtime: 0.245244 14 | X-UA-Compatible: IE=Edge,chrome=1 15 | Content-Length: 584 16 | Connection: keep-alive 17 | 18 | {"error":"authorisation_expired","error_description":"The authorisation has expired and can not be captured.","charge_token":"ch_lfUYEBK14zotCTykezJkfg"} -------------------------------------------------------------------------------- /tests/Mock/CardFailure.txt: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Cache-Control: max-age=0, private, must-revalidate 3 | Content-Type: application/json; charset=utf-8 4 | Date: Fri, 15 Feb 2013 15:42:42 GMT 5 | ETag: "e0b6339dc44a19a2901de1447ec94ebb" 6 | Server: Apache/2.2.20 (Ubuntu) 7 | Status: 200 8 | Strict-Transport-Security: max-age=31536000 9 | Vary: User-Agent 10 | X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.11 11 | X-Rack-Cache: invalidate, pass 12 | X-Request-Id: 6444d2d9467ed2a7ace471522f2d439b 13 | X-Runtime: 0.245244 14 | X-UA-Compatible: IE=Edge,chrome=1 15 | Content-Length: 584 16 | Connection: keep-alive 17 | 18 | {"error":"invalid_resource","error_description":"One or more parameters were missing or invalid","messages":[{"param":"expiry_month","code":"expiry_month_invalid","message":"Expiry month can't be blank"}]} 19 | -------------------------------------------------------------------------------- /tests/Mock/CustomerFailure.txt: -------------------------------------------------------------------------------- 1 | HTTP/1.1 422 Unprocessable Entity 2 | Cache-Control: no-cache 3 | Content-Type: application/json; charset=utf-8 4 | Date: Fri, 15 Feb 2013 15:54:18 GMT 5 | Server: Apache/2.2.20 (Ubuntu) 6 | Status: 422 7 | Strict-Transport-Security: max-age=31536000 8 | Vary: User-Agent 9 | X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.11 10 | X-Rack-Cache: invalidate, pass 11 | X-Request-Id: 293436e475bfc6face410e6ed241efe9 12 | X-Runtime: 0.161746 13 | X-UA-Compatible: IE=Edge,chrome=1 14 | Content-Length: 152 15 | Connection: keep-alive 16 | 17 | {"error":"invalid_resource","error_description":"One or more parameters were missing or invalid","messages":[{"param":"email","code":"email_invalid","message":"Email can't be blank"},{"param":"email","code":"email_invalid","message":"Email is not formatted properly"}]} 18 | -------------------------------------------------------------------------------- /tests/Mock/RefundSuccess.txt: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Cache-Control: max-age=0, private, must-revalidate 3 | Content-Type: application/json; charset=utf-8 4 | Date: Fri, 15 Feb 2013 15:42:42 GMT 5 | ETag: "e0b6339dc44a19a2901de1447ec94ebb" 6 | Server: Apache/2.2.20 (Ubuntu) 7 | Status: 200 8 | Strict-Transport-Security: max-age=31536000 9 | Vary: User-Agent 10 | X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.11 11 | X-Rack-Cache: invalidate, pass 12 | X-Request-Id: 6444d2d9467ed2a7ace471522f2d439b 13 | X-Runtime: 0.245244 14 | X-UA-Compatible: IE=Edge,chrome=1 15 | Content-Length: 584 16 | Connection: keep-alive 17 | 18 | {"response": {"token": "rf_ERCQy--Ay6o-NKGiUVcKKA","success": null,"amount": 400,"currency": "AUD","charge": "ch_bZ3RhJnIUZ8HhfvH8CCvfA","created_at": "2012-10-27T13:00:00Z","error_message": null,"status_message": "Pending"}} -------------------------------------------------------------------------------- /src/Message/CaptureRequest.php: -------------------------------------------------------------------------------- 1 | validate('transactionReference'); 18 | 19 | // Amount is the only possible optional parameter 20 | $amount = $this->getAmountInteger(); 21 | 22 | return $amount ? array('amount' => $amount) : array(); 23 | } 24 | 25 | public function sendData($data) 26 | { 27 | $httpResponse = $this->sendRequest( 28 | '/charges/' . $this->getTransactionReference() . '/capture', 29 | $data, 30 | 'PUT' 31 | ); 32 | return $this->response = new CaptureResponse($this, $httpResponse->getBody()->getContents()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | ./tests/ 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ./src 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /tests/Mock/CardSuccess.txt: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Cache-Control: max-age=0, private, must-revalidate 3 | Content-Type: application/json; charset=utf-8 4 | Date: Fri, 15 Feb 2013 15:42:42 GMT 5 | ETag: "e0b6339dc44a19a2901de1447ec94ebb" 6 | Server: Apache/2.2.20 (Ubuntu) 7 | Status: 200 8 | Strict-Transport-Security: max-age=31536000 9 | Vary: User-Agent 10 | X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.11 11 | X-Rack-Cache: invalidate, pass 12 | X-Request-Id: 6444d2d9467ed2a7ace471522f2d439b 13 | X-Runtime: 0.245244 14 | X-UA-Compatible: IE=Edge,chrome=1 15 | Content-Length: 584 16 | Connection: keep-alive 17 | 18 | {"response":{"token":"card_8LmnNMTYWG4zQZ4YnYQhBg","scheme":"master","display_number":"XXXX-XXXX-XXXX-0000","expiry_month":5,"expiry_year":2015,"name":"Roland Robot","address_line1":"42 Sevenoaks St","address_line2":"","address_city":"Lathlain","address_postcode":"6454","address_state":"WA","address_country":"Australia"},"ip_address":"27.32.236.92"} 19 | -------------------------------------------------------------------------------- /tests/Mock/CustomerSuccess.txt: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Cache-Control: max-age=0, private, must-revalidate 3 | Content-Type: application/json; charset=utf-8 4 | Date: Fri, 15 Feb 2013 15:42:42 GMT 5 | ETag: "e0b6339dc44a19a2901de1447ec94ebb" 6 | Server: Apache/2.2.20 (Ubuntu) 7 | Status: 200 8 | Strict-Transport-Security: max-age=31536000 9 | Vary: User-Agent 10 | X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.11 11 | X-Rack-Cache: invalidate, pass 12 | X-Request-Id: 6444d2d9467ed2a7ace471522f2d439b 13 | X-Runtime: 0.245244 14 | X-UA-Compatible: IE=Edge,chrome=1 15 | Content-Length: 584 16 | Connection: keep-alive 17 | 18 | {"response":{"token":"cus_Mb-8S1ZgEbLUUUJ97dfhfQ","email":"roland@pin.net.au","created_at":"2014-05-16T11:59:13Z","card":{"token":"card_ooPYTNYmvVr8gswiBwE8kQ","scheme":"master","display_number":"XXXX-XXXX-XXXX-0000","expiry_month":5,"expiry_year":2015,"name":"Roland Robot","address_line1":"42 Sevenoaks St","address_line2":"","address_city":"Lathlain","address_postcode":"6454","address_state":"WA","address_country":"Australia"}}} 19 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "omnipay/pin", 3 | "type": "library", 4 | "description": "Pin Payments driver for the Omnipay payment processing library", 5 | "keywords": [ 6 | "gateway", 7 | "merchant", 8 | "omnipay", 9 | "pay", 10 | "payment", 11 | "pin" 12 | ], 13 | "homepage": "https://github.com/thephpleague/omnipay-pin", 14 | "license": "MIT", 15 | "authors": [ 16 | { 17 | "name": "Adrian Macneil", 18 | "email": "adrian@adrianmacneil.com" 19 | }, 20 | { 21 | "name": "Omnipay Contributors", 22 | "homepage": "https://github.com/thephpleague/omnipay-pin/contributors" 23 | } 24 | ], 25 | "autoload": { 26 | "psr-4": { "Omnipay\\Pin\\" : "src/" } 27 | }, 28 | "require": { 29 | "omnipay/common": "~3.0" 30 | }, 31 | "require-dev": { 32 | "omnipay/tests": "~3.0", 33 | "squizlabs/php_codesniffer": "^3" 34 | }, 35 | "extra": { 36 | "branch-alias": { 37 | "dev-master": "3.0.x-dev" 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tests/Mock/PurchaseSuccess.txt: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Cache-Control: max-age=0, private, must-revalidate 3 | Content-Type: application/json; charset=utf-8 4 | Date: Fri, 15 Feb 2013 15:42:42 GMT 5 | ETag: "e0b6339dc44a19a2901de1447ec94ebb" 6 | Server: Apache/2.2.20 (Ubuntu) 7 | Status: 200 8 | Strict-Transport-Security: max-age=31536000 9 | Vary: User-Agent 10 | X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.11 11 | X-Rack-Cache: invalidate, pass 12 | X-Request-Id: 6444d2d9467ed2a7ace471522f2d439b 13 | X-Runtime: 0.245244 14 | X-UA-Compatible: IE=Edge,chrome=1 15 | Content-Length: 584 16 | Connection: keep-alive 17 | 18 | {"response":{"token":"ch_fXIxWf0gj1yFHJcV1W-d-w","success":true,"amount":1000,"currency":"USD","description":"first purchase","email":"fads","ip_address":"","created_at":"2013-02-15T15:42:42Z","status_message":"Success!","error_message":null,"card":{"token":"card_vRGOXvw3NSGR59-TSzVEiw","display_number":"XXXX-XXXX-XXXX-0000","scheme":"visa","address_line1":"jkl","address_line2":"jkl","address_city":"jkl","address_postcode":"jkl","address_state":"jkl","address_country":"jkl"},"transfer":[],"amount_refunded":0,"total_fees":null,"merchant_entitlement":null,"refund_pending":false}} 19 | -------------------------------------------------------------------------------- /tests/Message/CaptureResponseTest.php: -------------------------------------------------------------------------------- 1 | getMockHttpResponse('CaptureSuccess.txt'); 12 | $response = new CaptureResponse($this->getMockRequest(), $httpResponse->getBody()->getContents()); 13 | 14 | $this->assertTrue($response->isSuccessful()); 15 | $this->assertFalse($response->isRedirect()); 16 | $this->assertEquals('ch_lfUYEBK14zotCTykezJkfg', $response->getTransactionReference()); 17 | $this->assertTrue($response->getCaptured()); 18 | } 19 | 20 | public function testCaptureFailure() 21 | { 22 | $httpResponse = $this->getMockHttpResponse('CaptureFailure.txt'); 23 | $response = new CaptureResponse($this->getMockRequest(), $httpResponse->getBody()->getContents()); 24 | 25 | $this->assertFalse($response->isSuccessful()); 26 | $this->assertFalse($response->isRedirect()); 27 | $this->assertSame('The authorisation has expired and can not be captured.', $response->getMessage()); 28 | $this->assertNull($response->getCaptured()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/Mock/CaptureSuccess.txt: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Cache-Control: max-age=0, private, must-revalidate 3 | Content-Type: application/json; charset=utf-8 4 | Date: Fri, 15 Feb 2013 15:42:42 GMT 5 | ETag: "e0b6339dc44a19a2901de1447ec94ebb" 6 | Server: Apache/2.2.20 (Ubuntu) 7 | Status: 200 8 | Strict-Transport-Security: max-age=31536000 9 | Vary: User-Agent 10 | X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.11 11 | X-Rack-Cache: invalidate, pass 12 | X-Request-Id: 6444d2d9467ed2a7ace471522f2d439b 13 | X-Runtime: 0.245244 14 | X-UA-Compatible: IE=Edge,chrome=1 15 | Content-Length: 584 16 | Connection: keep-alive 17 | 18 | {"response":{"token":"ch_lfUYEBK14zotCTykezJkfg","success":true,"amount":400,"currency":"USD","description":"test charge","email":"roland@pin.net.au","ip_address":"203.192.1.172","created_at":"2012-06-20T03:10:49Z","status_message":"Success","error_message":null,"card":{"token":"card_pIQJKMs93GsCc9vLSLevbw","scheme":"master","display_number":"XXXX-XXXX-XXXX-0000","expiry_month":6,"expiry_year":2020,"name":"RolandRobot","address_line1":"42 Sevenoaks St","address_line2":null,"address_city":"Lathlain","address_postcode":"6454","address_state":"WA","address_country":"Australia","primary":null},"captured":true,"authorisation_expired":false,"transfer":[],"amount_refunded":0,"total_fees":42,"merchant_entitlement":358,"refund_pending":false,"settlement_currency":"AUD"}} -------------------------------------------------------------------------------- /tests/Message/RefundRequestTest.php: -------------------------------------------------------------------------------- 1 | request = new RefundRequest($this->getHttpClient(), $this->getHttpRequest()); 12 | $this->request->setTransactionReference('ch_bZ3RhJnIUZ8HhfvH8CCvfA') 13 | ->setAmount('400.00'); 14 | } 15 | 16 | public function testSendSuccess() 17 | { 18 | $this->setMockHttpResponse('RefundSuccess.txt'); 19 | $response = $this->request->send(); 20 | 21 | $this->assertTrue($response->isSuccessful()); 22 | $this->assertFalse($response->isRedirect()); 23 | $this->assertEquals('rf_ERCQy--Ay6o-NKGiUVcKKA', $response->getTransactionReference()); 24 | $this->assertSame('Pending', $response->getMessage()); 25 | } 26 | 27 | public function testSendError() 28 | { 29 | $this->setMockHttpResponse('RefundFailure.txt'); 30 | $response = $this->request->send(); 31 | 32 | $this->assertFalse($response->isSuccessful()); 33 | $this->assertFalse($response->isRedirect()); 34 | $this->assertNull($response->getTransactionReference()); 35 | $this->assertSame('Refund amount is more than your available Pin Payments balance.', $response->getMessage()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/Message/CaptureRequestTest.php: -------------------------------------------------------------------------------- 1 | request = new RefundRequest($this->getHttpClient(), $this->getHttpRequest()); 12 | $this->request->setTransactionReference('ch_bZ3RhJnIUZ8HhfvH8CCvfA') 13 | ->setAmount('400.00'); 14 | } 15 | 16 | public function testSendSuccess() 17 | { 18 | $this->setMockHttpResponse('CaptureSuccess.txt'); 19 | $response = $this->request->send(); 20 | $data = $response->getData(); 21 | 22 | $this->assertTrue($response->isSuccessful()); 23 | $this->assertFalse($response->isRedirect()); 24 | $this->assertEquals('ch_lfUYEBK14zotCTykezJkfg', $response->getTransactionReference()); 25 | 26 | $this->assertTrue($data['response']['captured']); 27 | } 28 | 29 | public function testSendError() 30 | { 31 | $this->setMockHttpResponse('CaptureFailure.txt'); 32 | $response = $this->request->send(); 33 | 34 | $this->assertFalse($response->isSuccessful()); 35 | $this->assertFalse($response->isRedirect()); 36 | $this->assertNull($response->getTransactionReference()); 37 | $this->assertSame('The authorisation has expired and can not be captured.', $response->getMessage()); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/Message/CreateCardRequestTest.php: -------------------------------------------------------------------------------- 1 | request = new CreateCardRequest($this->getHttpClient(), $this->getHttpRequest()); 12 | $this->request->initialize( 13 | array( 14 | 'card' => $this->getValidCard(), 15 | ) 16 | ); 17 | } 18 | 19 | public function testDataWithCard() 20 | { 21 | $card = $this->getValidCard(); 22 | $this->request->setCard($card); 23 | $data = $this->request->getData(); 24 | 25 | $this->assertSame($card['number'], $data['number']); 26 | } 27 | 28 | public function testSendSuccess() 29 | { 30 | $this->setMockHttpResponse('CardSuccess.txt'); 31 | 32 | $response = $this->request->send(); 33 | 34 | $this->assertTrue($response->isSuccessful()); 35 | $this->assertFalse($response->isRedirect()); 36 | $this->assertEquals('card_8LmnNMTYWG4zQZ4YnYQhBg', $response->getCardReference()); 37 | $this->assertTrue($response->getMessage()); 38 | } 39 | 40 | public function testSendError() 41 | { 42 | $this->setMockHttpResponse('CardFailure.txt'); 43 | $response = $this->request->send(); 44 | 45 | $this->assertFalse($response->isSuccessful()); 46 | $this->assertFalse($response->isRedirect()); 47 | $this->assertNull($response->getCardReference()); 48 | $this->assertSame('One or more parameters were missing or invalid', $response->getMessage()); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Message/RefundRequest.php: -------------------------------------------------------------------------------- 1 | 21 | * // Do a refund transaction on the gateway 22 | * $transaction = $gateway->refund(array( 23 | * 'transactionReference' => $sale_id, 24 | * 'amount' => '10.00', 25 | * )); 26 | * $response = $transaction->send(); 27 | * if ($response->isSuccessful()) { 28 | * echo "Refund transaction was successful!\n"; 29 | * $refund_id = $response->getTransactionReference(); 30 | * echo "Transaction reference = " . $refund_id . "\n"; 31 | * } 32 | * 33 | * 34 | * @see \Omnipay\Pin\Gateway 35 | * @link https://pin.net.au/docs/api/refunds#post-refunds 36 | */ 37 | class RefundRequest extends AbstractRequest 38 | { 39 | public function getData() 40 | { 41 | $this->validate('transactionReference', 'amount'); 42 | 43 | $data = array(); 44 | $data['amount'] = $this->getAmountInteger(); 45 | 46 | return $data; 47 | } 48 | 49 | public function sendData($data) 50 | { 51 | $httpResponse = $this->sendRequest('/charges/' . $this->getTransactionReference() . '/refunds', $data); 52 | 53 | return $this->response = new Response($this, $httpResponse->getBody()->getContents()); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /tests/Message/CreateCustomerRequestTest.php: -------------------------------------------------------------------------------- 1 | request = new CreateCustomerRequest($this->getHttpClient(), $this->getHttpRequest()); 12 | $this->request->initialize( 13 | array( 14 | 'email' => 'roland@pin.net.au', 15 | 'card' => $this->getValidCard(), 16 | ) 17 | ); 18 | } 19 | 20 | public function testDataWithCardReference() 21 | { 22 | $this->request->setToken('card_abc'); 23 | $data = $this->request->getData(); 24 | 25 | $this->assertSame('card_abc', $data['card_token']); 26 | } 27 | 28 | public function testDataWithCard() 29 | { 30 | $card = $this->getValidCard(); 31 | $this->request->setCard($card); 32 | $data = $this->request->getData(); 33 | 34 | $this->assertSame($card['number'], $data['card']['number']); 35 | } 36 | 37 | public function testSendSuccess() 38 | { 39 | $this->setMockHttpResponse('CustomerSuccess.txt'); 40 | 41 | $response = $this->request->send(); 42 | 43 | $this->assertTrue($response->isSuccessful()); 44 | $this->assertFalse($response->isRedirect()); 45 | $this->assertEquals('cus_Mb-8S1ZgEbLUUUJ97dfhfQ', $response->getCustomerReference()); 46 | $this->assertTrue($response->getMessage()); 47 | } 48 | 49 | public function testSendError() 50 | { 51 | $this->setMockHttpResponse('CustomerFailure.txt'); 52 | $response = $this->request->send(); 53 | 54 | $this->assertFalse($response->isSuccessful()); 55 | $this->assertFalse($response->isRedirect()); 56 | $this->assertNull($response->getCustomerReference()); 57 | $this->assertSame('One or more parameters were missing or invalid', $response->getMessage()); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Omnipay: Pin Payments 2 | 3 | **Pin Payments driver for the Omnipay PHP payment processing library** 4 | 5 | [![Build Status](https://travis-ci.org/thephpleague/omnipay-pin.png?branch=master)](https://travis-ci.org/thephpleague/omnipay-pin) 6 | [![Latest Stable Version](https://poser.pugx.org/omnipay/pin/version.png)](https://packagist.org/packages/omnipay/pin) 7 | [![Total Downloads](https://poser.pugx.org/omnipay/pin/d/total.png)](https://packagist.org/packages/omnipay/pin) 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 [Pin](https://pinpayments.com/) support for Omnipay. 11 | 12 | [Pin Payments](https://pinpayments.com/) is an Australian all-in-one payment system, allowing you 13 | to accept multi-currency credit card payments without a security 14 | deposit or a merchant account. 15 | 16 | ## Installation 17 | 18 | Omnipay is installed via [Composer](http://getcomposer.org/). To install, simply add it 19 | to your `composer.json` file: 20 | 21 | ```json 22 | { 23 | "require": { 24 | "omnipay/pin": "~3.0" 25 | } 26 | } 27 | ``` 28 | 29 | And run composer to update your dependencies: 30 | 31 | $ curl -s http://getcomposer.org/installer | php 32 | $ php composer.phar update 33 | 34 | ## Basic Usage 35 | 36 | The following gateways are provided by this package: 37 | 38 | * Pin 39 | 40 | For general usage instructions, please see the main [Omnipay](https://github.com/thephpleague/omnipay) 41 | repository. 42 | 43 | ## Support 44 | 45 | If you are having general issues with Omnipay, we suggest posting on 46 | [Stack Overflow](http://stackoverflow.com/). Be sure to add the 47 | [omnipay tag](http://stackoverflow.com/questions/tagged/omnipay) so it can be easily found. 48 | 49 | If you want to keep up to date with release anouncements, discuss ideas for the project, 50 | or ask more detailed questions, there is also a [mailing list](https://groups.google.com/forum/#!forum/omnipay) which 51 | you can subscribe to. 52 | 53 | If you believe you have found a bug, please report it using the [GitHub issue tracker](https://github.com/thephpleague/omnipay-pin/issues), 54 | or better yet, fork the library and submit a pull request. 55 | -------------------------------------------------------------------------------- /tests/Message/PurchaseRequestTest.php: -------------------------------------------------------------------------------- 1 | request = new PurchaseRequest($this->getHttpClient(), $this->getHttpRequest()); 12 | $this->request->initialize( 13 | array( 14 | 'amount' => '10.00', 15 | 'currency' => 'AUD', 16 | 'card' => $this->getValidCard(), 17 | 'email' => 'roland@pin.net.au', 18 | 'description' => 'test charge' 19 | ) 20 | ); 21 | } 22 | 23 | public function testDataWithCardToken() 24 | { 25 | $this->request->setToken('card_abc'); 26 | $data = $this->request->getData(); 27 | 28 | $this->assertSame('card_abc', $data['card_token']); 29 | } 30 | 31 | public function testDataWithCustomerToken() 32 | { 33 | $this->request->setToken('cus_abc'); 34 | $data = $this->request->getData(); 35 | 36 | $this->assertSame('cus_abc', $data['customer_token']); 37 | } 38 | 39 | public function testDataWithCard() 40 | { 41 | $card = $this->getValidCard(); 42 | $this->request->setCard($card); 43 | $data = $this->request->getData(); 44 | 45 | $this->assertSame($card['number'], $data['card']['number']); 46 | } 47 | 48 | public function testSendSuccess() 49 | { 50 | $this->setMockHttpResponse('PurchaseSuccess.txt'); 51 | 52 | $response = $this->request->send(); 53 | 54 | $this->assertTrue($response->isSuccessful()); 55 | $this->assertFalse($response->isRedirect()); 56 | $this->assertEquals('ch_fXIxWf0gj1yFHJcV1W-d-w', $response->getTransactionReference()); 57 | $this->assertSame('Success!', $response->getMessage()); 58 | } 59 | 60 | public function testSendError() 61 | { 62 | $this->setMockHttpResponse('PurchaseFailure.txt'); 63 | $response = $this->request->send(); 64 | 65 | $this->assertFalse($response->isSuccessful()); 66 | $this->assertFalse($response->isRedirect()); 67 | $this->assertNull($response->getTransactionReference()); 68 | $this->assertSame('The current resource was deemed invalid.', $response->getMessage()); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/Message/Response.php: -------------------------------------------------------------------------------- 1 | data = json_decode($data, true); 26 | } 27 | } 28 | 29 | public function isSuccessful() 30 | { 31 | return !isset($this->data['error']); 32 | } 33 | 34 | public function getTransactionReference() 35 | { 36 | if (isset($this->data['response']['token'])) { 37 | return $this->data['response']['token']; 38 | } 39 | } 40 | 41 | /** 42 | * Get Card Reference 43 | * 44 | * This is used after createCard to get the credit card token to be 45 | * used in future transactions. 46 | * 47 | * @return string 48 | */ 49 | public function getCardReference() 50 | { 51 | if (isset($this->data['response']['token'])) { 52 | return $this->data['response']['token']; 53 | } 54 | } 55 | 56 | /** 57 | * @deprecated 58 | */ 59 | public function getCardToken() 60 | { 61 | return $this->getCardReference(); 62 | } 63 | 64 | /** 65 | * Get Customer Reference 66 | * 67 | * This is used after createCustomer to get the customer token to be 68 | * used in future transactions. 69 | * 70 | * @return string 71 | */ 72 | public function getCustomerReference() 73 | { 74 | if (isset($this->data['response']['token'])) { 75 | return $this->data['response']['token']; 76 | } 77 | } 78 | 79 | /** 80 | * @deprecated 81 | */ 82 | public function getCustomerToken() 83 | { 84 | return $this->getCustomerReference(); 85 | } 86 | 87 | public function getMessage() 88 | { 89 | if ($this->isSuccessful()) { 90 | if (isset($this->data['response']['status_message'])) { 91 | return $this->data['response']['status_message']; 92 | } else { 93 | return true; 94 | } 95 | } else { 96 | return $this->data['error_description']; 97 | } 98 | } 99 | 100 | public function getCode() 101 | { 102 | if (isset($this->data['error'])) { 103 | return $this->data['error']; 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /tests/Message/ResponseTest.php: -------------------------------------------------------------------------------- 1 | getMockHttpResponse('PurchaseSuccess.txt'); 12 | $response = new Response($this->getMockRequest(), $httpResponse->getBody()->getContents()); 13 | 14 | $this->assertTrue($response->isSuccessful()); 15 | $this->assertFalse($response->isRedirect()); 16 | $this->assertSame('ch_fXIxWf0gj1yFHJcV1W-d-w', $response->getTransactionReference()); 17 | $this->assertSame('Success!', $response->getMessage()); 18 | } 19 | 20 | public function testPurchaseFailure() 21 | { 22 | $httpResponse = $this->getMockHttpResponse('PurchaseFailure.txt'); 23 | $response = new Response($this->getMockRequest(), $httpResponse->getBody()->getContents()); 24 | 25 | $this->assertFalse($response->isSuccessful()); 26 | $this->assertFalse($response->isRedirect()); 27 | $this->assertNull($response->getTransactionReference()); 28 | $this->assertSame('The current resource was deemed invalid.', $response->getMessage()); 29 | } 30 | 31 | public function testCardSuccess() 32 | { 33 | $httpResponse = $this->getMockHttpResponse('CardSuccess.txt'); 34 | $response = new Response($this->getMockRequest(), $httpResponse->getBody()->getContents()); 35 | 36 | $this->assertTrue($response->isSuccessful()); 37 | $this->assertFalse($response->isRedirect()); 38 | $this->assertEquals('card_8LmnNMTYWG4zQZ4YnYQhBg', $response->getCardReference()); 39 | $this->assertTrue($response->getMessage()); 40 | } 41 | 42 | public function testCardFailure() 43 | { 44 | $httpResponse = $this->getMockHttpResponse('CardFailure.txt'); 45 | $response = new Response($this->getMockRequest(), $httpResponse->getBody()->getContents()); 46 | 47 | $this->assertFalse($response->isSuccessful()); 48 | $this->assertFalse($response->isRedirect()); 49 | $this->assertNull($response->getCardReference()); 50 | $this->assertSame('One or more parameters were missing or invalid', $response->getMessage()); 51 | } 52 | 53 | public function testCustomerSuccess() 54 | { 55 | $httpResponse = $this->getMockHttpResponse('CustomerSuccess.txt'); 56 | $response = new Response($this->getMockRequest(), $httpResponse->getBody()->getContents()); 57 | 58 | $this->assertTrue($response->isSuccessful()); 59 | $this->assertFalse($response->isRedirect()); 60 | $this->assertEquals('cus_Mb-8S1ZgEbLUUUJ97dfhfQ', $response->getCustomerReference()); 61 | $this->assertTrue($response->getMessage()); 62 | } 63 | 64 | public function testCustomerFailure() 65 | { 66 | $httpResponse = $this->getMockHttpResponse('CustomerFailure.txt'); 67 | $response = new Response($this->getMockRequest(), $httpResponse->getBody()->getContents()); 68 | 69 | $this->assertFalse($response->isSuccessful()); 70 | $this->assertFalse($response->isRedirect()); 71 | $this->assertNull($response->getCustomerReference()); 72 | $this->assertSame('One or more parameters were missing or invalid', $response->getMessage()); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/Message/AbstractRequest.php: -------------------------------------------------------------------------------- 1 | getParameter('secretKey'); 64 | } 65 | 66 | /** 67 | * Set secret key 68 | * 69 | * Calls to the Pin Payments API must be authenticated using HTTP 70 | * basic authentication, with your API key as the username, and 71 | * a blank string as the password. 72 | * 73 | * @param string $value 74 | * @return AbstractRequest implements a fluent interface 75 | */ 76 | public function setSecretKey($value) 77 | { 78 | return $this->setParameter('secretKey', $value); 79 | } 80 | 81 | /** 82 | * Get the request email. 83 | * 84 | * @return string 85 | */ 86 | public function getEmail() 87 | { 88 | return $this->getParameter('email'); 89 | } 90 | 91 | /** 92 | * Sets the request email. 93 | * 94 | * @param string $value 95 | * @return AbstractRequest Provides a fluent interface 96 | */ 97 | public function setEmail($value) 98 | { 99 | return $this->setParameter('email', $value); 100 | } 101 | 102 | /** 103 | * Get API endpoint URL 104 | * 105 | * @return string 106 | */ 107 | protected function getEndpoint() 108 | { 109 | $base = $this->getTestMode() ? $this->testEndpoint : $this->liveEndpoint; 110 | return $base . self::API_VERSION; 111 | } 112 | 113 | /** 114 | * Send a request to the gateway. 115 | * 116 | * @param string $action 117 | * @param array $data 118 | * @param string $method 119 | * 120 | * @return HttpResponse 121 | */ 122 | public function sendRequest($action, $data = null, $method = 'POST') 123 | { 124 | $body = $data ? http_build_query($data) : null; 125 | return $this->httpClient->request( 126 | $method, 127 | $this->getEndpoint() . $action, 128 | array('Authorization' => 'Basic ' . base64_encode($this->getSecretKey() . ':')), 129 | $body 130 | ); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/Message/CreateCardRequest.php: -------------------------------------------------------------------------------- 1 | 29 | * // Create a gateway for the Pin REST Gateway 30 | * // (routes to GatewayFactory::create) 31 | * $gateway = Omnipay::create('PinGateway'); 32 | * 33 | * // Initialise the gateway 34 | * $gateway->initialize(array( 35 | * 'secretKey' => 'TEST', 36 | * 'testMode' => true, // Or false when you are ready for live transactions 37 | * )); 38 | * 39 | * // Create a credit card object 40 | * // This card can be used for testing. 41 | * // See https://pin.net.au/docs/api/test-cards for a list of card 42 | * // numbers that can be used for testing. 43 | * $card = new CreditCard(array( 44 | * 'firstName' => 'Example', 45 | * 'lastName' => 'Customer', 46 | * 'number' => '4200000000000000', 47 | * 'expiryMonth' => '01', 48 | * 'expiryYear' => '2020', 49 | * 'cvv' => '123', 50 | * 'email' => 'customer@example.com', 51 | * 'billingAddress1' => '1 Scrubby Creek Road', 52 | * 'billingCountry' => 'AU', 53 | * 'billingCity' => 'Scrubby Creek', 54 | * 'billingPostcode' => '4999', 55 | * 'billingState' => 'QLD', 56 | * )); 57 | * 58 | * $response = $gateway->createCard(array( 59 | * 'card' => $card, 60 | * ))->send(); 61 | * if ($response->isSuccessful()) { 62 | * // Find the card ID 63 | * $card_id = $response->getCardReference(); 64 | * } else { 65 | * echo "Gateway createCard failed.\n"; 66 | * echo "Error message == " . $response->getMessage() . "\n"; 67 | * } 68 | * 69 | * 70 | * @link https://pin.net.au/docs/api/cards 71 | */ 72 | class CreateCardRequest extends AbstractRequest 73 | { 74 | public function getData() 75 | { 76 | $data = array(); 77 | $this->getCard()->validate(); 78 | 79 | $data['number'] = $this->getCard()->getNumber(); 80 | $data['expiry_month'] = $this->getCard()->getExpiryMonth(); 81 | $data['expiry_year'] = $this->getCard()->getExpiryYear(); 82 | $data['cvc'] = $this->getCard()->getCvv(); 83 | $data['name'] = $this->getCard()->getName(); 84 | $data['address_line1'] = $this->getCard()->getAddress1(); 85 | $data['address_line2'] = $this->getCard()->getAddress2(); 86 | $data['address_city'] = $this->getCard()->getCity(); 87 | $data['address_postcode'] = $this->getCard()->getPostcode(); 88 | $data['address_state'] = $this->getCard()->getState(); 89 | $data['address_country'] = $this->getCard()->getCountry(); 90 | 91 | return $data; 92 | } 93 | 94 | public function sendData($data) 95 | { 96 | $httpResponse = $this->sendRequest('/cards', $data); 97 | 98 | return $this->response = new Response($this, $httpResponse->getBody()->getContents()); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/Message/CreateCustomerRequest.php: -------------------------------------------------------------------------------- 1 | 25 | * // Create a gateway for the Pin REST Gateway 26 | * // (routes to GatewayFactory::create) 27 | * $gateway = Omnipay::create('PinGateway'); 28 | * 29 | * // Initialise the gateway 30 | * $gateway->initialize(array( 31 | * 'secretKey' => 'TEST', 32 | * 'testMode' => true, // Or false when you are ready for live transactions 33 | * )); 34 | * 35 | * // Create a credit card object 36 | * // This card can be used for testing. 37 | * // See https://pin.net.au/docs/api/test-cards for a list of card 38 | * // numbers that can be used for testing. 39 | * $card = new CreditCard(array( 40 | * 'firstName' => 'Example', 41 | * 'lastName' => 'Customer', 42 | * 'number' => '4200000000000000', 43 | * 'expiryMonth' => '01', 44 | * 'expiryYear' => '2020', 45 | * 'cvv' => '123', 46 | * 'email' => 'customer@example.com', 47 | * 'billingAddress1' => '1 Scrubby Creek Road', 48 | * 'billingCountry' => 'AU', 49 | * 'billingCity' => 'Scrubby Creek', 50 | * 'billingPostcode' => '4999', 51 | * 'billingState' => 'QLD', 52 | * )); 53 | * 54 | * $response = $gateway->createCustomer(array( 55 | * 'card' => $card, 56 | * ))->send(); 57 | * if ($response->isSuccessful()) { 58 | * // Find the customer ID 59 | * $customer_id = $response->getCustomerToken(); 60 | * } else { 61 | * echo "Gateway createCustomer failed.\n"; 62 | * echo "Error message == " . $response->getMessage() . "\n"; 63 | * } 64 | * 65 | * 66 | * @link https://pin.net.au/docs/api/customers 67 | */ 68 | class CreateCustomerRequest extends AbstractRequest 69 | { 70 | public function getData() 71 | { 72 | $this->validate('email'); 73 | 74 | $data = array(); 75 | 76 | $data['email'] = $this->getEmail(); 77 | 78 | if ($this->getToken()) { 79 | $data['card_token'] = $this->getToken(); 80 | } else { 81 | $this->getCard()->validate(); 82 | 83 | $data['card']['number'] = $this->getCard()->getNumber(); 84 | $data['card']['expiry_month'] = $this->getCard()->getExpiryMonth(); 85 | $data['card']['expiry_year'] = $this->getCard()->getExpiryYear(); 86 | $data['card']['cvc'] = $this->getCard()->getCvv(); 87 | $data['card']['name'] = $this->getCard()->getName(); 88 | $data['card']['address_line1'] = $this->getCard()->getAddress1(); 89 | $data['card']['address_line2'] = $this->getCard()->getAddress2(); 90 | $data['card']['address_city'] = $this->getCard()->getCity(); 91 | $data['card']['address_postcode'] = $this->getCard()->getPostcode(); 92 | $data['card']['address_state'] = $this->getCard()->getState(); 93 | $data['card']['address_country'] = $this->getCard()->getCountry(); 94 | } 95 | 96 | return $data; 97 | } 98 | 99 | public function sendData($data) 100 | { 101 | $httpResponse = $this->sendRequest('/customers', $data); 102 | 103 | return $this->response = new Response($this, $httpResponse->getBody()->getContents()); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /makedoc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Smart little documentation generator. 5 | # GPL/LGPL 6 | # (c) Del 2015 http://www.babel.com.au/ 7 | # 8 | 9 | APPNAME='Omnipay Pin Gateway Module' 10 | CMDFILE=apigen.cmd.$$ 11 | DESTDIR=./documents 12 | 13 | # 14 | # Find apigen, either in the path or as a local phar file 15 | # 16 | if [ -f apigen.phar ]; then 17 | APIGEN="php apigen.phar" 18 | 19 | else 20 | APIGEN=`which apigen` 21 | if [ ! -f "$APIGEN" ]; then 22 | 23 | # Search for phpdoc if apigen is not found. 24 | if [ -f phpDocumentor.phar ]; then 25 | PHPDOC="php phpDocumentor.phar" 26 | 27 | else 28 | PHPDOC=`which phpdoc` 29 | if [ ! -f "$PHPDOC" ]; then 30 | echo "Neither apigen nor phpdoc is installed in the path or locally, please install one of them" 31 | echo "see http://www.apigen.org/ or http://www.phpdoc.org/" 32 | exit 1 33 | fi 34 | fi 35 | fi 36 | fi 37 | 38 | # 39 | # As of version 4 of apigen need to use the generate subcommand 40 | # 41 | if [ ! -z "$APIGEN" ]; then 42 | APIGEN="$APIGEN generate" 43 | fi 44 | 45 | # 46 | # Without any arguments this builds the entire system documentation, 47 | # making the cache file first if required. 48 | # 49 | if [ -z "$1" ]; then 50 | # 51 | # Check to see that the cache has been made. 52 | # 53 | if [ ! -f dirlist.cache ]; then 54 | echo "Making dirlist.cache file" 55 | $0 makecache 56 | fi 57 | 58 | # 59 | # Build the apigen/phpdoc command in a file. 60 | # 61 | if [ ! -z "$APIGEN" ]; then 62 | echo "$APIGEN --php --tree --title '$APPNAME API Documentation' --destination $DESTDIR/main \\" > $CMDFILE 63 | cat dirlist.cache | while read dir; do 64 | echo "--source $dir \\" >> $CMDFILE 65 | done 66 | echo "" >> $CMDFILE 67 | 68 | elif [ ! -z "$PHPDOC" ]; then 69 | echo "$PHPDOC --sourcecode --title '$APPNAME API Documentation' --target $DESTDIR/main --directory \\" > $CMDFILE 70 | cat dirlist.cache | while read dir; do 71 | echo "${dir},\\" >> $CMDFILE 72 | done 73 | echo "" >> $CMDFILE 74 | 75 | else 76 | "Neither apigen nor phpdoc are found, how did I get here?" 77 | exit 1 78 | fi 79 | 80 | # 81 | # Run the apigen command 82 | # 83 | rm -rf $DESTDIR/main 84 | mkdir -p $DESTDIR/main 85 | . ./$CMDFILE 86 | 87 | /bin/rm -f ./$CMDFILE 88 | 89 | # 90 | # The "makecache" argument causes the script to just make the cache file 91 | # 92 | elif [ "$1" = "makecache" ]; then 93 | echo "Find application source directories" 94 | find src -name \*.php -print | \ 95 | ( 96 | while read file; do 97 | grep -q 'class' $file && dirname $file 98 | done 99 | ) | sort -u | \ 100 | grep -v -E 'config|docs|migrations|phpunit|test|Test|views|web' > dirlist.app 101 | 102 | echo "Find vendor source directories" 103 | find vendor -name \*.php -print | \ 104 | ( 105 | while read file; do 106 | grep -q 'class' $file && dirname $file 107 | done 108 | ) | sort -u | \ 109 | grep -v -E 'config|docs|migrations|phpunit|codesniffer|test|Test|views' > dirlist.vendor 110 | 111 | # 112 | # Filter out any vendor directories for which apigen fails 113 | # 114 | echo "Filter source directories" 115 | mkdir -p $DESTDIR/tmp 116 | cat dirlist.app dirlist.vendor | while read dir; do 117 | if [ ! -z "$APIGEN" ]; then 118 | $APIGEN --quiet --title "Test please ignore" \ 119 | --source $dir \ 120 | --destination $DESTDIR/tmp && ( 121 | echo "Including $dir" 122 | echo $dir >> dirlist.cache 123 | ) || ( 124 | echo "Excluding $dir" 125 | ) 126 | 127 | elif [ ! -z "$PHPDOC" ]; then 128 | $PHPDOC --quiet --title "Test please ignore" \ 129 | --directory $dir \ 130 | --target $DESTDIR/tmp && ( 131 | echo "Including $dir" 132 | echo $dir >> dirlist.cache 133 | ) || ( 134 | echo "Excluding $dir" 135 | ) 136 | 137 | fi 138 | done 139 | echo "Documentation cache dirlist.cache built OK" 140 | 141 | # 142 | # Clean up 143 | # 144 | /bin/rm -rf $DESTDIR/tmp 145 | 146 | fi 147 | -------------------------------------------------------------------------------- /src/Message/AuthorizeRequest.php: -------------------------------------------------------------------------------- 1 | 44 | * // Create a gateway for the Pin REST Gateway 45 | * // (routes to GatewayFactory::create) 46 | * $gateway = Omnipay::create('PinGateway'); 47 | * 48 | * // Initialise the gateway 49 | * $gateway->initialize(array( 50 | * 'secretKey' => 'TEST', 51 | * 'testMode' => true, // Or false when you are ready for live transactions 52 | * )); 53 | * 54 | * // Create a credit card object 55 | * // This card can be used for testing. 56 | * // See https://pin.net.au/docs/api/test-cards for a list of card 57 | * // numbers that can be used for testing. 58 | * $card = new CreditCard(array( 59 | * 'firstName' => 'Example', 60 | * 'lastName' => 'Customer', 61 | * 'number' => '4200000000000000', 62 | * 'expiryMonth' => '01', 63 | * 'expiryYear' => '2020', 64 | * 'cvv' => '123', 65 | * 'email' => 'customer@example.com', 66 | * 'billingAddress1' => '1 Scrubby Creek Road', 67 | * 'billingCountry' => 'AU', 68 | * 'billingCity' => 'Scrubby Creek', 69 | * 'billingPostcode' => '4999', 70 | * 'billingState' => 'QLD', 71 | * )); 72 | * 73 | * // Do an authorize transaction on the gateway 74 | * $transaction = $gateway->authorize(array( 75 | * 'description' => 'Your order for widgets', 76 | * 'amount' => '10.00', 77 | * 'currency' => 'AUD', 78 | * 'clientIp' => $_SERVER['REMOTE_ADDR'], 79 | * 'card' => $card, 80 | * )); 81 | * $response = $transaction->send(); 82 | * if ($response->isSuccessful()) { 83 | * echo "Authorize transaction was successful!\n"; 84 | * $sale_id = $response->getTransactionReference(); 85 | * echo "Transaction reference = " . $sale_id . "\n"; 86 | * } 87 | * 88 | * 89 | * @see \Omnipay\Pin\Gateway 90 | * @link https://pin.net.au/docs/api/charges 91 | */ 92 | class AuthorizeRequest extends PurchaseRequest 93 | { 94 | /** 95 | * Get the Capture flag. 96 | * 97 | * Returns the capture parameter, which states whether the charge is 98 | * just an authorisation or it is captured instantly. By default all 99 | * charges are captured. Please note that the return has to be a string 100 | * and not a boolean or Pin's API will disregard it and consider it set 101 | * to 'true' 102 | * 103 | * By default for authorize transactions we return "false". 104 | * 105 | * @return string 106 | */ 107 | public function getCapture() 108 | { 109 | $capture = $this->getParameter('capture'); 110 | 111 | // By default with Pin a transaction is captured. 112 | return $capture === true ? 'true' : 'false'; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /tests/GatewayTest.php: -------------------------------------------------------------------------------- 1 | gateway = new Gateway($this->getHttpClient(), $this->getHttpRequest()); 14 | 15 | $this->options = array( 16 | 'amount' => '10.00', 17 | 'card' => $this->getValidCard(), 18 | 'email' => 'roland@pin.net.au', 19 | 'description' => 'test charge' 20 | ); 21 | } 22 | 23 | public function testPurchaseSuccess() 24 | { 25 | $this->setMockHttpResponse('PurchaseSuccess.txt'); 26 | 27 | $response = $this->gateway->purchase($this->options)->send(); 28 | 29 | $this->assertTrue($response->isSuccessful()); 30 | $this->assertFalse($response->isRedirect()); 31 | $this->assertEquals('ch_fXIxWf0gj1yFHJcV1W-d-w', $response->getTransactionReference()); 32 | $this->assertSame('Success!', $response->getMessage()); 33 | } 34 | 35 | public function testPurchaseError() 36 | { 37 | $this->setMockHttpResponse('PurchaseFailure.txt'); 38 | 39 | $response = $this->gateway->purchase($this->options)->send(); 40 | 41 | $this->assertFalse($response->isSuccessful()); 42 | $this->assertFalse($response->isRedirect()); 43 | $this->assertNull($response->getTransactionReference()); 44 | $this->assertSame('The current resource was deemed invalid.', $response->getMessage()); 45 | } 46 | 47 | public function testRefundSuccess() 48 | { 49 | $this->setMockHttpResponse('RefundSuccess.txt'); 50 | 51 | $response = $this->gateway->refund(array('amount' => '400.00', 'transactionReference' => 'ch_bZ3RhJnIUZ8HhfvH8CCvfA'))->send(); 52 | 53 | $this->assertTrue($response->isSuccessful()); 54 | $this->assertFalse($response->isRedirect()); 55 | $this->assertEquals('rf_ERCQy--Ay6o-NKGiUVcKKA', $response->getTransactionReference()); 56 | $this->assertSame('Pending', $response->getMessage()); 57 | } 58 | 59 | public function testRefundError() 60 | { 61 | $this->setMockHttpResponse('RefundFailure.txt'); 62 | 63 | $response = $this->gateway->refund(array('amount' => '500.00', 'transactionReference' => 'ch_bZ3RhJnIUZ8HhfvH8CCvfA'))->send(); 64 | 65 | $this->assertFalse($response->isSuccessful()); 66 | $this->assertFalse($response->isRedirect()); 67 | $this->assertNull($response->getTransactionReference()); 68 | $this->assertSame('Refund amount is more than your available Pin Payments balance.', $response->getMessage()); 69 | } 70 | 71 | public function testGetCardReferenceSuccess() 72 | { 73 | $this->setMockHttpResponse('CardSuccess.txt'); 74 | 75 | $response = $this->gateway->createCard($this->options)->send(); 76 | 77 | $this->assertTrue($response->isSuccessful()); 78 | $this->assertFalse($response->isRedirect()); 79 | $this->assertEquals('card_8LmnNMTYWG4zQZ4YnYQhBg', $response->getCardReference()); 80 | $this->assertTrue($response->getMessage()); 81 | } 82 | 83 | public function testCreateCardError() 84 | { 85 | $this->setMockHttpResponse('CardFailure.txt'); 86 | 87 | $response = $this->gateway->createCard($this->options)->send(); 88 | 89 | $this->assertFalse($response->isSuccessful()); 90 | $this->assertFalse($response->isRedirect()); 91 | $this->assertNull($response->getCardReference()); 92 | $this->assertSame('One or more parameters were missing or invalid', $response->getMessage()); 93 | } 94 | 95 | public function testCreateCustomerSuccess() 96 | { 97 | $this->setMockHttpResponse('CustomerSuccess.txt'); 98 | 99 | $response = $this->gateway->createCustomer($this->options)->send(); 100 | 101 | $this->assertTrue($response->isSuccessful()); 102 | $this->assertFalse($response->isRedirect()); 103 | $this->assertEquals('cus_Mb-8S1ZgEbLUUUJ97dfhfQ', $response->getCustomerReference()); 104 | $this->assertTrue($response->getMessage()); 105 | } 106 | 107 | public function testCreateCustomerError() 108 | { 109 | $this->setMockHttpResponse('CustomerFailure.txt'); 110 | 111 | $response = $this->gateway->createCustomer($this->options)->send(); 112 | 113 | $this->assertFalse($response->isSuccessful()); 114 | $this->assertFalse($response->isRedirect()); 115 | $this->assertNull($response->getCustomerReference()); 116 | $this->assertSame('One or more parameters were missing or invalid', $response->getMessage()); 117 | } 118 | 119 | public function testCaptureSuccess() 120 | { 121 | $this->setMockHttpResponse('CaptureSuccess.txt'); 122 | 123 | $response = $this->gateway->capture(array('amount' => '400.00', 'transactionReference' => 'ch_bZ3RhJnIUZ8HhfvH8CCvfA'))->send(); 124 | 125 | $this->assertTrue($response->isSuccessful()); 126 | $this->assertFalse($response->isRedirect()); 127 | $this->assertEquals('ch_lfUYEBK14zotCTykezJkfg', $response->getTransactionReference()); 128 | $this->assertTrue($response->getCaptured()); 129 | } 130 | 131 | public function testCaptureError() 132 | { 133 | $this->setMockHttpResponse('CaptureFailure.txt'); 134 | 135 | $response = $this->gateway->capture(array('amount' => '400.00', 'transactionReference' => 'ch_lfUYEBK14zotCTykezJkfg'))->send(); 136 | 137 | $this->assertFalse($response->isSuccessful()); 138 | $this->assertFalse($response->isRedirect()); 139 | $this->assertNull($response->getTransactionReference()); 140 | $this->assertSame('The authorisation has expired and can not be captured.', $response->getMessage()); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/Gateway.php: -------------------------------------------------------------------------------- 1 | 20 | * // Create a gateway for the Pin REST Gateway 21 | * // (routes to GatewayFactory::create) 22 | * $gateway = Omnipay::create('PinGateway'); 23 | * 24 | * // Initialise the gateway 25 | * $gateway->initialize(array( 26 | * 'secretKey' => 'TEST', 27 | * 'testMode' => true, // Or false when you are ready for live transactions 28 | * )); 29 | * 30 | * // Create a credit card object 31 | * // This card can be used for testing. 32 | * // See https://pin.net.au/docs/api/test-cards for a list of card 33 | * // numbers that can be used for testing. 34 | * $card = new CreditCard(array( 35 | * 'firstName' => 'Example', 36 | * 'lastName' => 'Customer', 37 | * 'number' => '4200000000000000', 38 | * 'expiryMonth' => '01', 39 | * 'expiryYear' => '2020', 40 | * 'cvv' => '123', 41 | * 'email' => 'customer@example.com', 42 | * 'billingAddress1' => '1 Scrubby Creek Road', 43 | * 'billingCountry' => 'AU', 44 | * 'billingCity' => 'Scrubby Creek', 45 | * 'billingPostcode' => '4999', 46 | * 'billingState' => 'QLD', 47 | * )); 48 | * 49 | * // Do a purchase transaction on the gateway 50 | * $transaction = $gateway->purchase(array( 51 | * 'description' => 'Your order for widgets', 52 | * 'amount' => '10.00', 53 | * 'currency' => 'AUD', 54 | * 'clientIp' => $_SERVER['REMOTE_ADDR'], 55 | * 'card' => $card, 56 | * )); 57 | * $response = $transaction->send(); 58 | * if ($response->isSuccessful()) { 59 | * echo "Purchase transaction was successful!\n"; 60 | * $sale_id = $response->getTransactionReference(); 61 | * echo "Transaction reference = " . $sale_id . "\n"; 62 | * } 63 | * 64 | * 65 | * ### Test modes 66 | * 67 | * The API has two endpoint host names: 68 | * 69 | * * api.pin.net.au (live) 70 | * * test-api.pin.net.au (test) 71 | * 72 | * The live host is for processing live transactions, whereas the test 73 | * host can be used for integration testing and development. 74 | * 75 | * Each endpoint requires a different set of API keys, which can be 76 | * found in your account settings. 77 | * 78 | * ### Authentication 79 | * 80 | * Calls to the Pin Payments API must be authenticated using HTTP 81 | * basic authentication, with your API key as the username, and 82 | * a blank string as the password. 83 | * 84 | * #### Keys 85 | * 86 | * Your account has two types of keys: 87 | * 88 | * * publishable 89 | * * secret 90 | * 91 | * You can find your keys on the account settings page of the dashboard 92 | * after you have created an account at pin.net.au and logged in. 93 | * 94 | * Your secret key can be used with all of the API, and must be kept 95 | * secure and secret at all times. You use your secret key from your 96 | * server to create charges and refunds. 97 | * 98 | * Your publishable key can be used from insecure locations (such as 99 | * browsers or mobile apps) to create cards with the cards API. This 100 | * is the key you use with Pin.js to create secure payment forms in 101 | * the browser. 102 | * 103 | * @see \Omnipay\Common\AbstractGateway 104 | * @link https://pin.net.au/docs/api 105 | */ 106 | class Gateway extends AbstractGateway 107 | { 108 | public function getName() 109 | { 110 | return 'Pin'; 111 | } 112 | 113 | public function getDefaultParameters() 114 | { 115 | return array( 116 | 'secretKey' => '', 117 | 'testMode' => false, 118 | ); 119 | } 120 | 121 | /** 122 | * Get secret key 123 | * 124 | * Calls to the Pin Payments API must be authenticated using HTTP 125 | * basic authentication, with your API key as the username, and 126 | * a blank string as the password. 127 | * 128 | * @return string 129 | */ 130 | public function getSecretKey() 131 | { 132 | return $this->getParameter('secretKey'); 133 | } 134 | 135 | /** 136 | * Set secret key 137 | * 138 | * Calls to the Pin Payments API must be authenticated using HTTP 139 | * basic authentication, with your API key as the username, and 140 | * a blank string as the password. 141 | * 142 | * @param string $value 143 | * @return Gateway implements a fluent interface 144 | */ 145 | public function setSecretKey($value) 146 | { 147 | return $this->setParameter('secretKey', $value); 148 | } 149 | 150 | /** 151 | * Create a purchase request 152 | * 153 | * @param array $parameters 154 | * @return \Omnipay\Pin\Message\PurchaseRequest 155 | */ 156 | public function purchase(array $parameters = array()) 157 | { 158 | return $this->createRequest('\Omnipay\Pin\Message\PurchaseRequest', $parameters); 159 | } 160 | 161 | /** 162 | * Create an authorize request 163 | * 164 | * @param array $parameters 165 | * @return \Omnipay\Pin\Message\AuthorizeRequest 166 | */ 167 | public function authorize(array $parameters = array()) 168 | { 169 | return $this->createRequest('\Omnipay\Pin\Message\AuthorizeRequest', $parameters); 170 | } 171 | 172 | /** 173 | * Create a capture request 174 | * 175 | * @param array $parameters 176 | * @return \Omnipay\Pin\Message\CaptureRequest 177 | */ 178 | public function capture(array $parameters = array()) 179 | { 180 | return $this->createRequest('\Omnipay\Pin\Message\CaptureRequest', $parameters); 181 | } 182 | 183 | /** 184 | * Create a refund request 185 | * 186 | * @param array $parameters 187 | * @return \Omnipay\Pin\Message\RefundRequest 188 | */ 189 | public function refund(array $parameters = array()) 190 | { 191 | return $this->createRequest('\Omnipay\Pin\Message\RefundRequest', $parameters); 192 | } 193 | 194 | /** 195 | * Create a createCustomer request 196 | * 197 | * @param array $parameters 198 | * @return \Omnipay\Pin\Message\CreateCustomerRequest 199 | */ 200 | public function createCustomer(array $parameters = array()) 201 | { 202 | return $this->createRequest('\Omnipay\Pin\Message\CreateCustomerRequest', $parameters); 203 | } 204 | 205 | /** 206 | * Create a createCard request 207 | * 208 | * @param array $parameters 209 | * @return \Omnipay\Pin\Message\CreateCardRequest 210 | */ 211 | public function createCard(array $parameters = array()) 212 | { 213 | return $this->createRequest('\Omnipay\Pin\Message\CreateCardRequest', $parameters); 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /src/Message/PurchaseRequest.php: -------------------------------------------------------------------------------- 1 | 44 | * // Create a gateway for the Pin REST Gateway 45 | * // (routes to GatewayFactory::create) 46 | * $gateway = Omnipay::create('PinGateway'); 47 | * 48 | * // Initialise the gateway 49 | * $gateway->initialize(array( 50 | * 'secretKey' => 'TEST', 51 | * 'testMode' => true, // Or false when you are ready for live transactions 52 | * )); 53 | * 54 | * // Create a credit card object 55 | * // This card can be used for testing. 56 | * // See https://pin.net.au/docs/api/test-cards for a list of card 57 | * // numbers that can be used for testing. 58 | * $card = new CreditCard(array( 59 | * 'firstName' => 'Example', 60 | * 'lastName' => 'Customer', 61 | * 'number' => '4200000000000000', 62 | * 'expiryMonth' => '01', 63 | * 'expiryYear' => '2020', 64 | * 'cvv' => '123', 65 | * 'email' => 'customer@example.com', 66 | * 'billingAddress1' => '1 Scrubby Creek Road', 67 | * 'billingCountry' => 'AU', 68 | * 'billingCity' => 'Scrubby Creek', 69 | * 'billingPostcode' => '4999', 70 | * 'billingState' => 'QLD', 71 | * )); 72 | * 73 | * // Do a purchase transaction on the gateway 74 | * $transaction = $gateway->purchase(array( 75 | * 'description' => 'Your order for widgets', 76 | * 'amount' => '10.00', 77 | * 'currency' => 'AUD', 78 | * 'clientIp' => $_SERVER['REMOTE_ADDR'], 79 | * 'card' => $card, 80 | * )); 81 | * $response = $transaction->send(); 82 | * if ($response->isSuccessful()) { 83 | * echo "Purchase transaction was successful!\n"; 84 | * $sale_id = $response->getTransactionReference(); 85 | * echo "Transaction reference = " . $sale_id . "\n"; 86 | * } 87 | * 88 | * 89 | * @see \Omnipay\Pin\Gateway 90 | * @link https://pin.net.au/docs/api/charges 91 | */ 92 | class PurchaseRequest extends AbstractRequest 93 | { 94 | public function getData() 95 | { 96 | $data = array(); 97 | $this->validate('amount', 'description'); 98 | 99 | $data = array(); 100 | 101 | $data['amount'] = $this->getAmountInteger(); 102 | $data['currency'] = strtolower($this->getCurrency()); 103 | $data['description'] = $this->getDescription(); 104 | $data['ip_address'] = $this->getClientIp(); 105 | $data['capture'] = $this->getCapture(); 106 | 107 | // Token payments. Really should use cardReference as the token 108 | // parameter but historically this has used token instead, so allow 109 | // both. 110 | $token = $this->getCardReference(); 111 | if (empty($token)) { 112 | $token = $this->getToken(); 113 | } 114 | if (! empty($token)) { 115 | if (strpos($token, 'card_') !== false) { 116 | $data['card_token'] = $token; 117 | } else { 118 | $data['customer_token'] = $token; 119 | } 120 | 121 | // Supply an email address if provided, but it is not required 122 | if ($this->getEmail()) { 123 | $data['email'] = $this->getEmail(); 124 | } 125 | 126 | // Card payments 127 | } else { 128 | $this->validate('card'); 129 | $this->getCard()->validate(); 130 | 131 | // An email address is required 132 | if ($this->getCard()->getEmail()) { 133 | $data['email'] = $this->getCard()->getEmail(); 134 | } elseif ($this->getEmail()) { 135 | $data['email'] = $this->getEmail(); 136 | } else { 137 | $this->validate('email'); 138 | } 139 | 140 | $data['card']['number'] = $this->getCard()->getNumber(); 141 | $data['card']['expiry_month'] = $this->getCard()->getExpiryMonth(); 142 | $data['card']['expiry_year'] = $this->getCard()->getExpiryYear(); 143 | $data['card']['cvc'] = $this->getCard()->getCvv(); 144 | $data['card']['name'] = $this->getCard()->getName(); 145 | $data['card']['address_line1'] = $this->getCard()->getAddress1(); 146 | $data['card']['address_line2'] = $this->getCard()->getAddress2(); 147 | $data['card']['address_city'] = $this->getCard()->getCity(); 148 | $data['card']['address_postcode'] = $this->getCard()->getPostcode(); 149 | $data['card']['address_state'] = $this->getCard()->getState(); 150 | $data['card']['address_country'] = $this->getCard()->getCountry(); 151 | } 152 | 153 | return $data; 154 | } 155 | 156 | public function sendData($data) 157 | { 158 | $httpResponse = $this->sendRequest('/charges', $data); 159 | 160 | return $this->response = new Response($this, $httpResponse->getBody()->getContents()); 161 | } 162 | 163 | /** 164 | * Get the Capture flag. 165 | * 166 | * Returns the capture parameter, which states whether the charge is 167 | * just an authorisation or it is captured instantly. By default all 168 | * charges are captured. Please note that the return has to be a string 169 | * and not a boolean or Pin's API will disregard it and consider it set 170 | * to 'true' 171 | * 172 | * @return string 173 | */ 174 | public function getCapture() 175 | { 176 | $capture = $this->getParameter('capture'); 177 | 178 | // By default with Pin a transaction is captured. 179 | return $capture === false ? 'false' : 'true'; 180 | } 181 | 182 | /** 183 | * Set the capture flag. 184 | * 185 | * This flag states whether the charge is just an authorisation or it is 186 | * captured instantly. By default all charges are captured. 187 | * 188 | * @param $value 189 | * 190 | * @return PurchaseRequest provides a fluent interface 191 | */ 192 | public function setCapture($value) 193 | { 194 | return $this->setParameter('capture', $value); 195 | } 196 | } 197 | --------------------------------------------------------------------------------