From 308e66737ae3a43ae90ead31d36723ee9b5afba2 Mon Sep 17 00:00:00 2001 From: Jesse Tabourel Date: Mon, 24 Mar 2014 17:00:45 +0100 Subject: [PATCH] Version 1.0.0 + Adds payment gateways for iDEAL, Creditcard, Mister Cash, Paypal, paysafecard, IBAN and more + Adds refund functionality in the admin panel for transactions made with this plugin --- .gitignore | 3 + .travis.yml | 6 + build/.gitignore | 1 + mollie/LICENSE | 8 + mollie/README.mdown | 61 ++ mollie/controllers/front/payment.php | 351 ++++++++ mollie/controllers/front/return.php | 117 +++ mollie/controllers/front/webhook.php | 138 +++ mollie/css/mollie.css | 101 +++ mollie/css/mollie_bootstrap.css | 129 +++ mollie/lib | 1 + mollie/logo.png | Bin 0 -> 2028 bytes mollie/logo_small.png | Bin 0 -> 754 bytes mollie/mollie.php | 815 ++++++++++++++++++ mollie/translations/fr.php | 86 ++ mollie/translations/nl.php | 86 ++ .../views/templates/front/mollie_issuers.tpl | 19 + .../views/templates/front/mollie_return.tpl | 3 + mollie/views/templates/hook/mollie_config.tpl | 219 +++++ .../views/templates/hook/mollie_methods.tpl | 74 ++ mollie/views/templates/hook/mollie_refund.tpl | 21 + release.sh | 2 + tests/bootstrap.php | 166 ++++ tests/impostor.php | 203 +++++ tests/phpunit.xml | 23 + tests/unittests/controllers/paymentTest.php | 122 +++ tests/unittests/controllers/returnTest.php | 71 ++ tests/unittests/controllers/webhookTest.php | 70 ++ tests/unittests/mollieTest.php | 124 +++ 29 files changed, 3020 insertions(+) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 build/.gitignore create mode 100644 mollie/LICENSE create mode 100644 mollie/README.mdown create mode 100644 mollie/controllers/front/payment.php create mode 100644 mollie/controllers/front/return.php create mode 100644 mollie/controllers/front/webhook.php create mode 100644 mollie/css/mollie.css create mode 100644 mollie/css/mollie_bootstrap.css create mode 160000 mollie/lib create mode 100644 mollie/logo.png create mode 100644 mollie/logo_small.png create mode 100644 mollie/mollie.php create mode 100644 mollie/translations/fr.php create mode 100644 mollie/translations/nl.php create mode 100644 mollie/views/templates/front/mollie_issuers.tpl create mode 100644 mollie/views/templates/front/mollie_return.tpl create mode 100644 mollie/views/templates/hook/mollie_config.tpl create mode 100644 mollie/views/templates/hook/mollie_methods.tpl create mode 100644 mollie/views/templates/hook/mollie_refund.tpl create mode 100755 release.sh create mode 100644 tests/bootstrap.php create mode 100644 tests/impostor.php create mode 100644 tests/phpunit.xml create mode 100644 tests/unittests/controllers/paymentTest.php create mode 100644 tests/unittests/controllers/returnTest.php create mode 100644 tests/unittests/controllers/webhookTest.php create mode 100644 tests/unittests/mollieTest.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..41f0a3284 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.DS_Store +.idea +/*.zip diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..ce0bf27e1 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,6 @@ +language: php +php: + - "5.5" + - "5.4" + - "5.3" +script: "phpunit -c tests/phpunit.xml" \ No newline at end of file diff --git a/build/.gitignore b/build/.gitignore new file mode 100644 index 000000000..f59ec20aa --- /dev/null +++ b/build/.gitignore @@ -0,0 +1 @@ +* \ No newline at end of file diff --git a/mollie/LICENSE b/mollie/LICENSE new file mode 100644 index 000000000..04e1af2df --- /dev/null +++ b/mollie/LICENSE @@ -0,0 +1,8 @@ +Copyright (c) 2014, Mollie B.V. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/mollie/README.mdown b/mollie/README.mdown new file mode 100644 index 000000000..192276cf5 --- /dev/null +++ b/mollie/README.mdown @@ -0,0 +1,61 @@ +![Mollie](https://www.mollie.nl/files/Mollie-Logo-Style-Small.png) + +# Prestashop plugin voor [betalingen via Mollie](https://www.mollie.nl/betaaldiensten/). # + +## Installatie [![Build Status](https://travis-ci.org/mollie/Prestashop.png)](https://travis-ci.org/mollie/Prestashop) ## +* Download de laatste versie van de module via de [Releases-pagina](https://github.com/mollie/Prestashop/releases). +* Pak het archief uit +* Kopieer de map 'Mollie' naar de map 'modules' in uw Prestashop installatie +* Ga in uw administratiepaneel naar de tab 'Modules' en kies in het lijstje 'Categories' voor 'Payments and Gateways' +* Klik op de 'install' knop rechts van de Mollie Payment Module +* Vul uw _API-key_ in en sla de gegevens vervolgens op. + +# Ondersteunde betaalmethodes # +### iDEAL ### +Met iDEAL kunt u vertrouwd, veilig en gemakkelijk uw online aankopen afrekenen. iDEAL is het systeem dat u direct koppelt aan uw internetbankierprogramma bij een online aankoop. +Via [Mollie](https://www.mollie.nl/) is iDEAL gemakkelijk aan te sluiten zonder de gebruikelijke technische en administratieve rompslomp. Mollie geeft u op ieder moment toegang tot uw transactieoverzichten en andere statistieken. Tevens is het mogelijk per e-mail of SMS een notificatie te ontvangen bij elke gelukte betaling. [Mollie](https://www.mollie.nl/) is hierdoor dus een perfecte partner op het gebied van iDEAL en is het dan ook niet verbazingwekkend dat [Mollie](https://www.mollie.nl/) ondertussen op meer dan 20.000 websites iDEAL-betalingen mag verzorgen. + +### Creditcard ### +Creditcard is vrijwel de bekendste methode voor het ontvangen van betalingen met wereldwijde dekking. Doordat we onder andere de bekende merken Mastercard en Visa ondersteunen, zorgt dit direct voor veel potentiële kopers. + +### Mister Cash ### +Mister Cash maakt gebruik van een fysieke kaart die gekoppeld is aan tegoed op een Belgische bankrekening. Betalingen via Mister Cash zijn gegarandeerd en lijkt daarmee sterk op iDEAL in Nederland. Daarom is het uitermate geschikt voor uw webwinkel. + +### PayPal ### +PayPal is wereldwijd een zeer populaire betaalmethode. In enkele klikken kunt u betalingen ontvangen via een bankoverschrijving, creditcard of het PayPal-saldo. + +### paysafecard ### +paysafecard is de populairste prepaidcard voor online betalingen die veel door ouders voor hun kinderen wordt gekocht. + +### Overboeking ### +Overboekingen binnen de SEPA zone ontvangen via Mollie. Hiermee kun je betalingen ontvangen van zowel particulieren als zakelijke klanten in meer dan 35 Europese landen. + +# Veel gestelde vragen # + +**Ik heb alles ingesteld, maar de module verschijnt niet bij het afrekenen.** + +Controleert u alstublieft of de module ingeschakeld is. Ook moeten euro's als valuta zijn ingesteld in uw winkel. + +**Moet ik ook een return- en / of webhook-URL instellen?** + +Het is niet nodig een redirect URL of webhook in te stellen. Dat doet de module zelf automatisch bij elke order. + +**Ik heb een probleem met deze module.** + +Neemt u alstublieft contact op met info@mollie.nl voor ondersteuning. + +# Licentie # +[BSD (Berkeley Software Distribution) License](http://www.opensource.org/licenses/bsd-license.php). +Copyright (c) 2013, Mollie B.V. + +# Ondersteuning # +Contact: [www.mollie.nl](https://www.mollie.nl) — info@mollie.nl — +31 20-612 88 55 + ++ [Meer informatie over iDEAL via Mollie](https://www.mollie.nl/betaaldiensten/ideal/) ++ [Meer informatie over Creditcard via Mollie](https://www.mollie.nl/betaaldiensten/creditcard/) ++ [Meer informatie over Mister Cash via Mollie](https://www.mollie.nl/betaaldiensten/mistercash/) ++ [Meer informatie over Overboeking via Mollie](https://www.mollie.nl/betaaldiensten/overboeking/) ++ [Meer informatie over PayPal via Mollie](https://www.mollie.nl/betaaldiensten/paypal/) ++ [Meer informatie over paysafecard via Mollie](https://www.mollie.nl/betaaldiensten/paysafecard/) + +![Powered By Mollie](https://www.mollie.nl/images/badge-betaling-medium.png) diff --git a/mollie/controllers/front/payment.php b/mollie/controllers/front/payment.php new file mode 100644 index 000000000..5dc6d7e77 --- /dev/null +++ b/mollie/controllers/front/payment.php @@ -0,0 +1,351 @@ + + * @copyright Mollie B.V. + * @link https://www.mollie.nl + */ + +if (!defined('_PS_VERSION_')) +{ + die('No direct script access'); +} + +/** + * Class MolliePaymentModuleFrontController + * @method setTemplate + * @property mixed context + * @property Mollie module + */ + +class MolliePaymentModuleFrontController extends ModuleFrontController +{ + /** + * @see FrontController::initContent() + */ + public function initContent() + { + parent::initContent(); + + /** @var Cart $cart */ + $cart = $this->context->cart; + $customer = new Customer($cart->id_customer); + + if (!$this->_validate($cart, $customer)) + { + die( + $this->module->lang['This payment method is not available.'] . + '

' . + '' . + $this->module->lang['Click here to continue'] . + '.' + ); + } + + $method = $_GET['method']; + $issuer = !empty($_GET['issuer']) ? $_GET['issuer'] : NULL; + + // If no issuer was set yet and the issuer list has its own page, show issuer list here + if ($issuer === null && $this->module->getConfigValue('MOLLIE_ISSUERS') === 'own-page') + { + $tpl_data = array(); + $tpl_data['issuers'] = $this->_getIssuerList($method); + + // Only show issuers if a choice is available + if (sizeof($tpl_data['issuers']) === 1) + { + $issuer = key($tpl_data['issuers']); + } + else if (!empty($tpl_data['issuers'])) + { + $tpl_data['msg_bankselect'] = $this->module->lang['Select your bank:']; + $tpl_data['msg_ok'] = $this->module->lang['OK']; + $tpl_data['msg_return'] = $this->module->lang['Return to the homepage']; + $tpl_data['module'] = $this->module; + $this->context->smarty->assign($tpl_data); + $this->setTemplate('mollie_issuers.tpl'); + return; + } + } + + // Currency conversion (thou shalt pay in euros) + $orig_amount = $cart->getOrderTotal(TRUE, Cart::BOTH); + $amount = $this->_convertCurrencyToEuro($orig_amount); + + // Validate + $this->module->validateOrder( + (int) $cart->id, + $this->module->getConfigValue('PS_OS_PREPARATION'), + $orig_amount, + $method, + NULL, + array(), + NULL, + FALSE, + $customer->secure_key + ); + + // Prepare payment + $order_id = $this->module->currentOrder; + $payment_data = $this->_getPaymentData($amount, $method, $issuer, $order_id); + $payment = $this->_createPayment($payment_data); + + // Store payment + Db::getInstance()->insert( + 'mollie_payments', + array( + 'order_id' => $order_id, + 'method' => $payment->method, + 'transaction_id' => $payment->id, + 'bank_status' => Mollie_API_Object_Payment::STATUS_OPEN, + 'created_at' => date("Y-m-d H:i:s") + ) + ); + + // Go to payment url + Tools::redirect($payment->getPaymentUrl()); + } + + /** + * Checks if this payment option is still available + * May redirect the user to a more appropriate page + * + * @param $cart + * @param $customer + * @return bool + */ + public function _validate($cart, $customer) + { + if (!$cart->id_customer || + !$cart->id_address_delivery || + !$cart->id_address_invoice || + !$this->module->active) + { + // We be like: how did you even get here? + Tools::redirect(_PS_BASE_URL_ . __PS_BASE_URI__); + return FALSE; + } + + $authorized = FALSE; + + foreach (Module::getPaymentModules() as $module) + { + if ($module['name'] == 'mollie') + { + $authorized = TRUE; + break; + } + } + + if (!$authorized) + { + return FALSE; + } + + if (!Validate::isLoadedObject($customer)) + { + return FALSE; + } + + return TRUE; + } + + /** + * Retrieves a list of issuers for the selected method + * + * @param string $method + * @return array + */ + protected function _getIssuerList($method) + { + try + { + $issuers = $this->module->api->issuers->all(); + $issuer_list = array(); + foreach ($issuers as $issuer) + { + if ($issuer->method === $method) + { + $issuer_list[$issuer->id] = $issuer->name; + } + } + return $issuer_list; + } + catch (Mollie_API_Exception $e) + { + if ($this->module->getConfigValue('MOLLIE_DEBUG_LOG')) + { + Logger::addLog(__METHOD__ . ' said: ' . $e->getMessage(), Mollie::NOTICE); + } + } + return array(); + } + + /** + * @param float $amount + * @return float + */ + protected function _convertCurrencyToEuro($amount) + { + $cart = $this->context->cart; + $currency_euro = Currency::getIdByIsoCode('EUR'); + if (!$currency_euro) + { + // No Euro currency available! + if ($this->module->getConfigValue('MOLLIE_DEBUG_LOG')) + { + Logger::addLog(__METHOD__ . ' said: In order to use this module, you need to enable Euros as currency.', Mollie::CRASH); + } + die($this->module->lang['This payment method is only available for Euros.']); + } + + if ($cart->id_currency !== $currency_euro) + { + // Convert non-euro currency to default + $amount = Tools::convertPrice($amount, $cart->id_currency, FALSE); + + if (Currency::getDefaultCurrency() !== $currency_euro) + { + // If default is not euro, convert to euro + $amount = Tools::convertPrice($amount, $currency_euro, TRUE); + } + + } + + return round($amount, 2); + } + + /** + * @param float $amount + * @param string $method + * @param string|null $issuer + * @param int $order_id + * @return array + */ + protected function _getPaymentData($amount, $method, $issuer, $order_id) + { + $payment_data = array( + "amount" => $amount, + "method" => $method, + "issuer" => $issuer, + "description" => str_replace('%', $order_id, $this->module->getConfigValue('MOLLIE_DESCRIPTION')), + "redirectUrl" => $this->context->link->getModuleLink('mollie','return', array( + 'id' => $order_id, + 'ref' => Order::getUniqReferenceOf($order_id)) + ), + "webhookUrl" => $this->context->link->getModuleLink('mollie', 'webhook'), + "metadata" => array( + "order_id" => $order_id, + ), + ); + + if (isset($this->context, $this->context->cart)) + { + if (isset($this->context->cart->id_address_invoice)) + { + $billing = new Address(intval($this->context->cart->id_address_invoice)); + $payment_data['billingCity'] = $billing->city; + $payment_data['billingRegion'] = State::getNameById($billing->id_state); + $payment_data['billingPostal'] = $billing->postcode; + $payment_data['billingCountry'] = Country::getIsoById($billing->id_country); + } + if (isset($this->context->cart->id_address_delivery)) + { + $shipping = new Address(intval($this->context->cart->id_address_delivery)); + $payment_data['shippingCity'] = $shipping->city; + $payment_data['shippingRegion'] = State::getNameById($shipping->id_state); + $payment_data['shippingPostal'] = $shipping->postcode; + $payment_data['shippingCountry'] = Country::getIsoById($shipping->id_country); + } + } + + return $payment_data; + } + + /** + * @param array $data + * @return Mollie_API_Object_Payment|null + */ + protected function _createPayment($data) + { + $payment = null; + if ($this->module->getConfigValue('MOLLIE_USE_PROFILE_WEBHOOK')) + { + unset($data['webhookUrl']); + } + + try + { + /** @var Mollie_API_Object_Payment $payment */ + $payment = $this->module->api->payments->create($data); + } + catch (Mollie_API_Exception $e) + { + try + { + if ($e->getField() == "webhookUrl") + { + if ($this->module->getConfigValue('MOLLIE_DEBUG_LOG')) + { + Logger::addLog(__METHOD__ . ' said: Could not reach generated webhook url, falling back to profile webhook url.', Mollie::WARNING); + } + unset($data['webhookUrl']); + $payment = $this->module->api->payments->create($data); + } + else + { + throw $e; + } + } + catch (Mollie_API_Exception $e) + { + if ($this->module->getConfigValue('MOLLIE_DEBUG_LOG')) + { + Logger::addLog(__METHOD__ . ' said: ' . $e->getMessage(), Mollie::CRASH); + } + if ($this->module->getConfigValue('MOLLIE_DISPLAY_ERRORS')) + { + die( + $this->module->lang['There was an error while processing your request: '] . + '
' . $e->getMessage() . '

' . + '' . + $this->module->lang['Click here to continue'] . + '.' + ); + } + else + { + Tools::redirect(_PS_BASE_URL_ . __PS_BASE_URI__); + } + } + } + return $payment; + } +} diff --git a/mollie/controllers/front/return.php b/mollie/controllers/front/return.php new file mode 100644 index 000000000..31c6d119e --- /dev/null +++ b/mollie/controllers/front/return.php @@ -0,0 +1,117 @@ + + * @copyright Mollie B.V. + * @link https://www.mollie.nl + */ + +if (!defined('_PS_VERSION_')) +{ + die('No direct script access'); +} + +/** + * Class MollieReturnModuleFrontController + * @method setTemplate + * @property mixed context + * @property Mollie module + */ + +class MollieReturnModuleFrontController extends ModuleFrontController +{ + /** + * @see FrontController::initContent() + */ + public function initContent() + { + parent::initContent(); + + $order_id = (int) $_GET['id']; + + // Check if user is allowed to be on the return page + $data['auth'] = Order::getUniqReferenceOf($order_id) === $_GET['ref']; + + // Get order information (if user is allowed to see it) + if ($data['auth']) + { + $data['mollie_info'] = Db::getInstance()->getRow( + sprintf( + 'SELECT * FROM `%s` WHERE `order_id` = %d', + _DB_PREFIX_ . 'mollie_payments', + $order_id + ) + ); + + if ($data['mollie_info'] === FALSE) + { + $data['mollie_info'] = array(); + $data['msg_details'] = $this->module->lang('The order with this id does not exist.'); + } + else + { + switch ($data['mollie_info']['bank_status']) + { + case Mollie_API_Object_Payment::STATUS_OPEN: + $data['msg_details'] = $this->module->lang('We have not received a definite payment status. You will be notified as soon as we receive a confirmation of the bank/merchant.'); + break; + case Mollie_API_Object_Payment::STATUS_CANCELLED: + $data['msg_details'] = $this->module->lang('You have cancelled your order.'); + break; + case Mollie_API_Object_Payment::STATUS_EXPIRED: + $data['msg_details'] = $this->module->lang('Unfortunately your order was expired.'); + break; + case Mollie_API_Object_Payment::STATUS_PAID: + $data['msg_details'] = $this->module->lang('Thank you. Your order has been received.'); + break; + default: + $data['msg_details'] = $this->module->lang('The transaction has an unexpected status.'); + if (Configuration::get('MOLLIE_DEBUG_LOG')) + { + Logger::addLog(__METHOD__ . 'said: The transaction has an unexpected status ('.$data['mollie_info']['bank_status'].')', Mollie::WARNING); + } + } + } + } + // Not allowed? Don't make query but redirect. + else + { + $data['mollie_info'] = array(); + $data['msg_details'] = $this->module->lang('You are not authorised to see this page.'); + Tools::redirect(_PS_BASE_URL_ . __PS_BASE_URI__); + } + + $data['msg_continue'] = '' . $this->module->lang('Continue shopping') . ''; + $data['msg_welcome'] = $this->module->lang('Welcome back'); + + $this->context->smarty->assign($data); + $this->setTemplate('mollie_return.tpl'); + } +} diff --git a/mollie/controllers/front/webhook.php b/mollie/controllers/front/webhook.php new file mode 100644 index 000000000..f6d9ce46a --- /dev/null +++ b/mollie/controllers/front/webhook.php @@ -0,0 +1,138 @@ + + * @copyright Mollie B.V. + * @link https://www.mollie.nl + */ + +if (!defined('_PS_VERSION_')) +{ + die('No direct script access'); +} + +/** + * Class MollieReturnModuleFrontController + * @method setTemplate + * @property mixed context + * @property Mollie module + */ + +class MollieWebhookModuleFrontController extends ModuleFrontController +{ + /** + * @see FrontController::initContent() + */ + public function initContent() + { + parent::initContent(); + + echo $this->_executeWebhook(); + exit; + } + + + /** + * @return string + */ + protected function _executeWebhook() + { + if (Tools::getValue('testByMollie')) + { + if ($this->module->getConfigValue('MOLLIE_DEBUG_LOG')) + { + Logger::addLog(__METHOD__ . 'said: Mollie webhook tester successfully communicated with the shop.', Mollie::NOTICE); + } + return 'OK'; + } + + $id = Tools::getValue('id'); + + if (empty($id)) + { + if ($this->module->getConfigValue('MOLLIE_DEBUG_LOG')) + { + Logger::addLog(__METHOD__ . 'said: Received webhook request without proper transaction ID.', Mollie::WARNING); + } + return 'NO ID'; + } + + try + { + /** @var Mollie_API_Object_Payment $payment */ + $payment = $this->module->api->payments->get($id); + $order_id = $payment->metadata->order_id; + $status = $payment->status; + } + catch (Exception $e) + { + if ($this->module->getConfigValue('MOLLIE_DEBUG_LOG')) + { + Logger::addLog(__METHOD__ . 'said: Could not retrieve payment details for id "' . $id . '". Reason: ' . $e->getMessage(), Mollie::WARNING); + } + return 'NOT OK'; + } + + // Store status in database + if (!$this->_saveOrderStatus($order_id, $status)) + { + if ($this->module->getConfigValue('MOLLIE_DEBUG_LOG')) + { + Logger::addLog(__METHOD__ . 'said: Could not save order status for payment "' . $id . '". Reason: ' . Db::getInstance()->getMsgError(), Mollie::WARNING); + } + } + + // Tell status to Shop + $this->module->setOrderStatus($order_id, $status); + + // Log successful webhook requests in extended log mode only + if ($this->module->getConfigValue('MOLLIE_DEBUG_LOG') > 1) + { + Logger::addLog(__METHOD__ . 'said: Received webhook request for order ' . (int) $order_id . ' / transaction ' . htmlentities($id), Mollie::NOTICE); + } + return 'OK'; + } + + + /** + * @param $order_id + * @param $status + * @return bool + */ + protected function _saveOrderStatus($order_id, $status) + { + $data = array( + 'updated_at' => date("Y-m-d H:i:s"), + 'bank_status' => $status, + ); + + return Db::getInstance()->update('mollie_payments', $data, '`order_id` = ' . (int)$order_id); + } +} diff --git a/mollie/css/mollie.css b/mollie/css/mollie.css new file mode 100644 index 000000000..15fa102db --- /dev/null +++ b/mollie/css/mollie.css @@ -0,0 +1,101 @@ +.mollie_methods p.payment_module a +{ + padding-left: 1px; + padding-right: 40px; + background: #FBFBFB; +} +.mollie_image +{ + margin-left: 26px; + padding-right: 20px; +} +.mollie_image_big +{ + margin-left: 6px; +} +.mollie_margin +{ + display: block; + float: left; + width: 96px; +} +.mollie_issuers +{ + display: block; + color: #333333; + padding-left: 96px; +} +.mollie_issuers select, .mollie_issuers input +{ + border: 1px solid #D6D4D4; + border-radius: 4px; + background: #FBFBFB; + height: 20px; +} +.mollie_refund +{ + background-color: #EBEDF4; + border: 1px solid #CCCED7; + color: #585A69; + font-size: 1.1em; + margin: 0; + margin-top: 25px; + padding: 1em; + padding-top: 20px; + position: relative; +} +.mollie_refund_message +{ + background: none repeat scroll 0 0 #EBEDF4; + border: 1px solid #CCCED7; + font-weight: 700; + padding: 0.2em 0.5em; + text-align: left; + display: inline; + margin: 0; + position: absolute; + top: -10px; +} +.mollie_refund_message img +{ + margin-right: 10px; +} +.mollie_refund_button +{ + background: -moz-linear-gradient(center top , #F9F9F9, #E3E3E3) repeat scroll 0 0 rgba(0, 0, 0, 0); + border-color: #CCCCCC #BBBBBB #A0A0A0; + border-radius: 3px; + border-style: solid; + border-width: 1px; + color: #000000; + cursor: pointer; + margin: 0; + outline: medium none; + padding: 3px 8px; + text-align: center; + text-shadow: 0 1px 0 #FFFFFF; + vertical-align: middle; + white-space: nowrap; +} +.mollie_refund_button:hover +{ + border: 1px solid #939393; +} +.mollie_refund_fail +{ + font-weight: bold; + color: #e9322d; +} +.mollie_refund_success +{ + font-weight: bold; + color: #46a546; +} +.mollie_refund_details +{ + font-size: small; +} +.mollie_refund_desc +{ + margin-bottom: 10px; +} \ No newline at end of file diff --git a/mollie/css/mollie_bootstrap.css b/mollie/css/mollie_bootstrap.css new file mode 100644 index 000000000..033732571 --- /dev/null +++ b/mollie/css/mollie_bootstrap.css @@ -0,0 +1,129 @@ +.mollie_methods +{ + width: 50%; + padding-right: 15px; + margin-top: 15px; +} +.mollie_methods p.payment_module +{ + margin-top: -15px; +} +.mollie_methods p.payment_module a:after +{ + display: block; + content: "\f054"; + font-family: "FontAwesome", Sans-Serif; + position: absolute; + right: 15px; + top: 50%; + font-size: 25px; + height: 22px; + margin-top: -11px; + width: 14px; + color: #777777; +} +.mollie_methods p.payment_module a +{ + padding-left: 1px; + padding-right: 40px; + background: #FBFBFB; +} +.mollie_image +{ + margin-left: 29px; + margin-right: 29px; +} +.mollie_image_big +{ + margin-left: 9px; + margin-right: 9px; +} +.mollie_margin +{ + display: block; + float: left; + width: 99px; +} +.mollie_issuers +{ + display: block; + margin-top: -20px; + margin-bottom: 30px; + padding-top: 20px; + padding-bottom: 20px; + padding-left: 99px; + background-color: #D6D4D4; + color: #333333; +} +.mollie_issuers select, .mollie_issuers input +{ + border: 1px solid #D6D4D4; + border-radius: 4px; + background: #FBFBFB; + height: 20px; +} +.mollie_refund +{ + border: 1px solid #D6D4D4; + border-radius: 4px; + background: #FFFFFF; + color: #333333; + padding: 20px; + margin-bottom: 20px; +} +.mollie_refund_message +{ + font-family: "Ubuntu Condensed", Helvetica, Arial, sans-serif; + font-size: 14px; + color: #555555; + border-bottom: 1px solid #EEEEEE; + text-transform: uppercase; + margin: -20px -16px 15px; + padding: 0 0 0 5px; +} +.mollie_refund_message img +{ + margin-right: 3px; +} +.mollie_refund_button_box +{ + background-color: #FCFDFE; + border: 1px solid #E1EBF5; + border-radius: 3px; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05) inset; + min-height: 20px; + padding: 19px; +} +.mollie_refund_button +{ + background-color: #FFFFFF; + box-shadow: 0 -2px 0 #E6E6E6 inset; + border: 1px solid #CCCCCC; + border-radius: 3px; + padding: 4px 8px; +} +.mollie_refund_button:hover +{ + background-color: #00AFF0; + box-shadow: none; + border: 1px solid #008ABD; + color: #FFFFFF; +} +.mollie_refund_fail +{ + font-weight: bold; + color: #e9322d; +} +.mollie_refund_success +{ + font-weight: bold; + color: #46a546; +} +.mollie_refund_details +{ + font-size: small; +} +.mollie_refund_desc +{ + margin-bottom: 10px; +} \ No newline at end of file diff --git a/mollie/lib b/mollie/lib new file mode 160000 index 000000000..31133c456 --- /dev/null +++ b/mollie/lib @@ -0,0 +1 @@ +Subproject commit 31133c456d9c7914cd6e708457421ebc1ca123cf diff --git a/mollie/logo.png b/mollie/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f34df2891c5162ed9fda1638cc1aba822dd19c41 GIT binary patch literal 2028 zcmV-P)x09w$NHa0!l?_3$~%t`_aq2cjlaZ_Fl_}GjnF)=VyIFhDanR2Lu;z0>6=My? zjP>n`ec*eEAypl5r3k2?OC8iXuogrxwHj>OUYaK|u7Cnj1cgHv7eMd9W-riw%!22V^rYYz1VsK^#PI? zmT#gf%TP^neWoxwiVK5HBW_EYg9oMRYfV^I7gPG_{pg;BWp=Qc=!-* z;W`*lkxGmRZoP{fdTb0FKz8iJr!8Yi%Y101ceajb$i$&PcYcH3-7;&?{&*yt0#z!kwQQ=D1Zb)D8&bl z1SzApRvQN2)lXRZ>#3m|9y&xGMQGtl`d4n^Z@Yu!@YeyzZgf~W@h76e8fgKAD@W|v;wbN=@MmB%4QXn~a6rH^rU0OnIguDJJJn$gRUALBuop}R) z?oFabdA8X&Lfcb_bBM@B1r#@`fOx$3Fuk=>AW2igJLgzmSOB2WYQg>oaSI(x2xQJt zd;H02eDCy0YM)*k1|eYDZM@3~8w|D@RLc(`1VOyueSoPg!!T~7@UM?qz3^7mR6lT# zo)75FW&G}08jn0$x(mop{h3CZ5=PTR+9J3D@ls)hAlTCHVJJS}LV(H13M`;R4%W|~ z9lGI>BgpNuWdFW`y?RfJl5cm{Zv z)3#9j?G0SNE!}-P(cb&$twa6MCo1~8r%qDOKsKBOw$VUBz*RUUmhEPR$+DbY=ICZQ zS)P+S#YFX?0_#0Y3-Y)B&f-7bEf)mp_dUQW&^U0gqJQo9tJDG4%g0l3bAl`vdfkj( zmiNVBUGQ3jKoJ5y1e|kZ3Ys>D+pxP%rVy^JvT}NUm`v`vmtz0@Onl{@a_^r%NAKKO z!X)Ht>tig)^c1;3;XOqN6cX?fu%Z~%{t2jxIES{I*e$~#46CaY0<8wDoS3T?PWJ9) z`st?`)L=JHyh?PVhqNc~c}~&o4tK(qtprQydsRe~AW9rmDTFd&jlmWkNfOLR5Ee^| z1PAq9Qxq58V(HpdW^Ub0`<{DAzr1Hi|J-pVCL@A@kY|K$7n&uLQLBwNU`5KzIfxAr zQLjRfQVQqLMw57AdPv{$BI3bJPotMREWY+yKLcB8{nM^<_6+XrbJTXu5ELZOklv61 zTW=s3d`t(o%&B}nvjU_d(GC#K|HHwv=vpY*w~h^e&!8U*4BnD0#@ecXtoVO0@w&~ z`4|K7^fa_vXyM1VXQ671>1SsH;=wlCRVD<`qCkP5O1yOo{^Av`pB(0ftFOOKcK%K3 zJ7)-@NED&DE9=R@$vLx~Xkrra4mD;_5tz6@5j9Ak3XMSOHI`S`aCwFY)^6OuHv4sf ziP$<7@zIOF;?gG{m&?5J2WIMqqLvUs$pFr=_~8fC_k9iZp0$e?Dc067wHl(;293<| zJ9k{1v1ZSJm{^sydV@=~I;)Ed;0o@TYBL+hs0aZ_lNz0?i@d+QP7Szwy2;FKGvs;c zDr*cT2>6RB#CeaIYyV-Fwb;mFTuu?k zWmW@vnPbb$6c2Bo0t~8Jduj}Ls*xgO8WZcFxk*!ku0*=?D^ zZ*+qdI&$SR8`}TZ4b6VR-2T{Sp1iX7B0xOfb+-UlzHw#oh3B?UoU!n%zx#5`riy ztcWgDgtQQ(Qd0|Z#%9j>&iStI+w%mdPaS&_uL{-y00000yOP&>AAR*^XrDQDBFlVA z#(XYKc7;xdl~uBgl<0KGb7{Iue;}-^k_A#a9i}Ib{;<&N9%<`Z41wiUshA5p+l&^7 zk-C<$Agpaj`Ba!qb@~Iim^CTgN7DXvReAIgz4t!WJNJcZqnu1sRV8cdMpf0ywiOqb^txU3_uqi-;ro?~3?4dW zw)uf{={I0`S((q&bt9YRvy|tBJTHXN2;|>>tx8Gn&;#1T4}!_&S>37vvD-Jdy;V6_cVW)r$+d`}V76 zxzw=r{=2%1OYS)Nw7<{1u0)l9I2D~(2`*t&8>Gt9(mH(lF2XLRtO{KxO~`xM(-3KTI4fhY=J z-o18l9O9v>KlJx-L7MD3kR`*Ax%uyws;cZ?+p9C^+o@aEMvK@z&qW}N^ literal 0 HcmV?d00001 diff --git a/mollie/mollie.php b/mollie/mollie.php new file mode 100644 index 000000000..5adc02882 --- /dev/null +++ b/mollie/mollie.php @@ -0,0 +1,815 @@ + + * @copyright Mollie B.V. + * @link https://www.mollie.nl + */ + +if (!defined('_PS_VERSION_')) +{ + die('No direct script access'); +} + +/** + * Class Mollie + * @method l + * @method display + * @method registerHook + * @method unregisterHook + * @method validateOrder + * @property mixed warning + * @property mixed _errors + * @property mixed _path + * @property mixed smarty + * @property mixed context + * @property mixed currentOrder + * @property mixed active + */ + +class Mollie extends PaymentModule +{ + /** @var Mollie_API_Client|null */ + public $api = NULL; + public $statuses = array(); + public $name = 'mollie'; + public $tab = 'payments_gateways'; + public $version = '1.0.0'; + public $author = 'Mollie B.V.'; + public $need_instance = TRUE; + public $ps_versions_compliancy = array('min' => '1.5', 'max' => '2'); + public $dependencies = array('blockcart'); + public $lang = array(); + + const NOTICE = 1; + const WARNING = 2; + const ERROR = 3; + const CRASH = 4; + + const NAME = 'mollie'; + + public function __construct() + { + parent::__construct(); + + $this->displayName = $this->l('Mollie Payment Module'); + $this->description = $this->l('Mollie Payments'); + + $this->confirmUninstall = $this->l('Are you sure you want to uninstall the Mollie Payment Module?'); + + require_once(dirname(__FILE__) . '/lib/src/Mollie/API/Autoloader.php'); + + try + { + $this->api = new Mollie_API_Client; + $this->api->setApiKey($this->getConfigValue('MOLLIE_API_KEY')); + $this->api->addVersionString('Prestashop/' . defined(_PS_VERSION_) ? _PS_VERSION_ : 'Unknown'); + $this->api->addVersionString('MolliePrestashop/' . isset($this->version) ? $this->version : 'Unknown'); + } + catch (Mollie_API_Exception $e) + { + $this->warning = $this->l('Payment error:') . $e->getMessage(); + Logger::addLog(__METHOD__ . ' said: ' . $this->warning, Mollie::CRASH); + } + + $this->statuses = array( + Mollie_API_Object_Payment::STATUS_OPEN => $this->getConfigValue('MOLLIE_STATUS_OPEN'), + Mollie_API_Object_Payment::STATUS_PAID => $this->getConfigValue('MOLLIE_STATUS_PAID'), + Mollie_API_Object_Payment::STATUS_CANCELLED => $this->getConfigValue('MOLLIE_STATUS_CANCELLED'), + Mollie_API_Object_Payment::STATUS_EXPIRED => $this->getConfigValue('MOLLIE_STATUS_EXPIRED'), + Mollie_API_Object_Payment::STATUS_REFUNDED => $this->getConfigValue('MOLLIE_STATUS_REFUNDED'), + ); + + // Load all translatable text here so we have a single translation point + $this->lang = array( + Mollie_API_Object_Payment::STATUS_OPEN => $this->l('open'), + Mollie_API_Object_Payment::STATUS_PAID => $this->l('paid'), + Mollie_API_Object_Payment::STATUS_CANCELLED => $this->l('cancelled'), + Mollie_API_Object_Payment::STATUS_EXPIRED => $this->l('expired'), + Mollie_API_Object_Payment::STATUS_REFUNDED => $this->l('refunded'), + 'This payment method is not available.' => $this->l('This payment method is not available.'), + 'Click here to continue' => $this->l('Click here to continue'), + 'This payment method is only available for Euros.' => $this->l('This payment method is only available for Euros.'), + 'There was an error while processing your request: ' => $this->l('There was an error while processing your request: '), + 'The order with this id does not exist.' => $this->l('The order with this id does not exist.'), + 'We have not received a definite payment status. You will be notified as soon as we receive a confirmation of the bank/merchant.' => + $this->l('We have not received a definite payment status. You will be notified as soon as we receive a confirmation of the bank/merchant.'), + 'You have cancelled your order.' => $this->l('You have cancelled your order.'), + 'Unfortunately your order was expired.' => $this->l('Unfortunately your order was expired.'), + 'Thank you. Your order has been received.' => $this->l('Thank you. Your order has been received.'), + 'The transaction has an unexpected status.' => $this->l('The transaction has an unexpected status.'), + 'You are not authorised to see this page.' => $this->l('You are not authorised to see this page.'), + 'Continue shopping' => $this->l('Continue shopping'), + 'Welcome back' => $this->l('Welcome back'), + 'Select your bank:' => $this->l('Select your bank:'), + 'OK' => $this->l('OK'), + 'Return to the homepage' => $this->l('Return to the homepage'), + 'Pay with %s' => $this->l('Pay with %s'), + 'Refund this order' => $this->l('Refund this order'), + 'Mollie refund' => $this->l('Mollie refund'), + 'Refund order #%d through the Mollie API.' => $this->l('Refund order #%d through the Mollie API.'), + 'iDEAL' => $this->l('iDEAL'), + 'Creditcard' => $this->l('Creditcard'), + 'Mister Cash' => $this->l('Mister Cash'), + 'Bank transfer' => $this->l('Bank transfer'), + 'PayPal' => $this->l('PayPal'), + 'paysafecard' => $this->l('paysafecard'), + 'MiniTix' => $this->l('MiniTix'), + 'Micropayments' => $this->l('Micropayments'), + ); + + // If an update includes a new hook, it normally takes a manual reinstall for it to take effect + // This would cause all config values to reset and the Mollie table to be cleared. + // $this->reinstall() fixes the hook registration without those sad side effects. + $version = $this->getConfigValue('MOLLIE_VERSION'); + if ($version === FALSE || !version_compare($this->version, $version, '>=')) + { + $this->reinstall(); + } + } + + + /** + * Installs the Mollie Payments Module + * + * @return bool + */ + public function install() + { + if ( + !parent::install() || + !$this->_registerHooks() + ) + { + $this->_errors[] = 'Unable to install module'; + return FALSE; + } + if ( + !$this->_initConfig() + ) + { + $this->_errors[] = 'Unable to set config values'; + return FALSE; + } + + $sql = sprintf(' + CREATE TABLE IF NOT EXISTS `%s` ( + `order_id` INT(64) NOT NULL PRIMARY KEY, + `method` VARCHAR(128) NOT NULL, + `transaction_id` VARCHAR(64) NOT NULL, + `bank_status` VARCHAR(64) NOT NULL, + `created_at` DATETIME NOT NULL, + `updated_at` DATETIME DEFAULT NULL, + UNIQUE KEY `transaction_id` (`transaction_id`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8;', + _DB_PREFIX_ . 'mollie_payments' + ); + + if (!Db::getInstance()->execute($sql)) + { + $this->_errors[] = 'Database error: ' . Db::getInstance()->getMsgError(); + return FALSE; + } + + return TRUE; + } + + /** + * @return bool + */ + public function uninstall() + { + if (!$this->_unregisterHooks()) + { + $this->_errors[] = 'Unable to unregister the module'; + return FALSE; + } + if ( + !$this->deleteConfigValue('MOLLIE_VERSION') || + !$this->deleteConfigValue('MOLLIE_API_KEY') || + !$this->deleteConfigValue('MOLLIE_DESCRIPTION') || + !$this->deleteConfigValue('MOLLIE_IMAGES') || + !$this->deleteConfigValue('MOLLIE_ISSUERS') || + !$this->deleteConfigValue('MOLLIE_CSS') || + !$this->deleteConfigValue('MOLLIE_DEBUG_LOG') || + !$this->deleteConfigValue('MOLLIE_DISPLAY_ERRORS') || + !$this->deleteConfigValue('MOLLIE_USE_PROFILE_WEBHOOK') || + !$this->deleteConfigValue('MOLLIE_STATUS_OPEN') || + !$this->deleteConfigValue('MOLLIE_STATUS_PAID') || + !$this->deleteConfigValue('MOLLIE_STATUS_CANCELLED') || + !$this->deleteConfigValue('MOLLIE_STATUS_EXPIRED') || + !$this->deleteConfigValue('MOLLIE_STATUS_REFUNDED') || + !$this->deleteConfigValue('MOLLIE_MAIL_WHEN_OPEN') || + !$this->deleteConfigValue('MOLLIE_MAIL_WHEN_PAID') || + !$this->deleteConfigValue('MOLLIE_MAIL_WHEN_CANCELLED') || + !$this->deleteConfigValue('MOLLIE_MAIL_WHEN_EXPIRED') || + !$this->deleteConfigValue('MOLLIE_MAIL_WHEN_REFUNDED') + ) + { + $this->_errors[] = 'Unable to unset the configuration'; + return FALSE; + } + + $sql = sprintf('DROP TABLE IF EXISTS `%s`;', + _DB_PREFIX_ . 'mollie_payments' + ); + + if (!Db::getInstance()->execute($sql)) + { + $this->_errors[] = 'Database error: ' . Db::getInstance()->getMsgError(); + return FALSE; + } + return parent::uninstall(); + } + + + public function reinstall() + { + return + $this->_unregisterHooks() && + $this->_registerHooks() && + $this->_initConfig() + ; + } + + + /** + * @return bool + */ + protected function _registerHooks() + { + return + $this->registerHook('displayPayment') && + $this->registerHook('displayAdminOrder') && + $this->registerHook('displayHeader') && + $this->registerHook('displayBackOfficeHeader') + ; + } + + /** + * @return bool + */ + protected function _unregisterHooks() + { + return + $this->unregisterHook('displayPayment') && + $this->unregisterHook('displayAdminOrder') && + $this->unregisterHook('displayHeader') && + $this->unregisterHook('displayBackOfficeHeader') + ; + } + + /** + * @return bool + */ + protected function _initConfig() + { + return + $this->initConfigValue('MOLLIE_VERSION', $this->version) && + $this->initConfigValue('MOLLIE_API_KEY', '') && + $this->initConfigValue('MOLLIE_DESCRIPTION', 'Order %') && + $this->initConfigValue('MOLLIE_IMAGES', 'normal') && + $this->initConfigValue('MOLLIE_ISSUERS', 'on-click') && + $this->initConfigValue('MOLLIE_CSS', '') && + $this->initConfigValue('MOLLIE_DEBUG_LOG', 1) && + $this->initConfigValue('MOLLIE_DISPLAY_ERRORS', FALSE) && + $this->initConfigValue('MOLLIE_USE_PROFILE_WEBHOOK', FALSE) && + $this->initConfigValue('MOLLIE_STATUS_OPEN', 3) && + $this->initConfigValue('MOLLIE_STATUS_PAID', 2) && + $this->initConfigValue('MOLLIE_STATUS_CANCELLED', 6) && + $this->initConfigValue('MOLLIE_STATUS_EXPIRED', 8) && + $this->initConfigValue('MOLLIE_STATUS_REFUNDED', 7) && + $this->initConfigValue('MOLLIE_MAIL_WHEN_OPEN', FALSE) && + $this->initConfigValue('MOLLIE_MAIL_WHEN_PAID', TRUE) && + $this->initConfigValue('MOLLIE_MAIL_WHEN_CANCELLED', FALSE) && + $this->initConfigValue('MOLLIE_MAIL_WHEN_EXPIRED', FALSE) && + $this->initConfigValue('MOLLIE_MAIL_WHEN_REFUNDED', TRUE) + ; + } + + /** + * @return mixed + */ + public function getErrors() + { + return $this->_errors; + } + + + /** + * @return string + */ + public function getContent() + { + global $cookie; + $lang = isset($cookie->id_lang) ? (int) $cookie->id_lang : 1; + + $update_message = $this->_getUpdateMessage('https://github.com/mollie/Prestashop'); + $result_msg = ''; + $image_options = array($this->l('big'), $this->l('normal'), $this->l('hide')); + $issuer_options = array($this->l('always-visible'), $this->l('on-click'), $this->l('own-page'), $this->l('payment-page')); + $logger_options = array($this->l('Nothing'), $this->l('Errors'), $this->l('Everything')); + + if (Tools::isSubmit('Mollie_Config_Save')) + { + $result_msg = $this->_getSaveResult($image_options, $issuer_options, $logger_options); + } + + $data = array( + 'form_action' => Tools::htmlentitiesUTF8($_SERVER['REQUEST_URI']), + 'config_title' => $this->l('Mollie Configuration'), + 'config_legend' => $this->l('Mollie Settings'), + 'update_message' => $update_message, + 'all_statuses' => OrderState::getOrderStates($lang), + 'image_options' => $image_options, + 'issuer_options' => $issuer_options, + 'logger_options' => $logger_options, + 'title_status' => $this->l('%s statuses:'), + 'title_visual' => $this->l('Visual settings:'), + 'title_debug' => $this->l('Debug info:'), + 'msg_result' => $result_msg, + 'msg_api_key' => $this->l('API key:'), + 'msg_desc' => $this->l('Description:'), + 'msg_images' => $this->l('Images:'), + 'msg_issuers' => $this->l('Issuer list:'), + 'msg_css' => $this->l('Css file:'), + 'msg_errors' => $this->l('Display errors:'), + 'msg_logger' => $this->l('Log level:'), + 'msg_save' => $this->l('Save settings:'), + 'desc_api_key' => sprintf($this->l('You can find your API key in your %sMollie Profile%s; it starts with test or live.'), '', ''), + 'desc_desc' => $this->l('Enter a description here. Note: Payment methods may have a character limit, best keep the description under 29 characters.'), + 'desc_images' => $this->l('Show big, normal or no payment method logos on checkout.'), + 'desc_issuers' => $this->l('Some payment methods (eg. iDEAL) have an issuer list. This setting specifies where it is shown.'), + 'desc_css' => $this->l('Leave empty for default stylesheet. Should include file path when set.') . '
' . $this->l('Hint: You can use {BASE}, {THEME}, {CSS}, {MOBILE}, {MOBILE_CSS} and {OVERRIDE} for easy folder mapping.'), + 'desc_errors' => $this->l('Enabling this feature will display error messages (if any) on the front page. Use for debug purposes only!'), + 'desc_logger' => sprintf($this->l('Recommended level: Errors. Set to Everything to monitor incoming webhook requests. %sView logs%s'), '', ''), + 'val_api_key' => $this->getConfigValue('MOLLIE_API_KEY'), + 'val_desc' => $this->getConfigValue('MOLLIE_DESCRIPTION'), + 'val_images' => $this->getConfigValue('MOLLIE_IMAGES'), + 'val_issuers' => $this->getConfigValue('MOLLIE_ISSUERS'), + 'val_css' => $this->getConfigValue('MOLLIE_CSS'), + 'val_errors' => $this->getConfigValue('MOLLIE_DISPLAY_ERRORS'), + 'val_logger' => $this->getConfigValue('MOLLIE_DEBUG_LOG'), + 'val_save' => $this->l('Save'), + 'lang' => $this->lang, + ); + + $db = Db::getInstance(); + $msg_status = $this->l('Status for %s payments'); + $desc_status = $this->l('%s payments get status "%s"'); + $msg_mail = $this->l('Send mails when %s'); + $desc_mail = $this->l('Send mails when transaction status becomes %s?'); + foreach ($this->statuses as $name => $val) + { + $val = (int) $val; + $data['msg_status_' . $name] = sprintf($msg_status, $this->lang[$name]); + $data['desc_status_' . $name] = ucfirst(sprintf($desc_status, + $this->lang[$name], + $db->getValue('SELECT `name` FROM `' . _DB_PREFIX_ . 'order_state_lang` WHERE `id_order_state` = ' . (int) $val . ' AND `id_lang` = ' . (int) $lang) + )); + $data['val_status_' . $name] = $val; + $data['msg_mail_' . $name] = sprintf($msg_mail, $this->lang[$name]); + $data['desc_mail_' . $name] = sprintf($desc_mail, $this->lang[$name]); + $data['val_mail_' . $name] = $this->getConfigValue('MOLLIE_MAIL_WHEN_' . strtoupper($name)); + $data['statuses'][] = $name; + } + + $this->context->smarty->assign($data); + + return $this->display(__FILE__, 'mollie_config.tpl'); + } + + + + /** + * @param $field + * @param $default_value + * @return bool + */ + public function initConfigValue($field, $default_value) + { + return Configuration::updateValue($field, (Configuration::get($field) !== FALSE) ? Configuration::get($field) : $default_value); + } + + /** + * @param $field + * @return bool + */ + public function deleteConfigValue($field) + { + return Configuration::deleteByName($field); + } + + /** + * @param $field + * @param $value + * @return bool + */ + public function updateConfigValue($field, $value) + { + return Configuration::updateValue($field, $value); + } + + /** + * @param $field + * @return mixed + */ + public function getConfigValue($field) + { + return Configuration::get($field); + } + + + /** + * @param string $str + * @return string + */ + public function lang($str) + { + if (array_key_exists($str, $this->lang)) + { + return $this->lang[$str]; + } + return $str; + } + + /** + * @param $order_id + * @param $status + * @return OrderHistory + */ + public function setOrderStatus($order_id, $status) + { + $status_id = (int)$this->statuses[$status]; + $history = new OrderHistory(); + $history->id_order = $order_id; + $history->id_order_state = $status_id; + $history->changeIdOrderState($status_id, $order_id); + + if ($this->getConfigValue('MOLLIE_MAIL_WHEN_' . strtoupper($status))) + { + $history->addWithemail(); + } + else + { + $history->add(); + } + + return $history; + } + + /** + * @param array $image_options + * @param array $issuer_options + * @param array $logger_options + * @return string + */ + protected function _getSaveResult($image_options = array(), $issuer_options = array(), $logger_options = array()) + { + $errors = array(); + if (!empty($_POST['Mollie_Api_Key']) && strpos($_POST['Mollie_Api_Key'], 'live') !== 0 && strpos($_POST['Mollie_Api_Key'], 'test') !== 0) + { + $errors[] = $this->l('The API key needs to start with test or live.'); + } + if (!in_array($_POST['Mollie_Images'], $image_options)) + { + $errors[] = $this->l('Invalid image setting.'); + } + if (!in_array($_POST['Mollie_Issuers'], $issuer_options)) + { + $errors[] = $this->l('Invalid issuer setting.'); + } + if (!isset($_POST['Mollie_Css'])) + { + $_POST['Mollie_Css'] = ''; + } + if (!is_numeric($_POST['Mollie_Logger'])) + { + if (in_array($_POST['Mollie_Logger'], $logger_options)) + { + $i = 0; + while (($opt = current($logger_options)) !== FALSE) { + if ($opt == $_POST['Mollie_Logger']) { + $_POST['Mollie_Logger'] = key($logger_options); + break; + } + if ($i++ > sizeof($logger_options)) + { + $errors[] = $this->l('Invalid debug log setting.'); + break; + } + next($logger_options); + } + } + else + { + $errors[] = $this->l('Invalid debug log setting.'); + } + } + if (!isset($_POST['Mollie_Errors'])) + { + $_POST['Mollie_Errors'] = FALSE; + } + else + { + $_POST['Mollie_Errors'] = ($_POST['Mollie_Errors'] == 1); + } + foreach ($this->statuses as $name => $val) + { + if (!is_numeric($_POST['Mollie_Status_' . $name])) + { + $errors[] = ucfirst($name) . ' status must be numeric.'; + } + } + + if (empty($errors)) + { + $this->updateConfigValue('MOLLIE_API_KEY', $_POST['Mollie_Api_Key']); + $this->updateConfigValue('MOLLIE_DESCRIPTION', $_POST['Mollie_Description']); + $this->updateConfigValue('MOLLIE_IMAGES', $_POST['Mollie_Images']); + $this->updateConfigValue('MOLLIE_ISSUERS', $_POST['Mollie_Issuers']); + $this->updateConfigValue('MOLLIE_CSS', $_POST['Mollie_Css']); + $this->updateConfigValue('MOLLIE_DISPLAY_ERRORS', (int) $_POST['Mollie_Errors']); + $this->updateConfigValue('MOLLIE_DEBUG_LOG', (int) $_POST['Mollie_Logger']); + foreach ($this->statuses as $name => $old) + { + $new = (int) $_POST['Mollie_Status_' . $name]; + $this->statuses[$name] = $new; + $this->updateConfigValue('MOLLIE_STATUS_' . strtoupper($name), $new); + $this->updateConfigValue( + 'MOLLIE_MAIL_WHEN_' . strtoupper($name), + !empty($_POST['Mollie_Mail_When_' . $name]) ? TRUE : FALSE + ); + } + $result_msg = $this->l('The configuration has been saved!'); + } + else + { + $result_msg = 'The configuration could not be saved:
- ' . implode('
- ', $errors); + } + return $result_msg; + } + + + /** + * @param string $url + * @return string + */ + protected function _getUpdateMessage($url) + { + $update_message = ''; + $update_xml = $this->_getUpdateXML($url); + if ($update_xml === FALSE) + { + $update_message = $this->l('Warning: Could not retrieve update xml file from github.'); + } + else + { + /** @var SimpleXMLElement $tags */ + $tags = new SimpleXMLElement($update_xml); + if (!empty($tags) && isset($tags->entry, $tags->entry[0], $tags->entry[0]->id)) + { + $title = $tags->entry[0]->id; + $latest_version = preg_replace("/[^0-9,.]/", "", substr($title, strrpos($title, '/'))); + if (!version_compare($this->version, $latest_version, '>=')) + { + $update_message = sprintf( + '' . $this->l('You are currently using version %s. We strongly recommend you to upgrade to the new version %s!') . '', + $url, $this->version, $latest_version + ); + } + } + else + { + $update_message = $this->l('Warning: Update xml file from github follows an unexpected format.'); + } + } + + return $update_message; + } + + /** + * @param string $url + * @return string + */ + protected function _getUpdateXML($url) + { + return @file_get_contents($url . '/releases.atom'); + } + + + /** + * @param int $order_id + * @param string $transaction_id + * @return string + */ + protected function _doRefund($order_id, $transaction_id) + { + try + { + $payment = $this->api->payments->get($transaction_id); + $this->api->payments->refund($payment); + } + catch (Mollie_API_Exception $e) + { + return array( + 'status' => 'fail', + 'msg_fail' => $this->lang('The order could not be refunded!'), + 'msg_details' => $this->lang('Reason:') . ' ' . $e->getMessage(), + ); + } + + // Tell status to shop + $this->setOrderStatus($order_id, Mollie_API_Object_Payment::STATUS_REFUNDED); + + // Save status in mollie_payments table + $update_data = array( + 'updated_at' => date("Y-m-d H:i:s"), + 'bank_status' => Mollie_API_Object_Payment::STATUS_REFUNDED, + ); + + Db::getInstance()->update('mollie_payments', $update_data, '`order_id` = ' . (int) $order_id); + + return array( + 'status' => 'success', + 'msg_success' => $this->lang('The order has been refunded!'), + 'msg_details' => $this->lang('Mollie B.V. will transfer the money back to the customer on the next business day.'), + ); + } + + /** + * @return array + */ + protected function _getIssuerList() + { + $issuers = $this->api->issuers->all(); + + $issuer_list = array(); + foreach ($issuers as $issuer) + { + $issuer_list[$issuer->method][$issuer->id] = $issuer->name; + } + return $issuer_list; + } + + protected function _addCSSFile($file = null) + { + if (is_null($file)) + { + $file = $this->getConfigValue('MOLLIE_CSS'); + } + + if (empty($file)) + { + if (strpos(_PS_THEME_DIR_, '/default-bootstrap/') !== FALSE) + { + // Use a modified css file for the new 1.6 default layout + $file = $this->_path . 'css/mollie_bootstrap.css'; + } + else + { + // Use default css file + $file = $this->_path . 'css/mollie.css'; + } + } + else + { + // Use a custom css file + $file = str_replace('{BASE}', _PS_BASE_URL_, $file); + $file = str_replace('{THEME}', _PS_THEME_DIR_, $file); + $file = str_replace('{CSS}', _PS_CSS_DIR_, $file); + $file = str_replace('{MOBILE}', _THEME_MOBILE_DIR_, $file); + $file = str_replace('{MOBILE_CSS}', _THEME_MOBILE_CSS_DIR_, $file); + $file = str_replace('{OVERRIDE}', _PS_THEME_OVERRIDE_DIR_, $file); + } + $this->context->controller->addCSS($file); + } + + // Hooks + + /** + */ + public function hookDisplayHeader() + { + $this->_addCSSFile($this->getConfigValue('MOLLIE_CSS')); + } + + public function hookDisplayBackOfficeHeader() + { + $this->_addCSSFile($this->getConfigValue('MOLLIE_CSS')); + } + + /** + * @param $params + * @return string + */ + public function hookDisplayAdminOrder($params) + { + $mollie_data = Db::getInstance()->getRow(sprintf( + 'SELECT * FROM `%s` WHERE `order_id` = %s;', + _DB_PREFIX_ . 'mollie_payments', + (int) $params['id_order'] + )); + + // Do not show refund option if it's not a successfully paid Mollie transaction + if ($mollie_data === FALSE || $mollie_data['bank_status'] !== Mollie_API_Object_Payment::STATUS_PAID) + { + return ''; + } + + if (Tools::isSubmit('Mollie_Refund')) + { + $tpl_data = $this->_doRefund($mollie_data['order_id'], $mollie_data['transaction_id']); + } + else + { + $tpl_data = array( + 'status' => 'form', + 'msg_button' => $this->lang['Refund this order'], + 'msg_description' => sprintf($this->lang['Refund order #%d through the Mollie API.'], (int) $mollie_data['order_id']), + ); + } + + $tpl_data['msg_title'] = $this->lang['Mollie refund']; + $tpl_data['img_src'] = $this->_path . 'logo_small.png'; + $this->smarty->assign($tpl_data); + return $this->display(__FILE__, 'mollie_refund.tpl'); + } + + /** + * @return string + */ + public function hookDisplayPayment() + { + if (!Currency::exists('EUR', 0)) + { + return '

' . + $this->l('Mollie Payment Methods are only available when Euros are activated.') . + '

'; + } + + $issuer_setting = $this->getConfigValue('MOLLIE_ISSUERS'); + $show_issuers_here = in_array($issuer_setting, array('always-visible', 'on-click')); + + try { + $methods = $this->api->methods->all(); + $issuer_list = in_array($issuer_setting, array('always-visible', 'on-click')) ? $this->_getIssuerList($show_issuers_here) : array(); + } catch (Mollie_API_Exception $e) { + $methods = array(); + $issuer_list = array(); + + if ($this->getConfigValue('MOLLIE_DEBUG_LOG')) + { + Logger::addLog(__METHOD__ . ' said: ' . $e->getMessage(), Mollie::ERROR); + } + if ($this->getConfigValue('MOLLIE_DISPLAY_ERRORS')) + { + return + '

' . + $e->getMessage() . + '

' + ; + } + } + + $this->smarty->assign(array( + 'methods' => $methods, + 'issuers' => $issuer_list, + 'issuer_setting' => $issuer_setting, + 'images' => $this->getConfigValue('MOLLIE_IMAGES'), + 'warning' => $this->warning, + 'msg_pay_with' => $this->lang['Pay with %s'], + 'msg_bankselect' => $this->lang['Select your bank:'], + 'module' => $this, + )); + + return $this->display(__FILE__, 'mollie_methods.tpl'); + } +} diff --git a/mollie/translations/fr.php b/mollie/translations/fr.php new file mode 100644 index 000000000..b1ca1dad9 --- /dev/null +++ b/mollie/translations/fr.php @@ -0,0 +1,86 @@ +mollie_09748ce33c8a71296b20ba8c3bd1d13e'] = 'Module de Paiement Mollie'; +$_MODULE['<{mollie}prestashop>mollie_95b3b272e06dcc3cc2aa62f6887aebc5'] = 'Paiements Mollie'; +$_MODULE['<{mollie}prestashop>mollie_48dedcf43487615c84c1bbbf6fe76c76'] = 'Etes-vous sûr de vouloir désinstaller le Module de Paiement Mollie?'; +$_MODULE['<{mollie}prestashop>mollie_ab552f085567bbe63872c10a3596cd27'] = 'Erreur de paiement:'; +$_MODULE['<{mollie}prestashop>mollie_7cef8a734855777c2a9d0caf42666e69'] = 'ouvert'; +$_MODULE['<{mollie}prestashop>mollie_76e084771e78c194efd0e2d5b8920bea'] = 'payé'; +$_MODULE['<{mollie}prestashop>mollie_38881e0a24039dc2621e1d6f86cb71f7'] = 'annulé'; +$_MODULE['<{mollie}prestashop>mollie_c4bfb2a0bab0e91bc7dcfbe3bbec246e'] = 'expiré'; +$_MODULE['<{mollie}prestashop>mollie_ad32204fca182b862a5f97a5534c03a2'] = 'remboursé'; +$_MODULE['<{mollie}prestashop>mollie_e2b7dec8fa4b498156dfee6e4c84b156'] = 'Ce methode de paiement n\'est pas disponible.'; +$_MODULE['<{mollie}prestashop>mollie_96d0e2862e0167af0c2fd0c99fe6bc5d'] = 'Cliquez ici pour continuer'; +$_MODULE['<{mollie}prestashop>mollie_540d9939d1ca9406e215ee3d78c76813'] = 'Ce methode de paiement n\'est seulement disponible pour les Euros.'; +$_MODULE['<{mollie}prestashop>mollie_1b2631119333d97dbda37f87e378b1e4'] = 'Il y avait un erreur lors du traitement de votre demande:'; +$_MODULE['<{mollie}prestashop>mollie_11bab828edcc0a6d5c97cbf84d61e652'] = 'La commande avec cette id n\'existe pas.'; +$_MODULE['<{mollie}prestashop>mollie_b34487c5f391f47b893ee3c61f8f9ab7'] = 'Nous n\'avons pas encore reçu un statut de paiement définitif. Vous serez informé dès que nous recevrons une confirmation de la banque.'; +$_MODULE['<{mollie}prestashop>mollie_d04c33bc66aeb69216e33a7eed26cfdc'] = 'Vous avez annulé votre commande.'; +$_MODULE['<{mollie}prestashop>mollie_3df6fa973fa0c51d0177b1a5b5091295'] = 'Malheureusement votre commande est expiré.'; +$_MODULE['<{mollie}prestashop>mollie_2afe257b1674f4160f5297c50bb8ab77'] = 'Merci! Votre commande a été reçu'; +$_MODULE['<{mollie}prestashop>mollie_7352a401b3c23b2966c68bc9ab97fa06'] = 'La transaction a un statut inconnu.'; +$_MODULE['<{mollie}prestashop>mollie_3f83176ddc3f63a5a374a623840bfb09'] = 'Vous n\'avez pas d\'accès a ce page.'; +$_MODULE['<{mollie}prestashop>mollie_300225ee958b6350abc51805dab83c24'] = 'Continuer'; +$_MODULE['<{mollie}prestashop>mollie_ebdf0f490b617d7efa3025d3625cec85'] = 'Bienvenu'; +$_MODULE['<{mollie}prestashop>mollie_66dac2278292ff24611ef8a85bc94e0d'] = 'Choisir une banque'; +$_MODULE['<{mollie}prestashop>mollie_e0aa021e21dddbd6d8cecec71e9cf564'] = 'OK'; +$_MODULE['<{mollie}prestashop>mollie_82ada3ecfa7c9965b4cee97b53f5e807'] = 'Retour a la page d\'accuil'; +$_MODULE['<{mollie}prestashop>mollie_35895cff7df70dab18783453e2bd241f'] = 'Payer avec %s'; +$_MODULE['<{mollie}prestashop>mollie_cc16e103e202a48009df202d9525f75f'] = 'Rembourser cette commande'; +$_MODULE['<{mollie}prestashop>mollie_c5222afef6530f674d3acf82ba2ce9dc'] = 'Remboursement Mollie'; +$_MODULE['<{mollie}prestashop>mollie_7064b25aa8a732a3db7f230c9867be19'] = 'Rembourse la commande #%d via l\'API Mollie.'; +$_MODULE['<{mollie}prestashop>mollie_f91ab041fe9d6057740394b8b7903a0f'] = 'iDEAL'; +$_MODULE['<{mollie}prestashop>mollie_ec69c6714c5bff48849d579aa48d79fe'] = 'Carte de credit'; +$_MODULE['<{mollie}prestashop>mollie_cb3b74ced021286f61222ac247b0cbd2'] = 'Mister Cash'; +$_MODULE['<{mollie}prestashop>mollie_431647a0a8b2cd589c9fda9535f90d6d'] = 'Virement bancaire'; +$_MODULE['<{mollie}prestashop>mollie_ad69e733ebae8d264bccaa38d68830e8'] = 'PayPal'; +$_MODULE['<{mollie}prestashop>mollie_6abcd8eecb4f2abb6ccfe36ef7046ba0'] = 'paysafecard'; +$_MODULE['<{mollie}prestashop>mollie_22a98bd87df1286e65f5d242d46d99f5'] = 'MiniTix'; +$_MODULE['<{mollie}prestashop>mollie_ca1f78a35cab3b273acbcd0b5a427dd7'] = 'Micropaiements'; +$_MODULE['<{mollie}prestashop>mollie_d861877da56b8b4ceb35c8cbfdf65bb4'] = 'large'; +$_MODULE['<{mollie}prestashop>mollie_fea087517c26fadd409bd4b9dc642555'] = 'normal'; +$_MODULE['<{mollie}prestashop>mollie_a88f05b6c963e145a45b58c47cd42a41'] = 'aucune'; +$_MODULE['<{mollie}prestashop>mollie_1b73bbc1a4953a0cb5c4c1739d368b0a'] = 'toujours-visible'; +$_MODULE['<{mollie}prestashop>mollie_b7b10ab45bb159cbf707d3cf9a119b81'] = 'sur-clic'; +$_MODULE['<{mollie}prestashop>mollie_c0fb21c0519492004d1fad2f0f3f4426'] = 'propre-page'; +$_MODULE['<{mollie}prestashop>mollie_a1ec2845502d15bc956b2d3706035ffc'] = 'page-payement'; +$_MODULE['<{mollie}prestashop>mollie_f80a4ad87fee7c9fdc19b7769495fdb5'] = 'Rien'; +$_MODULE['<{mollie}prestashop>mollie_5ef0c737746fae2ca90e66c39333f8f6'] = 'Erreurs'; +$_MODULE['<{mollie}prestashop>mollie_709468af25e91284821d1bdbfdded24c'] = 'Tout'; +$_MODULE['<{mollie}prestashop>mollie_a411181d6fa3ddcb756ac02146182e3c'] = 'Configuration Mollie'; +$_MODULE['<{mollie}prestashop>mollie_824f2c1d1c2ee9aecac9977d9347a2ea'] = 'Paramètres Mollie'; +$_MODULE['<{mollie}prestashop>mollie_6311eb29dee3acc14071e0b1efb173f5'] = 'Statuts %s:'; +$_MODULE['<{mollie}prestashop>mollie_d438a1d96c6037fccad15d7594737a84'] = 'Paramètres visuels:'; +$_MODULE['<{mollie}prestashop>mollie_49259add73e416838e985a6bf4d0e571'] = 'Infos de debug:'; +$_MODULE['<{mollie}prestashop>mollie_b443dabdbefd9f9710276c8cfd0bc64f'] = 'Clé API'; +$_MODULE['<{mollie}prestashop>mollie_d0042a700e9bdf79689d63ee6846dc0e'] = 'Description:'; +$_MODULE['<{mollie}prestashop>mollie_98cc90541a6b1e54b5352b3099bb5212'] = 'Images:'; +$_MODULE['<{mollie}prestashop>mollie_d0fece2050b631394934ccef96b4279b'] = 'Liste de banques:'; +$_MODULE['<{mollie}prestashop>mollie_caa578f91ac0075a1b4efe311b25e531'] = 'Fichier css:'; +$_MODULE['<{mollie}prestashop>mollie_7635c710b1b06102235e7a91a303f652'] = 'Montrer les erreurs:'; +$_MODULE['<{mollie}prestashop>mollie_d22c39fc0b11766a6ba91c68495b4e0e'] = 'Niveau d\'accréditation:'; +$_MODULE['<{mollie}prestashop>mollie_3d20adab19137b17432d70b2b4aefef5'] = 'Sauvgarder les paramètres:'; +$_MODULE['<{mollie}prestashop>mollie_9f4757e0e5dd959e2d51adc95d841f74'] = 'Vous trouvez votre clé API dans votre %sprofil Mollie% s, il commence par test ou par live.'; +$_MODULE['<{mollie}prestashop>mollie_a97d9b80c4861a067d6bf59d8c586800'] = 'Entrez une description ici. Remarque: les méthodes de paiement peuvent avoir une limite de caractères, mieux garder la description sous les 29 caractères.'; +$_MODULE['<{mollie}prestashop>mollie_f7a97136df639501521efb243047e0cf'] = 'Montrer des grandes, normales ou aucune images a la caisse.'; +$_MODULE['<{mollie}prestashop>mollie_27db39558366d2a9001a0dec69eea4d6'] = 'Certaines méthodes de paiement (par exemple iDEAL) ont une liste de banques. Ce paramètre indique où il est représenté.'; +$_MODULE['<{mollie}prestashop>mollie_20553a05467777c665629953d49ed143'] = 'Laissez vide pour le style défaut. Sinon, incluez le chemin du fichier.'; +$_MODULE['<{mollie}prestashop>mollie_4648fe2f09e6fd16b1f9023efc6a4b32'] = 'Astuce: Vous pouvez utiliser {BASE}, {THEME}, {CSS}, {MOBILE}, {MOBILE_CSS} et {OVERRIDE} pour accès facile aux dossiers.'; +$_MODULE['<{mollie}prestashop>mollie_37f9a8b20930c1dc7488b15872b6d36b'] = 'L\'activation de cette fonction affiche des messages d\'erreur (le cas échéant) sur les pages publics. Utilisez uniquement à des fins de débogage!'; +$_MODULE['<{mollie}prestashop>mollie_7b1a43ca1db02df70068b12a4b82a7bc'] = 'Niveau recommandé: Erreurs. Choisissez Tout pour surveiller l\'activité du webhook.'; +$_MODULE['<{mollie}prestashop>mollie_c9cc8cce247e49bae79f15173ce97354'] = 'Sauvegarder'; +$_MODULE['<{mollie}prestashop>mollie_7c4e7ada50c8572336f872fced4d1852'] = 'Statut pour les paiaments %ss:'; +$_MODULE['<{mollie}prestashop>mollie_5f812d3faa27a924d02c3f4f6781ee29'] = 'Les paiements %s auront le statut \"%s\"'; +$_MODULE['<{mollie}prestashop>mollie_b2a2c5a69af7c04c5adc48261fb5dc13'] = 'Envoier un mail pour %s'; +$_MODULE['<{mollie}prestashop>mollie_0511c3431d4e32ed4266fe943014d000'] = 'Envoier un mail quand le statut devient %s'; +$_MODULE['<{mollie}prestashop>mollie_1f93fc361bfc627c89a46e1b6c28df2b'] = 'Les clés API commencent par test ou live.'; +$_MODULE['<{mollie}prestashop>mollie_143b99aaeae450b0eb09fea52a4d5200'] = 'Réglage d\'image non valide.'; +$_MODULE['<{mollie}prestashop>mollie_ee0ef1a49864837fd9a08c26db2a9449'] = 'Réglage de liste des banques non valide.'; +$_MODULE['<{mollie}prestashop>mollie_11a129cc7bad9bd365cfcbe632b2dda9'] = 'Réglage accreditage non valide.'; +$_MODULE['<{mollie}prestashop>mollie_6ab1adfed768d989b47c908755fe677f'] = 'La configuration a été sauvegardé!'; +$_MODULE['<{mollie}prestashop>mollie_048ef1905ff33382d7660a68a6199305'] = 'Avertissement: Impossible de récupérer le fichier xml de mise à jour de github.'; +$_MODULE['<{mollie}prestashop>mollie_b7f73af7318580996a3889353b282827'] = 'Vous utilisez actuellement la version %s. Nous vous recommandons fortement de mettre à niveau vers la nouvelle version %s!'; +$_MODULE['<{mollie}prestashop>mollie_711d42f319398490b32cd0e2f0b8ccb8'] = 'Avertissement: fichier de mise à jour de xml de github suit un format inattendu.'; +$_MODULE['<{mollie}prestashop>mollie_ef8cd60e5277895bcc20dbddda97fcc4'] = 'Modes de paiement Mollie sont disponibles uniquement lorsque Euros sont activés.'; diff --git a/mollie/translations/nl.php b/mollie/translations/nl.php new file mode 100644 index 000000000..6f9c32f3e --- /dev/null +++ b/mollie/translations/nl.php @@ -0,0 +1,86 @@ +mollie_09748ce33c8a71296b20ba8c3bd1d13e'] = 'Mollie Payment Module'; +$_MODULE['<{mollie}prestashop>mollie_95b3b272e06dcc3cc2aa62f6887aebc5'] = 'Mollie Betalingen'; +$_MODULE['<{mollie}prestashop>mollie_48dedcf43487615c84c1bbbf6fe76c76'] = 'Weet u zeker dat u de installatie van de Mollie Payment Module ongedaan wilt maken?'; +$_MODULE['<{mollie}prestashop>mollie_ab552f085567bbe63872c10a3596cd27'] = 'Betaalfout:'; +$_MODULE['<{mollie}prestashop>mollie_7cef8a734855777c2a9d0caf42666e69'] = 'open'; +$_MODULE['<{mollie}prestashop>mollie_76e084771e78c194efd0e2d5b8920bea'] = 'betaald'; +$_MODULE['<{mollie}prestashop>mollie_38881e0a24039dc2621e1d6f86cb71f7'] = 'geannuleerd'; +$_MODULE['<{mollie}prestashop>mollie_c4bfb2a0bab0e91bc7dcfbe3bbec246e'] = 'verlopen'; +$_MODULE['<{mollie}prestashop>mollie_ad32204fca182b862a5f97a5534c03a2'] = 'terugbetaald'; +$_MODULE['<{mollie}prestashop>mollie_e2b7dec8fa4b498156dfee6e4c84b156'] = 'Deze betaalmethode is niet beschikbaar'; +$_MODULE['<{mollie}prestashop>mollie_96d0e2862e0167af0c2fd0c99fe6bc5d'] = 'Klik hier om verder te gaan'; +$_MODULE['<{mollie}prestashop>mollie_540d9939d1ca9406e215ee3d78c76813'] = 'Deze betaalmethode is alleen beschikbaar in Euros'; +$_MODULE['<{mollie}prestashop>mollie_1b2631119333d97dbda37f87e378b1e4'] = 'Er is een fout opgetreden:'; +$_MODULE['<{mollie}prestashop>mollie_11bab828edcc0a6d5c97cbf84d61e652'] = 'De bestelling met dit id kon niet gevonden worden.'; +$_MODULE['<{mollie}prestashop>mollie_b34487c5f391f47b893ee3c61f8f9ab7'] = 'Er is nog geen definitieve betaalstatus bekend. U wordt op de hoogte gesteld zodra de bank de status doorgeeft.'; +$_MODULE['<{mollie}prestashop>mollie_d04c33bc66aeb69216e33a7eed26cfdc'] = 'Uw bestelling is geannuleerd.'; +$_MODULE['<{mollie}prestashop>mollie_3df6fa973fa0c51d0177b1a5b5091295'] = 'Onfortuinlijk genoeg is uw bestelling verlopen.'; +$_MODULE['<{mollie}prestashop>mollie_2afe257b1674f4160f5297c50bb8ab77'] = 'Dank u wel, uw bestelling is ontvangen.'; +$_MODULE['<{mollie}prestashop>mollie_7352a401b3c23b2966c68bc9ab97fa06'] = 'De transactie heeft een onverwachte status.'; +$_MODULE['<{mollie}prestashop>mollie_3f83176ddc3f63a5a374a623840bfb09'] = 'U hebt geen toegang tot deze pagina.'; +$_MODULE['<{mollie}prestashop>mollie_300225ee958b6350abc51805dab83c24'] = 'Doorgaan met winkelen'; +$_MODULE['<{mollie}prestashop>mollie_ebdf0f490b617d7efa3025d3625cec85'] = 'Welkom terug'; +$_MODULE['<{mollie}prestashop>mollie_66dac2278292ff24611ef8a85bc94e0d'] = 'Kies uw bank:'; +$_MODULE['<{mollie}prestashop>mollie_e0aa021e21dddbd6d8cecec71e9cf564'] = 'Oke'; +$_MODULE['<{mollie}prestashop>mollie_82ada3ecfa7c9965b4cee97b53f5e807'] = 'Terug naar de homepage'; +$_MODULE['<{mollie}prestashop>mollie_35895cff7df70dab18783453e2bd241f'] = 'Betalen via %s'; +$_MODULE['<{mollie}prestashop>mollie_cc16e103e202a48009df202d9525f75f'] = 'Bestelling terugbetalen'; +$_MODULE['<{mollie}prestashop>mollie_c5222afef6530f674d3acf82ba2ce9dc'] = 'Mollie Terugbetalingen'; +$_MODULE['<{mollie}prestashop>mollie_7064b25aa8a732a3db7f230c9867be19'] = 'Betaal bestelling #%d terug via de Mollie API'; +$_MODULE['<{mollie}prestashop>mollie_f91ab041fe9d6057740394b8b7903a0f'] = 'iDEAL'; +$_MODULE['<{mollie}prestashop>mollie_ec69c6714c5bff48849d579aa48d79fe'] = 'Creditcard'; +$_MODULE['<{mollie}prestashop>mollie_cb3b74ced021286f61222ac247b0cbd2'] = 'Mister Cash'; +$_MODULE['<{mollie}prestashop>mollie_431647a0a8b2cd589c9fda9535f90d6d'] = 'Overboeking'; +$_MODULE['<{mollie}prestashop>mollie_ad69e733ebae8d264bccaa38d68830e8'] = 'PayPal'; +$_MODULE['<{mollie}prestashop>mollie_6abcd8eecb4f2abb6ccfe36ef7046ba0'] = 'paysafecard'; +$_MODULE['<{mollie}prestashop>mollie_22a98bd87df1286e65f5d242d46d99f5'] = 'MiniTix'; +$_MODULE['<{mollie}prestashop>mollie_ca1f78a35cab3b273acbcd0b5a427dd7'] = 'Micropayments'; +$_MODULE['<{mollie}prestashop>mollie_d861877da56b8b4ceb35c8cbfdf65bb4'] = 'groot'; +$_MODULE['<{mollie}prestashop>mollie_fea087517c26fadd409bd4b9dc642555'] = 'normaal'; +$_MODULE['<{mollie}prestashop>mollie_a88f05b6c963e145a45b58c47cd42a41'] = 'geen'; +$_MODULE['<{mollie}prestashop>mollie_1b73bbc1a4953a0cb5c4c1739d368b0a'] = 'altijd-zichtbaar'; +$_MODULE['<{mollie}prestashop>mollie_b7b10ab45bb159cbf707d3cf9a119b81'] = 'na-kik'; +$_MODULE['<{mollie}prestashop>mollie_c0fb21c0519492004d1fad2f0f3f4426'] = 'eigen-pagina'; +$_MODULE['<{mollie}prestashop>mollie_a1ec2845502d15bc956b2d3706035ffc'] = 'betaal-pagina'; +$_MODULE['<{mollie}prestashop>mollie_f80a4ad87fee7c9fdc19b7769495fdb5'] = 'Geen'; +$_MODULE['<{mollie}prestashop>mollie_5ef0c737746fae2ca90e66c39333f8f6'] = 'Fouten'; +$_MODULE['<{mollie}prestashop>mollie_709468af25e91284821d1bdbfdded24c'] = 'Alles'; +$_MODULE['<{mollie}prestashop>mollie_a411181d6fa3ddcb756ac02146182e3c'] = 'Mollie Configuratie'; +$_MODULE['<{mollie}prestashop>mollie_824f2c1d1c2ee9aecac9977d9347a2ea'] = 'Mollie instellingen'; +$_MODULE['<{mollie}prestashop>mollie_6311eb29dee3acc14071e0b1efb173f5'] = 'Status \"%s\":'; +$_MODULE['<{mollie}prestashop>mollie_d438a1d96c6037fccad15d7594737a84'] = 'Visuele instellingen:'; +$_MODULE['<{mollie}prestashop>mollie_49259add73e416838e985a6bf4d0e571'] = 'Debug informatie:'; +$_MODULE['<{mollie}prestashop>mollie_b443dabdbefd9f9710276c8cfd0bc64f'] = 'API Sleutel:'; +$_MODULE['<{mollie}prestashop>mollie_d0042a700e9bdf79689d63ee6846dc0e'] = 'Omschrijving:'; +$_MODULE['<{mollie}prestashop>mollie_98cc90541a6b1e54b5352b3099bb5212'] = 'Afbeeldingen:'; +$_MODULE['<{mollie}prestashop>mollie_d0fece2050b631394934ccef96b4279b'] = 'Bankenlijst:'; +$_MODULE['<{mollie}prestashop>mollie_caa578f91ac0075a1b4efe311b25e531'] = 'Css bestand:'; +$_MODULE['<{mollie}prestashop>mollie_7635c710b1b06102235e7a91a303f652'] = 'Foutmeldingen weergeven:'; +$_MODULE['<{mollie}prestashop>mollie_d22c39fc0b11766a6ba91c68495b4e0e'] = 'Log niveau:'; +$_MODULE['<{mollie}prestashop>mollie_3d20adab19137b17432d70b2b4aefef5'] = 'Instellingen opslaan:'; +$_MODULE['<{mollie}prestashop>mollie_9f4757e0e5dd959e2d51adc95d841f74'] = 'U vindt uw API Sleutel in uw %sMollie Profiel%s; de sleutel begint met _test of _live.'; +$_MODULE['<{mollie}prestashop>mollie_a97d9b80c4861a067d6bf59d8c586800'] = 'Vul hier een omschrijving in. Sommige betaalmethoden kunnen een karakterlimiet hebben; het is verstandig om 29 tekens of minder te gebruiken.'; +$_MODULE['<{mollie}prestashop>mollie_f7a97136df639501521efb243047e0cf'] = 'Geef grote, normale of geen afbeeldingen weer bij het afrekenen.'; +$_MODULE['<{mollie}prestashop>mollie_27db39558366d2a9001a0dec69eea4d6'] = 'Sommige betaalmethoden (zoals iDEAL) hebben een bankenlijst. Deze instelling bepaalt waar die lijst zichtbaar is.'; +$_MODULE['<{mollie}prestashop>mollie_20553a05467777c665629953d49ed143'] = 'Laat leeg voor standaard vormgeving.'; +$_MODULE['<{mollie}prestashop>mollie_4648fe2f09e6fd16b1f9023efc6a4b32'] = 'Hint: Gebruik {BASE}, {THEME}, {CSS}, {MOBILE}, {MOBILE_CSS} of {OVERRIDE} voor de standaard bestandsmappen.'; +$_MODULE['<{mollie}prestashop>mollie_37f9a8b20930c1dc7488b15872b6d36b'] = 'Door deze optie aan te zetten worden foutmeldingen op de voorpagina weergegeven. Alleen voor debug!'; +$_MODULE['<{mollie}prestashop>mollie_7b1a43ca1db02df70068b12a4b82a7bc'] = 'Aangeraden niveau: Errors. Zet op alles om de webhook requests te monitoren. %sBekijk logs%s'; +$_MODULE['<{mollie}prestashop>mollie_c9cc8cce247e49bae79f15173ce97354'] = 'Opslaan'; +$_MODULE['<{mollie}prestashop>mollie_7c4e7ada50c8572336f872fced4d1852'] = 'Status voor betaling %s'; +$_MODULE['<{mollie}prestashop>mollie_5f812d3faa27a924d02c3f4f6781ee29'] = 'Betalingen die %s zijn, krijgen de status: \"%s\"'; +$_MODULE['<{mollie}prestashop>mollie_b2a2c5a69af7c04c5adc48261fb5dc13'] = 'Verzend mail bij %s'; +$_MODULE['<{mollie}prestashop>mollie_0511c3431d4e32ed4266fe943014d000'] = 'Verstuur een email als de status in %s verandert?'; +$_MODULE['<{mollie}prestashop>mollie_1f93fc361bfc627c89a46e1b6c28df2b'] = 'De API Sleutel dient met _test of _live te beginnen.'; +$_MODULE['<{mollie}prestashop>mollie_143b99aaeae450b0eb09fea52a4d5200'] = 'Ongeldige afbeeldingsinstelling.'; +$_MODULE['<{mollie}prestashop>mollie_ee0ef1a49864837fd9a08c26db2a9449'] = 'Ongeldige bankenlijst instelling.'; +$_MODULE['<{mollie}prestashop>mollie_11a129cc7bad9bd365cfcbe632b2dda9'] = 'Ongeldige debug log instelling.'; +$_MODULE['<{mollie}prestashop>mollie_6ab1adfed768d989b47c908755fe677f'] = 'De configuratie is opgeslagen!'; +$_MODULE['<{mollie}prestashop>mollie_048ef1905ff33382d7660a68a6199305'] = 'Waarschuwing: Kon de update XML van github niet ophalen.'; +$_MODULE['<{mollie}prestashop>mollie_b7f73af7318580996a3889353b282827'] = 'U gebruikt momenteel versie %s. Wij raden u ten zeerste aan te upgraden naar de nieuwe versie, %s!'; +$_MODULE['<{mollie}prestashop>mollie_711d42f319398490b32cd0e2f0b8ccb8'] = 'Waarschuwing: Het update xml bestand van github volgt een onverwacht formaat.'; +$_MODULE['<{mollie}prestashop>mollie_ef8cd60e5277895bcc20dbddda97fcc4'] = 'Mollie betaalmethoden zijn alleen beschikbaar wanneer Euros zijn ingeschakeld.'; diff --git a/mollie/views/templates/front/mollie_issuers.tpl b/mollie/views/templates/front/mollie_issuers.tpl new file mode 100644 index 000000000..d0faac8a7 --- /dev/null +++ b/mollie/views/templates/front/mollie_issuers.tpl @@ -0,0 +1,19 @@ + +
+ {if count($issuers)} + + + {/if} +

+ {$msg_return} +
\ No newline at end of file diff --git a/mollie/views/templates/front/mollie_return.tpl b/mollie/views/templates/front/mollie_return.tpl new file mode 100644 index 000000000..821fb976d --- /dev/null +++ b/mollie/views/templates/front/mollie_return.tpl @@ -0,0 +1,3 @@ +

{$msg_welcome}

+

{$msg_details}

+

{$msg_continue}

\ No newline at end of file diff --git a/mollie/views/templates/hook/mollie_config.tpl b/mollie/views/templates/hook/mollie_config.tpl new file mode 100644 index 000000000..db08dbc7e --- /dev/null +++ b/mollie/views/templates/hook/mollie_config.tpl @@ -0,0 +1,219 @@ + + +
+

{$config_title|escape}

+
+ {$config_legend|escape} + + {if !empty($update_message)} + + + + {/if} + {if !empty($msg_result)} + + + + {/if} + + + + + + + + + + + + + + + + + + + + + + + + {foreach $statuses as $i => $name} + + + + + + + + + + + + {/foreach} + + + + + + + + + + + + + + + +
+ {$update_message} +
+ {$msg_result} +
+ + +
+ +
+ + +
+ +
{$title_visual}
+ + +
+ +
+ + +
+ +
+ + +
+ +
{$title_status|ucfirst|sprintf:$lang[$name]}
+ + +
+ +
+ + +
+ +
{$title_debug}
+ + + + +
+ + +
+ +
+ {$msg_save} + + +
+
+
\ No newline at end of file diff --git a/mollie/views/templates/hook/mollie_methods.tpl b/mollie/views/templates/hook/mollie_methods.tpl new file mode 100644 index 000000000..7cebf4400 --- /dev/null +++ b/mollie/views/templates/hook/mollie_methods.tpl @@ -0,0 +1,74 @@ + + + +{if $warning != ''} +

{$warning}

+{/if} + +
+{foreach $methods as $method} +

+ + {if isset($method->image) && $images !== 'hide'} + {if $images === 'big'} + + {else} + + {/if} + {else} +   + {/if} + {$module->lang($method->description)|escape} + +
+ {if isset($issuers[$method->id]) && count($issuers[$method->id])} + + + {*if $issuer_setting === 'on-click'*} + + {*/if*} + + {/if} +

+{/foreach} +
\ No newline at end of file diff --git a/mollie/views/templates/hook/mollie_refund.tpl b/mollie/views/templates/hook/mollie_refund.tpl new file mode 100644 index 000000000..d5c7b332d --- /dev/null +++ b/mollie/views/templates/hook/mollie_refund.tpl @@ -0,0 +1,21 @@ +
+
+
+ {$msg_title} +
+
+ {if $status === 'form'} +
+
{$msg_description}
+ +
+ {elseif $status === 'fail'} +
{$msg_fail}
+
{$msg_details}
+ {elseif $status === 'success'} +
{$msg_success}

+
{$msg_details}
+ {/if} +
+
+
\ No newline at end of file diff --git a/release.sh b/release.sh new file mode 100755 index 000000000..0b56fcd66 --- /dev/null +++ b/release.sh @@ -0,0 +1,2 @@ +#!/bin/sh +zip -9 -r release.zip mollie -x mollie/*.git* mollie/*.DS_Store \ No newline at end of file diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 000000000..f8bc58767 --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,166 @@ + 'mollie')); } +} + +class PaymentModule +{ + function __construct() {} + function install() { return TRUE; } + function uninstall() { return TRUE; } + function l($txt, $mod = '') { return $txt; } +} + +class Configuration +{ + static function get() { return FALSE; } + static function updateValue() { return TRUE; } + static function deleteByName() { return TRUE; } +} + +class Validate +{ + static function isLoadedObject() { return TRUE; } +} + +class Logger +{ + static function addLog() {} +} + +class Currency +{ + static function exists() { return TRUE; } + static function getIdByIsoCode() { return 1; } + static function getDefaultCurrency() { return 1; } +} + +class Tools +{ + static function isSubmit($field) { return isset($_POST[$field]); } + static function htmlentitiesUTF8() { return ''; } + static function redirect() { } + static function convertPrice() { return 0; } + static function getValue($key, $default = FALSE) + { + if (isset($_POST[$key])) + { + return $_POST[$key]; + } + elseif (isset($_GET[$key])) + { + return $_GET[$key]; + } + else + { + return $default; + } + } +} + +class Link +{ + public function getAdminLink() { return ''; } +} + +class Db +{ + static function getInstance() { return new Db(); } + function getValue() { return FALSE; } + function getRow() { return array('bank_status' => 'open'); } + function execute() { return TRUE; } + function insert() { return TRUE; } + function update() { return TRUE; } + function getMsgError() { return ''; } +} + +class Smarty +{ + public function assign() { } +} + +class Order +{ + static function getUniqReferenceOf() { return 'UNIQREF'; } +} + +class OrderState +{ + static function getOrderStates() { return array(); } +} + +class OrderHistory +{ + function changeIdOrderState() {} + function addWithemail() {} + function add() {} +} + +class Cart +{ + const BOTH = 'BOTH'; + public $id = null; + public $id_customer = 666; + public $id_address_delivery = 1; + public $id_address_invoice = 1; + function __construct() + { + $this->id_address_delivery = new Address(); + $this->id_address_invoice = new Address(); + } + function getOrderTotal() { return 13.37; } +} + +class Customer +{ + public $secure_key = ''; +} + +class Address +{ + public $city = ''; + public $id_state = ''; + public $id_country = ''; + public $postcode = ''; +} + +class State +{ + static function getNameById() { return ''; } +} + +class Country +{ + static function getIsoById() { return ''; } +} diff --git a/tests/impostor.php b/tests/impostor.php new file mode 100644 index 000000000..30253b813 --- /dev/null +++ b/tests/impostor.php @@ -0,0 +1,203 @@ + Aug 7, 2012 + * @copyright (C), Mollie B.V. + */ +class Mollie_Testing_Impostor +{ + /** + * @var mixed Base class instance + */ + protected $_base_class; + + /** + * Constructor + * + * @param string|object $base_class Class name of the base class, or an instance + * @param array $constructor_args (Optional) Arguments to pass to the constructor of the base class + * @param array $constants (Optional) Constants to override + */ + public function __construct ($base_class, array $constructor_args = array(), array $constants = array()) + { + // @codeCoverageIgnoreStart + if (PHP_VERSION_ID < 50300) + { + trigger_error(get_class().': This class requires PHP version 5.3 or higher.', E_USER_ERROR); + } + // @codeCoverageIgnoreEnd + + if (is_object($base_class) && count($constructor_args)) + { + throw new Mollie_Testing_Exception('Unused constructor arguments for passed instance of "'.get_class($base_class).'".'); + } + + // If it's an instance, just accept it + if (is_object($base_class)) + { + $this->_base_class = $base_class; + } + // If it's a classname, use ReflectionClass to create an instance, even if it's abstract + elseif (!class_exists($base_class)) + { + throw new Mollie_Testing_Exception("Base class '$base_class' does not exist."); + } + else + { + $ref = new ReflectionClass($base_class); + + if ($ref->isAbstract()) { + $ref = new ReflectionClass($this->createDerivedClass($base_class)); + } + + if ($ref->getConstructor() && count($constructor_args) < $ref->getConstructor()->getNumberOfRequiredParameters()) + { + throw new Mollie_Testing_Exception($ref->getConstructor()->getNumberOfRequiredParameters() . " constructor arguments required for '$base_class::__construct(...)'."); + } + + $this->_base_class = sizeof($constructor_args) ? $ref->newInstanceArgs($constructor_args) : $ref->newInstance(); + } + } + + /** + * Note: it can auto-extend abstract classes but not implement abstract methods. + * + * @param string $abstract_class Must be an existing classname + * @return string Returns name of a new instantiable class + * @param array $constants (Optional) Constants to override + * @throws Mollie_Testing_Exception + */ + public function createDerivedClass ($base_class, array $constants = array()) + { + $derived = "Derived_$base_class"; + + if (!class_exists($derived, FALSE) && class_exists($base_class)) + { + $class_definition = "final class $derived extends $base_class { "; + + foreach ($constants as $constant => $value) + { + $value = is_numeric($value) ? $value : "'$value'"; + $class_definition .= "const $constant = $value; "; + } + + $reflection = new ReflectionClass($base_class); + + foreach ($reflection->getMethods() as $method) + { + if ($method->isAbstract()) + { + $params = join(',', array_map(function (ReflectionParameter $p) { return '$'.$p->getName(); }, $method->getParameters())); + $class_definition .= "public function {$method->getName()} ($params) {} "; + } + } + + $class_definition .= '}'; + eval($class_definition); + } + + if (!class_exists($derived, FALSE)) + { + throw new Mollie_Testing_Exception("Failed to create instance of auto-extended abstract class '$base_class'."); + } + + return $derived; + } + + /** + * Get the original object back, convenient when some typehinting needs to be satisfied. + * + * @return object + */ + public function getInstance () + { + return $this->_base_class; + } + + /** + * Use the magic method __call() to invoke protected methods + * + * @param string $method Name of the method + * @param array $args Arguments to provide to the method + * @return mixed Return value of the method + * @throws Mollie_Testing_Exception + */ + public function __call ($method, $args) + { + if (method_exists($this->_base_class, $method)) + { + $ref = new ReflectionMethod($this->_base_class, $method); + + if (count($args) < $ref->getNumberOfRequiredParameters()) { + throw new Mollie_Testing_Exception("More arguments required for '".get_class($this->_base_class)."::$method(...)'."); + } + + $ref->setAccessible(TRUE); + return $ref->invokeArgs($this->_base_class, $args); + } + + if (method_exists($this->_base_class, '__call')) + { + // __call() is always public, no need for ReflectionMethod + return call_user_func_array(array($this->_base_class, $method), $args); + } + + throw new Mollie_Testing_Exception("Method '".get_class($this->_base_class)."::$method()' does not exist."); + } + + /** + * Use the magic method __get() to get protected properties + * + * @param string $property Name of the property + * @return mixed Value of the property + * @throws Mollie_Testing_Exception + */ + public function __get ($property) + { + if (property_exists($this->_base_class, $property)) + { + $ref = new ReflectionProperty($this->_base_class, $property); + $ref->setAccessible(TRUE); + return $ref->getValue($this->_base_class); + } + + if (method_exists($this->_base_class, '__get')) + { + // __get() is always public, no need for ReflectionProperty + return $this->_base_class->$property; + } + + throw new Mollie_Testing_Exception("Property '".get_class($this->_base_class)."::$property' does not exist."); + } + + /** + * Use the magic method __set() to set protected properties + * + * @param string $property Name of the property + * @param mixed $value Value to set the property to + * @return mixed New value of the property + * @throws Mollie_Testing_Exception + */ + public function __set ($property, $value) + { + if (property_exists($this->_base_class, $property)) + { + $ref = new ReflectionProperty($this->_base_class, $property); + $ref->setAccessible(TRUE); + $ref->setValue($this->_base_class, $value); + return $ref->getValue($this->_base_class); + } + + if (method_exists($this->_base_class, '__set')) + { + // __set() is always public, no need for ReflectionProperty + return $this->_base_class->$property = $value; + } + + throw new Mollie_Testing_Exception("Property '".get_class($this->_base_class)."::$property' does not exist."); + } +} \ No newline at end of file diff --git a/tests/phpunit.xml b/tests/phpunit.xml new file mode 100644 index 000000000..17d582cca --- /dev/null +++ b/tests/phpunit.xml @@ -0,0 +1,23 @@ + + + + + . + + + + + + + + + + /usr/share/php + + + ../lib + + + diff --git a/tests/unittests/controllers/paymentTest.php b/tests/unittests/controllers/paymentTest.php new file mode 100644 index 000000000..5eae664d4 --- /dev/null +++ b/tests/unittests/controllers/paymentTest.php @@ -0,0 +1,122 @@ +mollie = $this->getMock('Mollie', array( + 'getConfigValue', + 'validateOrder', + )); + $this->controller = $this->getMock('MolliePaymentModuleFrontController', array( + '_getIssuerList', + 'setTemplate', + '_convertCurrencyToEuro', + '_getPaymentData', + '_createPayment', + )); + $this->mollie_payment = $this->getMock('Mollie_API_Object_Payment', array( + 'getPaymentUrl' + )); + $this->controller->module = $this->mollie; + $this->controller->module->currentOrder = 666; + $this->controller->module->active = TRUE; + $this->controller->context = new stdClass(); + $this->controller->context->link = new Link(); + $this->controller->context->smarty = new Smarty(); + $this->controller->context->cart = new Cart(); + $this->controller->context->cart->id_customer = new Customer(); + } + + public function testShowModuleList() + { + // test if the module list is shown when applicable (config.MOLLIE_ISSUERS == own-page) + + // make module list apply + $this->mollie->expects($this->atLeastOnce()) + ->method('getConfigValue') + ->will($this->returnValue('own-page')); + + // needs a method + $_GET['method'] = 'ideal'; + + // needs more than one issuer + $this->controller->expects($this->once()) + ->method('_getIssuerList') + ->will($this->returnValue(array('my_bank', 'your_bank'))); + + // consider successful if it sets the template + $this->controller->expects($this->once()) + ->method('setTemplate') + ->with('mollie_issuers.tpl'); + + // execute + $this->controller->initContent(); + } + + public function testSuccessRedirect() + { + // test if the user is redirected if module list doesn't apply + + // make module list not apply + $this->mollie->expects($this->atLeastOnce()) + ->method('getConfigValue') + ->will($this->returnValue('payment-page')); + + // needs a method + $_GET['method'] = 'ideal'; + + // use mocked conversion (1:1 rate) + $this->controller->expects($this->once()) + ->method('_convertCurrencyToEuro') + ->will($this->returnValue(13.37)); + + // somehow pass the validation + $this->mollie->expects($this->once()) + ->method('validateOrder'); + + // set payment data + $this->controller->expects($this->once()) + ->method('_getPaymentData') + ->will($this->returnValue(array())); + + // create payment + $this->controller->expects($this->once()) + ->method('_createPayment') + ->will($this->returnValue($this->mollie_payment)); + + // consider successful if getPaymentUrl gets called + $this->mollie_payment->expects($this->once()) + ->method('getPaymentUrl'); + + // execute + $this->controller->initContent(); + } + + public function testValidOrder() + { + // test if a valid order passes the validation + $cart = new Cart(); + $customer = new Customer(); + $payments = new Mollie_Testing_Impostor($this->controller); + $this->assertTrue($payments->_validate($cart, $customer)); + } + + public function testInvalidOrder() + { + // test if an invalid order gets denied by the validation + $cart = new Cart(); + $cart->id_customer = null; + $cart->id_address_delivery = null; + $cart->id_address_invoice = null; + $customer = new Customer(); + $payments = new Mollie_Testing_Impostor($this->controller); + $this->assertFalse($payments->_validate($cart, $customer)); + } + + +} \ No newline at end of file diff --git a/tests/unittests/controllers/returnTest.php b/tests/unittests/controllers/returnTest.php new file mode 100644 index 000000000..cd234cf5d --- /dev/null +++ b/tests/unittests/controllers/returnTest.php @@ -0,0 +1,71 @@ +mollie = $this->getMock('Mollie', array( + 'lang', + 'getConfigValue' + )); + $this->mollie->version = '1.0.0'; + $this->controller = $this->getMock('MollieReturnModuleFrontController', array( + 'setTemplate', + )); + $this->controller->module = $this->mollie; + $this->controller->context = new stdClass(); + $this->controller->context->smarty = $this->getMock('Smarty', array( + 'assign', + )); + + $this->mollie->expects($this->any()) + ->method('lang') + ->will($this->returnArgument(0)); + $this->mollie->expects($this->any()) + ->method('lang') + ->will($this->returnValue('0.0.0')); + + $_GET['id'] = 1; + } + + public function testAuthorized() + { + // test if the page is visible if we have a correct access token + $_GET['ref'] = 'UNIQREF'; + + $this->controller->context->smarty->expects($this->once()) + ->method('assign') + ->with(array( + 'auth' => TRUE, + 'mollie_info' => array('bank_status' => 'open'), + 'msg_continue' => 'Continue shopping', + 'msg_details' => 'We have not received a definite payment status. You will be notified as soon as we receive a confirmation of the bank/merchant.', + 'msg_welcome' => 'Welcome back', + )); + + // execute + $this->controller->initContent(); + } + + public function testNotAuthorized() + { + // test if the page is denied if we have an incorrect access token + $_GET['ref'] = 'WRONGREF'; + + $this->controller->context->smarty->expects($this->once()) + ->method('assign') + ->with(array( + 'auth' => FALSE, + 'mollie_info' => array(), + 'msg_continue' => 'Continue shopping', + 'msg_details' => 'You are not authorised to see this page.', + 'msg_welcome' => 'Welcome back', + )); + + // execute + $this->controller->initContent(); + } +} \ No newline at end of file diff --git a/tests/unittests/controllers/webhookTest.php b/tests/unittests/controllers/webhookTest.php new file mode 100644 index 000000000..82715f375 --- /dev/null +++ b/tests/unittests/controllers/webhookTest.php @@ -0,0 +1,70 @@ +mollie = $this->getMock('Mollie', array( + 'getConfigValue', + 'setOrderStatus', + )); + $this->controller = new Mollie_Testing_Impostor($this->getMock('MollieWebhookModuleFrontController', array( + '_saveOrderStatus', + ))); + $this->controller->module = $this->mollie; + $this->payment = $this->getMock('Mollie_API_Object_Payment'); + $this->payment->metadata = new stdClass(); + $this->payment->metadata->order_id = 666; + $this->mollie->api = $this->getMock('Mollie_API_Client'); + $this->mollie->api->payments = $this->getMock('Mollie_API_Resource_Payments', array( + 'get', + ), array( + $this->mollie->api, + )); + + + $this->mollie->api->payments->expects($this->any()) + ->method('get') + ->will($this->returnValue($this->payment)); + + $this->mollie->expects($this->any()) + ->method('getConfigValue') + ->will($this->returnValue(FALSE)); + } + + public function testTellMollieOK() + { + // test if a request with testByMollie parameter results in OK + $_GET['testByMollie'] = TRUE; + $this->assertEquals('OK', $this->controller->_executeWebhook()); + } + + public function testNeedID() + { + // test if a request without id is denied + unset($_GET['testByMollie']); + $_GET['id'] = null; + $this->assertEquals('NO ID', $this->controller->_executeWebhook()); + } + + public function testEverythingGoesGreat() + { + // test if _saveOrderStatus is called correctly + $_GET['id'] = 'tr_q2cLW9pxMT'; + $this->payment->status = 'paid'; + + $this->controller->expects($this->once()) + ->method('_saveOrderStatus') + ->with(666, 'paid'); + + $this->mollie->expects($this->once()) + ->method('setOrderStatus') + ->with(666, 'paid'); + + $this->assertEquals('OK', $this->controller->_executeWebhook()); + } +} \ No newline at end of file diff --git a/tests/unittests/mollieTest.php b/tests/unittests/mollieTest.php new file mode 100644 index 000000000..2c7124a4e --- /dev/null +++ b/tests/unittests/mollieTest.php @@ -0,0 +1,124 @@ +mollie = $this->getMock('Mollie', array( + 'registerHook', + 'unregisterHook', + 'initConfigValue', + 'deleteConfigValue', + 'updateConfigValue', + 'display', + '_getUpdateXML', + )); + + $this->mollie->version = '1.0.0'; + $this->mollie->context = new stdClass(); + $this->mollie->context->link = new Link(); + $this->mollie->context->smarty = new Smarty(); + + $_SERVER['REQUEST_URI'] = 'something.dev'; + } + + public function testInstall() + { + // test if registerHook is called + $this->mollie->expects($this->atLeastOnce()) + ->method('registerHook') + ->will($this->returnValue(TRUE)); + + // test if initConfigValue is called + $this->mollie->expects($this->atLeastOnce()) + ->method('initConfigValue') + ->will($this->returnValue(TRUE)); + + // execute + $this->mollie->install(); + } + + public function testUninstall() + { + // test if unregisterHook is called + $this->mollie->expects($this->atLeastOnce()) + ->method('unregisterHook') + ->will($this->returnValue(TRUE)); + + // test if deleteConfigValue is called + $this->mollie->expects($this->atLeastOnce()) + ->method('deleteConfigValue') + ->will($this->returnValue(TRUE)); + + // execute + $this->mollie->uninstall(); + } + + public function testSaveConfig() + { + $this->setUpdateXML('0.0.0'); + + // create post array + $_POST = array( + 'Mollie_Config_Save' => TRUE, + 'Mollie_Api_Key' => 'test_something', + 'Mollie_Description' => 'Order %', + 'Mollie_Images' => 'normal', + 'Mollie_Issuers' => 'on-click', + 'Mollie_Logger' => 1, + 'Mollie_Errors' => FALSE, + 'Mollie_Status_open' => 3, + 'Mollie_Status_paid' => 2, + 'Mollie_Status_cancelled' => 6, + 'Mollie_Status_expired' => 8, + 'Mollie_Status_refunded' => 7, + ); + + // create valueMap to check if post values are passed to updateConfigValue + $valueMap = array(); + foreach ($_POST as $name => $val) + { + $valueMap[] = array($name, $val); + } + + // test if updateConfigValue is called right + $this->mollie->expects($this->atLeastOnce()) + ->method('updateConfigValue') + ->will($this->returnValueMap($valueMap)); + + // execute + $this->mollie->getContent(); + } + + public function testUpdateMessage() + { + // give _getUpdateMessage some githubish xml + $this->setUpdateXML('999.0.0'); + + // make mollie impostor to test protected _getUpdateMessage + $mollie = new Mollie_Testing_Impostor($this->mollie); + + // execute + $this->assertEquals( + 'You are currently using version 1.0.0. We strongly recommend you to upgrade to the new version 999.0.0!', + $mollie->_getUpdateMessage('https://github.com/mollie/Prestashop') + ); + } + + + private function setUpdateXML($version = '0.0.0') + { + $this->mollie->expects($this->any()) + ->method('_getUpdateXML') + ->with('https://github.com/mollie/Prestashop') + ->will($this->returnValue(' + + + tag:github.com,1970:Repository/123456789/' . $version . ' + + + ')); + } +} \ No newline at end of file