From 696314d58c76c9f8bf85fe355137b6f500d0c679 Mon Sep 17 00:00:00 2001 From: heitor dolinski Date: Mon, 30 Oct 2017 12:34:43 +0100 Subject: [PATCH] Push to GitHub --- .version | 1 + LICENSE-2.0.txt | 202 + modules/payxpert/config.xml | 13 + modules/payxpert/controllers/front/index.php | 36 + .../payxpert/controllers/front/payment.php | 101 + .../payxpert/controllers/front/redirect.php | 67 + .../payxpert/controllers/front/validation.php | 131 + modules/payxpert/controllers/index.php | 35 + modules/payxpert/css/index.php | 35 + modules/payxpert/css/payxpert.css | 17 + modules/payxpert/en.php | 4 + modules/payxpert/fr.php | 116 + modules/payxpert/images/baian.png | Bin 0 -> 2116 bytes modules/payxpert/images/fullpass.png | Bin 0 -> 4946 bytes modules/payxpert/images/index.php | 35 + modules/payxpert/images/logo-baian.gif | Bin 0 -> 80 bytes modules/payxpert/images/logo-baian.png | Bin 0 -> 784 bytes modules/payxpert/images/logo-fullpass.gif | Bin 0 -> 397 bytes modules/payxpert/images/logo-fullpass.png | Bin 0 -> 1236 bytes modules/payxpert/images/logo-payxpert.gif | Bin 0 -> 97 bytes modules/payxpert/images/logo-payxpert.png | Bin 0 -> 2019 bytes modules/payxpert/images/logo-payzone.gif | Bin 0 -> 1076 bytes modules/payxpert/images/logo-payzone.png | Bin 0 -> 1066 bytes .../images/payment-types/creditcard.png | Bin 0 -> 4873 bytes .../images/payment-types/creditcard_icon.png | Bin 0 -> 847 bytes .../payxpert/images/payment-types/ideal.png | Bin 0 -> 5315 bytes .../images/payment-types/przelewy24.png | Bin 0 -> 4367 bytes .../payxpert/images/payment-types/sofort.png | Bin 0 -> 4711 bytes modules/payxpert/images/payxpert.png | Bin 0 -> 18177 bytes modules/payxpert/images/payzone.png | Bin 0 -> 7476 bytes modules/payxpert/index.php | 35 + modules/payxpert/lib/Connect2PayClient.php | 3454 +++++++++++++++++ modules/payxpert/logo.gif | Bin 0 -> 591 bytes modules/payxpert/logo.png | Bin 0 -> 2472 bytes modules/payxpert/payment.php | 37 + modules/payxpert/payxpert.php | 976 +++++ modules/payxpert/redirect.php | 39 + modules/payxpert/validation.php | 107 + modules/payxpert/views/index.php | 36 + .../payxpert/views/templates/admin/config.tpl | 78 + .../payxpert/views/templates/admin/index.php | 35 + .../payxpert/views/templates/admin/infos.tpl | 26 + .../payxpert/views/templates/front/index.php | 36 + .../views/templates/front/payment_error.tpl | 53 + .../views/templates/front/payment_error17.tpl | 47 + .../templates/front/payment_execution.tpl | 78 + .../front/payment_execution_bank_transfer.tpl | 68 + .../front/payment_execution_credit_card.tpl | 68 + .../payment_infos_bank_transfer_ideal.tpl | 3 + ...payment_infos_bank_transfer_przelewy24.tpl | 3 + .../payment_infos_bank_transfer_sofort.tpl | 3 + .../front/payment_infos_credit_card.tpl | 3 + .../payxpert/views/templates/hook/index.php | 36 + .../templates/hook/orderconfirmation.tpl | 37 + .../payxpert/views/templates/hook/payment.tpl | 36 + modules/payxpert/views/templates/index.php | 36 + readme.txt | 46 + 57 files changed, 6169 insertions(+) create mode 100644 .version create mode 100644 LICENSE-2.0.txt create mode 100644 modules/payxpert/config.xml create mode 100644 modules/payxpert/controllers/front/index.php create mode 100644 modules/payxpert/controllers/front/payment.php create mode 100644 modules/payxpert/controllers/front/redirect.php create mode 100644 modules/payxpert/controllers/front/validation.php create mode 100644 modules/payxpert/controllers/index.php create mode 100644 modules/payxpert/css/index.php create mode 100644 modules/payxpert/css/payxpert.css create mode 100644 modules/payxpert/en.php create mode 100644 modules/payxpert/fr.php create mode 100644 modules/payxpert/images/baian.png create mode 100644 modules/payxpert/images/fullpass.png create mode 100644 modules/payxpert/images/index.php create mode 100644 modules/payxpert/images/logo-baian.gif create mode 100644 modules/payxpert/images/logo-baian.png create mode 100644 modules/payxpert/images/logo-fullpass.gif create mode 100644 modules/payxpert/images/logo-fullpass.png create mode 100644 modules/payxpert/images/logo-payxpert.gif create mode 100644 modules/payxpert/images/logo-payxpert.png create mode 100644 modules/payxpert/images/logo-payzone.gif create mode 100644 modules/payxpert/images/logo-payzone.png create mode 100644 modules/payxpert/images/payment-types/creditcard.png create mode 100644 modules/payxpert/images/payment-types/creditcard_icon.png create mode 100644 modules/payxpert/images/payment-types/ideal.png create mode 100644 modules/payxpert/images/payment-types/przelewy24.png create mode 100644 modules/payxpert/images/payment-types/sofort.png create mode 100644 modules/payxpert/images/payxpert.png create mode 100644 modules/payxpert/images/payzone.png create mode 100644 modules/payxpert/index.php create mode 100644 modules/payxpert/lib/Connect2PayClient.php create mode 100644 modules/payxpert/logo.gif create mode 100644 modules/payxpert/logo.png create mode 100644 modules/payxpert/payment.php create mode 100644 modules/payxpert/payxpert.php create mode 100644 modules/payxpert/redirect.php create mode 100644 modules/payxpert/validation.php create mode 100644 modules/payxpert/views/index.php create mode 100644 modules/payxpert/views/templates/admin/config.tpl create mode 100644 modules/payxpert/views/templates/admin/index.php create mode 100644 modules/payxpert/views/templates/admin/infos.tpl create mode 100644 modules/payxpert/views/templates/front/index.php create mode 100644 modules/payxpert/views/templates/front/payment_error.tpl create mode 100644 modules/payxpert/views/templates/front/payment_error17.tpl create mode 100644 modules/payxpert/views/templates/front/payment_execution.tpl create mode 100644 modules/payxpert/views/templates/front/payment_execution_bank_transfer.tpl create mode 100644 modules/payxpert/views/templates/front/payment_execution_credit_card.tpl create mode 100644 modules/payxpert/views/templates/front/payment_infos_bank_transfer_ideal.tpl create mode 100644 modules/payxpert/views/templates/front/payment_infos_bank_transfer_przelewy24.tpl create mode 100644 modules/payxpert/views/templates/front/payment_infos_bank_transfer_sofort.tpl create mode 100644 modules/payxpert/views/templates/front/payment_infos_credit_card.tpl create mode 100644 modules/payxpert/views/templates/hook/index.php create mode 100644 modules/payxpert/views/templates/hook/orderconfirmation.tpl create mode 100644 modules/payxpert/views/templates/hook/payment.tpl create mode 100644 modules/payxpert/views/templates/index.php create mode 100644 readme.txt diff --git a/.version b/.version new file mode 100644 index 0000000..238d6e8 --- /dev/null +++ b/.version @@ -0,0 +1 @@ +1.0.7 diff --git a/LICENSE-2.0.txt b/LICENSE-2.0.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/LICENSE-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/modules/payxpert/config.xml b/modules/payxpert/config.xml new file mode 100644 index 0000000..f11969b --- /dev/null +++ b/modules/payxpert/config.xml @@ -0,0 +1,13 @@ + + + payxpert + + + + + + + 1 + 1 + + \ No newline at end of file diff --git a/modules/payxpert/controllers/front/index.php b/modules/payxpert/controllers/front/index.php new file mode 100644 index 0000000..54b3024 --- /dev/null +++ b/modules/payxpert/controllers/front/index.php @@ -0,0 +1,36 @@ + +* @copyright 2007-2013 PrestaShop SA + +* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) +* International Registered Trademark & Property of PrestaShop SA +*/ + +header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); +header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); + +header('Cache-Control: no-store, no-cache, must-revalidate'); +header('Cache-Control: post-check=0, pre-check=0', false); +header('Pragma: no-cache'); + +header('Location: ../../../../'); +exit; \ No newline at end of file diff --git a/modules/payxpert/controllers/front/payment.php b/modules/payxpert/controllers/front/payment.php new file mode 100644 index 0000000..e2ab92e --- /dev/null +++ b/modules/payxpert/controllers/front/payment.php @@ -0,0 +1,101 @@ +context->cart; + + // Default value for Prestashop < 1.7 + $template = 'payment_execution.tpl'; + + $params = array(); + + // These should be filled only with Prestashop >= 1.7 + $paymentType = Tools::getValue('payment_type', null); + $paymentProvider = Tools::getValue('payment_provider', null); + + if (version_compare(_PS_VERSION_, '1.7', '>=')) { + if ($paymentType !== null && PayXpert\Connect2Pay\C2PValidate::isPayment($paymentType)) { + $params['payment_type'] = $paymentType; + + if ($paymentProvider !== null && PayXpert\Connect2Pay\C2PValidate::isProvider($paymentProvider)) { + $params['payment_provider'] = $paymentProvider; + } + + switch ($paymentType) { + case PayXpert\Connect2Pay\Connect2PayClient::_PAYMENT_TYPE_BANKTRANSFER: + $template = 'module:' . $this->module->name . '/views/templates/front/payment_execution_bank_transfer.tpl'; + + if (isset($params['payment_provider'])) { + switch ($params['payment_provider']) { + case PayXpert\Connect2Pay\Connect2PayClient::_PAYMENT_PROVIDER_SOFORT: + $paymentLogo = 'sofort'; + break; + case PayXpert\Connect2Pay\Connect2PayClient::_PAYMENT_PROVIDER_PRZELEWY24: + $paymentLogo = 'przelewy24'; + break; + case PayXpert\Connect2Pay\Connect2PayClient::_PAYMENT_PROVIDER_IDEALKP: + $paymentLogo = 'ideal'; + break; + } + } + break; + default: + // Default is Credit Card + $template = 'module:' . $this->module->name . '/views/templates/front/payment_execution_credit_card.tpl'; + $paymentLogo = 'creditcard'; + break; + } + + $this->context->smarty->assign("payment_logo", $paymentLogo); + } + } + + $this->context->smarty->assign( + array(/* */ + 'nbProducts' => $cart->nbProducts(), /* */ + 'cust_currency' => intval($cart->id_currency), /* */ + 'total' => $cart->getOrderTotal(true, Cart::BOTH), /* */ + 'isoCode' => $this->context->language->iso_code, /* */ + 'this_path' => $this->module->getPathUri(), /* */ + 'this_link' => $this->module->getModuleLinkCompat('payxpert', 'redirect', $params), /* */ + 'this_link_back' => $this->module->getPageLinkCompat('order', true, NULL, "step=3") /* */ + ) /* */ + ); + + $this->setTemplate($template); + } +} \ No newline at end of file diff --git a/modules/payxpert/controllers/front/redirect.php b/modules/payxpert/controllers/front/redirect.php new file mode 100644 index 0000000..acf0e7f --- /dev/null +++ b/modules/payxpert/controllers/front/redirect.php @@ -0,0 +1,67 @@ +context->cart)) { + $this->context->cart = new Cart(); + } + + $cart = $this->context->cart; + + // These should be filled only with Prestashop >= 1.7 + $paymentType = Tools::getValue('payment_type', null); + $paymentProvider = Tools::getValue('payment_provider', null); + + $errorMessage = $this->module->redirect($cart, $paymentType, $paymentProvider); + + $this->display_column_left = false; + parent::initContent(); + + $this->context->smarty->assign( + array(/* */ + 'errorMessage' => $errorMessage, /* */ + 'this_path' => $this->module->getPathUri(), /* */ + 'this_path_ssl' => Configuration::get('PS_SSL_ENABLED') ? 'https' : 'http' . '://' . $_SERVER['HTTP_HOST'] . __PS_BASE_URI__ . + 'modules/payxpert/', /* */ + 'this_link_back' => $this->module->getPageLinkCompat('order', true, NULL, "step=3") /* */ + ) /* */ + ); + + if (version_compare(_PS_VERSION_, '1.7', '>=')) { + $this->setTemplate('module:' . $this->module->name . '/views/templates/front/payment_error17.tpl'); + } else { + $this->setTemplate('payment_error.tpl'); + } + } +} diff --git a/modules/payxpert/controllers/front/validation.php b/modules/payxpert/controllers/front/validation.php new file mode 100644 index 0000000..956f67c --- /dev/null +++ b/modules/payxpert/controllers/front/validation.php @@ -0,0 +1,131 @@ +display_header = false; + $this->display_footer = false; + } + + /** + * + * @see FrontController::initContent() + */ + public function initContent() { + // $cart = $this->context->cart; + require_once dirname(__FILE__) . '/../../lib/Connect2PayClient.php'; + + // init api + $c2pClient = new PayXpert\Connect2Pay\Connect2PayClient($this->module->getPayXpertUrl(), Configuration::get('PAYXPERT_ORIGINATOR'), + html_entity_decode(Configuration::get('PAYXPERT_PASSWORD'))); + + if ($c2pClient->handleCallbackStatus()) { + $responseStatus = "KO"; + $responseMessage = "Callback validation failed"; + + $status = $c2pClient->getStatus(); + + // get the Error code + $errorCode = $status->getErrorCode(); + $errorMessage = $status->getErrorMessage(); + + $transaction = $status->getLastTransactionAttempt(); + + if ($transaction !== null) { + $transactionId = $transaction->getTransactionID(); + + $orderId = $status->getOrderID(); + $amount = number_format($transaction->getAmount() / 100, 2, '.', ''); + $callbackData = $status->getCtrlCustomData(); + + $severity = 1; + + $message = "PayXpert payment module: "; + $message .= "Received a new transaction status callback from " . $_SERVER["REMOTE_ADDR"] . ". "; + $message .= "Error code: " . $errorCode . " "; + $message .= "Error message: " . $errorMessage . " "; + $message .= "Transaction ID: " . $transactionId . " "; + $message .= "Order ID: " . $orderId . " "; + + $customer = null; + if (version_compare(_PS_VERSION_, '1.5', '>=')) { + Context::getContext()->cart = new Cart((int) $orderId); + $customer = new Customer((int) (Context::getContext()->cart->id_customer)); + } + + // For Prestashop >= 1.7, multi payment types is possible + switch ($transaction->getPaymentType()) { + case PayXpert\Connect2Pay\Connect2PayClient::_PAYMENT_TYPE_BANKTRANSFER: + $paymentMean = $this->module->l('Bank Transfer'); + break; + default: + $paymentMean = $this->module->l('Credit Card'); + break; + } + $paymentMean .= ' (PayXpert)'; + + if (!$customer) { + $message .= "Customer not found for order " . $orderId; + error_log($message); + $severity = 3; + } else { + if (!PayXpert::checkCallbackAuthenticityData($callbackData, Context::getContext()->cart->id, $customer->secure_key)) { + $message .= "Invalid callback received for order " . $orderId . ". Validation failed."; + error_log($message); + $severity = 3; + } else { + switch ($errorCode) { + case "000": + // Payment OK + $this->module->validateOrder((int) $orderId, Configuration::get('PS_OS_PAYMENT'), $amount, $paymentMean, $errorMessage, + array(), NULL, false); + break; + default: + $this->module->validateOrder((int) $orderId, Configuration::get('PS_OS_ERROR'), $amount, $paymentMean, $errorMessage, + array(), NULL, false); + $severity = 2; + break; + } + $responseStatus = "OK"; + $responseMessage = "Payment status recorded"; + } + } + } + + $this->module->addLog($message, $severity, $errorCode); + + // Send a response to mark this transaction as notified + $response = array("status" => $responseStatus, "message" => $responseMessage); + header("Content-type: application/json"); + echo json_encode($response); + exit(); + } else { + $this->module->addLog("PayXpert payment module:\n Callback received an incorrect status from " . $_SERVER["REMOTE_ADDR"], 2); + } + } +} diff --git a/modules/payxpert/controllers/index.php b/modules/payxpert/controllers/index.php new file mode 100644 index 0000000..3f4b16e --- /dev/null +++ b/modules/payxpert/controllers/index.php @@ -0,0 +1,35 @@ + +* @copyright 2007-2013 PrestaShop SA +* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) +* International Registered Trademark & Property of PrestaShop SA +*/ + +header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); +header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); + +header('Cache-Control: no-store, no-cache, must-revalidate'); +header('Cache-Control: post-check=0, pre-check=0', false); +header('Pragma: no-cache'); + +header('Location: ../../../../'); +exit; \ No newline at end of file diff --git a/modules/payxpert/css/index.php b/modules/payxpert/css/index.php new file mode 100644 index 0000000..a230e5a --- /dev/null +++ b/modules/payxpert/css/index.php @@ -0,0 +1,35 @@ + +* @copyright 2007-2013 PrestaShop SA +* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) +* International Registered Trademark & Property of PrestaShop SA +*/ + +header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); +header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); + +header("Cache-Control: no-store, no-cache, must-revalidate"); +header("Cache-Control: post-check=0, pre-check=0", false); +header("Pragma: no-cache"); + +header("Location: ../"); +exit; \ No newline at end of file diff --git a/modules/payxpert/css/payxpert.css b/modules/payxpert/css/payxpert.css new file mode 100644 index 0000000..aa3867e --- /dev/null +++ b/modules/payxpert/css/payxpert.css @@ -0,0 +1,17 @@ +p.payment_module a.creditcard::after{ + display: block; + content: "\f054"; + position: absolute; + right: 15px; + margin-top: -11px; + top: 50%; + font-family: "FontAwesome"; + font-size: 25px; + height: 22px; + width: 14px; + color: #777; +} + +p.payment_module a.creditcard { + background: url(../images/payment-types/creditcard_icon.png) 15px 12px no-repeat #fbfbfb; +} \ No newline at end of file diff --git a/modules/payxpert/en.php b/modules/payxpert/en.php new file mode 100644 index 0000000..601358d --- /dev/null +++ b/modules/payxpert/en.php @@ -0,0 +1,4 @@ +payxpert_cbe0a99684b145e77f3e14174ac212e3'] = 'Voulez-vous vraiment effacer ces données ?'; +$_MODULE['<{payxpert}prestashop>payxpert_a02758d758e8bec77a33d7f392eb3f8a'] = 'Aucune devise n\'a été configurée pour ce module.'; +$_MODULE['<{payxpert}prestashop>payxpert_a91fb0f9c94dc572c0db5aac09d4d443'] = 'Installation du module PayXpert : l\'installation a échoué'; +$_MODULE['<{payxpert}prestashop>payxpert_d79c0cec2cf84da7893298a7043bf275'] = 'Installation du module PayXpert : l\'installation des hooks a échoué'; +$_MODULE['<{payxpert}prestashop>payxpert_c6276fca84020c9022b21c27884ef91d'] = 'Installation du module PayXpert : la configuration a échoué'; +$_MODULE['<{payxpert}prestashop>payxpert_782a0d30f7df22256fc7c7d62aa83ebc'] = 'Installation du module PayXpert : l\'installation est réussie'; +$_MODULE['<{payxpert}prestashop>payxpert_e77bb171c7ae55bba8b2ed869fadfb19'] = 'Payer par carte bancaire'; +$_MODULE['<{payxpert}prestashop>payxpert_a282d97ef76eaba7b74335c441c6e9e4'] = 'Payer par virement bancaire via Sofort'; +$_MODULE['<{payxpert}prestashop>payxpert_3876948a17b228eb6664b7c1bf3fc169'] = 'Payer par virement bancaire via Przelewy24'; +$_MODULE['<{payxpert}prestashop>payxpert_5fd8f493f6299e6934e2342514fdbb14'] = 'Payer par virement bancaire via iDeal'; +$_MODULE['<{payxpert}prestashop>payxpert_abbbd19bce9246d4a53a252efe4a8ef8'] = 'Facture:'; +$_MODULE['<{payxpert}prestashop>payxpert_f4f70727dc34561dfde1a3c529b6205c'] = 'Paramètres'; +$_MODULE['<{payxpert}prestashop>payxpert_2ea3b0f6afbc5d22bca6c482c0bf54ca'] = 'Identifiant initiateur'; +$_MODULE['<{payxpert}prestashop>payxpert_1e0e47cb9fb5d70cfdee039faa4df351'] = 'L\'identifiant de votre initiateur'; +$_MODULE['<{payxpert}prestashop>payxpert_bd5d0eb5e80dabb222588e51b128a952'] = 'Mot de passe initiateur'; +$_MODULE['<{payxpert}prestashop>payxpert_b33897812550f490e39369ab16b494fe'] = 'Le mot de passe de votre initiateur (laissez vide pour conserver l\'actuel)'; +$_MODULE['<{payxpert}prestashop>payxpert_f234bf4aa382bcdf69c1f46dd045f280'] = 'Laissez vide pour conserver l\'actuel)'; +$_MODULE['<{payxpert}prestashop>payxpert_f70e151f4edf5e2dd4bb00a69a2e8aa7'] = 'Adresse de la page de paiement'; +$_MODULE['<{payxpert}prestashop>payxpert_2ac8cc53c7de4e6b529440632ab049d2'] = 'Laissez ce champ vide sauf si on vous a fourni une URL'; +$_MODULE['<{payxpert}prestashop>payxpert_6f974bbda9064a9c0836370dbf5a6076'] = 'Notifications marchand'; +$_MODULE['<{payxpert}prestashop>payxpert_b3151328e1f2e8eed187ecee1d0b078a'] = 'Envoyer ou non une notification par email au marchand pour chaque paiement'; +$_MODULE['<{payxpert}prestashop>payxpert_00d23a76e43b46dae9ec7aa9dcbebb32'] = 'Activées'; +$_MODULE['<{payxpert}prestashop>payxpert_b9f5c797ebbf55adccdd8539a65a0241'] = 'De'; +$_MODULE['<{payxpert}prestashop>payxpert_6ae25f49f9b8ff8dd9d77931f13cd7ce'] = 'Destinataire des notifications marchand'; +$_MODULE['<{payxpert}prestashop>payxpert_712cfbc42564d7b5b0f29cf3114f1b39'] = 'Adresse email du destinataire des notifications marchand'; +$_MODULE['<{payxpert}prestashop>payxpert_c200e98fc7b00b24a16affd294c5a856'] = 'Langue des notifications marchand'; +$_MODULE['<{payxpert}prestashop>payxpert_14f2d2487d30e069719bcbab2a9c9141'] = 'Langue à utiliser lors de l\'envoi des notifications marchand'; +$_MODULE['<{payxpert}prestashop>payxpert_78463a384a5aa4fad5fa73e2f506ecfc'] = 'Anglais'; +$_MODULE['<{payxpert}prestashop>payxpert_ad225f707802ba118c22987186dd38e8'] = 'Français'; +$_MODULE['<{payxpert}prestashop>payxpert_cb5480c32e71778852b08ae1e8712775'] = 'Espagnol'; +$_MODULE['<{payxpert}prestashop>payxpert_4be8e06d27bca7e1828f2fa9a49ca985'] = 'Italien'; +$_MODULE['<{payxpert}prestashop>payxpert_b17f3f4dcf653a5776792498a9b44d6a'] = 'Modifier la configuration'; +$_MODULE['<{payxpert}prestashop>payxpert_73a61696f100b3858511e212a3feea6b'] = 'Carte bancaire'; +$_MODULE['<{payxpert}prestashop>payxpert_104497b6ea18dff7f445ef5497d8a89a'] = 'Activer le moyen de paiement : carte bancaire'; +$_MODULE['<{payxpert}prestashop>payxpert_e66aa0693ced02e8d97af3c83d364757'] = 'Virement bancaire via Sofort'; +$_MODULE['<{payxpert}prestashop>payxpert_17613c57686611bcdb8f7dd684918f1a'] = 'Activer le moyen de paiement : virement bancaire via Sofort'; +$_MODULE['<{payxpert}prestashop>payxpert_1e25d70eb7c29b3396ff55c1bbd595b9'] = 'Virement bancaire via Przelewy24'; +$_MODULE['<{payxpert}prestashop>payxpert_820cdf51304d3b3dad0ac77a5c4c3a9a'] = 'Activer le moyen de paiement : virement bancaire via Przelewy24'; +$_MODULE['<{payxpert}prestashop>payxpert_133199f93d165a81bc21cdbcc42a1743'] = 'Virement bancaire via iDeal'; +$_MODULE['<{payxpert}prestashop>payxpert_4b554beb5ba2d91db0a6d06393a2dbee'] = 'Activer le moyen de paiement : virement bancaire via iDeal'; +$_MODULE['<{payxpert}prestashop>payxpert_a7ec39e91b86c1f5af031d85fc2eaba1'] = 'L\'identifiant de l\'initiateur est requis.'; +$_MODULE['<{payxpert}prestashop>payxpert_20aedd1e6de4dcf8d115b5a7424c58d7'] = 'Le mot de passe est requis.'; +$_MODULE['<{payxpert}prestashop>payxpert_02a2b395b673a990d4a164126510966f'] = 'L\'adresse du destinataire des notifications marchand est requise.'; +$_MODULE['<{payxpert}prestashop>payxpert_a6aab07cbf3e97724a9ea7fbda5e9d7a'] = 'L\'adresse email du destinataire des notifications marchand doit être une adresse email valide.'; +$_MODULE['<{payxpert}prestashop>payxpert_edec9b6255aa33c5dfa1ecb4cbf53634'] = 'La langue des notifications marchand n\'est pas valide.'; +$_MODULE['<{payxpert}prestashop>payxpert_20015706a8cbd457cbb6ea3e7d5dc9b3'] = 'Configuration mise à jour'; +$_MODULE['<{payxpert}prestashop>validation_73a61696f100b3858511e212a3feea6b'] = 'Carte bancaire'; +$_MODULE['<{payxpert}prestashop>validation_3726d2bc671a53445f9f57095bf9d76b'] = 'Virement bancaire'; +$_MODULE['<{payxpert}prestashop>config_f4f70727dc34561dfde1a3c529b6205c'] = 'Paramètres'; +$_MODULE['<{payxpert}prestashop>config_2ea3b0f6afbc5d22bca6c482c0bf54ca'] = 'Identifiant initiateur'; +$_MODULE['<{payxpert}prestashop>config_1e0e47cb9fb5d70cfdee039faa4df351'] = 'L\'identifiant de votre initiateur'; +$_MODULE['<{payxpert}prestashop>config_bd5d0eb5e80dabb222588e51b128a952'] = 'Mot de passe initiateur'; +$_MODULE['<{payxpert}prestashop>config_b33897812550f490e39369ab16b494fe'] = 'Le mot de passe de votre initiateur (laissez vide pour conserver l\'actuel)'; +$_MODULE['<{payxpert}prestashop>config_40b25dd0e73aec4884f398823590e65e'] = 'URL de la page de paiement'; +$_MODULE['<{payxpert}prestashop>config_f20ec5655452017530ce687f6fcea5cb'] = 'Laisser vide sauf si on vous a communiqué une adresse spécifique'; +$_MODULE['<{payxpert}prestashop>config_6f974bbda9064a9c0836370dbf5a6076'] = 'Notifications marchand'; +$_MODULE['<{payxpert}prestashop>config_b3151328e1f2e8eed187ecee1d0b078a'] = 'Envoyer ou non une notification par email au marchand pour chaque paiement'; +$_MODULE['<{payxpert}prestashop>config_6ae25f49f9b8ff8dd9d77931f13cd7ce'] = 'Destinataire des notifications marchand'; +$_MODULE['<{payxpert}prestashop>config_712cfbc42564d7b5b0f29cf3114f1b39'] = 'Adresse email du destinataire des notifications marchand'; +$_MODULE['<{payxpert}prestashop>config_c200e98fc7b00b24a16affd294c5a856'] = 'Langue des notifications marchand'; +$_MODULE['<{payxpert}prestashop>config_78463a384a5aa4fad5fa73e2f506ecfc'] = 'Anglais'; +$_MODULE['<{payxpert}prestashop>config_ad225f707802ba118c22987186dd38e8'] = 'Français'; +$_MODULE['<{payxpert}prestashop>config_cb5480c32e71778852b08ae1e8712775'] = 'Espagnol'; +$_MODULE['<{payxpert}prestashop>config_4be8e06d27bca7e1828f2fa9a49ca985'] = 'Italien'; +$_MODULE['<{payxpert}prestashop>config_14f2d2487d30e069719bcbab2a9c9141'] = 'Langue à utiliser lors de l\'envoi des notifications marchand'; +$_MODULE['<{payxpert}prestashop>config_b17f3f4dcf653a5776792498a9b44d6a'] = 'Modifier la configuration'; +$_MODULE['<{payxpert}prestashop>infos_aa2e442679e64b770ad11c1ac5d7d7d0'] = 'Ce module permet d\'accepter des paiements sécurisés.'; +$_MODULE['<{payxpert}prestashop>payment_error_5fdd505123089ad1f093d5467e6e0fa5'] = 'Paiement par carte bancaire'; +$_MODULE['<{payxpert}prestashop>payment_error_f1d3b424cd68795ecaa552883759aceb'] = 'Récapitulatif de commande'; +$_MODULE['<{payxpert}prestashop>payment_error_569fd05bdafa1712c4f6be5b153b8418'] = 'Autres moyens de paiement'; +$_MODULE['<{payxpert}prestashop>payment_execution_5fdd505123089ad1f093d5467e6e0fa5'] = 'Paiement par carte bancaire'; +$_MODULE['<{payxpert}prestashop>payment_execution_f1d3b424cd68795ecaa552883759aceb'] = 'Récapitulatif de commande'; +$_MODULE['<{payxpert}prestashop>payment_execution_879f6b8877752685a966564d072f498f'] = 'Votre panier est vide.'; +$_MODULE['<{payxpert}prestashop>payment_execution_73a61696f100b3858511e212a3feea6b'] = 'Carte bancaire'; +$_MODULE['<{payxpert}prestashop>payment_execution_38e5d5a82e049662d1d60d31ea2fd300'] = 'Vous avez choisi de régler par carte bancaire.'; +$_MODULE['<{payxpert}prestashop>payment_execution_c884ed19483d45970c5bf23a681e2dd2'] = 'Voici un bref récapitulatif de votre commande :'; +$_MODULE['<{payxpert}prestashop>payment_execution_e2867a925cba382f1436d1834bb52a1c'] = 'Le montant total de votre commande s\'élève à'; +$_MODULE['<{payxpert}prestashop>payment_execution_1f87346a16cf80c372065de3c54c86d9'] = 'TTC'; +$_MODULE['<{payxpert}prestashop>payment_execution_2c915fa837f3213915eea3e1dc6286ec'] = 'Vos informations de paiement vous serons demandées sur la prochaine page sécurisée'; +$_MODULE['<{payxpert}prestashop>payment_execution_93c1f9dffc8c38b2c108d449a9181d92'] = 'Merci de confirmer votre commande en cliquant sur \"Je confirme ma commande\"'; +$_MODULE['<{payxpert}prestashop>payment_execution_baa62374832554652160fe5a827b2741'] = 'Je confirme ma commande'; +$_MODULE['<{payxpert}prestashop>payment_execution_569fd05bdafa1712c4f6be5b153b8418'] = 'Autres moyens de paiement'; +$_MODULE['<{payxpert}prestashop>payment_execution_bank_transfer_fb077ecba55e5552916bde26d8b9e794'] = 'Confirmation de commande'; +$_MODULE['<{payxpert}prestashop>payment_execution_bank_transfer_879f6b8877752685a966564d072f498f'] = 'Votre panier est vide.'; +$_MODULE['<{payxpert}prestashop>payment_execution_bank_transfer_3726d2bc671a53445f9f57095bf9d76b'] = 'Virement bancaire'; +$_MODULE['<{payxpert}prestashop>payment_execution_bank_transfer_7932ecf622ec454c25bfbe87a6dca3a6'] = 'Vous avez choisi de payer par virement bancaire.'; +$_MODULE['<{payxpert}prestashop>payment_execution_bank_transfer_9afb6a88186a8c57ef9562b66e928135'] = 'Le montant total de votre commande est de %s.'; +$_MODULE['<{payxpert}prestashop>payment_execution_bank_transfer_5958921b7d034715d2f2ec04a3eaaf87'] = 'Vous serez en mesure de payer en fournissant les coordonnées de votre compte bancaire au moyen d\'un formulaire sécurisé sur les pages suivantes.'; +$_MODULE['<{payxpert}prestashop>payment_execution_bank_transfer_c624426fb64f742a7e113f3381f47b52'] = 'Veuillez confirmer votre commande en utilisant le bouton « Payer ma commande » ci dessous.'; +$_MODULE['<{payxpert}prestashop>payment_execution_bank_transfer_512bb802df28ada6f304c32398bb40d0'] = 'Payer ma commande'; +$_MODULE['<{payxpert}prestashop>payment_execution_bank_transfer_569fd05bdafa1712c4f6be5b153b8418'] = 'Autres moyens de paiement'; +$_MODULE['<{payxpert}prestashop>payment_execution_credit_card_fb077ecba55e5552916bde26d8b9e794'] = 'Récapitulatif de commande'; +$_MODULE['<{payxpert}prestashop>payment_execution_credit_card_879f6b8877752685a966564d072f498f'] = 'Votre panier est vide.'; +$_MODULE['<{payxpert}prestashop>payment_execution_credit_card_73a61696f100b3858511e212a3feea6b'] = 'Carte bancaire'; +$_MODULE['<{payxpert}prestashop>payment_execution_credit_card_38e5d5a82e049662d1d60d31ea2fd300'] = 'Vous avez choisi de régler par carte bancaire.'; +$_MODULE['<{payxpert}prestashop>payment_execution_credit_card_9afb6a88186a8c57ef9562b66e928135'] = 'Le montant total de votre commande s\'élève à %s.'; +$_MODULE['<{payxpert}prestashop>payment_execution_credit_card_aea960762718b5dfebc2731749d2b963'] = 'Vous serez en mesure de payer en fournissant les informations de votre carte bancaire au moyen d\'un formulaire sécurisé sur les pages suivantes.'; +$_MODULE['<{payxpert}prestashop>payment_execution_credit_card_c624426fb64f742a7e113f3381f47b52'] = 'Veuillez confirmer votre commande en utilisant le bouton « Payer ma commande » ci dessous.'; +$_MODULE['<{payxpert}prestashop>payment_execution_credit_card_512bb802df28ada6f304c32398bb40d0'] = 'Payer ma commande'; +$_MODULE['<{payxpert}prestashop>payment_execution_credit_card_569fd05bdafa1712c4f6be5b153b8418'] = 'Autres moyens de paiement'; +$_MODULE['<{payxpert}prestashop>payment_infos_bank_transfer_ideal_c3e6e1fb2780181e710c3b5b8df98568'] = 'Régler votre commande en utilisant vos informations de compte bancaire avec le fournisseur iDeal'; +$_MODULE['<{payxpert}prestashop>payment_infos_bank_transfer_przelewy24_a5c4c63be0923c45042b9c6544272db9'] = 'Régler votre commande en utilisant vos informations de compte bancaire avec le fournisseur Przelewy24'; +$_MODULE['<{payxpert}prestashop>payment_infos_bank_transfer_sofort_64c4d630033101176b2c183d95d4b077'] = 'Régler votre commande en utilisant vos informations de compte bancaire avec le fournisseur Sofort'; +$_MODULE['<{payxpert}prestashop>payment_infos_credit_card_7358d61686326706aedac475364bdb81'] = 'Régler votre commande en utilisant vos informations de carte bancaire'; +$_MODULE['<{payxpert}prestashop>orderconfirmation_1167e46c7a94af11bd9bef3805ef4e73'] = 'Le paiement de votre commande a été effectué.'; +$_MODULE['<{payxpert}prestashop>orderconfirmation_9bfbb6e7dd3a9356d9338c53dd5809c9'] = 'Elle sera validée ou expédiée au plus vite.'; +$_MODULE['<{payxpert}prestashop>orderconfirmation_0db71da7150c27142eef9d22b843b4a9'] = 'Pour toute question ou information complémentaire merci de contacter notre'; +$_MODULE['<{payxpert}prestashop>orderconfirmation_64430ad2835be8ad60c59e7d44e4b0b1'] = 'support client'; +$_MODULE['<{payxpert}prestashop>orderconfirmation_8591f5ec4ceb388620dc7617565f73ad'] = 'Votre commande est encore en attente.'; +$_MODULE['<{payxpert}prestashop>orderconfirmation_0750d4a213576f483f679fa8200145eb'] = 'Votre commande sera expédiée dès réception de votre paiement.'; +$_MODULE['<{payxpert}prestashop>orderconfirmation_8de637e24570c1edb0357826a2ad5aea'] = 'Nous avons rencontré un problème avec votre commande. Merci de prendre contact avec notre'; +$_MODULE['<{payxpert}prestashop>payment_e77bb171c7ae55bba8b2ed869fadfb19'] = 'Paiement par carte bancaire'; diff --git a/modules/payxpert/images/baian.png b/modules/payxpert/images/baian.png new file mode 100644 index 0000000000000000000000000000000000000000..3c0a418b62eb7e567b784871585df81e237f1403 GIT binary patch literal 2116 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 literal 0 HcmV?d00001 diff --git a/modules/payxpert/images/index.php b/modules/payxpert/images/index.php new file mode 100644 index 0000000..3f6561f --- /dev/null +++ b/modules/payxpert/images/index.php @@ -0,0 +1,35 @@ + +* @copyright 2007-2013 PrestaShop SA +* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) +* International Registered Trademark & Property of PrestaShop SA +*/ + +header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); +header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); + +header("Cache-Control: no-store, no-cache, must-revalidate"); +header("Cache-Control: post-check=0, pre-check=0", false); +header("Pragma: no-cache"); + +header("Location: ../"); +exit; \ No newline at end of file diff --git a/modules/payxpert/images/logo-baian.gif b/modules/payxpert/images/logo-baian.gif new file mode 100644 index 0000000000000000000000000000000000000000..4db7f9890cd84151e1268feacb128372aa8e12dd GIT binary patch literal 80 zcmZ?wbhEHb6krfwXkcVu*mUau|Nn|VSs1w(7#VaJfB+=Jz@*;8U%C6`sd+VNQ5C7o ij+OgL?}+yfitX0-Z@j zK~z}7?UqkSR8bVhe|P@8`IktR8G)4~8ilxP6Rrx1$dy8nID~{aWfDkHDXlUsX(JU{ zF51{4D6lB8RahVzK}@2xYasvBj5aEhjx+Oai#Ibmj;5o|6xFx7_v5~EzIVQJ4;R)7 zdo_Oo(r9ceitf%`NjQKZ;V-N<6F1uP@QypkFL0okpzVp1@ox=y+^>OA04`jE=K2-G zi3CzBG~T<+?%ZW37=nb5=N41qV52B^CQSu2z-d+ zjmk3oFV8y{mue~a7q$yBYDX;3n)ww4qzwNB{1>o30pfQHkbjj0m9@(c3@Jk!$j3k* zUA^lCn=Os@&JrxP<3Rd?(fXMZdo~7R@w#|LadGgFk*>$CrQ7Ji^8vPG?MJG~t9c** z!>)bQoE%#GEEjCf>_VyoNi|)shs^E1*a}qEZsS;KHah(*peDEN1PIKy$NW?jf7Ap# zdewu;QiKqxYyUtX!1Pps_Hr>gpO985tE76&o8H7Z;b9n3$1~QBhIR+uJ*5&Yab&SD!t5_T0I17cXACcJ12j+qduC zyLbQo{f7@9zI^%eKaGLnPZmZlpjUJlfB@tt2DViW6ACBH9z2CqSso# z#X+mTy;@_m*E3tZ#wKB@*XBUpM`AZq7e7qMRMwhT`YU!pf)IRB>7munAsFPG<#CwmbJ_WccefI;Oc<(O^r0A-2J{{N!#6bX92COOBs44>G z%BngPmp4!%T#rm_nwU#HFJpYuw%!La+{Bt&XRI}l_GG;?prE!Lw$^K7w}?7N5{&BhK3oy z_FOKYiJ^-MI2J>JDa4(RI7*RNI>eQJSLV6j1h+AnuQs8~y@etCL03vQF@E-6aus?*fTf~h5 zW`>Y%GMxv3Io9VLA*B06Tnlg$usMV@BuVaxBuO3tj)jn}6>)7qBX9%}_k)P57jZ*G z++-1V{Lcy%_qB){C*t;sxVa`9FXDD)bY2p1ZLP*yGKLMjfT&;-91Gkzi z0fvdV;r69D5tqww$<7eccHpQ*G6iaZNg{3nPy?*CiF!AXgpe)OF%3 zQ0aK@_gf`D2ka~Hd?gk&=N|%X)(MBN#b%q>z0D~0kgATapf^TU_n1zns^$lsg1>1q zY^!E%9o_>cnU}Br))s1X!)v=lQEMMjtTNitPP5_S=nQBW9A&JwV`_(% zB*nypH=!lTbeLKMtuKTzFwj=n>|)D^s6b<6?2Ouuk~);Bj?yA6o{v81r1MAX zV`qS4X@EMwhlJ3?0-0iV=Yb7CXPVCo1vq9xflL9L01g37X@LH-%0D_VAwj0(#0?hc zaQUzo*fP->50<_a0`q`s;1;`4-N0kO7R5{kuSnI4BVLbE)ai0cSNO;BALJ0gV$;es zHaGqo;$7h0sF)|fyUBt)sF*sz`%AUITOW;-v(j(L=sW78KafB|g^JOJ@Y3GP3UX*3 zOwsT(kYkEF2Ru>rKs;5<8O1Dgpsm{9lMx$Q72W2jxHkm2_bKif2sJi@mz=AK?PXJV zQBHkwXvF>Bd&_Wc2fcR4#tAST*qXqdoF3fP!Q$rKs6LbA%2K6-R@B5=jF>~$ zmQ}MZx*DMm#rYHPn!R*d(I@2+9`%wzUSLJ~yOakTZWE>r7X#L`Hds?_^b!<*4fLdt z_&u--m+oQ2aTTW=%r=`sKs*$KV)_;Dd*D=k%iqyAjH!xf zVxEc{OQs-$VqOcxT)#2A>_3pX{^LR8v-KFh3nfnOxVd41f-Kssr7>TZnDLc|LxCJ|uX2Hvj}^B%=Giis=Uvx>JG zF%^pWK!DewV*a3*8DLHZxcfGg-P@Tpkhv^$AB`+_K~^Z;hf^5-H53&vy9+r5o5L4D{D$QHwbXJcH5{xsxjYAdf_r0HN86 zX;w_w2A(yF_jbfQq!=f_)T@}L!14OlmuA@~a|yD_KR9TygE?=8{apZ50L$!q0a*$< zBeTX}9)Sed9QiyT?*R5EX_`9rduQ1SWl-J=&NrQ)M=j0gy$jqFd((uCp~d zD}O;&FMN*1{ddtA@nxmoqKat)c5@+rD6m(E-)ebosfyeW?6KVUXh86>in3RzkA6SD zQb-^XG`D{Gsvs!%B;w7tRPJDaISk%Sig}mfb|?ie*ZGf~1K8hsGsjuHR>jmQ z#sL#3X6O2{uYV;EHJOm6$Za!KWhd}7@DQ*(sWo}Pp}$R;v=8KkL4W|q`LfvRBS_hN zuQv7*lZPPPX+RA4tZjL?_NNG_Rh%NBJNUN$gl>#nplxdwJg6$N!}=wb+Wkh*FV)6& zT~`}xk-RY1=E$uDAnO%VmC}+VrRwNW%nddEk6wPuy)C7jyZR0Xoau`BFqpVvej13G zrnqMnZ@!Q?(GXrTew~3N_tj#{U}R*XuEW-cmE{M30|9V)Rdma*K|W*IQ6b1AV4lK> zaW&UusV1|miH=l>yd)$#Gcc_{kP{$p+WQ88lQTJ-7e1+@Xt5J$Qrxud{`>9t>}zCboC{eA1R`R|Cfs^Fi=P@yR~L><;kmsquGaJRMROeNt510xue&ki5 ze_R2MS(8?S3rM!`i-)=Y4aIz_m)S4Y`8%>cwDfT70Jg|ZYz~*^M3Z7QxZMVs;WnrM z_*@}>FUVQT2<{xKa>kNEt^s}syfckuOt;m4t|XolpKOklc)%i({nODT0A2+rR}+&7 z;Lzr9san&`Dy=KDq&waEKHyNCDgC+dN9%_{%IoX}p5#0L&!^F(0>2F~cU1dF^J@0h z8KcvWCSAbVd;>TZka6J8jC@?KBqx}UkcW~f$Sw<_YnVXrCdsqNhDyJ^Z^DAKvvtn_ z_W>`EoDDb)JO%hbeWl<2Mk+JPC%Gd2o8XF&{{l5RyWDG%-md@v002ovPDHLkV1n+q Bx?=zU literal 0 HcmV?d00001 diff --git a/modules/payxpert/images/logo-payzone.gif b/modules/payxpert/images/logo-payzone.gif new file mode 100644 index 0000000000000000000000000000000000000000..09ce9cefc5c27e3b4fe0353c279c1c05c92d4831 GIT binary patch literal 1076 zcmZ?wbhEHb6krfwc)pY2m6Ft3WvN$cvadl%?zNiy8z4hn{+)*WXHEIl2mx1aV6D@|^^>0nI-k9hz%EE28&mB!raBCH>lyMkFyw9g zZKTYQzn&p~!%t(4cV;?F`5RxG8@w^se`9XISg?t?U?X$ECYFMYZ!C?Ni#9SBZDJ_i z!Cth1t!VQ*Ya_0rjUTMdxJoy_wX@(V-NIeEnW17gciCpHvTeL&TNo<$a+h!CDc{Oa zwTHKSD_{BMca9c(AjWon5V=F3d^1D!{=CHk`o_gxxN@6d)lPw$ z-D1_-KDpVvcXyPi+5W-HS*CW+2OrlD{%-Gr{67YH>$LAz>^*MSwf|F0s7cQOv);qz z{RixN51RKM{*;yUF)Q_RR`SQ}v=2E+A9K^)rXTT`ar}Q?TEvDM#TzbHY`Rpv^~&cN z)9Q9y{W51}i&`R(WLAHViFddn!${|>H(eO~q;dc2g zCNnJrdHC3w_yjZz7!Iqe}J_{hY@Z8}ZNHtC7SgjVkvTAqtcJOig%?~J>9i1oDC zl9+XAcNbmlnj&Gd?OuhX^E0s(z9mnNJS^cB;GPr2B*9SN9U>uT`)$Q1l_f57V`d4N zc7%%-5VNvW%Rq?}w;avn@@ZIpLu=8@GB z$?)Wm)C^h?F!2!UG|jLT9@~u$JGTj|Tcs@jpwc<{z25?%Gbaql@UW}3`RZ_O~9Zt}w2+;h%- zp7-N<-*aX5(Ld?)J!t)ZI9Sx;0*w-;E76E^cMG99`oQ#J7Sf-7 zXzQ`UZ)a`x)F;+XjM{qb^{ZcO zY$f0~gDC>Wf);3shLEZ(|GBWjx!DyQA4Yza%*TC5IC2{T4v{CGBKk}Z0P_-K;My|R zhR4zB)*3R_Vk|tDOmMiP1xJ_nOw4C^_3L3q=Q0}z6iej3=|^G>!Kq)(Ve^GG0<-B= zz8sq3m#GX9Exx)l7Ob%x?Ml$LJ&LZZkIkfc?eqvk(oi?(<N&RUtcp5dhjcXG0)vkH8P6a8cSF_XsGP%F;H5QiT=T$_j|uaN)#4Botgcn8*a z6kLxNAJ|E6_W=^yqX7JR^#*SZTx4W6g$gLtTUGGU`$#Af3|cvFJr}upnf&!E-19UR zq39ZpA8Mz!`vALJww1vrmw0F3A{VZw5Rt%M>nBhskon>>RIG8638DyV!M5(lDn-%t zcqN(O-JVYN>?kYfrz?x}etU`Er&A!HESRcxE0r4Zr$7W1k0a5BO*0_I#R?Qk9xo&l zoIG+L9To7OC+6waa@S^B@1hsn)fG!Zi;P*BCkzO+5bOUYe`G0rs^uv9GOZ({G#^ox?Hn zvy{#cVy(euv%W^NNfJ=Ny?%@BHz?OJzZmyu@}+=brkb>eaoszVCOx{oaJ6l=#PP z4FB-03xX~Px*+I+pbLU72)ZEXg5YXXzn^3orVv-dR#jmNqwf>~Y1ZkdmOyeat%VVa zP3t+E#f@xny6uMxH}1KhD)qu8q|6-D{r+i#i^{#fTYt!|DfPb#Ib(dkDVe>R4EF|% zb(?c`A1^Mc^agZJ1ORbvds?s9+s5{tHYT-2EQ%|xTH~Oe(NN(Bq zN7ic!v(o4fn#PXB5!nJ3H_|cYPwp8fo#X$aCfzIz4-o+b5Qvc$6F9V}`KS};D~ihN z6h`4TEG==w!0rI{ohs3^h8K35a$RbCc;MNKRTF>y!7FR`yBunZ>r4a?O&Qgz`Kwpf z?6+$QvwW0@G*vlruB;=>q3TjoW;iE)XuoM&VXfOj5fi>k;Ql7vx9l(ALRyz@>h--H zHU&WT@nTJB_*SgT=Cs#KL}hJY_LG0hyIdVslNMV_qT6n3+M&*8Y{)*}g0eC?m{Z!3 z9zn$2_|qNFEjutpWg^U=@a8w^_R+R;O%!|4+)Mym$nt6*StK?SYQ6gE&rV)TcFtd}F}Y9`)-ez;q8rkC ze6lNV-KjA}bunvaz2i_#UVBEh=;o8J?{YdCJO~$Z$)giP_hr?7-2#D>NQ#dN5qJ1( z8RrelD5RW`)z8X508M58djII=RK2@3hgl2?3i;9Y+y>bRn!j5(+4_|WCAGTAJ2E=VNK1&0vV|Pz>J#Hu9KF%*Jsf_!d2fM` zRzoOfX7vwSul(W~>r!(eMhr>}-KV9*aziw-WC|NGf9;ZY_SgB1Z=mNwiD&1L%MHfG zZJ$3gePHhfd%?M|cIcP@`JO2QOfCR8RpX^S)AyhAg%29*Ft~VdRz~>oRDPv( zsZB1!QqVieJ$6{K6+QxVL%gzPf8QUhT(jx)wTOA*wH=DmFzM7WsS2Z!1G+b8xWYE? zE9hVdemXNFENMd0pAL?ZHAeyH2H&*zf>q9EX7%rr)Zj#q=amCw)$No7SNL(|)3@5x z7EGGS#e@I8dD`NS&Rnc&@~WVucH{1RtDeuiu^)gD0~0I|P>cRDA_#^LOiYT83O~Mo zW?bckZ2;c*__)_+SV{l=qAAvar!O=}fe>=!!0wF#%Cy9fUcMu!x1hJtQMLo8OUM6g zeNkiUux8U~Ym6YJynE6B07LtB3kQirR9xY$_39l7flXz@(h@96t1Nui1z_3xhwK)w zHZCKjS7O5=>jp2r;<4KNvFXW8X1*!2_u2O!oR!tz7c`sud6SEq7k=mun&BBf-kE20 znX@Mjh>o%W7}z`B>LV1!_M9m0NC;GgjTn&FAkPXuKVt4WR#a6R2rsgfxN}09RYdok zC}9@YErcA`3<3bDJ)+-ze#V*i<`3=LO*BS<5nZYBeR=Rw=yC7Kl4H4L)^uRW&nJZL z2dBmavHNNbcq8(EZ|N+pR*^JITFacYesAI&G@mri4>W#^`8nnUsyP zyhtIKGO8CBvH=2#FAiR`%H)r38`?e2X&tifREcIW-O(;vT(skxzw*!>8HdhZ`OBtL zmh6v03bOBX>8bomt1qba>QB9~t7%SkwOuOp1P#++Q#-6`lo0D2*gH-%&V{V)*@wn8 zOCQS>ixecrI$c*&=1qGpT+3Vqb(0!%)h*fq;GNG;TlxRicCpl>H;y|xpm4Tec7|@Y zJn6)dy?Q3Pt-n-zf`P`SKF)0qX9V{>yD@F~(kh?P7_Y=Qr^BuSsPqKt zyg}x+zq{qkstqTlM0|`xN?BbObZCmrVnIUz^$kONe7Nmgeo;+0zY;>mH`OWW@f%hl zRTzE#b-^$1jq6AVy2m>Q^@%IIQrEQF$N7(@4{2J`D)(9gbs=OphTV6nR8?7Mg*DX{ z3TXkvMA@2566>;WSb7(L$CiH;t~&vUa%iXD`$_Yn*W-WOvHpM0gdy0xx8Rrej_gQ9 zP!t-~IJOBn|A%G`i*YrjzNFG?TBN|_V&uTYu$ff8F^!WF{-AkXYW$afyw~N>Htf!? ztPNPTV`f%AmqT+qn_gpv^sqYeFArVnU|Yb5Mh#9fOkwgy*Ncy|P)a8Q|a}`r|x+Dz9D_P2_e^PIt4;_D$d1>tbQ$0IG|Uo zlrr4Y7ckCVs%~@n^qX5zxp(XS0;+6iXtXE2#C-E1-S0aOD#O%=A6gw2E>w67>D6ixvP6z+`H+|z)QB?zlffxu7 z5}ZTRY`08y%$uWLKa!>NxaKVWVp(xWT>MyG*$rue*wy$_LKv_mu%6Q>^#>F)5VpAQ zQ)ncm_nBAp&0mP3QV_sc%k?TDU~)?ArezLyz4BYur)T3*Nf|%#f~-1n(j8Kd#29f(zF8T&?7M@&_rg;Dn`s%-iL{=QO$z+>I;1<(1gdieN2LRGkvQ|*{tWJlZYS<)ET@#TA zm{5lisf`)7!7-Py$ecaJ4O1qr0=3pRwI?(RuKQ3_Rf9z!0s@XXjHR@&;AD?HDm^4C zk5IyxPLl#IY9Dym`1)W(WGb+YC9+eCp58f+BC-flkh`xk^^?w$0_pb~yZ1*V0)WyR z>adpilqO&RN+g=Vq$gK;&Qo++r$C^8{-q4+UxiJ(u~ zZy|6AQb7!oL$+QjBtRfdmhS8{2sUgXO$Cu_$!|$j&78A=x7Vp7(j7m(4~oLi=J}St zNp@QcsR01Sl(fFig^!5bPsQcEAO;~o)C4tBB%rY&zo7WxP;4;0{KQgt@~+~0ZHV1{ z*?{@7WScDADQix*GFWUg1jfEYV2s7ZI_Av*pd3CPczd1W$8+ru+ylV>_B*615l==K5nFfz|Js$4%`?r!!lR^YP*~F4Eq$ihu{m%$iP*fji(dsQ5uR5ekzUNWp zroY1UO4Bc|?4+pPlz0OGS(5`mdd>rY;eiyb$r##b)i@_c(ll)o#>=2?9y>*v=KT4C zWVh*Cw*xTt9}28|r)u=H>PdGmPUpi9 zNN;WBb>sc7y{%=9vfVz39Evo2fj3uDv;%-R`XctXI_$NhJ!nIoVoWVeaZa+#BBn{}&u*-QGyt=<=ZuVxG}k8O!s;G)cgQUHdoeqSdS!i@BjeX@B)l z0QBwIFie2V!zX0Wu+N?zy=u8AuK*y4TrWKx@_EKr*`a~Xg$sO3U-vA0D*De$-LF0e zAh7lWb=+v4b2_+%$e|b~{yVyFI`z7T^}ioH$dA9QjCz3$`YEJAMU-R2*Q57!-%}761fcz}=6C$zTOJlcgsQ zS}Y`2GGC(PDV>ue7-rSv*`ly0qGZkvr7yMUv19=5Cs;%QG5}$!cOC1rOi@*Bw@wMH zelMbA&JUIhC7GHW+LHij1Uq0xQaA~+p$j{=Ucd_qtFvyecaZI^7qOnC4nWgPNrC-# zV)2n3vrygY^vzJ5t?b?&r>OMp?OgPT^amo)1c*Y(i@-`k9uZ;5KwOcc45H%dRSCxo7TNxmBu4^u8!0b++UXELRouUO9;%863eeI6 zeTPJ7yNp8{Nzz1wD!?Yc4_}e2E9hKX&`|z6eyV2reNZDZ3Tg(a1Id;}6c<_HROsr& zwMfW>Ntgh{ScWzt_@PiUuU?x>w* z->ZKLe(*6bC?rk8xBa^T8Pr*PobArrTrWKxin2o)zBsv56m5l33#NS=77{#2u2kwb zhYfl-qByMs&mBsCK>u{Jcgb>5SVXGYLg2uKG)=N;QBVBR@ss-~KE4Gu4UfosN93*q z57gHVo7b3yLCz#L{Ao&>6iS@GFAy|vnsZLyo^77Ykrh=4>W~t4J4L&cA%koa$EjmS zw+hhm{j%bqtUU*_4#ET^6ero@5SLC#S>#UZC~7ZQ$5T?1gK@OMTDCX4cpou6QH&rcc_NDu??HL z7zw~IXi@Is4Bg0vO+6h?hXg<#bv&>cwv`P5K)KNKdSua2AOPibt9cB)P#aIyuU`QG zVo7NnP0zSQQLZ(TeM2^_r;oabX!H%7GnoD>3-qO)P-fJT@^)DRAkxE8d>jDxhecMI z1qT`c+G2A5g7d?zgwnBw20(5y&Gqj?3A$wmWMj%7;2V<%YC{0W%G=NWL$JaGaPR&! ztttNb;R~=g&9w-t8CT*?D$(U!vkc`04}jb@KU&Gq7U0OB4~8ZV6qp8qv>Ei1eD=xP8^4E+0pY|C?0qo|bf_drgYT7}5|o8sEQcmgz% zzV*PBT#C!Iqau=RufC(Gujd#6Q1)0j`M8a%9>@=wm(GTj4Ayag!^qmFoJbD=RAyYW z;PzPA)nSvdOn*~HF1yNd{81Z-tiAhXDcQVcSjh=cQIe-p!2mIa=WPW*ElkMDYtqi? zU4UT*9MTa^tpcEjS-Yoc8{lNldTJKe7v6DfJkf%cF$-!5b!Co@GBCZjdSA@(EPKR*>blCq>g-@_t}V{xFq^9}5#D_J>U2!$g8}L(+^PV=9I5+g ziP%%m9sqr#kp$TQ*onVT@o_e*U!wK5eS&Mhyr!MgXpuc`OMsYrPP@*K39jI zxuLs}79yHGd-l3@>rUnYh}e}LI_k#;3>YwAz<`R1is8eDS65dL8#b(}s%qrOkzp8m z?~7_H2!c}%f%l$>+S=Nho12eV#tA@h?1I+P(z0#aHW5k1RclQ|K@f}|KYsrF`Bz?f zB>-4!d!7pr@dzqY3Y1brR903tZQ3-Y)QRX`A`q{b1;7&$PF=9kMpXcKlJ{^{&AY#14u_Q(ub0Lv}DNZgpj+tZjv2%InV`mZ*$8ln8oS4n8 zzP5Pr;)xR{5>XUIQ4|G1ptaUoS5{UoUAit(!HgL*lv2Zn z4J#B1a$>`>XI~JL7h~92;iJyPbHdIzF62!d+d@7`thL^!_i)awU%!6Ik|mQSO-ea5 zo6Q2iS!bPf-+lKPV~(91@4dD5NC;AFy5a&v96EI9i9+DLD@aoCK29VS8;iH?Cwn7o zMI5_C*m`!ccaD8rXk$|l8%syRn0eQ(T~nt{MMR}k7=~Kwi!QpTp`pQAdn_!FqENgi zGwV}oZ#+;#eIfUe15jS0V<)Hq+9^l^L;!>+h)63Wj4}cALPa^y;1N>wQxtUP+<*ZC zo_gx3-~ayici(+?U0t10>ctmd96562s#U8lzx?tOQP|AfUKbvrSEf&&{^XNS4jD4! z_19m|WHQI?jm7-L)&HJ(?)}hGYs8@!0RjX8kW`aVx;}K?5fTbG@C}rlG5+k55oc5m ztr;|D0!Bo+074W1@t#v1>KTAu+49QNuTE`iYfDw;FMsvR8PjKctQJg{Tr>iwmJ39r z%7mFhNr{0LV*;lUy9z@h01yO+a5|Rq)4O^7hxJ=C=9w3v=u3G(QWktpE z`|r<$(Y$%{#*Q6({`u#BiX3DC5I&9ogrxlx5}SD2=3NQq`Zq_xs@I;Ja{FtG|66@% zf&@d4fzr;pdw%*Kw=7&3nSF`}ffJ3vP`o51-c?$c zbIy>BC>mZLmi_d%PffnfzS^L@M&}XH7_;=QWq*71Tw|^G{^px+cFv^^^`{_A!lDQQ zq?)jMZxY*0Ae1mqVUyN|bk34y@0b;2`tHG}uKb7he)g;uLI5I+ljJ`id1T_mi9rxN z^UO0#mMn>)=u-dz3knO70R+a3Ux3h7DTJSXs|*qQ4%r(h$RBiAo?_{ zJg{JOe(kmd0!(}>xKX1Cc2t`|^tu!Hg z9bf@coWyawXwjlUg9ZV>iWMu4niD0W4iFTbgyV|0M8sNK{BC;D7;~fs5(Fm&vWb!*|K^bMF$R14gYB5zU=D*L&a4&~Wd)_a3qNo!!3^^b3+C*|1^5kAM8*S6_X# zP$<;Y)ZB8*Ewg6L8a#M#2UQS4Zu+ofNF@-P#+E;B*{j~Mm0lCT`z6U~S5NeTQ+zmD z=LTn<+ZEL3O9T^w25rk{kEK4^_=3u3nm2!t*;+sVhp=0y1)bi!aZ@&5FkI7baA6Ik^lhUy4f(tI_e5H10gGq2{(%!&^7yZhMOs zJ#+42X^|!`mRTCj*5%K$j_mG0}50d zLqUV9$&6g|wfxkxnzN1pAOP_e6?lcnfH9~%=`iSRFjrt^Q#tEG$N~$4cbwz?=MV9j z)L4iBh?3Ov5|B{v!>39YhJMinoHs@+C z(}3UsjW=_y{u`wb1h#D15{6+ehf%}xDZ zII#J&-CIU00K~%u8N`EgiF2^m z|MtOOia{U3S=W52m5f&afM7VaohV?8Esui_*S-uM6oY3^T8%z;6cKFPxUq*_qa8bT zq#NFqm@xCUZQF`ha$daFdD5l6Bz|o-LL>q_bfEGA0NOKEmyTcdt#OaeAOGOIbAK=g zdS|p?36qSj4tr~b!Irw;$Q%2y(TQ^-=grtFZHO3n1O`6nfP*D0;Y_l9udk0oA@QOE zRn@=BIlp!5)*gnSsi~>6T{!}R!#sjwwC^256=ZTvwzahxG+F|a)rv!&H z1CF%DP@mSnzt%dA<0MH=B#GYD=+mc9eSJL! zFwoKdCJ_Myam)?&4^O@3O3oLjhXVd|d(0F~&k{`~tKv(=D6@fAVd z^8R0Mg8hlY06dfs;Gn+Wdhur%r_!aKow_*pZd2{7NnFYr!q&u;Hfx;$h<$xEM8JJ6 zIBRpxM@<$iGkBYWnUDQ|+R&6Dc@6?h0wmHTqW!^r+PimePeL$x^5pyOyYI#uZ#+UB zq}jVklO`=&wk%1KgMli7Dnsn0zymM@j@%oKuisHu8};(>0Wd&;=ZNfSS^zYF0}aTzl=c>({Rjf}lMLNs=sDv}ohTjo$nA*Toa$F=z&=$9Epv{PU@Q zH}>6toE9X=gE$2-Ma__D1l{7X6|ya{jHnLEvLyvo*wI|}X4^pSU#Y8Vq5&VhvSkPa*<~#)Eo;}V-L`F; zQmSv?zF+yuR|XCo$jnNqqT}Qe_wwy^?zi=-#U%CndViFRrINg7VpE>UJ@;34dosFR z7DWmAeJ- zQ6i^trfu^sIv5ictt{qPg`S(5_b7H1q74!XXdo9SSq@4!e`qwKl{2t(?`t2FX9Dd- zF(9HK6tt+1TFJ7FC_rp$XimxKz6`BTVDakEXn#GI%cYS*ib7Eqgfy`t219g!D01LP z3;{XcOCqsF%me@&VywUup@$NPgoS|9ZOo$f#s?UP6OYg!tSO_6gpB%N*#=O!ghCYM z#WM&VO567D-@hjzP)g04H?M>L(=mwt$xnV#T3T9k%e9k;Ap{5n$cqAGL5JWF@*t?N zeWo1+v=$>YX^Jz=c_KiLl@by}C8QZaDD=Q2Oi>Az)#qHF z;niqCJQiI3qYpkvD`>rY_wHdXINp8+JXpiPVj1gL>I%~JRp~$s0Du-{(b!%ptS$o- z0q>35x3^v^HTs-${*v3RFin^UBJh4_88&wcXfVJCXsmzp4{s5vF=NL3=}Rf6uB(+q z5JV7I5ygFAByPtUCSEL}D z&5jy1s(a-{pQzyW^hgLwG4$T<92%T9V_ZfAiHx(W>Q)hvvu4491>NMh{t^U1q0V`` zyRTgG;6mSrz*~wf-xmgG0SvU(`jJN- zdE<>YnEBh^{&o~aTI=pRCjY#-U@zr^Z(cb1yH|krOvFIDcJ5rTU_lTB*=+WP8*ccN z^cV0UwU}ze;vYwujNnlaKmih9N}d2PfB+(pLJ}k*65@S9zI^V56aV>IUrv@>UVH#> z(@i&Nt*y1+_{KMe4hNm$P$H$9GV^K zz?ggH4V*IpdP4x@S(hp`fByUp8#V+%FmBwqyY9NHP$;Awnn$f67TsLkKKY#nf<3IU zJSYYQpan=i#w?_E-Xa)sC=>{4PZ>Z2h>4p6=gB1+Wcpoe$6%4gkflmsjI6y@4WN6k8#?gbIJw5Dj)&_U^FlQ zNtY;~fG2b$ih(q?g0aZX#oQmYq}E z@3LVv=bVXs0?dL3cbV;dS8!Z3{Ec+HwMbLY-26bi@KXmx@R zh{(Ei>$;MfIF5Vu>Sc^cvql)w$UA2H`FS)9fT93IwU4-kIzSL)f~p}k6cAQKkoM+M zds?+~&asQaDBsxdZ};4L*Ro~ST4pXQD|`6ihv&|n3jjw|fjtQUGhce?rQI+H5fzzG z6qb)agS?M`1knY=hxQOzVgZ|xm>O* z6L7K+9HBhYju=Eds<5TG+QU`{Fynzh3m^h$1_iENL++884@PiGP?&&31O-2g+k$nKm6gH zciw4?DL(GRjM~RTpp@FPXU~EK3y$jnhk2w38~_P8>MRL}X}6klNW`9Z?A)0cvwg?g z`L?!$RBDZgDGFCzb=75;T{e66?CR=j@4eRgWHU0|9AFWVsZ*zZLNT9G#dg3H_wTB_$(9j5z)D(`##M z2M-=RWXO=(+S=;sYHMw}=O=S$@M!)>7hGhFan7YRqCd%K@5!f)Oet#=^>I%<1wa2U z7N4J4?)ex&K8c*+NzwC3WR2v{3Ifz8FH4=>6p8y2K)8i?@?Oj{lqw7!o+#^ow z!%zxVrk1b`4k@44sRkKc03Eq5joi8dhw2!Q}V5I&h7#i4`$ zf{jLNt@HUp-*eAB`}j|P@{`|Zb2(ci5{cN8PyXV28#iyd+cYBxAutRB!!VFiBBVqB zLd>HZ;1~d^l|m_n@B8?^kJcK`bLrZ%=b=09xZ_L47r*$$oA21R?E&R0kOD(Uq?E`o zYRmRG|0seQL}@Wv(MsX@9-iyb+S<0+vI?)7H*eYUSpXp=rZkY!z$iuP^uPH*kr=0k zlo)`P2By~d(g&@%dCQj1n(=sIq38QVV^M^ZNJ9qv8a`(3ZGKRsMh#jBq#;o{z|OH9 z;_<{ni6ET%5+Ovut7V|hbL$+ShTC$?WJse3FeM;`zz9DO;p?Izn5TgY%L6F{N^7K$ zA%+48m_>d?N`w@_^YVpj9@mR9u8RGd=ywU(Zv)B~U>K?s?dmlp=E)!}Fidk4uYNQHGd_4xg6GtBS>I z9@}XkiPr>6-V{NGMypih8!vc==<=tsp7|mSy959#yFnM~|Ii z|A8ZTo*zW46cy84YYjqR7?SoY79kKEJbWD2^@7y$LQ@tPo0w!|Y@DwBhiGYP{F})L|F~xmS|gR9qfvb22(kw_&RQV4_;b4LG#hWUR9sO!3njE-~o z$O#6AMllSD)-W_Y0zgeo6${&%X>D$#zJ3AebPc9q%(_3%4@~Fgrh0~k$8cR2$8m!> zCuY(?#58GasNxd`fD5Xlr<@-Li+h!06Znt5>a{DwTLgi@RCw(uh#tUQTyQ zNP*+HoH*G{Z*MScIj9K(<$K3>+bn3XG*($rXouXT_q8Ipo!({rw${{A6GM#d;u zHc|@C_Vm%wzL@nNx{^pVf>!!G9jhxboGoH6H>ZvakMW0{uj6@MI29!t&7#&8HmvWY zDwRY7Dm-{!&$&L#s?_~(aZ0CaNvCUBxx9nH!C_w8{RR=!57OyeDnmzPn^MVT!aur%y$OEu03y%FBIs!as{sEzYAdJ;@OKt*Vy<3FTK2* zLcs#yzkdB3TW`97y1I0QteFv|VJ3B1bg|Z~S-q0U$t)wIWB+U7J8|+1^>t|)8|!DC zWfuk385m&fh2NoFuVMi*7u1oy?m8lM3ucfxz|rHUICS^~zV9Q#>9@3fG13qh{k^Gu zT{L{+6SMC3y_!ikd}QOhp9va#fA)yIsNkF0zn{^kp9aT97xHMUfHykI&=WuB=;!|y z<+?K>;?-SUym{bg=|{EJT(fySn>Veawx;HSJeoc5CKEe%UiP%aS2{>%HH=SY85kO2 zaA*|Eana%DvpsCbV=|M&alK3D*oq=qI3@GPk5Rv6D+}-XT*<@`fIFFC|E-_E9T+6G zcv0#7$(%)9U7Dt*29N@+HH{7R)Yn#{!W6YA>t?Wu)>ys0Bv-8}bJ}L6xI%^%(qd{W zMM)J@yf^JbSEj)th^UjN&vN+aNg}3+VMvtLWV3meFKg#RA6zwK0UjP5=f#(HF*TLr zuRinX5?)&C8M4&$l_GChC=IUfVMsHmeFf!Pvd53n@R>WA%3IUCCnZjQKNtp<<1qg8 zZ%C|L$KD$TL4l0`^yYnU7;bCMvPIB!!;%lxX^V{c0d}u9ZeFFg2@ng7seNY9rO3bW29f4woZeoN8#f_L6QsZ&8^bzw3_91cci%z&;-goSN+pp}qP1o!lV#7| zH(A=T7^9es2pAuqWdHudY*@dBBS%hQ*-qFMqtQy^D-X~0v1|)pDWujK*Y$8*x3qN} zH`ux^-oPL%Sb*a=rT1LlXR>QAW;#t_Y>a^iAE5smUniDMliSxt-@^}+J#>iN>$}MA z-c4@zE(RZdh>7Q)r!YRjsn6fVdS2;#v)LSP>_5!a zS8c%aG_hC|yNE}KRXK)Q>oD`0LkVch!kd`DeR}{EuI$?P@rH*Od-PG-?ztD|>{&!S z&f@R?0MCq4zxqnXfAJ($Teebj>n9OWld=DJl-Tev&G+5M#DDLgdfhsjw{ORDeWYPv zE?z>RyBj|CakOP2lPSi3{y24?`VVAPQKC&vs9YWzz&&@4+{-Vs^gkaXYR0HfS63`PQc6ZgC#Xs# zOMMo(T%N9d2U**>ibymaF@A|j} z3++0%eSOs4a05CN%1Rm_4TO|TJoOaTp4}{c!+PM^Z>=_&nks-vCw^5r;34&!Gsc>VoY2i_$4k6*<|FTgM4nfTQ& ziMF;9@9f04ZDK1{;+{T@UeihLwO3jAjekPhHm>WE$z&ND8z+~yunHEIWz*8q$l^t9 zShmBP2M*KO`GFFsQcCjKJn?w^(t(}!6GLy*Ft86EB-+uAmCd6)?>z4jwCCZEj$*cV zAhepUo5f;`{`4p0cfQ1;?|v@;6(FBSYfZ!7-$$e=xauMrA@|yAL>4V(;;E;IE?I)t z--p@QNb~luAQA}>pnXNYYcFPVGiFOG?$INR{QJLAcl+&#WE^ur8Z|u3#BYDY;;()U z<+=zUwzPxnE3e>mcN48|K%~=nu1nXxgCrAi+FF}wZfd|ZP2%wwu~-a^rmO1!(P#wa zD+UKgN_k7cvdLtoFbsp5>Qta~v@ZGCl{$8|8WB)9evHJ5m7r(3H=$L8Gz>%}QgO8= zo_vDLZ=a_9!H1xx7Exx&Y0tyYX7Mcx-?p(%oTUHjUjx_0I&zp;M>`OF&zqVGzUR11 z{oxM`eD^y@A&IuMVxK-k;ot%4K659^b}`av@_YA?T(%5j*>VVf)2OdUO^h?~#Lua| z@kWG{WV3l($7AEhwKO(0P@AqLRh7apO+4Sn^L)&RiQ~GQ?mkQRTRn8Y)x)vlr$NBE zzPGV$8{{kwptz9HEd>715b>54qRW@hnOX_Kg4KgKq!qrHcHFi-HoiRMfyI`D>{gEbWqjV$>6uYg|VOxl#iO6 zWa0hW(WXhHtrd~W(s0{tcv>TrBD!P=)}cc*{Po|U%aRszK^^wnZ-e8I+WuuUkeSL- zS67Q|yEBrNVtwr+*KVp<)TJRgapDX;J$>AC5dKr7!sZuV%orxrRDLgregVQj zRM%GSI2uDlV>8mZ{DA`)ra}6SZFp878P~5{!-qF?&SBCNOEHya;QNYeu33*j;;ZoU zvPPJ4{7O|?QI0Lsoid2`Z@-52Jo>)=HPrAhZQHlw+ji+(ieA86Zuy1GJdK+EJOovj zcNtZvg7O9kAbd!^I!a#aKXh)`uB!#%EC6Z0m9}j69lp%V#|@A?>4+7E-1rImLj%7 z5M2K9_n+e^mcPrfG|{3W9TSN82HAHSw^~%%0=hh6%TS-k^&LiRakiJZwxnavyXzp7 zTtduK!G$Zn;X1F&m4PTPChF2-zLEQ#3l1SFF|06Qw4VJg1R=!bD)GOs0jjEyf*{uCwVTg_Iajpmu&EBM(0aNv+zh;ppeH|Q8xPE^fImcOJ3q>~wHTox zZi=w)jM9A&rd7!IMNAW=e850!g%GmD6@jLm2Xl6Cbw~>eP$=aSF-@#OzEAGhvE#Ae zE)tFMRp~EB=y_tjByg1qG4oXk>>WFHJSLLKMC^$tp8VdX%~#!RMj{9yF%1K07}Kqd zB1n8oy5j$_VAUuH@3iriLis+P@1wQCb6xiAdHtbncWnEI;v|pWbML($zh&#zI}^!d zn<%!Ii}IG*c|Mp{0F?cqogk$xWTP|*Gd0w6sTdLxp0zED>pT_(Ft$w;PLLCgaHG)FIB3VOci zozDopJH02p?Y}WKLW7VTLa?*;ZNXUO_Y}LPVX@#Cf4!BqxE`p8pnSYq0Q}{_OEX%A zJ4)*Fsi&XVVjQ0GFEKrvWV;yb*v3p8Ul1{Za4k50?5R}yRptbCR97G4)$VmMRYt*f z|Np7|Ynrc1{p}*d?yd*AbEk3>EEhvrjR!6=i*ATH-MMnZ&%NIn{IU?5^TBz#zf^!T zDI&+W@7hi#97wxtUC5CXBsl@ER0!oCLRK&Osdi@Km3l@ty&k(lzM*P(h<}hqG<3L6 zLmRJnFr{-`bX_mEOccaU?!}iVb`_O9jFop(Bqt|klRcqQwT(FRW24xh*Hrq!HZLxl z+&M-n%?j3{f*6t^rTRe;e7_T7oOAS;=cmFpV%9N924AYbfE7hQBJdmz zmaj*Qi1nk-p74Uxl$_4gI<$5_)5|C2Z;LmVt@aPw z3(8%n^%dcg{NcOj9O+wn^NbABX1r(*Ip3ae1?G7fr7bu0$T<~*n0%iViy1s;$NAIe zlRp~N6xkYm*;+Q(U&HBc647_3##7Q4O$+(c?Ssf}({ zZ9eV8$rG?MghggVM^%PeJ6sz;*dWvzpTWR<+>sbR^=APlXVJ)l5gK&@?G1NUG1IL4 z>_9B-s^X5wEe9tbAA{g@2d2i3l%z4;r)z_RU-K^G)*ZM_6UT_&MRv9hzOH03h>Z`o zhrc2EK5hrq(5g+`dn=XxG#%|O7d9vITH3H=_GypYQQe_VKZ}-1;|wpG3Al;Ch_hs( z3Ylx~M2mx_4x)nmts_cK>xL0r2wE@WK+KA}5G&^~2u0oo;+8CIEhKY1I3(A_Zx#+xyI5gA%sxv50;4?1@#7`#*03IiRhSrLRlS z?0vW_1^65=wbEdAA4722foG!kjXen>)?V^#MmN9o3E)YMkzeq%@>h54KkHSTSSPB` znhVcQ;SgkJm}yD!?wr-_kbt(6VYunvXnImSFBAa&)hCX)H5ZUoidf8*ILbZ#q65aJ zO!79AGWTE5a)TR6PuW4Eo;l!|K)u~JKeDETO+ ztZb+k6QTND$@jTO`wef+=*KAoeworK(;DDI#?GigA>-;at}+b^K(~#8amsAgm6G6^ zlXlkO{mk>JT$E&u&Va}-2@eSDLnBG?37T-HyQbjAj`T}QUiFe5C4G9J0pinR5IdxZ z2|hLhDz}+ffKB_=ger|!$s)U-Hcp*rfgDfs=&0m_ue;u%zi^vL|C)vUr**yj%PS}0 z`e9nL4+yfn@E_}XKIBzFWy|UYT8{aGeS)K{Wn+xEGUx3|g3jrL0ecmer~#8n;&?kP zYv)sbPIsLGi6;0UU)4$nQ@E6-(np0_o^U{>7>iwG6aGv!WlHuy!L7a*?E7 zk)2x%N;W6-n@>R@fU6+k-5E(mxwA_gkOScvu``bhZrQWor1{5^bvb+Jd6RVd%$G+8 z>krVh#vqrd{B3kpYqk|_uXflnR!C1 zMaL9|!qU?xYAeAUrEk^6TWs3!y7WvE(q~=c^89~xSaRZPRbN{X7~|_i?U#GOSkNMgCKQtX@ej;)M1{RP+(j&iM9&bEGus8bI9pCY zyy9DgcEQl07CZMvP>=%izQiBO1ww|~x%pxF!L~d!F=!Wx+BNS24ToBlLx#k=QH95b zEq>*v1K*n@^qAMBrNgy)^xgd%=8U0)$~!gmfZi9mptj0K*^>c&R8m*38?nm4Y6ZZ* zSQ8(5cAKJ4I4-yupao=Mr9Je@o##pbHWz5 z6#gOlD9R0C4_>1TmnRFHl1xL25gUc-NjOcyg{Fh7TR{FOAuk-_p8i*=`w+{ zvYqm~RZuk%LDK_B9RA$zPZ(SL<>R^EP6jILU{3TQjx!BBz8KR8?zxI;0YJ_~uDY1mdG;3Bk1 z1rXa2=C59&b7yuf8#((Ock(=Np&lc2$d5Ok?Zt~cQp{LkWz_O~jej<#0}0_3?A*%% z31j0c*~u>PRbl$j`6%HKqkura7pPRLYl#geGh~jcHqpuH;5E-jo#Jl^)oI+>k5_9o zal7Q_X@x+8eyJYzw9Hn8)!K&>! z4;2}%Gvvu=8qrQz9qa>520q@Hzk=V^Ieu=nz9Q)OzF8~iDj{=V)8YS*p*h=E>&%Ne zGxg-Ehx5A~OHm^MN_}}a<6Uut!z9)V<3HP;KJ|Tt&7|32mOA-dPcg<=YJcz-w;PfO zrt56!6Um34kVHwetJ|J@<(fzsm^tq3L<=);!%X*$Q2#*7S#DJpcQVV;7p`VmOM-#55H4Lu%#XC25wL?R|03C2EC8;kUQAqYHK5!kIpo5#^ z)KO)uD)r_1=pZld5^_wKTj3w#Z)-J{#8GT7NZ&>QSqei#?h7r3=YVmCMR6p{-zBt& z`BOyV9P*gY@lL?fWyTZ{kAF=p^8s9HfFUHA#vHRqRNF~L!IO{n43HtXW` z-km1%pY;}n*@q`%y>WjKsaGXRr(wpyHTIV7Ta4Zdmx~!Qg$?_fm-x<~stQqUht4T= zxHrLMfUjNmU+(q_vt#{~i-s{;OfYqD-rgZp+A;ZJ4{=C)<#M(4i0kc(+J#mdkn#yL zl$lOAuSTkvC{40#{*iL`dy2TfbRza$Jx;2?>6;-C(9x%DlX3j+-e~Sh&AaU5w&GsX zKvEra5>Nb`+biGhQ~`*A{4VaecZvQXL;Zn5wL{!sxK* zILGzHrtu`=ex{k4fso{&sfCInB^|Nprd8d;rW)!AR#25jGyn~Np#Wn^D+a9NJSb? zA-p(^DQ5l}9xx4cF7*E$AN#H3U|x=f4}gch(2R7Rdaa2Gc&~pvW@H zE^}NT@t7JLn9vtYyk&R-vEkA(^v z+iHxS>)R4MfOzKceZSTqnfno%vmco{4u{W&(nUAk)JqZ8J7RV{_7+-=A{E_&ZWfDu z8&1QNmJUiwdCPkqVv2rYrF;TSr}9lB;%#TQi7veHzuN+vQ&ncxhq?d&fk5aIUgBxw zJgDjlwqfs?euK?i83DFxOGi!Qqj!s?7LlJ&pAPQ8czv)44~B?Xl#$&vb&=(M%hHPY z*%s^Ig?-q-+PTQe4hwRh_8aJ+W%TE6rRlb}|G;R^ds=*8v9(G+M*t49zUiIO>NH@$ z*9L@8-WAidfr{pO6j043>zEDoQ>`Nm9Wj1hsX#}gFm?)Fi=LF&>&4>!GD^^Pyp8(_ zpRjLfYInS#BLWxxsC9>ULDZ`!74+OU+cRHh!rOOP;A?i6qK z)wSE+2b0E|)z#H~EiHup?N{MDw2wzP$F{t5g(ec)7hC=J$d!|dqRqS~fz@tb-P9MH4nyR_ZDuu}aaBCEIe4Ee8-bxG^+slT7oVn@1CyK{ClS{ov6=L(}aBY>XeyNye7s zq-=$fN>!?y!@YIW$$Rg$=IkH)+)~;2mZULg#`8dX++TN`v(MRUerwLT=KSV&NLBIe ze0hKZ3kFM(-sG(k}Ko{d0~f)F^67-3)JA)>f+S`t7G0p5~*$?E@yF8+3Z zfFLa}Tr8jhfD$rffzd^7BgalaO_*tpWeR;{JNEt) zQ(tlRvek{9m#=xl&b4>?PV7mQEjO zeeU6X9}vtVd&%N2f$0(%6MB#u!%xqg=6DIo_9AOG@^)5?B}qVkrW%&SE_v+KZylUI zq{&MbfBw_42=v1020y6S{c8Y|<7!cKKwPgZ$-`t3&S|Kp$)-SU<|@m0X7*;{SuTHg z|6hccu=0FYmx`P+$_uCfD2(<^(c%1G1(--+T!8XOW2M#MH1XhQKFbvIL{>Baj>reD z9Gd!IGfck(mrGw2_(U1(5IBe}L>)pE#lH$Li3hU@9LWX4O@vTKist%kx}W3h#1*zJ)MSj*KMm$-fFPvCDxJ3{|~(+xJ(p%ktuQTDiz| z5d%<_AbH_mI?z3D-hfVo7WoXh5g`u{`qupGC=E~nWg)m1OS<Q zYYu^x<*&Z#M|W+1qoW~_j?iQrwkIZHckpGG{g`{H{Qdl=ISY18vH$Dv{LT05efgK3 z{=|tX;01*_QdJRA4aS&@5hel50Exn@DwBhpYq+v_DGORwS|k`4W)=mL_do~U!8$NQ8OB2`asa9z zHAEJQ@~<$kR6glK8AlnkczZ_*5Cjs40TK|y5MTsUE|~(*=N8lh29N-wAoU@@L<)8? z_z1o5T3s-P0t7I?lEE9O1;h8%)+q-)a`@IxWP|&et15RaPd!-!Km(O`AX&KGbHUAq zP{L?n5LHzbfY}HDRU(RrpsGYAlDt4ctY88|0dpw_7d(tz@F9aIfFekd5MRIwh(JU{ z3YZd7#+H>b76J33J7WP!5GmJ~%BQHuLpN{yCEDCEs9GR+oNn*_=vRL8yzEhvk|Zgi~?S5WXcB-5ie?tAtuYP7j|t3Y78xc zq@YUlPs69Lk%gh)Y!7fbW}iIy7q-5k9jy`j^=&tV0pEq*Xww*C?L}VBWg!1dDHxN}-1;Y@`AQqSi#lU|n5CA0@ z5#lf)8UNGbq3=Qs*g!4FfCg{0>Pif1X;D$4oB>i}MPQ5)JP-^7VysXRmrIj}K0__1 zW!R8NxD654b;B3)f7femHO`hSQ;EU1~5SRe^=740&olP{@*s2J@6DgA` zgNCs|L{uXJse-u&wtzuEc_tqKc9AWngP5&E3S@x_h=_=@b-v)47MuW)5_`a@uIzlbOf?^hF~iTsa5HG1}VavEsH@QzyZb(X$%!WVHiXNSPhCGQUnc|YZ$-+kx5Fw z1&TqU#Z_==ZY=|&M5lV~ks^fP12Jm=01X#qxaH1a`bN9k(jhGPCjj2s0SH7u ztVCqkD7>mACZDIqf(S68k`ZL#cIme^HVeSP8zMvO7%2#B5s;T)(!us39xMe!ys9xg zNcEtB>G_XgA`1yS1PE{*2uxkpIvD~^<#|I*U{OP22#V4>K9|vz@KVJ^PhbJQ5c!KDi(>O0a;FVA+6BfI0;_h$cLQ5D0}w2Kmbr^5Xmj4DBnadrUZ+q z6bi>IKpzMJ!mxx$#4sPe-U ziVC2l@qT+;iM!=_dH{4=r!}xC(rLbHuc0z`(&m^Vj3H(Y+5yT&Dy0`jU?-! zF@?B1b9D2WuZH5dQG|q}D%nNv{||e<`sktkP0Olu+r}&2a>FZ!z&4<7A^|$N zJaY8t6K794=XNezb>rIA)xyBqF5$`PaPRTSd(OANq!v*M$hE$Ad!1jme(6<9t0Mr3 z+A<~nmd|D5=>kujYd>;k{>i!Sk(_!I1!GTW_qA2`ilw!imJMyL+X`SbSit!*g;AsE z1J5?YR}P*y{UP#)Gk4l*9=I6NEw=5#6LZq=ZmB`kjC^p}Gn)8OO0tB%f0bY3MAD(?1 zwDVK1pYnh*_D$b^&$B<*YxR2h*8|ognk#au^tU~8{*(Tx$s5-H$J@63OhsZ-9t~MU zJ!u5)0Vz?Y8lTT+9zOXe4;}i`UXjvwZK|e|hBOr|Tz{|JchvHq65yR_Z}h0N^ZWVNnw)n4O}hA!Psoh3TE_P5$@C zFR%62ZoBg}9?W6jiLYPvuIZB}ch7vimF^9-mGfO5j?Ru0ZtKwI7y*6(PX?kskSC&c zzxBY;C)%mmEyYlMeEj&acWk}c2Ef9gNW@hvJ#u#DGg)-r_jl|$@Tyg-VS6X@>Ia@W z`Vcy)84ctk>NgnFEy?vg}rEKNF2UGv7Vk4Zm^d+>foQ{QSm-wbFI2V$fw#*s3B? z#AyA|TxzpCx9!wqccyEn)AV=?Kk?Y!{iv_%r|WsP?}oRD|6{ci^OLu(S@q6GPkgLZ zo1<)%oXy2frha?g+{pZ+r-nARPjsDK8*CBabi2WfyIySi7X{ z&kmVoj~)2Hg9rZ1R{Z*rH($B_FGp$P!z1&b9;$5JvFt7Dm%M7_l5Hlco}b=d$l(X}fADDY zGhf{OcxeB|t()E@@Q^e}Z|C~AKYZ$g&1UUX^ZwzXH-bSFP#&twdJUBY3lOoAhgz5( zq4DUx|6)kCt^AI9G;RU1P{~E9>Z&il_HFJ!{izfEcF0!Sq-dqfD?4{>|2GQPx88t_ zGAkICVGECbvlE-d=f#e+K0Do9yKI#sAV{zzP$*!u$5Mo_RLQvXXn|I*{ySga{lT7K zWTMt9R{4A)vdaTL7Z*$6>OMl&`g1wQkDU3%o3^e3yaS86@}tQ?{Jg=(_MZ8b!}H71 zH4lkLD!25)`a))_Y2ImlPjB)=;}QB{S6=@SSq+QW$Es8ON%eX%xorJt{i>WZM%MS)U78JR-7-! zYz13}uf2BjD;_<3%YD!MkJ)hleNVsd)tA4go+JPvfUL4w0FO_-|AD=KG1GeX>XpBE z^Y$NFUSCT-Gsbzc6U&DC`869RUj4~Oe*0+iuOHa=C!1DWx3szmVvS9gH?ChldfTy? zC-2|$-!HrMjim4jOPPQGF`SlXCJ~Uv%$?v1Mm$$cKXdvMTw8ke+P50i%2G73hQc$u ziS+8%T)Fj%)wdox`E-$oBw4a`!)=YU`q;61_DmjIvvke+;k7I3D`QHt%&W7*OGh2M zS})YVE6vc(RU1hGO9C<|Gew!VUPx91?zr?HCnrC!cWMmD9gf@i{A<@Py{=yGoS$x5 zy|1bJ&(FiCKXF@9ZZJ&HU!+&awK$vF1FgdK>2c z)7EvXlDZ!vu}ku{>^gV+XFJpF`p{@6{%_gzvE6$=v|~E}D`FYol6=J75E2TPyYaJh z=GZ)bea|6E*F7Ba8-wrWXAzm@mME5uDUXe(1!1g0cXaZ5seOZ`FLf2J*0<@|EJIX? z%}&~(Zh^^uf0@@rqh3GiWt>LC7oSEK1rt@|{(bLz_VC}_e$_AUTK9h`1q+b6;0x;_ zC@5fv*WR+>-G#T0o}?#^zJJBYE3V)8Iv@rCYRhQ))Kg#Wx1v{G^-I@n_`y_aMgU`= zphDI5)2Nmped~?C@@Jnp-7-&qb^k}c`a*^c_0J0UWZydRGb@l2fs(El9 z&A-L^Hc=X&EuEejokPUA=3WtHBpA zu3hx&E`lOJ3X&ni!=BCr^Wmc>CX;w&(fP^ETW(uX4T_mqD$ABtJ>DqT)79U+f8R`R z=+z!yAbQmI_pg-A!=Y=P2dn@F4^0;TYya5;u5o9pb+FR=-m&OEZojf&J>U@(HgwbU zrpCJ0ZCm$iUwL*qtMbsA!?Sard3OFyJBFN4S;JESvz<{6r_N_}i zAqNCVAQnDIZcurCFm>|t2d6&p+N*!(n$>S(LeQWH$e0rc1t5?-Z^rQu-LmCPlar4h ztQ>mk_y@PHylyO64U<7)@!+WV{@dSsX6od!@s$=vsBg$XBcH=MfGR~lxI`_gS8sU3 z7Z2ULfA;PmKgSln&rwor7`?qlYfV(#f4Tq6@9wM{>$(LRrr+h{{kso7XolZ#vIWEg07t|ii0JAn_H^<0 zN6zlbd;O%v|Mu(TBibPHS!L&pLY!>BNS$Qzu=j^OAVY?W2RPqXGsBjZs~<wktML`Xtj<|mq+PDGWfR=ycQ%C8{; z?-eji0VE0~3g8?Jo5*zMu&tUbEH%E;$+Q!wWoh2vJcSv<9p_A94jeyV6*XgHGO#=- z?fM)H1;=Wr@J$FCy>+7 zpXv2RgYND0A8K1wq||G|eQN(qXpBmKu4nnXS2xBPusxsmVj#-9&UX_lYBYuIB0=O{ zQysn`W`yQzDz&eknOiufdjn7iAk$MiY3Q~t!G&Mmw93Gvr&_6^C;*F0ZH|fth=ZU4 zHwxD@2m&W&M}ccHsf+Q74p2DEFgi3KETpP6h3geB2uvCZYg@d+oN!_|*XC9JrIE{J=A$G8?7qln|E$ArCTf^iNmDH>C3pOE1)2f4M z=3(AL0#ajvfT4I|%ZgjPH1{04JHu=sD0#q_ECW#n3a|yxD)v8n{LAc`S8x1xgf2|04=Ig_6%H#`EThN* z$TTlB0APhR1cFy}LI$SeI1Bk|XT3wlJvK;GMA1)BI1jXJL8=_vbXyW`WxWN}%iGxv zmE_*(+>wXx&Uox8YNtBAjg;>v`|61mGseRdDW{?^QN^h#`@UH}M6f8_>S43F+h6Zu zv}T{4Yb%viD}gGB0IW)LeLt4getqStMioikpGnpjBB+U|xvsHs=h#~&+(-wRarFk4EWvm^)GHMA^GqZ2A4YH3 zR9(?!bP1^@E;zudg(m|+L}(h{HM*o9R+DWiTOhV6;6Q8*62QR{>To3!Oh)54PZ~2a zcch-Qdja!V2Npcine2YmS|DFe6_R3GU516#)YKLcd4h*?5(3z!A-9Uc;ViJN;dXS} zXOiJBYuqgW?Z>bHbxnbyy$s0;o9@^7cTL#B32bcy#Tco=IWWl9fCff@s$rxY!8k-l zkv5~~sytr~zk`zVlzlOGgPLIk*yO9!A5k8YT_{b2hOPagP(9TP8OZW1*_ zC330?V}K%LG=F;XN%eDESG@%Zaxbx6Y?Jh$Au=^6ph<-2RX5z39M2y(`n9v?=GHFX zcE>Gmcx?aPr}jU~Y%kxwYRGFyc65Y+kcJG&2RJ~Xi?`g>q#09%?E;2z?Y|a!D zq9}qj$Z{C`i(UVmU?PoFo88|0P?`){X&j>;!<8P8R9OPV!X~*QDHJ3=6s@9|Z|2hh z%DhfBDBQvk45S#cxB*_U{wLKB;!$(ssu=raN6e#cwjQ`t`-AeH;0=89SwOPL4ar|M5dG~ zY-46c^o*-K)9V08^K86UDI|bXLnS$qj*m*)Z(Q8N^3K%2&I zuF^F=?ml+neJh85&j<`Ll$lXTfa8ac{52!He(etsCfYA419RjSU;oz}jIt z7lH*maVy9YF&P0&!^Ui`TUB+WL{t!h*FbE^uF1Q`q6tD=Yl|3b&u1NGzHVuw5f4at zsvLqs(EFF27x`!Vw4%t$<4%%PN)mzhup)VgIYMS;o;dp1J;y&Xn?2sn&$F%=8W~Tc zRcl6GKAfzp*jlbqOlD^~GiHH94F(j10vgrb_|+@F|IuTAaA4{q^Z9>XVn={P#FKHX ze0c7w)BR^+U4G5#?*KA3<|3}}KVbm`SPNr73I&cg5A8emXg{8x?{Xy?szfI1`$~$y zO2mccQ?2=ybgQ9S-qDMXI7T6h(5o&H=5)Y*f_jyUra`pKJ)*d5`x1ZjWqx%AWHz8Qq&DpJcW#GRoQ}EQ~TeRU<&AgauGP2AUHscEh*sH z!-xO+>7(yIH+O$6-n?bacdVPZWA*rr4PW(Y(g-8~p)cnr=Rek)J#oPym5~ADLmI$Pilxp zKueubz-kze(~h;7p!y#o9D@N?fH?hy=Ns4j_!zIT$`)-y5OD9afJ!a8%t{7VO^G@TSX^W zrzE5i0I~=WgDMn4cJuJ%8!Fcv=sGXP?E zsFeUgu$BR8YXLGfkc6CV9D&+FxKeEXp6h@2!w;Bdk|KLzHIo|cRPapc}SAADS920|JHS{>7>Uv6+v@N_WWQ8**1e%wz5K@kU72sUR z2}M@uiDS)fUwUbsdNXsCk(M8#rf>0T$js#7CZCxuONgz;GW>?lb9(PhNEF$-AAXR+nTL^G3`Q&c@nmQmr8X zWgwmnHZo-Mb{x4}Onruv$%_IVg$<^O11?ce1&unPZZj z;9$2cyQ}283x>{j_qBUdjp)S6#-@^ieNK6&~Oy^w3*$5>k7S zrq^x%p=Td?=c%d3TfND8yz%MN9~D2pwDRhe%Qp-rSO`JI62pK1uOVg&0Ahet8KjJ4 z=HavVJ#*-xdTspjwYRPq-SpG1|F0)o$3`k63DxUdGXPxh$d8=acgT_TygF?h@AsZK zarhN0cEF>rxwV!E5JXH&$eFyc^SR7BwnzZqlPt2S1st4(QDqz2YHJUj_a>>0<(*Aw z)%Uv-730aU`bcrx=84~b@&KsT^x5A}>FpjnNWr!bGV!oc40~xhZukr&h|v?InrdWc zfYfVB3d4Xf5JKpxBvI6s7b!~R90NIuBZ`#>zSm|NsskNHRV{oNF%$|Imw4qiVf2NB zxz^OI6h27`rKYiv5Cs{8iCEy=L^fH6u5LpkOczxLfF% zq_9h)%bqLkAPdNB+=CH=@yIlakoWqe8c$7|G~T>uuEQ3fytmDl8s2 z@K@fqx37MEotGFk1L7#k>^Q%8npo5lqlcL%&wcuLKlZ~Pc<{Xk!_luCy6*$`{m#?R ze7d1S+tVwS^Xd@{+h8Rx0zv_y$o5@jwwLAoB66-%3~GRhji6+~01^bNp&;~3e5BoX zfGe~rSVCM!5ve!<^)q%oBg-J7{%4wT0)tjyK&x<8Bkq8iA0LMl&v|oJvBKILe zF~s3`TuTVsnfj8Fmu@bew8x=C5C@3b45Q5#mNShm+x)es|IVXF(g+@r^-}amK> zqofN{5aM95``jlUKlS+`Y`%8myDVS~6-5X@HQE5~SR2peM?HCPAEs}?Mq`3iok2iQ z?>M4l_6yIvr>H#I>h>1TIUKmKsNAsT2Mx*BPkdls>z>KZ?qRcK$J*CvNJ~Q32WFxmt_U{tJ1UuiDLq1o1lp4>kf$_OpcTq$@Kr0juv zX5-&}`pi+y!2!we@`&HKrV1zt3;;vp&cAK#*sh}cEO=*;J$ZKi&mTT<+8{&<(}U5D zSIWexcbdgPW}EtFPn`XC_n!L?kHvEWU*`Ej1Vn5AOv;Pa$|F~?@T*aP+^lGyc=xO? zERQ?3K~s&TSB_sw&orBjZ(t3WU;WizE{EO;3MG&P@cjq=;7ot67fyECtu+%j#pH;M z`Zk*i6AW7riFd(b-^}Me`P45qvG0bZKXKERA0!e+28|3u^5oE&FPv@98dqJl^hQfD zBSW5&0wyO6DIw3f;O5Sv~c=S3cSz}D5%5WCABS29Qm7B zJbq@j1v$NA`5UiXahK*W778I2h6O~4nJgd@m{~yi;n}_S?fJ9QIFj|a!D%(J-O%fE zD`0gs>{N5q4lS=Igvf|dp?({mKRNa5``h;+TH(T;K(|=Dd&}@O!$!$D z-!}%H41-n=Rr<4?FEo9l8h<&+-I3jY1v-9e;1}lDoJ83F$;Lu1zPD^tQ|R}tYE)w~N+2O!m?`_#0~+9vKRa7|xkoD^ z-dmv8YAuc3)=Jb>^H`Vu>(j?RbM)*r>y}lSs=r6zT)+MMT-ixQ*O*iRChXkwj^j_iXW!I6 zte<=3hLK&vB`gG@oN3>3INLvb?^l1R(?9X{TR#8bu@66b_Lmp0`gw~Q5E|ULeBG<= zIePT${GJ-pE7pIf1;`;3!9=RCB4A?-IRFyWSb;i^&NHV!cC`6GFQ##`HbE#t9-*do zILl4fX9a9IQb-W8Ab0@Ip@Hh_)?Wq7?|<^ECt{?odTMs=3uljf*TnkLvj<`|wyG3~ zj@Ob8Wwa!Vp85JAC;j2kdb1vVB_^u%9ckf+exgQ0xpe zTpf-F1&hI)c!k&ooqMr|P5~&oea+}+9y*rQs+_nlck?CB9DmPo=S9`=_7!H=CBfVa>!LL9O_O-FyLw&YmJs?D ziD3W*kctW`1Mt!_oB%l__J)tn+~cjUa1;@@y7S&uJ&*hR{E+%hwGlg*L4^_%A%q}W zIBNo|Q-`1_+3CDrHP&`|HY-X_qb2UcWGY6q0l#ge{;uHfo9!M>V#LdD?1lP#b_Z43 zmj99CYttUulk3yQn^r7&>&BXsykKKgK@KDaqM|5h%dmatwxKgs`S8ipKe|K|I{n84?dv=d6CLFC98(MekhIibs>U-h2(5@vXKx{^!0L_6$VjX+y zuD=k9{OazLXZId46dmfzy0&dk_zfni+;sK3uV4K`A2F%k+tdC0{etxOT}(AgBVwxo8mO zAQ9qr$NsdhSEsZUN<)WrmZX9I1KUvi7O;vQL!M7 zQHTVXgaWQg^S@s+c6U7V`{#Oh^W5^#F@)J(F=pJuu(z6_)NwQPu1omsJGNdo3`==| z2*C@1nFRDi&Od0WsKTu)p`|b%DZNyZ*=JOJ5B@DW7YfJ2$(3dgj!eI}&qkI9)k0 zw0TKmb;=`vD?93oHKl@f=Q>ADP477~bExl|t`euU>W=zbhZ{>GS1c+6m~4mP(R$vS8rc_4zQQI&YHiTf5?iH?Q=J=>mtE{ex3;r@C3jkw)bag!)s~92y#H$#J1ZtoPc+gztXPVvF zP7lCHH63kKhGT1?1OyOc@p=28Pys85=K~#>?L9T!I?>9M{E9T%KGN7a(il(5W|BY^ z7c~PeQPT3NDgq`DMZ>ja!?mhkeT87DDpf1-_Teh#m1Oy|-4Zf%k!# znVFywdZY~)NG@zp0bMrw)GF|!RCIcEU2*xES51s=A*M^TL5N7822`t5 z;y5;!;v@j@Rx#mtVl26FbeS$_kJ z6f7A-17^d3T%chfbETq6i+SRbdZkLF!UU&qKm(;tM%fUALIswHGL1stKGD2m%s8tSv|A3U6EjLDoZD zg`zmuntJ5e|MS$byZdxbb!y|#54>{6Pp=udV&l?Vc1+x2A*2=oU?edIJX|sXkvd#5Ehgs7gJxM@+${`6h>jd5C*{#L?NJ@#4v#c z413Xi7WH_AZ;KY?le3AKA}(_%<6%6k2j@Ca6JxyuX+~=*)!^e0jFxOyCSn%x7n~3c zW(riqFS^QP=K5#$pZ>f>xOU?^Vj`46dRj)q82`JxD+{jbIMaW3pXJ`G6(Ir`$(9ux z55*=I#1OzK%4JK0WQw>ChYd>(F{b8eqLfB*e2U;lrfZUfu}4U=8N zA0E51b2LAY71s-R)Ay@64+~O-V(8S({{)N}7{>zxfW;}&9L?u_2mp+sMd%E`7}O6; zQv?77zz_^F16%<&AdC?j5RCzY44Amr-Uru{2Z(@0z$74Y1_FT_;EHo_Ik*5$(a8ZK zlZXy5mvN5^hYJoufDj-!0!JvGgK)U;xNsSF9*n>xIvO}(ZI4YmPfm^!I0uI_p9=vT z3D|uR%w%AyXw{I@#7D**K+w}Gk+RRs;(M^3F~b-LPJof?;&%dqGl^&rIeBsf1TfRf zLEq2Wq0@8wVX!Tac2?qlp zf&t^O&zq}Wru=*QK5a)78iz?JuA4@ynljB8Fu}mkT5>ooWWb=ft`$y?mh3Q&J#hU) zPfx!NV`K5Cs4;kE{}u2Dtws3AdSj6P6VKg6hdSk)}96u zAXGWm;SOX37zPCZAGC{HGsXb9M(CbA{$FSRH7_T9C$G)?5HB$(tMHm)HLhTUnc8p6 zS^6*Q{xmxT#ReRX9PUcvx?BM0Jd~y2tNc#wAMGHxz+EQ=pg;iUpyTo~_EZWVaWD-U zxf26u1{|655O+)FAj?>JN@qBNQUzmDfNrdnVHykv0Il`)+aHB;6wr^sXdWX7?xeH% z35QpMp7e!NU-R^A(PLb07$8C!=rV+qF=alDqQAa}gIqCi0Gu!kJ>PKVaRy8QqDFy^ z07PG#l;G2IJRXv15)gyP(kxys%E`uh9<9|2oC7%Q_T6*n#-Kcf5t=dIS*-L3a|?x7 zrPD?Sa%J6%vqg`db{xzV5$F(N;cx)8US;anmLK$h}TzyLvV*98QZ#YKyN4xi5G z#k$~&hr}*j2ErG>LDP^>DvX#(Q-IAF!#M;&o-MfOXqJ{ zRK9Gs$Z?GZQylX<3_M6FU;%usH*Vz!G)kX_CQ>4Vv7FK>Ev19N8CTq;F_?1L!`lUl z0T>4*FK&?nuESDX6xWRA2m+wWU5paY#4dA~sb=n&FO$h<6<1%m&Q0cr>IRFqW^AIUT9x^w_ zMb4m!1JKH0K-1@oU$!5k}&&e=nbkmxDd-5Bbz!W#5nU$joQf0<* z5t!BnG%#bBLjJV|;0$p#zaKWnP)xH>C}c93WJ<(tyhPav$0_bkW*;fK52YN(Nv2oB zFifRVl)~ejQ~5ZKJ)1%>)qaAPd-#IGP$T!NKd1_%x)8c=w6m<-_ zjM4QNFpyHZu4@}Uy~l>(oYPBxodnYhcVc zf`cx8EEoVtW6CW_#oXt#aNAx<{*verK9!-~N_N9NL&99c09hzF0;Ht`4uB3A1@v-dw9AE-U<|tM zy~u_!CXVA&DrM=^T5DaLUY8VN+AQ>*_$JIPV@yiPIk!!)orj2YbEd5&CRia$S`KSA zEDbZYj!Z~W2a@caX>#b&7(@1q-b?i)4ReV-d&ri_8c*sKB6_BC+?ZEc?C-Mo3TP$-a;kdGq|MZ6=l6vr_DxUL(= zG3htSqT@J8(V>%$jt*i(DwVQMhl>Cqc0>xmbDWF{eZX?AE8qG3K9nxUG{|zmG#Up0 zQYlV`Feyovk4h=)&KP6VH$)E=`0HQ)O46`@|9*Nqi3lmA>$)Uir0$;QkpuuhS6A1; zg9np+Pv`Hv^A711xy4*Ack|}WD2h1eQ54xq2qzKKifJ>?lTu14i6HRpYm!bf5=tpFTx)}^|Ez_lsyOFKXQY&}1%wdf{;piPLVBFb<*dfjuQi`RaPOmJGHgnzl`B`a zw6svKQ)iQH3&W6Pg-pfp@NhPp^*k?*V*(6Rp1fPqNRz=MNhM}>cXtz?E#+Ytl5$cd zLI}dFwv3e_D)42{((JoA;`_kBz~tm4BDS};hhbP(SGRTRRsi_)(@*>Q`o_n{CnhGE zo12#{TlVqCANTb1c%HXu)273R55MxtDgsB2Z2b1OzkTc0t)`}?{rmUdx^;_Ww56rx z%$YMaH8p*GeH9fI&CSjG_U#LTz!>w3U;IK!83e(}lPAZ=$ET*I8X6ilZ{FP3*Voq8 z76iejO`8@kUi|L6?|Pm$I5@a*V_KKhHT|xpL)(4IB3C*)w6W8996QEFzvf zd2(Q2fIwdy$DN&>fB3^65OHd1YS*q^xm>QhyIX7B)6;YA+_{SvFP=Yt9uZHUK7H-l zwfEk8Z+v_l5pUeMK{X)a?%lf)F`Lcq+_^KK&m-c&g9k5PynqVPVEd^vZ66;|Xr{9H zp}&p)@|U|VTSzPxMKt{?~yab#rVlTSVw7#L`4Ym4K!r>E!g<;zN`9XobhxNrdx z+uGWCdU~#3zfP>9V|;x4jW^y1f)X z6BBnvR=?P+MEObm>wu zjfj}f=g*uubL`kLt#y5UJ?VE8Mc?|?x5!7+_^Y%5Y^SyO-)T& z>$-nl(d1L#I!lUcY|54WGnu97WOf>(}%7d|6ppS65d>MFnB`%F4>#-rlOJszRX< z1VIo4cHqM~U$9`o<;$0!efHTXiUtM->gwt`J3E&yU22T!>grm%c5Qce_r{GI`}+Dm z`Q(#1bLMQ>vZb-Hkui4b)-7`1K@e0{Rz^`YH8mB-u^o2h^ZA;Znjik~hxPUKh&VVn zNa&a`M%`(nR-E%N3}1i!^{T3>jT<)-@}s|`l*GL-3`a&rYHDg6$MJoCaBz@wp3CJv z{q)lf8#Ww2e*EV@|9PQMIC0_xJ>obH#fKfonVOm+9O?T$g*VH}%I43XzhJ?FS6+F= zhO9~k0kb)4VD{1-#SvzqP#{JCz<~n?nwpwOm^kNygM-_*ZX`LBQd>uuY%5eEOwZ+?S_&CSgg)fEbb*4EaSUV3TWx^=sE?>5Ff z_Sj?J`ObH!@-=JL?Ay2R)TvYR=FR)bPkvHaS!vC0I-P#vi6;&nI<$TJb|J*(&6^t< z8gAaaxog+1d_KQ=_3HZi`mwRG9Xoa~#x`%>ylBy)0|yR#@WBV3=e4x75JFF<(_>>} zt*xyuzWAaYX=gH-d_KQq$&v#H4)pi;FI>2A{rdGZTuNdQ0_m>nPE1TlDev65)7IAZ z)1Us7dYx>K<2cpT)klsTxq9{L&wlnZGB$-m;a9)WvDbuO2aQZ8SKAXH>; z+VOTrN5|Q-XUQ>>3om&po6R0Sew@x}+-u#rb?UY@^7mmFQVkSDreDGVNd!RW^e{7z;ByUUbki9><$1JV`E^P{;yu5s7_*F_-Sy@SgUP2N? zfz32^baX6VzPu#PN%2D)t0j*{_sRZQ(@pQ18UH1eLmr{{1sr1(cd<#2WUh*=2w7Qr zgnBUCaQ{%W{HKc`GI5_d}eaM zir{@^!deBJ@=V$-0<-iM>J?%i`5NM53HH2is>Eg|EHENEEp1jA?0HFoDA~-U!I+r> zpNTuE??3ZRI-*Up*sRNaQ<)@xRKyFej6ywm+;@|01;6v6Xc$Gp8h2ZMGuyIY}!kd{nIkTSRe3)d;)n;|< sBgq6`NoqFvcnM+26I)e@s?XN(zfL|IkvSExIRF3v07*qoM6N<$f+xqe_1&cHS%m`3*kpxnJ53=SAopW-5I0@jF@I$HJ)4?2cX5S z-%46i;_?6s0~DZ3pI#l-ikp+_vUJ;VGV|T^Z5>09s?cM>8nTMLzJ9U+h!JT?iG6_; z0Tu>a_W)hmwDs{mtlF8u#3d=TuNgw2Zm>7EnAl(&8=mMxqi2_r@AWBvcPhZ$0Tu=* zK$kXkuM>{bt}*`0Us*b~8y)IJ&^jiBBQplEFSD4TudQX>#B1>5#NVRi{il&AAY5#oZx;Y?(h zz6Y$9G0IT!i__y-C{d_U+(@$KFWT=R$F@ft)$Iw|%TewFkkzad6w79w7H17SO}PO`RXjkSHZ3cqm-yBW1s z)bA5n;u6REc2&+4OGGbCR#4902)B+2F}@hvwc7b@(@F&^3-q##;EEg(ItkotVQuzSZY-feEv{ZCUkFvZpy0)?52d4Ggh$Z z!LFF1)C*}kKLg5QNpPM1QkP=NznHh(+axM|&ZZ>Q$4%PLS)*^$YrONZ=D(jYTI3sVo7wmMNkLRBoQ5IghNt?NL3Yh&1nBk{=Hvg~ zrWhBXD5Zp1!&{hn?!SQ z&~QQ~JWS!6|2U-$@Aece`;pOR0NTE=inKxx)sb!}K~h`|il%g|XFuReD@IpU@OsWo^99=p zx@DBlvaEY=BY)n@m<7Hqg>%$HJ{>U6x}TMt$H!La7ux#{)k2?`WcmsxbW`%<_+CbA zghTaXHD$eLmT;jU|I6@J`h7hbXcb!WSJoI?(()~`y8X^7B8ydJ`_ujCQa9|Xi`&mh zFp=4x7EbMt>%)z-)KYvM21l>J{?!{Gwg1%Mph zxG~YZ{R|*)J$t2@np3P^NrLLsRO(G#a>nm&>{ORu9_x+kB4y++7oDPAQoWJpS#Q>J z+%z1uR&AekWZZf)LOr#flBFwf-j{-{^t)oCDy(tYj)^XCxx`oDbsF7mC9Io_iK(yRNl z`UQV|LsM(jbJ_b1v-@@o{Ez*%x7QmhQ?u3c%?eB4<2%}$16$Xs5WopDR>-VkkKhU< zn?*%R@S2k5FRbM4k!={!sg8dSz^-v<)*!Bb^#|6cQlQZcFgw^V^4)@yics8%Y+P1UL@}S#qqv)M?OSAtz zz@Gc$6no_BkuGbe9`>^x)m`uXqA%H-p{eJ2P((_2ZA2?$VCz~HdIQa8t}wHTJy*>g ze}DSVW>z1_Wd1E}{C=Y9=PA`+4}QY?HG9QqfPo(De318 zazjd99@f&hwM(4pUlB;zdiJ+wMv>>Ly2w)%f_FC_Vd!gX&-m@cLGdiSvtvb9E?x0- z*$7AOlt~~>YP{#$^)_=dC|L078SC+;?8KeyKdBQo`6;B!?O$0~tz?b5UG=7HsW32` z{NG>APq!Y^&ew|QrsOX}TNrnBtM3=&h9S-NbG|dv3fx!aZM}*RtUHoRhdHY#a#g%L zZ9wZ7ew@$~%O8}k9o}D4DyYLj#*M>7?HvdGe)G>?4xjhAZjWK|bl-UI=$;MzZWq&a)9n0W zvOJPsqH>kf!MqX@W-Mpf*zUBb6Y4*_sU6DBr}}a2g6~PqD?tFR3$*etuiA&(IJXS{ z)+2eBFVJOie&s|TLSPmaVy36#{$(9SZ@q!kB?w84_dfC6wx4Ssp%ZHYbJ*s915xiczc}&Wj&z-Q=mhO}&!_#`^`iM>owbFDA>wc_nIK$+(nU zrX*>8G9Ta7k?Y&~Kim}NwD8N5eYoL`pIEg&3*ES|Ww=+r+edB{>~+6nfu7#A9q5&m z>`)ZYG=$Yso{_Tk=!Oy+>BpUR5I${o<;8z>8{!-_isDcIeNiXFqnkY2Ki)fWfPau9 zF|YmW8hI!$V9EbTcB{(&eDE_$vX=%bGi7VAZ6&ud7g4M^}j+P|r_0+7p&FRUUpHvn>f6l77EvwAOU zQ?vQ}p)M6Jd%kviJA(gj>(!CZxa50im^kma^P)E^tPa9wKYvlq+M7}`u~%bvMIe_F z*=qI*QgcfJ&t#p+BNKuj4(E_CZ3QJ~xX@zmEr|i3UlJXRiXeFGpR1*9$Dk1iOVzHu zO5n-fO;r=4P0xqHMR9I?pa4yU=sh^Wu^Qy7YPpoiwFd`%vTk zPpkBr>u35jEtxbp-d+*N8%$kFu3Ha){Cosl2%64X!O#1$uWCMA(#vbMj_t7b@x2U| zKj&$RKmUr#xNX4FBAyy=FZ9izM)6o$H^aMqccqW-zP5Gs2?LrsDstEFertVx`%i>}}r#$Dky!gv+O3hs*>~`{Q-GR)_Muhv$>PNi%7ALOl z;d^WBdBx=LVEelI^S2~wXP9j9uLqLCDwD6U)?ACn(Ptz2ZJlg%D&-eDD zRlBwAW{_FC+OkY_!2Ii7=-JN&biq@d1&$8Sn$N7Aq z;X>4B=3OKGGbuD2=iPTyN>hfEjOkdcZgy8$b zxg^f|7PFc!mOLwCSBZJxOA_d^sDP01ll(}kfos+GRQ4M^MtTwK4K~<{4@=81$EOenN3J!~U+M-E_MWu%Q^dzB6H%Ke-REa-i zN=d_DJL05Qa~0q~K?#P0Mj>_(7k|2P-QG&uM}PJ}4^V}4!Vyl-Zd0&GBfyLR1!D97 z1t>rPpa&>G=ayFqupj{R>LLNyEh-L+id|FCs^P9OO%YhsD|>pSgb__+u&Dtt4gkFx zs8O(;Bhv@6>9K1#G;JX1vj#K1Yr~6beHM&NWYOrPi*~1ER?7sk} z4@kHu3ONAuDx{Wkza{#qZ+Q5V%{)7-Ie8^sJcdcvT4D5WSQD3SB7xd=D-jm0ToE`F zaf(uibJ$QssbJS}*tkAEnnH#&FsN}9o|C}u)(!eMs7Z&YP&&qj;qBp#`bAUoWn|eN9jUHiPxYN+8I za_0=?-X0C;SU;S?dDqdUP8dU5*J96e11NUu6uWf}&l*fZq!S6;*s2z5{@jZqugU6h zJ^1wgB;sR2_~Ef$d@(wS60gCOq0Lw~@fzk1Z^eY(jcFPi!e`^UGHqxJiaiE@y}btSVtvmF!tV_}lI6h>s3t+vC?D4U+{U6ZzkM zP0EfZNZ!7yJ$H7A!-inPGkw`Pxi5WM#L%{GC{9%&bJk!+_h>+u#*yT_Fq8+9;_#TI z?H-*ygqE=(e0HDjedaE&!Nw_lIq=*7k{U-c|EAVt%pO97!-B3GWX~Ex&!#n)HoOIy zGY3=RHE0?g!hz`n$^kKRO*a_bcUr zD#0oQ$EFSB_1oIgqE-m$&ky0fTiW8$O_n~|lgybz7?xO@r-w9S@05NNdUX0HL<4YV z*ZSPst06A0!JaAom_EEEgIm{P#h7kX*1M5f0FG5hUp~|Yho;i1b|^Ex+QH20nzQLp zE_W~7grW$ti@Yoz*B#qqitQ7f$U#OhnOx1-mB?|J>!b_{;?2gW4D(J(TI zey{w1stT5EOJ~&+y=f3^$CQ%XA`hb$ZbDLe@j~+MOsr+O0V!eW)^wg&oPr_*#}fw= zV%K=0cTRnk(Ub=%&yGDEsCyx$_r}x}s zbl|hiX)GDvjloT$xwA_gpKUqDpFY`yO;eb)ayOcyV4Cujr_)R+Pk9jWkxw?WJT(ge z?3&V#g+CtV^|h%eiXbQ7!=(Q4EJ{h|(LwRle|9PP9vzQvQuN~WK3!sf`#;>om%ENL zb=gjKP3gzjt__&JVmH=Fi|F4tisS>?yg#Y~BbwD>+5QZKBB&qcASJ7aQQhnF{E}VR z%bt&po3RYLMJ3p&(J0u#6JMuL=+@C+9!^5-5N>T%o79XV?)_*JR#jnn$_bV})`Q^x zY{it4Q6K!m(p@KrNY>atV<0hB3moIxLlT z7kvQeRY6qM!oZL-hBcjSj%34nY(xw z|GBp_!{7Xo`Za=Bxb+xKYdFjE0jdz>xpiDt14W3^v74p5Z5$JfrYVf+(XhPzzpvb1 z9x|A+^g#)CS=eOP6uf1OQH4Mi0;g4_>r2TzKcqRvUq|rbvOUaRx%<3t6aFL6j{`9Q zSXMr**qwo1<_iZ|RKDGxMb9QRDe@RtRKd7DO~^0w;5H?bze-`pv;Ek4ET6^uGPwQS z4J?_^gO7hagel>RUysqZO$?7O-i}vF3{w)MsTZ_${^M=On0z#!7jJIO-V;Uiet8YK zUgNYX4`vl}-8<_U*|HW3?@OZLvrADG!K-Wbu{W;-QyKPs1CL=+;x%YlKb+6M-pMlqo3VO#CO3ZYGZrCu`?hu%Wq_NVyoX6c68Pf& zF3kRB*IDz{q6&7V7tkci$$g)0!eP_!8WM*^skn-=LRFUD{%cVMX}KY?^{a2qY4F*)renf~g<`B-IWhAvTnK8HKb<3}awI6!(0%k)Mv_o)V)M&byBF z2Xbf{9nAN;GDs_O^XE^uvh|sMtl5)Ah+QSpqS5B1WbXLa2G;yPd$H%KzNBWC&^x{+o#w7$Q(7Ji z*B$22%t5T)ok>EOwe@B23{Q62c{U^ZRrN3iQeAs=o&%9dk!EF0g0MfW7pyjBPs z59TngcLNshK8{6INZxURYg$C}(Jx0(g(&xoe)C4Gs)F63lqdaAKvNXvuG~YfCN=TS zAI{nX*|e_{#!c_6XYJt}f~@LkORNHcTQ^v_{Wz)92k_&89L9dSh0Tv&!=__-)DCm7 zDK!VXRw<|YeiCU(iNk;|0`R;rI(ZAM0D^@=fsd1J#a@FJ5l(Ctl?~~6gxY?Oo??S- z9Ly`hS_XhfhlT8t-_PB943kKUM&p`J_GA>2?KQA#3brzkocwaAO_V~XL`ob8qyTrB zv<3@>B5C3>OzPOJ9L#s&@_6~%$TswE6HDj$$>p#UfXidhu}(M{1#b2iln_+r>bkuK zo$G~@neSm&ZV|y{V=3_HvsUD@D>gC5Pzp8WhgCj@#b-nPYh+{Jt4)e2?f(Oje=NQiW@FRvJvZt~ z`mF#5(vlJz13Ljr0Jc{L2_V?2;X;DoiU9d< +* @copyright 2007-2013 PrestaShop SA +* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) +* International Registered Trademark & Property of PrestaShop SA +*/ + +header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); +header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); + +header("Cache-Control: no-store, no-cache, must-revalidate"); +header("Cache-Control: post-check=0, pre-check=0", false); +header("Pragma: no-cache"); + +header("Location: ../"); +exit; \ No newline at end of file diff --git a/modules/payxpert/lib/Connect2PayClient.php b/modules/payxpert/lib/Connect2PayClient.php new file mode 100644 index 0000000..04d24ce --- /dev/null +++ b/modules/payxpert/lib/Connect2PayClient.php @@ -0,0 +1,3454 @@ += 5.3.0 + * PHP CURL module + * PHP Mcrypt module + * + * @version 2.6.0 + * @copyright 2011-2017 PayXpert + * + */ +class Connect2PayClient { + /** + * Payment types constants + */ + const _PAYMENT_TYPE_CREDITCARD = 'CreditCard'; + const _PAYMENT_TYPE_TODITOCASH = 'ToditoCash'; + const _PAYMENT_TYPE_BANKTRANSFER = 'BankTransfer'; + + /** + * Payment providers constants + */ + const _PAYMENT_PROVIDER_SOFORT = 'Sofort'; + const _PAYMENT_PROVIDER_PRZELEWY24 = 'Przelewy24'; + const _PAYMENT_PROVIDER_IDEALKP = 'IDealKP'; + + /** + * Operation types constants + */ + const _OPERATION_TYPE_SALE = 'sale'; + const _OPERATION_TYPE_AUTHORIZE = 'authorize'; + + /** + * Payment modes constants + */ + const _PAYMENT_MODE_SINGLE = 'Single'; + const _PAYMENT_MODE_ONSHIPPING = 'OnShipping'; + const _PAYMENT_MODE_RECURRENT = 'Recurrent'; + const _PAYMENT_MODE_INSTALMENTS = 'InstalmentsPayments'; + + /** + * Shipping types constants + */ + const _SHIPPING_TYPE_PHYSICAL = 'Physical'; + const _SHIPPING_TYPE_ACCESS = 'Access'; + const _SHIPPING_TYPE_VIRTUAL = 'Virtual'; + + /** + * Subscription types constants + */ + const _SUBSCRIPTION_TYPE_NORMAL = 'normal'; + const _SUBSCRIPTION_TYPE_LIFETIME = 'lifetime'; + const _SUBSCRIPTION_TYPE_ONETIME = 'onetime'; + const _SUBSCRIPTION_TYPE_INFINITE = 'infinite'; + + /** + * Lang constants + */ + const _LANG_EN = 'en'; + const _LANG_FR = 'fr'; + const _LANG_ES = 'es'; + const _LANG_IT = 'it'; + + /** + * ~~~~ + * Subscription cancel reasons + * ~~~~ + */ + /** + * Bank denial + */ + const _SUBSCRIPTION_CANCEL_BANK_DENIAL = 1000; + /** + * Canceled due to refund + */ + const _SUBSCRIPTION_CANCEL_REFUNDED = 1001; + /** + * Canceled due to retrieval request + */ + const _SUBSCRIPTION_CANCEL_RETRIEVAL = 1002; + /** + * Cancellation letter sent by bank + */ + const _SUBSCRIPTION_CANCEL_BANK_LETTER = 1003; + /** + * Chargeback + */ + const _SUBSCRIPTION_CANCEL_CHARGEBACK = 1004; + /** + * Company account closed + */ + const _SUBSCRIPTION_CANCEL_COMPANY_ACCOUNT_CLOSED = 1005; + /** + * Site account closed + */ + const _SUBSCRIPTION_CANCEL_WEBSITE_ACCOUNT_CLOSED = 1006; + /** + * Didn't like the site + */ + const _SUBSCRIPTION_CANCEL_DID_NOT_LIKE = 1007; + /** + * Disagree ('Did not do it' or 'Do not recognize the transaction') + */ + const _SUBSCRIPTION_CANCEL_DISAGREE = 1008; + /** + * Fraud from webmaster + */ + const _SUBSCRIPTION_CANCEL_WEBMASTER_FRAUD = 1009; + /** + * I could not get in to the site + */ + const _SUBSCRIPTION_CANCEL_COULD_NOT_GET_INTO = 1010; + /** + * No problem, just moving on + */ + const _SUBSCRIPTION_CANCEL_NO_PROBLEM = 1011; + /** + * Not enough updates + */ + const _SUBSCRIPTION_CANCEL_NOT_UPDATED = 1012; + /** + * Problems with the movies/videos + */ + const _SUBSCRIPTION_CANCEL_TECH_PROBLEM = 1013; + /** + * Site was too slow + */ + const _SUBSCRIPTION_CANCEL_TOO_SLOW = 1014; + /** + * The site did not work + */ + const _SUBSCRIPTION_CANCEL_DID_NOT_WORK = 1015; + /** + * Too expensive + */ + const _SUBSCRIPTION_CANCEL_TOO_EXPENSIVE = 1016; + /** + * Un-authorized signup by family member + */ + const _SUBSCRIPTION_CANCEL_UNAUTH_FAMILLY = 1017; + /** + * Undetermined reasons + */ + const _SUBSCRIPTION_CANCEL_UNDETERMINED = 1018; + /** + * Webmaster requested to cancel + */ + const _SUBSCRIPTION_CANCEL_WEBMASTER_REQUESTED = 1019; + /** + * I haven't received my item + */ + const _SUBSCRIPTION_CANCEL_NOTHING_RECEIVED = 1020; + /** + * The item was damaged or defective + */ + const _SUBSCRIPTION_CANCEL_DAMAGED = 1021; + /** + * The box was empty + */ + const _SUBSCRIPTION_CANCEL_EMPTY_BOX = 1022; + /** + * The order was incomplete + */ + const _SUBSCRIPTION_CANCEL_INCOMPLETE_ORDER = 1023; + + /** + * Field content constant + */ + const _UNAVAILABLE = 'NA'; + const _UNAVAILABLE_COUNTRY = 'ZZ'; + + /* + * API calls routes + */ + private static $API_ROUTES = array(/* */ + 'TRANS_PREPARE' => '/payment/prepare', /* */ + 'PAYMENT_STATUS' => '/payment/:merchantToken/status', /* */ + 'TRANS_REFUND' => '/transaction/:transactionID/refund', /* */ + 'TRANS_DOPAY' => '/payment/:customerToken', /* */ + 'SUB_CANCEL' => '/subscription/:subscriptionID/cancel'); + + /* + * Fields required for payment creation + */ + protected $fieldsRequired = array('orderID', 'currency', 'amount', 'shippingType', 'paymentMode'); + + /* + * Fields maximum size + */ + protected $fieldsSize = array(/* */ + 'shopperID' => 32, /* */ + 'shopperEmail' => 100, /* */ + 'shipToCountryCode' => 2, /* */ + 'shopperCountryCode' => 2, /* */ + 'orderID' => 100, /* */ + 'orderDescription' => 500, /* */ + 'currency' => 3, /* */ + 'orderFOLanguage' => 50, /* */ + 'shippingType' => 50, /* */ + 'shippingName' => 50, /* */ + 'paymentType' => 32, /* */ + 'operation' => 32, /* */ + 'paymentMode' => 30, /* */ + 'subscriptionType' => 32, /* */ + 'trialPeriod' => 10, /* */ + 'rebillPeriod' => 10, /* */ + 'ctrlRedirectURL' => 2048, /* */ + 'ctrlCallbackURL' => 2048, /* */ + 'timeOut' => 10, /* */ + 'merchantNotificationTo' => 100, /* */ + 'merchantNotificationLang' => 2, /* */ + 'ctrlCustomData' => 2048 /* */ + ); + + /* + * Fields validation constraints + */ + protected $fieldsValidate = array(/* */ + 'shopperID' => 'isString', /* */ + 'shopperEmail' => 'isEmail', /* */ + 'shipToCountryCode' => 'isCountryName', /* */ + 'shopperCountryCode' => 'isCountryName', /* */ + 'orderID' => 'isString', /* */ + 'orderDescription' => 'isString', /* */ + 'currency' => 'isString', /* */ + 'amount' => 'isInt', /* */ + 'orderTotalWithoutShipping' => 'isInt', /* */ + 'orderShippingPrice' => 'isInt', /* */ + 'orderDiscount' => 'isInt', /* */ + 'orderFOLanguage' => 'isString', /* */ + 'shippingType' => 'isShippingType', /* */ + 'shippingName' => 'isString', /* */ + 'paymentType' => 'isPayment', /* */ + 'provider' => 'isProvider', /* */ + 'operation' => 'isOperation', /* */ + 'paymentMode' => 'isPaymentMode', /* */ + 'offerID' => 'isInt', /* */ + 'subscriptionType' => 'isSubscriptionType', /* */ + 'trialPeriod' => 'isString', /* */ + 'rebillAmount' => 'isInt', /* */ + 'rebillPeriod' => 'isString', /* */ + 'rebillMaxIteration' => 'isInt', /* */ + 'ctrlRedirectURL' => 'isAbsoluteUrl', /* */ + 'ctrlCallbackURL' => 'isAbsoluteUrl', /* */ + 'timeOut' => 'isString', /* */ + 'merchantNotification' => 'isBool', /* */ + 'merchantNotificationTo' => 'isEmail', /* */ + 'merchantNotificationLang' => 'isString', /* */ + 'themeID' => 'isInt' /* */ + ); + + /* + * Fields to be included in JSON + */ + protected $fieldsJSON = array(/* */ + 'apiVersion', /* */ + 'shopperID', /* */ + 'shopperEmail', /* */ + 'shipToFirstName', /* */ + 'shipToLastName', /* */ + 'shipToCompany', /* */ + 'shipToPhone', /* */ + 'shipToAddress', /* */ + 'shipToState', /* */ + 'shipToZipcode', /* */ + 'shipToCity', /* */ + 'shipToCountryCode', /* */ + 'shopperFirstName', /* */ + 'shopperLastName', /* */ + 'shopperPhone', /* */ + 'shopperAddress', /* */ + 'shopperState', /* */ + 'shopperZipcode', /* */ + 'shopperCity', /* */ + 'shopperCountryCode', /* */ + 'shopperBirthDate', /* */ + 'shopperIDNumber', /* */ + 'shopperCompany', /* */ + 'shopperLoyaltyProgram', /* */ + 'orderID', /* */ + 'orderDescription', /* */ + 'currency', /* */ + 'amount', /* */ + 'orderTotalWithoutShipping', /* */ + 'orderShippingPrice', /* */ + 'orderDiscount', /* */ + 'orderFOLanguage', /* */ + 'orderCartContent', /* */ + 'shippingType', /* */ + 'shippingName', /* */ + 'paymentType', /* */ + 'provider', /* */ + 'operation', /* */ + 'paymentMode', /* */ + 'secure3d', /* */ + 'offerID', /* */ + 'subscriptionType', /* */ + 'trialPeriod', /* */ + 'rebillAmount', /* */ + 'rebillPeriod', /* */ + 'rebillMaxIteration', /* */ + 'ctrlCustomData', /* */ + 'ctrlRedirectURL', /* */ + 'ctrlCallbackURL', /* */ + 'timeOut', /* */ + 'merchantNotification', /* */ + 'merchantNotificationTo', /* */ + 'merchantNotificationLang', /* */ + 'themeID' /* */ + ); + + /* + * API version implemented by this library + */ + private $apiVersion = '002.50'; + + /** + * URL of the connect2pay application + * + * @var string + */ + private $url; + + /** + * Login for the connect2pay application + * + * @var string + */ + private $merchant; + + /** + * Password for the connect2pay application + * + * @var string + */ + private $password; + + // ~~~~ + // Transaction related data + // ~~~~ + + /** + * Force the transaction to use Secure 3D + * + * @var Boolean + */ + private $secure3d; + + // Customer fields + /** + * Merchant unique customer numeric id + * + * @var string + */ + private $shopperID; + /** + * Customer email address + * + * @var string + */ + private $shopperEmail; + /** + * Customer first name for shipping + * + * @var string + */ + private $shipToFirstName; + /** + * Customer last name for shipping + * + * @var string + */ + private $shipToLastName; + /** + * Customer company name for shipping + * + * @var string + */ + private $shipToCompany; + /** + * Customer phone for shipping ; if many, separate by ";" + * + * @var string + */ + private $shipToPhone; + /** + * Customer address for shipping + * + * @var string + */ + private $shipToAddress; + /** + * Customer state for shipping + * + * @var string + */ + private $shipToState; + /** + * Customer ZIP Code for shipping + * + * @var string + */ + private $shipToZipcode; + /** + * Customer city for shipping + * + * @var string + */ + private $shipToCity; + /** + * Customer country for shipping + * + * @var string + */ + private $shipToCountryCode; + /** + * Customer first name for invoicing + * + * @var string + */ + private $shopperFirstName; + /** + * Customer last name for invoicing + * + * @var string + */ + private $shopperLastName; + /** + * Customer phone for invoicing ; if many, separate by ";" + * + * @var string + */ + private $shopperPhone; + /** + * Customer address for invoicing + * + * @var string + */ + private $shopperAddress; + /** + * Customer state for invoicing + * + * @var string + */ + private $shopperState; + /** + * Customer ZIP Code for invoicing + * + * @var string + */ + private $shopperZipcode; + /** + * Customer city for invoicing + * + * @var string + */ + private $shopperCity; + /** + * Customer country for invoicing + * + * @var string + */ + private $shopperCountryCode; + /** + * Customer birth date YYYYMMDD + * + * @var string + */ + private $shopperBirthDate; + /** + * Customer ID number (identity card, passport...) + * + * @var string + */ + private $shopperIDNumber; + /** + * Customer company name for invoicing + * + * @var string + */ + private $shopperCompany; + /** + * Customer Loyalty Program name + * + * @var string + */ + private $shopperLoyaltyProgram; + + // Order Fields + /** + * Merchant internal unique order ID + * + * @var string + */ + private $orderID; + /** + * Sum up of the order to display on the payment page + * + * @var string + */ + private $orderDescription; + /** + * Currency for the current order + * + * @var string + */ + private $currency; + /** + * The transaction amount in cents (for 1€ => 100) + * + * @var integer + */ + private $amount; + /** + * The transaction amount in cents, without shipping fee + * + * @var integer + */ + private $orderTotalWithoutShipping; + /** + * The shipping amount in cents (for 1€ => 100) + * + * @var integer + */ + private $orderShippingPrice; + /** + * The discount amount in cents (for 1€ => 100) + * + * @var integer + */ + private $orderDiscount; + /** + * Language of the Front Office used to validate the order + * + * @var string + */ + private $orderFOLanguage; + /** + * Product or service bought - see details below + * + * @var array[](integer CartProductId, string CartProductName, float + * CartProductUnitPrice, + * integer CartProductQuantity, string CartProductBrand, string + * CartProductMPN, + * string CartProductCategoryName, integer CartProductCategoryID) + */ + private $orderCartContent; + + // Shipping Fields + /** + * Type can be either : Physical (for physical goods), Virtual (for + * dematerialized goods), Access (for protected content) + * + * @var string + */ + private $shippingType; + /** + * In case of Physical shipping type, name of the shipping company + * + * @var string + */ + private $shippingName; + + // Payment Detail Fields + /** + * Can be CreditCard, ToditoCash, BankTransfer or empty. + * This will change the type of the payment page displayed. + * If empty, a selection page will be displayed to the customer with payment + * types available for the account. + * + * @var string + */ + private $paymentType; + + /** + * The technical payment provider to use for the payment. + * This can be needed for payment types other than credit card where everal + * provider are available and can not be all used in every countries. + * + * @var string + */ + private $provider; + + /** + * Can be authorize or sale (default value is according to what is configured + * for the account). + * This will change the operation done for the payment page. + * Only relevant for Credit Card payment type. + * + * @var string + */ + private $operation; + + /** + * Can be either : Single, OnShipping, Recurrent, InstalmentsPayments + * + * @var string + */ + private $paymentMode; + + /** + * Predefined price point with initial and rebill period (for Recurrent, + * InstalmentsPayments payment types) + * + * @var integer + */ + private $offerID; + + /** + * Type of subscription. + * + * @var string + */ + private $subscriptionType; + + /** + * Number of days in the initial period (for Recurrent, InstalmentsPayments + * payment types) + * + * @var integer + */ + private $trialPeriod; + + /** + * Number in minor unit, amount to be rebilled after the initial period (for + * Recurrent, InstalmentsPayments payment types) + * + * @var integer + */ + private $rebillAmount; + + /** + * Number of days next re-billing transaction will be settled in (for + * Recurrent, InstalmentsPayments payment types) + * + * @var integer + */ + private $rebillPeriod; + + /** + * Number of re-billing transactions that will be settled (for Recurrent, + * InstalmentsPayments payment types) + * + * @var integer + */ + private $rebillMaxIteration; + + // Template and Control Fields + /** + * The URL where to redirect the customer after the transaction processing + * + * @var string + */ + private $ctrlRedirectURL; + + /** + * A URL that will be notified of the status of the transaction + * + * @var string + */ + private $ctrlCallbackURL; + + /** + * Custom data that will be returned back with the status of the transaction + * + * @var string + */ + private $ctrlCustomData; + + /** + * Validity for the payment link in ISO 8601 duration format. + * See http://en.wikipedia.org/wiki/ISO_8601. + * For example: 2 days => P2D, 1 month => P1M + * + * @var string + */ + private $timeOut; + + /** + * Whether or not to send notification to the merchant after payment + * processing + * + * @var boolean + */ + private $merchantNotification; + + /** + * Mail address to send merchant notification to + * + * @var string + */ + private $merchantNotificationTo; + + /** + * Lang to use in merchant notification (defaults to the customer lang) + * + * @var string + */ + private $merchantNotificationLang; + + /** + * Select a predefined payment page template + * + * @var integer + */ + private $themeID; + + // Data returned from prepare call + private $returnCode; + private $returnMessage; + private $merchantToken; + private $customerToken; + + // Data returned from status call + private $status; + + // Internal data + private $clientErrorMessage; + + // HTTP Proxy data + private $proxy_host = null; + private $proxy_port = null; + private $proxy_username = null; + private $proxy_password = null; + + // Internal Currency Helper + private $currencyHelper = null; + + // Extra CURL options that can be set by the caller + private $extraCurlOptions = array(); + + /** + * Instantiate a new payment page client + * + * @param string $url + * The URL of the payment page application + * @param string $merchant + * The login of the merchant on the payment page + * @param string $password + * The password of the merchant on the payment page + * @param array $data + * Data for the transaction to create (optional) + */ + public function __construct($url, $merchant, $password, $data = null) { + $this->url = preg_replace('/\/*$/', '', $url); + $this->merchant = $merchant; + $this->password = $password; + + if ($data != null && is_array($data)) { + foreach ($data as $var => $value) { + if (property_exists($this, $var)) { + $this->$var = $value; + } + } + } + } + + /** + * Set the parameter in the case of the use of an outgoing proxy + * + * @param string $host + * The proxy host. + * @param int $port + * The proxy port. + * @param string $username + * The proxy username. + * @param string $password + * The proxy password. + */ + public function useProxy($host, $port, $username = null, $password = null) { + $this->proxy_host = $host; + $this->proxy_port = $port; + $this->proxy_username = $username; + $this->proxy_password = $password; + } + + /** + * Force the validation of the Connect2Pay SSL certificate. + * + * @param string $certFilePath + * The path to the PEM file containing the certification chain. + * If not set, defaults to + * "_current-dir_/ssl/connect2pay-signing-ca-cert.pem" + * @deprecated Has no effect anymore + */ + public function forceSSLValidation($certFilePath = null) { + Utils::deprecation_error('Custom certificate file path is deprecated. Will use the system CA.'); + } + + /** + * Add extra curl options + */ + public function setExtraCurlOption($name, $value) { + $this->extraCurlOptions[$name] = $value; + } + + /** + * + * @deprecated Use preparePayment() instead. + */ + public function prepareTransaction() { + Utils::deprecation_error('Method prepareTransaction() is deprecated, use preparePayment() instead'); + return $this->preparePayment(); + } + + /** + * Prepare a new payment on the payment page application. + * This method will validate the payment data and call + * the payment page application to create a new payment. + * The fields returnCode, returnMessage, merchantToken and + * customerToken will be populated according to the call result. + * + * @return boolean true if creation is successful, false otherwise + */ + public function preparePayment() { + if ($this->validate()) { + $trans = array(); + + foreach ($this->fieldsJSON as $fieldName) { + if (is_array($this->{$fieldName}) || !C2PValidate::isEmpty($this->{$fieldName})) { + $trans[$fieldName] = $this->{"get" . ucfirst($fieldName)}(); + } + } + + // Only PHP >= 5.4 has JSON_UNESCAPED_SLASHES option + $post_data = str_replace('\\/', '/', json_encode($trans)); + $url = $this->url . Connect2PayClient::$API_ROUTES['TRANS_PREPARE']; + + $result = $this->doPost($url, $post_data); + + if ($result != null && is_array($result)) { + $this->returnCode = $result['code']; + $this->returnMessage = $result['message']; + + if ($this->returnCode == "200") { + $this->merchantToken = $result['merchantToken']; + $this->customerToken = $result['customerToken']; + return true; + } else { + $this->clientErrorMessage = $this->returnMessage; + } + } + } else { + $this->clientErrorMessage = 'The transaction is not valid.'; + } + + return false; + } + + /** + * + * @deprecated Use getPaymentStatus($merchantToken) instead. + * + * @param string $merchantToken + */ + public function getTransactionStatus($merchantToken) { + Utils::deprecation_error('getTransactionStatus is deprecated, use getPaymentStatus instead'); + return $this->getPaymentStatus($merchantToken); + } + + /** + * Do a transaction status request on the payment page application. + * + * @param string $merchantToken + * The merchant token related to this payment + * @return The PaymentStatus object of the payment or null on error + */ + public function getPaymentStatus($merchantToken) { + if ($merchantToken != null && strlen(trim($merchantToken)) > 0) { + $url = $this->url . str_replace(":merchantToken", $merchantToken, Connect2PayClient::$API_ROUTES['PAYMENT_STATUS']); + + $result = $this->doGet($url, array(), false); + + if ($result !== null && is_object($result)) { + $this->initStatus($result); + if (isset($this->status)) { + return $this->status; + } + } + } + + return null; + } + + /** + * Refund a transaction. + * + * @param string $transactionID + * Identifier of the transaction to refund + * @param int $amount + * The amount to refund + * @return The RefundStatus filled with values returned from the operation or + * null on failure (in that case call getClientErrorMessage()) + */ + public function refundTransaction($transactionID, $amount) { + if ($transactionID !== null && $amount !== null && (is_int($amount) || ctype_digit($amount))) { + $url = $this->url . str_replace(":transactionID", $transactionID, Connect2PayClient::$API_ROUTES['TRANS_REFUND']); + $trans = array(); + $trans['apiVersion'] = $this->apiVersion; + $trans['amount'] = intval($amount); + + $result = $this->doPost($url, json_encode($trans)); + + $this->status = null; + if ($result != null && is_array($result)) { + $this->status = new RefundStatus(); + if (isset($result['code'])) { + $this->status->setCode($result['code']); + } + if (isset($result['message'])) { + $this->status->setMessage($result['message']); + } + if (isset($result['transactionID'])) { + $this->status->setTransactionID($result['transactionID']); + } + + return $this->status; + } else { + $this->clientErrorMessage = 'No result received from refund call'; + } + } else { + $this->clientErrorMessage = '"transactionID" must not be null, "amount" must be a positive integer'; + } + + return null; + } + + /** + * Do a subscription cancellation. + * + * @param int $subscriptionID + * Identifier of the subscription to cancel + * @param int $cancelReason + * Identifier of the cancelReason (see _SUBSCRIPTION_CANCEL_* + * constants) + * @return The result code of the operation (200 for success) or null on + * failure + */ + public function cancelSubscription($subscriptionID, $cancelReason) { + if ($subscriptionID != null && is_numeric($subscriptionID) && isset($cancelReason) && is_numeric($cancelReason)) { + $url = $this->url . str_replace(":subscriptionID", $subscriptionID, Connect2PayClient::$API_ROUTES['SUB_CANCEL']); + $trans = array(); + $trans['apiVersion'] = $this->apiVersion; + $trans['cancelReason'] = intval($cancelReason); + + $result = $this->doPost($url, json_encode($trans)); + + if ($result != null && is_array($result)) { + $this->clientErrorMessage = $result['message']; + return $result['code']; + } + } else { + $this->clientErrorMessage = 'subscriptionID and cancelReason must be not null and numeric'; + } + + return null; + } + + /** + * Handle the callback done by the payment page application after + * a transaction processing. + * This will populate the status field that can be retrieved by calling + * getStatus(). + * + * @return true on succes or false on error + */ + public function handleCallbackStatus() { + // Read the body of the request + $body = @file_get_contents('php://input'); + + if ($body != null && strlen(trim($body)) > 0) { + $status = json_decode(trim($body), false); + + if ($status != null && is_object($status)) { + $this->initStatus($status); + return true; + } + } + + return false; + } + + /** + * Handle the data received by the POST done when payment page redirects + * the customer to the merchant website. + * This will populate the status field that can be retrieved by calling + * getStatus(). + * + * @param string $encryptedData + * The content of the 'data' field posted + * @param string $merchantToken + * The merchant token related to this transaction + * @return boolean True on success or false on error + */ + public function handleRedirectStatus($encryptedData, $merchantToken) { + $key = $this->urlsafe_base64_decode($merchantToken); + $binData = $this->urlsafe_base64_decode($encryptedData); + + // Decrypting + $json = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $binData, MCRYPT_MODE_ECB); + + if ($json) { + // Remove PKCS#5 padding + $json = $this->pkcs5_unpad($json); + $status = json_decode($json, false); + + if ($status != null && is_object($status)) { + $this->initStatus($status); + return true; + } + } + + return false; + } + + /** + * Returns the URL to redirect the customer to after a transaction + * creation. + * + * @return string The URL to redirect the customer to. + */ + public function getCustomerRedirectURL() { + return $this->url . str_replace(":customerToken", $this->customerToken, Connect2PayClient::$API_ROUTES['TRANS_DOPAY']); + } + + /** + * Validate the current transaction data. + * + * @return boolean True if transaction data are valid, false otherwise + */ + public function validate() { + $arrErrors = array(); + + $arrErrors = $this->validateFields(); + + if (sizeof($arrErrors) > 0) { + foreach ($arrErrors as $error) { + $this->clientErrorMessage .= $error . " * "; + } + return false; + } + + return true; + } + + private function doGet($url, $params, $assoc = true) { + return $this->doHTTPRequest("GET", $url, $params, $assoc); + } + + private function doPost($url, $data, $assoc = true) { + return $this->doHTTPRequest("POST", $url, $data, $assoc); + } + + private function doHTTPRequest($type, $url, $data, $assoc = true) { + $curl = curl_init(); + + if ($type === "GET") { + // In that case, $data is the array of params to add in the URL + if (is_array($data) && count($data) > 0) { + $urlParams = array(); + foreach ($data as $param => $value) { + $urlParams[] = urlencode($param) . "=" . urlencode($value); + } + if (count($urlParams) > 0) { + $url .= "?" . implode("&", $urlParams); + } + } + } elseif ($type === "POST") { + // In that case, $data is the body of the request + curl_setopt($curl, CURLOPT_POST, true); + curl_setopt($curl, CURLOPT_POSTFIELDS, $data); + curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-Type: application/json")); + } else { + $this->clientErrorMessage = "Bad HTTP method specified."; + return null; + } + + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); + curl_setopt($curl, CURLOPT_USERPWD, $this->merchant . ":" . $this->password); + + if ($this->proxy_host != null && $this->proxy_port != null) { + curl_setopt($curl, CURLOPT_PROXY, $this->proxy_host); + curl_setopt($curl, CURLOPT_PROXYPORT, $this->proxy_port); + + if ($this->proxy_username != null && $this->proxy_password != null) { + curl_setopt($curl, CURLOPT_PROXYAUTH, CURLAUTH_BASIC); + curl_setopt($curl, CURLOPT_PROXYUSERPWD, $this->proxy_username . ":" . $this->proxy_password); + } + } + + // Extra Curl Options + foreach ($this->extraCurlOptions as $name => $value) { + curl_setopt($curl, $name, $value); + } + + $json = curl_exec($curl); + $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); + curl_close($curl); + + if ($httpCode != 200) { + $this->clientErrorMessage = "Received HTTP code " . $httpCode . " from payment page."; + } else { + if ($json !== false) { + $result = json_decode($json, $assoc); + + if ($result != null) { + return $result; + } else { + $this->clientErrorMessage = 'JSON decoding error.'; + } + } else { + $this->clientErrorMessage = 'Error requesting ' . $connect2pay; + } + } + + return null; + } + + private function initStatus($status) { + if ($status != null && is_object($status)) { + // Root element, PaymentStatus + $this->status = new PaymentStatus(); + $reflector = new \ReflectionClass('PayXpert\Connect2Pay\PaymentStatus'); + $this->copyScalarProperties($reflector->getProperties(), $status, $this->status); + + // Transaction attempts + if (isset($status->transactions) && is_array($status->transactions)) { + $transactionAttempts = array(); + foreach ($status->transactions as $transaction) { + $transAttempt = new TransactionAttempt(); + + $reflector = new \ReflectionClass('PayXpert\Connect2Pay\TransactionAttempt'); + $this->copyScalarProperties($reflector->getProperties(), $transaction, $transAttempt); + + // Set the shopper + if (isset($transaction->shopper) && is_object($transaction->shopper)) { + $shopper = new Shopper(); + $reflector = new \ReflectionClass('PayXpert\Connect2Pay\Shopper'); + $this->copyScalarProperties($reflector->getProperties(), $transaction->shopper, $shopper); + $transAttempt->setShopper($shopper); + } + + // Payment Mean Info + if (isset($transaction->paymentType) && isset($transaction->paymentMeanInfo) && is_object($transaction->paymentMeanInfo)) { + $paymentMeanInfo = null; + switch ($transaction->paymentType) { + case self::_PAYMENT_TYPE_CREDITCARD: + $paymentMeanInfo = $this->extractCreditCardPaymentMeanInfo($transaction->paymentMeanInfo); + break; + case self::_PAYMENT_TYPE_TODITOCASH: + $paymentMeanInfo = $this->extractToditoCashPaymentMeanInfo($transaction->paymentMeanInfo); + break; + case self::_PAYMENT_TYPE_BANKTRANSFER: + $paymentMeanInfo = $this->extractBankTransferPaymentMeanInfo($transaction->paymentMeanInfo); + break; + } + + if ($paymentMeanInfo !== null) { + $transAttempt->setPaymentMeanInfo($paymentMeanInfo); + } + } + + $transactionAttempts[] = $transAttempt; + } + + $this->status->setTransactions($transactionAttempts); + } + } + } + + private function extractCreditCardPaymentMeanInfo($paymentMeanInfo) { + $ccInfo = new CreditCardPaymentMeanInfo(); + $reflector = new \ReflectionClass('PayXpert\Connect2Pay\CreditCardPaymentMeanInfo'); + $this->copyScalarProperties($reflector->getProperties(), $paymentMeanInfo, $ccInfo); + + return $ccInfo; + } + + private function extractToditoCashPaymentMeanInfo($paymentMeanInfo) { + $tcInfo = new ToditoCashPaymentMeanInfo(); + $reflector = new \ReflectionClass('PayXpert\Connect2Pay\ToditoCashPaymentMeanInfo'); + $this->copyScalarProperties($reflector->getProperties(), $paymentMeanInfo, $tcInfo); + + return $tcInfo; + } + + private function extractBankTransferPaymentMeanInfo($paymentMeanInfo) { + $btInfo = new BankTransferPaymentMeanInfo(); + $reflector = new \ReflectionClass('PayXpert\Connect2Pay\BankAccount'); + + if (is_object($paymentMeanInfo->sender)) { + $sender = new BankAccount(); + $this->copyScalarProperties($reflector->getProperties(), $paymentMeanInfo->sender, $sender); + $btInfo->setSender($sender); + } + + if (is_object($paymentMeanInfo->recipient)) { + $recipient = new BankAccount(); + $this->copyScalarProperties($reflector->getProperties(), $paymentMeanInfo->recipient, $recipient); + $btInfo->setRecipient($recipient); + } + + return $btInfo; + } + + private function copyScalarProperties($properties, $src, &$dest) { + if ($properties !== null && is_object($src) && is_object($dest)) { + foreach ($properties as $property) { + if (isset($src->{$property->getName()}) && is_scalar($src->{$property->getName()})) { + $dest->{"set" . ucfirst($property->getName())}($src->{$property->getName()}); + } + } + } + } + + private function urlsafe_base64_decode($string) { + return base64_decode(strtr($string, '-_', '+/')); + } + + private function pkcs5_unpad($text) { + $pad = ord($text{strlen($text) - 1}); + if ($pad > strlen($text)) { + // The initial text was empty + return ""; + } + + if (strspn($text, chr($pad), strlen($text) - $pad) != $pad) { + // The length of the padding sequence is incorrect + return false; + } + + return substr($text, 0, -1 * $pad); + } + + public function getApiVersion() { + return $this->apiVersion; + } + + public function getURL() { + return $this->url; + } + + public function setURL($url) { + $this->url = $url; + return ($this); + } + + public function getMerchant() { + return $this->merchant; + } + + public function setMerchant($merchant) { + $this->merchant = $merchant; + return ($this); + } + + public function getPassword() { + return $this->password; + } + + public function setPassword($password) { + $this->password = $password; + return ($this); + } + + public function getAfClientId() { + Utils::deprecation_error('The field afClientId does not exist any more'); + return null; + } + + public function setAfClientId($afClientId) { + Utils::deprecation_error('The field afClientId does not exist any more'); + return ($this); + } + + public function getAfPassword() { + Utils::deprecation_error('The field afPassword does not exist any more'); + return null; + } + + public function setAfPassword($afPassword) { + Utils::deprecation_error('The field afPassword does not exist any more'); + return ($this); + } + + public function getSecure3d() { + return $this->secure3d; + } + + public function setSecure3d($secure3d) { + $this->secure3d = $secure3d; + return ($this); + } + + public function getShopperID() { + return $this->shopperID; + } + + public function setShopperID($shopperID) { + $this->shopperID = (strlen($shopperID) > 32) ? substr((string) $shopperID, 0, 32) : (string) $shopperID; + return ($this); + } + + public function getShopperEmail() { + return $this->shopperEmail; + } + + public function setShopperEmail($shopperEmail) { + $this->shopperEmail = (strlen($shopperEmail) > 100) ? substr((string) $shopperEmail, 0, 100) : (string) $shopperEmail; + return ($this); + } + + public function getShipToFirstName() { + return $this->shipToFirstName; + } + + public function setShipToFirstName($shipToFirstName) { + $this->shipToFirstName = (strlen($shipToFirstName) > 35) ? substr((string) $shipToFirstName, 0, 35) : (string) $shipToFirstName; + return ($this); + } + + public function getShipToLastName() { + return $this->shipToLastName; + } + + public function setShipToLastName($shipToLastName) { + $this->shipToLastName = (strlen($shipToLastName) > 35) ? substr((string) $shipToLastName, 0, 35) : (string) $shipToLastName; + return ($this); + } + + public function getShipToCompany() { + return $this->shipToCompany; + } + + public function setShipToCompany($shipToCompany) { + $this->shipToCompany = (strlen($shipToCompany) > 128) ? substr((string) $shipToCompany, 0, 128) : (string) $shipToCompany; + return ($this); + } + + public function getShipToPhone() { + return $this->shipToPhone; + } + + public function setShipToPhone($shipToPhone) { + $this->shipToPhone = (strlen($shipToPhone) > 20) ? substr((string) $shipToPhone, 0, 20) : (string) $shipToPhone; + return ($this); + } + + public function getShipToAddress() { + return $this->shipToAddress; + } + + public function setShipToAddress($shipToAddress) { + $this->shipToAddress = (strlen($shipToAddress) > 255) ? substr((string) $shipToAddress, 0, 255) : (string) $shipToAddress; + return ($this); + } + + public function getShipToState() { + return $this->shipToState; + } + + public function setShipToState($shipToState) { + $this->shipToState = (strlen($shipToState) > 30) ? substr((string) $shipToState, 0, 30) : (string) $shipToState; + return ($this); + } + + public function getShipToZipcode() { + return $this->shipToZipcode; + } + + public function setShipToZipcode($shipToZipcode) { + $this->shipToZipcode = (strlen($shipToZipcode) > 10) ? substr((string) $shipToZipcode, 0, 10) : (string) $shipToZipcode; + return ($this); + } + + public function getShipToCity() { + return $this->shipToCity; + } + + public function setShipToCity($shipToCity) { + $this->shipToCity = (strlen($shipToCity) > 50) ? substr((string) $shipToCity, 0, 50) : (string) $shipToCity; + return ($this); + } + + public function getShipToCountryCode() { + return $this->shipToCountryCode; + } + + public function setShipToCountryCode($shipToCountryCode) { + $this->shipToCountryCode = (strlen($shipToCountryCode) > 2) ? substr((string) $shipToCountryCode, 0, 2) : (string) $shipToCountryCode; + return ($this); + } + + public function getShopperFirstName() { + return $this->shopperFirstName; + } + + public function setShopperFirstName($shopperFirstName) { + $this->shopperFirstName = (strlen($shopperFirstName) > 35) ? substr((string) $shopperFirstName, 0, 35) : (string) $shopperFirstName; + return ($this); + } + + public function getShopperLastName() { + return (!C2PValidate::isEmpty($this->shopperLastName)) ? $this->shopperLastName : Connect2PayClient::_UNAVAILABLE; + } + + public function setShopperLastName($shopperLastName) { + $this->shopperLastName = (strlen($shopperLastName) > 35) ? substr((string) $shopperLastName, 0, 35) : (string) $shopperLastName; + return ($this); + } + + public function getShopperPhone() { + return (!C2PValidate::isEmpty($this->shopperPhone)) ? $this->shopperPhone : Connect2PayClient::_UNAVAILABLE; + } + + public function setShopperPhone($shopperPhone) { + $this->shopperPhone = (strlen($shopperPhone) > 20) ? substr((string) $shopperPhone, 0, 20) : (string) $shopperPhone; + return ($this); + } + + public function getShopperAddress() { + return (!C2PValidate::isEmpty($this->shopperAddress)) ? $this->shopperAddress : Connect2PayClient::_UNAVAILABLE; + } + + public function setShopperAddress($shopperAddress) { + $this->shopperAddress = (strlen($shopperAddress) > 255) ? substr((string) $shopperAddress, 0, 255) : (string) $shopperAddress; + return ($this); + } + + public function getShopperState() { + return (!C2PValidate::isEmpty($this->shopperState)) ? $this->shopperState : Connect2PayClient::_UNAVAILABLE; + } + + public function setShopperState($shopperState) { + $this->shopperState = (strlen($shopperState) > 30) ? substr((string) $shopperState, 0, 30) : (string) $shopperState; + return ($this); + } + + public function getShopperZipcode() { + return (!C2PValidate::isEmpty($this->shopperZipcode)) ? $this->shopperZipcode : Connect2PayClient::_UNAVAILABLE; + } + + public function setShopperZipcode($shopperZipcode) { + $this->shopperZipcode = (strlen($shopperZipcode) > 10) ? substr((string) $shopperZipcode, 0, 10) : (string) $shopperZipcode; + return ($this); + } + + public function getShopperCity() { + return (!C2PValidate::isEmpty($this->shopperCity)) ? $this->shopperCity : Connect2PayClient::_UNAVAILABLE; + } + + public function setShopperCity($shopperCity) { + $this->shopperCity = (strlen($shopperCity) > 50) ? substr((string) $shopperCity, 0, 50) : (string) $shopperCity; + return ($this); + } + + public function getShopperCountryCode() { + return (!C2PValidate::isEmpty($this->shopperCountryCode)) ? $this->shopperCountryCode : Connect2PayClient::_UNAVAILABLE_COUNTRY; + } + + public function setShopperCountryCode($shopperCountryCode) { + $this->shopperCountryCode = (strlen($shopperCountryCode) > 2) ? substr((string) $shopperCountryCode, 0, 2) : (string) $shopperCountryCode; + return ($this); + } + + public function getShopperBirthDate() { + return $this->shopperBirthDate; + } + + public function setShopperBirthDate($shopperBirthDate) { + $this->shopperBirthDate = (strlen($shopperBirthDate) > 8) ? substr((string) $shopperBirthDate, 0, 8) : (string) $shopperBirthDate; + return ($this); + } + + public function getShopperIDNumber() { + return $this->shopperIDNumber; + } + + public function setShopperIDNumber($shopperIDNumber) { + $this->shopperIDNumber = (strlen($shopperIDNumber) > 32) ? substr((string) $shopperIDNumber, 0, 32) : (string) $shopperIDNumber; + return ($this); + } + + public function getShopperCompany() { + return $this->shopperCompany; + } + + public function setShopperCompany($shopperCompany) { + $this->shopperCompany = (strlen($shopperCompany) > 128) ? substr((string) $shopperCompany, 0, 128) : (string) $shopperCompany; + return ($this); + } + + public function getShopperLoyaltyProgram() { + return $this->shopperLoyaltyProgram; + } + + public function setShopperLoyaltyProgram($shopperLoyaltyProgram) { + $this->shopperLoyaltyProgram = (string) $shopperLoyaltyProgram; + return ($this); + } + + public function getOrderID() { + return $this->orderID; + } + + public function setOrderID($orderID) { + $this->orderID = (string) $orderID; + return ($this); + } + + public function getOrderDescription() { + return $this->orderDescription; + } + + public function setOrderDescription($orderDescription) { + $this->orderDescription = (strlen($orderDescription) > 500) ? substr((string) $orderDescription, 0, 500) : (string) $orderDescription; + return ($this); + } + + public function getCurrency() { + return $this->currency; + } + + public function setCurrency($currency) { + $this->currency = (string) $currency; + return ($this); + } + + public function getAmount() { + return $this->amount; + } + + public function setAmount($amount) { + $this->amount = (int) $amount; + return ($this); + } + + public function getOrderTotalWithoutShipping() { + return $this->orderTotalWithoutShipping; + } + + public function setOrderTotalWithoutShipping($orderTotalWithoutShipping) { + $this->orderTotalWithoutShipping = (int) $orderTotalWithoutShipping; + return ($this); + } + + public function getOrderShippingPrice() { + return $this->orderShippingPrice; + } + + public function setOrderShippingPrice($orderShippingPrice) { + $this->orderShippingPrice = (int) $orderShippingPrice; + return ($this); + } + + public function getOrderDiscount() { + return $this->orderDiscount; + } + + public function setOrderDiscount($orderDiscount) { + $this->orderDiscount = (int) $orderDiscount; + return ($this); + } + + /** + * + * @deprecated This field is not present anymore in the API, the value is + * obtained from the connected user + */ + public function getCustomerIP() { + return null; + } + + /** + * + * @deprecated This field is not present anymore in the API, the value is + * obtained from the connected user + */ + public function setCustomerIP($customerIP) { + return ($this); + } + + public function getOrderFOLanguage() { + return $this->orderFOLanguage; + } + + public function setOrderFOLanguage($orderFOLanguage) { + $this->orderFOLanguage = (string) $orderFOLanguage; + return ($this); + } + + public function getOrderCartContent() { + return $this->orderCartContent; + } + + public function setOrderCartContent($orderCartContent) { + $this->orderCartContent = $orderCartContent; + return ($this); + } + + /** + * Add a CartProduct in the orderCartContent. + * + * @param CartProduct $cartProduct + * The product to add to the cart + * @return Connect2PayClient + */ + public function addCartProduct($cartProduct) { + if ($this->orderCartContent == null || !is_array($this->orderCartContent)) { + $this->orderCartContent = array(); + } + + if ($cartProduct instanceof CartProduct) { + $this->orderCartContent[] = $cartProduct; + } + + return $this; + } + + public function getShippingType() { + return $this->shippingType; + } + + public function setShippingType($shippingType) { + $this->shippingType = (string) $shippingType; + return ($this); + } + + public function getShippingName() { + return $this->shippingName; + } + + public function setShippingName($shippingName) { + $this->shippingName = (string) $shippingName; + return ($this); + } + + public function getPaymentType() { + return (!C2PValidate::isEmpty($this->paymentType)) ? $this->paymentType : Connect2PayClient::_PAYMENT_TYPE_CREDITCARD; + } + + public function setPaymentType($paymentType) { + $this->paymentType = (string) $paymentType; + return ($this); + } + + public function getProvider() { + return $this->provider; + } + + public function setProvider($provider) { + $this->provider = $provider; + return $this; + } + + public function getOperation() { + return $this->operation; + } + + public function setOperation($operation) { + $this->operation = (string) $operation; + return ($this); + } + + public function getPaymentMode() { + return $this->paymentMode; + } + + public function setPaymentMode($paymentMode) { + $this->paymentMode = (string) $paymentMode; + return ($this); + } + + public function getOfferID() { + return $this->offerID; + } + + public function setOfferID($offerID) { + $this->offerID = (int) $offerID; + return ($this); + } + + public function getSubscriptionType() { + return $this->subscriptionType; + } + + public function setSubscriptionType($subscriptionType) { + $this->subscriptionType = $subscriptionType; + return ($this); + } + + public function getTrialPeriod() { + return $this->trialPeriod; + } + + public function setTrialPeriod($trialPeriod) { + $this->trialPeriod = $trialPeriod; + return ($this); + } + + public function getRebillAmount() { + return $this->rebillAmount; + } + + public function setRebillAmount($rebillAmount) { + $this->rebillAmount = (int) $rebillAmount; + return ($this); + } + + public function getRebillPeriod() { + return $this->rebillPeriod; + } + + public function setRebillPeriod($rebillPeriod) { + $this->rebillPeriod = $rebillPeriod; + return ($this); + } + + public function getRebillMaxIteration() { + return $this->rebillMaxIteration; + } + + public function setRebillMaxIteration($rebillMaxIteration) { + $this->rebillMaxIteration = (int) $rebillMaxIteration; + return ($this); + } + + public function getCtrlRedirectURL() { + return $this->ctrlRedirectURL; + } + + public function setCtrlRedirectURL($ctrlRedirectURL) { + $this->ctrlRedirectURL = (string) $ctrlRedirectURL; + return ($this); + } + + public function getCtrlCallbackURL() { + return $this->ctrlCallbackURL; + } + + public function setCtrlCallbackURL($ctrlCallbackURL) { + $this->ctrlCallbackURL = (string) $ctrlCallbackURL; + return ($this); + } + + public function getCtrlCustomData() { + return $this->ctrlCustomData; + } + + public function setCtrlCustomData($ctrlCustomData) { + $this->ctrlCustomData = (string) $ctrlCustomData; + return ($this); + } + + public function getTimeOut() { + return $this->timeOut; + } + + public function setTimeOut($timeOut) { + $this->timeOut = (string) $timeOut; + return ($this); + } + + public function getMerchantNotification() { + return $this->merchantNotification; + } + + public function setMerchantNotification($merchantNotification) { + $this->merchantNotification = $merchantNotification; + return ($this); + } + + public function getMerchantNotificationTo() { + return $this->merchantNotificationTo; + } + + public function setMerchantNotificationTo($merchantNotificationTo) { + $this->merchantNotificationTo = $merchantNotificationTo; + return ($this); + } + + public function getMerchantNotificationLang() { + return $this->merchantNotificationLang; + } + + public function setMerchantNotificationLang($merchantNotificationLang) { + $this->merchantNotificationLang = $merchantNotificationLang; + return ($this); + } + + public function getThemeID() { + return $this->themeID; + } + + public function setThemeID($themeID) { + $this->themeID = (int) $themeID; + return ($this); + } + + public function getReturnCode() { + return $this->returnCode; + } + + public function getReturnMessage() { + return $this->returnMessage; + } + + public function getMerchantToken() { + return $this->merchantToken; + } + + public function getCustomerToken() { + return $this->customerToken; + } + + public function getStatus() { + return $this->status; + } + + public function getClientErrorMessage() { + return $this->clientErrorMessage; + } + + public function getCurrencyHelper() { + if ($this->currencyHelper == null) { + $this->currencyHelper = new Connect2PayCurrencyHelper(); + + $this->currencyHelper->useProxy($this->proxy_host, $this->proxy_port, $this->proxy_password, $this->proxy_username); + } + + return $this->currencyHelper; + } + + /** + * Set a default cart content, to be used when anti fraud system is enabled + * and no real cart is known + */ + public function setDefaultOrderCartContent() { + $this->orderCartContent = array(); + $product = new CartProduct(); + $product->setCartProductId(0)->setCartProductName("NA"); + $product->setCartProductUnitPrice(0)->setCartProductQuantity(1); + $product->setCartProductBrand("NA")->setCartProductMPN("NA"); + $product->setCartProductCategoryName("NA")->setCartProductCategoryID(0); + + $this->orderCartContent[] = $product; + } + + /** + * Check for fields validity + * + * @return array empty if everything is OK or as many elements as errors + * matched + */ + private function validateFields() { + $fieldsRequired = $this->fieldsRequired; + $returnError = array(); + + foreach ($fieldsRequired as $field) { + if (C2PValidate::isEmpty($this->{$field}) && (!is_numeric($this->{$field}))) + $returnError[] = $field . ' is empty'; + } + + foreach ($this->fieldsSize as $field => $size) { + if (isset($this->{$field}) && C2PValidate::strlen($this->{$field}) > $size) + $returnError[] = $field . ' Length ' . $size; + } + + foreach ($this->fieldsValidate as $field => $method) { + if (!C2PValidate::isEmpty($this->{$field}) && !call_user_func(array('PayXpert\Connect2Pay\C2PValidate', $method), $this->{$field})) + $returnError[] = $field . ' = ' . $this->{$field}; + } + + return $returnError; + } +} + +/** + * Represent the status of a payment returned by the payment page + */ +class PaymentStatus { + /** + * Status of the payment: "Authorized", "Not authorized", "Expired", "Call + * failed", "Pending" or "Not processed" + * + * @var String + */ + private $status; + + /** + * The merchant token of this payment + * + * @var String + */ + private $merchantToken; + + /** + * Type of operation for the last transaction done for this payment: Can be + * sale or authorize. + * + * @var String + */ + private $operation; + + /** + * Result code of the last transaction done for this payment + * + * @var Int + */ + private $errorCode; + + /** + * Error message of the last transaction done for this payment + * + * @var String + */ + private $errorMessage; + + /** + * The order ID of the payment + * + * @var String + */ + private $orderID; + + /** + * Currency for the payment + * + * @var String + */ + private $currency; + + /** + * Amount of the payment in cents (1.00€ => 100) + * + * @var Int + */ + private $amount; + + /** + * Custom data provided by merchant at payment creation. + * + * @var String + */ + private $ctrlCustomData; + + /** + * The list of transactions done to complete this payment + * + * @var array + */ + private $transactions; + + public function getStatus() { + return $this->status; + } + + public function setStatus($status) { + $this->status = $status; + return $this; + } + + public function getMerchantToken() { + return $this->merchantToken; + } + + public function setMerchantToken($merchantToken) { + $this->merchantToken = $merchantToken; + return $this; + } + + public function getOperation() { + return $this->operation; + } + + public function setOperation($operation) { + $this->operation = $operation; + return $this; + } + + public function getErrorCode() { + return $this->errorCode; + } + + public function setErrorCode($errorCode) { + $this->errorCode = $errorCode; + return $this; + } + + public function getErrorMessage() { + return $this->errorMessage; + } + + public function setErrorMessage($errorMessage) { + $this->errorMessage = $errorMessage; + return $this; + } + + public function getOrderID() { + return $this->orderID; + } + + public function setOrderID($orderID) { + $this->orderID = $orderID; + return $this; + } + + public function getCurrency() { + return $this->currency; + } + + public function setCurrency($currency) { + $this->currency = $currency; + return $this; + } + + public function getAmount() { + return $this->amount; + } + + public function setAmount($amount) { + $this->amount = $amount; + return $this; + } + + public function getCtrlCustomData() { + return $this->ctrlCustomData; + } + + public function setCtrlCustomData($ctrlCustomData) { + $this->ctrlCustomData = $ctrlCustomData; + return $this; + } + + public function getTransactions() { + return $this->transactions; + } + + public function setTransactions($transactions) { + $this->transactions = $transactions; + return $this; + } + + /** + * Return the last transaction attempt done for this payment + * + * @return TransactionAttempt The last transaction attempt done for this + * payment + */ + public function getLastTransactionAttempt() { + $lastAttempt = null; + + if (isset($this->transactions) && is_array($this->transactions) && count($this->transactions) > 0) { + // Return the entry with the highest timestamp with type sale or authorize + foreach ($this->transactions as $transaction) { + if (in_array($transaction->getOperation(), array("sale", "authorize"))) { + if ($lastAttempt == null || $lastAttempt->getDate() < $transaction->getDate()) { + $lastAttempt = $transaction; + } + } + } + } + + return $lastAttempt; + } +} + +class TransactionAttempt { + /** + * Type of payment for this transaction attempt: CreditCard, BankTransfer or + * ToditoCash + * + * @var String + */ + private $paymentType; + + /** + * Type of operation for that transaction: Can be sale or authorize. + * + * @var String + */ + private $operation; + + /** + * Date of the transaction + * + * @var timestamp + */ + private $date; + + /** + * Amount of the transaction + * + * @var integer + */ + private $amount; + + /** + * The result code for this transaction + * + * @var String + */ + private $resultCode; + + /** + * The result message for this transaction + * + * @var String + */ + private $resultMessage; + + /** + * Status of the transaction: "Authorized", "Not authorized", "Expired", "Call + * failed", "Pending" or "Not processed" + * + * @var String + */ + private $status; + + /** + * Shopper information for this transaction + * + * @var Shopper + */ + private $shopper; + + /** + * Transaction identifier of this transaction. + * + * @var String + */ + private $transactionID; + + /** + * Identifier of the subscription this transaction is part of (if any). + * + * @var Int + */ + private $subscriptionID; + + /** + * Details of the payment mean used to process the transaction + * + * @var Depends on the paymentType + */ + private $paymentMeanInfo; + + public function getPaymentType() { + return $this->paymentType; + } + + public function setPaymentType($paymentType) { + $this->paymentType = $paymentType; + return $this; + } + + public function getOperation() { + return $this->operation; + } + + public function setOperation($operation) { + $this->operation = $operation; + return $this; + } + + public function getDate() { + return $this->date; + } + + public function getDateAsDateTime() { + if ($this->date != null) { + // API returns date as timestamp in milliseconds + $timestamp = intval($this->date / 1000); + return new \DateTime("@" . $timestamp); + } + + return null; + } + + public function setDate($date) { + $this->date = $date; + return $this; + } + + public function getAmount() { + return $this->amount; + } + + public function setAmount($amount) { + $this->amount = $amount; + return $this; + } + + public function getResultCode() { + return $this->resultCode; + } + + public function setResultCode($resultCode) { + $this->resultCode = $resultCode; + return $this; + } + + public function getResultMessage() { + return $this->resultMessage; + } + + public function setResultMessage($resultMessage) { + $this->resultMessage = $resultMessage; + return $this; + } + + public function getStatus() { + return $this->status; + } + + public function setStatus($status) { + $this->status = $status; + return $this; + } + + public function getShopper() { + return $this->shopper; + } + + public function setShopper($shopper) { + $this->shopper = $shopper; + return $this; + } + + public function getTransactionID() { + return $this->transactionID; + } + + public function setTransactionID($transactionID) { + $this->transactionID = $transactionID; + return $this; + } + + public function getSubscriptionID() { + return $this->subscriptionID; + } + + public function setSubscriptionID($subscriptionID) { + $this->subscriptionID = $subscriptionID; + return $this; + } + + public function getPaymentMeanInfo() { + return $this->paymentMeanInfo; + } + + public function setPaymentMeanInfo($paymentMeanInfo) { + $this->paymentMeanInfo = $paymentMeanInfo; + return $this; + } +} + +class Shopper { + /** + * Name provided by the shopper + * + * @var String + */ + private $name; + + /** + * Address provided by the shopper + * + * @var String + */ + private $address; + + /** + * Zipcode provided by the shopper. + * + * @var String + */ + private $zipcode; + + /** + * City provided by the shopper. + * + * @var String + */ + private $city; + + /** + * State provided by the shopper + * + * @var String + */ + private $state; + + /** + * Country provided by the shopper. + * + * @var String + */ + private $countryCode; + + /** + * Phone provided by the shopper + * + * @var String + */ + private $phone; + + /** + * Email address provided by the shopper. + * + * @var String + */ + private $email; + + /** + * Birth date provided by the shopper (YYYYMMDD) + * + * @var string + */ + private $birthDate; + + /** + * ID number provided by the shopper (identity card, passport...) + * + * @var string + */ + private $idNumber; + + /** + * IP address of the shopper + * + * @var String + */ + private $ipAddress; + + public function getname() { + return $this->name; + } + + public function setName($name) { + $this->name = $name; + return $this; + } + + public function getAddress() { + return $this->address; + } + + public function setAddress($address) { + $this->address = $address; + return $this; + } + + public function getZipcode() { + return $this->zipcode; + } + + public function setZipcode($zipcode) { + $this->zipcode = $zipcode; + return $this; + } + + public function getCity() { + return $this->city; + } + + public function setCity($city) { + $this->city = $city; + return $this; + } + + public function getState() { + return $this->state; + } + + public function setState($state) { + $this->state = $state; + return $this; + } + + public function getCountryCode() { + return $this->countryCode; + } + + public function setCountryCode($countryCode) { + $this->countryCode = $countryCode; + return $this; + } + + public function getPhone() { + return $this->phone; + } + + public function setPhone($phone) { + $this->phone = $phone; + return $this; + } + + public function getEmail() { + return $this->email; + } + + public function setEmail($email) { + $this->email = $email; + return $this; + } + + public function getBirthDate() { + return $this->birthDate; + } + + public function setBirthDate($birthDate) { + $this->birthDate = $birthDate; + return $this; + } + + public function getIdNumber() { + return $this->idNumber; + } + + public function setIdNumber($idNumber) { + $this->idNumber = $idNumber; + return $this; + } + + public function getIpAddress() { + return $this->ipAddress; + } + + public function setIpAddress($ipAddress) { + $this->ipAddress = $ipAddress; + return $this; + } +} + +class CreditCardPaymentMeanInfo { + /** + * The truncated card number used for this transaction + * + * @var string + */ + private $cardNumber; + + /** + * The card expiration year + * + * @var string + */ + private $cardExpireYear; + + /** + * The card expire month + * + * @var string + */ + private $cardExpireMonth; + + /** + * The name of the holder of the card + * + * @var string + */ + private $cardHolderName; + + /** + * Brand of the card (Visa, Mcrd...) + * + * @var string + */ + private $cardBrand; + + /** + * Level of the card. + * Special permission needed + * + * @var string + */ + private $cardLevel; + + /** + * Sub type of the card. + * Special permission needed. + * + * @var string + */ + private $cardSubType; + + /** + * ISO2 country code of the issuer of the card. + * Special permission needed. + * + * @var string + */ + private $iinCountry; + + /** + * Card Issuer Bank Name. + * Special permission needed. + * + * @var string + */ + private $iinBankName; + + /** + * The liability shift for 3D Secure. + * Can be true or false + * + * @var boolean + */ + private $is3DSecure; + + /** + * Credit Card Descriptor for this transaction + * + * @var String + */ + private $statementDescriptor; + + public function getCardNumber() { + return $this->cardNumber; + } + + public function setCardNumber($cardNumber) { + $this->cardNumber = $cardNumber; + return $this; + } + + public function getCardExpireYear() { + return $this->cardExpireYear; + } + + public function setCardExpireYear($cardExpireYear) { + $this->cardExpireYear = $cardExpireYear; + return $this; + } + + public function getCardExpireMonth() { + return $this->cardExpireMonth; + } + + public function setCardExpireMonth($cardExpireMonth) { + $this->cardExpireMonth = $cardExpireMonth; + return $this; + } + + public function getCardHolderName() { + return $this->cardHolderName; + } + + public function setCardHolderName($cardHolderName) { + $this->cardHolderName = $cardHolderName; + return $this; + } + + public function getCardBrand() { + return $this->cardBrand; + } + + public function setCardBrand($cardBrand) { + $this->cardBrand = $cardBrand; + return $this; + } + + public function getCardLevel() { + return $this->cardLevel; + } + + public function setCardLevel($cardLevel) { + $this->cardLevel = $cardLevel; + return $this; + } + + public function getCardSubType() { + return $this->cardSubType; + } + + public function setCardSubType($cardSubType) { + $this->cardSubType = $cardSubType; + return $this; + } + + public function getIinCountry() { + return $this->iinCountry; + } + + public function setIinCountry($iinCountry) { + $this->iinCountry = $iinCountry; + return $this; + } + + public function getIinBankName() { + return $this->iinBankName; + } + + public function setIinBankName($iinBankName) { + $this->iinBankName = $iinBankName; + return $this; + } + + public function getIs3DSecure() { + return $this->is3DSecure; + } + + public function setIs3DSecure($is3DSecure) { + $this->is3DSecure = $is3DSecure; + return $this; + } + + public function getStatementDescriptor() { + return $this->statementDescriptor; + } + + public function setStatementDescriptor($statementDescriptor) { + $this->statementDescriptor = $statementDescriptor; + return $this; + } +} + +class ToditoCashPaymentMeanInfo { + /** + * The truncated Todito card number used for this transaction + * + * @var string + */ + private $cardNumber; + + public function getCardNumber() { + return $this->cardNumber; + } + + public function setCardNumber($cardNumber) { + $this->cardNumber = $cardNumber; + return $this; + } +} + +class BankTransferPaymentMeanInfo { + /** + * Sender account + * + * @var BankAccount + */ + private $sender; + + /** + * Recipient account + * + * @var BankAccount + */ + private $recipient; + + public function getSender() { + return $this->sender; + } + + public function setSender($sender) { + $this->sender = $sender; + return $this; + } + + public function getRecipient() { + return $this->recipient; + } + + public function setRecipient($recipient) { + $this->recipient = $recipient; + return $this; + } +} + +class BankAccount { + /** + * The account holder name + * + * @var string + */ + private $holderName; + + /** + * Name of the bank of the account + * + * @var string + */ + private $bankName; + + /** + * IBAN number of the account (truncated) + * + * @var string + */ + private $iban; + + /** + * BIC number of the account + * + * @var string + */ + private $bic; + + /** + * ISO2 country code of the account + * + * @var string + */ + private $countryCode; + + public function getHolderName() { + return $this->holderName; + } + + public function setHolderName($holderName) { + $this->holderName = $holderName; + return $this; + } + + public function getBankName() { + return $this->bankName; + } + + public function setBankName($bankName) { + $this->bankName = $bankName; + return $this; + } + + public function getIban() { + return $this->iban; + } + + public function setIban($iban) { + $this->iban = $iban; + return $this; + } + + public function getBic() { + return $this->bic; + } + + public function setBic($bic) { + $this->bic = $bic; + return $this; + } + + public function getCountryCode() { + return $this->countryCode; + } + + public function setCountryCode($countryCode) { + $this->countryCode = $countryCode; + return $this; + } +} + +class RefundStatus { + /** + * Result code of the refund call + * + * @var Int + */ + private $code; + + /** + * Error message of the refund call + * + * @var String + */ + private $message; + + /** + * Transaction identifier of refund transaction. + * + * @var String + */ + private $transactionID; + + public function getCode() { + return $this->code; + } + + public function setCode($code) { + $this->code = $code; + return $this; + } + + public function getMessage() { + return $this->message; + } + + public function setMessage($message) { + $this->message = $message; + return $this; + } + + public function getTransactionID() { + return $this->transactionID; + } + + public function setTransactionID($transactionID) { + $this->transactionID = $transactionID; + return $this; + } +} + +class CartProduct { + // Fields are public otherwise json_encode can't see them... + public $cartProductId; + public $cartProductName; + public $cartProductUnitPrice; + public $cartProductQuantity; + public $cartProductBrand; + public $cartProductMPN; + public $cartProductCategoryName; + public $cartProductCategoryID; + + public function getCartProductId() { + return $this->cartProductId; + } + + public function setCartProductId($cartProductId) { + $this->cartProductId = $cartProductId; + return $this; + } + + public function getCartProductName() { + return $this->cartProductName; + } + + public function setCartProductName($cartProductName) { + $this->cartProductName = $cartProductName; + return $this; + } + + public function getCartProductUnitPrice() { + return $this->cartProductUnitPrice; + } + + public function setCartProductUnitPrice($cartProductUnitPrice) { + $this->cartProductUnitPrice = $cartProductUnitPrice; + return $this; + } + + public function getCartProductQuantity() { + return $this->cartProductQuantity; + } + + public function setCartProductQuantity($cartProductQuantity) { + $this->cartProductQuantity = $cartProductQuantity; + return $this; + } + + public function getCartProductBrand() { + return $this->cartProductBrand; + } + + public function setCartProductBrand($cartProductBrand) { + $this->cartProductBrand = $cartProductBrand; + return $this; + } + + public function getCartProductMPN() { + return $this->cartProductMPN; + } + + public function setCartProductMPN($cartProductMPN) { + $this->cartProductMPN = $cartProductMPN; + return $this; + } + + public function getCartProductCategoryName() { + return $this->cartProductCategoryName; + } + + public function setCartProductCategoryName($cartProductCategoryName) { + $this->cartProductCategoryName = $cartProductCategoryName; + return $this; + } + + public function getCartProductCategoryID() { + return $this->cartProductCategoryID; + } + + public function setCartProductCategoryID($cartProductCategoryID) { + $this->cartProductCategoryID = $cartProductCategoryID; + return $this; + } +} + +/** + * Helper to manipulate amount in different currencies. + * Permits to convert amount between different currencies + * and get rates in real time from Yahoo Web service. + */ +class Connect2PayCurrencyHelper { + // The base address to fetch currency rates + private static $YAHOO_SERVICE_URL = 'http://download.finance.yahoo.com/d/quotes.csv'; + + // Optional proxy to use for outgoing request + private static $proxy_host = null; + private static $proxy_port = null; + private static $proxy_username = null; + private static $proxy_password = null; + private static $currencies = array( /* */ + "AUD" => array("currency" => "Australian Dollar", "code" => "036", "symbol" => "$"), + "CAD" => array("currency" => "Canadian Dollar", "code" => "124", "symbol" => "$"), + "CHF" => array("currency" => "Swiss Franc", "code" => "756", "symbol" => "CHF"), + "DKK" => array("currency" => "Danish Krone", "code" => "208", "symbol" => "kr"), + "EUR" => array("currency" => "Euro", "code" => "978", "symbol" => "€"), + "GBP" => array("currency" => "Pound Sterling", "code" => "826", "symbol" => "£"), + "HKD" => array("currency" => "Hong Kong Dollar", "code" => "344", "symbol" => "$"), + "JPY" => array("currency" => "Yen", "code" => "392", "symbol" => "¥"), + "MXN" => array("currency" => "Mexican Peso", "code" => "484", "symbol" => "$"), + "NOK" => array("currency" => "Norwegian Krone", "code" => "578", "symbol" => "kr"), + "SEK" => array("currency" => "Swedish Krona", "code" => "752", "symbol" => "kr"), + "USD" => array("currency" => "US Dollar", "code" => "840", "symbol" => "$") /* */ + ); + + /** + * Set the parameter in the case of the use of an outgoing proxy + * + * @param string $host + * The proxy host. + * @param int $port + * The proxy port. + * @param string $username + * The proxy username. + * @param string $password + * The proxy password. + */ + public static function useProxy($host, $port, $username = null, $password = null) { + Connect2PayCurrencyHelper::$proxy_host = $host; + Connect2PayCurrencyHelper::$proxy_port = $port; + Connect2PayCurrencyHelper::$proxy_username = $username; + Connect2PayCurrencyHelper::$proxy_password = $password; + } + + /** + * Return the supported currencies array. + * + * @return Array of all the currencies supported. + */ + public static function getCurrencies() { + return array_keys(Connect2PayCurrencyHelper::$currencies); + } + + /** + * Get a currency alphabetic code according to its numeric code in ISO4217 + * + * @param string $code + * The numeric code to look for + * @return The alphabetic code (like EUR or USD) or null if not found. + */ + public static function getISO4217CurrencyFromCode($code) { + foreach (Connect2PayCurrencyHelper::$currencies as $currency => $data) { + if ($data["code"] == $code) { + return $currency; + } + } + + return null; + } + + /** + * Return the ISO4217 currency code. + * + * @param string $currency + * The currency to look for + * @return The ISO4217 code or null if not found + */ + public static function getISO4217CurrencyCode($currency) { + return (array_key_exists($currency, Connect2PayCurrencyHelper::$currencies)) ? Connect2PayCurrencyHelper::$currencies[$currency]["code"] : null; + } + + /** + * Return the currency symbol. + * + * @param string $currency + * The currency to look for + * @return The currency symbol or null if not found + */ + public static function getCurrencySymbol($currency) { + return (array_key_exists($currency, Connect2PayCurrencyHelper::$currencies)) ? Connect2PayCurrencyHelper::$currencies[$currency]["symbol"] : null; + } + + /** + * Return the currency name. + * + * @param string $currency + * The currency to look for + * @return The currency name or null if not found + */ + public static function getCurrencyName($currency) { + return (array_key_exists($currency, Connect2PayCurrencyHelper::$currencies)) ? Connect2PayCurrencyHelper::$currencies[$currency]["currency"] : null; + } + + /** + * Get a currency conversion rate from Yahoo webservice. + * + * @param string $from + * The source currency + * @param string $to + * The destination currency + */ + public static function getRate($from, $to) { + // Check if currencies exists + if (!Connect2PayCurrencyHelper::currencyIsAvailable($from) || !Connect2PayCurrencyHelper::currencyIsAvailable($to)) { + return null; + } + + // Build the request URL + $url = Connect2PayCurrencyHelper::$YAHOO_SERVICE_URL . "?s=" . $from . $to . "=X&f=l1&e=.csv"; + + // Do the request + $curl = curl_init($url); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + + if (Connect2PayCurrencyHelper::$proxy_host != null && Connect2PayCurrencyHelper::$proxy_port != null) { + curl_setopt($curl, CURLOPT_PROXY, Connect2PayCurrencyHelper::$proxy_host); + curl_setopt($curl, CURLOPT_PROXYPORT, Connect2PayCurrencyHelper::$proxy_port); + + if (Connect2PayCurrencyHelper::$proxy_username != null && Connect2PayCurrencyHelper::$proxy_password != null) { + curl_setopt($curl, CURLOPT_PROXYAUTH, CURLAUTH_BASIC); + curl_setopt($curl, CURLOPT_PROXYUSERPWD, + Connect2PayCurrencyHelper::$proxy_username . ":" . Connect2PayCurrencyHelper::$proxy_password); + } + } + + $csv = trim(curl_exec($curl)); + $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); + curl_close($curl); + + // Parse the CSV, we should only have a number, check this + if ($httpCode == 200 && preg_match('/^[0-9.]+$/', $csv)) { + return $csv; + } + + return null; + } + + /** + * Convert an amount from one currency to another + * + * @param int $amount + * The amount to convert + * @param string $from + * The source currency + * @param string $to + * The destination currency + * @param boolean $cent + * Specifies if the amount is in cent (default true) + * @return The converted amount or null in case of error + */ + public static function convert($amount, $from, $to, $cent = true) { + // Get the conversion rate + $rate = Connect2PayCurrencyHelper::getRate($from, $to); + + if ($rate != null) { + $convert = $amount * $rate; + + // If the amount was in cent, truncate the digit after the comma + // else round the result to 2 digits only + return ($cent) ? round($convert, 0) : round($convert, 2); + } + + return null; + } + + private static function currencyIsAvailable($currency) { + return array_key_exists($currency, Connect2PayCurrencyHelper::$currencies); + } +} + +/** + * Validation class + */ +class C2PValidate { + + /** + * Check for e-mail validity + * + * @param string $email + * e-mail address to validate + * @return boolean Validity is ok or not + */ + static public function isEmail($email) { + return C2PValidate::isEmpty($email) or + preg_match('/^[a-z0-9!#$%&\'*+\/=?^`{}|~_-]+[.a-z0-9!#$%&\'*+\/=?^`{}|~_-]*@[a-z0-9]+[._a-z0-9-]*\.[a-z0-9]+$/ui', $email); + } + + /** + * Check for IP validity + * + * @param string $ip + * IP address to validate + * @return boolean Validity is ok or not + */ + static public function isIP($ip) { + return C2PValidate::isEmpty($ip) or preg_match('/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/', $ip); + } + + /** + * Check for MD5 string validity + * + * @param string $md5 + * MD5 string to validate + * @return boolean Validity is ok or not + */ + static public function isMd5($md5) { + return preg_match('/^[a-f0-9A-F]{32}$/', $md5); + } + + /** + * Check for SHA1 string validity + * + * @param string $sha1 + * SHA1 string to validate + * @return boolean Validity is ok or not + */ + static public function isSha1($sha1) { + return preg_match('/^[a-fA-F0-9]{40}$/', $sha1); + } + + /** + * Check for a float number validity + * + * @param float $float + * Float number to validate + * @return boolean Validity is ok or not + */ + static public function isFloat($float) { + return strval((float) ($float)) == strval($float); + } + + static public function isUnsignedFloat($float) { + return strval((float) ($float)) == strval($float) and $float >= 0; + } + + /** + * Check for name validity + * + * @param string $name + * Name to validate + * @return boolean Validity is ok or not + */ + static public function isName($name) { + return preg_match('/^[^0-9!<>,;?=+()@#"°{}_$%:]*$/', stripslashes($name)); + } + + /** + * Check for a country name validity + * + * @param string $name + * Country name to validate + * @return boolean Validity is ok or not + */ + static public function isCountryName($name) { + return preg_match('/^[a-zA-Z -]+$/', $name); + } + + /** + * Check for a postal address validity + * + * @param string $address + * Address to validate + * @return boolean Validity is ok or not + */ + static public function isAddress($address) { + return empty($address) or preg_match('/^[^!<>?=+@{}_$%]*$/', $address); + } + + /** + * Check for city name validity + * + * @param string $city + * City name to validate + * @return boolean Validity is ok or not + */ + static public function isCityName($city) { + return preg_match('/^[^!<>;?=+@#"°{}_$%]*$/', $city); + } + + /** + * Check for date format + * + * @param string $date + * Date to validate + * @return boolean Validity is ok or not + */ + static public function isDateFormat($date) { + return (bool) preg_match('/^([0-9]{4})-((0?[0-9])|(1[0-2]))-((0?[1-9])|([0-2][0-9])|(3[01]))( [0-9]{2}:[0-9]{2}:[0-9]{2})?$/', $date); + } + + /** + * Check for date validity + * + * @param string $date + * Date to validate + * @return boolean Validity is ok or not + */ + static public function isDate($date) { + if (!preg_match('/^([0-9]{4})-((0?[1-9])|(1[0-2]))-((0?[1-9])|([1-2][0-9])|(3[01]))( [0-9]{2}:[0-9]{2}:[0-9]{2})?$/', $date, $matches)) + return false; + return checkdate((int) $matches[2], (int) $matches[5], (int) $matches[0]); + } + + /** + * Check for boolean validity + * + * @param boolean $bool + * Boolean to validate + * @return boolean Validity is ok or not + */ + static public function isBool($bool) { + return is_null($bool) or is_bool($bool) or preg_match('/^0|1$/', $bool); + } + + /** + * Check for phone number validity + * + * @param string $phoneNumber + * Phone number to validate + * @return boolean Validity is ok or not + */ + static public function isPhoneNumber($phoneNumber) { + return preg_match('/^[+0-9. ()-;]*$/', $phoneNumber); + } + + /** + * Check for postal code validity + * + * @param string $postcode + * Postal code to validate + * @return boolean Validity is ok or not + */ + static public function isPostCode($postcode) { + return empty($postcode) or preg_match('/^[a-zA-Z 0-9-]+$/', $postcode); + } + + /** + * Check for zip code format validity + * + * @param string $zip_code + * zip code format to validate + * @return boolean Validity is ok or not + */ + static public function isZipCodeFormat($zip_code) { + if (!empty($zip_code)) + return preg_match('/^[NLCnlc -]+$/', $zip_code); + return true; + } + + /** + * Check for an integer validity + * + * @param integer $id + * Integer to validate + * @return boolean Validity is ok or not + */ + static public function isInt($value) { + return ((string) (int) $value === (string) $value or $value === false or empty($value)); + } + + /** + * Check for an integer validity (unsigned) + * + * @param integer $id + * Integer to validate + * @return boolean Validity is ok or not + */ + static public function isUnsignedInt($value) { + return (preg_match('#^[0-9]+$#', (string) $value) and $value < 4294967296 and $value >= 0); + } + + /** + * Check url valdity (disallowed empty string) + * + * @param string $url + * Url to validate + * @return boolean Validity is ok or not + */ + static public function isUrl($url) { + return preg_match('/^[~:#%&_=\(\)\.\? \+\-@\/a-zA-Z0-9]+$/', $url); + } + + /** + * Check object validity + * + * @param integer $object + * Object to validate + * @return boolean Validity is ok or not + */ + static public function isAbsoluteUrl($url) { + if (!empty($url)) + return preg_match('/^https?:\/\/[:#%&_=\(\)\.\? \+\-@\/a-zA-Z0-9]+$/', $url); + return true; + } + + /** + * String validity (PHP one) + * + * @param string $data + * Data to validate + * @return boolean Validity is ok or not + */ + static public function isString($data) { + return is_string($data); + } + + /** + * Shipping Type validity + * + * @param string $shipping + * Shipping Type to validate + * @return boolean Validity is ok or not + */ + static public function isShippingType($shipping) { + return ((string) $shipping == "Physical" || (string) $shipping == "Virtual" || (string) $shipping == "Access"); + } + + /** + * Payment Mean validity + * + * @param string $payment + * Payment Mean to validate + * @return boolean Validity is ok or not + */ + static public function isPayment($payment) { + return ((string) $payment == Connect2PayClient::_PAYMENT_TYPE_CREDITCARD || + (string) $payment == Connect2PayClient::_PAYMENT_TYPE_TODITOCASH || + (string) $payment == Connect2PayClient::_PAYMENT_TYPE_BANKTRANSFER); + } + + /** + * Provider validity + * + * @param string $provider + * Provider to validate + * @return boolean Validity is ok or not + */ + static public function isProvider($provider) { + return ((string) $provider == Connect2PayClient::_PAYMENT_PROVIDER_SOFORT || + (string) $provider == Connect2PayClient::_PAYMENT_PROVIDER_PRZELEWY24 || + (string) $provider == Connect2PayClient::_PAYMENT_PROVIDER_IDEALKP); + } + + /** + * Operation validity + * + * @param string $operation + * Operation to validate + * @return boolean Validity is ok or not + */ + static public function isOperation($operation) { + return ((string) $operation == Connect2PayClient::_OPERATION_TYPE_SALE || + (string) $operation == Connect2PayClient::_OPERATION_TYPE_AUTHORIZE); + } + + /** + * Payment Type validity + * + * @param string $paymentMode + * Payment Mode to validate + * @return boolean Validity is ok or not + */ + static public function isPaymentMode($paymentMode) { + return ((string) $paymentMode == Connect2PayClient::_PAYMENT_MODE_SINGLE || + (string) $paymentMode == Connect2PayClient::_PAYMENT_MODE_ONSHIPPING || + (string) $paymentMode == Connect2PayClient::_PAYMENT_MODE_RECURRENT || + (string) $paymentMode == Connect2PayClient::_PAYMENT_MODE_INSTALMENTS); + } + + /** + * Subscription Type validity + * + * @param string $subscriptionType + * Subscription Type to validate + * @return boolean Validity is ok or not + */ + static public function isSubscriptionType($subscriptionType) { + return ((string) $subscriptionType == Connect2PayClient::_SUBSCRIPTION_TYPE_NORMAL || + (string) $subscriptionType == Connect2PayClient::_SUBSCRIPTION_TYPE_INFINITE || + (string) $subscriptionType == Connect2PayClient::_SUBSCRIPTION_TYPE_ONETIME || + (string) $subscriptionType == Connect2PayClient::_SUBSCRIPTION_TYPE_LIFETIME); + } + + /** + * Test if a variable is set + * + * @param mixed $field + * @return boolean field is set or not + */ + public static function isEmpty($field) { + return ($field === '' or $field === NULL); + } + + /** + * strlen overloaded function + * + * @param string $str + * @return int size of the string + */ + public static function strlen($str) { + if (is_array($str)) + return false; + + if (function_exists('mb_strlen')) + return mb_strlen($str, 'UTF-8'); + + return strlen($str); + } +} + +class Utils { + + public static function deprecation_error($message) { + trigger_error($message, version_compare(phpversion(), '5.3.0', '<') ? E_USER_NOTICE : E_USER_DEPRECATED); + } +} diff --git a/modules/payxpert/logo.gif b/modules/payxpert/logo.gif new file mode 100644 index 0000000000000000000000000000000000000000..69a9bbb824049944ac79a2ae5c490168ca948c96 GIT binary patch literal 591 zcmV-V0loR6&TIT%6y@_n5VMw^Yr%i z_Q}f1t-i|f^Yz5e*V@_Fd!fB8E-%Z+!?niLqrK77-{!H#)!*LS_4M?+!@T|e{qOPf z%*@KHx4*&8*SWW~r@6?YywCLV@b&QR)zs3gsicLXy7~F}a+R;k%gM3A&wrPy#mUFu z-P-Bu>i78g_4W0+$<%F|yt&5FTv0u@=;Yqd*xl;u?99!~j;p-z@bTf~;x{!i{QUc? zzs%^~*6{7;c%{M4&dpw4UiSC+=+1goTEOh=UtciG*kqATy16auyvtX;~v8hj4F9aVTMVd20ZLHYx}! zcTRZ{5qNfkXATr}brpF^W_WWYH(+{K3?U{Sc};D2csXMNSOa5P%m7U|>LEgb08xMS>g=azaBO06RnDSxf)` literal 0 HcmV?d00001 diff --git a/modules/payxpert/logo.png b/modules/payxpert/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..b56962efe3d8b6b24e47d7d581200737044a522b GIT binary patch literal 2472 zcmV;Z30L-sP)Qb$_pnS89y+s^ zZPVwx$Nk@;YaHT^Y1UdCv-U&NuK$4(eXm(g9cA4_cT*T&=twRF{A0{UZ1b;)S1+B%dxNEI7*y~uxtkx%k57Df!iT^ctxu=b+^xav%7mv zpW~Gwg=5QkLHw;@7^ud48 z;5SUmzDqMK#KHmU1QQ_Nd-kW}Kv}CI8VYV&vS|MLoB@20 z9EIO5BOwF1DvxB@hDYF$H#o#X{{D{U_zN@J+t*IFY}D=AO{bH?FYej9KjZiL-C`~} z0mfXVT;W?=65Hm_?YcRcDI%2`MN?D;?}$jLHRR}AF>N>%1xs3^Sas>bNFo+p%Niew zMF|HL4?nv3iEZ0oxN%xz+=cSLCh%dh^>nuF?CfY?I+!jXo0-7;1_xEUiXlaSYRhy@ z1?>%9T(__ri)J^|%`~7dbX;D*a*U|G*h#t*3Iqc4WZCa(%{dDGO9HGrT2+Vd?_~2~FgXs7UcxlVfui$xJ7a;W z!HPK%Ts40d;tgS{l`4{g$YoO4*8d{S!e|_&4SFZSGwW>d5 zxe0tk2g=0sNI1CZvP*i`D~5xi;WRzEj<_V?bgqJo;lZVCFj2^}plQbTID6oO-@ z7}(K|XSQv}d&f`0!`G4gV90&u*KfZS8#mmI_O45iK6B#HkyQHk!H`%z$A$Vo5>P7| zk*#T4Z};q*)44KInJIV$4~n{tv3w0JksxkcHUo=05~LmsXFny!;f(|PvE_Hq;q^Z= zcpaRb7(=C^;@WGj!hIWlj1||d25Jh%M}|({=PrlW^@NT}U)WU^AS3VH9%{*uG;69Roay{`~BE(@7?(BcfO5C zLj>a!ITTAO$hr`V$Dmh9KzIjoAPC8)KB=nZRjdmFN9`o@c=C91^!89RPJ-frS~Ve3 zJC}FHkeC)BoWt-~8eZ8sfTxMwhYlYloH;izOW@X9)?ocTcVTW%4@T1yD5Z0l+1iG- z*&+sy97dr~q@XfvnjD%gNRof$y<%EaavpQ7RU2#pjl}Rj*!s9VRCW7&@IoqNNp~Pymc#X3a#6S+`Y# zSEBJFyJl~8Ccj+c*ml2QlUXoE(rE0+<)(Ur4UPBPAafyh2>F9}aO+EW{*QZ6R*E#! z8phHoG&eQj;m04t*KX+p^O_Swqlh&o(Am{W`vS)}Vgk(exg(6^uvd>E;1^Gf@ zhi%zEa?Pkh3&aK4rT0dMFU+HnUURh6LhQ}sz`mDo`cwvGHAijd@q_Q*Nyi78$Oo#c z9F9Nb17e8H!p2|z8uzUGDh$oR;IR{!)zL-c6mYknYPCuRHG=HqSt@|X^yvxeB+pEY zx>jMqA0zd9!0Ywo1vdM159`!<*dcuB%0<}q<}nzmjmB`$WjD=dzFJXN+Tad}gohrR zgXF0+I7^4j+wX?O8xh{b64lc?PWX@W|XmtLld@1<5B6$l=;(}T~?3SjNkT^K%F zgdBTQnsQoEnpCcqKHOHc)^1C z;6_GM@N#4{l=ZtOhw+yaDGW^%$Z$kD1Q2=e<9vbpD`ZmNx~fZG+SBG69zRRsB_a}O zAPuoe2{jTOYPPCAK#4!X$jSn-%Gs2$ab$ms2j3sX;gKxHi61_J-zXV6%GKJjbY?Q!JG1fiL{l?aws{U`V!NW2pP)5tlO#!F zl23HuVGC-NIKxpgUauE^Nk%vlf-Ij~|Ji+v6T*cZz@e6B%bKfJ%jYzsBQ9f*qT&ouugL9P6Pn7+?2^nPNvI|&-? zjqKsfWql;OehTb4Prm>7%ZQH7^JnM7i-}2$RY{}-nu^{=*QS*0{?F5cY5{Uoqh;2t{I5@-I~dd99GXtbKm$jE}bBSfuc$x`Qej&OG& mWR-HisLogged()) { + Tools::redirect('authentication.php?back=order.php'); +} + +$payxpert = new PayXpert(); +echo $payxpert->execPayment($cart); + +require_once(dirname(__FILE__) . '/../../footer.php'); \ No newline at end of file diff --git a/modules/payxpert/payxpert.php b/modules/payxpert/payxpert.php new file mode 100644 index 0000000..8936968 --- /dev/null +++ b/modules/payxpert/payxpert.php @@ -0,0 +1,976 @@ +name = 'payxpert'; + $this->version = '1.0.8'; + + $this->tab = 'payments_gateways'; + + $this->author = 'PayXpert'; + $this->need_instance = 1; + + $this->controllers = array('payment', 'validation'); + $this->is_eu_compatible = 1; + + if (version_compare(_PS_VERSION_, '1.5', '>=')) { + $this->ps_versions_compliancy = array('min' => '1.4.0.0', 'max' => _PS_VERSION_); + } + + if (version_compare(_PS_VERSION_, '1.6', '>=')) { + $this->bootstrap = true; + } + + parent::__construct(); + + $this->displayName = 'PayXpert Payment Solutions'; + $this->description = $this->l("Accept payments today with PayXpert"); + $this->confirmUninstall = $this->l('Are you sure about removing these details?'); + + if (!count(Currency::checkPaymentCurrencies($this->id))) { + $this->warning = $this->l('No currency has been set for this module.'); + } + + /* For 1.4.3 and less compatibility */ + $updateConfig = array('PS_OS_CHEQUE' => 1, 'PS_OS_PAYMENT' => 2, 'PS_OS_PREPARATION' => 3, 'PS_OS_SHIPPING' => 4, + 'PS_OS_DELIVERED' => 5, 'PS_OS_CANCELED' => 6, 'PS_OS_REFUND' => 7, 'PS_OS_ERROR' => 8, 'PS_OS_OUTOFSTOCK' => 9, + 'PS_OS_BANKWIRE' => 10, 'PS_OS_PAYPAL' => 11, 'PS_OS_WS_PAYMENT' => 12); + + foreach ($updateConfig as $u => $v) { + if (!Configuration::get($u) || (int) Configuration::get($u) < 1) { + if (defined('_' . $u . '_') && (int) constant('_' . $u . '_') > 0) { + Configuration::updateValue($u, constant('_' . $u . '_')); + } else { + Configuration::updateValue($u, $v); + } + } + } + } + + /** + * Install method + */ + public function install() { + // call parents + if (!parent::install()) { + $errorMessage = Tools::displayError($this->l('PayXpert installation : install failed.')); + $this->addLog($errorMessage, 3, '000002'); + return false; + } + + // Add hook methods + $hookResult = $this->registerHook('paymentReturn'); + if (version_compare(_PS_VERSION_, '1.7', '<')) { + $hookResult = $hookResult && $this->registerHook('payment'); + } else { + $hookResult = $hookResult && $this->registerHook('paymentOptions'); + } + + if (!$hookResult) { + $errorMessage = Tools::displayError($this->l('PayXpert installation : hooks failed.')); + $this->addLog($errorMessage, 3, '000002'); + + return false; + } + + // Add configuration parameters + foreach ($this->getModuleParameters() as $parameter) { + if (!Configuration::updateValue($parameter, '')) { + $errorMessage = Tools::displayError($this->l('PayXpert installation : configuration failed.')); + $this->addLog($errorMessage, 3, '000002'); + + return false; + } + } + + $this->addLog($this->l('PayXpert installation : installation successful')); + + return true; + } + + /** + * Uninstall the module + * + * @return boolean + */ + public function uninstall() { + $result = parent::uninstall(); + + foreach ($this->getModuleParameters() as $parameter) { + $result = $result || Configuration::deleteByName($parameter); + } + + return $result; + } + + private function getModuleParameters() { + $moduleParameters = array( /* */ + 'PAYXPERT_ORIGINATOR', /* */ + 'PAYXPERT_PASSWORD', /* */ + 'PAYXPERT_URL', /* */ + 'PAYXPERT_MERCHANT_NOTIF', /* */ + 'PAYXPERT_MERCHANT_NOTIF_TO', /* */ + 'PAYXPERT_MERCHANT_NOTIF_LANG' /* */ + ); + + if (version_compare(_PS_VERSION_, '1.7', '>=')) { + $moduleParameters[] = 'PAYXPERT_PAYMENT_TYPE_CREDIT_CARD'; + $moduleParameters[] = 'PAYXPERT_PAYMENT_TYPE_BANK_TRANSFERT_SOFORT'; + $moduleParameters[] = 'PAYXPERT_PAYMENT_TYPE_BANK_TRANSFERT_PRZELEWY24'; + $moduleParameters[] = 'PAYXPERT_PAYMENT_TYPE_BANK_TRANSFERT_IDEAL'; + } + + return $moduleParameters; + } + + public function checkPaymentOption($params) { + // if module disabled, can't go through + if (!$this->active) { + return false; + } + + // Check if currency ok + if (!$this->checkCurrency($params['cart'])) { + return false; + } + + // Check if module is configured + if (Configuration::get('PAYXPERT_ORIGINATOR') == "" && Configuration::get('PAYXPERT_PASSWORD') == "") { + return false; + } + + return true; + } + + /** + * Hook payment options + * + * @since Prestashop 1.7 + * @param type $params + * @return type + */ + public function hookPaymentOptions($params) { + if (!$this->checkPaymentOption($params)) { + return; + } + + $this->smarty->assign($this->getTemplateVarInfos()); + + $payment_options = array(); + + $ccOption = $this->getCreditCardPaymentOption(); + if ($ccOption != null) { + $payment_options[] = $ccOption; + } + $sofortOption = $this->getBankTransferViaSofortPaymentOption(); + if ($sofortOption != null) { + $payment_options[] = $sofortOption; + } + $przelewy24Option = $this->getBankTransferViaPrzelewy24PaymentOption(); + if ($przelewy24Option != null) { + $payment_options[] = $przelewy24Option; + } + $idealOption = $this->getBankTransferViaIDealPaymentOption(); + if ($idealOption != null) { + $payment_options[] = $idealOption; + } + + return $payment_options; + } + + /** + * + * @since Prestashop 1.7 + */ + public function getCreditCardPaymentOption() { + if (Configuration::get('PAYXPERT_PAYMENT_TYPE_CREDIT_CARD') == "true") { + $option = new PrestaShop\PrestaShop\Core\Payment\PaymentOption(); + $option->setCallToActionText($this->l('Pay by Credit Card')); + $option->setAction( + $this->context->link->getModuleLink($this->name, 'payment', + array('payment_type' => PayXpert\Connect2Pay\Connect2PayClient::_PAYMENT_TYPE_CREDITCARD), true)); + + $this->context->smarty->assign('pxpCCLogo', + Media::getMediaPath(_PS_MODULE_DIR_ . $this->name . '/images/payment-types/creditcard.png')); + $option->setAdditionalInformation( + $this->context->smarty->fetch('module:payxpert/views/templates/front/payment_infos_credit_card.tpl')); + + return $option; + } + + return null; + } + + /** + * + * @since Prestashop 1.7 + */ + public function getBankTransferViaSofortPaymentOption() { + if (Configuration::get('PAYXPERT_PAYMENT_TYPE_BANK_TRANSFERT_SOFORT') == "true") { + $option = new PrestaShop\PrestaShop\Core\Payment\PaymentOption(); + $option->setCallToActionText($this->l('Pay by Bank Transfer via Sofort')); + $option->setAction( + $this->context->link->getModuleLink($this->name, 'payment', + array('payment_type' => PayXpert\Connect2Pay\Connect2PayClient::_PAYMENT_TYPE_BANKTRANSFER, + 'payment_provider' => PayXpert\Connect2Pay\Connect2PayClient::_PAYMENT_PROVIDER_SOFORT), true)); + + $this->context->smarty->assign("pxpSofortLogo", + Media::getMediaPath(_PS_MODULE_DIR_ . $this->name . '/images/payment-types/sofort.png')); + $option->setAdditionalInformation( + $this->context->smarty->fetch('module:payxpert/views/templates/front/payment_infos_bank_transfer_sofort.tpl')); + + return $option; + } + + return null; + } + + /** + * + * @since Prestashop 1.7 + */ + public function getBankTransferViaPrzelewy24PaymentOption() { + if (Configuration::get('PAYXPERT_PAYMENT_TYPE_BANK_TRANSFERT_PRZELEWY24') == "true") { + $option = new PrestaShop\PrestaShop\Core\Payment\PaymentOption(); + $option->setCallToActionText($this->l('Pay by Bank Transfer via Przelewy24')); + $option->setAction( + $this->context->link->getModuleLink($this->name, 'payment', + array('payment_type' => PayXpert\Connect2Pay\Connect2PayClient::_PAYMENT_TYPE_BANKTRANSFER, + 'payment_provider' => PayXpert\Connect2Pay\Connect2PayClient::_PAYMENT_PROVIDER_PRZELEWY24), true)); + + $this->context->smarty->assign("pxpPrzelewy24Logo", + Media::getMediaPath(_PS_MODULE_DIR_ . $this->name . '/images/payment-types/przelewy24.png')); + $option->setAdditionalInformation( + $this->context->smarty->fetch('module:payxpert/views/templates/front/payment_infos_bank_transfer_przelewy24.tpl')); + + return $option; + } + + return null; + } + + /** + * + * @since Prestashop 1.7 + */ + public function getBankTransferViaIDealPaymentOption() { + if (Configuration::get('PAYXPERT_PAYMENT_TYPE_BANK_TRANSFERT_IDEAL') == "true") { + $option = new PrestaShop\PrestaShop\Core\Payment\PaymentOption(); + $option->setCallToActionText($this->l('Pay by Bank Transfer via iDeal')); + $option->setAction( + $this->context->link->getModuleLink($this->name, 'payment', + array('payment_type' => PayXpert\Connect2Pay\Connect2PayClient::_PAYMENT_TYPE_BANKTRANSFER, + 'payment_provider' => PayXpert\Connect2Pay\Connect2PayClient::_PAYMENT_PROVIDER_IDEALKP), true)); + + $this->context->smarty->assign("pxpIdealLogo", Media::getMediaPath(_PS_MODULE_DIR_ . $this->name . '/images/payment-types/ideal.png')); + $option->setAdditionalInformation( + $this->context->smarty->fetch('module:payxpert/views/templates/front/payment_infos_bank_transfer_ideal.tpl')); + + return $option; + } + + return null; + } + + public function getTemplateVarInfos() { + $cart = $this->context->cart; + + return array(/* */ + 'nbProducts' => $cart->nbProducts(), /* */ + 'cust_currency' => $cart->id_currency, /* */ + 'total' => $cart->getOrderTotal(true, Cart::BOTH), /* */ + 'isoCode' => $this->context->language->iso_code /* */ + ); + } + + /** + * Hook payment for Prestashop < 1.7 + * + * @param type $params + * @return type + */ + public function hookPayment($params) { + if (!$this->checkPaymentOption($params)) { + return; + } + + $this->assignSmartyVariable('this_path', $this->_path); + $this->assignSmartyVariable('this_path_ssl', + (Configuration::get('PS_SSL_ENABLED') ? 'https://' : 'http://') . htmlspecialchars($_SERVER['HTTP_HOST'], ENT_COMPAT, 'UTF-8') . + __PS_BASE_URI__ . 'modules/payxpert/'); + $this->assignSmartyVariable('this_link', $this->getModuleLinkCompat('payxpert', 'payment')); + + if (version_compare(_PS_VERSION_, '1.6.0', '>=') === true) { + $this->context->controller->addCSS($this->_path . 'css/payxpert.css'); + } + + return $this->display(__FILE__, 'views/templates/hook/payment.tpl'); + } + + /** + * Hook paymentReturn + * + * Displays order confirmation + * + * @param type $params + * @return type + */ + public function hookPaymentReturn($params) { + if (!$this->active) { + return; + } + + if (isset($params['objOrder'])) { + // For Prestashop < 1.7 + $order = $params['objOrder']; + } else { + $order = $params['order']; + } + + switch ($order->getCurrentState()) { + case _PS_OS_PAYMENT_: + case _PS_OS_OUTOFSTOCK_: + $this->assignSmartyVariable('status', 'ok'); + break; + + case _PS_OS_BANKWIRE_: + $this->assignSmartyVariable('status', 'pending'); + break; + + case _PS_OS_ERROR_: + default: + $this->assignSmartyVariable('status', 'failed'); + break; + } + + $this->assignSmartyVariable('this_link_contact', $this->getPageLinkCompat('contact', true)); + + return $this->display(__FILE__, 'views/templates/hook/orderconfirmation.tpl'); + } + + /** + * Init the payment + * + * In this method, we'll start to initialize the transaction + * And redirect the customer + * + * For Prestashop >= 1.5 + * + * @global type $cookie + * @param Cart $cart + * @return type + */ + public function redirect($cart, $paymentType = null, $paymentProvider = null) { + // if module disabled, can't go through + if (!$this->active) { + return "Module is not active"; + } + + // Check if currency ok + if (!$this->checkCurrency($cart)) { + return "Incorrect currency"; + } + + // Check if module is configured + if (Configuration::get('PAYXPERT_ORIGINATOR') == "" && Configuration::get('PAYXPERT_PASSWORD') == "") { + return "Module is not setup"; + } + + if ($paymentType == null || !PayXpert\Connect2Pay\C2PValidate::isPayment($paymentType)) { + $paymentType = PayXpert\Connect2Pay\Connect2PayClient::_PAYMENT_TYPE_CREDITCARD; + } + + if (!$this->checkPaymentTypeAndProvider($paymentType, $paymentProvider)) { + return "Payment type or provider is not enabled"; + } + + // get all informations + $customer = new Customer((int) ($cart->id_customer)); + $currency = new Currency((int) ($cart->id_currency)); + $carrier = new Carrier((int) ($cart->id_carrier)); + $addr_delivery = new Address((int) ($cart->id_address_delivery)); + $addr_invoice = new Address((int) ($cart->id_address_invoice)); + + $invoice_state = new State((int) ($addr_invoice->id_state)); + $invoice_country = new Country((int) ($addr_invoice->id_country)); + + $delivery_state = new State((int) ($addr_delivery->id_state)); + $delivery_country = new Country((int) ($addr_delivery->id_country)); + + $invoice_phone = (!empty($addr_invoice->phone)) ? $addr_invoice->phone : $addr_invoice->phone_mobile; + $delivery_phone = (!empty($addr_delivery->phone)) ? $addr_delivery->phone : $addr_delivery->phone_mobile; + + // init api + $c2pClient = new PayXpert\Connect2Pay\Connect2PayClient($this->getPayXpertUrl(), Configuration::get('PAYXPERT_ORIGINATOR'), + html_entity_decode(Configuration::get('PAYXPERT_PASSWORD'))); + + // customer informations + $c2pClient->setShopperID($cart->id_customer); + $c2pClient->setShopperEmail($customer->email); + $c2pClient->setShopperFirstName(substr($customer->firstname, 0, 35)); + $c2pClient->setShopperLastName(substr($customer->lastname, 0, 35)); + $c2pClient->setShopperCompany(substr($addr_invoice->company, 0, 128)); + $c2pClient->setShopperAddress(substr(trim($addr_invoice->address1 . ' ' . $addr_invoice->address2), 0, 255)); + $c2pClient->setShopperZipcode(substr($addr_invoice->postcode, 0, 10)); + $c2pClient->setShopperCity(substr($addr_invoice->city, 0, 50)); + $c2pClient->setShopperState(substr($invoice_state->name, 0, 30)); + $c2pClient->setShopperCountryCode($invoice_country->iso_code); + $c2pClient->setShopperPhone(substr(trim($invoice_phone), 0, 20)); + + // Shipping information + $c2pClient->setShipToFirstName(substr($addr_delivery->firstname, 0, 35)); + $c2pClient->setShipToLastName(substr($addr_delivery->lastname, 0, 35)); + $c2pClient->setShipToCompany(substr($addr_delivery->company, 0, 128)); + $c2pClient->setShipToPhone(substr(trim($delivery_phone), 0, 20)); + $c2pClient->setShipToAddress(substr(trim($addr_delivery->address1 . " " . $addr_delivery->address2), 0, 255)); + $c2pClient->setShipToZipcode(substr($addr_delivery->postcode, 0, 10)); + $c2pClient->setShipToCity(substr($addr_delivery->city, 0, 50)); + $c2pClient->setShipToState(substr($delivery_state->name, 0, 30)); + $c2pClient->setShipToCountryCode($delivery_country->iso_code); + $c2pClient->setShippingName(substr($carrier->name, 0, 50)); + $c2pClient->setShippingType(PayXpert\Connect2Pay\Connect2PayClient::_SHIPPING_TYPE_PHYSICAL); + + // Order informations + $c2pClient->setOrderID(substr(pSQL($cart->id), 0, 100)); + $c2pClient->setOrderDescription(substr($this->l('Invoice:') . pSQL($cart->id), 0, 255)); + $c2pClient->setCustomerIP($_SERVER['REMOTE_ADDR']); + $c2pClient->setCurrency($currency->iso_code); + + $total = number_format($cart->getOrderTotal(true, 3) * 100, 0, '.', ''); + + $c2pClient->setAmount($total); + $c2pClient->setOrderCartContent($this->getProductsApi($cart)); + $c2pClient->setPaymentMode(PayXpert\Connect2Pay\Connect2PayClient::_PAYMENT_MODE_SINGLE); + $c2pClient->setPaymentType($paymentType); + if ($paymentProvider != null && PayXpert\Connect2Pay\C2PValidate::isProvider($paymentProvider)) { + $c2pClient->setProvider($paymentProvider); + } + $c2pClient->setCtrlCustomData(PayXpert::getCallbackAuthenticityData($c2pClient->getOrderID(), $customer->secure_key)); + + // Merchant notifications + if (Configuration::get('PAYXPERT_MERCHANT_NOTIF') === "true" && Configuration::get('PAYXPERT_MERCHANT_NOTIF_TO')) { + $c2pClient->setMerchantNotification(true); + $c2pClient->setMerchantNotificationTo(Configuration::get('PAYXPERT_MERCHANT_NOTIF_TO')); + if (Configuration::get('PAYXPERT_MERCHANT_NOTIF_LANG')) { + $c2pClient->setMerchantNotificationLang(Configuration::get('PAYXPERT_MERCHANT_NOTIF_LANG')); + } + } + + $ctrlURLPrefix = Configuration::get('PS_SSL_ENABLED') ? 'https://' : 'http://'; + + if (version_compare(_PS_VERSION_, '1.5', '<')) { + $c2pClient->setCtrlCallbackURL($ctrlURLPrefix . $_SERVER['HTTP_HOST'] . __PS_BASE_URI__ . 'modules/payxpert/validation.php'); + $c2pClient->setCtrlRedirectURL( + $ctrlURLPrefix . $_SERVER['HTTP_HOST'] . __PS_BASE_URI__ . 'order-confirmation.php?id_cart=' . (int) ($cart->id) . '&id_module=' . + (int) ($this->id) . '&key=' . $customer->secure_key); + } else { + $c2pClient->setCtrlCallbackURL($this->context->link->getModuleLink('payxpert', 'validation')); + $c2pClient->setCtrlRedirectURL( + $ctrlURLPrefix . $_SERVER['HTTP_HOST'] . __PS_BASE_URI__ . 'index.php?controller=order-confirmation&id_cart=' . (int) ($cart->id) . + '&id_module=' . (int) ($this->id) . '&key=' . $customer->secure_key); + } + + // prepare API + if ($c2pClient->preparePayment() == false) { + $message = "PayXpert : can't prepare transaction - " . $c2pClient->getClientErrorMessage(); + $this->addLog($message, 3); + return $message; + } + + header('Location: ' . $c2pClient->getCustomerRedirectURL()); + exit(); + } + + /** + * Return array of product to fill Api Product properties + * + * @param Cart $cart + * @return array + */ + protected function getProductsApi($cart) { + $products = array(); + + foreach ($cart->getProducts() as $product) { + $obj = new Product((int) $product['id_product']); + $products[] = array( /* */ + 'CartProductId' => $product['id_product'], /* */ + 'CartProductName' => $product['name'], /* */ + 'CartProductUnitPrice' => $product['price'], /* */ + 'CartProductQuantity' => $product['quantity'], /* */ + 'CartProductBrand' => $obj->manufacturer_name, /* */ + 'CartProductMPN' => $product['ean13'], /* */ + 'CartProductCategoryName' => $product['category'], /* */ + 'CartProductCategoryID' => $product['id_category_default'] /* */ + ); + } + + return $products; + } + + public function getContent() { + if (Tools::isSubmit('btnSubmit')) { + $this->_postValidation(); + + if (!count($this->_postErrors)) { + $this->_postProcess(); + } else { + foreach ($this->_postErrors as $err) { + $this->_html .= $this->displayError($err); + } + } + } else { + $this->_html .= '
'; + } + + $this->_html .= $this->display(__FILE__, '/views/templates/admin/infos.tpl'); + + if (version_compare(_PS_VERSION_, '1.6', '<')) { + /* Prestashop parameter names must not exceed 32 chars for v < 1.6 */ + $this->assignSmartyVariable('PAYXPERT_ORIGINATOR', + Tools::safeOutput(Tools::getValue('PAYXPERT_ORIGINATOR', Configuration::get('PAYXPERT_ORIGINATOR')))); + $this->assignSmartyVariable('PAYXPERT_URL', Tools::safeOutput(Tools::getValue('PAYXPERT_URL', Configuration::get('PAYXPERT_URL')))); + + $merchantNotifications = (Configuration::get('PAYXPERT_MERCHANT_NOTIF') == "true") ? "true" : "false"; + if (Tools::getValue('PAYXPERT_MERCHANT_NOTIF')) { + $merchantNotifications = (in_array(Tools::getValue('PAYXPERT_MERCHANT_NOTIF'), array("true", "1", "on"))) ? "true" : "false"; + } + $this->assignSmartyVariable('PAYXPERT_MERCHANT_NOTIF', $merchantNotifications); + $this->assignSmartyVariable('PAYXPERT_MERCHANT_NOTIF_TO', + Tools::safeOutput(Tools::getValue('PAYXPERT_MERCHANT_NOTIF_TO', Configuration::get('PAYXPERT_MERCHANT_NOTIF_TO')))); + $this->assignSmartyVariable('PAYXPERT_MERCHANT_NOTIF_LANG', + Tools::safeOutput(Tools::getValue('PAYXPERT_MERCHANT_NOTIF_LANG', Configuration::get('PAYXPERT_MERCHANT_NOTIF_LANG')))); + + $this->_html .= $this->display(__FILE__, '/views/templates/admin/config.tpl'); + } else { + $this->_html .= $this->renderForm(); + } + + return $this->_html; + } + + public function getConfigFieldsValues() { + // Handle checkboxes + $merchantNotif = Tools::getValue('PAYXPERT_MERCHANT_NOTIF', Configuration::get('PAYXPERT_MERCHANT_NOTIF')); + + $result = array( /* */ + 'PAYXPERT_ORIGINATOR' => Tools::getValue('PAYXPERT_ORIGINATOR', Configuration::get('PAYXPERT_ORIGINATOR')), /* */ + 'PAYXPERT_URL' => Tools::getValue('PAYXPERT_URL', Configuration::get('PAYXPERT_URL')), /* */ + 'PAYXPERT_MERCHANT_NOTIF' => ($merchantNotif === "true" || $merchantNotif == 1) ? 1 : 0, /* */ + 'PAYXPERT_MERCHANT_NOTIF_TO' => Tools::getValue('PAYXPERT_MERCHANT_NOTIF_TO', Configuration::get('PAYXPERT_MERCHANT_NOTIF_TO')), /* */ + 'PAYXPERT_MERCHANT_NOTIF_LANG' => Tools::getValue('PAYXPERT_MERCHANT_NOTIF_LANG', + Configuration::get('PAYXPERT_MERCHANT_NOTIF_LANG')), /* */ + ); + + if (version_compare(_PS_VERSION_, '1.7', '>=')) { + $creditCardPaymentType = Tools::getValue('PAYXPERT_PAYMENT_TYPE_CREDIT_CARD', Configuration::get('PAYXPERT_PAYMENT_TYPE_CREDIT_CARD')); + $sofortPaymentType = Tools::getValue('PAYXPERT_PAYMENT_TYPE_BANK_TRANSFERT_SOFORT', + Configuration::get('PAYXPERT_PAYMENT_TYPE_BANK_TRANSFERT_SOFORT')); + $przelewy24PaymentType = Tools::getValue('PAYXPERT_PAYMENT_TYPE_BANK_TRANSFERT_PRZELEWY24', + Configuration::get('PAYXPERT_PAYMENT_TYPE_BANK_TRANSFERT_PRZELEWY24')); + $idealPaymentType = Tools::getValue('PAYXPERT_PAYMENT_TYPE_BANK_TRANSFERT_IDEAL', + Configuration::get('PAYXPERT_PAYMENT_TYPE_BANK_TRANSFERT_IDEAL')); + + $result['PAYXPERT_PAYMENT_TYPE_CREDIT_CARD'] = ($creditCardPaymentType === "true" || $creditCardPaymentType == 1) ? 1 : 0; + $result['PAYXPERT_PAYMENT_TYPE_BANK_TRANSFERT_SOFORT'] = ($sofortPaymentType === "true" || $sofortPaymentType == 1) ? 1 : 0; + $result['PAYXPERT_PAYMENT_TYPE_BANK_TRANSFERT_PRZELEWY24'] = ($przelewy24PaymentType === "true" || $przelewy24PaymentType == 1) ? 1 : 0; + $result['PAYXPERT_PAYMENT_TYPE_BANK_TRANSFERT_IDEAL'] = ($idealPaymentType === "true" || $idealPaymentType == 1) ? 1 : 0; + } + + return $result; + } + + public function renderForm() { + $fields_form = array( + 'form' => array( /* */ + 'legend' => array( /* */ + 'title' => $this->l('Settings'), /* */ + 'icon' => 'icon-gears' /* */ + ), /* */ + 'input' => array( /* */ + array( /* */ + 'type' => 'text', /* */ + 'name' => 'PAYXPERT_ORIGINATOR', /* */ + 'label' => $this->l('Originator ID'), /* */ + 'desc' => $this->l('The identifier of your Originator'), /* */ + 'required' => true /* */ + ), + array( /* */ + 'type' => 'password', /* */ + 'name' => 'PAYXPERT_PASSWORD', /* */ + 'label' => $this->l('Originator password'), /* */ + 'desc' => $this->l('The password associated with your Originator (leave empty to keep the current one)'), /* */ + 'hint' => $this->l('Leave empty to keep the current one'), /* */ + 'required' => false /* */ + ), + array( /* */ + 'type' => 'text', /* */ + 'name' => 'PAYXPERT_URL', /* */ + 'label' => $this->l('Payment Page URL'), /* */ + 'desc' => $this->l('Leave this field empty unless you have been given an URL'), /* */ + 'required' => false /* */ + ), + array( /* */ + 'type' => 'switch', /* */ + 'name' => 'PAYXPERT_MERCHANT_NOTIF', /* */ + 'label' => $this->l('Merchant notifications'), /* */ + 'desc' => $this->l('Whether or not to send a notification to the merchant for each processed payment'), /* */ + 'required' => false, /* */ + 'is_bool' => true, /* */ + 'values' => array( /* */ + array('id' => 'notif_on', 'value' => 1, 'label' => $this->l('Enabled')), /* */ + array('id' => 'notif_off', 'value' => 0, 'label' => $this->l('Disabled')) /* */ + ) /* */ + ), /* */ + array( /* */ + 'type' => 'text', /* */ + 'name' => 'PAYXPERT_MERCHANT_NOTIF_TO', /* */ + 'label' => $this->l('Merchant notifications recipient'), /* */ + 'desc' => $this->l('Recipient email address for merchant notifications'), /* */ + 'required' => false, /* */ + 'size' => 100 /* */ + ), /* */ + array( /* */ + 'type' => 'select', /* */ + 'name' => 'PAYXPERT_MERCHANT_NOTIF_LANG', /* */ + 'label' => $this->l('Merchant notifications lang'), /* */ + 'desc' => $this->l('Language to use for merchant notifications'), /* */ + 'required' => false, /* */ + 'options' => array( /* */ + 'query' => array( /* */ + array('id_option' => 'en', 'name' => $this->l('English')), /* */ + array('id_option' => 'fr', 'name' => $this->l('French')), /* */ + array('id_option' => 'es', 'name' => $this->l('Spanish')), /* */ + array('id_option' => 'it', 'name' => $this->l('Italian')) /* */ + ), /* */ + 'id' => 'id_option', /* */ + 'name' => 'name' /* */ + ) /* */ + ) /* */ + ), /* */ + 'submit' => array('title' => $this->l('Update settings')) /* */ + ) /* */ + ); + + if (version_compare(_PS_VERSION_, '1.7', '>=')) { + $fields_form['form']['input'][] = array( /* */ + 'type' => 'switch', /* */ + 'name' => 'PAYXPERT_PAYMENT_TYPE_CREDIT_CARD', /* */ + 'label' => $this->l('Credit Card'), /* */ + 'desc' => $this->l('Enable payment type: Credit Card'), /* */ + 'required' => false, /* */ + 'is_bool' => true, /* */ + 'values' => array(/* */ + array('id' => 'cc_on', 'value' => 1, 'label' => $this->l('Enabled')), /* */ + array('id' => 'cc_off', 'value' => 0, 'label' => $this->l('Disabled')) /* */ + ) /* */ + ); + $fields_form['form']['input'][] = array( /* */ + 'type' => 'switch', /* */ + 'name' => 'PAYXPERT_PAYMENT_TYPE_BANK_TRANSFERT_SOFORT', /* */ + 'label' => $this->l('Bank Transfert via Sofort'), /* */ + 'desc' => $this->l('Enable payment type: Bank Transfer via Sofort'), /* */ + 'required' => false, /* */ + 'is_bool' => true, /* */ + 'values' => array(/* */ + array('id' => 'sofort_on', 'value' => 1, 'label' => $this->l('Enabled')), /* */ + array('id' => 'sofort_off', 'value' => 0, 'label' => $this->l('Disabled')) /* */ + ) /* */ + ); + $fields_form['form']['input'][] = array( /* */ + 'type' => 'switch', /* */ + 'name' => 'PAYXPERT_PAYMENT_TYPE_BANK_TRANSFERT_PRZELEWY24', /* */ + 'label' => $this->l('Bank Transfert via Przelewy24'), /* */ + 'desc' => $this->l('Enable payment type: Bank Transfer via Przelewy24'), /* */ + 'required' => false, /* */ + 'is_bool' => true, /* */ + 'values' => array(/* */ + array('id' => 'przelewy24_on', 'value' => 1, 'label' => $this->l('Enabled')), /* */ + array('id' => 'przelewy24_off', 'value' => 0, 'label' => $this->l('Disabled')) /* */ + ) /* */ + ); + $fields_form['form']['input'][] = array( /* */ + 'type' => 'switch', /* */ + 'name' => 'PAYXPERT_PAYMENT_TYPE_BANK_TRANSFERT_IDEAL', /* */ + 'label' => $this->l('Bank Transfert via iDeal'), /* */ + 'desc' => $this->l('Enable payment type: Bank Transfer via iDeal'), /* */ + 'required' => false, /* */ + 'is_bool' => true, /* */ + 'values' => array(/* */ + array('id' => 'ideal_on', 'value' => 1, 'label' => $this->l('Enabled')), /* */ + array('id' => 'ideal_off', 'value' => 0, 'label' => $this->l('Disabled')) /* */ + ) /* */ + ); + } + + $helper = new HelperForm(); + $helper->show_toolbar = false; + $helper->table = $this->table; + $lang = new Language((int) Configuration::get('PS_LANG_DEFAULT')); + $helper->default_form_language = $lang->id; + $helper->allow_employee_form_lang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') ? Configuration::get( + 'PS_BO_ALLOW_EMPLOYEE_FORM_LANG') : 0; + $this->fields_form = array(); + + $helper->identifier = $this->identifier; + $helper->submit_action = 'btnSubmit'; + $helper->currentIndex = $this->context->link->getAdminLink('AdminModules', false) . '&configure=' . $this->name . '&tab_module=' . + $this->tab . '&module_name=' . $this->name; + $helper->token = Tools::getAdminTokenLite('AdminModules'); + $helper->tpl_vars = array( /* */ + 'fields_value' => $this->getConfigFieldsValues(), /* */ + 'languages' => $this->context->controller->getLanguages(), /* */ + 'id_language' => $this->context->language->id /* */ + ); + + return $helper->generateForm(array($fields_form)); + } + + private function _postValidation() { + if (Tools::isSubmit('btnSubmit')) { + if (!Tools::getValue('PAYXPERT_ORIGINATOR')) { + $this->_postErrors[] = $this->l('Originator is required.'); + } + + if (!Configuration::get('PAYXPERT_PASSWORD') && !Tools::getValue('PAYXPERT_PASSWORD')) { + $this->_postErrors[] = $this->l('Password is required.'); + } + + if (in_array(Tools::getValue('PAYXPERT_MERCHANT_NOTIF'), array("true", "1", "on")) && !Tools::getValue('PAYXPERT_MERCHANT_NOTIF_TO')) { + $this->_postErrors[] = $this->l('Merchant notifications recipient is required.'); + } + + if (Tools::getValue('PAYXPERT_MERCHANT_NOTIF_TO') && !Validate::isEmail(Tools::getValue('PAYXPERT_MERCHANT_NOTIF_TO'))) { + $this->_postErrors[] = $this->l('Merchant notifications recipient must be a valid email address.'); + } + + if (!in_array(Tools::getValue('PAYXPERT_MERCHANT_NOTIF_LANG'), array("en", "fr", "es", "it"))) { + $this->_postErrors[] = $this->l('Merchant notification lang is not valid.'); + } + } + } + + protected function _postProcess() { + if (Tools::isSubmit('btnSubmit')) { + Configuration::updateValue('PAYXPERT_ORIGINATOR', Tools::getValue('PAYXPERT_ORIGINATOR')); + + if (Tools::getValue('PAYXPERT_PASSWORD')) { + // Manually handle HTML special chars to avoid losing them + Configuration::updateValue('PAYXPERT_PASSWORD', htmlentities(Tools::getValue('PAYXPERT_PASSWORD'))); + } + + Configuration::updateValue('PAYXPERT_URL', Tools::getValue('PAYXPERT_URL')); + + Configuration::updateValue('PAYXPERT_MERCHANT_NOTIF_TO', Tools::getValue('PAYXPERT_MERCHANT_NOTIF_TO')); + + if (in_array(Tools::getValue('PAYXPERT_MERCHANT_NOTIF_LANG'), array("en", "fr", "es", "it"))) { + Configuration::updateValue('PAYXPERT_MERCHANT_NOTIF_LANG', Tools::getValue('PAYXPERT_MERCHANT_NOTIF_LANG')); + } + + // Handle checkboxes + $checkboxes = array( /* */ + 'PAYXPERT_MERCHANT_NOTIF' /* */ + ); + if (version_compare(_PS_VERSION_, '1.7', '>=')) { + $checkboxes[] = 'PAYXPERT_PAYMENT_TYPE_CREDIT_CARD'; + $checkboxes[] = 'PAYXPERT_PAYMENT_TYPE_BANK_TRANSFERT_SOFORT'; + $checkboxes[] = 'PAYXPERT_PAYMENT_TYPE_BANK_TRANSFERT_PRZELEWY24'; + $checkboxes[] = 'PAYXPERT_PAYMENT_TYPE_BANK_TRANSFERT_IDEAL'; + } + + foreach ($checkboxes as $checkbox) { + if (in_array(Tools::getValue($checkbox), array("true", "1", "on"))) { + Configuration::updateValue($checkbox, "true"); + } else { + Configuration::updateValue($checkbox, "false"); + } + } + } + + if (version_compare(_PS_VERSION_, '1.6', '>=')) { + $this->_html .= $this->displayConfirmation($this->l('Configuration updated')); + } else { + $this->_html .= '
' . $this->l('Configuration updated') . '
'; + + return true; + } + } + + private function checkPaymentTypeAndProvider($paymentType, $paymentProvider) { + // For Prestashop >=1.7, check that the payment type is enabled + if (version_compare(_PS_VERSION_, '1.7.0', '>=') === true) { + switch ($paymentType) { + case PayXpert\Connect2Pay\Connect2PayClient::_PAYMENT_TYPE_CREDITCARD: + return Configuration::get('PAYXPERT_PAYMENT_TYPE_CREDIT_CARD') === "true"; + case PayXpert\Connect2Pay\Connect2PayClient::_PAYMENT_TYPE_BANKTRANSFER: + if ($paymentProvider !== null) { + switch ($paymentProvider) { + case PayXpert\Connect2Pay\Connect2PayClient::_PAYMENT_PROVIDER_SOFORT: + return Configuration::get('PAYXPERT_PAYMENT_TYPE_BANK_TRANSFERT_SOFORT') === "true"; + case PayXpert\Connect2Pay\Connect2PayClient::_PAYMENT_PROVIDER_PRZELEWY24: + return Configuration::get('PAYXPERT_PAYMENT_TYPE_BANK_TRANSFERT_PRZELEWY24') === "true"; + case PayXpert\Connect2Pay\Connect2PayClient::_PAYMENT_PROVIDER_IDEALKP: + return Configuration::get('PAYXPERT_PAYMENT_TYPE_BANK_TRANSFERT_IDEAL') === "true"; + } + } + break; + } + } else { + return true; + } + + return false; + } + + private function checkCurrency($cart) { + $currency_order = new Currency((int) ($cart->id_currency)); + $currencies_module = $this->getCurrency((int) $cart->id_currency); + + if (is_array($currencies_module)) { + foreach ($currencies_module as $currency_module) { + if ($currency_order->id == $currency_module['id_currency']) { + return true; + } + } + } + + return false; + } + + /** + * Get PayXpert Url depending of the env + * + * @return string Url + */ + public function getPayXpertUrl() { + $url = Configuration::get('PAYXPERT_URL'); + + if (strlen(trim($url)) <= 0) { + $url = 'https://connect2.payxpert.com/'; + } + + return $url; + } + + /* Theses functions are used to support all versions of Prestashop */ + public function assignSmartyVariable($name, $value) { + + // Check if context smarty variable is available + if (isset($this->context->smarty)) { + return $this->context->smarty->assign($name, $value); + } else { + // Use the global variable + global $smarty; + + return $smarty->assign($name, $value); + } + } + + public function getModuleLinkCompat($module, $controller = 'default', $params = null) { + if (class_exists('Context')) { + if (!$params) { + $params = array(); + } + + return Context::getContext()->link->getModuleLink($module, $controller, $params); + } else { + if ($controller == 'default') { + if ($params) { + $params = "?" . $params; + } + + return Configuration::get('PS_SSL_ENABLED') ? 'https' : 'http' . '://' . $_SERVER['HTTP_HOST'] . __PS_BASE_URI__ . $module . '.php' . + $params; + } else { + return Configuration::get('PS_SSL_ENABLED') ? 'https' : 'http' . '://' . $_SERVER['HTTP_HOST'] . __PS_BASE_URI__ . + 'modules/payxpert/' . $controller . '.php'; + } + } + } + + public function getPageLinkCompat($controller, $ssl = null, $id_lang = null, $request = null, $request_url_encode = false, $id_shop = null) { + if (class_exists('Context')) { + return Context::getContext()->link->getPageLink($controller, $ssl, $id_lang, $request, $request_url_encode, $id_shop); + } else { + if ($controller == 'contact') { + return Configuration::get('PS_SSL_ENABLED') ? 'https' : 'http' . '://' . $_SERVER['HTTP_HOST'] . __PS_BASE_URI__ . 'contact-form.php'; + } else { + $params = (isset($params)) ? "?" . $params : ""; + + return Configuration::get('PS_SSL_ENABLED') ? 'https' : 'http' . '://' . $_SERVER['HTTP_HOST'] . __PS_BASE_URI__ . $controller . + '.php' . $params; + } + } + } + + public function addLog($message, $severity = 1, $errorCode = null, $objectType = null, $objectId = null, $allowDuplicate = true) { + if (class_exists('PrestaShopLogger')) { + PrestaShopLogger::addLog($message, $severity, $errorCode, $objectType, $objectId, $allowDuplicate); + } else if (class_exists('Logger')) { + Logger::addLog($message, $severity, $errorCode, $objectType, $objectId, $allowDuplicate); + } else { + error_log($message . "(" . $errorCode . ")"); + } + } + + /* Callback authenticity check methods */ + public static function getCallbackAuthenticityData($orderId, $secure_key) { + return sha1($orderId . $secure_key . html_entity_decode(Configuration::get('PAYXPERT_PASSWORD'))); + } + + public static function checkCallbackAuthenticityData($callbackData, $orderId, $secure_key) { + return (strcasecmp($callbackData, PayXpert::getCallbackAuthenticityData($orderId, $secure_key)) === 0); + } + + /* Theses functions are only used for Prestashop prior to version 1.5 */ + public function execPayment($cart) { + global $cookie; + + $this->assignSmartyVariable('nbProducts', $cart->nbProducts()); + $this->assignSmartyVariable('cust_currency', $cart->id_currency); + $this->assignSmartyVariable('currencies', $this->getCurrency()); + $this->assignSmartyVariable('total', $cart->getOrderTotal(true, 3)); + $this->assignSmartyVariable('isoCode', Language::getIsoById(intval($cookie->id_lang))); + $this->assignSmartyVariable('this_path', $this->_path); + $this->assignSmartyVariable('this_link', $this->getModuleLinkCompat('payxpert', 'redirect')); + $this->assignSmartyVariable('this_link_back', $this->getPageLinkCompat('order', true, NULL, "step=3")); + + return $this->display(__FILE__, '/views/templates/front/payment_execution.tpl'); + } + + public function displayErrorPage($message) { + $this->assignSmartyVariable('errorMessage', $message); + $this->assignSmartyVariable('this_link_back', $this->getPageLinkCompat('order', true, NULL, "step=3")); + + return $this->display(__FILE__, '/views/templates/front/payment_error.tpl'); + } +} \ No newline at end of file diff --git a/modules/payxpert/redirect.php b/modules/payxpert/redirect.php new file mode 100644 index 0000000..78a4f87 --- /dev/null +++ b/modules/payxpert/redirect.php @@ -0,0 +1,39 @@ +isLogged()) { + Tools::redirect('authentication.php?back=order.php'); +} + +$payxpert = new PayXpert(); +$message = $payxpert->redirect($cart); + +echo $payxpert->displayErrorPage($message); + +require_once(dirname(__FILE__) . '/../../footer.php'); diff --git a/modules/payxpert/validation.php b/modules/payxpert/validation.php new file mode 100644 index 0000000..bd3e4c6 --- /dev/null +++ b/modules/payxpert/validation.php @@ -0,0 +1,107 @@ +getPayXpertUrl(), Configuration::get('PAYXPERT_ORIGINATOR'), + html_entity_decode(Configuration::get('PAYXPERT_PASSWORD'))); + +if ($c2pClient->handleCallbackStatus()) { + + $status = $c2pClient->getStatus(); + + // get the Error code + $errorCode = $status->getErrorCode(); + $errorMessage = $status->getErrorMessage(); + + $transaction = $status->getLastTransactionAttempt(); + + if ($transaction !== null) { + $transactionId = $transaction->getTransactionID(); + + $orderId = $status->getOrderID(); + $amount = number_format($status->getAmount() / 100, 2, '.', ''); + $callbackData = $status->getCtrlCustomData(); + + $message = "PayXpert payment module: "; + + // load the customer cart and perform some checks + $cart = new Cart((int) ($orderId)); + if (!$cart->id) { + $message .= "Cart is empty: " . $orderId; + error_log($message); + } + + $responseStatus = "KO"; + $responseMessage = "Callback validation failed"; + $customer = new Customer((int) ($cart->id_customer)); + + if (!$customer) { + $message .= "Customer is empty for order " . $orderId; + error_log($message); + } else { + if (!PayXpert::checkCallbackAuthenticityData($callbackData, $cart->id, $customer->secure_key)) { + $message .= "Invalid callback received for order " . $orderId . ". Validation failed."; + error_log($message); + } else { + $responseStatus = "OK"; + $responseMessage = "Status recorded"; + + $message .= "Error code: " . $errorCode . "
"; + $message .= "Error message: " . $errorMessage . "
"; + $message .= "Transaction ID: " . $transactionId . "
"; + $message .= "Order ID: " . $orderId . "
"; + + error_log(str_replace("
", " ", $message)); + + // To avoid issue with conversion rate get the amount from the order + $amount = $cart->getOrderTotal(true, 3); + + $paymentMean = $payxpert->l('Credit Card') . ' (PayXpert)'; + + switch ($errorCode) { + case "000": + /* Payment OK */ + $payxpert->validateOrder((int) $orderId, _PS_OS_PAYMENT_, $amount, $paymentMean, $message); + break; + default: + $payxpert->validateOrder((int) $orderId, _PS_OS_ERROR_, $amount, $paymentMean, $message); + break; + } + } + } + } + + // Send a response to mark this transaction as notified + $response = array("status" => $responseStatus, "message" => $responseMessage); + header("Content-type: application/json"); + echo json_encode($response); +} diff --git a/modules/payxpert/views/index.php b/modules/payxpert/views/index.php new file mode 100644 index 0000000..69b76d9 --- /dev/null +++ b/modules/payxpert/views/index.php @@ -0,0 +1,36 @@ + +* @copyright 2007-2013 PrestaShop SA + +* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) +* International Registered Trademark & Property of PrestaShop SA +*/ + +header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); +header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); + +header('Cache-Control: no-store, no-cache, must-revalidate'); +header('Cache-Control: post-check=0, pre-check=0', false); +header('Pragma: no-cache'); + +header('Location: ../../../'); +exit; \ No newline at end of file diff --git a/modules/payxpert/views/templates/admin/config.tpl b/modules/payxpert/views/templates/admin/config.tpl new file mode 100644 index 0000000..f3d99ea --- /dev/null +++ b/modules/payxpert/views/templates/admin/config.tpl @@ -0,0 +1,78 @@ +{* +* Copyright 2013-2017 PayXpert +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* @author Regis Vidal +* +*} +
+
+ Payxpert - {l s='Settings' mod='payxpert'} + +
 
+ +
+ +

{l s='The identifier of your Originator' mod='payxpert'}

+
+
 
+ + +
+ +

{l s='The password associated with your Originator (leave empty to keep the current one)' mod='payxpert'}

+
+
 
+ + +
+ +

{l s='Leave this field empty unless you have been given an URL"' mod='payxpert'}

+
+
 
+ + +
+ + +

{l s='Whether or not to send a notification to the merchant for each processed payment' mod='payxpert'}

+
+
 
+ + +
+ +

{l s='Recipient email address for merchant notifications' mod='payxpert'}

+
+
 
+ + +
+ +

{l s='Language to use for merchant notifications' mod='payxpert'}

+
+
 
+ +
+ +
+
 
+
+
+
 
diff --git a/modules/payxpert/views/templates/admin/index.php b/modules/payxpert/views/templates/admin/index.php new file mode 100644 index 0000000..a230e5a --- /dev/null +++ b/modules/payxpert/views/templates/admin/index.php @@ -0,0 +1,35 @@ + +* @copyright 2007-2013 PrestaShop SA +* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) +* International Registered Trademark & Property of PrestaShop SA +*/ + +header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); +header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); + +header("Cache-Control: no-store, no-cache, must-revalidate"); +header("Cache-Control: post-check=0, pre-check=0", false); +header("Pragma: no-cache"); + +header("Location: ../"); +exit; \ No newline at end of file diff --git a/modules/payxpert/views/templates/admin/infos.tpl b/modules/payxpert/views/templates/admin/infos.tpl new file mode 100644 index 0000000..417d1ad --- /dev/null +++ b/modules/payxpert/views/templates/admin/infos.tpl @@ -0,0 +1,26 @@ +{* + Copyright 2013-2017 PayXpert + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + @author Alexandre Chatiron +*} +{if $smarty.const._PS_VERSION_ >= 1.6} +
+{/if} + +

