├── .gitignore ├── .styleci.yml ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── composer.json ├── phpunit.xml.dist ├── runtests-win.sh ├── runtests.sh ├── src ├── ConnectGateway.php ├── GlobalGateway.php ├── Message │ ├── CompletePurchaseRequest.php │ ├── CompletePurchaseResponse.php │ ├── PayeezyAbstractRequest.php │ ├── PayeezyAuthorizeRequest.php │ ├── PayeezyCaptureRequest.php │ ├── PayeezyPurchaseRequest.php │ ├── PayeezyRefundRequest.php │ ├── PayeezyResponse.php │ ├── PayeezyVoidRequest.php │ ├── PurchaseRequest.php │ ├── PurchaseResponse.php │ ├── WebserviceAbstractRequest.php │ ├── WebserviceAuthorizeRequest.php │ ├── WebserviceCaptureRequest.php │ ├── WebservicePurchaseRequest.php │ ├── WebserviceRefundRequest.php │ ├── WebserviceResponse.php │ └── WebserviceVoidRequest.php ├── PayeezyGateway.php └── WebserviceGateway.php └── tests ├── GatewayTest.php ├── Message ├── CompletePurchaseResponseTest.php ├── PayeezyAuthorizeRequestTest.php ├── PayeezyPurchaseRequestTest.php ├── PayeezyPurchaseResponseTest.php ├── PayeezyRefundRequestTest.php ├── PurchaseResponseTest.php ├── WebserviceCaptureRequestTest.php ├── WebservicePurchaseRequestTest.php ├── WebserviceRefundRequestTest.php └── WebserviceVoidRequestTest.php ├── Mock ├── PurchaseSuccess.txt ├── RefundError.txt ├── RefundSuccess.txt └── WebservicePurchaseSuccess.txt ├── PayeezyGatewayTest.php └── WebserviceGatewayTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | composer.lock 3 | composer.phar 4 | phpunit.xml 5 | .directory 6 | .idea 7 | /documents 8 | dirlist.app 9 | dirlist.cache 10 | dirlist.vendor 11 | -------------------------------------------------------------------------------- /.styleci.yml: -------------------------------------------------------------------------------- 1 | preset: psr2 2 | 3 | risky: false 4 | 5 | linting: true 6 | 7 | enabled: 8 | - long_array_syntax 9 | - align_double_arrow 10 | - binary_operator_spaces 11 | - no_empty_statement 12 | - no_singleline_whitespace_before_semicolons 13 | - no_whitespace_in_blank_line 14 | - align_equals 15 | - not_operator_with_successor_space 16 | - linebreak_after_opening_tag 17 | - ordered_imports 18 | 19 | finder: 20 | exclude: 21 | - "tests" 22 | name: 23 | - "*.php" 24 | -------------------------------------------------------------------------------- /.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 | # This triggers builds to run on the new TravisCI infrastructure. 11 | # See: http://docs.travis-ci.com/user/workers/container-based-infrastructure/ 12 | sudo: false 13 | 14 | ## Cache composer 15 | cache: 16 | directories: 17 | - $HOME/.composer/cache 18 | 19 | env: 20 | global: 21 | - symfony="*" 22 | 23 | matrix: 24 | include: 25 | - php: 5.6 26 | env: symfony="^2.1" 27 | - php: 5.6 28 | env: symfony="^3" 29 | - php: 7.1 30 | env: symfony="^4" 31 | 32 | install: 33 | - if [[ $symfony != '*' ]]; then travis_retry composer require symfony/http-foundation:${symfony} --no-update --no-interaction; fi 34 | 35 | script: composer install --prefer-dist --no-interaction 36 | -------------------------------------------------------------------------------- /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: First Data 2 | 3 | **First Data driver for the Omnipay PHP payment processing library** 4 | 5 | [![Build Status](https://travis-ci.org/thephpleague/omnipay-firstdata.png?branch=master)](https://travis-ci.org/thephpleague/omnipay-firstdata) 6 | [![Latest Stable Version](https://poser.pugx.org/omnipay/firstdata/version.png)](https://packagist.org/packages/omnipay/firstdata) 7 | [![Total Downloads](https://poser.pugx.org/omnipay/firstdata/d/total.png)](https://packagist.org/packages/omnipay/firstdata) 8 | 9 | [Omnipay](https://github.com/thephpleague/omnipay) is a framework agnostic, multi-gateway payment 10 | processing library for PHP. This package implements First Data 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/firstdata": "~3.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 | * FirstData_Connect 35 | * FirstData_Webservice 36 | * FirstData_Payeezy 37 | 38 | For general usage instructions, please see the main [Omnipay](https://github.com/thephpleague/omnipay) 39 | repository. 40 | 41 | ## References 42 | 43 | First Data Corporation is a global payment technology solutions company headquartered in Atlanta, Georgia, 44 | United States. First Data Corporation was incorporated in 1971. In 1980, American Express Information 45 | Services Corporation (ISC) bought 80% of First Data. First Data Corporation spun off from American Express 46 | and went public in 1992. 47 | 48 | The First Data Global Gateway Connect 2.0 is a simple payment solution for connecting an online store to 49 | the First Data Global Gateway. It provides redirect based payments (purchase() method with a corresponding 50 | completePurchase() method). It is referred to here as the "First Data Connect" gateway, currently at 51 | version 2.0. 52 | 53 | The Global Gateway was originally called the LinkPoint Gateway but since First Data's acquisition of 54 | LinkPoint it is now known as the First Data Global Gateway. As of this writing the Global Gateway version 55 | 9.0 is supported. It is referred to here as the "First Data Webservice" gateway, more correctly speaking 56 | it is the "First Data Global Web Services API", currently at version 9.0 57 | 58 | The First Data Global Gateway e4 (previously referred to as "First Data Global", and so if you see 59 | internet references to the First Data Global Gateway, they are probably referring to this one, distinguished 60 | by having URLs like "api.globalgatewaye4.firstdata.com") is now called the Payeezy Gateway and is 61 | referred to here as the "First Data Payeezy" Gateway. 62 | 63 | The Connect, Global, and Payeezy gateways are implemented here although each have gone through a number 64 | of API changes since their initial releases. 65 | 66 | The First Data APIs are listed here: 67 | 68 | https://www.firstdata.com/en_us/customer-center/merchants/first-data-global-gateway-api-software-landing.html 69 | 70 | ### First Data Connect 2.0 71 | 72 | The First Data Connect 2.0 Integration guide is here: 73 | 74 | https://www.firstdata.com/downloads/pdf/FDGG_Connect_2.0_Integration_Manual_v2.0.pdf 75 | 76 | ### First Data Global Web Services API 9.0 77 | 78 | The Global Webservice API description is here: 79 | 80 | https://www.firstdata.com/downloads/pdf/FDGG_Web_Service_API_v9.0.pdf 81 | 82 | The API manual for an older (v1.1) version of the same can be found here: 83 | 84 | https://www.firstdata.com/downloads/marketing-merchant/fd_globalgatewayapi_usermanual.pdf 85 | 86 | Reference code that implements connections to this gateway can be found at: 87 | 88 | * http://ashokks.com/First-Data-Global-Gateway-Web-Service-API-Complete-PHP-Example 89 | 90 | # First Data Payeezy Gateway 91 | 92 | API details for the Payeezy gateway are here: 93 | 94 | https://support.payeezy.com/hc/en-us 95 | 96 | and here: 97 | 98 | https://support.payeezy.com/hc/en-us/articles/204029989-First-Data-Payeezy-Gateway-Web-Service-API-Reference-Guide- 99 | 100 | Reference code that implements connections to this gateway can be found at: 101 | 102 | * https://github.com/VinceG/php-first-data-api 103 | * https://github.com/loganhenson/firstdata 104 | 105 | ## Support 106 | 107 | If you are having general issues with Omnipay, we suggest posting on 108 | [Stack Overflow](http://stackoverflow.com/). Be sure to add the 109 | [omnipay tag](http://stackoverflow.com/questions/tagged/omnipay) so it can be easily found. 110 | 111 | If you want to keep up to date with release anouncements, discuss ideas for the project, 112 | or ask more detailed questions, there is also a [mailing list](https://groups.google.com/forum/#!forum/omnipay) which 113 | you can subscribe to. 114 | 115 | If you believe you have found a bug, please report it using the [GitHub issue tracker](https://github.com/thephpleague/omnipay-firstdata/issues), 116 | or better yet, fork the library and submit a pull request. 117 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "omnipay/firstdata", 3 | "type": "library", 4 | "description": "First Data driver for the Omnipay payment processing library", 5 | "keywords": [ 6 | "first data", 7 | "firstdata", 8 | "gateway", 9 | "merchant", 10 | "omnipay", 11 | "pay", 12 | "payment" 13 | ], 14 | "homepage": "https://github.com/thephpleague/omnipay-firstdata", 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-firstdata/contributors" 24 | } 25 | ], 26 | "autoload": { 27 | "psr-4": { "Omnipay\\FirstData\\" : "src/" } 28 | }, 29 | "require": { 30 | "php": "^5.6|^7", 31 | "omnipay/common": "~3.0", 32 | "php-http/guzzle6-adapter": "^1.1" 33 | }, 34 | "require-dev": { 35 | "omnipay/tests": "~3.1" 36 | }, 37 | "extra": { 38 | "branch-alias": { 39 | "dev-master": "3.0.x-dev" 40 | } 41 | }, 42 | "prefer-stable": true 43 | } 44 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | ./tests/ 15 | 16 | 17 | 18 | 19 | ./src 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /runtests-win.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 | # Ensure that dependencies are installed (including codeception and phpunit) 11 | # 12 | if [ -f composer.lock ]; then 13 | composer install 14 | else 15 | composer update 16 | fi 17 | 18 | # 19 | # Clean up after any previous test runs 20 | # 21 | mkdir -p documents 22 | rm -rf documents/coverage-html-new 23 | rm -f documents/coverage.xml 24 | 25 | # 26 | # Run phpunit 27 | # 28 | vendor/bin/phpunit --coverage-html documents/coverage-html-new --coverage-clover documents/coverage.xml --log-junit documents/phpunit.xml 29 | 30 | if [ -d documents/coverage-html-new ]; then 31 | rm -rf documents/coverage-html 32 | mv documents/coverage-html-new documents/coverage-html 33 | fi 34 | 35 | -------------------------------------------------------------------------------- /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 | # Ensure that dependencies are installed (including codeception and phpunit) 11 | # 12 | if [ -f composer.lock ]; then 13 | /usr/local/bin/composer install 14 | else 15 | /usr/local/bin/composer update 16 | fi 17 | 18 | # 19 | # Clean up after any previous test runs 20 | # 21 | mkdir -p documents 22 | rm -rf documents/coverage-html-new 23 | rm -f documents/coverage.xml 24 | 25 | # 26 | # Run phpunit 27 | # 28 | vendor/bin/phpunit --coverage-html documents/coverage-html-new --coverage-clover documents/coverage.xml --log-junit documents/phpunit.xml 29 | 30 | if [ -d documents/coverage-html-new ]; then 31 | rm -rf documents/coverage-html 32 | mv documents/coverage-html-new documents/coverage-html 33 | fi 34 | 35 | -------------------------------------------------------------------------------- /src/ConnectGateway.php: -------------------------------------------------------------------------------- 1 | 59 | * // Create a gateway for the First Data Connect Gateway 60 | * // (routes to GatewayFactory::create) 61 | * $gateway = Omnipay::create('FirstData_Connect'); 62 | * 63 | * // Initialise the gateway 64 | * $gateway->initialize(array( 65 | * 'storeId' => '12341234', 66 | * 'sharedSecret' => 'IcantTELLyouITSaSECRET', 67 | * 'testMode' => true, // Or false when you are ready for live transactions 68 | * )); 69 | * 70 | * // Do a purchase transaction on the gateway 71 | * $transaction = $gateway->purchase(array( 72 | * 'description' => 'Your order for widgets', 73 | * 'amount' => '10.00', 74 | * 'transactionId' => 12345, 75 | * )); 76 | * $response = $transaction->send(); 77 | * if ($response->isSuccessful()) { 78 | * echo "Purchase transaction was successful!\n"; 79 | * $sale_id = $response->getTransactionReference(); 80 | * echo "Transaction reference = " . $sale_id . "\n"; 81 | * } 82 | * 83 | * 84 | * @link https://www.firstdata.com/downloads/pdf/FDGG_Connect_2.0_Integration_Manual_v2.0.pdf 85 | */ 86 | class ConnectGateway extends AbstractGateway 87 | { 88 | public function getName() 89 | { 90 | return 'First Data Connect'; 91 | } 92 | 93 | public function getDefaultParameters() 94 | { 95 | return array( 96 | 'storeId' => '', 97 | 'sharedSecret' => '', 98 | 'testMode' => false, 99 | ); 100 | } 101 | 102 | /** 103 | * Set Store ID 104 | * 105 | * Calls to the Connect Gateway API are secured with a store ID and 106 | * shared secret. 107 | * 108 | * @return ConnectGateway provides a fluent interface 109 | */ 110 | public function setStoreId($value) 111 | { 112 | return $this->setParameter('storeId', $value); 113 | } 114 | 115 | /** 116 | * Get Store ID 117 | * 118 | * Calls to the Connect Gateway API are secured with a store ID and 119 | * shared secret. 120 | * 121 | * @return string 122 | */ 123 | public function getStoreId() 124 | { 125 | return $this->getParameter('storeId'); 126 | } 127 | 128 | /** 129 | * Set Shared Secret 130 | * 131 | * Calls to the Connect Gateway API are secured with a store ID and 132 | * shared secret. 133 | * 134 | * @return ConnectGateway provides a fluent interface 135 | */ 136 | public function setSharedSecret($value) 137 | { 138 | return $this->setParameter('sharedSecret', $value); 139 | } 140 | 141 | /** 142 | * Get Shared Secret 143 | * 144 | * Calls to the Connect Gateway API are secured with a store ID and 145 | * shared secret. 146 | * 147 | * @return string 148 | */ 149 | public function getSharedSecret() 150 | { 151 | return $this->getParameter('sharedSecret'); 152 | } 153 | 154 | /** 155 | * Create a purchase request. 156 | * 157 | * @param array $parameters 158 | * @return \Omnipay\FirstData\Message\PurchaseRequest 159 | */ 160 | public function purchase(array $parameters = array()) 161 | { 162 | return $this->createRequest('\Omnipay\FirstData\Message\PurchaseRequest', $parameters); 163 | } 164 | 165 | /** 166 | * Create a complete purchase request. 167 | * 168 | * @param array $parameters 169 | * @return \Omnipay\FirstData\Message\CompletePurchaseRequest 170 | */ 171 | public function completePurchase(array $parameters = array()) 172 | { 173 | return $this->createRequest('\Omnipay\FirstData\Message\CompletePurchaseRequest', $parameters); 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /src/GlobalGateway.php: -------------------------------------------------------------------------------- 1 | httpRequest->request->get('response_hash'); 18 | $dateTime = (string) $this->httpRequest->request->get('txndatetime'); 19 | $amount = (string) $this->httpRequest->request->get('chargetotal'); 20 | $code = (string) $this->httpRequest->request->get('approval_code'); 21 | $ourHash = $this->createResponseHash($amount, $dateTime, $code); 22 | if ($theirHash !== $ourHash) { 23 | throw new InvalidResponseException("Callback hash does not match expected value"); 24 | } 25 | 26 | return $this->httpRequest->request->all(); 27 | } 28 | 29 | public function sendData($data) 30 | { 31 | return $this->response = new CompletePurchaseResponse($this, $data); 32 | } 33 | 34 | /** 35 | * Generate a hash string that matches the format of the one returned by the payment gateway 36 | * 37 | * @param string $amount 38 | * @param string $dateTime 39 | * @param string $code 40 | * @return string 41 | */ 42 | public function createResponseHash($amount, $dateTime, $code) 43 | { 44 | $this->validate('storeId', 'sharedSecret', 'currency'); 45 | 46 | $storeId = $this->getStoreId(); 47 | $sharedSecret = $this->getSharedSecret(); 48 | $currency = $this->getCurrencyNumeric(); 49 | 50 | $stringToHash = $sharedSecret . $code . $amount . $currency . $dateTime . $storeId; 51 | $ascii = bin2hex($stringToHash); 52 | 53 | return sha1($ascii); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Message/CompletePurchaseResponse.php: -------------------------------------------------------------------------------- 1 | data['status']) && $this->data['status'] == 'APPROVED'; 18 | } 19 | 20 | public function getTransactionId() 21 | { 22 | return isset($this->data['oid']) ? $this->data['oid'] : null; 23 | } 24 | 25 | public function getTransactionReference() 26 | { 27 | return isset($this->data['refnumber']) ? $this->data['refnumber'] : null; 28 | } 29 | 30 | public function getMessage() 31 | { 32 | return isset($this->data['status']) ? $this->data['status'] : null; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Message/PayeezyAbstractRequest.php: -------------------------------------------------------------------------------- 1 | 'Visa', 54 | 'mastercard' => 'Mastercard', 55 | 'discover' => 'Discover', 56 | 'amex' => 'American Express', 57 | 'diners_club' => 'Diners Club', 58 | 'jcb' => 'JCB', 59 | ); 60 | 61 | /** 62 | * Get Gateway ID 63 | * 64 | * Calls to the Payeezy Gateway API are secured with a gateway ID and 65 | * password. 66 | * 67 | * @return string 68 | */ 69 | public function getGatewayId() 70 | { 71 | return $this->getParameter('gatewayId'); 72 | } 73 | 74 | /** 75 | * Set Gateway ID 76 | * 77 | * Calls to the Payeezy Gateway API are secured with a gateway ID and 78 | * password. 79 | * 80 | * @return PayeezyAbstractRequest provides a fluent interface. 81 | */ 82 | public function setGatewayId($value) 83 | { 84 | return $this->setParameter('gatewayId', $value); 85 | } 86 | 87 | /** 88 | * Get Password 89 | * 90 | * Calls to the Payeezy Gateway API are secured with a gateway ID and 91 | * password. 92 | * 93 | * @return string 94 | */ 95 | public function getPassword() 96 | { 97 | return $this->getParameter('password'); 98 | } 99 | 100 | /** 101 | * Set Password 102 | * 103 | * Calls to the Payeezy Gateway API are secured with a gateway ID and 104 | * password. 105 | * 106 | * @return PayeezyAbstractRequest provides a fluent interface. 107 | */ 108 | public function setPassword($value) 109 | { 110 | return $this->setParameter('password', $value); 111 | } 112 | 113 | /** 114 | * Get Key Id 115 | * 116 | * Calls to the Payeezy Gateway API are secured with a gateway ID and 117 | * password. 118 | * 119 | * @return mixed 120 | */ 121 | public function getKeyId() 122 | { 123 | return $this->getParameter('keyId'); 124 | } 125 | 126 | /** 127 | * Set Key Id 128 | * 129 | * Calls to the Payeezy Gateway API are secured with a gateway ID and 130 | * password. 131 | * 132 | * @return PayeezyAbstractRequest provides a fluent interface. 133 | */ 134 | public function setKeyId($value) 135 | { 136 | return $this->setParameter('keyId', $value); 137 | } 138 | 139 | /** 140 | * Get Hmac 141 | * 142 | * Calls to the Payeezy Gateway API are secured with a gateway ID and 143 | * password. 144 | * 145 | * @return mixed 146 | */ 147 | public function getHmac() 148 | { 149 | return $this->getParameter('hmac'); 150 | } 151 | 152 | /** 153 | * Set Hmac 154 | * 155 | * Calls to the Payeezy Gateway API are secured with a gateway ID and 156 | * password. 157 | * 158 | * @return PayeezyAbstractRequest provides a fluent interface. 159 | */ 160 | public function setHmac($value) 161 | { 162 | return $this->setParameter('hmac', $value); 163 | } 164 | 165 | /** 166 | * Set transaction type 167 | * 168 | * @param int $transactionType 169 | * 170 | * @return PayeezyAbstractRequest provides a fluent interface. 171 | */ 172 | public function setTransactionType($transactionType) 173 | { 174 | $this->transactionType = $transactionType; 175 | return $this; 176 | } 177 | 178 | /** 179 | * Get transaction type 180 | * 181 | * @return int 182 | */ 183 | public function getTransactionType() 184 | { 185 | return $this->transactionType; 186 | } 187 | 188 | /** 189 | * Get the base transaction data. 190 | * 191 | * @return array 192 | */ 193 | protected function getBaseData() 194 | { 195 | $data = array(); 196 | $data['gateway_id'] = $this->getGatewayID(); 197 | $data['password'] = $this->getPassword(); 198 | $data['transaction_type'] = $this->getTransactionType(); 199 | 200 | return $data; 201 | } 202 | 203 | /** 204 | * Get the transaction headers. 205 | * 206 | * @return array 207 | */ 208 | protected function getHeaders() 209 | { 210 | return array( 211 | 'Content-Type' => self::CONTENT_TYPE, 212 | 'Accept' => 'application/json' 213 | ); 214 | } 215 | 216 | /** 217 | * @return string 218 | */ 219 | protected function getGge4Date() 220 | { 221 | return gmdate("Y-m-d") . 'T' . gmdate("H:i:s") . 'Z'; 222 | } 223 | 224 | /** 225 | * Composes the hash string needed for the newer versions of the API 226 | * 227 | * @param $contentDigest 228 | * @param $gge4Date 229 | * @param $uri 230 | * 231 | * @return string 232 | */ 233 | protected function buildHashString($contentDigest, $gge4Date, $uri) 234 | { 235 | return sprintf( 236 | "%s\n%s\n%s\n%s\n%s", 237 | self::METHOD_POST, 238 | self::CONTENT_TYPE, 239 | $contentDigest, 240 | $gge4Date, 241 | $uri 242 | ); 243 | } 244 | 245 | /** 246 | * Composes the auth string needed for the newer versions of the API 247 | * 248 | * @param $hashString 249 | * 250 | * @return string 251 | */ 252 | protected function buildAuthString($hashString) 253 | { 254 | return sprintf( 255 | 'GGE4_API %s:%s', 256 | $this->getKeyId(), 257 | base64_encode(hash_hmac("sha1", $hashString, $this->getHmac(), true)) 258 | ); 259 | } 260 | 261 | /** 262 | * Get the card type name, from the card type code. 263 | * 264 | * @param string $type 265 | * 266 | * @return string 267 | */ 268 | public static function getCardType($type) 269 | { 270 | if (isset(self::$cardTypes[$type])) { 271 | return self::$cardTypes[$type]; 272 | } 273 | return $type; 274 | } 275 | 276 | /** 277 | * Get the AVS Hash. 278 | * 279 | * Important Note about v12 or higher of the Web Service API: Merchants wishing to use 280 | * V12 or higher of the API must implement the API HMAC hash security calculation. 281 | * Further information on this subject can be found at the link below. 282 | * 283 | * @link https://support.payeezy.com/entries/22069302-api-security-hmac-hash 284 | * 285 | * @return string 286 | */ 287 | public function getAVSHash() 288 | { 289 | $parts = array(); 290 | $parts[] = $this->getCard()->getAddress1(); 291 | $parts[] = $this->getCard()->getPostcode(); 292 | $parts[] = $this->getCard()->getCity(); 293 | $parts[] = $this->getCard()->getState(); 294 | $parts[] = $this->getCard()->getCountry(); 295 | return implode('|', $parts); 296 | } 297 | 298 | /** 299 | * @return array 300 | */ 301 | public function getData() 302 | { 303 | $this->setTransactionType($this->action); 304 | $data = $this->getBaseData(); 305 | return $data; 306 | } 307 | 308 | /** 309 | * @param mixed $data 310 | * 311 | * @return PayeezyResponse 312 | */ 313 | public function sendData($data) 314 | { 315 | $headers = $this->getHeaders(); 316 | $gge4Date = $this->getGge4Date(); 317 | $endpoint = $this->getEndpoint(); 318 | 319 | $url = parse_url($endpoint); 320 | 321 | $contentDigest = sha1(json_encode($data)); 322 | 323 | $hashString = $this->buildHashString($contentDigest, $gge4Date, $url['path']); 324 | 325 | $authString = $this->buildAuthString($hashString); 326 | 327 | $headers["X-GGe4-Content-SHA1"] = $contentDigest; 328 | $headers["X-GGe4-Date"] = $gge4Date; 329 | $headers["Authorization"] = $authString; 330 | 331 | $httpResponse = $this->httpClient->request( 332 | self::METHOD_POST, 333 | $endpoint, 334 | $headers, 335 | json_encode($data) 336 | ); 337 | 338 | return $this->createResponse($httpResponse->getBody()->getContents()); 339 | } 340 | 341 | /** 342 | * Get the endpoint URL for the request. 343 | * 344 | * @return string 345 | */ 346 | protected function getEndpoint() 347 | { 348 | return ($this->getTestMode() ? $this->testEndpoint : $this->liveEndpoint) . self::API_VERSION; 349 | } 350 | 351 | /** 352 | * Create the response object. 353 | * 354 | * @param $data 355 | * 356 | * @return PayeezyResponse 357 | */ 358 | protected function createResponse($data) 359 | { 360 | return $this->response = new PayeezyResponse($this, $data); 361 | } 362 | } 363 | -------------------------------------------------------------------------------- /src/Message/PayeezyAuthorizeRequest.php: -------------------------------------------------------------------------------- 1 | 13 | * // Create a gateway for the First Data Payeezy Gateway 14 | * // (routes to GatewayFactory::create) 15 | * $gateway = Omnipay::create('FirstData_Payeezy'); 16 | * 17 | * // Initialise the gateway 18 | * $gateway->initialize(array( 19 | * 'gatewayId' => '12341234', 20 | * 'password' => 'thisISmyPASSWORD', 21 | * 'testMode' => true, // Or false when you are ready for live transactions 22 | * )); 23 | * 24 | * // Create a credit card object 25 | * $card = new CreditCard(array( 26 | * 'firstName' => 'Example', 27 | * 'lastName' => 'Customer', 28 | * 'number' => '4222222222222222', 29 | * 'expiryMonth' => '01', 30 | * 'expiryYear' => '2020', 31 | * 'cvv' => '123', 32 | * 'email' => 'customer@example.com', 33 | * 'billingAddress1' => '1 Scrubby Creek Road', 34 | * 'billingCountry' => 'AU', 35 | * 'billingCity' => 'Scrubby Creek', 36 | * 'billingPostcode' => '4999', 37 | * 'billingState' => 'QLD', 38 | * )); 39 | * 40 | * // Do a purchase transaction on the gateway 41 | * $transaction = $gateway->purchase(array( 42 | * 'description' => 'Your order for widgets', 43 | * 'amount' => '10.00', 44 | * 'transactionId' => 12345, 45 | * 'clientIp' => $_SERVER['REMOTE_ADDR'], 46 | * 'card' => $card, 47 | * )); 48 | * 49 | * // USE A TRANS-ARMOR TOKEN TO PROCESS A PURCHASE: 50 | * 51 | * // Create a credit card object 52 | * $card = new CreditCard(array( 53 | * 'firstName' => 'Example', 54 | * 'lastName' => 'Customer', 55 | * 'expiryMonth' => '01', 56 | * 'expiryYear' => '2020', 57 | * )); 58 | * 59 | * // Do a purchase transaction on the gateway 60 | * $transaction = $gateway->purchase(array( 61 | * 'description' => 'Your order for widgets', 62 | * 'amount' => '10.00', 63 | * 'cardReference' => $yourStoredToken, 64 | * 'clientIp' => $_SERVER['REMOTE_ADDR'], 65 | * 'card' => $card, 66 | * 'tokenCardType' => 'visa', // MUST BE VALID CONST FROM \omnipay\common\CreditCard 67 | * )); 68 | * 69 | * 70 | * 71 | * 72 | * $response = $transaction->send(); 73 | * if ($response->isSuccessful()) { 74 | * echo "Purchase transaction was successful!\n"; 75 | * $sale_id = $response->getTransactionReference(); 76 | * echo "Transaction reference = " . $sale_id . "\n"; 77 | * } 78 | * 79 | */ 80 | class PayeezyPurchaseRequest extends PayeezyAbstractRequest 81 | { 82 | protected $action = self::TRAN_PURCHASE; 83 | 84 | public function getData() 85 | { 86 | $data = parent::getData(); 87 | 88 | $this->validate('amount', 'card'); 89 | 90 | $data['amount'] = $this->getAmount(); 91 | $data['currency_code'] = $this->getCurrency(); 92 | $data['reference_no'] = $this->getTransactionId(); 93 | 94 | // add credit card details 95 | if ($this->getCardReference()) { 96 | $this->validate('tokenCardType'); 97 | $data['transarmor_token'] = $this->getCardReference(); 98 | $data['credit_card_type'] = $this->getTokenCardType(); 99 | } else { 100 | $data['credit_card_type'] = self::getCardType($this->getCard()->getBrand()); 101 | $data['cc_number'] = $this->getCard()->getNumber(); 102 | $data['cc_verification_str2'] = $this->getCard()->getCvv(); 103 | $data['cc_verification_str1'] = $this->getAVSHash(); 104 | $data['cvd_presence_ind'] = 1; 105 | $data['cvd_code'] = $this->getCard()->getCvv(); 106 | } 107 | $data['cardholder_name'] = $this->getCard()->getName(); 108 | $data['cc_expiry'] = $this->getCard()->getExpiryDate('my'); 109 | 110 | 111 | $data['client_ip'] = $this->getClientIp(); 112 | $data['client_email'] = $this->getCard()->getEmail(); 113 | $data['language'] = strtoupper($this->getCard()->getCountry()); 114 | 115 | return $data; 116 | } 117 | 118 | public function getTokenCardType() 119 | { 120 | return $this->getParameter('tokenCardType'); 121 | } 122 | 123 | public function setTokenCardType($value) 124 | { 125 | return $this->setParameter('tokenCardType', $value); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/Message/PayeezyRefundRequest.php: -------------------------------------------------------------------------------- 1 | validate('transactionReference', 'amount'); 20 | 21 | $data['amount'] = $this->getAmount(); 22 | $transaction_reference = $this->getTransactionReference(); 23 | list($auth, $tag) = explode('::', $transaction_reference); 24 | $data['authorization_num'] = $auth; 25 | $data['transaction_tag'] = $tag; 26 | 27 | return $data; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Message/PayeezyResponse.php: -------------------------------------------------------------------------------- 1 | request = $request; 28 | $this->data = json_decode($data, true); 29 | } 30 | 31 | public function isSuccessful() 32 | { 33 | return ($this->data['transaction_approved'] == '1') ? true : false; 34 | } 35 | 36 | /** 37 | * Get an item from the internal data array 38 | * 39 | * This is a short cut function to ensure that we test that the item 40 | * exists in the data array before we try to retrieve it. 41 | * 42 | * @param $itemname 43 | * @return mixed|null 44 | */ 45 | public function getDataItem($itemname) 46 | { 47 | if (isset($this->data[$itemname])) { 48 | return $this->data[$itemname]; 49 | } 50 | 51 | return null; 52 | } 53 | 54 | /** 55 | * Get the authorization number 56 | * 57 | * This is the authorization number returned by the cardholder’s financial 58 | * institution when a transaction has been approved. This value overrides any 59 | * value sent for the Request Property of the same name. 60 | * 61 | * @return integer 62 | */ 63 | public function getAuthorizationNumber() 64 | { 65 | return $this->getDataItem('authorization_num'); 66 | } 67 | 68 | /** 69 | * Get the transaction tag. 70 | * 71 | * A unique identifier to associate with a tagged transaction. This value overrides 72 | * any value sent for the Request Property of the same name. 73 | * 74 | * @return string 75 | */ 76 | public function getTransactionTag() 77 | { 78 | return $this->getDataItem('transaction_tag'); 79 | } 80 | 81 | /** 82 | * Get the transaction reference 83 | * 84 | * Because refunding or voiding a transaction requires both the authorization number 85 | * and the transaction tag, we concatenate them together to make the transaction 86 | * reference. 87 | * 88 | * @return string 89 | */ 90 | public function getTransactionReference() 91 | { 92 | return $this->getAuthorizationNumber() . '::' . $this->getTransactionTag(); 93 | } 94 | 95 | /** 96 | * Get the transaction sequence number. 97 | * 98 | * A digit sequentially incremented number generated by Global Gateway e4 and passed 99 | * through to the financial institution. It is also passed back to the client in the 100 | * transaction response. This number can be used for tracking and audit purposes. 101 | * 102 | * @return string 103 | */ 104 | public function getSequenceNo() 105 | { 106 | return $this->getDataItem('sequence_no'); 107 | } 108 | 109 | /** 110 | * Get the credit card reference for a completed transaction. 111 | * 112 | * This is only provided if TransArmor processing is turned on for the gateway. 113 | * 114 | * @return string 115 | */ 116 | public function getCardReference() 117 | { 118 | return $this->getDataItem('transarmor_token'); 119 | } 120 | 121 | public function getMessage() 122 | { 123 | return $this->getDataItem('exact_message'); 124 | } 125 | 126 | /** 127 | * Get the error code. 128 | * 129 | * This property indicates the processing status of the transaction. Please refer 130 | * to the section on Exception Handling for further information. The Transaction_Error 131 | * property will return True if this property is not “00”. 132 | * 133 | * @return string 134 | */ 135 | public function getCode() 136 | { 137 | return $this->getDataItem('exact_resp_code'); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/Message/PayeezyVoidRequest.php: -------------------------------------------------------------------------------- 1 | setParameter('storeId', $value); 35 | } 36 | 37 | /** 38 | * Get Store ID 39 | * 40 | * Calls to the Connect Gateway API are secured with a store ID and 41 | * shared secret. 42 | * 43 | * @return string 44 | */ 45 | public function getStoreId() 46 | { 47 | return $this->getParameter('storeId'); 48 | } 49 | 50 | /** 51 | * Set Shared Secret 52 | * 53 | * Calls to the Connect Gateway API are secured with a store ID and 54 | * shared secret. 55 | * 56 | * @return PurchaseRequest provides a fluent interface 57 | */ 58 | public function setSharedSecret($value) 59 | { 60 | return $this->setParameter('sharedSecret', $value); 61 | } 62 | 63 | /** 64 | * Get Shared Secret 65 | * 66 | * Calls to the Connect Gateway API are secured with a store ID and 67 | * shared secret. 68 | * 69 | * @return string 70 | */ 71 | public function getSharedSecret() 72 | { 73 | return $this->getParameter('sharedSecret'); 74 | } 75 | 76 | public function setHostedDataId($value) 77 | { 78 | return $this->setParameter('hostedDataId', $value); 79 | } 80 | 81 | public function getHostedDataId() 82 | { 83 | return $this->getParameter('hostedDataId'); 84 | } 85 | 86 | public function setCustomerId($value) 87 | { 88 | return $this->setParameter('customerId', $value); 89 | } 90 | 91 | public function getCustomerId() 92 | { 93 | return $this->getParameter('customerId'); 94 | } 95 | 96 | public function getData() 97 | { 98 | $this->validate('amount', 'card'); 99 | 100 | $data = array(); 101 | $data['storename'] = $this->getStoreId(); 102 | $data['txntype'] = 'sale'; 103 | $data['timezone'] = 'GMT'; 104 | $data['chargetotal'] = $this->getAmount(); 105 | $data['txndatetime'] = $this->getDateTime(); 106 | $data['hash'] = $this->createHash($data['txndatetime'], $data['chargetotal']); 107 | $data['currency'] = $this->getCurrencyNumeric(); 108 | $data['mode'] = 'payonly'; 109 | $data['full_bypass'] = 'true'; 110 | $data['oid'] = $this->getParameter('transactionId'); 111 | 112 | // If no hosted data, or a number is passed, validate the whole card 113 | if (is_null($this->getHostedDataId()) || ! is_null($this->getCard()->getNumber())) { 114 | $this->getCard()->validate(); 115 | } elseif (is_null($this->getCard()->getCvv())) { 116 | // Else we only require the cvv when using hosted data 117 | throw new InvalidCreditCardException("The CVV parameter is required when using hosteddataid"); 118 | } 119 | 120 | $data['cardnumber'] = $this->getCard()->getNumber(); 121 | $data['cvm'] = $this->getCard()->getCvv(); 122 | $data['expmonth'] = $this->getCard()->getExpiryDate('m'); 123 | $data['expyear'] = $this->getCard()->getExpiryDate('y'); 124 | 125 | $data['bname'] = $this->getCard()->getBillingName(); 126 | $data['baddr1'] = $this->getCard()->getBillingAddress1(); 127 | $data['baddr2'] = $this->getCard()->getBillingAddress2(); 128 | $data['bcity'] = $this->getCard()->getBillingCity(); 129 | $data['bstate'] = $this->getCard()->getBillingState(); 130 | $data['bcountry'] = $this->getCard()->getBillingCountry(); 131 | $data['bzip'] = $this->getCard()->getBillingPostcode(); 132 | 133 | $data['sname'] = $this->getCard()->getShippingName(); 134 | $data['saddr1'] = $this->getCard()->getShippingAddress1(); 135 | $data['saddr2'] = $this->getCard()->getShippingAddress2(); 136 | $data['scity'] = $this->getCard()->getShippingCity(); 137 | $data['sstate'] = $this->getCard()->getShippingState(); 138 | $data['scountry'] = $this->getCard()->getShippingCountry(); 139 | $data['szip'] = $this->getCard()->getShippingPostcode(); 140 | 141 | $data['phone'] = $this->getCard()->getPhone(); 142 | $data['email'] = $this->getCard()->getEmail(); 143 | 144 | $data['responseSuccessURL'] = $this->getParameter('returnUrl'); 145 | $data['responseFailURL'] = $this->getParameter('returnUrl'); 146 | 147 | $data['customerid'] = $this->getCustomerId(); 148 | 149 | $data['hosteddataid'] = $this->getHostedDataId(); 150 | 151 | return $data; 152 | } 153 | 154 | /** 155 | * Returns a SHA-1 hash of the transaction data. 156 | * 157 | * @param $dateTime 158 | * @param $amount 159 | * @return string 160 | */ 161 | public function createHash($dateTime, $amount) 162 | { 163 | $storeId = $this->getStoreId(); 164 | $sharedSecret = $this->getSharedSecret(); 165 | $currency = $this->getCurrencyNumeric(); 166 | $stringToHash = $storeId . $dateTime . $amount . $currency . $sharedSecret; 167 | $ascii = bin2hex($stringToHash); 168 | 169 | return sha1($ascii); 170 | } 171 | 172 | public function sendData($data) 173 | { 174 | return $this->response = new PurchaseResponse($this, $data); 175 | } 176 | 177 | public function getEndpoint() 178 | { 179 | return $this->getTestMode() ? $this->testEndpoint : $this->liveEndpoint; 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /src/Message/PurchaseResponse.php: -------------------------------------------------------------------------------- 1 | getRequest()->getEndpoint(); 31 | } 32 | 33 | public function getRedirectMethod() 34 | { 35 | return 'POST'; 36 | } 37 | 38 | public function getRedirectData() 39 | { 40 | return $this->data; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Message/WebserviceAbstractRequest.php: -------------------------------------------------------------------------------- 1 | 33 | 34 | 35 | %xmlBody% 36 | 37 | 38 | '; 39 | 40 | /** @var string XML template for the purchase request */ 41 | protected $xmlTemplate = ''; 42 | 43 | /** 44 | * Get SSL Certificate file name 45 | * 46 | * You must establish a secure communication channel to send the HTTP request. 47 | * This ensures that the data sent between your client application and the First 48 | * Data Webservice Gateway Web Service API is encrypted and that both parties can 49 | * be sure they are communicating with each other and no one else. 50 | * 51 | * The Web Service API requires an SSL connection with client and server exchanging 52 | * certificates to guarantee this level of security. The client and server certificates 53 | * each uniquely identify the party. 54 | * 55 | * @return string 56 | */ 57 | public function getSslCertificate() 58 | { 59 | return $this->getParameter('sslCertificate'); 60 | } 61 | 62 | /** 63 | * Set SSL Certificate file name 64 | * 65 | * You must establish a secure communication channel to send the HTTP request. 66 | * This ensures that the data sent between your client application and the First 67 | * Data Webservice Gateway Web Service API is encrypted and that both parties can 68 | * be sure they are communicating with each other and no one else. 69 | * 70 | * The Web Service API requires an SSL connection with client and server exchanging 71 | * certificates to guarantee this level of security. The client and server certificates 72 | * each uniquely identify the party. 73 | * 74 | * @param string $value 75 | * @return WebserviceAbstractRequest provides a fluent interface. 76 | */ 77 | public function setSslCertificate($value) 78 | { 79 | return $this->setParameter('sslCertificate', $value); 80 | } 81 | 82 | /** 83 | * Get SSL Key file name 84 | * 85 | * You must establish a secure communication channel to send the HTTP request. 86 | * This ensures that the data sent between your client application and the First 87 | * Data Webservice Gateway Web Service API is encrypted and that both parties can 88 | * be sure they are communicating with each other and no one else. 89 | * 90 | * The Web Service API requires an SSL connection with client and server exchanging 91 | * certificates to guarantee this level of security. The client and server certificates 92 | * each uniquely identify the party. 93 | * 94 | * @return string 95 | */ 96 | public function getSslKey() 97 | { 98 | return $this->getParameter('sslKey'); 99 | } 100 | 101 | /** 102 | * Set SSL Key file name 103 | * 104 | * You must establish a secure communication channel to send the HTTP request. 105 | * This ensures that the data sent between your client application and the First 106 | * Data Webservice Gateway Web Service API is encrypted and that both parties can 107 | * be sure they are communicating with each other and no one else. 108 | * 109 | * The Web Service API requires an SSL connection with client and server exchanging 110 | * certificates to guarantee this level of security. The client and server certificates 111 | * each uniquely identify the party. 112 | * 113 | * @param string $value 114 | * @return WebserviceAbstractRequest provides a fluent interface. 115 | */ 116 | public function setSslKey($value) 117 | { 118 | return $this->setParameter('sslKey', $value); 119 | } 120 | 121 | /** 122 | * Get SSL Key password 123 | * 124 | * You must establish a secure communication channel to send the HTTP request. 125 | * This ensures that the data sent between your client application and the First 126 | * Data Webservice Gateway Web Service API is encrypted and that both parties can 127 | * be sure they are communicating with each other and no one else. 128 | * 129 | * The Web Service API requires an SSL connection with client and server exchanging 130 | * certificates to guarantee this level of security. The client and server certificates 131 | * each uniquely identify the party. 132 | * 133 | * @return string 134 | */ 135 | public function getSslKeyPassword() 136 | { 137 | return $this->getParameter('sslKeyPassword'); 138 | } 139 | 140 | /** 141 | * Set SSL Key password 142 | * 143 | * You must establish a secure communication channel to send the HTTP request. 144 | * This ensures that the data sent between your client application and the First 145 | * Data Webservice Gateway Web Service API is encrypted and that both parties can 146 | * be sure they are communicating with each other and no one else. 147 | * 148 | * The Web Service API requires an SSL connection with client and server exchanging 149 | * certificates to guarantee this level of security. The client and server certificates 150 | * each uniquely identify the party. 151 | * 152 | * @param string $value 153 | * @return WebserviceAbstractRequest provides a fluent interface. 154 | */ 155 | public function setSslKeyPassword($value) 156 | { 157 | return $this->setParameter('sslKeyPassword', $value); 158 | } 159 | 160 | /** 161 | * Get Username 162 | * 163 | * Calls to the Webservice Gateway API are secured with a username and 164 | * password sent via HTTP Basic Authentication. 165 | * 166 | * @return string 167 | */ 168 | public function getUserName() 169 | { 170 | return $this->getParameter('userName'); 171 | } 172 | 173 | /** 174 | * Set Username 175 | * 176 | * Calls to the Webservice Gateway API are secured with a username and 177 | * password sent via HTTP Basic Authentication. 178 | * 179 | * @param string $value 180 | * @return WebserviceAbstractRequest provides a fluent interface. 181 | */ 182 | public function setUserName($value) 183 | { 184 | return $this->setParameter('userName', $value); 185 | } 186 | 187 | /** 188 | * Get Password 189 | * 190 | * Calls to the Webservice Gateway API are secured with a username and 191 | * password sent via HTTP Basic Authentication. 192 | * 193 | * @return string 194 | */ 195 | public function getPassword() 196 | { 197 | return $this->getParameter('password'); 198 | } 199 | 200 | /** 201 | * Set Password 202 | * 203 | * Calls to the Webservice Gateway API are secured with a username and 204 | * password sent via HTTP Basic Authentication. 205 | * 206 | * @param string $value 207 | * @return WebserviceAbstractRequest provides a fluent interface. 208 | */ 209 | public function setPassword($value) 210 | { 211 | return $this->setParameter('password', $value); 212 | } 213 | 214 | /** 215 | * Get the base transaction data. 216 | * 217 | * @return array 218 | */ 219 | protected function getBaseData() 220 | { 221 | $data = array(); 222 | 223 | return $data; 224 | } 225 | 226 | /** 227 | * Get the transaction headers. 228 | * 229 | * @return array 230 | */ 231 | protected function getHeaders() 232 | { 233 | return array( 234 | 'Content-Type: text/xml' 235 | ); 236 | } 237 | 238 | public function getData() 239 | { 240 | $data = $this->getBaseData(); 241 | return $data; 242 | } 243 | 244 | /** 245 | * Build the cURL client. 246 | * 247 | * @return resource 248 | */ 249 | public function buildCurlClient() 250 | { 251 | // 252 | // Use PHP Native cURL because the various Soap clients (BeSimple, 253 | // PHP native SoapClient) can't handle the WSDL file. 254 | // 255 | $this->curl = curl_init($this->getEndPoint()); 256 | 257 | $sslCertificate = $this->getSslCertificate(); 258 | $sslKey = $this->getSslKey(); 259 | $sslKeyPassword = $this->getSslKeyPassword(); 260 | $userName = $this->getUsername(); 261 | $password = $this->getPassword(); 262 | $headers = $this->getHeaders(); 263 | 264 | // configuring cURL not to verify the server certificate 265 | curl_setopt($this->curl, CURLOPT_SSL_VERIFYPEER, 0); 266 | 267 | // setting the path where cURL can find the client certificate 268 | curl_setopt($this->curl, CURLOPT_SSLCERT, $sslCertificate); 269 | 270 | // setting the path where cURL can find the client certificate’s 271 | // private key 272 | curl_setopt($this->curl, CURLOPT_SSLKEY, $sslKey); 273 | 274 | // setting the key password 275 | curl_setopt($this->curl, CURLOPT_SSLKEYPASSWD, $sslKeyPassword); 276 | 277 | // setting the request type to POST 278 | curl_setopt($this->curl, CURLOPT_POST, 1); 279 | 280 | // setting the content type 281 | curl_setopt($this->curl, CURLOPT_HTTPHEADER, $headers); 282 | 283 | // setting the authorization method to BASIC 284 | curl_setopt($this->curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); 285 | 286 | // supplying your credentials 287 | curl_setopt($this->curl, CURLOPT_USERPWD, $userName . ':' . $password); 288 | 289 | // telling cURL to return the HTTP response body as operation result 290 | // value when calling curl_exec 291 | curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, 1); 292 | 293 | return $this->curl; 294 | } 295 | 296 | public function sendData($data) 297 | { 298 | // 299 | // Do it with PHP Native Curl 300 | // 301 | $curl = $this->buildCurlClient(); 302 | 303 | // Create the XML body 304 | $xmlBody = $this->xmlTemplate; 305 | foreach ($data as $key => $value) { 306 | $xmlBody = str_replace('%' . $key . '%', $value, $xmlBody); 307 | } 308 | 309 | // Substitute the XML body into the template 310 | $soapBody = str_replace('%xmlBody%', $xmlBody, $this->soapTemplate); 311 | 312 | // fill the request body with the SOAP message 313 | curl_setopt($curl, CURLOPT_POSTFIELDS, $soapBody); 314 | 315 | // echo "SOAP Body\n"; 316 | // echo $soapBody; 317 | // echo "\nEND SOAP Body\n"; 318 | 319 | // Send the request 320 | $result = curl_exec($curl); 321 | 322 | // close cURL 323 | curl_close($curl); 324 | 325 | // echo "SOAP Response\n"; 326 | // echo $result; 327 | // echo "\nEND SOAP Response\n"; 328 | 329 | // Create and return a response object 330 | return $this->createResponse($result); 331 | } 332 | 333 | /** 334 | * Get the endpoint URL for the request. 335 | * 336 | * @return string 337 | */ 338 | public function getEndpoint() 339 | { 340 | return $this->getTestMode() ? $this->testEndpoint : $this->liveEndpoint; 341 | } 342 | 343 | /** 344 | * Create the response object. 345 | * 346 | * Create a structure by parsing the XML data and returning a simplified 347 | * array that our WebserviceResponse class can easily pull data from. 348 | * 349 | * @param string $data XML 350 | * @return WebserviceResponse 351 | */ 352 | public function createResponse($data) 353 | { 354 | // echo "XML Data = $data\n"; 355 | 356 | // Parse the XML 357 | $parser = xml_parser_create_ns(); 358 | $intermediate_data = array(); 359 | $parsed_data = array(); 360 | xml_parse_into_struct($parser, $data, $intermediate_data); 361 | 362 | // echo "Intermediate data =\n"; 363 | // print_r($intermediate_data); 364 | // echo "\nEnd intermediate data\n"; 365 | 366 | // Invert the parsed array from this type of structure: 367 | /* 368 | [4] => Array 369 | ( 370 | [tag] => HTTP://SECURE.LINKPT.NET/FDGGWSAPI/SCHEMAS_US/FDGGWSAPI:COMMERCIALSERVICEPROVIDER 371 | [type] => complete 372 | [level] => 4 373 | [value] => CSI 374 | ) 375 | */ 376 | // To this, which we want for our internal purposes 377 | // [COMMERCIALSERVICEPROVIDER] => CSI 378 | // We basically just strip out everything before the final ':' of the 379 | // tag and attach any value to that, ignoring any fields that come through 380 | // from the XML parser without any values. 381 | 382 | foreach ($intermediate_data as $item) { 383 | if (! empty($item['value'])) { 384 | $parsed_tag = explode(':', $item['tag']); 385 | $tag = array_pop($parsed_tag); 386 | $parsed_data[$tag] = $item['value']; 387 | } 388 | } 389 | 390 | return $this->response = new WebserviceResponse($this, $parsed_data); 391 | } 392 | } 393 | -------------------------------------------------------------------------------- /src/Message/WebserviceAuthorizeRequest.php: -------------------------------------------------------------------------------- 1 | 13 | * // Create a gateway for the First Data Webservice Gateway 14 | * // (routes to GatewayFactory::create) 15 | * $gateway = Omnipay::create('FirstData_Webservice'); 16 | * 17 | * // Initialise the gateway 18 | * $gateway->initialize(array( 19 | * 'sslCertificate' => 'WS9999999._.1.pem', 20 | * 'sslKey' => 'WS9999999._.1.key', 21 | * 'sslKeyPassword' => 'sslKEYpassWORD', 22 | * 'userName' => 'WS9999999._.1', 23 | * 'password' => 'passWORD', 24 | * 'testMode' => true, 25 | * )); 26 | * 27 | * // Create a credit card object 28 | * $card = new CreditCard(array( 29 | * 'firstName' => 'Example', 30 | * 'lastName' => 'Customer', 31 | * 'number' => '4222222222222222', 32 | * 'expiryMonth' => '01', 33 | * 'expiryYear' => '2020', 34 | * 'cvv' => '123', 35 | * 'email' => 'customer@example.com', 36 | * 'billingAddress1' => '1 Scrubby Creek Road', 37 | * 'billingCountry' => 'AU', 38 | * 'billingCity' => 'Scrubby Creek', 39 | * 'billingPostcode' => '4999', 40 | * 'billingState' => 'QLD', 41 | * )); 42 | * 43 | * // Do an authorize transaction on the gateway 44 | * $transaction = $gateway->authorize(array( 45 | * 'accountId' => '12345', 46 | * 'amount' => '10.00', 47 | * 'currency' => 'USD', 48 | * 'description' => 'Super Deluxe Excellent Discount Package', 49 | * 'transactionId' => 12345, 50 | * 'clientIp' => $_SERVER['REMOTE_ADDR'], 51 | * 'card' => $card, 52 | * )); 53 | * $response = $transaction->send(); 54 | * if ($response->isSuccessful()) { 55 | * echo "Authorize transaction was successful!\n"; 56 | * $sale_id = $response->getTransactionReference(); 57 | * echo "Transaction reference = " . $sale_id . "\n"; 58 | * } 59 | * 60 | */ 61 | class WebserviceAuthorizeRequest extends WebservicePurchaseRequest 62 | { 63 | /** @var string Transaction type */ 64 | protected $txn_type = 'preAuth'; 65 | } 66 | -------------------------------------------------------------------------------- /src/Message/WebserviceCaptureRequest.php: -------------------------------------------------------------------------------- 1 | 13 | * // Create a gateway for the First Data Webservice Gateway 14 | * // (routes to GatewayFactory::create) 15 | * $gateway = Omnipay::create('FirstData_Webservice'); 16 | * 17 | * // Initialise the gateway 18 | * $gateway->initialize(array( 19 | * 'sslCertificate' => 'WS9999999._.1.pem', 20 | * 'sslKey' => 'WS9999999._.1.key', 21 | * 'sslKeyPassword' => 'sslKEYpassWORD', 22 | * 'userName' => 'WS9999999._.1', 23 | * 'password' => 'passWORD', 24 | * 'testMode' => true, 25 | * )); 26 | * 27 | * // Do a capture transaction on the gateway. This assumes that an authorize 28 | * // request has been successful, and that the transactionReference from the 29 | * // authorize request is stored in $sale_id. 30 | * $transaction = $gateway->capture(array( 31 | * 'transactionReference' => $sale_id, 32 | * )); 33 | * $response = $transaction->send(); 34 | * if ($response->isSuccessful()) { 35 | * echo "Capture transaction was successful!\n"; 36 | * $sale_id = $response->getTransactionReference(); 37 | * echo "Transaction reference = " . $sale_id . "\n"; 38 | * } 39 | * 40 | */ 41 | class WebserviceCaptureRequest extends WebserviceAbstractRequest 42 | { 43 | /** @var string XML template for the capture request */ 44 | protected $xmlTemplate = ' 45 | 47 | 48 | 49 | %txn_type% 50 | 51 | 52 | %reference_no% 53 | 54 | 55 | 56 | '; 57 | 58 | /** @var string Transaction type */ 59 | protected $txn_type = 'postAuth'; 60 | 61 | public function getData() 62 | { 63 | $data = parent::getData(); 64 | 65 | $data['txn_type'] = $this->txn_type; 66 | 67 | $this->validate('transactionReference'); 68 | 69 | // Fetch the original transaction reference and tdate from the 70 | // concatenated transactionReference returned by the authorize() 71 | // request. 72 | $transaction_reference = $this->getTransactionReference(); 73 | list($orderid, $tdate) = explode('::', $transaction_reference); 74 | $data['reference_no'] = $orderid; 75 | 76 | return $data; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/Message/WebservicePurchaseRequest.php: -------------------------------------------------------------------------------- 1 | 13 | * // Create a gateway for the First Data Webservice Gateway 14 | * // (routes to GatewayFactory::create) 15 | * $gateway = Omnipay::create('FirstData_Webservice'); 16 | * 17 | * // Initialise the gateway 18 | * $gateway->initialize(array( 19 | * 'sslCertificate' => 'WS9999999._.1.pem', 20 | * 'sslKey' => 'WS9999999._.1.key', 21 | * 'sslKeyPassword' => 'sslKEYpassWORD', 22 | * 'userName' => 'WS9999999._.1', 23 | * 'password' => 'passWORD', 24 | * 'testMode' => true, 25 | * )); 26 | * 27 | * // Create a credit card object 28 | * $card = new CreditCard(array( 29 | * 'firstName' => 'Example', 30 | * 'lastName' => 'Customer', 31 | * 'number' => '4222222222222222', 32 | * 'expiryMonth' => '01', 33 | * 'expiryYear' => '2020', 34 | * 'cvv' => '123', 35 | * 'email' => 'customer@example.com', 36 | * 'billingAddress1' => '1 Scrubby Creek Road', 37 | * 'billingCountry' => 'AU', 38 | * 'billingCity' => 'Scrubby Creek', 39 | * 'billingPostcode' => '4999', 40 | * 'billingState' => 'QLD', 41 | * )); 42 | * 43 | * // Do a purchase transaction on the gateway 44 | * $transaction = $gateway->purchase(array( 45 | * 'accountId' => '12345', 46 | * 'amount' => '10.00', 47 | * 'transactionId' => 12345, 48 | * 'clientIp' => $_SERVER['REMOTE_ADDR'], 49 | * 'card' => $card, 50 | * )); 51 | * $response = $transaction->send(); 52 | * if ($response->isSuccessful()) { 53 | * echo "Purchase transaction was successful!\n"; 54 | * $sale_id = $response->getTransactionReference(); 55 | * echo "Transaction reference = " . $sale_id . "\n"; 56 | * } 57 | * 58 | */ 59 | class WebservicePurchaseRequest extends WebserviceAbstractRequest 60 | { 61 | /** @var string XML template for the purchase request */ 62 | protected $xmlTemplate = ' 63 | 65 | 66 | 67 | %txn_type% 68 | 69 | 70 | %card_number% 71 | %card_expiry_month% 72 | %card_expiry_year% 73 | 74 | 75 | %amount% 76 | 77 | 78 | %reference_no% 79 | %ip% 80 | No 81 | 82 | 83 | %account_id% 84 | %card_name% 85 | %card_address1% 86 | %card_city% 87 | %card_state% 88 | %card_postcode% 89 | %card_country% 90 | %card_email% 91 | 92 | 93 | 94 | '; 95 | 96 | /** @var string Transaction type */ 97 | protected $txn_type = 'sale'; 98 | 99 | /** 100 | * Get the request accountId 101 | * 102 | * @return string 103 | */ 104 | public function getAccountId() 105 | { 106 | return $this->getParameter('accountId'); 107 | } 108 | 109 | /** 110 | * Set the request accountId 111 | * 112 | * @param string $value 113 | * @return WebserviceAbstractRequest provides a fluent interface. 114 | */ 115 | public function setAccountId($value) 116 | { 117 | return $this->setParameter('accountId', $value); 118 | } 119 | 120 | public function getData() 121 | { 122 | $data = parent::getData(); 123 | 124 | $data['txn_type'] = $this->txn_type; 125 | 126 | // We have to make the transactionId a required parameter because 127 | // it is returned as the transactionReference, and required for 128 | // voids, refunds, and captures. The accountId parameter is also 129 | // required by First Data. 130 | $this->validate('amount', 'card', 'transactionId', 'accountId'); 131 | 132 | $data['amount'] = $this->getAmount(); 133 | $data['reference_no'] = $this->getTransactionId(); 134 | $data['ip'] = $this->getClientIp(); 135 | 136 | // Add account details 137 | $data['account_id'] = $this->getAccountId(); 138 | 139 | // add credit card details 140 | $data['card_number'] = $this->getCard()->getNumber(); 141 | $data['card_name'] = $this->getCard()->getName(); 142 | $data['card_expiry_month'] = $this->getCard()->getExpiryDate('m'); 143 | $data['card_expiry_year'] = $this->getCard()->getExpiryDate('y'); 144 | $data['card_address1'] = $this->getCard()->getBillingAddress1(); 145 | $data['card_address2'] = $this->getCard()->getBillingAddress2(); 146 | $data['card_city'] = $this->getCard()->getBillingCity(); 147 | $data['card_state'] = $this->getCard()->getBillingState(); 148 | $data['card_postcode'] = $this->getCard()->getBillingPostcode(); 149 | $data['card_country'] = $this->getCard()->getBillingCountry(); 150 | $data['card_email'] = $this->getCard()->getEmail(); 151 | $data['cvd_code'] = $this->getCard()->getCvv(); 152 | 153 | return $data; 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/Message/WebserviceRefundRequest.php: -------------------------------------------------------------------------------- 1 | 13 | * // Create a gateway for the First Data Webservice Gateway 14 | * // (routes to GatewayFactory::create) 15 | * $gateway = Omnipay::create('FirstData_Webservice'); 16 | * 17 | * // Initialise the gateway 18 | * $gateway->initialize(array( 19 | * 'sslCertificate' => 'WS9999999._.1.pem', 20 | * 'sslKey' => 'WS9999999._.1.key', 21 | * 'sslKeyPassword' => 'sslKEYpassWORD', 22 | * 'userName' => 'WS9999999._.1', 23 | * 'password' => 'passWORD', 24 | * 'testMode' => true, 25 | * )); 26 | * 27 | * // Do a refund transaction on the gateway. This assumes that a purchase 28 | * // request has been successful, and that the transactionReference from the 29 | * // purchase request is stored in $sale_id. 30 | * $transaction = $gateway->refund(array( 31 | * 'transactionReference' => $sale_id, 32 | * 'amount' => 5.00, 33 | * )); 34 | * $response = $transaction->send(); 35 | * if ($response->isSuccessful()) { 36 | * echo "Refund transaction was successful!\n"; 37 | * $sale_id = $response->getTransactionReference(); 38 | * echo "Transaction reference = " . $sale_id . "\n"; 39 | * } 40 | * 41 | * 42 | * ### Quirks 43 | * 44 | * In the case of a captured authorization, the transaction reference passed 45 | * to refund() must be the transaction reference returned from the capture() 46 | * request and not the transaction reference from the original authorize() 47 | * request. 48 | */ 49 | class WebserviceRefundRequest extends WebserviceAbstractRequest 50 | { 51 | /** @var string XML template for the refund request */ 52 | protected $xmlTemplate = ' 53 | 55 | 56 | 57 | %txn_type% 58 | 59 | 60 | %amount% 61 | 62 | 63 | %reference_no% 64 | 65 | 66 | 67 | '; 68 | 69 | /** @var string Transaction type */ 70 | protected $txn_type = 'return'; 71 | 72 | public function getData() 73 | { 74 | $data = parent::getData(); 75 | 76 | $data['txn_type'] = $this->txn_type; 77 | 78 | $this->validate('amount', 'transactionReference'); 79 | 80 | // Fetch the original transaction reference and tdate from the 81 | // concatenated transactionReference returned by the purchase() 82 | // request. 83 | $transaction_reference = $this->getTransactionReference(); 84 | list($orderid, $tdate) = explode('::', $transaction_reference); 85 | $data['reference_no'] = $orderid; 86 | $data['tdate'] = $tdate; 87 | 88 | $data['amount'] = $this->getAmount(); 89 | 90 | return $data; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/Message/WebserviceResponse.php: -------------------------------------------------------------------------------- 1 | data[$itemname])) { 32 | return $this->data[$itemname]; 33 | } 34 | 35 | return null; 36 | } 37 | 38 | public function isSuccessful() 39 | { 40 | return ($this->getDataItem('TRANSACTIONRESULT') == 'APPROVED') ? true : false; 41 | } 42 | 43 | /** 44 | * Get the transaction reference 45 | * 46 | * Because refunding or voiding a transaction requires both the order ID 47 | * and the TDATE, we concatenate them together to make the transaction 48 | * reference. 49 | * 50 | * @return string 51 | */ 52 | public function getTransactionReference() 53 | { 54 | return $this->getDataItem('ORDERID') . '::' . $this->getDataItem('TDATE'); 55 | } 56 | 57 | public function getMessage() 58 | { 59 | return $this->getDataItem('ERRORMESSAGE'); 60 | } 61 | 62 | public function getCode() 63 | { 64 | return $this->getDataItem('TRANSACTIONRESULT'); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Message/WebserviceVoidRequest.php: -------------------------------------------------------------------------------- 1 | 13 | * // Create a gateway for the First Data Webservice Gateway 14 | * // (routes to GatewayFactory::create) 15 | * $gateway = Omnipay::create('FirstData_Webservice'); 16 | * 17 | * // Initialise the gateway 18 | * $gateway->initialize(array( 19 | * 'sslCertificate' => 'WS9999999._.1.pem', 20 | * 'sslKey' => 'WS9999999._.1.key', 21 | * 'sslKeyPassword' => 'sslKEYpassWORD', 22 | * 'userName' => 'WS9999999._.1', 23 | * 'password' => 'passWORD', 24 | * 'testMode' => true, 25 | * )); 26 | * 27 | * // Do a void transaction on the gateway. This assumes that a purchase 28 | * // request has been successful, and that the transactionReference from the 29 | * // purchase request is stored in $sale_id. 30 | * $transaction = $gateway->void(array( 31 | * 'transactionReference' => $sale_id, 32 | * )); 33 | * $response = $transaction->send(); 34 | * if ($response->isSuccessful()) { 35 | * echo "Void transaction was successful!\n"; 36 | * $sale_id = $response->getTransactionReference(); 37 | * echo "Transaction reference = " . $sale_id . "\n"; 38 | * } 39 | * 40 | * 41 | * ### Quirks 42 | * 43 | * In the case of a captured authorization, the transaction reference passed 44 | * to void() must be the transaction reference returned from the capture() 45 | * request and not the transaction reference from the original authorize() 46 | * request. 47 | */ 48 | class WebserviceVoidRequest extends WebserviceAbstractRequest 49 | { 50 | /** @var string XML template for the void request */ 51 | protected $xmlTemplate = ' 52 | 54 | 55 | 56 | %txn_type% 57 | 58 | 59 | %reference_no% 60 | %tdate% 61 | 62 | 63 | 64 | '; 65 | 66 | /** @var string Transaction type */ 67 | protected $txn_type = 'void'; 68 | 69 | public function getData() 70 | { 71 | $data = parent::getData(); 72 | 73 | $data['txn_type'] = $this->txn_type; 74 | 75 | $this->validate('transactionReference'); 76 | 77 | // Fetch the original transaction reference and tdate from the 78 | // concatenated transactionReference returned by the purchase() 79 | // request. 80 | $transaction_reference = $this->getTransactionReference(); 81 | list($orderid, $tdate) = explode('::', $transaction_reference); 82 | $data['reference_no'] = $orderid; 83 | $data['tdate'] = $tdate; 84 | 85 | return $data; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/PayeezyGateway.php: -------------------------------------------------------------------------------- 1 | 22 | * // Create a gateway for the First Data Payeezy Gateway 23 | * // (routes to GatewayFactory::create) 24 | * $gateway = Omnipay::create('FirstData_Payeezy'); 25 | * 26 | * // Initialise the gateway 27 | * $gateway->initialize(array( 28 | * 'gatewayId' => '12341234', 29 | * 'password' => 'thisISmyPASSWORD', 30 | * 'testMode' => true, // Or false when you are ready for live transactions 31 | * )); 32 | * 33 | * // Create a credit card object 34 | * $card = new CreditCard(array( 35 | * 'firstName' => 'Example', 36 | * 'lastName' => 'Customer', 37 | * 'number' => '4222222222222222', 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 | * 'transactionId' => 12345, 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 Accounts 66 | * 67 | * Test accounts can be obtained here: 68 | * https://provisioning.demo.globalgatewaye4.firstdata.com/signup 69 | * Note that only USD transactions are supported for test accounts. 70 | * 71 | * Once you have created a test account, log in to the gateway here: 72 | * https://demo.globalgatewaye4.firstdata.com/main 73 | * Navigate to Administration -> Terminals and click on the terminal with TERM ECOMM name, 74 | * There will be a Gateway ID displayed there and you can also generate a password. 75 | * 76 | * Test credit card numbers can be found here: 77 | * https://support.payeezy.com/hc/en-us/articles/204504235-Using-test-credit-card-numbers 78 | * 79 | * ### Quirks 80 | * 81 | * This gateway requires both a transaction reference (aka an authorization number) 82 | * and a transaction tag to implement either voids or refunds. These are referred 83 | * to in the documentation as "tagged refund" and "tagged voids". 84 | * 85 | * Card token transactions are supported (these are referred to in the documentation as 86 | * "TransArmor Multi-Pay") but have to be enabled for each merchant account. There is no 87 | * createCard method, instead a card token is generated when a zero dollar authorization 88 | * is submitted. 89 | * 90 | * Void and Refund transactions require the amount parameter. 91 | * 92 | * @link https://support.payeezy.com/hc/en-us 93 | * @link https://provisioning.demo.globalgatewaye4.firstdata.com/signup 94 | * @link https://support.payeezy.com/hc/en-us/articles/204504235-Using-test-credit-card-numbers 95 | */ 96 | class PayeezyGateway extends AbstractGateway 97 | { 98 | public function getName() 99 | { 100 | return 'First Data Payeezy'; 101 | } 102 | 103 | public function getDefaultParameters() 104 | { 105 | return array( 106 | 'gatewayId' => '', 107 | 'password' => '', 108 | 'keyId' => '', 109 | 'hmac' => '', 110 | 'testMode' => false, 111 | ); 112 | } 113 | 114 | /** 115 | * Get Gateway ID 116 | * 117 | * Calls to the Payeezy Gateway API are secured with a gateway ID and 118 | * password. 119 | * 120 | * @return string 121 | */ 122 | public function getGatewayId() 123 | { 124 | return $this->getParameter('gatewayId'); 125 | } 126 | 127 | /** 128 | * Set Gateway ID 129 | * 130 | * Calls to the Payeezy Gateway API are secured with a gateway ID and 131 | * password. 132 | * 133 | * @return PayeezyGateway provides a fluent interface. 134 | */ 135 | public function setGatewayId($value) 136 | { 137 | return $this->setParameter('gatewayId', $value); 138 | } 139 | 140 | /** 141 | * Get Password 142 | * 143 | * Calls to the Payeezy Gateway API are secured with a gateway ID and 144 | * password. 145 | * 146 | * @return string 147 | */ 148 | public function getPassword() 149 | { 150 | return $this->getParameter('password'); 151 | } 152 | 153 | /** 154 | * Set Password 155 | * 156 | * Calls to the Payeezy Gateway API are secured with a gateway ID and 157 | * password. 158 | * 159 | * @return PayeezyGateway provides a fluent interface. 160 | */ 161 | public function setPassword($value) 162 | { 163 | return $this->setParameter('password', $value); 164 | } 165 | 166 | /** 167 | * Get Key Id 168 | * 169 | * Calls to the Payeezy Gateway API are secured with a gateway ID and 170 | * password. 171 | * 172 | * @return string 173 | */ 174 | public function getKeyId() 175 | { 176 | return $this->getParameter('keyId'); 177 | } 178 | 179 | /** 180 | * Set Key Id 181 | * 182 | * Calls to the Payeezy Gateway API are secured with a gateway ID and 183 | * password. 184 | * 185 | * @return PayeezyGateway provides a fluent interface. 186 | */ 187 | public function setKeyId($value) 188 | { 189 | return $this->setParameter('keyId', $value); 190 | } 191 | 192 | /** 193 | * Get Hmac 194 | * 195 | * Calls to the Payeezy Gateway API are secured with a gateway ID and 196 | * password. 197 | * 198 | * @return string 199 | */ 200 | public function getHmac() 201 | { 202 | return $this->getParameter('hmac'); 203 | } 204 | 205 | /** 206 | * Set Hmac 207 | * 208 | * Calls to the Payeezy Gateway API are secured with a gateway ID and 209 | * password. 210 | * 211 | * @return PayeezyGateway provides a fluent interface. 212 | */ 213 | public function setHmac($value) 214 | { 215 | return $this->setParameter('hmac', $value); 216 | } 217 | 218 | /** 219 | * Create a purchase request. 220 | * 221 | * @param array $parameters 222 | * 223 | * @return \Omnipay\FirstData\Message\PayeezyPurchaseRequest 224 | */ 225 | public function purchase(array $parameters = array()) 226 | { 227 | return $this->createRequest('\Omnipay\FirstData\Message\PayeezyPurchaseRequest', $parameters); 228 | } 229 | 230 | /** 231 | * Create an authorize request. 232 | * 233 | * @param array $parameters 234 | * 235 | * @return \Omnipay\FirstData\Message\PayeezyAuthorizeRequest 236 | */ 237 | public function authorize(array $parameters = array()) 238 | { 239 | return $this->createRequest('\Omnipay\FirstData\Message\PayeezyAuthorizeRequest', $parameters); 240 | } 241 | 242 | /** 243 | * Create a capture request. 244 | * 245 | * @param array $parameters 246 | * 247 | * @return \Omnipay\FirstData\Message\PayeezyCaptureRequest 248 | */ 249 | public function capture(array $parameters = array()) 250 | { 251 | return $this->createRequest('\Omnipay\FirstData\Message\PayeezyCaptureRequest', $parameters); 252 | } 253 | 254 | /** 255 | * Create a refund request. 256 | * 257 | * @param array $parameters 258 | * 259 | * @return \Omnipay\FirstData\Message\PayeezyRefundRequest 260 | */ 261 | public function refund(array $parameters = array()) 262 | { 263 | return $this->createRequest('\Omnipay\FirstData\Message\PayeezyRefundRequest', $parameters); 264 | } 265 | 266 | /** 267 | * Create a void request. 268 | * 269 | * @param array $parameters 270 | * 271 | * @return \Omnipay\FirstData\Message\PayeezyVoidRequest 272 | */ 273 | public function void(array $parameters = array()) 274 | { 275 | return $this->createRequest('\Omnipay\FirstData\Message\PayeezyVoidRequest', $parameters); 276 | } 277 | } 278 | -------------------------------------------------------------------------------- /src/WebserviceGateway.php: -------------------------------------------------------------------------------- 1 | ) throws an error message. The XML header must be 42 | * omitted. 43 | * 44 | * To be honest I have better things to spend my time on than dealing with such 45 | * nonsense. If people can't drag themselves out of the 19th century and use 46 | * REST APIs instead of SOAP then they can at least have the good grace and 47 | * common courtesy to get their XML handling and formatting correct. 48 | * 49 | * #### Transaction ID 50 | * 51 | * A user supplied transaction ID (transactionId parameter) must be supplied for each 52 | * purchase() or authorize() request. This is known as "OrderId" in the Webservice Gateway. 53 | * 54 | * The First Data Webservice Gateway Web Service API only accepts ASCII characters. The Order 55 | * ID cannot contain the following characters: &, %, /, or exceed 100 characters in length. 56 | * The Order ID will be restricted in such a way so that it can only accepts alpha numeric 57 | * (a-z, A-Z, 0-9) and some special characters for merchants convenience. 58 | * 59 | * #### Voids and Refunds 60 | * 61 | * Voids and Refunds require both the transactionId and the TDATE parameter returned 62 | * from the purchase (or capture) call. To make things cleaner for calling applicatons, 63 | * the transactionReference returned by getTransactionReference() after the purhcase 64 | * or capture call is the transactionId and the TDATE concatenated together and 65 | * separated by '::'. 66 | * 67 | * Refunds require an amount parameter. The amount parameter is ignored by the void 68 | * call. 69 | * 70 | * ### Authentication 71 | * 72 | * Within the SSL connection (see below), authentication is done via HTTP Basic Auth. 73 | * 74 | * First Data should provide you, as part of the connection package, a username and a 75 | * password. The username will be of the form WS*******._.1 and the password will be 76 | * a string containing letters and numbers. Provide these as the userName and password 77 | * parameters when initializing the gateway. 78 | * 79 | * ### SSL Connection Security 80 | * 81 | * The Web Service API requires an SSL connection with client and server exchanging 82 | * certificates to guarantee this level of security. The client and server certificates 83 | * each uniquely identify the party. 84 | * 85 | * First Data should provide you, as part of the connection package, at least the 86 | * following files: 87 | * 88 | * * WS____.pem (certificate file) 89 | * * WS____.key (key file) 90 | * * WS____.key.pw.txt (text file containing the password for the key) 91 | * 92 | * ... where WS___ is your username also provided by First Data (see above). 93 | * 94 | * You need to store the certificate file and the key file on disk somewhere and 95 | * pass the following parameters when initializing the gateway: 96 | * 97 | * * sslCertificate -- on disk location of the .pem certificate file. 98 | * * sslKey -- on disk location of the .key file. 99 | * * sslKeyPassword -- the password for the key (not the file name) 100 | * 101 | * In case First Data provide you with a .p12 (PKCS-12) file for the certificate 102 | * instead of a PEM file, you will need to convert the .p12 file to a .pem file 103 | * using this command: 104 | * 105 | * ``` 106 | * openssl pkcs12 -in WS____.p12 -out WS____.1.pem -clcerts -nokeys 107 | * ``` 108 | * 109 | * ### Test Accounts 110 | * 111 | * To obtain a test account, use this form: 112 | * http://www.firstdata.com/gg/apply_test_account.htm 113 | * 114 | * ### Example 115 | * 116 | * This is an example of a purchase request. 117 | * 118 | * 119 | * // Create a gateway for the First Data Webservice Gateway 120 | * // (routes to GatewayFactory::create) 121 | * $gateway = Omnipay::create('FirstData_Webservice'); 122 | * 123 | * // Initialise the gateway 124 | * $gateway->initialize(array( 125 | * 'sslCertificate' => 'WS9999999._.1.pem', 126 | * 'sslKey' => 'WS9999999._.1.key', 127 | * 'sslKeyPassword' => 'sslKEYpassWORD', 128 | * 'userName' => 'WS9999999._.1', 129 | * 'password' => 'passWORD', 130 | * 'testMode' => true, 131 | * )); 132 | * 133 | * // Create a credit card object 134 | * $card = new CreditCard(array( 135 | * 'firstName' => 'Example', 136 | * 'lastName' => 'Customer', 137 | * 'number' => '4222222222222222', 138 | * 'expiryMonth' => '01', 139 | * 'expiryYear' => '2020', 140 | * 'cvv' => '123', 141 | * 'email' => 'customer@example.com', 142 | * 'billingAddress1' => '1 Scrubby Creek Road', 143 | * 'billingCountry' => 'AU', 144 | * 'billingCity' => 'Scrubby Creek', 145 | * 'billingPostcode' => '4999', 146 | * 'billingState' => 'QLD', 147 | * )); 148 | * 149 | * // Do a purchase transaction on the gateway 150 | * $transaction = $gateway->purchase(array( 151 | * 'accountId' => '12345', 152 | * 'amount' => '10.00', 153 | * 'currency' => 'USD', 154 | * 'description' => 'Super Deluxe Excellent Discount Package', 155 | * 'transactionId' => 12345, 156 | * 'clientIp' => $_SERVER['REMOTE_ADDR'], 157 | * 'card' => $card, 158 | * )); 159 | * $response = $transaction->send(); 160 | * if ($response->isSuccessful()) { 161 | * echo "Purchase transaction was successful!\n"; 162 | * $sale_id = $response->getTransactionReference(); 163 | * echo "Transaction reference = " . $sale_id . "\n"; 164 | * } 165 | * 166 | * 167 | * @link https://www.firstdata.com/downloads/pdf/FDGG_Web_Service_API_v9.0.pdf 168 | */ 169 | class WebserviceGateway extends AbstractGateway 170 | { 171 | public function getName() 172 | { 173 | return 'First Data Webservice'; 174 | } 175 | 176 | public function getDefaultParameters() 177 | { 178 | return array( 179 | 'sslCertificate' => '', 180 | 'sslKey' => '', 181 | 'sslKeyPassword' => '', 182 | 'userName' => '', 183 | 'password' => '', 184 | 'testMode' => false, 185 | ); 186 | } 187 | 188 | /** 189 | * Get SSL Certificate file name 190 | * 191 | * You must establish a secure communication channel to send the HTTP request. 192 | * This ensures that the data sent between your client application and the First 193 | * Data Webservice Gateway Web Service API is encrypted and that both parties can 194 | * be sure they are communicating with each other and no one else. 195 | * 196 | * The Web Service API requires an SSL connection with client and server exchanging 197 | * certificates to guarantee this level of security. The client and server certificates 198 | * each uniquely identify the party. 199 | * 200 | * @return string 201 | */ 202 | public function getSslCertificate() 203 | { 204 | return $this->getParameter('sslCertificate'); 205 | } 206 | 207 | /** 208 | * Set SSL Certificate file name 209 | * 210 | * You must establish a secure communication channel to send the HTTP request. 211 | * This ensures that the data sent between your client application and the First 212 | * Data Webservice Gateway Web Service API is encrypted and that both parties can 213 | * be sure they are communicating with each other and no one else. 214 | * 215 | * The Web Service API requires an SSL connection with client and server exchanging 216 | * certificates to guarantee this level of security. The client and server certificates 217 | * each uniquely identify the party. 218 | * 219 | * @param string $value 220 | * @return WebserviceGateway provides a fluent interface. 221 | */ 222 | public function setSslCertificate($value) 223 | { 224 | return $this->setParameter('sslCertificate', $value); 225 | } 226 | 227 | /** 228 | * Get SSL Key file name 229 | * 230 | * You must establish a secure communication channel to send the HTTP request. 231 | * This ensures that the data sent between your client application and the First 232 | * Data Webservice Gateway Web Service API is encrypted and that both parties can 233 | * be sure they are communicating with each other and no one else. 234 | * 235 | * The Web Service API requires an SSL connection with client and server exchanging 236 | * certificates to guarantee this level of security. The client and server certificates 237 | * each uniquely identify the party. 238 | * 239 | * @return string 240 | */ 241 | public function getSslKey() 242 | { 243 | return $this->getParameter('sslKey'); 244 | } 245 | 246 | /** 247 | * Set SSL Key file name 248 | * 249 | * You must establish a secure communication channel to send the HTTP request. 250 | * This ensures that the data sent between your client application and the First 251 | * Data Webservice Gateway Web Service API is encrypted and that both parties can 252 | * be sure they are communicating with each other and no one else. 253 | * 254 | * The Web Service API requires an SSL connection with client and server exchanging 255 | * certificates to guarantee this level of security. The client and server certificates 256 | * each uniquely identify the party. 257 | * 258 | * @param string $value 259 | * @return WebserviceGateway provides a fluent interface. 260 | */ 261 | public function setSslKey($value) 262 | { 263 | return $this->setParameter('sslKey', $value); 264 | } 265 | 266 | /** 267 | * Get SSL Key password 268 | * 269 | * You must establish a secure communication channel to send the HTTP request. 270 | * This ensures that the data sent between your client application and the First 271 | * Data Global Gateway Web Service API is encrypted and that both parties can 272 | * be sure they are communicating with each other and no one else. 273 | * 274 | * The Web Service API requires an SSL connection with client and server exchanging 275 | * certificates to guarantee this level of security. The client and server certificates 276 | * each uniquely identify the party. 277 | * 278 | * @return string 279 | */ 280 | public function getSslKeyPassword() 281 | { 282 | return $this->getParameter('sslKeyPassword'); 283 | } 284 | 285 | /** 286 | * Set SSL Key password 287 | * 288 | * You must establish a secure communication channel to send the HTTP request. 289 | * This ensures that the data sent between your client application and the First 290 | * Data Global Gateway Web Service API is encrypted and that both parties can 291 | * be sure they are communicating with each other and no one else. 292 | * 293 | * The Web Service API requires an SSL connection with client and server exchanging 294 | * certificates to guarantee this level of security. The client and server certificates 295 | * each uniquely identify the party. 296 | * 297 | * @param string $value 298 | * @return WebserviceGateway provides a fluent interface. 299 | */ 300 | public function setSslKeyPassword($value) 301 | { 302 | return $this->setParameter('sslKeyPassword', $value); 303 | } 304 | 305 | /** 306 | * Get Username 307 | * 308 | * Calls to the Global Gateway API are secured with a username and 309 | * password sent via HTTP Basic Authentication. 310 | * 311 | * @return string 312 | */ 313 | public function getUserName() 314 | { 315 | return $this->getParameter('userName'); 316 | } 317 | 318 | /** 319 | * Set Username 320 | * 321 | * Calls to the Global Gateway API are secured with a username and 322 | * password sent via HTTP Basic Authentication. 323 | * 324 | * @param string $value 325 | * @return WebserviceGateway provides a fluent interface. 326 | */ 327 | public function setUserName($value) 328 | { 329 | return $this->setParameter('userName', $value); 330 | } 331 | 332 | /** 333 | * Get Password 334 | * 335 | * Calls to the Global Gateway API are secured with a username and 336 | * password sent via HTTP Basic Authentication. 337 | * 338 | * @return string 339 | */ 340 | public function getPassword() 341 | { 342 | return $this->getParameter('password'); 343 | } 344 | 345 | /** 346 | * Set Password 347 | * 348 | * Calls to the Global Gateway API are secured with a username and 349 | * password sent via HTTP Basic Authentication. 350 | * 351 | * @param string $value 352 | * @return WebserviceGateway provides a fluent interface. 353 | */ 354 | public function setPassword($value) 355 | { 356 | return $this->setParameter('password', $value); 357 | } 358 | 359 | /** 360 | * Create a purchase request. 361 | * 362 | * @param array $parameters 363 | * @return \Omnipay\FirstData\Message\WebservicePurchaseRequest 364 | */ 365 | public function purchase(array $parameters = array()) 366 | { 367 | return $this->createRequest('\Omnipay\FirstData\Message\WebservicePurchaseRequest', $parameters); 368 | } 369 | 370 | /** 371 | * Create an authorize request. 372 | * 373 | * @param array $parameters 374 | * @return \Omnipay\FirstData\Message\WebserviceAuthorizeRequest 375 | */ 376 | public function authorize(array $parameters = array()) 377 | { 378 | return $this->createRequest('\Omnipay\FirstData\Message\WebserviceAuthorizeRequest', $parameters); 379 | } 380 | 381 | /** 382 | * Create a capture request. 383 | * 384 | * @param array $parameters 385 | * @return \Omnipay\FirstData\Message\WebserviceCaptureRequest 386 | */ 387 | public function capture(array $parameters = array()) 388 | { 389 | return $this->createRequest('\Omnipay\FirstData\Message\WebserviceCaptureRequest', $parameters); 390 | } 391 | 392 | /** 393 | * Create a void request. 394 | * 395 | * @param array $parameters 396 | * @return \Omnipay\FirstData\Message\WebserviceVoidRequest 397 | */ 398 | public function void(array $parameters = array()) 399 | { 400 | return $this->createRequest('\Omnipay\FirstData\Message\WebserviceVoidRequest', $parameters); 401 | } 402 | 403 | /** 404 | * Create a refund request. 405 | * 406 | * @param array $parameters 407 | * @return \Omnipay\FirstData\Message\WebserviceRefundRequest 408 | */ 409 | public function refund(array $parameters = array()) 410 | { 411 | return $this->createRequest('\Omnipay\FirstData\Message\WebserviceRefundRequest', $parameters); 412 | } 413 | } 414 | -------------------------------------------------------------------------------- /tests/GatewayTest.php: -------------------------------------------------------------------------------- 1 | gateway = new ConnectGateway($this->getHttpClient(), $this->getHttpRequest()); 14 | $this->gateway->setSharedSecret('96MbdNvxTa'); 15 | $this->gateway->setStoreId('1120540155'); 16 | 17 | $this->options = array( 18 | 'amount' => '13.00', 19 | 'returnUrl' => 'https://www.example.com/return', 20 | 'card' => $this->getValidCard(), 21 | 'transactionId' => 'abc123', 22 | 'currency' => 'GBP', 23 | 'customerId' => 54321 24 | ); 25 | } 26 | 27 | public function testPurchase() 28 | { 29 | $response = $this->gateway->purchase($this->options)->send(); 30 | 31 | $this->assertFalse($response->isSuccessful()); 32 | $this->assertTrue($response->isRedirect()); 33 | $this->assertNull($response->getTransactionReference()); 34 | $this->assertContains('ipg-online.com/connect/gateway/processing', $response->getRedirectUrl()); 35 | } 36 | 37 | public function testCompletePurchaseSuccess() 38 | { 39 | $this->getHttpRequest()->request->replace( 40 | array( 41 | 'chargetotal' => '110.00', 42 | 'response_hash' => '796d7ca236576256236e92900dedfd55be08567a', 43 | 'status' => 'APPROVED', 44 | 'oid' => 'abc123456', 45 | 'txndatetime' => '2013:09:27-16:06:26', 46 | 'approval_code' => 'Y:136432:0013649958:PPXM:0015' 47 | ) 48 | ); 49 | 50 | $response = $this->gateway->completePurchase($this->options)->send(); 51 | 52 | $this->assertTrue($response->isSuccessful()); 53 | $this->assertFalse($response->isRedirect()); 54 | $this->assertEquals('abc123456', $response->getTransactionId()); 55 | $this->assertSame('APPROVED', $response->getMessage()); 56 | $this->assertNull($response->getTransactionReference()); 57 | } 58 | 59 | /** 60 | * @expectedException \Omnipay\Common\Exception\InvalidResponseException 61 | */ 62 | public function testCompletePurchaseInvalidCallbackPassword() 63 | { 64 | $this->getHttpRequest()->request->replace( 65 | array( 66 | 'chargetotal' => '110.00', 67 | 'response_hash' => 'FAKE', 68 | 'status' => 'APPROVED', 69 | 'oid' => 'abc123456', 70 | 'txndatetime' => '2013:09:27-16:06:26', 71 | 'approval_code' => 'Y:136432:0013649958:PPXM:0015' 72 | ) 73 | ); 74 | 75 | $response = $this->gateway->completePurchase($this->options)->send(); 76 | } 77 | 78 | public function testCompletePurchaseError() 79 | { 80 | $this->getHttpRequest()->request->replace( 81 | array( 82 | 'chargetotal' => '110.00', 83 | 'response_hash' => '0dfe9e4b3c6306343926207a8814a48f72087cc7', 84 | 'status' => 'DECLINED', 85 | 'oid' => 'abc1234', 86 | 'txndatetime' => '2013:09:27-16:00:19', 87 | 'approval_code' => 'N:05:DECLINED' 88 | ) 89 | ); 90 | 91 | $response = $this->gateway->completePurchase($this->options)->send(); 92 | 93 | $this->assertFalse($response->isSuccessful()); 94 | $this->assertFalse($response->isRedirect()); 95 | $this->assertEquals('abc1234', $response->getTransactionId()); 96 | $this->assertSame('DECLINED', $response->getMessage()); 97 | } 98 | 99 | /** 100 | * testPurchaseWithHostedDataId. 101 | * 102 | * Simulates a purchase with "save this card" selected 103 | */ 104 | public function testPurchaseWithHostedDataId() 105 | { 106 | $dataId = rand(); 107 | $this->options['hostedDataId'] = $dataId; 108 | 109 | $response = $this->gateway->purchase($this->options)->send(); 110 | 111 | $this->assertFalse($response->isSuccessful()); 112 | $this->assertTrue($response->isRedirect()); 113 | $requestData = $response->getRedirectData(); 114 | $this->assertEquals($dataId, $requestData['hosteddataid']); 115 | } 116 | 117 | /** 118 | * testPurchaseWithHostedDataIdAndWithoutCardFailsWithoutCVV. 119 | * 120 | * Simulates paying using a saved card, rather than passing card data 121 | * This example is checking that an exception occurs if missing the CVV number 122 | * 123 | * @expectedException \Omnipay\Common\Exception\InvalidCreditCardException 124 | */ 125 | public function testPurchaseWithHostedDataIdAndWithoutCardFailsWithoutCVV() 126 | { 127 | $dataId = rand(); 128 | $this->options['hostedDataId'] = $dataId; 129 | // Remove number to simulate repeat purchase 130 | unset($this->options['card']['number']); 131 | // Also remove required cvv to check for error 132 | unset($this->options['card']['cvv']); 133 | 134 | $response = $this->gateway->purchase($this->options)->send(); 135 | 136 | $this->assertFalse($response->isSuccessful()); 137 | $this->assertTrue($response->isRedirect()); 138 | $requestData = $response->getRedirectData(); 139 | $this->assertEquals($dataId, $requestData['hosteddataid']); 140 | } 141 | 142 | /** 143 | * testPurchaseWithHostedDataIdAndWithoutCard. 144 | * 145 | * Simulates paying using a saved card, rather than passing card data 146 | */ 147 | public function testPurchaseWithHostedDataIdAndWithoutCard() 148 | { 149 | $dataId = rand(); 150 | $this->options['hostedDataId'] = $dataId; 151 | unset($this->options['card']); 152 | $this->options['card']['cvv'] = 123; 153 | 154 | $response = $this->gateway->purchase($this->options)->send(); 155 | 156 | $this->assertFalse($response->isSuccessful()); 157 | $this->assertTrue($response->isRedirect()); 158 | $requestData = $response->getRedirectData(); 159 | $this->assertEquals($dataId, $requestData['hosteddataid']); 160 | } 161 | 162 | /** 163 | * testPurchaseErrorWhenMissingHostedDataIdAndWithoutCardNumber. 164 | * 165 | * Simulates neither hosteddataid or card data being passed, should be caught in app. 166 | * 167 | * @expectedException \Omnipay\Common\Exception\InvalidCreditCardException 168 | */ 169 | public function testPurchaseErrorWhenMissingHostedDataIdAndWithoutCardNumber() 170 | { 171 | unset($this->options['card']); 172 | $this->options['card']['cvv'] = 123; 173 | 174 | $response = $this->gateway->purchase($this->options)->send(); 175 | 176 | $this->assertFalse($response->isSuccessful()); 177 | $this->assertTrue($response->isRedirect()); 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /tests/Message/CompletePurchaseResponseTest.php: -------------------------------------------------------------------------------- 1 | getMockRequest(), 13 | array( 14 | 'chargetotal' => '110.00', 15 | 'response_hash' => '796d7ca236576256236e92900dedfd55be08567a', 16 | 'status' => 'APPROVED', 17 | 'oid' => 'abc123456', 18 | 'txndatetime' => '2013:09:27-16:06:26', 19 | 'approval_code' => 'Y:136432:0013649958:PPXM:0015' 20 | ) 21 | ); 22 | 23 | $this->assertTrue($response->isSuccessful()); 24 | $this->assertFalse($response->isRedirect()); 25 | $this->assertSame('abc123456', $response->getTransactionId()); 26 | $this->assertSame('APPROVED', $response->getMessage()); 27 | } 28 | 29 | public function testCompletePurchaseFailure() 30 | { 31 | $response = new CompletePurchaseresponse( 32 | $this->getMockRequest(), 33 | array( 34 | 'chargetotal' => '110.00', 35 | 'response_hash' => '0dfe9e4b3c6306343926207a8814a48f72087cc7', 36 | 'status' => 'DECLINED', 37 | 'oid' => 'abc1234', 38 | 'txndatetime' => '2013:09:27-16:00:19', 39 | 'approval_code' => 'N:05:DECLINED' 40 | ) 41 | ); 42 | 43 | $this->assertFalse($response->isSuccessful()); 44 | $this->assertFalse($response->isRedirect()); 45 | $this->assertSame('abc1234', $response->getTransactionId()); 46 | $this->assertSame('DECLINED', $response->getMessage()); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tests/Message/PayeezyAuthorizeRequestTest.php: -------------------------------------------------------------------------------- 1 | getHttpClient(), $this->getHttpRequest()); 12 | $request->initialize( 13 | array( 14 | 'amount' => '12.00', 15 | 'card' => $this->getValidCard(), 16 | ) 17 | ); 18 | 19 | $data = $request->getData(); 20 | $this->assertEquals('01', $data['transaction_type']); 21 | $this->assertEquals('4111111111111111', $data['cc_number']); 22 | $this->assertEquals('Visa', $data['credit_card_type']); 23 | $this->assertEquals('12.00', $data['amount']); 24 | $this->assertEquals('123 Billing St|12345|Billstown|CA|US', $data['cc_verification_str1']); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/Message/PayeezyPurchaseRequestTest.php: -------------------------------------------------------------------------------- 1 | getHttpClient(), $this->getHttpRequest()); 13 | $request->initialize( 14 | array( 15 | 'amount' => '12.00', 16 | 'card' => $this->getValidCard(), 17 | ) 18 | ); 19 | 20 | $data = $request->getData(); 21 | $this->assertEquals('00', $data['transaction_type']); 22 | $this->assertEquals('4111111111111111', $data['cc_number']); 23 | $this->assertEquals('Visa', $data['credit_card_type']); 24 | $this->assertEquals('12.00', $data['amount']); 25 | $this->assertEquals('123 Billing St|12345|Billstown|CA|US', $data['cc_verification_str1']); 26 | } 27 | 28 | public function testPurchaseSuccessMaestroType() 29 | { 30 | $options = array( 31 | 'amount' => '12.00', 32 | 'card' => $this->getValidCard(), 33 | ); 34 | 35 | $options['card']['number'] = '6304000000000000'; 36 | 37 | $request = new PayeezyPurchaseRequest($this->getHttpClient(), $this->getHttpRequest()); 38 | $request->initialize($options); 39 | 40 | $data = $request->getData(); 41 | $this->assertEquals('00', $data['transaction_type']); 42 | $this->assertEquals('maestro', $data['credit_card_type']); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tests/Message/PayeezyPurchaseResponseTest.php: -------------------------------------------------------------------------------- 1 | getMockRequest(), json_encode(array( 13 | 'amount' => 1000, 14 | 'exact_resp_code' => 00, 15 | 'exact_message' => 'Transaction Normal', 16 | 'reference_no' => 'abc123', 17 | 'authorization_num' => 'auth1234', 18 | 'transaction_approved' => 1, 19 | ))); 20 | 21 | $this->assertTrue($response->isSuccessful()); 22 | $this->assertEquals('auth1234::', $response->getTransactionReference()); 23 | $this->assertSame('Transaction Normal', $response->getMessage()); 24 | $this->assertEquals('00', $response->getCode()); 25 | } 26 | 27 | public function testPurchaseError() 28 | { 29 | $response = new PayeezyResponse($this->getMockRequest(), json_encode(array( 30 | 'amount' => 1000, 31 | 'exact_resp_code' => 22, 32 | 'exact_message' => 'Invalid Credit Card Number', 33 | 'reference_no' => 'abc123', 34 | 'authorization_num' => 'auth1234', 35 | 'transaction_approved' => 0, 36 | ))); 37 | 38 | $this->assertFalse($response->isSuccessful()); 39 | $this->assertEquals('auth1234::', $response->getTransactionReference()); 40 | $this->assertSame('Invalid Credit Card Number', $response->getMessage()); 41 | $this->assertEquals('22', $response->getCode()); 42 | } 43 | 44 | public function testBankError() 45 | { 46 | $response = new PayeezyResponse($this->getMockRequest(), json_encode(array( 47 | 'amount' => 1000, 48 | 'exact_resp_code' => 00, 49 | 'reference_no' => 'abc123', 50 | 'authorization_num' => '', 51 | 'transaction_approved' => 0, 52 | ))); 53 | 54 | $this->assertFalse($response->isSuccessful()); 55 | $this->assertEquals('::', $response->getTransactionReference()); 56 | $this->assertEquals('00', $response->getCode()); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /tests/Message/PayeezyRefundRequestTest.php: -------------------------------------------------------------------------------- 1 | getHttpClient(), $this->getHttpRequest()); 12 | $request->initialize( 13 | array( 14 | 'amount' => '12.00', 15 | 'transactionReference' => '9999::DATADATADATA', 16 | ) 17 | ); 18 | 19 | $data = $request->getData(); 20 | $this->assertEquals('9999', $data['authorization_num']); 21 | $this->assertEquals('DATADATADATA', $data['transaction_tag']); 22 | $this->assertEquals('12.00', $data['amount']); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/Message/PurchaseResponseTest.php: -------------------------------------------------------------------------------- 1 | getMockRequest(), array( 12 | 'amount' => 1000, 13 | 'returnUrl' => 'https://www.example.com/return', 14 | )); 15 | 16 | $this->assertFalse($response->isSuccessful()); 17 | $this->assertTrue($response->isRedirect()); 18 | $this->assertNull($response->getTransactionReference()); 19 | $this->assertNull($response->getMessage()); 20 | $this->assertSame('POST', $response->getRedirectMethod()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/Message/WebserviceCaptureRequestTest.php: -------------------------------------------------------------------------------- 1 | getHttpClient(), $this->getHttpRequest()); 12 | $request->initialize( 13 | array( 14 | 'transactionReference' => '98765::ABCDEF', 15 | ) 16 | ); 17 | 18 | $data = $request->getData(); 19 | $this->assertEquals('postAuth', $data['txn_type']); 20 | $this->assertEquals('98765', $data['reference_no']); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/Message/WebservicePurchaseRequestTest.php: -------------------------------------------------------------------------------- 1 | getHttpClient(), $this->getHttpRequest()); 12 | $request->initialize( 13 | array( 14 | 'amount' => '12.00', 15 | 'transactionId' => '98765', 16 | 'accountId' => '67890', 17 | 'card' => $this->getValidCard(), 18 | 'testMode' => true, 19 | ) 20 | ); 21 | 22 | $data = $request->getData(); 23 | $this->assertEquals('sale', $data['txn_type']); 24 | $this->assertEquals('4111111111111111', $data['card_number']); 25 | $this->assertEquals('12.00', $data['amount']); 26 | $this->assertEquals('123 Billing St', $data['card_address1']); 27 | $this->assertEquals('Billstown', $data['card_city']); 28 | $this->assertEquals('12345', $data['card_postcode']); 29 | $this->assertEquals('CA', $data['card_state']); 30 | $this->assertEquals('US', $data['card_country']); 31 | $this->assertEquals('98765', $data['reference_no']); 32 | 33 | // Test request internals 34 | $curl = $request->buildCurlClient(); 35 | $this->assertTrue(is_resource($curl)); 36 | 37 | $endpoint = $request->getEndpoint(); 38 | $this->assertEquals('https://ws.merchanttest.firstdataglobalgateway.com:443/fdggwsapi/services', $endpoint); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tests/Message/WebserviceRefundRequestTest.php: -------------------------------------------------------------------------------- 1 | getHttpClient(), $this->getHttpRequest()); 12 | $request->initialize( 13 | array( 14 | 'amount' => '12.00', 15 | 'transactionReference' => '98765::ABCDEF', 16 | ) 17 | ); 18 | 19 | $data = $request->getData(); 20 | $this->assertEquals('return', $data['txn_type']); 21 | $this->assertEquals('12.00', $data['amount']); 22 | $this->assertEquals('98765', $data['reference_no']); 23 | $this->assertEquals('ABCDEF', $data['tdate']); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/Message/WebserviceVoidRequestTest.php: -------------------------------------------------------------------------------- 1 | getHttpClient(), $this->getHttpRequest()); 12 | $request->initialize( 13 | array( 14 | 'transactionReference' => '98765::ABCDEF', 15 | ) 16 | ); 17 | 18 | $data = $request->getData(); 19 | $this->assertEquals('void', $data['txn_type']); 20 | $this->assertEquals('98765', $data['reference_no']); 21 | $this->assertEquals('ABCDEF', $data['tdate']); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/Mock/PurchaseSuccess.txt: -------------------------------------------------------------------------------- 1 | HTTP/1.1 201 OK 2 | Date: Tue, 11 Feb 2014 02:34:58 GMT 3 | Content-type: text/html; charset=utf-8 4 | 5 | {"account_number":"","amount":"13.0","amount_requested":"","authorization":"","authorization_num":"ET181147","avs":"1","bank_id":"","bank_message":"Approved","bank_resp_code":"100","bank_resp_code_2":"","card_cost":"","cardholder_name":"Example User","cavv":"","cavv_algorithm":"","cavv_response":"","cc_expiry":"0318","cc_number":"############1111","cc_verification_str1":"123 Billing St|12345|Billstown|CA|US","cc_verification_str2":"208","check_number":"","check_type":"","clerk_id":"","client_email":"","client_ip":"104.36.244.246","correlation_id":"","credit_card_type":"Visa","ctr":"=========== TRANSACTION RECORD ==========\nPriceWaiter DEMO0243\n426 Market St\nChattenooga, TN 37402\nUnited States\nhttps:\/\/www.pricewaiter.com\/\n\nTYPE: Purchase\n\nACCT: Visa $ 13.00 USD\n\nCARDHOLDER NAME : Example User\nCARD NUMBER : ############1111\nDATE\/TIME : 11 Aug 14 14:09:06\nREFERENCE # : 000056 M\nAUTHOR. # : ET181147\nTRANS. REF. : order2\n\n Approved - Thank You 100\n\n\nPlease retain this copy for your records.\n\nCardholder will pay above amount to card\nissuer pursuant to cardholder agreement.\n=========================================","currency_code":"USD","current_balance":"","customer_id_number":"","customer_id_type":"","customer_name":"","customer_ref":"","cvd_presence_ind":"0","cvv2":"N","date_of_birth":"","device_id":"","ean":"","ecommerce_flag":"","error_description":"","error_number":"","exact_message":"Transaction Normal","exact_resp_code":"00","fraud_suspected":"","gateway_id":"AF8163-05","gift_card_amount":"","gross_amount_currency_id":"","language":"","logon_message":"","merchant_address":"426 Market St","merchant_city":"Chattenooga","merchant_country":"United States","merchant_name":"PriceWaiter DEMO0243","merchant_postal":"37402","merchant_province":"Tennessee","merchant_url":"https:\/\/www.pricewaiter.com\/","message":"","micr":"","pan":"","partial_redemption":"0","password":"","payer_id":"","previous_balance":"","reference_3":"","reference_no":"order2","registration_date":"","registration_no":"","release_type":"","retrieval_ref_no":"7775501","secure_auth_required":"","secure_auth_result":"","sequence_no":"000056","success":"","surcharge_amount":"","tax1_amount":"","tax1_number":"","tax2_amount":"","tax2_number":"","timestamp":"","track1":"","track2":"","transaction_approved":"1","transaction_error":"0","transaction_tag":"28513493","transaction_type":"00","transarmor_token":"","user_name":"","vip":"","virtual_card":"","xid":"","zip_code":""} 6 | -------------------------------------------------------------------------------- /tests/Mock/RefundError.txt: -------------------------------------------------------------------------------- 1 | HTTP/1.1 201 OK 2 | Date: Tue, 11 Feb 2014 02:34:58 GMT 3 | Content-type: text/html; charset=utf-8 4 | 5 | account_number=&amount=13.0&amount_requested=&authorization=&authorization_num=&avs=&bank_id=&bank_message=&bank_resp_code=&bank_resp_code_2=&card_cost=&cardholder_name=&cavv=&cavv_algorithm=&cavv_response=&cc_expiry=9999&cc_number=&cc_verification_str1=&cc_verification_str2=&check_number=&check_type=&clerk_id=&client_email=&client_ip=&correlation_id=&credit_card_type=&ctr=¤cy_code=USD¤t_balance=&customer_id_number=&customer_id_type=&customer_name=&customer_ref=&cvd_presence_ind=0&cvv2=&date_of_birth=&device_id=&ean=&ecommerce_flag=&error_description=&error_number=&exact_message=Invalid+Refund&exact_resp_code=64&fraud_suspected=&gateway_id=AF8163-05&gift_card_amount=&gross_amount_currency_id=&language=&logon_message=&merchant_address=426+Market+St&merchant_city=Chattenooga&merchant_country=United+States&merchant_name=PriceWaiter+DEMO0243&merchant_postal=37402&merchant_province=Tennessee&merchant_url=https%3A%2F%2Fwww.pricewaiter.com%2F&message=&micr=&pan=&partial_redemption=0&password=&payer_id=&previous_balance=&reference_3=&reference_no=order2®istration_date=®istration_no=&release_type=&retrieval_ref_no=&secure_auth_required=&secure_auth_result=&sequence_no=000056&success=&surcharge_amount=&tax1_amount=&tax1_number=&tax2_amount=&tax2_number=×tamp=&track1=&track2=&transaction_approved=0&transaction_error=1&transaction_tag=28513493&transaction_type=34&transarmor_token=&user_name=&vip=&virtual_card=&xid=&zip_code= 6 | -------------------------------------------------------------------------------- /tests/Mock/RefundSuccess.txt: -------------------------------------------------------------------------------- 1 | HTTP/1.1 201 OK 2 | Date: Tue, 11 Feb 2014 02:34:58 GMT 3 | Content-type: text/html; charset=utf-8 4 | 5 | account_number=&amount=13.0&amount_requested=&authorization=&authorization_num=ET181147&avs=&bank_id=&bank_message=Approved&bank_resp_code=100&bank_resp_code_2=&card_cost=&cardholder_name=Example+User&cavv=&cavv_algorithm=&cavv_response=&cc_expiry=0318&cc_number=%23%23%23%23%23%23%23%23%23%23%23%231111&cc_verification_str1=&cc_verification_str2=&check_number=&check_type=&clerk_id=&client_email=&client_ip=&correlation_id=&credit_card_type=Visa&ctr=¤cy_code=USD¤t_balance=&customer_id_number=&customer_id_type=&customer_name=&customer_ref=&cvd_presence_ind=0&cvv2=&date_of_birth=&device_id=&ean=&ecommerce_flag=&error_description=&error_number=&exact_message=Transaction+Normal&exact_resp_code=00&fraud_suspected=&gateway_id=AF8163-05&gift_card_amount=&gross_amount_currency_id=&language=&logon_message=&merchant_address=426+Market+St&merchant_city=Chattenooga&merchant_country=United+States&merchant_name=PriceWaiter+DEMO0243&merchant_postal=37402&merchant_province=Tennessee&merchant_url=https%3A%2F%2Fwww.pricewaiter.com%2F&message=&micr=&pan=&partial_redemption=0&password=&payer_id=&previous_balance=&reference_3=&reference_no=order2®istration_date=®istration_no=&release_type=&retrieval_ref_no=7775501&secure_auth_required=&secure_auth_result=&sequence_no=000056&success=&surcharge_amount=&tax1_amount=&tax1_number=&tax2_amount=&tax2_number=×tamp=&track1=&track2=&transaction_approved=1&transaction_error=0&transaction_tag=28513493&transaction_type=34&transarmor_token=&user_name=&vip=&virtual_card=&xid=&zip_code= 6 | -------------------------------------------------------------------------------- /tests/Mock/WebservicePurchaseSuccess.txt: -------------------------------------------------------------------------------- 1 | CSISun Jan 10 23:34:04 201621840362OK242CAPPROVED259611OK242C0021840362:XXRnull:XXRnull1452486844APPROVEDAERRORConfiguration Error. 2 | -------------------------------------------------------------------------------- /tests/PayeezyGatewayTest.php: -------------------------------------------------------------------------------- 1 | gateway = new PayeezyGateway($this->getHttpClient(), $this->getHttpRequest()); 20 | $this->gateway->setGatewayId('1234'); 21 | $this->gateway->setPassword('abcde'); 22 | 23 | $this->options = array( 24 | 'amount' => '13.00', 25 | 'card' => $this->getValidCard(), 26 | 'transactionId' => 'order2', 27 | 'currency' => 'USD', 28 | 'testMode' => true, 29 | ); 30 | } 31 | 32 | public function testProperties() 33 | { 34 | $this->assertEquals('1234', $this->gateway->getGatewayId()); 35 | $this->assertEquals('abcde', $this->gateway->getPassword()); 36 | } 37 | 38 | public function testPurchaseSuccess() 39 | { 40 | $this->setMockHttpResponse('PurchaseSuccess.txt'); 41 | 42 | $response = $this->gateway->purchase($this->options)->send(); 43 | 44 | $this->assertTrue($response->isSuccessful()); 45 | $this->assertFalse($response->isRedirect()); 46 | $this->assertEquals('ET181147::28513493', $response->getTransactionReference()); 47 | $this->assertEquals('000056', $response->getSequenceNo()); 48 | $this->assertEmpty($response->getCardReference()); 49 | } 50 | 51 | public function testAuthorizeSuccess() 52 | { 53 | $this->setMockHttpResponse('PurchaseSuccess.txt'); 54 | 55 | $response = $this->gateway->authorize($this->options)->send(); 56 | 57 | $this->assertTrue($response->isSuccessful()); 58 | $this->assertFalse($response->isRedirect()); 59 | $this->assertEquals('ET181147::28513493', $response->getTransactionReference()); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /tests/WebserviceGatewayTest.php: -------------------------------------------------------------------------------- 1 | gateway = new WebserviceGateway($this->getHttpClient(), $this->getHttpRequest()); 20 | $this->gateway->setSslCertificate('my.pem'); 21 | $this->gateway->setSslKey('my.key'); 22 | $this->gateway->setSslKeyPassword('thisISaPASSWORD'); 23 | $this->gateway->setUserName('1234'); 24 | $this->gateway->setPassword('abcde'); 25 | 26 | $this->options = array( 27 | 'accountId' => '12345', 28 | 'transactionId' => '259611', 29 | 'amount' => '10.00', 30 | 'currency' => 'USD', 31 | 'clientIp' => '127.0.0.1', 32 | 'card' => $this->getValidCard(), 33 | 'testMode' => true, 34 | ); 35 | } 36 | 37 | public function testProperties() 38 | { 39 | $this->assertEquals('my.pem', $this->gateway->getSslCertificate()); 40 | $this->assertEquals('my.key', $this->gateway->getSslKey()); 41 | $this->assertEquals('thisISaPASSWORD', $this->gateway->getSslKeyPassword()); 42 | $this->assertEquals('1234', $this->gateway->getUserName()); 43 | $this->assertEquals('abcde', $this->gateway->getPassword()); 44 | } 45 | 46 | public function testPurchaseSuccess() 47 | { 48 | // Mocks don't work on this gateway because it has to call cURL directly. 49 | // $this->setMockHttpResponse('WebservicePurchaseSuccess.txt'); 50 | $data = file_get_contents(__DIR__ . '/Mock/WebservicePurchaseSuccess.txt'); 51 | 52 | $purchase = $this->gateway->purchase($this->options); 53 | $response = $purchase->createResponse($data); 54 | 55 | // echo "Response data =\n"; 56 | // print_r($response->getData()); 57 | // echo "\nEnd Response data\n"; 58 | 59 | $this->assertTrue($response->isSuccessful()); 60 | $this->assertFalse($response->isRedirect()); 61 | $this->assertEquals('259611::1452486844', $response->getTransactionReference()); 62 | $this->assertNull($response->getMessage()); 63 | $this->assertEquals('APPROVED', $response->getCode()); 64 | } 65 | } 66 | --------------------------------------------------------------------------------