From f068195d466ed0b1e964e82a7fade2604433866b Mon Sep 17 00:00:00 2001 From: Michiel Gerritsen Date: Mon, 22 Jun 2020 14:41:10 +0200 Subject: [PATCH] Feature: Implemented Mollie Components --- .../Payment/Form/CreditcardComponents.php | 11 +++ .../Mollie/Mpm/Model/Client/Orders.php | 4 + .../Mollie/Mpm/Model/Client/Payments.php | 4 + .../Mollie/Mpm/Model/Method/Abstract.php | 1 + .../Mollie/Mpm/Model/Method/Creditcard.php | 22 ++++++ .../community/Mollie/Mpm/Model/Observer.php | 24 ++++++ .../Mollie/Mpm/controllers/ApiController.php | 20 ++++- app/code/community/Mollie/Mpm/etc/config.xml | 9 +++ app/code/community/Mollie/Mpm/etc/system.xml | 59 ++++++++++----- .../base/default/layout/mollie_mpm.xml | 16 ++++ .../mollie/mpm/payment/after_body_start.phtml | 13 ++++ .../payment/form/creditcard-components.phtml | 32 ++++++++ modman | 1 + .../js/mollie/mpm/creditcard-components.js | 73 +++++++++++++++++++ .../base/default/mollie/mpm/style.css | 34 +++++++++ 15 files changed, 303 insertions(+), 20 deletions(-) create mode 100644 app/code/community/Mollie/Mpm/Block/Payment/Form/CreditcardComponents.php create mode 100644 app/design/frontend/base/default/template/mollie/mpm/payment/after_body_start.phtml create mode 100644 app/design/frontend/base/default/template/mollie/mpm/payment/form/creditcard-components.phtml create mode 100644 skin/frontend/base/default/js/mollie/mpm/creditcard-components.js diff --git a/app/code/community/Mollie/Mpm/Block/Payment/Form/CreditcardComponents.php b/app/code/community/Mollie/Mpm/Block/Payment/Form/CreditcardComponents.php new file mode 100644 index 00000000..82d5cdd1 --- /dev/null +++ b/app/code/community/Mollie/Mpm/Block/Payment/Form/CreditcardComponents.php @@ -0,0 +1,11 @@ +setTemplate('mollie/mpm/payment/form/creditcard-components.phtml'); + } +} \ No newline at end of file diff --git a/app/code/community/Mollie/Mpm/Model/Client/Orders.php b/app/code/community/Mollie/Mpm/Model/Client/Orders.php index 82dbf4b8..e28e82f8 100644 --- a/app/code/community/Mollie/Mpm/Model/Client/Orders.php +++ b/app/code/community/Mollie/Mpm/Model/Client/Orders.php @@ -110,6 +110,10 @@ public function startTransaction(Mage_Sales_Model_Order $order) $orderData['payment']['dueDate'] = $this->mollieHelper->getBanktransferDueDate($storeId); } + if ($method == 'creditcard' && isset($additionalData['card_token'])) { + $orderData['payment']['cardToken'] = $additionalData['card_token']; + } + if (isset($additionalData['limited_methods'])) { $orderData['method'] = $additionalData['limited_methods']; } diff --git a/app/code/community/Mollie/Mpm/Model/Client/Payments.php b/app/code/community/Mollie/Mpm/Model/Client/Payments.php index 52eb8a37..cd2a2efa 100644 --- a/app/code/community/Mollie/Mpm/Model/Client/Payments.php +++ b/app/code/community/Mollie/Mpm/Model/Client/Payments.php @@ -98,6 +98,10 @@ public function startTransaction(Mage_Sales_Model_Order $order) $paymentData['billingEmail'] = $order->getCustomerEmail(); } + if ($method == 'creditcard' && isset($additionalData['card_token'])) { + $paymentData['cardToken'] = $additionalData['card_token']; + } + if (!$order->getIsVirtual() && $order->hasData('shipping_address_id')) { $paymentData['shippingAddress'] = $this->getAddressLine($order->getShippingAddress()); } diff --git a/app/code/community/Mollie/Mpm/Model/Method/Abstract.php b/app/code/community/Mollie/Mpm/Model/Method/Abstract.php index 1fe95548..30b747fe 100644 --- a/app/code/community/Mollie/Mpm/Model/Method/Abstract.php +++ b/app/code/community/Mollie/Mpm/Model/Method/Abstract.php @@ -70,6 +70,7 @@ public function assignData($data) { parent::assignData($data); $this->getInfoInstance()->setAdditionalInformation('selected_issuer', null); + $this->getInfoInstance()->setAdditionalInformation('card_token', null); return $this; } } \ No newline at end of file diff --git a/app/code/community/Mollie/Mpm/Model/Method/Creditcard.php b/app/code/community/Mollie/Mpm/Model/Method/Creditcard.php index 3d01c673..2005db8a 100644 --- a/app/code/community/Mollie/Mpm/Model/Method/Creditcard.php +++ b/app/code/community/Mollie/Mpm/Model/Method/Creditcard.php @@ -49,4 +49,26 @@ class Mollie_Mpm_Model_Method_Creditcard extends Mollie_Mpm_Model_Method_Abstrac */ protected $_paymentMethod = self::PAYMENT_METHOD; + /** + * Type of block that generates method form + * + * @var string + */ + protected $_formBlockType = 'mpm/payment_form_creditcardComponents'; + + /** + * @param mixed $data + * + * @return $this|Mage_Payment_Model_Info + * @throws Mage_Core_Exception + */ + public function assignData($data) + { + parent::assignData($data); + + $cardToken = Mage::app()->getRequest()->getParam('cardToken'); + $this->getInfoInstance()->setAdditionalInformation('card_token', $cardToken); + + return $this; + } } diff --git a/app/code/community/Mollie/Mpm/Model/Observer.php b/app/code/community/Mollie/Mpm/Model/Observer.php index 13b31920..7e37d8d9 100644 --- a/app/code/community/Mollie/Mpm/Model/Observer.php +++ b/app/code/community/Mollie/Mpm/Model/Observer.php @@ -159,4 +159,28 @@ public function restoreQuoteWhenReturningFromMollie(Varien_Event_Observer $obser Mage::logException($e); } } + + /** + * The Mollie javascript library conflicts with he ancient prototype.js library, that's why we load the library + * as soon as possible. When adding the script using xml it is always added to late. That's why we do it by + * manipulating the html. + * + * @param Varien_Event_Observer $observer + */ + public function injectMollieComponentsJs(Varien_Event_Observer $observer) + { + /** @var Mage_Core_Block_Template $block */ + $block = $observer->getBlock(); + + if (!$block instanceof Mage_Page_Block_Html_Head) { + return; + } + + /** @var \Varient_Object $transport */ + $transport = $observer->getData('transport'); + $html = $transport->getHtml(); + $html = preg_replace('##', '' . PHP_EOL . '', $html, 1); + + $transport->setHtml($html); + } } diff --git a/app/code/community/Mollie/Mpm/controllers/ApiController.php b/app/code/community/Mollie/Mpm/controllers/ApiController.php index b1b80ca9..52461878 100644 --- a/app/code/community/Mollie/Mpm/controllers/ApiController.php +++ b/app/code/community/Mollie/Mpm/controllers/ApiController.php @@ -92,8 +92,8 @@ public function paymentAction() } $methodInstance = $order->getPayment()->getMethodInstance(); - $redirectUrl = $methodInstance->startTransaction($order); - if (!empty($redirectUrl)) { + $redirectUrl = $this->getRedirectUrl($methodInstance, $order); + if ($redirectUrl) { $this->_redirectUrl($redirectUrl); return; } else { @@ -239,4 +239,20 @@ public function redirectAction() $this->loadLayout(); $this->renderLayout(); } + + /** + * @param Mage_Payment_Model_Method_Abstract $methodInstance + * @param Mage_Sales_Model_Order $order + * @return string|null + */ + private function getRedirectUrl(Mage_Payment_Model_Method_Abstract $methodInstance, Mage_Sales_Model_Order $order) + { + $redirectUrl = $methodInstance->startTransaction($order); + + if (!$redirectUrl && $methodInstance instanceof Mollie_Mpm_Model_Method_Creditcard) { + $redirectUrl = Mage::getUrl('checkout/onepage/success'); + } + + return $redirectUrl; + } } diff --git a/app/code/community/Mollie/Mpm/etc/config.xml b/app/code/community/Mollie/Mpm/etc/config.xml index 57663635..7347bc12 100644 --- a/app/code/community/Mollie/Mpm/etc/config.xml +++ b/app/code/community/Mollie/Mpm/etc/config.xml @@ -145,6 +145,15 @@ + + + + singleton + Mollie_Mpm_Model_Observer + injectMollieComponentsJs + + + diff --git a/app/code/community/Mollie/Mpm/etc/system.xml b/app/code/community/Mollie/Mpm/etc/system.xml index 35fb0236..09e64200 100644 --- a/app/code/community/Mollie/Mpm/etc/system.xml +++ b/app/code/community/Mollie/Mpm/etc/system.xml @@ -93,10 +93,20 @@ 1 + + + 12 + 1 + 1 + 1 + + 1 + + text - 12 + 13 1 1 1 @@ -107,7 +117,7 @@ text - 12 + 14 1 1 1 @@ -119,7 +129,7 @@ button mpm/adminhtml_system_config_form_apitest_button - 13 + 15 1 1 1 @@ -131,7 +141,7 @@ button mpm/adminhtml_system_config_form_apitest_result - 14 + 16 1 1 1 @@ -168,7 +178,7 @@ select adminhtml/system_config_source_yesno - 22 + 23 1 1 1 @@ -181,7 +191,7 @@ select adminhtml/system_config_source_order_status_new - 23 + 24 1 1 1 @@ -194,7 +204,7 @@ select mpm/adminhtml_system_config_source_processing - 24 + 25 1 1 1 @@ -207,7 +217,7 @@ select adminhtml/system_config_source_yesno - 25 + 26 1 1 1 @@ -220,7 +230,7 @@ select mpm/adminhtml_system_config_source_locale - 26 + 27 1 1 1 @@ -233,7 +243,7 @@ select adminhtml/system_config_source_yesno - 27 + 28 1 1 1 @@ -246,7 +256,7 @@ select adminhtml/system_config_source_yesno - 27 + 29 1 1 1 @@ -259,7 +269,7 @@ select adminhtml/system_config_source_yesno - 28 + 30 1 1 1 @@ -764,10 +774,23 @@ 1 + + + select + adminhtml/system_config_source_yesno + 5 + 1 + 1 + 1 + Note: You need to enter your Profile ID in the general section of this extension configuration to use Mollie Components.]]> + + 1 + + text - 4 + 6 1 1 1 @@ -786,7 +809,7 @@ allowspecific - 5 + 7 adminhtml/system_config_source_payment_allspecificcountries 1 1 @@ -798,7 +821,7 @@ multiselect - 6 + 8 adminhtml/system_config_source_country 1 1 @@ -811,7 +834,7 @@ text - 7 + 9 1 1 1 @@ -822,7 +845,7 @@ text - 8 + 10 1 1 1 @@ -833,7 +856,7 @@ text - 9 + 11 1 1 1 diff --git a/app/design/frontend/base/default/layout/mollie_mpm.xml b/app/design/frontend/base/default/layout/mollie_mpm.xml index 3d9bba70..af218b2f 100644 --- a/app/design/frontend/base/default/layout/mollie_mpm.xml +++ b/app/design/frontend/base/default/layout/mollie_mpm.xml @@ -112,4 +112,20 @@ + + + + + skin_js + js/mollie/mpm/creditcard-components.js + + + mollie/mpm/style.css + + + + + + + diff --git a/app/design/frontend/base/default/template/mollie/mpm/payment/after_body_start.phtml b/app/design/frontend/base/default/template/mollie/mpm/payment/after_body_start.phtml new file mode 100644 index 00000000..55b2bf0d --- /dev/null +++ b/app/design/frontend/base/default/template/mollie/mpm/payment/after_body_start.phtml @@ -0,0 +1,13 @@ + + + \ No newline at end of file diff --git a/app/design/frontend/base/default/template/mollie/mpm/payment/form/creditcard-components.phtml b/app/design/frontend/base/default/template/mollie/mpm/payment/form/creditcard-components.phtml new file mode 100644 index 00000000..16c26b1e --- /dev/null +++ b/app/design/frontend/base/default/template/mollie/mpm/payment/form/creditcard-components.phtml @@ -0,0 +1,32 @@ + + +getMethodCode(); +?> + + + + + \ No newline at end of file diff --git a/modman b/modman index c410ae51..48539aee 100644 --- a/modman +++ b/modman @@ -19,4 +19,5 @@ app/design/adminhtml/default/default/template/mollie/mpm app/design/ad lib/Mollie lib/Mollie # skin skin/frontend/base/default/mollie skin/frontend/base/default/mollie +skin/frontend/base/default/js/mollie skin/frontend/base/default/js/mollie skin/adminhtml/default/default/mollie skin/adminhtml/default/default/mollie diff --git a/skin/frontend/base/default/js/mollie/mpm/creditcard-components.js b/skin/frontend/base/default/js/mollie/mpm/creditcard-components.js new file mode 100644 index 00000000..3e7467f0 --- /dev/null +++ b/skin/frontend/base/default/js/mollie/mpm/creditcard-components.js @@ -0,0 +1,73 @@ +var MollieComponents = Class.create(); +MollieComponents.prototype = { + components: {}, + + initialize: function (profile_id, testmode, locale) { + if (!window.Nodelist && !window.NodeList.prototype.each && window.NodeList.prototype.forEach) { + NodeList.prototype.each = NodeList.prototype.forEach; + } + + try { + this.mollie = Mollie(profile_id, { + testMode: testmode, + locale: locale + }); + + this.components.cardHolder = this.mollie.createComponent('cardHolder'); + this.components.cardNumber = this.mollie.createComponent('cardNumber'); + this.components.expiryDate = this.mollie.createComponent('expiryDate'); + this.components.verificationCode = this.mollie.createComponent('verificationCode'); + } catch (error) { + console.error(error); + } + }, + + getMollieToken: function() { + if ($$('input:checked[name=payment[method]]')[0].value !== 'mollie_creditcard') { + return this.parentSave(); + } + + this.mollie.createToken().then( function (result) { + if (result.error) { + alert(result.error.message); + return false; + } + + var tokenFields = $$('[name=cardToken]'); + if (result.token && tokenFields && tokenFields.length) { + var tokenField = tokenFields.shift(); + tokenField.removeAttribute('disabled'); + tokenField.value = result.token; + } + + this.parentSave(); + }.bind(this)); + }, + + mount: function () { + payment.addAfterInitFunction('mollie_components', function () { + this.parentSave = payment.save.bind(payment); + payment.save = this.getMollieToken.bind(this); + }.bind(this)); + + this.mountElement(this.components.cardHolder, '#card-holder'); + this.mountElement(this.components.cardNumber, '#card-number'); + this.mountElement(this.components.expiryDate, '#expiry-date'); + this.mountElement(this.components.verificationCode, '#verification-code'); + }, + + mountElement: function (element, id) { + element.mount(id); + + var errorElement = document.querySelector(id + '-error'); + element.addEventListener('change', function (event) { + if (event.error && event.touched) { + errorElement.textContent = event.error; + errorElement.style.display = 'block'; + } else { + errorElement.textContent = ''; + errorElement.style.display = 'none'; + } + }); + } +}; diff --git a/skin/frontend/base/default/mollie/mpm/style.css b/skin/frontend/base/default/mollie/mpm/style.css index 10cf96d0..a38b8852 100644 --- a/skin/frontend/base/default/mollie/mpm/style.css +++ b/skin/frontend/base/default/mollie/mpm/style.css @@ -66,4 +66,38 @@ 100% { transform: rotate(360deg); } +} + +.mollie-component { + width: 90%; + background-color: #FFF; + padding: 10px 15px; + border-radius: 6px; + color: #222; + transition: all .05s ease; + box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.1), 0px 1px 3px 0px rgba(0, 0, 0, 0.1), 0px 0px 0px 1px rgba(0, 0, 0, 0.05); + margin-bottom: 10px; + margin-top: 5px; +} + +.mollie-component.is-invalid { + background-color: #FFF0F0; + box-shadow: 0px 1px 1px 0px rgba(255, 51, 68, 0.1), 0px 1px 3px 0px rgba(255, 51, 68, 0.1); +} + +.payment-method-content .card-container { + max-width: 400px; + overflow: auto; + background-color: #FFF; + border-radius: 10px; + border: 1px solid rgba(0, 0, 0, 0.1); + display: block; + padding: 20px; + margin-bottom: 10px; +} + +.component-error { + color: #FF0000; + display: none; + margin-bottom: 10px; } \ No newline at end of file