{l s='This module allows you to accept secure payments.' mod='payxpert'}

+





+{if $smarty.const._PS_VERSION_ >= 1.6} +
+{/if} \ No newline at end of file diff --git a/modules/payxpert/views/templates/front/index.php b/modules/payxpert/views/templates/front/index.php new file mode 100644 index 0000000..422fa9d --- /dev/null +++ b/modules/payxpert/views/templates/front/index.php @@ -0,0 +1,36 @@ + +* @copyright 2007-2013 PrestaShop SA + +* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) +* International Registered Trademark & Property of PrestaShop SA +*/ + +header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); +header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); + +header('Cache-Control: no-store, no-cache, must-revalidate'); +header('Cache-Control: post-check=0, pre-check=0', false); +header('Pragma: no-cache'); + +header('Location: ../../../../../'); +exit; \ No newline at end of file diff --git a/modules/payxpert/views/templates/front/payment_error.tpl b/modules/payxpert/views/templates/front/payment_error.tpl new file mode 100644 index 0000000..ce2df2e --- /dev/null +++ b/modules/payxpert/views/templates/front/payment_error.tpl @@ -0,0 +1,53 @@ +{* +* Copyright 2013-2017 PayXpert +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* @author Regis Vidal +* +*} +{capture name=path}{l s='Credit Card payment.' mod='payxpert'}{/capture} +{if $smarty.const._PS_VERSION_ < 1.6}{include file="$tpl_dir./breadcrumb.tpl"}{/if} +

