We will be off from 27/1 (Monday) to 31/1 (Friday) (GMT +7) for our Tet Holiday (Lunar New Year) in our country

Commit e9cfcb60 authored by Alessio Zampatti's avatar Alessio Zampatti Committed by GitHub

Fix installments (#229)

* PW-303: Fixed the installments to only show the configured ones.

* PW-303: installments and fix cronmessage

* PW-303: Fixed OneClick installments, small fix on CronMessage

* PW-303: Reformat code

* PW-303: Readded the optionsCaption in the forms

* PW-303: Added incomplete installmentvalidator

* PW-303: Added installmentvalidator

* removed comment

* PW-303: Fixed merge and formatting

* PW-303: Removed ObjectManager call, added sorting to installments

* PW-303: Added tooltip for the installments.
parent 19dc78da
...@@ -80,14 +80,14 @@ class Installments extends \Magento\Config\Block\System\Config\Form\Field\FieldA ...@@ -80,14 +80,14 @@ class Installments extends \Magento\Config\Block\System\Config\Form\Field\FieldA
$this->addColumn( $this->addColumn(
'amount', 'amount',
[ [
'label' => __('Amount Range (minor units)'), 'label' => __('Amount Range'),
'renderer' => false, 'renderer' => false,
] ]
); );
$this->addColumn( $this->addColumn(
'installments', 'installments',
[ [
'label' => __('Max Number Of Installments'), 'label' => __('Number Of Installments'),
'renderer' => $this->getNumberOfInstallmentsRenderer(), 'renderer' => $this->getNumberOfInstallmentsRenderer(),
] ]
); );
......
<?php
/**
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
*
* Adyen Payment Module
*
* Copyright (c) 2017 Adyen B.V.
* This file is open source and available under the MIT license.
* See the LICENSE file for more info.
*
* Author: Adyen <magento@adyen.com>
*/
namespace Adyen\Payment\Gateway\Validator;
use Magento\Payment\Gateway\Validator\AbstractValidator;
class InstallmentValidator extends AbstractValidator
{
/**
* @var \Adyen\Payment\Logger\AdyenLogger
*/
private $adyenLogger;
/**
* @var \Adyen\Payment\Helper\Data
*/
private $adyenHelper;
/**
* @var \Magento\Checkout\Model\Session
*/
private $session;
/**
* InstallmentValidator constructor.
* @param \Magento\Payment\Gateway\Validator\ResultInterfaceFactory $resultFactory
* @param \Adyen\Payment\Logger\AdyenLogger $adyenLogger
* @param \Adyen\Payment\Helper\Data $adyenHelper
* @param \Magento\Framework\App\ObjectManager $objectManager
*/
public function __construct(
\Magento\Payment\Gateway\Validator\ResultInterfaceFactory $resultFactory,
\Adyen\Payment\Logger\AdyenLogger $adyenLogger,
\Adyen\Payment\Helper\Data $adyenHelper,
\Magento\Checkout\Model\Session $session
) {
$this->adyenLogger = $adyenLogger;
$this->adyenHelper = $adyenHelper;
$this->session = $session;
parent::__construct($resultFactory);
}
public function validate(array $validationSubject)
{
$isValid = true;
$fails = [];
$payment = $validationSubject['payment'];
$quote = $this->session->getQuote();
if ($quote) {
$grandTotal = $quote->getGrandTotal();
$installmentsAvailable = $this->adyenHelper->getAdyenCcConfigData('installments');
$installmentSelected = $payment->getAdditionalInformation('number_of_installments');
$ccType = $payment->getAdditionalInformation('cc_type');
if ($installmentsAvailable) {
$installments = unserialize($installmentsAvailable);
}
if ($installmentSelected && $installmentsAvailable) {
$isValid = false;
$fails[] = __('Installments not valid.');
if ($installments) {
foreach ($installments as $ccTypeInstallment => $installment) {
if ($ccTypeInstallment == $ccType) {
foreach ($installment as $amount => $installmentsData) {
if ($installmentSelected == $installmentsData) {
if ($grandTotal >= $amount) {
$isValid = true;
}
}
}
}
}
}
}
}
return $this->createResult($isValid, $fails);
}
}
...@@ -817,18 +817,19 @@ class Data extends AbstractHelper ...@@ -817,18 +817,19 @@ class Data extends AbstractHelper
} }
if ($installments) { if ($installments) {
$numberOfInstallments = null; $numberOfInstallments = [];
foreach ($installments as $ccTypeInstallment => $installment) { foreach ($installments as $ccTypeInstallment => $installment) {
if ($ccTypeInstallment == $ccType) { if ($ccTypeInstallment == $ccType) {
foreach ($installment as $amount => $installments) { foreach ($installment as $amount => $installments) {
if ($grandTotal <= $amount) { if ($grandTotal >= $amount) {
$numberOfInstallments = $installments; array_push($numberOfInstallments, $installments);
} }
} }
} }
} }
if ($numberOfInstallments) { if ($numberOfInstallments) {
sort($numberOfInstallments);
$data['number_of_installments'] = $numberOfInstallments; $data['number_of_installments'] = $numberOfInstallments;
} }
} }
...@@ -935,7 +936,7 @@ class Data extends AbstractHelper ...@@ -935,7 +936,7 @@ class Data extends AbstractHelper
{ {
$notifications = $this->_notificationFactory->create(); $notifications = $this->_notificationFactory->create();
$notifications->unprocessedNotificationsFilter(); $notifications->unprocessedNotificationsFilter();
return count($notifications); return $notifications->getSize();;
} }
/** /**
......
...@@ -66,7 +66,6 @@ class Installments extends \Magento\Framework\App\Config\Value ...@@ -66,7 +66,6 @@ class Installments extends \Magento\Framework\App\Config\Value
if ($unserialized !== false) { if ($unserialized !== false) {
return $this; return $this;
} }
$result = []; $result = [];
foreach ($value as $data) { foreach ($value as $data) {
if (!$data) { if (!$data) {
...@@ -83,12 +82,19 @@ class Installments extends \Magento\Framework\App\Config\Value ...@@ -83,12 +82,19 @@ class Installments extends \Magento\Framework\App\Config\Value
$installments = $data['installments']; $installments = $data['installments'];
$ccTypes = $data['cc_types']; $ccTypes = $data['cc_types'];
foreach($ccTypes as $ccType) { foreach ($ccTypes as $ccType) {
$result[$ccType][$amount] = $installments; $result[$ccType][$amount] = $installments;
} }
} }
$this->setValue(serialize($result)); // sort on installments
$finalResult = [];
foreach ($result as $key => $installments) {
asort($installments);
$finalResult[$key] = $installments;
}
$this->setValue(serialize($finalResult));
return $this; return $this;
} }
......
...@@ -139,9 +139,10 @@ class AdyenCcConfigProvider implements ConfigProviderInterface ...@@ -139,9 +139,10 @@ class AdyenCcConfigProvider implements ConfigProviderInterface
$config['payment']['adyenCc']['hasInstallments'] = false; $config['payment']['adyenCc']['hasInstallments'] = false;
// get Installments // get Installments
$installmentsEnabled = $this->_adyenHelper->getAdyenCcConfigData('enable_installments');
$installments = $this->_adyenHelper->getAdyenCcConfigData('installments'); $installments = $this->_adyenHelper->getAdyenCcConfigData('installments');
if ($installments) { if ($installmentsEnabled && $installments) {
$config['payment']['adyenCc']['installments'] = unserialize($installments); $config['payment']['adyenCc']['installments'] = unserialize($installments);
$config['payment']['adyenCc']['hasInstallments'] = true; $config['payment']['adyenCc']['hasInstallments'] = true;
} else { } else {
......
...@@ -67,9 +67,17 @@ ...@@ -67,9 +67,17 @@
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model> <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<config_path>payment/adyen_cc/enable_moto</config_path> <config_path>payment/adyen_cc/enable_moto</config_path>
</field> </field>
<field id="installments" translate="label" sortOrder="220" showInDefault="1" showInWebsite="1" showInStore="0"> <field id="enable_installments" translate="label" type="select" sortOrder="219" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Enable Installments</label>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<tooltip>Enable installments for each credit card type.</tooltip>
<config_path>payment/adyen_cc/enable_installments</config_path>
</field>
<field id="installments" translate="label" sortOrder="220" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Installments</label> <label>Installments</label>
<tooltip>Configure your installment foreach creditcard type.</tooltip> <depends><field id="enable_installments">1</field></depends>
<tooltip>Configure your installment for each credit card type: Insert the minimum amount required to make the configured installment available in the amount range column.
Example: if the amount range is configured to 100 and the number of installments to 4x, the shopper will see the 4x option only if the payment total is higher or equal than 100.</tooltip>
<frontend_model>Adyen\Payment\Block\Adminhtml\System\Config\Field\Installments</frontend_model> <frontend_model>Adyen\Payment\Block\Adminhtml\System\Config\Field\Installments</frontend_model>
<backend_model>Adyen\Payment\Model\Config\Backend\Installments</backend_model> <backend_model>Adyen\Payment\Model\Config\Backend\Installments</backend_model>
<config_path>payment/adyen_cc/installments</config_path> <config_path>payment/adyen_cc/installments</config_path>
......
...@@ -653,6 +653,7 @@ ...@@ -653,6 +653,7 @@
<arguments> <arguments>
<argument name="validators" xsi:type="array"> <argument name="validators" xsi:type="array">
<item name="country" xsi:type="string">AdyenCcCountryValidator</item> <item name="country" xsi:type="string">AdyenCcCountryValidator</item>
<item name="global" xsi:type="string">Adyen\Payment\Gateway\Validator\InstallmentValidator</item>
</argument> </argument>
</arguments> </arguments>
</virtualType> </virtualType>
...@@ -666,6 +667,7 @@ ...@@ -666,6 +667,7 @@
<arguments> <arguments>
<argument name="validators" xsi:type="array"> <argument name="validators" xsi:type="array">
<item name="country" xsi:type="string">AdyenOneclickCountryValidator</item> <item name="country" xsi:type="string">AdyenOneclickCountryValidator</item>
<item name="global" xsi:type="string">Adyen\Payment\Gateway\Validator\InstallmentValidator</item>
</argument> </argument>
</arguments> </arguments>
</virtualType> </virtualType>
......
...@@ -51,3 +51,4 @@ ...@@ -51,3 +51,4 @@
"Failed to disable this contract","Failed to disable this contract" "Failed to disable this contract","Failed to disable this contract"
"You will be redirected to the Adyen App", "You will be redirected to the Adyen App" "You will be redirected to the Adyen App", "You will be redirected to the Adyen App"
"Continue to Adyen App", "Continue to Adyen App" "Continue to Adyen App", "Continue to Adyen App"
"Do not use Installments", "Do not use Installments"
\ No newline at end of file
...@@ -8,7 +8,7 @@ define( ...@@ -8,7 +8,7 @@ define(
], ],
function (ko) { function (ko) {
'use strict'; 'use strict';
var installments = ko.observableArray([]); var installments = ko.observableArray(['key', 'value']);
return { return {
/** /**
* Populate the list of installments * Populate the list of installments
...@@ -17,14 +17,15 @@ define( ...@@ -17,14 +17,15 @@ define(
setInstallments: function (installmentData) { setInstallments: function (installmentData) {
// remove everything from the current list // remove everything from the current list
installments.removeAll(); installments.removeAll();
// populate installments
var i; var i;
for (i = 1; i <= installmentData; i++) { for (i = 0; i < installmentData.length; i++) {
installments.push({ installments.push(
key: i, {
value: i key: installmentData[i].key,
}); value: installmentData[i].value
}
);
} }
}, },
/** /**
......
...@@ -72,6 +72,9 @@ define( ...@@ -72,6 +72,9 @@ define(
var self = this; var self = this;
this._super(); this._super();
installments.setInstallments(0);
// include dynamic cse javascript // include dynamic cse javascript
var dfScriptTag = document.createElement('script'); var dfScriptTag = document.createElement('script');
dfScriptTag.src = this.getLibrarySource(); dfScriptTag.src = this.getLibrarySource();
...@@ -85,29 +88,42 @@ define( ...@@ -85,29 +88,42 @@ define(
var allInstallments = self.getAllInstallments(); var allInstallments = self.getAllInstallments();
// what card is this ?? // what card is this ??
if (creditCardData.creditCard) {
var creditcardType = creditCardData.creditCard.type; var creditcardType = creditCardData.creditCard.type;
if (creditcardType) {
cvcLength(4); cvcLength(4);
if (creditcardType != "AE") { if (creditcardType != "AE") {
cvcLength(3); cvcLength(3);
} }
if (creditcardType in allInstallments) { if (creditcardType in allInstallments) {
// get for the creditcard the installments // get for the creditcard the installments
var installmentCreditcard = allInstallments[creditcardType]; var installmentCreditcard = allInstallments[creditcardType];
var grandTotal = quote.totals().grand_total; var grandTotal = quote.totals().grand_total;
var numberOfInstallments = 0; var numberOfInstallments = [];
var dividedAmount = 0;
var dividedString = "";
$.each(installmentCreditcard, function (amount, installment) { $.each(installmentCreditcard, function (amount, installment) {
if (grandTotal <= amount) {
numberOfInstallments = installment; if (grandTotal >= amount) {
dividedAmount = (grandTotal / installment).toFixed(quote.getPriceFormat().precision);
dividedString = installment + " x " + dividedAmount + " " + quote.totals().quote_currency_code;
numberOfInstallments.push({
key: [dividedString],
value: installment
});
}
else {
return false; return false;
} }
}); });
}
if (numberOfInstallments > 0) { if (numberOfInstallments) {
installments.setInstallments(numberOfInstallments); installments.setInstallments(numberOfInstallments);
} }
} else { else {
installments.setInstallments(0); installments.setInstallments(0);
} }
} }
...@@ -188,8 +204,16 @@ define( ...@@ -188,8 +204,16 @@ define(
context: function () { context: function () {
return this; return this;
}, },
isCseEnabled: function () {
return window.checkoutConfig.payment.adyenCc.cseEnabled;
},
getCSEKey: function () {
return window.checkoutConfig.payment.adyenCc.cseKey;
},
getLibrarySource: function () { getLibrarySource: function () {
return window.checkoutConfig.payment.adyenCc.librarySource; return window.checkoutConfig.payment.adyenCc.librarySource;
}, },
getGenerationTime: function () { getGenerationTime: function () {
return window.checkoutConfig.payment.adyenCc.generationTime; return window.checkoutConfig.payment.adyenCc.generationTime;
...@@ -207,7 +231,9 @@ define( ...@@ -207,7 +231,9 @@ define(
var form = 'form[data-role=adyen-cc-form]'; var form = 'form[data-role=adyen-cc-form]';
var validate = $(form).validation() && $(form).validation('isValid'); var validate = $(form).validation() && $(form).validation('isValid');
// add extra validation because jqeury validation will not work on non name attributes
// add extra validation because jquery validation will not work on non name attributes
var ccNumber = Boolean($(form + ' #creditCardNumber').valid()); var ccNumber = Boolean($(form + ' #creditCardNumber').valid());
var owner = Boolean($(form + ' #creditCardHolderName').valid()); var owner = Boolean($(form + ' #creditCardHolderName').valid());
var expiration = Boolean($(form + ' #adyen_cc_expiration').valid()); var expiration = Boolean($(form + ' #adyen_cc_expiration').valid());
......
...@@ -107,7 +107,9 @@ define( ...@@ -107,7 +107,9 @@ define(
if (updatedExpiryDate || self.hasVerification()) { if (updatedExpiryDate || self.hasVerification()) {
var options = {enableValidations: false}; var options = {enableValidations: false};
var cseInstance = adyen.createEncryption(options); var cseInstance = adyen.createEncryption(options);
var encryptedData = cseInstance.encrypt(cardData); var encryptedData = cseInstance.encrypt(cardData);
data.additional_data.encrypted_data = encryptedData; data.additional_data.encrypted_data = encryptedData;
} }
...@@ -134,6 +136,7 @@ define( ...@@ -134,6 +136,7 @@ define(
context: function () { context: function () {
return this; return this;
}, },
canCreateBillingAgreement: function () { canCreateBillingAgreement: function () {
return window.checkoutConfig.payment.adyenCc.canCreateBillingAgreement; return window.checkoutConfig.payment.adyenCc.canCreateBillingAgreement;
}, },
...@@ -153,11 +156,18 @@ define( ...@@ -153,11 +156,18 @@ define(
// pre-define installments if they are set // pre-define installments if they are set
var i, installments = []; var i, installments = [];
if (value.number_of_installments > 0) {
for (i = 1; i <= value.number_of_installments; i++) { var grandTotal = quote.totals().grand_total;
var dividedString = "";
var dividedAmount = 0;
if (value.number_of_installments) {
for (i = 0; i < value.number_of_installments.length; i++) {
dividedAmount = (grandTotal / value.number_of_installments[i]).toFixed(quote.getPriceFormat().precision);
dividedString = value.number_of_installments[i] + " x " + dividedAmount + " " + quote.totals().quote_currency_code;
installments.push({ installments.push({
key: i, key: [dividedString],
value: i value: value.number_of_installments[i]
}); });
} }
} }
...@@ -178,6 +188,7 @@ define( ...@@ -178,6 +188,7 @@ define(
creditCardVerificationNumber: '', creditCardVerificationNumber: '',
creditCardExpMonth: ko.observable(creditCardExpMonth), creditCardExpMonth: ko.observable(creditCardExpMonth),
creditCardExpYear: ko.observable(creditCardExpYear), creditCardExpYear: ko.observable(creditCardExpYear),
getGenerationTime: function () { getGenerationTime: function () {
return window.checkoutConfig.payment.adyenCc.generationTime; return window.checkoutConfig.payment.adyenCc.generationTime;
}, },
......
...@@ -215,14 +215,16 @@ ...@@ -215,14 +215,16 @@
<span><!-- ko text: $t('Installments')--><!-- /ko --></span> <span><!-- ko text: $t('Installments')--><!-- /ko --></span>
</label> </label>
<div class="control"> <div class="control">
<select class="select" <select class="select"
name="payment[number_of_installments]" name="payment[number_of_installments]"
data-bind="attr: {id: getCode() + '_installments', 'data-container': getCode() + '-installments', 'data-validate': JSON.stringify({required:true})}, data-bind="attr: {id: getCode() + '_installments', 'data-container': getCode() + '-installments', 'data-validate': JSON.stringify({required:false})},
enable: isActive($parents), enable: isActive($parents),
options: getInstallments, options: getInstallments,
optionsValue: 'value', optionsValue: 'value',
optionsText: 'key', optionsText: 'key',
optionsCaption: $t('Installments'), optionsCaption: $t('Do not use Installments'),
value: installment" value: installment"
data-validate="{required:true}"> data-validate="{required:true}">
</select> </select>
......
...@@ -196,7 +196,7 @@ ...@@ -196,7 +196,7 @@
<!--/ko--> <!--/ko-->
<!-- ko if: number_of_installments > 0 --> <!-- ko if: number_of_installments.length > 0 -->
<div class="field required" data-bind="attr: {id: getCode() + '_installments_div'}, visible: getInstallments().length > 0"> <div class="field required" data-bind="attr: {id: getCode() + '_installments_div'}, visible: getInstallments().length > 0">
<label data-bind="attr: {for: getCode() + '_installments'}" class="label"> <label data-bind="attr: {for: getCode() + '_installments'}" class="label">
...@@ -205,12 +205,12 @@ ...@@ -205,12 +205,12 @@
<div class="control"> <div class="control">
<select class="select" <select class="select"
name="payment[number_of_installments]" name="payment[number_of_installments]"
data-bind="attr: {id: getCode() + '_installments', 'data-container': getCode() + '-installments', 'data-validate': JSON.stringify({required:true})}, data-bind="attr: {id: getCode() + '_installments', 'data-container': getCode() + '-installments', 'data-validate': JSON.stringify({required:false})},
enable: $parent.isActive($parents), enable: $parent.isActive($parents),
options: getInstallments, options: getInstallments,
optionsValue: 'value', optionsValue: 'value',
optionsText: 'key', optionsText: 'key',
optionsCaption: $t('Installments'), optionsCaption: $t('Do not use Installments'),
value: installment" value: installment"
data-validate="{required:true}"> data-validate="{required:true}">
</select> </select>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment