diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dcfb845 --- /dev/null +++ b/.gitignore @@ -0,0 +1,55 @@ +# Created by .ignore support plugin (hsz.mobi) +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff: +.idea/workspace.xml +.idea/tasks.xml +.idea/dictionaries +.idea/vcs.xml +.idea/jsLibraryMappings.xml + +# Sensitive or high-churn files: +.idea/dataSources.ids +.idea/dataSources.xml +.idea/dataSources.local.xml +.idea/sqlDataSources.xml +.idea/dynamic.xml +.idea/uiDesigner.xml + +# Gradle: +.idea/gradle.xml +.idea/libraries + +# Mongo Explorer plugin: +.idea/mongoSettings.xml + +## File-based project format: +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties +### Example user template template +### Example user template + +# IntelliJ project files +.idea +*.iml +out +gen +vendor \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..258e079 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Aleksandr Zhiliaev + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index a2358ba..95a0558 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,7 @@ # omnipay-payeer -Payeer gateway for Omnipay payment processing library +Payeer gateway for [Omnipay](https://github.com/thephpleague/omnipay) payment processing library. + +## To-do +- Full documentation +- Handling all custom parameters +- Unit tests \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..7df5aaa --- /dev/null +++ b/composer.json @@ -0,0 +1,36 @@ +{ + "name": "aleksandrzhiliaev/omnipay-payeer", + "type": "library", + "description": "Payeer gateway for Omnipay payment processing library", + "keywords": [ + "gateway", + "merchant", + "omnipay", + "pay", + "payment", + "payeer", + "purchase" + ], + "homepage": "http://sassoft.ru", + "license": "", + "authors": [ + { + "name": "Aleksandr Zhiliaev", + "email": "sassoftinc@gmail.com" + } + ], + "autoload": { + "psr-4": { "Omnipay\\Payeer\\" : "src/" } + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + } +} diff --git a/src/Gateway.php b/src/Gateway.php new file mode 100644 index 0000000..73e4435 --- /dev/null +++ b/src/Gateway.php @@ -0,0 +1,92 @@ +getParameter('account'); + } + + public function setAccount($value) + { + return $this->setParameter('account', $value); + } + + public function getApiId() + { + return $this->getParameter('api_id'); + } + + public function setApiId($value) + { + return $this->setParameter('api_id', $value); + } + + public function getApiSecret() + { + return $this->getParameter('api_secret'); + } + + public function setApiSecret($value) + { + return $this->setParameter('api_secret', $value); + } + + public function getShopId() + { + return $this->getParameter('shop_id'); + } + + public function setShopId($value) + { + return $this->setParameter('shop_id', $value); + } + + public function getShopSecret() + { + return $this->getParameter('shop_secret'); + } + + public function setShopSecret($value) + { + return $this->setParameter('shop_secret', $value); + } + + public function getDefaultParameters() + { + return array( + 'account' => '', + 'api_id' => '', + 'api_secret' => '', + 'shop_id' => '', + 'shop_secret' => '', + ); + } + + public function purchase(array $parameters = array()) + { + return $this->createRequest('\Omnipay\Payeer\Message\PurchaseRequest', $parameters); + } + + public function completePurchase(array $parameters = array()) + { + return $this->createRequest('\Omnipay\Payeer\Message\CompletePurchaseRequest', $parameters); + } + + public function refund(array $parameters = array()) + { + return $this->createRequest('\Omnipay\Payeer\Message\RefundRequest', $parameters); + } +} diff --git a/src/Message/AbstractRequest.php b/src/Message/AbstractRequest.php new file mode 100644 index 0000000..b5bc66d --- /dev/null +++ b/src/Message/AbstractRequest.php @@ -0,0 +1,17 @@ +liveMerchantEndpoint; + } +} diff --git a/src/Message/CompletePurchaseRequest.php b/src/Message/CompletePurchaseRequest.php new file mode 100644 index 0000000..5d7892b --- /dev/null +++ b/src/Message/CompletePurchaseRequest.php @@ -0,0 +1,57 @@ +getParameter('shop_secret'); + } + + public function setShopSecret($value) + { + return $this->setParameter('shop_secret', $value); + } + + public function getData() + { + if ($this->httpRequest->request->get('m_curr') != $this->getCurrency()) { + throw new InvalidResponseException("Invalid m_curr:".$this->httpRequest->request->get('m_curr')); + } + + if ($this->httpRequest->request->get('m_status') != 'success') { + throw new InvalidResponseException("Invalid m_status:".$this->httpRequest->request->get('m_status')); + } + + $arHash = [ + $this->httpRequest->request->get('m_operation_id'), + $this->httpRequest->request->get('m_operation_ps'), + $this->httpRequest->request->get('m_operation_date'), + $this->httpRequest->request->get('m_operation_pay_date'), + $this->httpRequest->request->get('m_shop'), + $this->httpRequest->request->get('m_orderid'), + $this->httpRequest->request->get('m_amount'), + $this->httpRequest->request->get('m_curr'), + $this->httpRequest->request->get('m_desc'), + $this->httpRequest->request->get('m_status'), + $this->getShopSecret(), + ]; + $sign_hash = strtoupper(hash('sha256', implode(':', $arHash))); + + if ($this->httpRequest->request->get('m_sign') != $sign_hash) { + throw new InvalidResponseException("Invalid m_sign"); + } + + echo $this->httpRequest->request->get('m_orderid').'|success'; + + return $this->httpRequest->request->all(); + } + + public function sendData($data) + { + return $this->response = new CompletePurchaseResponse($this, $data); + } +} diff --git a/src/Message/CompletePurchaseResponse.php b/src/Message/CompletePurchaseResponse.php new file mode 100644 index 0000000..bdc4ed9 --- /dev/null +++ b/src/Message/CompletePurchaseResponse.php @@ -0,0 +1,54 @@ +data['m_status'] == 'success') ? true : false; + } + + public function isCancelled() + { + return ($this->data['m_status'] != 'success') ? true : false; + } + + public function isRedirect() + { + return false; + } + + public function getRedirectUrl() + { + return null; + } + + public function getRedirectMethod() + { + return null; + } + + public function getRedirectData() + { + return null; + } + + public function getTransactionId() + { + return intval($this->data['m_orderid']); + } + + public function getAmount() + { + return floatval($this->data['m_amount']); + } + + public function getMessage() + { + return null; + } +} diff --git a/src/Message/PurchaseRequest.php b/src/Message/PurchaseRequest.php new file mode 100644 index 0000000..26eddf8 --- /dev/null +++ b/src/Message/PurchaseRequest.php @@ -0,0 +1,66 @@ +getParameter('account'); + } + + public function setAccount($value) + { + return $this->setParameter('account', $value); + } + + public function getShopId() + { + return $this->getParameter('shop_id'); + } + + public function setShopId($value) + { + return $this->setParameter('shop_id', $value); + } + + public function getShopSecret() + { + return $this->getParameter('shop_secret'); + } + + public function setShopSecret($value) + { + return $this->setParameter('shop_secret', $value); + } + + public function getData() + { + $this->validate('account', 'currency', 'amount', 'description'); + + $arHash = [ + $this->getShopId(), + $this->getTransactionId(), + $this->getAmount(), + $this->getCurrency(), + base64_encode($this->getDescription()), + $this->getShopSecret(), + ]; + $sign = strtoupper(hash('sha256', implode(":", $arHash))); + + $data['m_shop'] = $this->getShopId(); + $data['m_orderid'] = $this->getTransactionId(); + $data['m_amount'] = $this->getAmount(); + $data['m_curr'] = $this->getCurrency(); + $data['m_desc'] = base64_encode($this->getDescription()); + $data['m_sign'] = $sign; + + return $data; + } + + public function sendData($data) + { + return $this->response = new PurchaseResponse($this, $data, $this->getMerchantEndpoint()); + } +} diff --git a/src/Message/PurchaseResponse.php b/src/Message/PurchaseResponse.php new file mode 100644 index 0000000..8599890 --- /dev/null +++ b/src/Message/PurchaseResponse.php @@ -0,0 +1,44 @@ +redirectUrl = $redirectUrl; + } + + public function isSuccessful() + { + return false; + } + + public function isRedirect() + { + return true; + } + + public function getRedirectUrl() + { + return $this->redirectUrl; + } + + public function getRedirectMethod() + { + return 'POST'; + } + + public function getRedirectData() + { + return $this->data; + } +} diff --git a/src/Message/RefundRequest.php b/src/Message/RefundRequest.php new file mode 100644 index 0000000..091f1b9 --- /dev/null +++ b/src/Message/RefundRequest.php @@ -0,0 +1,75 @@ +getParameter('account'); + } + + public function setAccount($value) + { + return $this->setParameter('account', $value); + } + + public function getApiId() + { + return $this->getParameter('api_id'); + } + + public function setApiId($value) + { + return $this->setParameter('api_id', $value); + } + + public function getApiSecret() + { + return $this->getParameter('api_secret'); + } + + public function setApiSecret($value) + { + return $this->setParameter('api_secret', $value); + } + + public function getPayeeAccount() + { + return $this->getParameter('payeeAccount'); + } + + public function setPayeeAccount($value) + { + return $this->setParameter('payeeAccount', $value); + } + + public function getData() + { + $this->validate('payeeAccount', 'amount', 'currency', 'description'); + + $data['apiPass'] = $this->getApiSecret(); + $data['apiId'] = $this->getApiId(); + $data['account'] = $this->getAccount(); + $data['sum'] = $this->getAmount(); + $data['curIn'] = $this->getCurrency(); + $data['curOut'] = $this->getCurrency(); + $data['to'] = $this->getPayeeAccount(); + $data['comment'] = $this->getDescription(); + $data['action'] = 'transfer'; + + return $data; + } + + public function sendData($data) + { + $httpResponse = $this->httpClient->post($this->endpoint, null, $data)->send(); + $jsonResponse = json_decode($httpResponse->getBody(true)); + return $this->response = new RefundResponse($this, $jsonResponse); + } + +} diff --git a/src/Message/RefundResponse.php b/src/Message/RefundResponse.php new file mode 100644 index 0000000..62aa440 --- /dev/null +++ b/src/Message/RefundResponse.php @@ -0,0 +1,43 @@ +request = $request; + $this->data = $data; + $this->success = false; + $this->parseResponse($data); + } + + public function isSuccessful() + { + return $this->success; + } + + public function getMessage() + { + return $this->message; + } + + private function parseResponse($data) + { + if (is_array($data->errors) && count($data->errors)) { + $this->message = implode(" | ", $data->errors); + $this->success = false; + return false; + } + $this->success = true; + } + +}