{l s='Order summary' mod='payxpert'}

+ +{assign var='current_step' value='payment'} +{include file="$tpl_dir./order-steps.tpl"} + +{if $smarty.const._PS_VERSION_ >= 1.6} +
+

Error

+{else} +{if $smarty.const._PS_VERSION_ >= 1.5 && version_compare(_PS_VERSION_, '1.6', '<') } + +{/if} +
+

Error

+{/if} +

{$errorMessage}

+{if $smarty.const._PS_VERSION_ >= 1.6} +
+

+ + {l s='Other payment methods' mod='payxpert'} + +

+{else} +

+ {l s='Other payment methods' mod='payxpert'} +

+
+{/if} \ No newline at end of file diff --git a/modules/payxpert/views/templates/front/payment_error17.tpl b/modules/payxpert/views/templates/front/payment_error17.tpl new file mode 100644 index 0000000..c786fa1 --- /dev/null +++ b/modules/payxpert/views/templates/front/payment_error17.tpl @@ -0,0 +1,47 @@ +{* +* Copyright 2013-2017 PayXpert +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* @author Regis Vidal +* +*} +{capture name=path}{l s='Credit Card payment.' mod='payxpert'}{/capture} + +{extends file='page.tpl'} +

{l s='Order summary' mod='payxpert'}

