From 3d186064a86a4b2143c7ba441c5c142df5e3a2eb Mon Sep 17 00:00:00 2001 From: Ed Mark Date: Mon, 23 May 2016 14:47:18 +0300 Subject: [PATCH 1/2] remove old --- DIEGIMAS.txt | 10 - README.md | 21 - README.txt | 10 - .../local/Mage/Paysera/Block/Callback.php | 33 - app/code/local/Mage/Paysera/Block/Form.php | 13 - .../local/Mage/Paysera/Block/Redirect.php | 51 - .../Mage/Paysera/Model/PaymentMethod.php | 124 -- .../Paysera/controllers/PayController.php | 57 - app/code/local/Mage/Paysera/etc/config.xml | 62 - app/code/local/Mage/Paysera/etc/system.xml | 60 - .../Mage/Paysera/libwebtopay/WebToPay.php | 1202 ----------------- .../default/template/paysera/form.phtml | 6 - app/etc/modules/Mage_Paysera.xml | 12 - 13 files changed, 1661 deletions(-) delete mode 100644 DIEGIMAS.txt delete mode 100644 README.md delete mode 100644 README.txt delete mode 100644 app/code/local/Mage/Paysera/Block/Callback.php delete mode 100644 app/code/local/Mage/Paysera/Block/Form.php delete mode 100644 app/code/local/Mage/Paysera/Block/Redirect.php delete mode 100644 app/code/local/Mage/Paysera/Model/PaymentMethod.php delete mode 100644 app/code/local/Mage/Paysera/controllers/PayController.php delete mode 100644 app/code/local/Mage/Paysera/etc/config.xml delete mode 100644 app/code/local/Mage/Paysera/etc/system.xml delete mode 100644 app/code/local/Mage/Paysera/libwebtopay/WebToPay.php delete mode 100644 app/design/frontend/default/default/template/paysera/form.phtml delete mode 100644 app/etc/modules/Mage_Paysera.xml diff --git a/DIEGIMAS.txt b/DIEGIMAS.txt deleted file mode 100644 index 2174b1b..0000000 --- a/DIEGIMAS.txt +++ /dev/null @@ -1,10 +0,0 @@ -Diegimas - -1. Padarykite atsargine failu kopija[nebutina]. -2. Nukopijuokite viska i magento direktorija. -3. Isjunkite visus cache. -4. System -> Configuration -> Payments -> Paysera.com (irasykite Jusu Mokejimai.lt duomenis). - -Kontaktai - -Kilus klausimams prasome kreiptis i pagalba@mokejimai.lt \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index 60873dd..0000000 --- a/README.md +++ /dev/null @@ -1,21 +0,0 @@ -plugin-magento -============== - -Paysera.com payment gateway plugin for Magento - -Requirements ------------- - -- Magento - -Installation ------------- - -1. Download this repository as zip and extract "app" folder into magento main directory. -2. Turn off all cache. -3. System -> Configuration -> Payments -> Paysera.com (write your Paysera.com project data). - -Contacts --------- - -If any problems occur please feel free to seek help via support@paysera.com \ No newline at end of file diff --git a/README.txt b/README.txt deleted file mode 100644 index 8798b9a..0000000 --- a/README.txt +++ /dev/null @@ -1,10 +0,0 @@ -Installation - -1. BACKUP ALL FILES [optional]. -2. Copy all files to magento directory. -3. Turn off all cache. -4. System -> Configuration -> Payments -> Paysera.com (write your Paysera.com project data). - -Contacts - -If any problems occur please feel free to seek help via support@paysera.com \ No newline at end of file diff --git a/app/code/local/Mage/Paysera/Block/Callback.php b/app/code/local/Mage/Paysera/Block/Callback.php deleted file mode 100644 index bbe2030..0000000 --- a/app/code/local/Mage/Paysera/Block/Callback.php +++ /dev/null @@ -1,33 +0,0 @@ -validateCallback(); - } -} diff --git a/app/code/local/Mage/Paysera/Block/Form.php b/app/code/local/Mage/Paysera/Block/Form.php deleted file mode 100644 index b7cfe4b..0000000 --- a/app/code/local/Mage/Paysera/Block/Form.php +++ /dev/null @@ -1,13 +0,0 @@ -setTemplate('paysera/form.phtml'); - - parent::_construct(); - } -} - -?> \ No newline at end of file diff --git a/app/code/local/Mage/Paysera/Block/Redirect.php b/app/code/local/Mage/Paysera/Block/Redirect.php deleted file mode 100644 index 173c34f..0000000 --- a/app/code/local/Mage/Paysera/Block/Redirect.php +++ /dev/null @@ -1,51 +0,0 @@ -setAction($paysera->getPayURL()) - ->setId('paysera_checkout') - ->setName('paysera_checkout') - ->setMethod('POST') - ->setUseContainer(true); - foreach ($paysera->getRequest() as $field=>$value) { - $form->addField($field, 'hidden', array('name'=>$field, 'value'=>$value)); - } - $html = ''; - $html.= ''; - $html.= ''; - $html.= $this->__('...'); - $html.= $form->toHtml(); - $html.= ''; - $html.= ''; - - return $html; - } -} diff --git a/app/code/local/Mage/Paysera/Model/PaymentMethod.php b/app/code/local/Mage/Paysera/Model/PaymentMethod.php deleted file mode 100644 index 6cf5848..0000000 --- a/app/code/local/Mage/Paysera/Model/PaymentMethod.php +++ /dev/null @@ -1,124 +0,0 @@ -load(Mage::getSingleton('checkout/session')->getLastOrderId()); - - $pData = Mage::getStoreConfig('payment/paysera'); - $language = substr(Mage::app()->getLocale()->getLocaleCode(), 3, 5); - - $address = $this->getCustomerAddressInfo($order); - - try { - $request = WebToPay::buildRequest(array( - 'projectid' => $pData['api_key'], - 'sign_password' => $pData['api_secret'], - - 'orderid' => $order->increment_id, - 'amount' => intval(number_format(($order->grand_total * 100), 0, '', '')), - 'currency' => $order->order_currency_code, - 'lang' => ($language === 'LT') ? 'LTU' : 'ENG', - - 'accepturl' => Mage::getUrl('paysera/pay/success'), - 'cancelurl' => Mage::getUrl('paysera/pay/cancel'), - 'callbackurl' => Mage::getUrl('paysera/pay/callback'), - 'payment' => '', - 'country' => 'LT', - - 'p_firstname' => $order->customer_firstname, - 'p_lastname' => $order->customer_lastname, - 'p_email' => $order->customer_email, - 'p_street' => $address['Street'], - 'p_city' => $address['City'], - 'p_state' => '', - 'p_zip' => $address['Postcode'], - - 'test' => $pData['test'], - )); - } catch (WebToPayException $e) { - echo get_class($e) . ': ' . $e->getMessage(); - } - - return $request; - } - - public function getPayUrl() { - require_once(Mage::getBaseDir() . '/app/code/local/Mage/Paysera/libwebtopay/WebToPay.php'); - return WebToPay::PAY_URL; - } - - public function validateCallback() { - include_once(Mage::getBaseDir() . '/app/code/local/Mage/Paysera/libwebtopay/WebToPay.php'); - if ($_REQUEST[WebToPay::PREFIX . 'status'] == 1) { - - - $order = Mage::getModel('sales/order')->loadByIncrementId($_REQUEST[WebToPay::PREFIX . 'orderid']); - $pData = Mage::getStoreConfig('payment/paysera'); - - $response_amount = intval(number_format($_REQUEST[WebToPay::PREFIX . 'amount'], 0, '', '')); - $system_amount = intval(number_format(($order->grand_total * 100), 0, '', '')); - - if ($response_amount < $system_amount) { - return 'Bad amount: ' . $response_amount . ' Should be: ' . $system_amount; - } - - if ($_REQUEST[WebToPay::PREFIX . 'currency'] != $order->order_currency_code) { - return 'Bad currency: ' . $_REQUEST[WebToPay::PREFIX . 'currency']; - } - - if ($order->increment_id) { - try { - WebToPay::toggleSS2(true); - $response = WebToPay::checkResponse($_GET, array( - 'projectid' => $pData['api_key'], - 'sign_password' => $pData['api_secret'], - )); - - $order->setStatus(Mage_Sales_Model_Order::STATE_PROCESSING)->save(); - exit('OK'); - - } catch (Exception $e) { - return get_class($e) . ': ' . $e->getMessage(); - } - } else { - return 'No such order!'; - } - } - } - - public function getCustomerAddressInfo($orderObject) { - $addressInfo = array( - 'City' => '', - 'Street' => '', - 'Postcode' => '', - ); - - if (!$orderObject->customer_is_guest) { - $address = $orderObject->getBillingAddress(); - - $addressInfo['City'] = $address->city; - $addressInfo['Street'] = $address->street; - $addressInfo['Postcode'] = $address->postcode; - } - - return $addressInfo; - } - - public function d($var) { - echo '
';
-        print_r($var);
-        echo '
'; - } -} diff --git a/app/code/local/Mage/Paysera/controllers/PayController.php b/app/code/local/Mage/Paysera/controllers/PayController.php deleted file mode 100644 index 853771a..0000000 --- a/app/code/local/Mage/Paysera/controllers/PayController.php +++ /dev/null @@ -1,57 +0,0 @@ -getCheckout()->getQuote(); - } - - public function redirectAction() - { - $session = Mage::getSingleton('checkout/session'); - $session->setPayQuoteId($session->getQuoteId()); - $session->unsQuoteId(); - $this->getResponse()->setBody($this->getLayout()->createBlock('paysera/redirect')->toHtml()); - } - - public function callbackAction() - { - $this->getResponse()->setBody($this->getLayout()->createBlock('paysera/callback')->toHtml()); - } - - public function cancelAction() - { - $session = Mage::getSingleton('checkout/session'); - $session->setQuoteId($session->getPayQuoteId(true)); - $this->_redirect('checkout/cart'); - } - - public function successAction() - { - $session = Mage::getSingleton('checkout/session'); - $session -> setQuoteId($session -> getPayQuoteId(true)); - Mage::getSingleton('checkout/session') -> getQuote() -> setIsActive(false) -> save(); - $this -> _redirect('checkout/onepage/success', array('_secure' => true)); - } - - public function failAction() - { - $order = Mage::getModel('sales/order'); - $order->load(Mage::getSingleton('checkout/session')->getLastOrderId()); - - if($order->getId()) - { - $order->setStatus('canceled')->save(); - } - - $this->_redirect('checkout/onepage/failure'); - } -} -?> diff --git a/app/code/local/Mage/Paysera/etc/config.xml b/app/code/local/Mage/Paysera/etc/config.xml deleted file mode 100644 index 8ed5b20..0000000 --- a/app/code/local/Mage/Paysera/etc/config.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - 0.1.0 - - - - - - Mage_Paysera_Block - - - - Mage_Paysera_Model - - - - - - Mage_Paysera - - - core_setup - - - - - core_write - - - - - core_read - - - - - - - - standard - - Mage_Paysera - paysera - - - - - - - - 0 - paysera/paymentMethod - jusu mokejimai.lt projekto id - jusu mokejimai.lt projekto slaptazodis - 1 - Paysera.com / Mokejimai.lt - - - - diff --git a/app/code/local/Mage/Paysera/etc/system.xml b/app/code/local/Mage/Paysera/etc/system.xml deleted file mode 100644 index 46ff80b..0000000 --- a/app/code/local/Mage/Paysera/etc/system.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - 670 - 1 - 1 - 0 - - - - select - adminhtml/system_config_source_yesno - 1 - 1 - 1 - 0 - - - - text - 2 - 1 - 1 - 0 - - - - text - 3 - 1 - 1 - 0 - - - - select - adminhtml/system_config_source_yesno - 4 - 1 - 1 - 0 - - - <label>Title</label> - <frontend_type>text</frontend_type> - <sort_order>7</sort_order> - <show_in_default>1</show_in_default> - <show_in_website>1</show_in_website> - <show_in_store>0</show_in_store> - - - - - - - diff --git a/app/code/local/Mage/Paysera/libwebtopay/WebToPay.php b/app/code/local/Mage/Paysera/libwebtopay/WebToPay.php deleted file mode 100644 index 67fe9ef..0000000 --- a/app/code/local/Mage/Paysera/libwebtopay/WebToPay.php +++ /dev/null @@ -1,1202 +0,0 @@ -. - * - * @package WebToPay - * @author EVP International - * @license http://www.gnu.org/licenses/lgpl.html - * @version 1.5 - * @link http://www.webtopay.com/ - */ - -class WebToPay { - - /** - * WebToPay Library version. - */ - const VERSION = '1.5'; - - /** - * Server URL where all requests should go. - */ - const PAY_URL = 'https://www.mokejimai.lt/pay/'; - - /** - * Server URL where we can get XML with payment method data. - */ - const XML_URL = 'https://www.mokejimai.lt/new/lt/lib_web_to_pays/api/'; - - /** - * SMS answer url. - */ - const SMS_ANSWER_URL = 'https://www.mokejimai.lt/psms/respond/'; - - /** - * Prefix for callback data. - */ - const PREFIX = 'wp_'; - - - /** - * Identifies what verification method was used. - * - * Values can be: - * - false not verified - * - RESPONSE only response parameters are verified - * - SS1v2 SS1 v2 verification - * - SS2 SS2 verification - */ - public static $verified = false; - - - /** - * If true, check SS2 if false, skip to SS1 - * - * @deprecated - */ - private static $SS2 = true; - - /** - * Toggle SS2 checking. Usualy you don't need to use this method, because - * by default first SS2 support are checked and if it doesn't work, - * fallback to SS1. - * - * Use this method if your server supports SS2, but you want to use SS1. - * - * @deprecated - */ - public static function toggleSS2($value) { - self::$SS2 = (bool) $value; - } - - - /** - * Throw exception. - * - * @param string $code - * @return void - */ - public static function throwResponseError($code) { - $errors = array( - '0x1' => self::_('mokėjimo suma per maža'), - '0x2' => self::_('mokėjimo suma per didelė'), - '0x3' => self::_('nurodyta valiuta neaptarnaujama'), - '0x4' => self::_('nėra sumos arba valiutos'), - '0x6' => self::_('klaidos kodas nebenaudojamas'), - '0x7' => self::_('išjungtas testavimo režimas'), - '0x8' => self::_('jūs uždraudėte šį mokėjimo būdą'), - '0x9' => self::_('blogas "paytext" kintamojo kodavimas (turi būti utf-8)'), - '0x10' => self::_('tuščias arba neteisingai užpildytas "orderid"'), - '0x11' => self::_('mokėjimas negalimas, kol projektas nepatvirtintas arba jeigu jis yra blokuotas'), - '0x12' => self::_('negautas "projectid" parametras, nors jis yra privalomas'), - '0x13' => self::_('"accepturl", "cancellurl" arba "callbacurl" skiriasi nuo projekte patvirtintų adresų'), - '0x14' => self::_('blogai sugeneruotas paraštas ("sign" parametras)'), - '0x15' => self::_('klaidingi kai kurie iš perduotų parametrų'), - '0x15x0' => self::_('neteisingas vienas iš šių parametrų: cancelurl, accepturl, callbackurl'), - '0x15x1' => self::_('neteisingas parametras: time_limit'), - ); - - if (isset($errors[$code])) { - $msg = $errors[$code]; - } - else { - $msg = self::_('Nenumatyta klaida'); - } - - throw new WebToPayException($msg); - } - - - /** - * Returns specification array for request. - * - * @return array - */ - public static function getRequestSpec() { - // Array structure: - // * name – request item name. - // * maxlen – max allowed value for item. - // * required – is this item is required. - // * user – if true, user can set value of this item, if false - // item value is generated. - // * isrequest – if true, item will be included in request array, if - // false, item only be used internaly and will not be - // included in outgoing request array. - // * regexp – regexp to test item value. - return array( - array('projectid', 11, true, true, true, '/^\d+$/'), - array('orderid', 40, true, true, true, ''), - array('lang', 3, false, true, true, '/^[a-z]{3}$/i'), - array('amount', 11, false, true, true, '/^\d+$/'), - array('currency', 3, false, true, true, '/^[a-z]{3}$/i'), - array('accepturl', 255, true, true, true, ''), - array('cancelurl', 255, true, true, true, ''), - array('callbackurl', 255, true, true, true, ''), - array('payment', 20, false, true, true, ''), - array('country', 2, false, true, true, '/^[a-z_]{2}$/i'), - array('paytext', 255, false, true, true, ''), - array('p_firstname', 255, false, true, true, ''), - array('p_lastname', 255, false, true, true, ''), - array('p_email', 255, false, true, true, ''), - array('p_street', 255, false, true, true, ''), - array('p_city', 255, false, true, true, ''), - array('p_state', 20, false, true, true, ''), - array('p_zip', 20, false, true, true, ''), - array('p_countrycode', 2, false, true, true, '/^[a-z]{2}$/i'), - array('sign', 255, true, false, true, ''), - array('sign_password', 255, true, true, false, ''), - array('only_payments', 0, false, true, true, ''), - array('disalow_payments', 0, false, true, true, ''), - array('repeat_request', 1, false, false, true, '/^[01]$/'), - array('test', 1, false, true, true, '/^[01]$/'), - array('version', 9, true, false, true, '/^\d+\.\d+$/'), - array('time_limit', 19, false, true, true, '/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/'), - ); - } - - - /** - * Returns specification array for repeat request. - * - * @return array - */ - public static function getRepeatRequestSpec() { - // Array structure: - // * name – request item name. - // * maxlen – max allowed value for item. - // * required – is this item is required. - // * user – if true, user can set value of this item, if false - // item value is generated. - // * isrequest – if true, item will be included in request array, if - // false, item only be used internaly and will not be - // included in outgoing request array. - // * regexp – regexp to test item value. - return array( - array('projectid', 11, true, true, true, '/^\d+$/'), - array('requestid', 40, true, true, true, ''), - array('sign', 255, true, false, true, ''), - array('sign_password', 255, true, true, false, ''), - array('repeat_request', 1, true, false, true, '/^1$/'), - array('version', 9, true, false, true, '/^\d+\.\d+$/'), - ); - } - - - /** - * Returns specification array for makro response. - * - * @return array - */ - public static function getMakroResponseSpec() { - // Array structure: - // * name – request item name. - // * maxlen – max allowed value for item. - // * required – is this item is required in response. - // * mustcheck – this item must be checked by user. - // * isresponse – if false, item must not be included in response array. - // * regexp – regexp to test item value. - return array( - 'projectid' => array(11, true, true, true, '/^\d+$/'), - 'orderid' => array(40, false, false, true, ''), - 'lang' => array(3, false, false, true, '/^[a-z]{3}$/i'), - 'amount' => array(11, false, false, true, '/^\d+$/'), - 'currency' => array(3, false, false, true, '/^[a-z]{3}$/i'), - 'payment' => array(20, false, false, true, ''), - 'country' => array(2, false, false, true, '/^[a-z_]{2}$/i'), - 'paytext' => array(0, false, false, true, ''), - '_ss2' => array(0, true, false, true, ''), - '_ss1v2' => array(0, false, false, true, ''), - 'name' => array(255, false, false, true, ''), - 'surename' => array(255, false, false, true, ''), - 'status' => array(255, false, false, true, ''), - 'error' => array(20, false, false, true, ''), - 'test' => array(1, false, false, true, '/^[01]$/'), - - 'p_email' => array(0, false, false, true, ''), - 'requestid' => array(40, false, false, true, ''), - 'payamount' => array(0, false, false, true, ''), - 'paycurrency' => array(0, false, false, true, ''), - - 'version' => array(9, true, false, true, '/^\d+\.\d+$/'), - - 'sign_password' => array(255, false, true, false, ''), - ); - } - - - - /** - * Returns specification array for mikro response. - * - * @return array - */ - public static function getMikroResponseSpec() { - // Array structure: - // * name – request item name. - // * maxlen – max allowed value for item. - // * required – is this item is required in response. - // * mustcheck – this item must be checked by user. - // * isresponse – if false, item must not be included in response array. - // * regexp – regexp to test item value. - return array( - 'to' => array(0, true, false, true, ''), - 'sms' => array(0, true, false, true, ''), - 'from' => array(0, true, false, true, ''), - 'operator' => array(0, true, false, true, ''), - 'amount' => array(0, true, false, true, ''), - 'currency' => array(0, true, false, true, ''), - 'country' => array(0, true, false, true, ''), - 'id' => array(0, true, false, true, ''), - '_ss2' => array(0, true, false, true, ''), - '_ss1v2' => array(0, true, false, true, ''), - 'test' => array(0, true, false, true, ''), - 'key' => array(0, true, false, true, ''), - //'version' => array(9, true, false, true, '/^\d+\.\d+$/'), - ); - } - - /** - * Checks user given request data array. - * - * If any errors occurs, WebToPayException will be raised. - * - * This method returns validated request array. Returned array contains - * only those items from $data, that are needed. - * - * @param array $data - * @return array - */ - public static function checkRequestData($data, $specs) { - $request = array(); - foreach ($specs as $spec) { - list($name, $maxlen, $required, $user, $isrequest, $regexp) = $spec; - if (!$user) continue; - if ($required && !isset($data[$name])) { - $e = new WebToPayException( - self::_("'%s' is required but missing.", $name), - WebToPayException::E_MISSING); - $e->setField($name); - throw $e; - } - - if (!empty($data[$name])) { - if ($maxlen && strlen($data[$name]) > $maxlen) { - $e = new WebToPayException( - self::_("'%s' value '%s' is too long, %d characters allowed.", - $name, $data[$name], $maxlen), - WebToPayException::E_MAXLEN); - $e->setField($name); - throw $e; - } - - if ('' != $regexp && !preg_match($regexp, $data[$name])) { - $e = new WebToPayException( - self::_("'%s' value '%s' is invalid.", $name, $data[$name]), - WebToPayException::E_REGEXP); - $e->setField($name); - throw $e; - } - } - - if ($isrequest && isset($data[$name])) { - $request[$name] = $data[$name]; - } - } - - return $request; - } - - - /** - * Puts signature on request data array. - * - * @param array $specification - * @param string $request - * @param string $password - * @return string - */ - public static function signRequest($specification, $request, $password) { - $fields = array(); - foreach ($specification as $field) { - if ($field[4] && $field[0] != 'sign') { - $fields[] = $field[0]; - } - } - - $data = ''; - foreach ($fields as $key) { - if (isset($request[$key]) && trim($request[$key]) != '') { - $data .= $request[$key]; - } - } - $request['sign'] = md5($data . $password); - - return $request; - } - - - /** - * Builds request data array. - * - * This method checks all given data and generates correct request data - * array or raises WebToPayException on failure. - * - * Method accepts single parameter $data of array type. All possible array - * keys are described here: - * https://www.mokejimai.lt/makro_specifikacija.html - * - * @param array $data Information about current payment request. - * @return array - */ - public static function buildRequest($data) { - $specs = self::getRequestSpec(); - $request = self::checkRequestData($data, $specs); - $version = explode('.', self::VERSION); - $request['version'] = $version[0].'.'.$version[1]; - $request = self::signRequest($specs, $request, $data['sign_password']); - return $request; - } - - - /** - * Builds repeat request data array. - * - * This method checks all given data and generates correct request data - * array or raises WebToPayException on failure. - * - * Method accepts single parameter $data of array type. All possible array - * keys are described here: - * https://www.mokejimai.lt/makro_specifikacija.html - * - * @param array $data Information about current payment request. - * @return array - */ - public static function buildRepeatRequest($data) { - $specs = self::getRepeatRequestSpec(); - $request = self::checkRequestData($data, $specs); - $request['repeat_request'] = '1'; - $version = explode('.', self::VERSION); - $request['version'] = $version[0].'.'.$version[1]; - $request = self::signRequest($specs, $request, $data['sign_password']); - return $request; - } - - /** - * Download certificate from webtopay.com. - * - * @param string $cert - * @return string - */ - public static function getCert($cert) { - return self::getUrlContent('http://downloads.webtopay.com/download/'.$cert); - } - - /** - * Check is response certificate is valid - * - * @param string $response - * @param string $cert - * @return bool - */ - public static function checkResponseCert($response, $cert='public.key') { - $pKeyP = self::getCert($cert); - if (!$pKeyP) { - throw new WebToPayException( - self::_('Can\'t get openssl public key for %s', $cert), - WebToPayException::E_INVALID); - } - - $_SS2 = ''; - foreach ($response as $key => $value) { - if (in_array($key, array('_ss1v2', '_ss2'))) { - continue; - } - $_SS2 .= "{$value}|"; - } - $ok = openssl_verify($_SS2, base64_decode($response['_ss2']), $pKeyP); - - if ($ok !== 1) { - throw new WebToPayException( - self::_('Can\'t verify SS2 for %s', $cert), - WebToPayException::E_INVALID); - } - - return true; - } - - public static function checkResponseData($response, $mustcheck_data, $specs) { - $resp_keys = array(); - foreach ($specs as $name => $spec) { - list($maxlen, $required, $mustcheck, $is_response, $regexp) = $spec; - if ($required && !isset($response[$name])) { - $e = new WebToPayException( - self::_("'%s' is required but missing.", $name), - WebToPayException::E_MISSING); - $e->setField($name); - throw $e; - } - - if ($mustcheck) { - if (!isset($mustcheck_data[$name])) { - $e = new WebToPayException( - self::_("'%s' must exists in array of second parameter ". - "of checkResponse() method.", $name), - WebToPayException::E_USER_PARAMS); - $e->setField($name); - throw $e; - } - - if ($is_response) { - if ($response[$name] != $mustcheck_data[$name]) { - $e = new WebToPayException( - self::_("'%s' yours and requested value is not ". - "equal ('%s' != '%s') ", - $name, $mustcheck_data[$name], $response[$name]), - WebToPayException::E_INVALID); - $e->setField($name); - throw $e; - } - } - } - - if (!empty($response[$name])) { - if ($maxlen && strlen($response[$name]) > $maxlen) { - $e = new WebToPayException( - self::_("'%s' value '%s' is too long, %d characters allowed.", - $name, $response[$name], $maxlen), - WebToPayException::E_MAXLEN); - $e->setField($name); - throw $e; - } - - if ('' != $regexp && !preg_match($regexp, $response[$name])) { - $e = new WebToPayException( - self::_("'%s' value '%s' is invalid.", $name, $response[$name]), - WebToPayException::E_REGEXP); - $e->setField($name); - throw $e; - } - } - - if (isset($response[$name])) { - $resp_keys[] = $name; - } - } - - // Filter only parameters passed from webtopay - $_response = array(); - foreach (array_keys($response) as $key) { - if (in_array($key, $resp_keys)) { - $_response[$key] = $response[$key]; - } - } - - return $_response; - } - - - /** - * Check if SS2 checking is available and enabled. - * - * @return bool - */ - public static function useSS2() { - return function_exists('openssl_pkey_get_public'); - } - - - /** - * Check for SS1, which is not depend on openssl functions. - * - * @param array $response - * @param string $password - * @return bool - */ - public static function checkSS1v2($response, $password) { - if (32 != strlen($password)) { - $password = md5($password); - } - - $buffer = array($password); - foreach ($response as $key => $value) { - if (in_array($key, array('_ss1v2', '_ss2'))) { - continue; - } - $buffer[] = $value; - } - - $ss1v2 = md5(implode('|', $buffer)); - - if ($response['_ss1v2'] != $ss1v2) { - throw new WebToPayException( - self::_('Can\'t verify SS1 v2'), - WebToPayException::E_INVALID); - } - - return true; - } - - /** - * Filters saved payment method cache by e-shop's order sum and language - * - * @param string $payCurrency - * @param int $sum - * @param array $currency array ( '0' => array ('iso' => 'USD', 'rate' => 0.417391, ),); - * @param string $lang - * @param int $projectID - * @return array $filtered - */ - public static function getPaymentMethods($payCurrency, $sum, $currency, $lang, $projectID) { - - $filtered = array(); - $data = self::loadXML(); - $lang = strtolower($lang); - - //jei xml senesnis nei para - if((($data['ts']+3600*24) - time()) < 0 || $data == null) { - self::getXML($projectID); //siunciam nauja - $data = self::loadXML(); //vel uzloadinam - } - - $filtered = self::filterPayMethods($data['data'], $payCurrency, $sum, $currency, $lang); - - return $filtered; - } - - - /** - * Downloads xml data from webtopay.com - * - * @param int $projectID - * @return string - */ - public static function getXML($projectID) { - $response = self::getUrlContent(self::XML_URL.$projectID.'/'); - $feed = simplexml_load_string($response); - - $feed = simplexml_load_string($response); - if($feed === false){ - return false; - } else { - self::parseXML($feed); - return true; - } - } - - - /** - * Returns payment url - * - * @param string $language - * @return string $url - */ - public static function getPaymentUrl($language) { - $url = self::PAY_URL; - if($language != 'LT') { - $url = str_replace('mokejimai.lt', 'webtopay.com', $url); - } - return $url; - } - - /** - * Loads and unserializes xml data from file - * - * @return array $data - */ - private static function loadXML() { - - $data = array(); - $file = dirname(__FILE__).DIRECTORY_SEPARATOR.'cache.php'; - - if (file_exists($file)) { - $fh = fopen($file, 'r'); - $data = unserialize(fread($fh,filesize($file))); - fclose($fh); - return $data; - } else { - return null; - } - } - - /** - * Parses xml to array, serializes it and writes it to file /cache.php - * - * @param obj $xml - */ - public static function parseXML($xml){ - - $paydata = array(); - $parsed = array(); - $language = array(); - $logo = array(); - $qouta = array(); - $title = array(); - $cache = array(); - - foreach($xml->country as $country){ - $countries = strtolower(trim((string)$country->attributes())); - foreach($country->payment_group as $group){ - $groups = strtolower(trim((string)$group->attributes())); - foreach($group->title as $tit => $v){ - $language[strtolower(trim((string)$v->attributes()))] = trim((string)$v); - } - $parsed[$countries][$groups]['translate'] = $language; - foreach($group->payment_type as $type) { - $types = strtolower(trim((string)$type->attributes())); - foreach($type as $key => $value) { - if($key === 'logo_url'){ - $logo[trim((string)$value->attributes())] = trim((string)$value); - } - if($key === 'title'){ - $title[trim((string)$value->attributes())] = trim((string)$value); - } - if($key === 'max' || $key === 'min') { - foreach($value->attributes() as $k => $v){ - $qouta[$key.'_amount'] = trim((string)$value->attributes()); - $qouta[$key.'_amount_currency'] = trim((string)$v); - } - } - $paydata['logo'] = $logo; - $paydata['title'] = $title; - $paydata['amount'] = $qouta; - $parsed[$countries][$groups][$types] = $paydata; - } - //unset($qouta); - $qouta = null; - } - } - } - - $cache['ts'] = time(); - $cache['data'] = $parsed; - - if (!is_writable(dirname(__FILE__))) { - throw new WebToPayException(self::_('Directory '.dirname(__FILE__).' is not writable.',WebToPayException::E_INVALID)); - } else { - $file = serialize($cache); - $path = dirname(__FILE__).DIRECTORY_SEPARATOR.'cache.php'; - $fp = fopen($path, 'w') or die('error writing cache'); - fwrite($fp, $file); - fclose($fp); - }; - } - - /** - * Converts money amount to e-shops base currency - * - * @param int $sum - * @param string $payCurrency - * @param string $convertCurrency - * @param array $currency array ( '0' => array ('iso' => USD, 'rate' => 0.417391, ),); - * @return int $amount - */ - private static function toBaseCurrency($sum, $payCurrency, $convertCurrency, $currency){ - $amount = 0; - foreach($currency as $entry) { - if($payCurrency == $entry['iso']) { - $amount = $sum/$entry['rate']; //turim viska BASE valiuta - foreach($currency as $entry) { - if($convertCurrency == $entry['iso']) { - $amount *= $entry['rate']; - return $amount; - break; - } - } - break; - } - } - } - - - /** - * Checks minimum amount of payment method - * - * @param array $data - * @param int $sum - * @param string $payCurrency - * @param array $currency array ( '0' => array ('iso' => USD, 'rate' => 0.417391, ),); - * @return bool - */ - private static function checkMinAmount($data, $sum, $payCurrency, $currency){ - //jei apribotas min_amount - if (array_key_exists('min_amount', $data) && $data['min_amount'] != null) { - if ($payCurrency == $data['min_amount_currency']) {//kai sutampa valiutos - return ($sum >= $data['min_amount']); - } else { - //konvertuojam i base - $amount = self::toBaseCurrency($sum, $payCurrency, $data['min_amount_currency'], $currency); - return ($amount >= $data['min_amount']); - } - } - return true; - } - - /** - * Checks maximum amount of payment method - * - * @param array $data - * @param int $sum - * @param string $payCurrency - * @param array $currency array ( '0' => array ('iso' => USD, 'rate' => 0.417391, ),); - * @return bool - */ - private static function checkMaxAmount($data, $sum, $payCurrency, $currency){ - //jei apribotas max_amount - if (array_key_exists('max_amount', $data) && $data['max_amount'] != null) { - if ($payCurrency == $data['max_amount_currency']) {//kai sutampa valiutos - return ($data['max_amount'] >= $sum); - } else { - //konvertuojam i base - $amount = self::toBaseCurrency($sum, $payCurrency, $data['max_amount_currency'], $currency); - return ($data['max_amount'] >= $amount); - } - } - return true; - } - - /** - * Checks maximum amount of payment method - * - * @param array $payMethods - unserialized array with pay method data - * @param string $payCurrency - - * @param int $sum - * @param string $payCurrency - * @param array $currency array ( '0' => array ('iso' => USD, 'rate' => 0.417391, ),); - * @param string $lang - * @return array - */ - public static function filterPayMethods($payMethods, $payCurrency, $sum, $currency, $lang) { - - $filtered = array(); - $groupName = array(); - $logo = null; - $name = null; - - foreach($payMethods as $key1 => $value1) { - foreach($value1 as $key2 => $value2){ - foreach($value2 as $key3 => $value3){ - if($key3 === 'translate') { - foreach($value3 as $loc => $text) { - if($loc === 'en'){ - $groupName = $text; - } - if($loc === $lang) { - $groupName = $text; - break; - } - } - } else { - foreach($value3 as $key4 => $value4) { - if($key4 === 'logo'){ - foreach($value4 as $k => $v) { - if($k === 'en'){ //statom anglu kalba default jei nerasta vertimu - $logo = $v; - } - if($k === $lang) { - $logo = $v; - break; - } - } - } - if($key4 === 'title'){ - foreach($value4 as $k => $v) { - if($k === 'en'){ - $name = $v; - } - if($k === $lang) { - $name = $v; - break; - } - } - } - if($key4 === 'amount'){ - $min = self::checkMinAmount($value4, $sum, $payCurrency, $currency); - $max = self::checkMaxAmount($value4, $sum, $payCurrency, $currency); - if($min && $max) { //jei praeina pagal min ir max irasom - $filtered[$key1][$groupName][$name] = array('name' => $key3,'logo' => $logo); - } - } - } - } - } - } - } - - return $filtered; - } - - - /** - * Return type and specification of given response array. - * - * @param array $response - * @return array($type, $specs) - */ - public static function getSpecsForResponse($response) { - if ( - isset($response['to']) && - isset($response['from']) && - isset($response['sms']) && - !isset($response['projectid']) - ) - { - $type = 'mikro'; - $specs = self::getMikroResponseSpec(); - } - else { - $type = 'makro'; - $specs = self::getMakroResponseSpec(); - } - - return array($type, $specs); - } - - - public static function getPrefixed($data, $prefix) { - if (empty($prefix)) return $data; - $ret = array(); - foreach ($data as $key => $val) { - if (strpos($key, $prefix) === 0 && strlen($key) > 3) { - $ret[substr($key, 3)] = $val; - } - } - return $ret; - } - - private static function getUrlContent($URL){ - $url = parse_url($URL); - if ('https' == $url['scheme']) { - $host = 'ssl://'.$url['host']; - $port = 443; - } else { - $host = $url['host']; - $port = 80; - } - - try { - $fp = fsockopen($host, $port, $errno, $errstr, 30); - if (!$fp) { - throw new WebToPayException( - self::_('Can\'t connect to %s', $URL), - WebToPayException::E_INVALID); - } - - if(isset($url['query'])) { - $data = $url['path'].'?'.$url['query']; - } else { - $data = $url['path']; - } - - $out = "GET " . $data . " HTTP/1.0\r\n"; - $out .= "Host: ".$url['host']."\r\n"; - $out .= "Connection: Close\r\n\r\n"; - - $content = ''; - - fwrite($fp, $out); - while (!feof($fp)) $content .= fgets($fp, 8192); - fclose($fp); - - list($header, $content) = explode("\r\n\r\n", $content, 2); - - return trim($content); - - } catch (WebToPayException $e) { - throw new WebToPayException(self::_('fsockopen fail!', WebToPayException::E_INVALID)); - } - } - - - /** - * Checks and validates response from WebToPay server. - * - * This function accepts both mikro and makro responses. - * - * First parameter usualy should by $_GET array. - * - * Description about response can be found here: - * makro: https://www.mokejimai.lt/makro_specifikacija.html - * mikro: https://www.mokejimai.lt/mikro_mokejimu_specifikacija_SMS.html - * - * If response is not correct, WebToPayException will be raised. - * - * @param array $response Response array. - * @param array $user_data - * @return void - */ - public static function checkResponse($response, $user_data=array()) { - self::$verified = false; - - $response = self::getPrefixed($response, self::PREFIX); - - // *get* response type (makro|mikro) - list($type, $specs) = self::getSpecsForResponse($response); - - try { - // *check* response - $version = explode('.', self::VERSION); - $version = $version[0].'.'.$version[1]; - if ('makro' == $type && $response['version'] != $version) { - throw new WebToPayException( - self::_('Incompatible library and response versions: ' . - 'libwebtopay %s, response %s', self::VERSION, $response['version']), - WebToPayException::E_INVALID); - } - - if ('makro' == $type && $response['projectid'] != $user_data['projectid']) { - throw new WebToPayException( - self::_('Bad projectid: ' . - 'libwebtopay %s, response %s', self::VERSION, $response['version']), - WebToPayException::E_INVALID); - } - - if ('makro' == $type) { - self::$verified = 'RESPONSE VERSION '.$response['version'].' OK'; - } - - $orderid = 'makro' == $type ? $response['orderid'] : $response['id']; - $password = $user_data['sign_password']; - - // *check* SS2 - if (self::useSS2()) { - $cert = 'public.key'; - if (self::checkResponseCert($response, $cert)) { - self::$verified = 'SS2 public.key'; - } - } - - // *check* SS1 v2 - else if (self::checkSS1v2($response, $password)) { - self::$verified = 'SS1v2'; - } - - // *check* status - if ('makro' == $type && $response['status'] != '1') { - throw new WebToPayException( - self::_('Returned transaction status is %d, successful status '. - 'should be 1.', $response['status']), - WebToPayException::E_STATUS); - } - - } - - catch (WebToPayException $e) { - if (isset($user_data['log'])) { - self::log('ERR', - self::responseToLog($type, $response) . - ' ('. get_class($e).': '. $e->getMessage().')', - $user_data['log']); - } - throw $e; - } - - if (isset($user_data['log'])) { - self::log('OK', self::responseToLog($type, $response), $user_data['log']); - } - - return $response; - } - - public static function responseToLog($type, $req) { - if ('mikro' == $type) { - return self::mikroResponseToLog($req); - } - else { - return self::makroResponseToLog($req); - } - } - - public static function mikroResponseToLog($req) { - $ret = array(); - foreach (array('to', 'from', 'id', 'sms') as $key) { - $ret[] = $key.':"'.$req[$key].'"'; - } - - return 'MIKRO '.implode(', ', $ret); - } - - public static function makroResponseToLog($req) { - $ret = array(); - foreach (array('projectid', 'orderid', 'payment') as $key) { - $ret[] = $key.':"'.$req[$key].'"'; - } - - return 'MAKRO '.implode(', ', $ret); - } - - public static function mikroAnswerToLog($answer) { - $ret = array(); - foreach (array('id', 'msg') as $key) { - $ret[] = $key.':"'.$answer[$key].'"'; - } - - return 'MIKRO [answer] '.implode(', ', $ret); - } - - public static function log($type, $msg, $logfile=null) { - if (!isset($logfile)) { - return false; - } - - $fp = @fopen($logfile, 'a'); - if (!$fp) { - throw new WebToPayException( - self::_('Can\'t write to logfile: %s', $logfile), WebToPayException::E_LOG); - } - - $logline = array(); - - // *log* type - $logline[] = $type; - - // *log* REMOTE_ADDR - if (isset($_SERVER['REMOTE_ADDR'])) { - $logline[] = $_SERVER['REMOTE_ADDR']; - } - else { - $logline[] = '-'; - } - - // *log* datetime - $logline[] = date('[Y-m-d H:i:s O]'); - - // *log* version - $logline[] = 'v'.self::VERSION.':'; - - // *log* message - $logline[] = $msg; - - $logline = implode(' ', $logline)."\n"; - fwrite($fp, $logline); - fclose($fp); - - // clear big log file - if (filesize($logfile) > 1024 * 1024 * pi()) { - copy($logfile, $logfile.'.old'); - unlink($logfile); - } - } - - - /** - * Sends SMS answer. - * - * @param array $answer - * @return void - */ - public static function smsAnswer($answer) { - - $data = array( - 'id' => $answer['id'], - 'msg' => $answer['msg'], - 'transaction' => md5($answer['sign_password'].'|'.$answer['id']), - ); - - $url = self::SMS_ANSWER_URL.'?'.http_build_query($data); - try { - $content = self::getUrlContent($url); - if (strpos($content, 'OK') !== 0) { - throw new WebToPayException( - self::_('Error: %s', $content), - WebToPayException::E_SMS_ANSWER); - } - } catch (WebToPayException $e) { - if (isset($answer['log'])) { - self::log('ERR', - self::mikroAnswerToLog($answer). - ' ('. get_class($e).': '. $e->getMessage().')', - $answer['log']); - } - throw $e; - } - - if (isset($answer['log'])) { - self::log('OK', self::mikroAnswerToLog($answer), $answer['log']); - } - - } - - - /** - * I18n support. - */ - public static function _() { - $args = func_get_args(); - if (sizeof($args) > 1) { - return call_user_func_array('sprintf', $args); - } - else { - return $args[0]; - } - } - -} - - - -class WebToPayException extends Exception { - - /** - * Missing field. - */ - const E_MISSING = 1; - - /** - * Invalid field value. - */ - const E_INVALID = 2; - - /** - * Max length exceeded. - */ - const E_MAXLEN = 3; - - /** - * Regexp for field value doesn't match. - */ - const E_REGEXP = 4; - - /** - * Missing or invalid user given parameters. - */ - const E_USER_PARAMS = 5; - - /** - * Logging errors - */ - const E_LOG = 6; - - /** - * SMS answer errors - */ - const E_SMS_ANSWER = 7; - - /** - * Macro answer errors - */ - const E_STATUS = 8; - - protected $field_name = false; - - public function setField($field_name) { - $this->field_name = $field_name; - } - - public function getField() { - return $this->field_name; - } -} diff --git a/app/design/frontend/default/default/template/paysera/form.phtml b/app/design/frontend/default/default/template/paysera/form.phtml deleted file mode 100644 index c84b5e4..0000000 --- a/app/design/frontend/default/default/template/paysera/form.phtml +++ /dev/null @@ -1,6 +0,0 @@ -getMethodCode(); ?> - \ No newline at end of file diff --git a/app/etc/modules/Mage_Paysera.xml b/app/etc/modules/Mage_Paysera.xml deleted file mode 100644 index 3fee5b9..0000000 --- a/app/etc/modules/Mage_Paysera.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - true - local - - - - 0.1.0 - - - \ No newline at end of file From 05af81785f4fb60e3ae5427a879963a1e8e57b0c Mon Sep 17 00:00:00 2001 From: Ed Mark Date: Mon, 23 May 2016 14:49:16 +0300 Subject: [PATCH 2/2] new version --- DIEGIMAS.txt | 11 + Paysera/Paysera/Controller/Index/Callback.php | 68 + Paysera/Paysera/Controller/Index/Index.php | 62 + Paysera/Paysera/Controller/Index/WebToPay.php | 2357 +++++++++++++++++ .../Source/Order/Status/Pendingpayment.php | 20 + Paysera/Paysera/Model/Paysera.php | 28 + Paysera/Paysera/etc/adminhtml/system.xml | 36 + Paysera/Paysera/etc/config.xml | 25 + Paysera/Paysera/etc/frontend/routes.xml | 9 + Paysera/Paysera/etc/module.xml | 10 + Paysera/Paysera/etc/payment.xml | 20 + Paysera/Paysera/registration.php | 7 + .../frontend/layout/checkout_index_index.xml | 51 + .../payment/method-renderer/paysera-method.js | 75 + .../frontend/web/js/view/payment/paysera.js | 26 + .../view/frontend/web/template/paysera.html | 43 + README.md | 13 + README.txt | 11 + 18 files changed, 2872 insertions(+) create mode 100755 DIEGIMAS.txt create mode 100755 Paysera/Paysera/Controller/Index/Callback.php create mode 100755 Paysera/Paysera/Controller/Index/Index.php create mode 100755 Paysera/Paysera/Controller/Index/WebToPay.php create mode 100755 Paysera/Paysera/Model/Config/Source/Order/Status/Pendingpayment.php create mode 100755 Paysera/Paysera/Model/Paysera.php create mode 100755 Paysera/Paysera/etc/adminhtml/system.xml create mode 100755 Paysera/Paysera/etc/config.xml create mode 100755 Paysera/Paysera/etc/frontend/routes.xml create mode 100755 Paysera/Paysera/etc/module.xml create mode 100755 Paysera/Paysera/etc/payment.xml create mode 100755 Paysera/Paysera/registration.php create mode 100755 Paysera/Paysera/view/frontend/layout/checkout_index_index.xml create mode 100755 Paysera/Paysera/view/frontend/web/js/view/payment/method-renderer/paysera-method.js create mode 100755 Paysera/Paysera/view/frontend/web/js/view/payment/paysera.js create mode 100755 Paysera/Paysera/view/frontend/web/template/paysera.html create mode 100755 README.md create mode 100755 README.txt diff --git a/DIEGIMAS.txt b/DIEGIMAS.txt new file mode 100755 index 0000000..214df0f --- /dev/null +++ b/DIEGIMAS.txt @@ -0,0 +1,11 @@ +Diegimas + +1. Padarykite atsargine failu kopija[nebutina]. +2. Nukopijuokite visus archyvo failus i jusu svetaines app/code direktorija (jeigu code direktorijos nera - sukurkite). +3. app/etc/config.php faile, pridekite tokia eilute: 'Paysera_Paysera' => 1, (eilute reikia prideti pries ");" ir ")," zenklus). +4. Isjunkite visus cache. +5. Admin meniu: Stores -> Configuration -> Sales -> Payment Methods -> Paysera (irasykite Jusu Mokejimai.lt duomenis). + +Kontaktai + +Kilus klausimams prasome kreiptis i pagalba@mokejimai.lt \ No newline at end of file diff --git a/Paysera/Paysera/Controller/Index/Callback.php b/Paysera/Paysera/Controller/Index/Callback.php new file mode 100755 index 0000000..b5ffce1 --- /dev/null +++ b/Paysera/Paysera/Controller/Index/Callback.php @@ -0,0 +1,68 @@ +pageFactory = $pageFactory; + $this->scopeConfig = $scopeConfig; + return parent::__construct($context); + } + + public function execute() + { + require_once('WebToPay.php'); + + $paysera_config = $this->scopeConfig->getValue('payment/paysera', \Magento\Store\Model\ScopeInterface::SCOPE_STORE); + + $callback = \WebToPay::checkResponse($_GET, $paysera_config); + + if($callback['status'] == 1){ + $env = (include './app/etc/env.php'); + $db = $env['db']['connection']['default']; + + $con = mysqli_connect($db['host'], $db['username'], $db['password'], $db['dbname']); + if (!$con) { + die("Database connection failed: " . mysqli_connect_error()); + } + + $i = 0; + + if (mysqli_query($con, "UPDATE sales_order SET state='pending' WHERE entity_id=".$callback['orderid'])) { + $i++; + } else { + echo "Error updating record: " . mysqli_error($con); + } + + if (mysqli_query($con, "UPDATE sales_order SET status='pending' WHERE entity_id=".$callback['orderid'])) { + $i++; + } else { + echo "Error updating record: " . mysqli_error($con); + } + + if (mysqli_query($con, "UPDATE sales_order_grid SET status='pending' WHERE entity_id=".$callback['orderid'])) { + $i++; + } else { + echo "Error updating record: " . mysqli_error($con); + } + + if($i == 3){ + echo 'OK'; + }else{ + echo 'NOT OK'; + } + }else{ + echo 'NOT OK'; + } + } +} \ No newline at end of file diff --git a/Paysera/Paysera/Controller/Index/Index.php b/Paysera/Paysera/Controller/Index/Index.php new file mode 100755 index 0000000..7776244 --- /dev/null +++ b/Paysera/Paysera/Controller/Index/Index.php @@ -0,0 +1,62 @@ +pageFactory = $pageFactory; + $this->scopeConfig = $scopeConfig; + $this->storeManager = $storeManager; + return parent::__construct($context); + } + + public function execute() + { + $env = (include './app/etc/env.php'); + $db = $env['db']['connection']['default']; + + $con = mysqli_connect($db['host'], $db['username'], $db['password'], $db['dbname']); + if (!$con) { + die("Database connection failed: " . mysqli_connect_error()); + } + + $id = mysqli_query($con, "SELECT MAX(entity_id) AS MAX_ID FROM sales_order"); + $id = mysqli_fetch_assoc($id); + $id = $id['MAX_ID']; + + $order = mysqli_query($con, 'SELECT * FROM sales_order WHERE entity_id='.$id); + $order = mysqli_fetch_assoc($order); + + require_once('WebToPay.php'); + + $paysera_config = $this->scopeConfig->getValue('payment/paysera', \Magento\Store\Model\ScopeInterface::SCOPE_STORE); + + $request = \WebToPay::buildRequest(array( + 'projectid' => $paysera_config['projectid'], + 'amount' => $order['grand_total']*100, + 'orderid' => $order['entity_id'], + 'callbackurl' => $this->storeManager->getStore()->getBaseUrl().'paysera/index/callback', + 'currency' => $order['order_currency_code'], + 'country' => 'LT', + 'p_email' => $order['customer_email'], + 'sign_password' => $paysera_config['sign_password'], + 'accepturl' => $this->storeManager->getStore()->getBaseUrl().'checkout/onepage/success', + 'cancelurl' => $this->storeManager->getStore()->getBaseUrl(), + 'test' => $paysera_config['test'], + )); + + echo json_encode(array("url" => \WebToPay::PAYSERA_PAY_URL.'?data='.$request['data'].'&sign='.$request['sign'])); + + } +} \ No newline at end of file diff --git a/Paysera/Paysera/Controller/Index/WebToPay.php b/Paysera/Paysera/Controller/Index/WebToPay.php new file mode 100755 index 0000000..714496b --- /dev/null +++ b/Paysera/Paysera/Controller/Index/WebToPay.php @@ -0,0 +1,2357 @@ +. + * + * @package WebToPay + * @author EVP International + * @license http://www.gnu.org/licenses/lgpl.html + * @version 1.6 + * @link http://www.webtopay.com/ + */ + + +/** + * Contains static methods for most used scenarios. + */ +class WebToPay { + + /** + * WebToPay Library version. + */ + const VERSION = '1.6'; + + /** + * Server URL where all requests should go. + */ + const PAY_URL = 'https://www.paysera.com/pay/'; + + /** + * Server URL where all non-lithuanian language requests should go. + */ + const PAYSERA_PAY_URL = 'https://www.paysera.com/pay/'; + + /** + * Server URL where we can get XML with payment method data. + */ + const XML_URL = 'https://www.paysera.com/new/api/paymentMethods/'; + + /** + * SMS answer url. + */ + const SMS_ANSWER_URL = 'https://www.paysera.com/psms/respond/'; + + /** + * Builds request data array. + * + * This method checks all given data and generates correct request data + * array or raises WebToPayException on failure. + * + * Possible keys: + * https://www.paysera.com/makro_specifikacija.html + * + * @param array $data Information about current payment request + * + * @return array + * + * @throws WebToPayException on data validation error + */ + public static function buildRequest($data) { + if (!isset($data['sign_password']) || !isset($data['projectid'])) { + throw new WebToPayException('sign_password or projectid is not provided'); + } + $password = $data['sign_password']; + $projectId = $data['projectid']; + unset($data['sign_password']); + unset($data['projectid']); + + $factory = new WebToPay_Factory(array('projectId' => $projectId, 'password' => $password)); + $requestBuilder = $factory->getRequestBuilder(); + return $requestBuilder->buildRequest($data); + } + + + /** + * Builds request and redirects user to payment window with generated request data + * + * Possible array keys are described here: + * https://www.paysera.com/makro_specifikacija.html + * + * @param array $data Information about current payment request. + * @param boolean $exit if true, exits after sending Location header; default false + * + * @throws WebToPayException on data validation error + */ + public static function redirectToPayment($data, $exit = false) { + if (!isset($data['sign_password']) || !isset($data['projectid'])) { + throw new WebToPayException('sign_password or projectid is not provided'); + } + $password = $data['sign_password']; + $projectId = $data['projectid']; + unset($data['sign_password']); + unset($data['projectid']); + + $factory = new WebToPay_Factory(array('projectId' => $projectId, 'password' => $password)); + $url = $factory->getRequestBuilder() + ->buildRequestUrlFromData($data); + + if (headers_sent()) { + echo ''; + } else { + header("Location: $url", true); + } + printf( + 'Redirecting to %s. Please wait.', + htmlentities($url, ENT_QUOTES, 'UTF-8'), + htmlentities($url, ENT_QUOTES, 'UTF-8') + ); + if ($exit) { + exit(); + } + } + + /** + * Builds repeat request data array. + * + * This method checks all given data and generates correct request data + * array or raises WebToPayException on failure. + * + * Method accepts single parameter $data of array type. All possible array + * keys are described here: + * https://www.paysera.com/makro_specifikacija.html + * + * @param array $data Information about current payment request + * + * @return array + * + * @throws WebToPayException on data validation error + */ + public static function buildRepeatRequest($data) { + if (!isset($data['sign_password']) || !isset($data['projectid']) || !isset($data['orderid'])) { + throw new WebToPayException('sign_password, projectid or orderid is not provided'); + } + $password = $data['sign_password']; + $projectId = $data['projectid']; + $orderId = $data['orderid']; + + $factory = new WebToPay_Factory(array('projectId' => $projectId, 'password' => $password)); + $requestBuilder = $factory->getRequestBuilder(); + return $requestBuilder->buildRepeatRequest($orderId); + } + + /** + * Returns payment url. Argument is same as lang parameter in request data + * + * @param string $language + * @return string $url + */ + public static function getPaymentUrl($language = 'LIT') { + return (in_array($language, array('lt', 'lit', 'LIT'))) + ? self::PAY_URL + : self::PAYSERA_PAY_URL; + } + + /** + * Parses response from WebToPay server and validates signs. + * + * This function accepts both micro and macro responses. + * + * First parameter usualy should be $_GET array. + * + * Description about response can be found here: + * makro: https://www.paysera.com/makro_specifikacija.html + * mikro: https://www.paysera.com/mikro_mokejimu_specifikacija_SMS.html + * + * If response is not correct, WebToPayException will be raised. + * + * @param array $query Response array + * @param array $userData + * + * @return array + * + * @throws WebToPayException + * @deprecated use validateAndParseData() and check status code yourself + */ + public static function checkResponse($query, $userData = array()) { + $projectId = isset($userData['projectid']) ? $userData['projectid'] : null; + $password = isset($userData['sign_password']) ? $userData['sign_password'] : null; + $logFile = isset($userData['log']) ? $userData['log'] : null; + + try { + $data = self::validateAndParseData($query, $projectId, $password); + if ($data['type'] == 'macro' && $data['status'] != 1) { + throw new WebToPayException('Expected status code 1', WebToPayException::E_DEPRECATED_USAGE); + } + + if ($logFile) { + self::log('OK', http_build_query($data, null, '&'), $logFile); + } + return $data; + + } catch (WebToPayException $exception) { + if ($logFile && $exception->getCode() != WebToPayException::E_DEPRECATED_USAGE) { + self::log('ERR', $exception . "\nQuery: " . http_build_query($query, null, '&'), $logFile); + } + throw $exception; + } + } + + /** + * Parses request (query) data and validates its signature. + * + * @param array $query usually $_GET + * @param integer $projectId + * @param string $password + * + * @return array + * + * @throws WebToPayException + */ + public static function validateAndParseData(array $query, $projectId, $password) { + $factory = new WebToPay_Factory(array('projectId' => $projectId, 'password' => $password)); + $validator = $factory->getCallbackValidator(); + $data = $validator->validateAndParseData($query); + return $data; + } + + /** + * Sends SMS answer + * + * @param array $userData + * + * @throws WebToPayException + * @throws WebToPay_Exception_Validation + */ + public static function smsAnswer($userData) { + if (!isset($userData['id']) || !isset($userData['msg']) || !isset($userData['sign_password'])) { + throw new WebToPay_Exception_Validation('id, msg and sign_password are required'); + } + + $smsId = $userData['id']; + $text = $userData['msg']; + $password = $userData['sign_password']; + $logFile = isset($userData['log']) ? $userData['log'] : null; + + try { + + $factory = new WebToPay_Factory(array('password' => $password)); + $factory->getSmsAnswerSender()->sendAnswer($smsId, $text); + + if ($logFile) { + self::log('OK', 'SMS ANSWER ' . $smsId . ' ' . $text, $logFile); + } + + } catch (WebToPayException $e) { + if ($logFile) { + self::log('ERR', 'SMS ANSWER ' . $e, $logFile); + } + throw $e; + } + + } + + + /** + * Gets available payment methods for project. Gets methods min and max amounts in specified currency. + * + * @param integer $projectId + * @param string $currency + * + * @return WebToPay_PaymentMethodList + * + * @throws WebToPayException + */ + public static function getPaymentMethodList($projectId, $currency = 'EUR') { + $factory = new WebToPay_Factory(array('projectId' => $projectId)); + return $factory->getPaymentMethodListProvider()->getPaymentMethodList($currency); + } + + /** + * Logs to file. Just skips logging if file is not writeable + * + * @param string $type + * @param string $msg + * @param string $logfile + */ + protected static function log($type, $msg, $logfile) { + $fp = @fopen($logfile, 'a'); + if (!$fp) { + return; + } + + $logline = array( + $type, + isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '-', + date('[Y-m-d H:i:s O]'), + 'v' . self::VERSION . ':', + $msg + ); + + $logline = implode(' ', $logline)."\n"; + fwrite($fp, $logline); + fclose($fp); + + // clear big log file + if (filesize($logfile) > 1024 * 1024 * pi()) { + copy($logfile, $logfile.'.old'); + unlink($logfile); + } + } +} + + + + +/** + * Base exception class for all exceptions in this library + */ +class WebToPayException extends Exception { + + /** + * Missing field. + */ + const E_MISSING = 1; + + /** + * Invalid field value. + */ + const E_INVALID = 2; + + /** + * Max length exceeded. + */ + const E_MAXLEN = 3; + + /** + * Regexp for field value doesn't match. + */ + const E_REGEXP = 4; + + /** + * Missing or invalid user given parameters. + */ + const E_USER_PARAMS = 5; + + /** + * Logging errors + */ + const E_LOG = 6; + + /** + * SMS answer errors + */ + const E_SMS_ANSWER = 7; + + /** + * Macro answer errors + */ + const E_STATUS = 8; + + /** + * Library errors - if this happens, bug-report should be sent; also you can check for newer version + */ + const E_LIBRARY = 9; + + /** + * Errors in remote service - it returns some invalid data + */ + const E_SERVICE = 10; + + /** + * Deprecated usage errors + */ + const E_DEPRECATED_USAGE = 11; + + /** + * @var string|boolean + */ + protected $fieldName = false; + + /** + * Sets field which failed + * + * @param string $fieldName + */ + public function setField($fieldName) { + $this->fieldName = $fieldName; + } + + /** + * Gets field which failed + * + * @return string|boolean false + */ + public function getField() { + return $this->fieldName; + } +} + +/** + * Parses and validates callbacks + */ +class WebToPay_CallbackValidator { + + /** + * @var WebToPay_Sign_SignCheckerInterface + */ + protected $signer; + + /** + * @var WebToPay_Util + */ + protected $util; + + /** + * @var integer + */ + protected $projectId; + + /** + * Constructs object + * + * @param integer $projectId + * @param WebToPay_Sign_SignCheckerInterface $signer + * @param WebToPay_Util $util + */ + public function __construct($projectId, WebToPay_Sign_SignCheckerInterface $signer, WebToPay_Util $util) { + $this->signer = $signer; + $this->util = $util; + $this->projectId = $projectId; + } + + /** + * Parses callback parameters from query parameters and checks if sign is correct. + * Request has parameter "data", which is signed and holds all callback parameters + * + * @param array $requestData + * + * @return array Parsed callback parameters + * + * @throws WebToPayException + * @throws WebToPay_Exception_Callback + */ + public function validateAndParseData(array $requestData) { + if (!$this->signer->checkSign($requestData)) { + throw new WebToPay_Exception_Callback('Invalid sign parameters, check $_GET length limit'); + } + + if (!isset($requestData['data'])) { + throw new WebToPay_Exception_Callback('"data" parameter not found'); + } + $data = $requestData['data']; + + $queryString = $this->util->decodeSafeUrlBase64($data); + $request = $this->util->parseHttpQuery($queryString); + + if (!isset($request['projectid'])) { + throw new WebToPay_Exception_Callback( + 'Project ID not provided in callback', + WebToPayException::E_INVALID + ); + } + + if ((string) $request['projectid'] !== (string) $this->projectId) { + throw new WebToPay_Exception_Callback( + sprintf('Bad projectid: %s, should be: %s', $request['projectid'], $this->projectId), + WebToPayException::E_INVALID + ); + } + + if (!isset($request['type']) || !in_array($request['type'], array('micro', 'macro'))) { + $micro = ( + isset($request['to']) + && isset($request['from']) + && isset($request['sms']) + ); + $request['type'] = $micro ? 'micro' : 'macro'; + } + + return $request; + } + + /** + * Checks data to have all the same parameters provided in expected array + * + * @param array $data + * @param array $expected + * + * @throws WebToPayException + */ + public function checkExpectedFields(array $data, array $expected) { + foreach ($expected as $key => $value) { + $passedValue = isset($data[$key]) ? $data[$key] : null; + if ($passedValue != $value) { + throw new WebToPayException( + sprintf('Field %s is not as expected (expected %s, got %s)', $key, $value, $passedValue) + ); + } + } + } +} + +/** + * Wrapper class to group payment methods. Each country can have several payment method groups, each of them + * have one or more payment methods. + */ +class WebToPay_PaymentMethodGroup { + /** + * Some unique (in the scope of country) key for this group + * + * @var string + */ + protected $groupKey; + + /** + * Translations array for this group. Holds associative array of group title by country codes. + * + * @var array + */ + protected $translations; + + /** + * Holds actual payment methods + * + * @var WebToPay_PaymentMethod[] + */ + protected $paymentMethods; + + /** + * Default language for titles + * + * @var string + */ + protected $defaultLanguage; + + /** + * Constructs object + * + * @param string $groupKey + * @param array $translations + * @param string $defaultLanguage + */ + public function __construct($groupKey, array $translations = array(), $defaultLanguage = 'lt') { + $this->groupKey = $groupKey; + $this->translations = $translations; + $this->defaultLanguage = $defaultLanguage; + $this->paymentMethods = array(); + } + + /** + * Sets default language for titles. + * Returns itself for fluent interface + * + * @param string $language + * + * @return WebToPay_PaymentMethodGroup + */ + public function setDefaultLanguage($language) { + $this->defaultLanguage = $language; + foreach ($this->paymentMethods as $paymentMethod) { + $paymentMethod->setDefaultLanguage($language); + } + return $this; + } + + /** + * Gets default language for titles + * + * @return string + */ + public function getDefaultLanguage() { + return $this->defaultLanguage; + } + + /** + * Gets title of the group. Tries to get title in specified language. If it is not found or if language is not + * specified, uses default language, given to constructor. + * + * @param string [Optional] $languageCode + * + * @return string + */ + public function getTitle($languageCode = null) { + if ($languageCode !== null && isset($this->translations[$languageCode])) { + return $this->translations[$languageCode]; + } elseif (isset($this->translations[$this->defaultLanguage])) { + return $this->translations[$this->defaultLanguage]; + } else { + return $this->groupKey; + } + } + + /** + * Returns group key + * + * @return string + */ + public function getKey() { + return $this->groupKey; + } + + /** + * Returns available payment methods for this group + * + * @return WebToPay_PaymentMethod[] + */ + public function getPaymentMethods() { + return $this->paymentMethods; + } + + + /** + * Adds new payment method for this group. + * If some other payment method with specified key was registered earlier, overwrites it. + * Returns given payment method + * + * @param WebToPay_PaymentMethod $paymentMethod + * + * @return WebToPay_PaymentMethod + */ + public function addPaymentMethod(WebToPay_PaymentMethod $paymentMethod) { + return $this->paymentMethods[$paymentMethod->getKey()] = $paymentMethod; + } + + /** + * Gets payment method object with key. If no payment method with such key is found, returns null. + * + * @param string $key + * + * @return null|WebToPay_PaymentMethod + */ + public function getPaymentMethod($key) { + return isset($this->paymentMethods[$key]) ? $this->paymentMethods[$key] : null; + } + + /** + * Returns new group instance with only those payment methods, which are available for provided amount. + * + * @param integer $amount + * @param string $currency + * + * @return WebToPay_PaymentMethodGroup + */ + public function filterForAmount($amount, $currency) { + $group = new WebToPay_PaymentMethodGroup($this->groupKey, $this->translations, $this->defaultLanguage); + foreach ($this->getPaymentMethods() as $paymentMethod) { + if ($paymentMethod->isAvailableForAmount($amount, $currency)) { + $group->addPaymentMethod($paymentMethod); + } + } + return $group; + } + + /** + * Returns new country instance with only those payment methods, which are returns or not iban number after payment + * + * @param boolean $isIban + * + * @return WebToPay_PaymentMethodGroup + */ + public function filterForIban($isIban = true) { + $group = new WebToPay_PaymentMethodGroup($this->groupKey, $this->translations, $this->defaultLanguage); + foreach ($this->getPaymentMethods() as $paymentMethod) { + if ($paymentMethod->isIban() == $isIban) { + $group->addPaymentMethod($paymentMethod); + } + } + return $group; + } + + /** + * Returns whether this group has no payment methods + * + * @return boolean + */ + public function isEmpty() { + return count($this->paymentMethods) === 0; + } + + /** + * Loads payment methods from given XML node + * + * @param SimpleXMLElement $groupNode + */ + public function fromXmlNode($groupNode) { + foreach ($groupNode->payment_type as $paymentTypeNode) { + $key = (string) $paymentTypeNode->attributes()->key; + $titleTranslations = array(); + foreach ($paymentTypeNode->title as $titleNode) { + $titleTranslations[(string) $titleNode->attributes()->language] = (string) $titleNode; + } + $logoTranslations = array(); + foreach ($paymentTypeNode->logo_url as $logoNode) { + if ((string) $logoNode !== '') { + $logoTranslations[(string) $logoNode->attributes()->language] = (string) $logoNode; + } + } + $minAmount = null; + $maxAmount = null; + $currency = null; + $isIban = false; + $baseCurrency = null; + if (isset($paymentTypeNode->min)) { + $minAmount = (int) $paymentTypeNode->min->attributes()->amount; + $currency = (string) $paymentTypeNode->min->attributes()->currency; + } + if (isset($paymentTypeNode->max)) { + $maxAmount = (int) $paymentTypeNode->max->attributes()->amount; + $currency = (string) $paymentTypeNode->max->attributes()->currency; + } + + if (isset($paymentTypeNode->is_iban)) { + $isIban = (int) $paymentTypeNode->is_iban; + } + if (isset($paymentTypeNode->base_currency)) { + $baseCurrency = (string) $paymentTypeNode->base_currency; + } + $this->addPaymentMethod($this->createPaymentMethod( + $key, $minAmount, $maxAmount, $currency, $logoTranslations, $titleTranslations, $isIban, $baseCurrency + )); + } + } + + /** + * Method to create new payment method instances. Overwrite if you have to use some other subclass. + * + * @param string $key + * @param integer $minAmount + * @param integer $maxAmount + * @param string $currency + * @param array $logoList + * @param array $titleTranslations + * @param bool $isIban + * @param null $baseCurrency + * + * @return WebToPay_PaymentMethod + */ + protected function createPaymentMethod( + $key, $minAmount, $maxAmount, $currency, array $logoList = array(), array $titleTranslations = array(), + $isIban = false, $baseCurrency = null + ) { + return new WebToPay_PaymentMethod( + $key, $minAmount, $maxAmount, $currency, $logoList, $titleTranslations, $this->defaultLanguage, + $isIban, $baseCurrency + ); + } +} + +/** + * Loads data about payment methods and constructs payment method list object from that data + * You need SimpleXML support to use this feature + */ +class WebToPay_PaymentMethodListProvider { + + /** + * @var integer + */ + protected $projectId; + + /** + * @var WebToPay_WebClient + */ + protected $webClient; + + /** + * Holds constructed method lists by currency + * + * @var WebToPay_PaymentMethodList[] + */ + protected $methodListCache = array(); + + /** + * Builds various request URLs + * + * @var WebToPay_UrlBuilder $urlBuilder + */ + protected $urlBuilder; + + /** + * Constructs object + * + * @param integer $projectId + * @param WebToPay_WebClient $webClient + * @param WebToPay_UrlBuilder $urlBuilder + * + * @throws WebToPayException if SimpleXML is not available + */ + public function __construct( + $projectId, + WebToPay_WebClient $webClient, + WebToPay_UrlBuilder $urlBuilder + ) + { + $this->projectId = $projectId; + $this->webClient = $webClient; + $this->urlBuilder = $urlBuilder; + + if (!function_exists('simplexml_load_string')) { + throw new WebToPayException('You have to install libxml to use payment methods API'); + } + } + + /** + * Gets payment method list for specified currency + * + * @param string $currency + * + * @return WebToPay_PaymentMethodList + * + * @throws WebToPayException + */ + public function getPaymentMethodList($currency) { + if (!isset($this->methodListCache[$currency])) { + $xmlAsString = $this->webClient->get($this->urlBuilder->buildForPaymentsMethodList($this->projectId, $currency)); + $useInternalErrors = libxml_use_internal_errors(false); + $rootNode = simplexml_load_string($xmlAsString); + libxml_clear_errors(); + libxml_use_internal_errors($useInternalErrors); + if (!$rootNode) { + throw new WebToPayException('Unable to load XML from remote server'); + } + $methodList = new WebToPay_PaymentMethodList($this->projectId, $currency); + $methodList->fromXmlNode($rootNode); + $this->methodListCache[$currency] = $methodList; + } + return $this->methodListCache[$currency]; + } +} + +/** + * Raised on error in callback + */ +class WebToPay_Exception_Callback extends WebToPayException { + +} + +/** + * Raised if configuration is incorrect + */ +class WebToPay_Exception_Configuration extends WebToPayException { + +} + + +/** + * Raised on validation error in passed data when building the request + */ +class WebToPay_Exception_Validation extends WebToPayException { + + public function __construct($message, $code = 0, $field = null, Exception $previousException = null) { + parent::__construct($message, $code, $previousException); + if ($field) { + $this->setField($field); + } + } +} + +/** + * Class to hold information about payment method + */ +class WebToPay_PaymentMethod { + /** + * Assigned key for this payment method + * + * @var string + */ + protected $key; + + /** + * Logo url list by language. Usually logo is same for all languages, but exceptions exist + * + * @var array + */ + protected $logoList; + + /** + * Title list by language + * + * @var array + */ + protected $titleTranslations; + + /** + * Default language to use for titles + * + * @var string + */ + protected $defaultLanguage; + + /** + * @var boolean + */ + protected $isIban; + + /** + * @var string + */ + protected $baseCurrency; + + /** + * Constructs object + * + * @param string $key + * @param integer $minAmount + * @param integer $maxAmount + * @param string $currency + * @param array $logoList + * @param array $titleTranslations + * @param string $defaultLanguage + * @param bool $isIban + * @param string $baseCurrency + */ + public function __construct( + $key, $minAmount, $maxAmount, $currency, array $logoList = array(), array $titleTranslations = array(), + $defaultLanguage = 'lt', $isIban = false, $baseCurrency = null + ) { + $this->key = $key; + $this->minAmount = $minAmount; + $this->maxAmount = $maxAmount; + $this->currency = $currency; + $this->logoList = $logoList; + $this->titleTranslations = $titleTranslations; + $this->defaultLanguage = $defaultLanguage; + $this->isIban = $isIban; + $this->baseCurrency = $baseCurrency; + } + + /** + * Sets default language for titles. + * Returns itself for fluent interface + * + * @param string $language + * + * @return WebToPay_PaymentMethod + */ + public function setDefaultLanguage($language) { + $this->defaultLanguage = $language; + return $this; + } + + /** + * Gets default language for titles + * + * @return string + */ + public function getDefaultLanguage() { + return $this->defaultLanguage; + } + + /** + * Get assigned payment method key + * + * @return string + */ + public function getKey() { + return $this->key; + } + + /** + * Gets logo url for this payment method. Uses specified language or default one. + * If logotype is not found for specified language, null is returned. + * + * @param string [Optional] $languageCode + * + * @return string|null + */ + public function getLogoUrl($languageCode = null) { + if ($languageCode !== null && isset($this->logoList[$languageCode])) { + return $this->logoList[$languageCode]; + } elseif (isset($this->logoList[$this->defaultLanguage])) { + return $this->logoList[$this->defaultLanguage]; + } else { + return null; + } + } + + /** + * Gets title for this payment method. Uses specified language or default one. + * + * @param string [Optional] $languageCode + * + * @return string + */ + public function getTitle($languageCode = null) { + if ($languageCode !== null && isset($this->titleTranslations[$languageCode])) { + return $this->titleTranslations[$languageCode]; + } elseif (isset($this->titleTranslations[$this->defaultLanguage])) { + return $this->titleTranslations[$this->defaultLanguage]; + } else { + return $this->key; + } + } + + /** + * Checks if this payment method can be used for specified amount. + * Throws exception if currency checked is not the one, for which payment method list was downloaded. + * + * @param integer $amount + * @param string $currency + * + * @return boolean + * + * @throws WebToPayException + */ + public function isAvailableForAmount($amount, $currency) { + if ($this->currency !== $currency) { + throw new WebToPayException( + 'Currencies does not match. You have to get payment types for the currency you are checking. Given currency: ' + . $currency . ', available currency: ' . $this->currency + ); + } + return ( + ($this->minAmount === null || $amount >= $this->minAmount) + && ($this->maxAmount === null || $amount <= $this->maxAmount) + ); + } + + /** + * Returns min amount for this payment method. If no min amount is specified, returns empty string. + * + * @return string + */ + public function getMinAmountAsString() { + return $this->minAmount === null ? '' : ($this->minAmount . ' ' . $this->currency); + } + + /** + * Returns max amount for this payment method. If no max amount is specified, returns empty string. + * + * @return string + */ + public function getMaxAmountAsString() { + return $this->maxAmount === null ? '' : ($this->maxAmount . ' ' . $this->currency); + } + + /** + * Set if this method returns IBAN number after payment + * + * @param boolean $isIban + */ + public function setIsIban($isIban) { + $this->isIban = $isIban == 1; + } + + /** + * Get if this method returns IBAN number after payment + * + * @return bool + */ + public function isIban() { + return $this->isIban; + } + + /** + * Setter of BaseCurrency + * + * @param string $baseCurrency + */ + public function setBaseCurrency($baseCurrency) + { + $this->baseCurrency = $baseCurrency; + } + + /** + * Getter of BaseCurrency + * + * @return string + */ + public function getBaseCurrency() + { + return $this->baseCurrency; + } +} + + +/** + * Utility class + */ +class WebToPay_Util { + + /** + * Decodes url-safe-base64 encoded string + * Url-safe-base64 is same as base64, but + is replaced to - and / to _ + * + * @param string $encodedText + * + * @return string + */ + public function decodeSafeUrlBase64($encodedText) { + return base64_decode(strtr($encodedText, array('-' => '+', '_' => '/'))); + } + + /** + * Encodes string to url-safe-base64 + * Url-safe-base64 is same as base64, but + is replaced to - and / to _ + * + * @param string $text + * + * @return string + */ + public function encodeSafeUrlBase64($text) { + return strtr(base64_encode($text), array('+' => '-', '/' => '_')); + } + + /** + * Parses HTTP query to array + * + * @param string $query + * + * @return array + */ + public function parseHttpQuery($query) { + $params = array(); + parse_str($query, $params); + if (get_magic_quotes_gpc()) { + $params = $this->stripSlashesRecursively($params); + } + return $params; + } + + /** + * Strips slashes recursively, so this method can be used on arrays with more than one level + * + * @param mixed $data + * + * @return mixed + */ + protected function stripSlashesRecursively($data) { + if (is_array($data)) { + $result = array(); + foreach ($data as $key => $value) { + $result[stripslashes($key)] = $this->stripSlashesRecursively($value); + } + return $result; + } else { + return stripslashes($data); + } + } +} + +/** + * Class with all information about available payment methods for some project, optionally filtered by some amount. + */ +class WebToPay_PaymentMethodList { + /** + * Holds available payment countries + * + * @var WebToPay_PaymentMethodCountry[] + */ + protected $countries; + + /** + * Default language for titles + * + * @var string + */ + protected $defaultLanguage; + + /** + * Project ID, to which this method list is valid + * + * @var integer + */ + protected $projectId; + + /** + * Currency for min and max amounts in this list + * + * @var string + */ + protected $currency; + + /** + * If this list is filtered for some amount, this field defines it + * + * @var integer + */ + protected $amount; + + /** + * Constructs object + * + * @param integer $projectId + * @param string $currency currency for min and max amounts in this list + * @param string $defaultLanguage + * @param integer $amount null if this list is not filtered by amount + */ + public function __construct($projectId, $currency, $defaultLanguage = 'lt', $amount = null) { + $this->projectId = $projectId; + $this->countries = array(); + $this->defaultLanguage = $defaultLanguage; + $this->currency = $currency; + $this->amount = $amount; + } + + /** + * Sets default language for titles. + * Returns itself for fluent interface + * + * @param string $language + * + * @return WebToPay_PaymentMethodList + */ + public function setDefaultLanguage($language) { + $this->defaultLanguage = $language; + foreach ($this->countries as $country) { + $country->setDefaultLanguage($language); + } + return $this; + } + + /** + * Gets default language for titles + * + * @return string + */ + public function getDefaultLanguage() { + return $this->defaultLanguage; + } + + /** + * Gets project ID for this payment method list + * + * @return integer + */ + public function getProjectId() { + return $this->projectId; + } + + /** + * Gets currency for min and max amounts in this list + * + * @return string + */ + public function getCurrency() { + return $this->currency; + } + + /** + * Gets whether this list is already filtered for some amount + * + * @return boolean + */ + public function isFiltered() { + return $this->amount !== null; + } + + /** + * Returns available countries + * + * @return WebToPay_PaymentMethodCountry[] + */ + public function getCountries() { + return $this->countries; + } + + /** + * Adds new country to payment methods. If some other country with same code was registered earlier, overwrites it. + * Returns added country instance + * + * @param WebToPay_PaymentMethodCountry $country + * + * @return WebToPay_PaymentMethodCountry + */ + public function addCountry(WebToPay_PaymentMethodCountry $country) { + return $this->countries[$country->getCode()] = $country; + } + + /** + * Gets country object with specified country code. If no country with such country code is found, returns null. + * + * @param string $countryCode + * + * @return null|WebToPay_PaymentMethodCountry + */ + public function getCountry($countryCode) { + return isset($this->countries[$countryCode]) ? $this->countries[$countryCode] : null; + } + + /** + * Returns new payment method list instance with only those payment methods, which are available for provided + * amount. + * Returns itself, if list is already filtered and filter amount matches the given one. + * + * @param integer $amount + * @param string $currency + * + * @return WebToPay_PaymentMethodList + * + * @throws WebToPayException if this list is already filtered and not for provided amount + */ + public function filterForAmount($amount, $currency) { + if ($currency !== $this->currency) { + throw new WebToPayException( + 'Currencies do not match. Given currency: ' . $currency . ', currency in list: ' . $this->currency + ); + } + if ($this->isFiltered()) { + if ($this->amount === $amount) { + return $this; + } else { + throw new WebToPayException('This list is already filtered, use unfiltered list instead'); + } + } else { + $list = new WebToPay_PaymentMethodList($this->projectId, $currency, $this->defaultLanguage, $amount); + foreach ($this->getCountries() as $country) { + $country = $country->filterForAmount($amount, $currency); + if (!$country->isEmpty()) { + $list->addCountry($country); + } + } + return $list; + } + } + + /** + * Loads countries from given XML node + * + * @param SimpleXMLElement $xmlNode + */ + public function fromXmlNode($xmlNode) { + foreach ($xmlNode->country as $countryNode) { + $titleTranslations = array(); + foreach ($countryNode->title as $titleNode) { + $titleTranslations[(string) $titleNode->attributes()->language] = (string) $titleNode; + } + $this->addCountry($this->createCountry((string) $countryNode->attributes()->code, $titleTranslations)) + ->fromXmlNode($countryNode); + } + } + + /** + * Method to create new country instances. Overwrite if you have to use some other country subtype. + * + * @param string $countryCode + * @param array $titleTranslations + * + * @return WebToPay_PaymentMethodCountry + */ + protected function createCountry($countryCode, array $titleTranslations = array()) { + return new WebToPay_PaymentMethodCountry($countryCode, $titleTranslations, $this->defaultLanguage); + } +} + +/** + * Sends answer to SMS payment if it was not provided with response to callback + */ +class WebToPay_SmsAnswerSender { + + /** + * @var string + */ + protected $password; + + /** + * @var WebToPay_WebClient + */ + protected $webClient; + + /** + * @var WebToPay_UrlBuilder $urlBuilder + */ + protected $urlBuilder; + + /** + * Constructs object + * + * @param string $password + * @param WebToPay_WebClient $webClient + * @param WebToPay_UrlBuilder $urlBuilder + */ + public function __construct( + $password, + WebToPay_WebClient $webClient, + WebToPay_UrlBuilder $urlBuilder + ) { + $this->password = $password; + $this->webClient = $webClient; + $this->urlBuilder = $urlBuilder; + } + + /** + * Sends answer by sms ID get from callback. Answer can be send only if it was not provided + * when responding to callback + * + * @param integer $smsId + * @param string $text + * + * @throws WebToPayException + */ + public function sendAnswer($smsId, $text) { + $content = $this->webClient->get($this->urlBuilder->buildForSmsAnswer(), array( + 'id' => $smsId, + 'msg' => $text, + 'transaction' => md5($this->password . '|' . $smsId), + )); + if (strpos($content, 'OK') !== 0) { + throw new WebToPayException( + sprintf('Error: %s', $content), + WebToPayException::E_SMS_ANSWER + ); + } + } +} + + +/** + * Creates objects. Also caches to avoid creating several instances of same objects + */ +class WebToPay_Factory { + + const ENV_PRODUCTION = 'production'; + const ENV_SANDBOX = 'sandbox'; + + /** + * @var array + */ + protected static $defaultConfiguration = array( + 'routes' => array( + self::ENV_PRODUCTION => array( + 'publicKey' => 'http://www.paysera.com/download/public.key', + 'payment' => 'https://www.paysera.com/pay/', + 'paymentMethodList' => 'https://www.paysera.com/new/api/paymentMethods/', + 'smsAnswer' => 'https://www.paysera.com/psms/respond/', + ), + self::ENV_SANDBOX => array( + 'publicKey' => 'http://sandbox.paysera.com/download/public.key', + 'payment' => 'https://sandbox.paysera.com/pay/', + 'paymentMethodList' => 'https://sandbox.paysera.com/new/api/paymentMethods/', + 'smsAnswer' => 'https://sandbox.paysera.com/psms/respond/', + ), + ) + ); + + /** + * @var string + */ + protected $environment; + + /** + * @var array + */ + protected $configuration; + + /** + * @var WebToPay_WebClient + */ + protected $webClient = null; + + /** + * @var WebToPay_CallbackValidator + */ + protected $callbackValidator = null; + + /** + * @var WebToPay_RequestBuilder + */ + protected $requestBuilder = null; + + /** + * @var WebToPay_Sign_SignCheckerInterface + */ + protected $signer = null; + + /** + * @var WebToPay_SmsAnswerSender + */ + protected $smsAnswerSender = null; + + /** + * @var WebToPay_PaymentMethodListProvider + */ + protected $paymentMethodListProvider = null; + + /** + * @var WebToPay_Util + */ + protected $util = null; + + /** + * @var WebToPay_UrlBuilder + */ + protected $urlBuilder = null; + + + /** + * Constructs object. + * Configuration keys: projectId, password + * They are required only when some object being created needs them, + * if they are not found at that moment - exception is thrown + * + * @param array $configuration + */ + public function __construct(array $configuration = array()) { + + $this->configuration = array_merge(self::$defaultConfiguration, $configuration); + $this->environment = self::ENV_PRODUCTION; + } + + /** + * If passed true the factory will use sandbox when constructing URLs + * + * @param $enableSandbox + * @return self + */ + public function useSandbox($enableSandbox) + { + if ($enableSandbox) { + $this->environment = self::ENV_SANDBOX; + } else { + $this->environment = self::ENV_PRODUCTION; + } + return $this; + } + + /** + * Creates or gets callback validator instance + * + * @return WebToPay_CallbackValidator + * + * @throws WebToPay_Exception_Configuration + */ + public function getCallbackValidator() { + if ($this->callbackValidator === null) { + if (!isset($this->configuration['projectId'])) { + throw new WebToPay_Exception_Configuration('You have to provide project ID'); + } + $this->callbackValidator = new WebToPay_CallbackValidator( + $this->configuration['projectId'], + $this->getSigner(), + $this->getUtil() + ); + } + return $this->callbackValidator; + } + + /** + * Creates or gets request builder instance + * + * @throws WebToPay_Exception_Configuration + * + * @return WebToPay_RequestBuilder + */ + public function getRequestBuilder() { + if ($this->requestBuilder === null) { + if (!isset($this->configuration['password'])) { + throw new WebToPay_Exception_Configuration('You have to provide project password to sign request'); + } + if (!isset($this->configuration['projectId'])) { + throw new WebToPay_Exception_Configuration('You have to provide project ID'); + } + $this->requestBuilder = new WebToPay_RequestBuilder( + $this->configuration['projectId'], + $this->configuration['password'], + $this->getUtil(), + $this->getUrlBuilder() + ); + } + return $this->requestBuilder; + } + + /** + * @return WebToPay_UrlBuilder + */ + public function getUrlBuilder() { + if ($this->urlBuilder === null) { + $this->urlBuilder = new WebToPay_UrlBuilder( + $this->configuration, + $this->environment + ); + } + return $this->urlBuilder; + } + + /** + * Creates or gets SMS answer sender instance + * + * @throws WebToPay_Exception_Configuration + * + * @return WebToPay_SmsAnswerSender + */ + public function getSmsAnswerSender() { + if ($this->smsAnswerSender === null) { + if (!isset($this->configuration['password'])) { + throw new WebToPay_Exception_Configuration('You have to provide project password'); + } + $this->smsAnswerSender = new WebToPay_SmsAnswerSender( + $this->configuration['password'], + $this->getWebClient(), + $this->getUrlBuilder() + ); + } + return $this->smsAnswerSender; + } + + /** + * Creates or gets payment list provider instance + * + * @throws WebToPay_Exception_Configuration + * + * @return WebToPay_PaymentMethodListProvider + */ + public function getPaymentMethodListProvider() { + if ($this->paymentMethodListProvider === null) { + if (!isset($this->configuration['projectId'])) { + throw new WebToPay_Exception_Configuration('You have to provide project ID'); + } + $this->paymentMethodListProvider = new WebToPay_PaymentMethodListProvider( + $this->configuration['projectId'], + $this->getWebClient(), + $this->getUrlBuilder() + + ); + } + return $this->paymentMethodListProvider; + } + + /** + * Creates or gets signer instance. Chooses SS2 signer if openssl functions are available, SS1 in other case + * + * @throws WebToPay_Exception_Configuration + * + * @return WebToPay_Sign_SignCheckerInterface + * + * @throws WebToPayException + */ + protected function getSigner() { + if ($this->signer === null) { + if (function_exists('openssl_pkey_get_public')) { + $webClient = $this->getWebClient(); + $publicKey = $webClient->get($this->getUrlBuilder()->buildForPublicKey()); + if (!$publicKey) { + throw new WebToPayException('Cannot download public key from WebToPay website'); + } + $this->signer = new WebToPay_Sign_SS2SignChecker($publicKey, $this->getUtil()); + } else { + if (!isset($this->configuration['password'])) { + throw new WebToPay_Exception_Configuration( + 'You have to provide project password if OpenSSL is unavailable' + ); + } + $this->signer = new WebToPay_Sign_SS1SignChecker($this->configuration['password']); + } + } + return $this->signer; + } + + /** + * Creates or gets web client instance + * + * @throws WebToPay_Exception_Configuration + * + * @return WebToPay_WebClient + */ + protected function getWebClient() { + if ($this->webClient === null) { + $this->webClient = new WebToPay_WebClient(); + } + return $this->webClient; + } + + /** + * Creates or gets util instance + * + * @throws WebToPay_Exception_Configuration + * + * @return WebToPay_Util + */ + protected function getUtil() { + if ($this->util === null) { + $this->util = new WebToPay_Util(); + } + return $this->util; + } +} + + +/** + * Sign checker which checks SS1 signature. SS1 does not depend on SSL functions + */ +class WebToPay_Sign_SS1SignChecker implements WebToPay_Sign_SignCheckerInterface { + + /** + * @var string + */ + protected $projectPassword; + + /** + * Constructs object + * + * @param string $projectPassword + */ + public function __construct($projectPassword) { + $this->projectPassword = $projectPassword; + } + + /** + * Check for SS1, which is not depend on openssl functions. + * + * @param array $request + * + * @return boolean + * + * @throws WebToPay_Exception_Callback + */ + public function checkSign(array $request) { + if (!isset($request['data']) || !isset($request['ss1'])) { + throw new WebToPay_Exception_Callback('Not enough parameters in callback. Possible version mismatch'); + } + + return md5($request['data'] . $this->projectPassword) === $request['ss1']; + } +} + +/** + * Checks SS2 signature. Depends on SSL functions + */ +class WebToPay_Sign_SS2SignChecker implements WebToPay_Sign_SignCheckerInterface { + + /** + * @var string + */ + protected $publicKey; + + /** + * @var WebToPay_Util + */ + protected $util; + + /** + * Constructs object + * + * @param string $publicKey + * @param WebToPay_Util $util + */ + public function __construct($publicKey, WebToPay_Util $util) { + $this->publicKey = $publicKey; + $this->util = $util; + } + + /** + * Checks signature + * + * @param array $request + * + * @return boolean + * + * @throws WebToPay_Exception_Callback + */ + public function checkSign(array $request) { + if (!isset($request['data']) || !isset($request['ss2'])) { + throw new WebToPay_Exception_Callback('Not enough parameters in callback. Possible version mismatch'); + } + + $ss2 = $this->util->decodeSafeUrlBase64($request['ss2']); + $ok = openssl_verify($request['data'], $ss2, $this->publicKey); + return $ok === 1; + } +} + +/** + * Interface for sign checker + */ +interface WebToPay_Sign_SignCheckerInterface { + + /** + * Checks whether request is signed properly + * + * @param array $request + * + * @return boolean + */ + public function checkSign(array $request); +} + +/** + * Simple web client + */ +class WebToPay_WebClient { + + /** + * Gets page contents by specified URI. Adds query data if provided to the URI + * Ignores status code of the response and header fields + * + * @param string $uri + * @param array $queryData + * + * @return string + * + * @throws WebToPayException + */ + public function get($uri, array $queryData = array()) { + if (count($queryData) > 0) { + $uri .= strpos($uri, '?') === false ? '?' : '&'; + $uri .= http_build_query($queryData, null, '&'); + } + $url = parse_url($uri); + if ('https' == $url['scheme']) { + $host = 'ssl://'.$url['host']; + $port = 443; + } else { + $host = $url['host']; + $port = 80; + } + + $fp = fsockopen($host, $port, $errno, $errstr, 30); + if (!$fp) { + throw new WebToPayException(sprintf('Cannot connect to %s', $uri), WebToPayException::E_INVALID); + } + + if(isset($url['query'])) { + $data = $url['path'].'?'.$url['query']; + } else { + $data = $url['path']; + } + + $out = "GET " . $data . " HTTP/1.0\r\n"; + $out .= "Host: ".$url['host']."\r\n"; + $out .= "Connection: Close\r\n\r\n"; + + $content = ''; + + fwrite($fp, $out); + while (!feof($fp)) $content .= fgets($fp, 8192); + fclose($fp); + + list($header, $content) = explode("\r\n\r\n", $content, 2); + + return trim($content); + } +} + +/** + * Payment method configuration for some country + */ +class WebToPay_PaymentMethodCountry { + /** + * @var string + */ + protected $countryCode; + + /** + * Holds available payment types for this country + * + * @var WebToPay_PaymentMethodGroup[] + */ + protected $groups; + + /** + * Default language for titles + * + * @var string + */ + protected $defaultLanguage; + + /** + * Translations array for this country. Holds associative array of country title by language codes. + * + * @var array + */ + protected $titleTranslations; + + /** + * Constructs object + * + * @param string $countryCode + * @param array $titleTranslations + * @param string $defaultLanguage + */ + public function __construct($countryCode, $titleTranslations, $defaultLanguage = 'lt') { + $this->countryCode = $countryCode; + $this->defaultLanguage = $defaultLanguage; + $this->titleTranslations = $titleTranslations; + $this->groups = array(); + } + + /** + * Sets default language for titles. + * Returns itself for fluent interface + * + * @param string $language + * + * @return WebToPay_PaymentMethodCountry + */ + public function setDefaultLanguage($language) { + $this->defaultLanguage = $language; + foreach ($this->groups as $group) { + $group->setDefaultLanguage($language); + } + return $this; + } + + /** + * Gets title of the group. Tries to get title in specified language. If it is not found or if language is not + * specified, uses default language, given to constructor. + * + * @param string [Optional] $languageCode + * + * @return string + */ + public function getTitle($languageCode = null) { + if ($languageCode !== null && isset($this->titleTranslations[$languageCode])) { + return $this->titleTranslations[$languageCode]; + } elseif (isset($this->titleTranslations[$this->defaultLanguage])) { + return $this->titleTranslations[$this->defaultLanguage]; + } else { + return $this->countryCode; + } + } + + /** + * Gets default language for titles + * + * @return string + */ + public function getDefaultLanguage() { + return $this->defaultLanguage; + } + + /** + * Gets country code + * + * @return string + */ + public function getCode() { + return $this->countryCode; + } + + /** + * Adds new group to payment methods for this country. + * If some other group was registered earlier with same key, overwrites it. + * Returns given group + * + * @param WebToPay_PaymentMethodGroup $group + * + * @return WebToPay_PaymentMethodGroup + */ + public function addGroup(WebToPay_PaymentMethodGroup $group) { + return $this->groups[$group->getKey()] = $group; + } + + /** + * Gets group object with specified group key. If no group with such key is found, returns null. + * + * @param string $groupKey + * + * @return null|WebToPay_PaymentMethodGroup + */ + public function getGroup($groupKey) { + return isset($this->groups[$groupKey]) ? $this->groups[$groupKey] : null; + } + + /** + * Returns payment method groups registered for this country. + * + * @return WebToPay_PaymentMethodGroup[] + */ + public function getGroups() { + return $this->groups; + } + + /** + * Gets payment methods in all groups + * + * @return WebToPay_PaymentMethod[] + */ + public function getPaymentMethods() { + $paymentMethods = array(); + foreach ($this->groups as $group) { + $paymentMethods = array_merge($paymentMethods, $group->getPaymentMethods()); + } + return $paymentMethods; + } + + /** + * Returns new country instance with only those payment methods, which are available for provided amount. + * + * @param integer $amount + * @param string $currency + * + * @return WebToPay_PaymentMethodCountry + */ + public function filterForAmount($amount, $currency) { + $country = new WebToPay_PaymentMethodCountry($this->countryCode, $this->titleTranslations, $this->defaultLanguage); + foreach ($this->getGroups() as $group) { + $group = $group->filterForAmount($amount, $currency); + if (!$group->isEmpty()) { + $country->addGroup($group); + } + } + return $country; + } + + /** + * Returns new country instance with only those payment methods, which are returns or not iban number after payment + * + * @param boolean $isIban + * + * @return WebToPay_PaymentMethodCountry + */ + public function filterForIban($isIban = true) { + $country = new WebToPay_PaymentMethodCountry($this->countryCode, $this->titleTranslations, $this->defaultLanguage); + foreach ($this->getGroups() as $group) { + $group = $group->filterForIban($isIban); + if (!$group->isEmpty()) { + $country->addGroup($group); + } + } + return $country; + } + + /** + * Returns whether this country has no groups + * + * @return boolean + */ + public function isEmpty() { + return count($this->groups) === 0; + } + + /** + * Loads groups from given XML node + * + * @param SimpleXMLElement $countryNode + */ + public function fromXmlNode($countryNode) { + foreach ($countryNode->payment_group as $groupNode) { + $key = (string) $groupNode->attributes()->key; + $titleTranslations = array(); + foreach ($groupNode->title as $titleNode) { + $titleTranslations[(string) $titleNode->attributes()->language] = (string) $titleNode; + } + $this->addGroup($this->createGroup($key, $titleTranslations))->fromXmlNode($groupNode); + } + } + + /** + * Method to create new group instances. Overwrite if you have to use some other group subtype. + * + * @param string $groupKey + * @param array $translations + * + * @return WebToPay_PaymentMethodGroup + */ + protected function createGroup($groupKey, array $translations = array()) { + return new WebToPay_PaymentMethodGroup($groupKey, $translations, $this->defaultLanguage); + } +} + + +/** + * Used to build a complete request URL. + * + * Class WebToPay_UrlBuilder + */ +class WebToPay_UrlBuilder { + + const PLACEHOLDER_KEY = '[domain]'; + + /** + * @var array + */ + protected $configuration = array(); + + /** + * @var string + */ + protected $environment; + + /** + * @var array + */ + protected $environmentSettings; + + /** + * @param array $configuration + * @param string $environment + */ + function __construct($configuration, $environment) + { + $this->configuration = $configuration; + $this->environment = $environment; + $this->environmentSettings = $this->configuration['routes'][$this->environment]; + } + + /** + * Builds a complete request URL based on the provided parameters + * + * @param $request + * @param null $language + * @return string + */ + public function buildForRequest($request, $language = null) { + return $this->createUrlFromRequestAndLanguage($request); + } + + /** + * Builds a complete URL for payment list API + * + * @param int $projectId + * @param string $currency + * @return string + */ + public function buildForPaymentsMethodList($projectId, $currency) { + $route = $this->environmentSettings['paymentMethodList']; + return $route . $projectId . '/currency:' . $currency; + } + + /** + * Builds a complete URL for Sms Answer + * + * @return string + */ + public function buildForSmsAnswer() { + $route = $this->environmentSettings['smsAnswer']; + return $route; + } + + /** + * Build the url to the public key + * + * @return string + */ + public function buildForPublicKey() { + $route = $this->environmentSettings['publicKey']; + return $route; + } + + /** + * Creates an URL from the request and data provided. + * + * @param array $request + * @return string + */ + protected function createUrlFromRequestAndLanguage($request) { + $url = $this->getPaymentUrl() . '?' . http_build_query($request, null, '&'); + return preg_replace('/[\r\n]+/is', '', $url); + } + + /** + * Returns payment url. Argument is same as lang parameter in request data + * + * @return string $url + */ + protected function getPaymentUrl() { + $route = $this->environmentSettings['payment']; + return $route; + } +} + + +/** + * Builds and signs requests + */ +class WebToPay_RequestBuilder { + + /** + * @var string + */ + protected $projectPassword; + + /** + * @var WebToPay_Util + */ + protected $util; + + /** + * @var integer + */ + protected $projectId; + + + /** + * @var WebToPay_UrlBuilder $urlBuilder + */ + protected $urlBuilder; + + /** + * Constructs object + * + * @param integer $projectId + * @param string $projectPassword + * @param WebToPay_Util $util + * @param WebToPay_UrlBuilder $urlBuilder + */ + public function __construct( + $projectId, + $projectPassword, + WebToPay_Util $util, + WebToPay_UrlBuilder $urlBuilder + ) + { + $this->projectId = $projectId; + $this->projectPassword = $projectPassword; + $this->util = $util; + $this->urlBuilder = $urlBuilder; + } + + /** + * Builds request data array. + * + * This method checks all given data and generates correct request data + * array or raises WebToPayException on failure. + * + * @param array $data information about current payment request + * + * @return array + * + * @throws WebToPayException + */ + public function buildRequest($data) { + $this->validateRequest($data, self::getRequestSpec()); + $data['version'] = WebToPay::VERSION; + $data['projectid'] = $this->projectId; + unset($data['repeat_request']); + return $this->createRequest($data); + } + + /** + * Builds the full request url (including the protocol and the domain) + * + * @param array $data + * @return string + */ + public function buildRequestUrlFromData($data) { + $language = isset($data['lang']) ? $data['lang'] : null; + $request = $this->buildRequest($data); + return $this->urlBuilder->buildForRequest($request, $language); + } + + /** + * Builds repeat request data array. + * + * This method checks all given data and generates correct request data + * array or raises WebToPayException on failure. + * + * @param string $orderId order id of repeated request + * + * @return array + * + * @throws WebToPayException + */ + public function buildRepeatRequest($orderId) { + $data['orderid'] = $orderId; + $data['version'] = WebToPay::VERSION; + $data['projectid'] = $this->projectId; + $data['repeat_request'] = '1'; + return $this->createRequest($data); + } + + /** + * Builds the full request url for a repeated request (including the protocol and the domain) + * + * @param string $orderId order id of repeated request + * @return string + */ + public function buildRepeatRequestUrlFromOrderId($orderId) { + $request = $this->buildRepeatRequest($orderId); + return $this->urlBuilder->buildForRequest($request); + } + + /** + * Checks data to be valid by passed specification + * + * @param array $data + * @param array $specs + * + * @throws WebToPay_Exception_Validation + */ + protected function validateRequest($data, $specs) { + foreach ($specs as $spec) { + list($name, $maxlen, $required, $regexp) = $spec; + if ($required && !isset($data[$name])) { + throw new WebToPay_Exception_Validation( + sprintf("'%s' is required but missing.", $name), + WebToPayException::E_MISSING, + $name + ); + } + + if (!empty($data[$name])) { + if ($maxlen && strlen($data[$name]) > $maxlen) { + throw new WebToPay_Exception_Validation(sprintf( + "'%s' value is too long (%d), %d characters allowed.", + $name, + strlen($data[$name]), + $maxlen + ), WebToPayException::E_MAXLEN, $name); + } + + if ($regexp !== '' && !preg_match($regexp, $data[$name])) { + throw new WebToPay_Exception_Validation( + sprintf("'%s' value '%s' is invalid.", $name, $data[$name]), + WebToPayException::E_REGEXP, + $name + ); + } + } + } + } + + /** + * Makes request data array from parameters, also generates signature + * + * @param array $request + * + * @return array + */ + protected function createRequest(array $request) { + $data = $this->util->encodeSafeUrlBase64(http_build_query($request, null, '&')); + return array( + 'data' => $data, + 'sign' => md5($data . $this->projectPassword), + ); + } + + /** + * Returns specification of fields for request. + * + * Array structure: + * name – request item name + * maxlen – max allowed value for item + * required – is this item is required + * regexp – regexp to test item value + * + * @return array + */ + protected static function getRequestSpec() { + return array( + array('orderid', 40, true, ''), + array('accepturl', 255, true, ''), + array('cancelurl', 255, true, ''), + array('callbackurl', 255, true, ''), + array('lang', 3, false, '/^[a-z]{3}$/i'), + array('amount', 11, false, '/^\d+$/'), + array('currency', 3, false, '/^[a-z]{3}$/i'), + array('payment', 20, false, ''), + array('country', 2, false, '/^[a-z_]{2}$/i'), + array('paytext', 255, false, ''), + array('p_firstname', 255, false, ''), + array('p_lastname', 255, false, ''), + array('p_email', 255, false, ''), + array('p_street', 255, false, ''), + array('p_city', 255, false, ''), + array('p_state', 20, false, ''), + array('p_zip', 20, false, ''), + array('p_countrycode', 2, false, '/^[a-z]{2}$/i'), + array('test', 1, false, '/^[01]$/'), + array('time_limit', 19, false, '/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/'), + ); + } +} \ No newline at end of file diff --git a/Paysera/Paysera/Model/Config/Source/Order/Status/Pendingpayment.php b/Paysera/Paysera/Model/Config/Source/Order/Status/Pendingpayment.php new file mode 100755 index 0000000..13a9403 --- /dev/null +++ b/Paysera/Paysera/Model/Config/Source/Order/Status/Pendingpayment.php @@ -0,0 +1,20 @@ + + + + +
+ + + + + Magento\Config\Model\Config\Source\Yesno + + + + + + + Magento\Config\Model\Config\Backend\Encrypted + + + + Magento\Config\Model\Config\Backend\Encrypted + + + + Magento\Config\Model\Config\Source\Yesno + + +
+
+
+ diff --git a/Paysera/Paysera/etc/config.xml b/Paysera/Paysera/etc/config.xml new file mode 100755 index 0000000..1086e7a --- /dev/null +++ b/Paysera/Paysera/etc/config.xml @@ -0,0 +1,25 @@ + + + + + + + 1 + Paysera\Paysera\Model\Paysera + Paysera + pending_payment + + + 1 + Instruction. + true + offline + + + + diff --git a/Paysera/Paysera/etc/frontend/routes.xml b/Paysera/Paysera/etc/frontend/routes.xml new file mode 100755 index 0000000..7fb4b62 --- /dev/null +++ b/Paysera/Paysera/etc/frontend/routes.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/Paysera/Paysera/etc/module.xml b/Paysera/Paysera/etc/module.xml new file mode 100755 index 0000000..97c04a8 --- /dev/null +++ b/Paysera/Paysera/etc/module.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/Paysera/Paysera/etc/payment.xml b/Paysera/Paysera/etc/payment.xml new file mode 100755 index 0000000..e3e3164 --- /dev/null +++ b/Paysera/Paysera/etc/payment.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + 1 + + + diff --git a/Paysera/Paysera/registration.php b/Paysera/Paysera/registration.php new file mode 100755 index 0000000..1778bc1 --- /dev/null +++ b/Paysera/Paysera/registration.php @@ -0,0 +1,7 @@ + + + + + + + + + + + + + + + + + + + + + + Paysera_Paysera/js/view/payment/paysera + + + + true + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Paysera/Paysera/view/frontend/web/js/view/payment/method-renderer/paysera-method.js b/Paysera/Paysera/view/frontend/web/js/view/payment/method-renderer/paysera-method.js new file mode 100755 index 0000000..8339b3d --- /dev/null +++ b/Paysera/Paysera/view/frontend/web/js/view/payment/method-renderer/paysera-method.js @@ -0,0 +1,75 @@ +/*browser:true*/ +/*global define*/ +define( + [ + 'jquery', + 'Magento_Checkout/js/view/payment/default', + 'Magento_Checkout/js/action/place-order', + 'Magento_Checkout/js/action/select-payment-method', + 'Magento_Customer/js/model/customer', + 'Magento_Checkout/js/checkout-data', + 'Magento_Checkout/js/model/payment/additional-validators', + 'mage/url', + ], + function ( + $, + Component, + placeOrderAction, + selectPaymentMethodAction, + customer, + checkoutData, + additionalValidators, + url) { + 'use strict'; + + return Component.extend({ + defaults: { + template: 'Paysera_Paysera/paysera' + }, + + placeOrder: function (data, event) { + if (event) { + event.preventDefault(); + } + var self = this, + placeOrder, + emailValidationResult = customer.isLoggedIn(), + loginFormSelector = 'form[data-role=email-with-possible-login]'; + if (!customer.isLoggedIn()) { + $(loginFormSelector).validation(); + emailValidationResult = Boolean($(loginFormSelector + ' input[name=username]').valid()); + } + if (emailValidationResult && this.validate() && additionalValidators.validate()) { + this.isPlaceOrderActionAllowed(false); + placeOrder = placeOrderAction(this.getData(), false, this.messageContainer); + + $.when(placeOrder).fail(function () { + self.isPlaceOrderActionAllowed(true); + }).done(this.afterPlaceOrder.bind(this)); + return true; + } + return false; + }, + + selectPaymentMethod: function() { + selectPaymentMethodAction(this.getData()); + checkoutData.setSelectedPaymentMethod(this.item.method); + return true; + }, + + afterPlaceOrder: function () { + var xmlhttp = new XMLHttpRequest(); + var url = "http://"+window.location.hostname+"/paysera"; + + xmlhttp.onreadystatechange = function() { + if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { + var response = JSON.parse(xmlhttp.responseText); + window.location.href = response['url']; + } + }; + xmlhttp.open("GET", url, true); + xmlhttp.send(); + } + }); + } +); \ No newline at end of file diff --git a/Paysera/Paysera/view/frontend/web/js/view/payment/paysera.js b/Paysera/Paysera/view/frontend/web/js/view/payment/paysera.js new file mode 100755 index 0000000..2089793 --- /dev/null +++ b/Paysera/Paysera/view/frontend/web/js/view/payment/paysera.js @@ -0,0 +1,26 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*browser:true*/ +/*global define*/ +define( + [ + 'uiComponent', + 'Magento_Checkout/js/model/payment/renderer-list' + ], + function ( + Component, + rendererList + ) { + 'use strict'; + rendererList.push( + { + type: 'paysera', + component: 'Paysera_Paysera/js/view/payment/method-renderer/paysera-method' + } + ); + /** Add view logic here if needed */ + return Component.extend({}); + } +); \ No newline at end of file diff --git a/Paysera/Paysera/view/frontend/web/template/paysera.html b/Paysera/Paysera/view/frontend/web/template/paysera.html new file mode 100755 index 0000000..7814be8 --- /dev/null +++ b/Paysera/Paysera/view/frontend/web/template/paysera.html @@ -0,0 +1,43 @@ + +
+
+ + +
+
+ + + +
+ +
+
+ + + +
+
+
+ +
+
+
+
diff --git a/README.md b/README.md new file mode 100755 index 0000000..a0dcf2e --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +Paysera payments module for Magento 2.0 + +Installation + +1. BACKUP ALL FILES [optional]. +2. Copy all archive files to your root /app/code directory. +3. In app/etc/config.php file, add next line: 'Paysera_Paysera' => 1, +4. Turn off all cache. +5. Admin menu: Stores -> Configuration -> Sales -> Payment Methods -> Paysera (write your Paysera.com project data). + +Contacts + +If any problems occur please feel free to seek help via support@paysera.com \ No newline at end of file diff --git a/README.txt b/README.txt new file mode 100755 index 0000000..f291176 --- /dev/null +++ b/README.txt @@ -0,0 +1,11 @@ +Installation + +1. BACKUP ALL FILES [optional]. +2. Copy all archive files to your root /app/code directory. +3. In app/etc/config.php file, add next line: 'Paysera_Paysera' => 1, +4. Turn off all cache. +5. Admin menu: Stores -> Configuration -> Sales -> Payment Methods -> Paysera (write your Paysera.com project data). + +Contacts + +If any problems occur please feel free to seek help via support@paysera.com \ No newline at end of file