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 7bf173e6 authored by attilak's avatar attilak

Add configuration for POS instalments

Add POS instalments
Refactor instalments on the frontend (credit cards, pos cloud)
If no terminal is available show message
parent 578230a5
<?php
/**
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
*
* Adyen Payment module (https://www.adyen.com/)
*
* Copyright (c) 2015 Adyen BV (https://www.adyen.com/)
* See LICENSE.txt for license details.
*
* Author: Adyen <magento@adyen.com>
*/
namespace Adyen\Payment\Block\Adminhtml\System\Config\Field;
class InstallmentsPosCloud extends \Magento\Config\Block\System\Config\Form\Field\FieldArray\AbstractFieldArray
{
/**
* @var \Adyen\Payment\Block\Adminhtml\System\Config\Field\Installment
*/
protected $_installmentRenderer = null;
/**
* Return renderer for installments
*
* @return Installment|\Magento\Framework\View\Element\BlockInterface
* @throws \Magento\Framework\Exception\LocalizedException
*/
protected function getNumberOfInstallmentsRenderer()
{
if (!$this->_installmentRenderer) {
$this->_installmentRenderer = $this->getLayout()->createBlock(
'\Adyen\Payment\Block\Adminhtml\System\Config\Field\Installment',
'',
['data' => ['is_render_to_js_template' => true]]
);
}
return $this->_installmentRenderer;
}
/**
* Prepare to render
* @return void
*/
protected function _prepareToRender()
{
$this->addColumn(
'amount',
[
'label' => __('Amount Range'),
'renderer' => false,
]
);
$this->addColumn(
'installments',
[
'label' => __('Number Of Installments'),
'renderer' => $this->getNumberOfInstallmentsRenderer(),
]
);
$this->_addAfter = false;
$this->_addButtonLabel = __('Add Rule');
}
/**
* Prepare existing row data object
*
* @param \Magento\Framework\DataObject $row
* @throws \Magento\Framework\Exception\LocalizedException
*/
protected function _prepareArrayRow(\Magento\Framework\DataObject $row)
{
$installlments = $row->getInstallments();
$options = [];
if ($installlments) {
$options['option_' . $this->getNumberOfInstallmentsRenderer()->calcOptionHash($installlments)]
= 'selected="selected"';
}
$row->setData('option_extra_attrs', $options);
}
}
......@@ -153,14 +153,32 @@ class AdyenInitiateTerminalApi implements AdyenInitiateTerminalApiInterface
'RequestedAmount' => doubleval($quote->getGrandTotal()),
],
],
'PaymentData' =>
[
'PaymentType' => $transactionType,
],
],
],
];
if (!empty($payload['number_of_installments'])) {
$request['SaleToPOIRequest']['PaymentData'] = [
"PaymentType" => "Instalment",
"Instalment" => [
"InstalmentType" => "EqualInstalments",
"SequenceNumber" => 1,
"Period" => 1,
"PeriodUnit" => "Monthly",
"TotalNbOfPayments" => (int)$payload['number_of_installments']
]
];
$request['SaleToPOIRequest']['PaymentRequest']['PaymentTransaction']['TransactionConditions'] = [
"DebitPreferredFlag" => false
];
} else {
$request['SaleToPOIRequest']['PaymentData'] = [
'PaymentType' => $transactionType,
];
}
$customerId = $this->getCustomerId($quote);
// If customer exists add it into the request to store request
......
<?php
/**
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
*
* Adyen Payment module (https://www.adyen.com/)
*
* Copyright (c) 2015 Adyen BV (https://www.adyen.com/)
* See LICENSE.txt for license details.
*
* Author: Adyen <magento@adyen.com>
*/
namespace Adyen\Payment\Model\Config\Backend;
class InstallmentsPosCloud extends \Magento\Framework\App\Config\Value
{
/**
* @var \Magento\Framework\Math\Random
*/
protected $mathRandom;
/**
* @param \Magento\Framework\Model\Context $context
* @param \Magento\Framework\Registry $registry
* @param \Magento\Framework\App\Config\ScopeConfigInterface $config
* @param \Magento\Framework\App\Cache\TypeListInterface $cacheTypeList
* @param \Magento\Framework\Math\Random $mathRandom
* @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource
* @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
* @param array $data
*/
public function __construct(
\Magento\Framework\Model\Context $context,
\Magento\Framework\Registry $registry,
\Magento\Framework\App\Config\ScopeConfigInterface $config,
\Magento\Framework\App\Cache\TypeListInterface $cacheTypeList,
\Magento\Framework\Math\Random $mathRandom,
\Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
\Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
array $data = []
) {
$this->mathRandom = $mathRandom;
parent::__construct($context, $registry, $config, $cacheTypeList, $resource, $resourceCollection, $data);
}
/**
* Prepare data before save
*
* @return $this
*/
public function beforeSave()
{
$value = $this->getValue();
$unserialized = @unserialize($value);
if ($unserialized !== false) {
return $this;
}
$result = [];
foreach ($value as $data) {
if (!$data) {
continue;
}
if (!is_array($data)) {
continue;
}
if (count($data) < 2) {
continue;
}
$amount = $data['amount'];
$installments = $data['installments'];
$result[$amount] = $installments;
}
asort($result);
$this->setValue(serialize($result));
return $this;
}
/**
* Process data after load
*
* @return $this
*/
protected function _afterLoad()
{
$value = $this->getValue();
$value = unserialize($value);
if (is_array($value)) {
$value = $this->encodeArrayFieldValue($value);
$this->setValue($value);
}
return $this;
}
/**
* Encode value to be used in \Magento\Config\Block\System\Config\Form\Field\FieldArray\AbstractFieldArray
*
* @param array $items
* @return array
*/
protected function encodeArrayFieldValue(array $items)
{
$result = [];
// sort on amount
ksort($items);
foreach ($items as $amount => $installment) {
$resultId = $this->mathRandom->getUniqueHash('_');
$result[$resultId] = ['amount' => $amount, 'installments' => $installment];
}
return $result;
}
}
......@@ -48,6 +48,11 @@ class AdyenPosCloudConfigProvider implements ConfigProviderInterface
*/
protected $paymentMethodsHelper;
/**
* @var \Adyen\Payment\Helper\Data
*/
protected $adyenHelper;
/**
* AdyenHppConfigProvider constructor.
*
......@@ -57,11 +62,13 @@ class AdyenPosCloudConfigProvider implements ConfigProviderInterface
public function __construct(
\Magento\Framework\App\RequestInterface $request,
\Magento\Framework\UrlInterface $urlBuilder,
\Adyen\Payment\Helper\PaymentMethods $paymentMethodsHelper
\Adyen\Payment\Helper\PaymentMethods $paymentMethodsHelper,
\Adyen\Payment\Helper\Data $adyenHelper
) {
$this->request = $request;
$this->urlBuilder = $urlBuilder;
$this->paymentMethodsHelper = $paymentMethodsHelper;
$this->adyenHelper = $adyenHelper;
}
/**
......@@ -86,6 +93,20 @@ class AdyenPosCloudConfigProvider implements ConfigProviderInterface
$config['payment']['adyenPos']['connectedTerminals'] = $this->getConnectedTerminals();
// has installments by default false
$config['payment']['adyenPos']['hasInstallments'] = false;
// get Installments
$installmentsEnabled = $this->adyenHelper->getAdyenPosCloudConfigData('enable_installments');
$installments = $this->adyenHelper->getAdyenPosCloudConfigData('installments');
if ($installmentsEnabled && $installments) {
$config['payment']['adyenPos']['installments'] = unserialize($installments);
$config['payment']['adyenPos']['hasInstallments'] = true;
} else {
$config['payment']['adyenPos']['installments'] = [];
}
return $config;
}
......
......@@ -32,12 +32,14 @@ use Magento\Quote\Api\Data\PaymentInterface;
class AdyenPosCloudDataAssignObserver extends AbstractDataAssignObserver
{
const TERMINAL_ID = 'terminal_id';
const NUMBER_OF_INSTALLMENTS = 'number_of_installments';
/**
* @var array
*/
protected $additionalInformationList = [
self::TERMINAL_ID
self::TERMINAL_ID,
self::NUMBER_OF_INSTALLMENTS
];
/**
......
......@@ -78,6 +78,28 @@
<config_path>payment/adyen_pos_cloud/recurring_type</config_path>
<comment>If you want to store the credentials for ONECLICK or RECURRING or combination of these two you need to contact support@adyen.com and ask if they can enable to store cards on company level. Changing this setting without doing this will lead to failed payments!</comment>
</field>
<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_pos_cloud/enable_installments</config_path>
</field>
<field id="installments" translate="label" sortOrder="220" showInDefault="1" showInWebsite="1"
showInStore="1">
<label>Installments</label>
<depends>
<field id="enable_installments">1</field>
</depends>
<tooltip>Configure your installment: 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\InstallmentsPosCloud</frontend_model>
<backend_model>Adyen\Payment\Model\Config\Backend\InstallmentsPosCloud</backend_model>
<config_path>payment/adyen_pos_cloud/installments</config_path>
</field>
<group id="adyen_pos_country_specific" translate="label" showInDefault="1" showInWebsite="1" sortOrder="210">
<label>Country Specific Settings</label>
<frontend_model>Magento\Config\Block\System\Config\Form\Fieldset</frontend_model>
......
......@@ -5,35 +5,36 @@
define(
[
'ko',
'jquery',
],
function (ko) {
function (ko, $) {
'use strict';
var installments = ko.observableArray(['key', 'value']);
return {
/**
* Populate the list of installments
* @param {Array} methods
*/
setInstallments: function (installmentData) {
// remove everything from the current list
installments.removeAll();
var i;
for (i = 0; i < installmentData.length; i++) {
installments.push(
{
key: installmentData[i].key,
value: installmentData[i].value
}
);
}
},
/**
* Get the list of available installments.
*
* @param installments
* @param grandTotal
* @param precision
* @param currencyCode
* @returns {Array}
*/
getInstallments: function () {
return installments;
getInstallmentsWithPrices: function (installments, grandTotal, precision, currencyCode) {
let numberOfInstallments = [];
let dividedAmount = 0;
let dividedString = "";
$.each(installments, function (amount, installment) {
if (grandTotal >= amount) {
dividedAmount = (grandTotal / installment).toFixed(precision);
dividedString = installment + " x " + dividedAmount + " " + currencyCode;
numberOfInstallments.push({
key: [dividedString],
value: installment
});
}
});
return numberOfInstallments;
}
};
}
......
......@@ -39,7 +39,7 @@ define(
'Adyen_Payment/js/threeds2-js-utils',
'Adyen_Payment/js/model/threeds2'
],
function ($, ko, Component, customer, creditCardData, additionalValidators, quote, installments, url, VaultEnabler, urlBuilder, storage, fullScreenLoader, setPaymentMethodAction, selectPaymentMethodAction, threeDS2Utils, threeds2) {
function ($, ko, Component, customer, creditCardData, additionalValidators, quote, installmentsHelper, url, VaultEnabler, urlBuilder, storage, fullScreenLoader, setPaymentMethodAction, selectPaymentMethodAction, threeDS2Utils, threeds2) {
'use strict';
......@@ -83,13 +83,13 @@ define(
'expiryMonth',
'expiryYear',
'installment',
'installments',
'creditCardDetailsValid',
'placeOrderAllowed'
]);
return this;
},
getInstallments: installments.getInstallments(),
/**
* Returns true if card details can be stored
* @returns {*|boolean}
......@@ -104,17 +104,17 @@ define(
* set up the installments
*/
renderSecureFields: function () {
var self = this;
let self = this;
if (!self.getOriginKey()) {
return;
}
installments.setInstallments(0);
self.installments(0);
// installments enabled ??
var allInstallments = self.getAllInstallments();
var cardNode = document.getElementById('cardContainer');
// installments
let allInstallments = self.getAllInstallments();
let cardNode = document.getElementById('cardContainer');
self.cardComponent = self.checkout.create('card', {
originKey: self.getOriginKey(),
......@@ -147,35 +147,24 @@ define(
if (creditCardType) {
// If the credit card type is already set, check if it changed or not
if (!self.creditCardType() || self.creditCardType() && self.creditCardType() != creditCardType) {
let numberOfInstallments = [];
if (creditCardType in allInstallments) {
// get for the creditcard the installments
var installmentCreditcard = allInstallments[creditCardType];
var grandTotal = quote.totals().grand_total;
var numberOfInstallments = [];
var dividedAmount = 0;
var dividedString = "";
$.each(installmentCreditcard, function (amount, 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;
}
});
let installmentCreditcard = allInstallments[creditCardType];
let grandTotal = quote.totals().grand_total;
let precision = quote.getPriceFormat().precision;
let currencyCode = quote.totals().quote_currency_code;
numberOfInstallments = installmentsHelper.getInstallmentsWithPrices(installmentCreditcard, grandTotal, precision, currencyCode);
}
if (numberOfInstallments) {
installments.setInstallments(numberOfInstallments);
self.installments(numberOfInstallments);
}
else {
installments.setInstallments(0);
self.installments(0);
}
}
......@@ -188,7 +177,7 @@ define(
}
} else {
self.creditCardType("")
installments.setInstallments(0);
self.installments(0);
}
}
}).mount(cardNode);
......
......@@ -37,9 +37,10 @@ define(
'Magento_Checkout/js/model/full-screen-loader',
'Magento_Checkout/js/model/error-processor',
'Magento_Ui/js/model/messages',
'Magento_Checkout/js/action/redirect-on-success'
'Magento_Checkout/js/action/redirect-on-success',
'Adyen_Payment/js/model/installments'
],
function (ko, $, Component, additionalValidators, placeOrderAction, quote, agreementsAssigner, customer, urlBuilder, storage, fullScreenLoader, errorProcessor, Messages, redirectOnSuccessAction) {
function (ko, $, Component, additionalValidators, placeOrderAction, quote, agreementsAssigner, customer, urlBuilder, storage, fullScreenLoader, errorProcessor, Messages, redirectOnSuccessAction, installmentsHelper) {
'use strict';
return Component.extend({
......@@ -47,7 +48,34 @@ define(
defaults: {
template: 'Adyen_Payment/payment/pos-cloud-form'
},
initObservable: function () {
this._super()
.observe([
'terminalId',
'installments',
'installment'
]);
return this;
},
initialize: function () {
this._super();
let self = this;
// installments
let allInstallments = self.getAllInstallments();
let grandTotal = quote.totals().grand_total;
let precision = quote.getPriceFormat().precision;
let currencyCode = quote.totals().quote_currency_code;
let numberOfInstallments = installmentsHelper.getInstallmentsWithPrices(allInstallments, grandTotal, precision, currencyCode);
if (numberOfInstallments) {
self.installments(numberOfInstallments);
} else {
self.installments(0);
}
},
initiate: function () {
var self = this,
serviceUrl,
......@@ -59,7 +87,10 @@ define(
fullScreenLoader.startLoader();
let payload = {
"payload": JSON.stringify({terminal_id: self.terminalId()})
"payload": JSON.stringify({
terminal_id: self.terminalId(),
number_of_installments: self.installment()
})
}
return storage.post(
......@@ -69,21 +100,13 @@ define(
self.placeOrderPos()});
return false;
},
initObservable: function () {
this._super()
.observe([
'terminalId'
]);
return this;
},
posComplete: function () {
this.afterPlaceOrder();
if (this.redirectAfterPlaceOrder) {
redirectOnSuccessAction.execute();
}
},
placeOrderPos: function () {
var self = this;
return $.when(
......@@ -128,16 +151,33 @@ define(
return {
'method': this.item.method,
additional_data: {
'terminal_id': this.terminalId()
'terminal_id': this.terminalId(),
'number_of_installments': this.installment(),
}
};
},
hasInstallments: function () {
return window.checkoutConfig.payment.adyenPos.hasInstallments;
},
getAllInstallments: function () {
return window.checkoutConfig.payment.adyenPos.installments;
},
showLogo: function () {
return window.checkoutConfig.payment.adyen.showLogo;
},
validate: function () {
return true;
}
},
isActive: function () {
return true;
},
/**
* Returns state of place order button
* @returns {boolean}
*/
isButtonActive: function () {
return this.isActive() && this.getCode() == this.isChecked();
},
});
}
);
......@@ -87,7 +87,7 @@
<!-- ko if: (hasInstallments())-->
<div class="field required"
data-bind="attr: {id: getCode() + '_installments_div'}, visible: getInstallments().length > 0">
data-bind="attr: {id: getCode() + '_installments_div'}, visible: installments().length > 0">
<label data-bind="attr: {for: getCode() + '_installments'}" class="label">
<span><!-- ko text: $t('Installments')--><!-- /ko --></span>
</label>
......@@ -98,7 +98,7 @@
data-bind="attr: {id: getCode() + '_installments', 'data-container': getCode() + '-installments', 'data-validate': JSON.stringify({required:false})},
enable: isActive($parents),
options: getInstallments,
options: installments,
optionsValue: 'value',
optionsText: 'key',
optionsCaption: $t('Do not use Installments'),
......
......@@ -50,30 +50,61 @@
<!--/ko-->
</div>
<div class="field required"
data-bind="attr: {id: getCode() + '_connected_terminals_div'}, visible: getConnectedTerminals().length > 0">
<label data-bind="attr: {for: getCode() + '_connected_terminals'}" class="label">
<span><!-- ko text: $t('Connected terminals')--><!-- /ko --></span>
</label>
<div class="control">
<!-- ko if: (getConnectedTerminals().length > 0) -->
<select class="select"
name="paymentMethod[connected_terminals]"
data-bind="attr: {id: getCode() + '_connected_terminals', 'data-container': getCode() + '-connected-terminals', 'data-validate': JSON.stringify({required:true})},
options: getConnectedTerminals(),
optionsValue: 'value',
optionsText: 'key',
value: terminalId"
>
</select>
<div class="field required"
data-bind="attr: {id: getCode() + '_connected_terminals_div'}, visible: getConnectedTerminals().length > 0">
<label data-bind="attr: {for: getCode() + '_connected_terminals'}" class="label">
<span><!-- ko text: $t('Connected terminals')--><!-- /ko --></span>
</label>
<div class="control">
<select class="select"
name="paymentMethod[connected_terminals]"
data-bind="attr: {id: getCode() + '_connected_terminals', 'data-container': getCode() + '-connected-terminals', 'data-validate': JSON.stringify({required:true})},
options: getConnectedTerminals(),
optionsValue: 'value',
optionsText: 'key',
value: terminalId"
>
</select>
</div>
</div>
</div>
<div class="checkout-agreements-block">
<!-- ko foreach: $parent.getRegion('before-place-order') -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->
</div>
<!-- ko if: (hasInstallments())-->
<div class="field required"
data-bind="attr: {id: getCode() + '_installments_div'}, visible: installments().length > 0">
<label data-bind="attr: {for: getCode() + '_installments'}" class="label">
<span><!-- ko text: $t('Installments')--><!-- /ko --></span>
</label>
<div class="control">
<select class="select"
name="payment[number_of_installments]"
data-bind="attr: {id: getCode() + '_installments', 'data-container': getCode() + '-installments', 'data-validate': JSON.stringify({required:false})},
enable: isActive($parents),
options: installments,
optionsValue: 'value',
optionsText: 'key',
optionsCaption: $t('Do not use Installments'),
value: installment"
data-validate="{required:true}">
</select>
</div>
</div>
<!-- /ko -->
<div class="checkout-agreements-block">
<!-- ko foreach: $parent.getRegion('before-place-order') -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->
</div>
<!--/ko-->
<!-- ko ifnot: (getConnectedTerminals().length > 0) -->
<p><!-- ko text: $t('Please connect at least 1 terminal')--><!-- /ko --></p>
<!--/ko-->
<div class="actions-toolbar">
<div class="primary">
<button class="action primary checkout"
......@@ -81,7 +112,7 @@
data-bind="
click: initiate,
attr: {title: $t('Place Order')},
enable: getConnectedTerminals().length > 0
enable: isButtonActive()
"
disabled>
<span data-bind="text: $t('Place Order')"></span>
......
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