+ +{assign var='current_step' value='payment'} + +{block name="content"} + + + +
+

Error

+ +

{$errorMessage}

+ +
+ +

+ + {l s='Other payment methods' mod='payxpert'} + +

+ +{/block} \ No newline at end of file diff --git a/modules/payxpert/views/templates/front/payment_execution.tpl b/modules/payxpert/views/templates/front/payment_execution.tpl new file mode 100644 index 0000000..75f85bd --- /dev/null +++ b/modules/payxpert/views/templates/front/payment_execution.tpl @@ -0,0 +1,78 @@ +{* +* Copyright 2013-2017 PayXpert +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* @author Regis Vidal +* @copyright 2013-2017 PayXpert +* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 (the "License") +*} + +{capture name=path}{l s='Credit Card payment.' mod='payxpert'}{/capture} + +{if $smarty.const._PS_VERSION_ < 1.6} +{include file="$tpl_dir./breadcrumb.tpl"} +{/if} +

{l s='Order summary' mod='payxpert'}

+ +{assign var='current_step' value='payment'} +{include file="$tpl_dir./order-steps.tpl"} + +{if $nbProducts <= 0} +

{l s='Your shopping cart is empty.' mod='payxpert'}

+{else} + {if $smarty.const._PS_VERSION_ < 1.6}

{l s='Credit Card payment.' mod='payxpert'}

{/if} +
+ {if $smarty.const._PS_VERSION_ < 1.6} +

+ {else} +

+

{l s='Credit Card payment.' mod='payxpert'}

+

+ + {/if} + {l s='Credit Card' mod='payxpert'} + {l s='You have chosen to pay by Credit Card.' mod='payxpert'} {l s='Here is a short summary of your order:' mod='payxpert'} + {if $smarty.const._PS_VERSION_ >= 1.6}{/if} +

+

+

+ - {l s='The total amount of your order is' mod='payxpert'} + {Tools::displayPrice($total, $currency, false)} + {if $use_taxes == 1} + {l s='(tax incl.)' mod='payxpert'} + {/if} +

+

+ {l s='Credit Card information will be displayed on the next page using a secure payment page.' mod='payxpert'} +

+ {l s='Please confirm your order by clicking "Place my order."' mod='payxpert'}. +

+ {if $smarty.const._PS_VERSION_ < 1.6} +

+ + {l s='Other payment methods' mod='payxpert'} +

+ {else} +
+

+ + {l s='Other payment methods' mod='payxpert'} + + +

+ {/if} +
+{/if} \ No newline at end of file diff --git a/modules/payxpert/views/templates/front/payment_execution_bank_transfer.tpl b/modules/payxpert/views/templates/front/payment_execution_bank_transfer.tpl new file mode 100644 index 0000000..c06f378 --- /dev/null +++ b/modules/payxpert/views/templates/front/payment_execution_bank_transfer.tpl @@ -0,0 +1,68 @@ +{* +* Copyright 2013-2017 PayXpert +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* @author Regis Vidal +* @copyright 2013-2017 PayXpert +* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 (the "License") +*} + +{extends file=$layout} + +{block name='content'} +
+
+

{l s='Order confirmation' mod='payxpert'}

+
+ {if $nbProducts <= 0} +

{l s='Your shopping cart is empty.' mod='payxpert'}

+ {else} +
+ {assign var='current_step' value='payment'} +
+ {l s='Bank Transfer' mod='payxpert'} +
+
+ + {l s='You have chosen to pay by Bank Transfer.' mod='payxpert'}
+
+

+ {capture name='amount'}{Tools::displayPrice($total, $cust_currency)}{/capture} + {assign var='order_amount' value=$smarty.capture.amount} + {l s='The total amount of your order is %s.' sprintf=[$order_amount|escape:'html':'UTF-8'] mod='payxpert'} +
+ {l s='You will be able to pay by entering your bank account information on the next pages using a secured payment form.' mod='payxpert'} +

+

+ {l s='Please confirm your order by clicking the "Pay my order" button below.' mod='payxpert'} +

+
+
+
+ +
+
+ +
+
+
+ {/if} +
+{/block} \ No newline at end of file diff --git a/modules/payxpert/views/templates/front/payment_execution_credit_card.tpl b/modules/payxpert/views/templates/front/payment_execution_credit_card.tpl new file mode 100644 index 0000000..794eedb --- /dev/null +++ b/modules/payxpert/views/templates/front/payment_execution_credit_card.tpl @@ -0,0 +1,68 @@ +{* +* Copyright 2013-2017 PayXpert +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* @author Regis Vidal +* @copyright 2013-2017 PayXpert +* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 (the "License") +*} + +{extends file=$layout} + +{block name='content'} +
+
+

{l s='Order confirmation' mod='payxpert'}

+
+ {if $nbProducts <= 0} +

{l s='Your shopping cart is empty.' mod='payxpert'}

+ {else} +
+ {assign var='current_step' value='payment'} +
+ {l s='Credit Card' mod='payxpert'} +
+
+ + {l s='You have chosen to pay by Credit Card.' mod='payxpert'}
+
+

+ {capture name='amount'}{Tools::displayPrice($total, $cust_currency)}{/capture} + {assign var='order_amount' value=$smarty.capture.amount} + {l s='The total amount of your order is %s.' sprintf=[$order_amount|escape:'html':'UTF-8'] mod='payxpert'} +
+ {l s='You will be able to pay by entering your credit card information on the next page using a secured payment page.' mod='payxpert'} +

+

+ {l s='Please confirm your order by clicking the "Pay my order" button below.' mod='payxpert'} +

+
+
+
+ +
+
+ +
+
+
+ {/if} +
+{/block} \ No newline at end of file diff --git a/modules/payxpert/views/templates/front/payment_infos_bank_transfer_ideal.tpl b/modules/payxpert/views/templates/front/payment_infos_bank_transfer_ideal.tpl new file mode 100644 index 0000000..37f2f9c --- /dev/null +++ b/modules/payxpert/views/templates/front/payment_infos_bank_transfer_ideal.tpl @@ -0,0 +1,3 @@ +
+

iDeal{l s='Use your bank account information with the iDeal provider to pay your order' mod='payxpert'}

+
\ No newline at end of file diff --git a/modules/payxpert/views/templates/front/payment_infos_bank_transfer_przelewy24.tpl b/modules/payxpert/views/templates/front/payment_infos_bank_transfer_przelewy24.tpl new file mode 100644 index 0000000..6539034 --- /dev/null +++ b/modules/payxpert/views/templates/front/payment_infos_bank_transfer_przelewy24.tpl @@ -0,0 +1,3 @@ +
+

Przelewy24{l s='Use your bank account information with the Przelewy24 provider to pay your order' mod='payxpert'}

+
\ No newline at end of file diff --git a/modules/payxpert/views/templates/front/payment_infos_bank_transfer_sofort.tpl b/modules/payxpert/views/templates/front/payment_infos_bank_transfer_sofort.tpl new file mode 100644 index 0000000..b07ab79 --- /dev/null +++ b/modules/payxpert/views/templates/front/payment_infos_bank_transfer_sofort.tpl @@ -0,0 +1,3 @@ +
+

Sofort{l s='Use your bank account information with the Sofort provider to pay your order' mod='payxpert'}

+
\ No newline at end of file diff --git a/modules/payxpert/views/templates/front/payment_infos_credit_card.tpl b/modules/payxpert/views/templates/front/payment_infos_credit_card.tpl new file mode 100644 index 0000000..b971ee3 --- /dev/null +++ b/modules/payxpert/views/templates/front/payment_infos_credit_card.tpl @@ -0,0 +1,3 @@ +
+

Credit Card{l s='Use your credit card information in a secured form to pay your order' mod='payxpert'}

+
\ No newline at end of file diff --git a/modules/payxpert/views/templates/hook/index.php b/modules/payxpert/views/templates/hook/index.php new file mode 100644 index 0000000..422fa9d --- /dev/null +++ b/modules/payxpert/views/templates/hook/index.php @@ -0,0 +1,36 @@ + +* @copyright 2007-2013 PrestaShop SA + +* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) +* International Registered Trademark & Property of PrestaShop SA +*/ + +header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); +header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); + +header('Cache-Control: no-store, no-cache, must-revalidate'); +header('Cache-Control: post-check=0, pre-check=0', false); +header('Pragma: no-cache'); + +header('Location: ../../../../../'); +exit; \ No newline at end of file diff --git a/modules/payxpert/views/templates/hook/orderconfirmation.tpl b/modules/payxpert/views/templates/hook/orderconfirmation.tpl new file mode 100644 index 0000000..e6ae09b --- /dev/null +++ b/modules/payxpert/views/templates/hook/orderconfirmation.tpl @@ -0,0 +1,37 @@ +{* +* Copyright 2013-2017 PayXpert +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* @author Regis Vidal +* @copyright 2013-2017 PayXpert +* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 (the "License") +*} +{if $status == 'ok'} +

{l s='Your order has been completed.' mod='payxpert'} +

{l s='It will be shipped as soon as possible.' mod='payxpert'} +

{l s='For any questions or for further information, please contact our' mod='payxpert'} {l s='customer support' mod='payxpert'}. +

+{else} + {if $status == 'pending'} +

{l s='Your order is still pending.' mod='payxpert'} +

{l s='Your order will be shipped as soon as we receive your payment.' mod='payxpert'} +

{l s='For any questions or for further information, please contact our' mod='payxpert'} {l s='customer support' mod='payxpert'}. +

+ {else} +

+ {l s='We noticed a problem with your order. If you think this is an error, you can contact our' mod='payxpert'} + {l s='customer support' mod='payxpert'}. +

+ {/if} +{/if} \ No newline at end of file diff --git a/modules/payxpert/views/templates/hook/payment.tpl b/modules/payxpert/views/templates/hook/payment.tpl new file mode 100644 index 0000000..1d5e112 --- /dev/null +++ b/modules/payxpert/views/templates/hook/payment.tpl @@ -0,0 +1,36 @@ +{* +* Copyright 2013-2014 PayXpert +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* @author Regis Vidal +* @copyright 2013-2017 PayXpert +* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 (the "License") +*} + +{if $smarty.const._PS_VERSION_ >= 1.6} + +{/if} \ No newline at end of file diff --git a/modules/payxpert/views/templates/index.php b/modules/payxpert/views/templates/index.php new file mode 100644 index 0000000..54b3024 --- /dev/null +++ b/modules/payxpert/views/templates/index.php @@ -0,0 +1,36 @@ + +* @copyright 2007-2013 PrestaShop SA + +* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) +* International Registered Trademark & Property of PrestaShop SA +*/ + +header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); +header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); + +header('Cache-Control: no-store, no-cache, must-revalidate'); +header('Cache-Control: post-check=0, pre-check=0', false); +header('Pragma: no-cache'); + +header('Location: ../../../../'); +exit; \ No newline at end of file diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..ca1612f --- /dev/null +++ b/readme.txt @@ -0,0 +1,46 @@ +//----------------------------------------------------------------- +// Prestashop PayXpert Payment Module +// Version for Prestashop 1.4.X to 1.7.x +//------------------------------------------------------------------ + +This version works with all version of Prestashop + +The author of this plugin can NEVER be held responsible for this software. +There is no warranty what so ever. You accept this by using this software. + +Changelog +========= +1.0.7 - Supports Prestashop 1.7 +1.0.1 - Improve Prestashop versions support +1.0.0 - Initial Release + +Automatic Installation +====================== +1. In Prestashop Admin panel, go to "Modules" + +2. Choose "Add a new module" or "Add a module from my computer" (according to your Prestashop version) + +3. Using the "Module file" form field, select the PayXpert module zip archive and click "Upload this module" + +4. Locate the PayXpert entry in the module list and select install + +5. According to your Prestashop version, either the configure page will be displayed or select Configure and setup your information + +6. Save your settings and you'll be ready to start using the module + +Manual Installation +=================== +1. Unzip the module zip archive + +2. Upload the "payxpert" folder to your Prestashop modules folder. No files will be overwritten, only added + +3. Go to the admin panel. Select Modules and then Payments. Locate the PayXpert entry in the module list and select install + +4. After installation, select Configure and setup your information + +5. Save your settings and you'll be ready to start using the module + +Support +============ + +Please visit the PayXpert website (http://www.payxpert.com) for our support contact details. \ No newline at end of file