├── etc ├── db_schema.xml ├── adminhtml │ ├── routes.xml │ └── system.xml ├── frontend │ ├── routes.xml │ └── di.xml ├── events.xml ├── module.xml ├── csp_whitelist.xml ├── di.xml └── config.xml ├── composer.json ├── view ├── adminhtml │ ├── web │ │ ├── css │ │ │ └── system-config.css │ │ └── js │ │ │ └── lib │ │ │ └── connect.js │ ├── requirejs-config.js │ ├── layout │ │ └── adminhtml_system_config_edit.xml │ └── templates │ │ └── connect │ │ └── widget.phtml └── frontend │ ├── web │ ├── css │ │ └── main.css │ ├── js │ │ ├── view │ │ │ └── payment │ │ │ │ ├── xpayments-cloud.js │ │ │ │ └── method-renderer │ │ │ │ └── xpayments-cloud.js │ │ ├── base.js │ │ └── lib │ │ │ └── widget.js │ └── template │ │ └── payment │ │ └── form.html │ ├── requirejs-config.js │ └── layout │ └── checkout_index_index.xml ├── registration.php ├── Observer └── Payment │ └── DataAssignObserver.php ├── Transport ├── DataObject.php ├── WidgetSettings.php └── ConnectSettings.php ├── Logger ├── Handler.php └── Logger.php ├── Block ├── Payment │ └── Info.php ├── System │ └── Config │ │ └── CloudIframe.php └── Adminhtml │ └── Connect │ └── Widget.php ├── Helper ├── Client.php ├── Address.php └── Cart.php ├── Model ├── Order │ └── Payment.php └── Payment │ └── Method │ └── XPaymentsCloud.php ├── Controller └── Adminhtml │ └── System │ └── Config │ └── Save.php ├── README.md ├── Setup └── Patch │ └── Data │ └── AddXPaymentsCustomerIDAttribute.php └── Ui └── XPaymentsCloud └── ConfigProvider.php /etc/db_schema.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 |
7 |
8 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cdev/x-payments-cloud", 3 | "description": "PCI level 1 certified & PSD2/SCA ready all-in-one secure credit card processing solution for web shops X-Payments takes the PCI DSS burden off your shoulders.", 4 | "type": "magento2-module", 5 | "version": "100.4.1", 6 | "license": [ 7 | "OSL-3.0", 8 | "AFL-3.0" 9 | ], 10 | "minimum-stability": "dev", 11 | "require": { 12 | "php": "~7.4.0||~8.1.0", 13 | "magento/module-payment": "100.4.*", 14 | "magento/module-checkout": "100.4.*", 15 | "magento/module-sales": "103.0.*", 16 | "xpayments/cloud-sdk-php": "~0.2.0" 17 | }, 18 | "autoload": { 19 | "files": [ "registration.php" ], 20 | "psr-4": { 21 | "CDev\\XPaymentsCloud\\": "" 22 | } 23 | }, 24 | "repositories": [ 25 | { 26 | "type": "git", 27 | "url": "https://github.com/xpayments/m2-cloud" 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /view/adminhtml/web/css/system-config.css: -------------------------------------------------------------------------------- 1 | /** 2 | vim: set ts=4 sw=4 sts=4 et: 3 | * X-Payments Cloud Settings 4 | * 5 | * NOTICE OF LICENSE 6 | * 7 | * This source file is subject to the Open Software License (OSL 3.0) 8 | * that is bundled with this package in the file LICENSE.txt. 9 | * It is also available through the world-wide-web at this URL: 10 | * http://opensource.org/licenses/osl-3.0.php 11 | * If you did not receive a copy of the license and are unable to 12 | * obtain it through the world-wide-web, please send an email 13 | * to license@magentocommerce.com so we can send you a copy immediately. 14 | * 15 | * @author Qualiteam Software 16 | * @category CDev 17 | * @package CDev_XPaymentsCloud 18 | * @copyright (c) 2010-present Qualiteam software Ltd . All rights reserved 19 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 20 | */ 21 | 22 | #xpayments-iframe-container iframe { 23 | border: 0; 24 | } 25 | -------------------------------------------------------------------------------- /view/adminhtml/requirejs-config.js: -------------------------------------------------------------------------------- 1 | // vim: set ts=2 sw=2 sts=2 et: 2 | /** 3 | * Magento 4 | * 5 | * NOTICE OF LICENSE 6 | * 7 | * This source file is subject to the Open Software License (OSL 3.0) 8 | * that is bundled with this package in the file LICENSE.txt. 9 | * It is also available through the world-wide-web at this URL: 10 | * http://opensource.org/licenses/osl-3.0.php 11 | * If you did not receive a copy of the license and are unable to 12 | * obtain it through the world-wide-web, please send an email 13 | * to license@magentocommerce.com so we can send you a copy immediately. 14 | * 15 | * @author Qualiteam Software 16 | * @category CDev 17 | * @package CDev_XPaymentsCloud 18 | * @copyright (c) 2010-present Qualiteam software Ltd . All rights reserved 19 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 20 | */ 21 | 22 | var config = { 23 | paths: { 24 | 'xpayments/lib/connect': 'CDev_XPaymentsCloud/js/lib/connect', 25 | }, 26 | }; 27 | 28 | -------------------------------------------------------------------------------- /registration.php: -------------------------------------------------------------------------------- 1 | 17 | * @category CDev 18 | * @package CDev_XPaymentsCloud 19 | * @copyright (c) 2010-present Qualiteam software Ltd . All rights reserved 20 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 21 | */ 22 | 23 | \Magento\Framework\Component\ComponentRegistrar::register( 24 | \Magento\Framework\Component\ComponentRegistrar::MODULE, 25 | 'CDev_XPaymentsCloud', 26 | __DIR__ 27 | ); 28 | -------------------------------------------------------------------------------- /view/frontend/web/css/main.css: -------------------------------------------------------------------------------- 1 | /** 2 | vim: set ts=4 sw=4 sts=4 et: 3 | * Checkout page 4 | * 5 | * NOTICE OF LICENSE 6 | * 7 | * This source file is subject to the Open Software License (OSL 3.0) 8 | * that is bundled with this package in the file LICENSE.txt. 9 | * It is also available through the world-wide-web at this URL: 10 | * http://opensource.org/licenses/osl-3.0.php 11 | * If you did not receive a copy of the license and are unable to 12 | * obtain it through the world-wide-web, please send an email 13 | * to license@magentocommerce.com so we can send you a copy immediately. 14 | * 15 | * @author Qualiteam Software 16 | * @category CDev 17 | * @package CDev_XPaymentsCloud 18 | * @copyright (c) 2010-present Qualiteam software Ltd . All rights reserved 19 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 20 | */ 21 | 22 | @supports (-webkit-appearance: -apple-pay-button) { 23 | .apple-pay-button { 24 | -webkit-appearance: -apple-pay-button; 25 | overflow: hidden; 26 | color: transparent !important; 27 | } 28 | .apple-pay-button span { 29 | visibility: hidden; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /view/adminhtml/layout/adminhtml_system_config_edit.xml: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /etc/adminhtml/routes.xml: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /etc/frontend/routes.xml: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /etc/events.xml: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /view/frontend/requirejs-config.js: -------------------------------------------------------------------------------- 1 | // vim: set ts=2 sw=2 sts=2 et: 2 | /** 3 | * Magento 4 | * 5 | * NOTICE OF LICENSE 6 | * 7 | * This source file is subject to the Open Software License (OSL 3.0) 8 | * that is bundled with this package in the file LICENSE.txt. 9 | * It is also available through the world-wide-web at this URL: 10 | * http://opensource.org/licenses/osl-3.0.php 11 | * If you did not receive a copy of the license and are unable to 12 | * obtain it through the world-wide-web, please send an email 13 | * to license@magentocommerce.com so we can send you a copy immediately. 14 | * 15 | * @author Qualiteam Software 16 | * @category CDev 17 | * @package CDev_XPaymentsCloud 18 | * @copyright (c) 2010-present Qualiteam software Ltd . All rights reserved 19 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 20 | */ 21 | 22 | var config = { 23 | paths: { 24 | 'xpayments/lib/widget': 'CDev_XPaymentsCloud/js/lib/widget', 25 | 'xpayments/base': 'CDev_XPaymentsCloud/js/base', 26 | }, 27 | shim: { 28 | 'xpayments/base': ['prototype', 'xpayments/lib/widget'], 29 | 'CDev_XPaymentsCloud/js/view/payment/xpayments-cloud': ['xpayments/base'], 30 | }, 31 | deps: ['xpayments/lib/widget'] 32 | }; 33 | -------------------------------------------------------------------------------- /etc/module.xml: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /etc/csp_whitelist.xml: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 26 | 27 | 28 | connect.xpayments.com 29 | *.xpayments.com 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /view/frontend/web/js/view/payment/xpayments-cloud.js: -------------------------------------------------------------------------------- 1 | // vim: set ts=2 sw=2 sts=2 et: 2 | /** 3 | * Magento 4 | * 5 | * NOTICE OF LICENSE 6 | * 7 | * This source file is subject to the Open Software License (OSL 3.0) 8 | * that is bundled with this package in the file LICENSE.txt. 9 | * It is also available through the world-wide-web at this URL: 10 | * http://opensource.org/licenses/osl-3.0.php 11 | * If you did not receive a copy of the license and are unable to 12 | * obtain it through the world-wide-web, please send an email 13 | * to license@magentocommerce.com so we can send you a copy immediately. 14 | * 15 | * @author Qualiteam Software 16 | * @category CDev 17 | * @package CDev_XPaymentsCloud 18 | * @copyright (c) 2010-present Qualiteam software Ltd . All rights reserved 19 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 20 | */ 21 | define( 22 | [ 23 | 'uiComponent', 24 | 'Magento_Checkout/js/model/payment/renderer-list', 25 | ], 26 | function ( 27 | Component, 28 | rendererList 29 | ) { 30 | 'use strict'; 31 | 32 | rendererList.push( 33 | { 34 | type: 'xpayments_cloud', 35 | component: 'CDev_XPaymentsCloud/js/view/payment/method-renderer/xpayments-cloud', 36 | } 37 | ); 38 | 39 | return Component.extend({}); 40 | } 41 | ); 42 | -------------------------------------------------------------------------------- /etc/frontend/di.xml: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 26 | 27 | 28 | CDev\XPaymentsCloud\Ui\XPaymentsCloud\ConfigProvider 29 | 30 | 31 | 32 | 33 | 34 | 35 | 1 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Observer/Payment/DataAssignObserver.php: -------------------------------------------------------------------------------- 1 | 17 | * @category CDev 18 | * @package CDev_XPaymentsCloud 19 | * @copyright (c) 2010-present Qualiteam software Ltd . All rights reserved 20 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 21 | */ 22 | 23 | namespace CDev\XPaymentsCloud\Observer\Payment; 24 | 25 | /** 26 | * Data assign observer for X-Payments Cloud payment method 27 | */ 28 | class DataAssignObserver extends \Magento\Payment\Observer\AbstractDataAssignObserver 29 | { 30 | /** 31 | * Assign data 32 | * 33 | * @param \Magento\Framework\Event\Observer $observer 34 | * 35 | * @return void 36 | */ 37 | public function execute(\Magento\Framework\Event\Observer $observer) 38 | { 39 | $method = $this->readMethodArgument($observer); 40 | $data = $this->readDataArgument($observer); 41 | 42 | $additionalData = $data->getData(\Magento\Quote\Api\Data\PaymentInterface::KEY_ADDITIONAL_DATA); 43 | 44 | if (!empty($additionalData['xpayments_token'])) { 45 | $paymentInfo = $method->getInfoInstance(); 46 | $paymentInfo->setAdditionalInformation('xpayments_token', $additionalData['xpayments_token']); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Transport/DataObject.php: -------------------------------------------------------------------------------- 1 | 17 | * @category CDev 18 | * @package CDev_XPaymentsCloud 19 | * @copyright (c) 2010-present Qualiteam software Ltd . All rights reserved 20 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 21 | */ 22 | 23 | namespace CDev\XPaymentsCloud\Transport; 24 | 25 | /** 26 | * Base data-object class for transport 27 | */ 28 | abstract class DataObject extends \Magento\Framework\DataObject 29 | { 30 | /** 31 | * Tiny function to enhance functionality of ucwords 32 | * Will capitalize first letters and convert separators if needed 33 | * Doesn't exist in Magento 2 unfortunately 34 | * 35 | * @param string $str 36 | * @param string $destSep 37 | * @param string $srcSep 38 | * 39 | * @return string 40 | */ 41 | protected function ucWords($str, $destSep = '_', $srcSep = '_') 42 | { 43 | return str_replace(' ', $destSep, ucwords(str_replace($srcSep, ' ', $str))); 44 | } 45 | 46 | /** 47 | * Converts field names for setters and geters 48 | * (Do not use underscopes, actually, keep orig names) 49 | * 50 | * @param string $name 51 | * 52 | * @return string 53 | */ 54 | protected function _underscore($name) 55 | { 56 | return lcfirst($name); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Logger/Handler.php: -------------------------------------------------------------------------------- 1 | 17 | * @category CDev 18 | * @package CDev_XPaymentsCloud 19 | * @copyright (c) 2010-present Qualiteam software Ltd . All rights reserved 20 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 21 | */ 22 | 23 | namespace CDev\XPaymentsCloud\Logger; 24 | 25 | /** 26 | * Logger handler 27 | */ 28 | class Handler extends \Magento\Framework\Logger\Handler\Base 29 | { 30 | /** 31 | * Log file name 32 | */ 33 | protected const XPAYMENTS_LOG_FILE = '/var/log/xpayments-cloud-%s.log'; 34 | 35 | /** 36 | * Constructor 37 | * 38 | * @param \Magento\Framework\Filesystem\DriverInterface $filesystem 39 | * @param \Magento\Framework\Stdlib\DateTime\DateTime $date 40 | * @param string $filePath 41 | * @param string $fileName 42 | * 43 | * @return void 44 | * 45 | * @SuppressWarnings(MEQP2.Classes.ConstructorOperations.CustomOperationsFound) 46 | * @codingStandardsIgnoreStart 47 | */ 48 | public function __construct( 49 | \Magento\Framework\Filesystem\DriverInterface $filesystem, 50 | \Magento\Framework\Stdlib\DateTime\DateTime $date, 51 | $filePath = null, 52 | $fileName = null 53 | ) { 54 | 55 | $this->fileName = sprintf(self::XPAYMENTS_LOG_FILE, $date->date('Y-m')); 56 | 57 | parent::__construct($filesystem, $filePath, $fileName); 58 | } 59 | } 60 | 61 | -------------------------------------------------------------------------------- /etc/di.xml: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | CDev\XPaymentsCloud\Model\Payment\Method\XPaymentsCloud::CODE 31 | 32 | 33 | 34 | 35 | 36 | 37 | Magento\Framework\Filesystem\Driver\File 38 | 39 | 40 | 41 | 42 | xpcLogger 43 | 44 | CDev\XPaymentsCloud\Logger\Handler 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /etc/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 26 | 27 | 28 | 29 | 0 30 | 0 31 | CDev\XPaymentsCloud\Model\Payment\Method\XPaymentsCloud 32 | pending_payment 33 | authorize_capture 34 | Credit or Debit Card 35 | USD 36 | 1 37 | 1 38 | 1 39 | 1 40 | 1 41 | 1 42 | 1 43 | 0 44 | 1 45 | cc_last_4,cc_first6,xpayments_customer_id 46 | cc_first6,xpayments_customer_id 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /view/frontend/web/template/payment/form.html: -------------------------------------------------------------------------------- 1 | 23 |
24 |
25 | 29 | 32 |
33 | 34 |
35 | 36 | 37 | 38 |
39 | 40 | 41 | 42 |
43 | 44 |
45 | 46 |
47 |
48 | 60 |
61 |
62 |
63 |
64 | -------------------------------------------------------------------------------- /Block/Payment/Info.php: -------------------------------------------------------------------------------- 1 | 17 | * @category CDev 18 | * @package CDev_XPaymentsCloud 19 | * @copyright (c) 2010-present Qualiteam software Ltd . All rights reserved 20 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 21 | */ 22 | 23 | namespace CDev\XPaymentsCloud\Block\Payment; 24 | 25 | /** 26 | * Payment info block 27 | */ 28 | class Info extends \Magento\Payment\Block\ConfigurableInfo 29 | { 30 | /** 31 | * Name of the X-Payments card field 32 | */ 33 | protected const XPAYMENTS_CARD = 'xpayments_card'; 34 | 35 | /** 36 | * Placeholder for hidden numbers in card number 37 | */ 38 | protected const PLACEHOLDER = '•'; 39 | 40 | /** 41 | * Returns label 42 | * 43 | * @param string $field 44 | * 45 | * @return \Magento\Framework\Phrase 46 | */ 47 | protected function getLabel($field) 48 | { 49 | if (self::XPAYMENTS_CARD == $field) { 50 | $field = 'Payment Card'; 51 | } 52 | 53 | return parent::getLabel($field); 54 | } 55 | 56 | /** 57 | * Prepare payment information 58 | * 59 | * @param \Magento\Framework\DataObject|array|null $transport 60 | * 61 | * @return \Magento\Framework\DataObject 62 | */ 63 | protected function _prepareSpecificInformation($transport = null) 64 | { 65 | $transport = parent::_prepareSpecificInformation($transport); 66 | 67 | $payment = $this->getInfo(); 68 | 69 | $first6 = $payment->getCcFirst6() ?: str_repeat(self::PLACEHOLDER, 6); 70 | 71 | $middleLength = ('AMEX' === $payment->getCcType()) ? 5 : 6; 72 | $middle = str_repeat(self::PLACEHOLDER, $middleLength); 73 | 74 | $card = sprintf( 75 | '[%s] %s%s%s (%s/%s)', 76 | $payment->getCcType(), 77 | $first6, $middle, $payment->getCcLast4(), 78 | $payment->getCcExpMonth(), $payment->getCcExpYear() 79 | ); 80 | 81 | $this->setDataToTransfer( 82 | $transport, 83 | self::XPAYMENTS_CARD, 84 | $card 85 | ); 86 | 87 | return $transport; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /Block/System/Config/CloudIframe.php: -------------------------------------------------------------------------------- 1 | 17 | * @category CDev 18 | * @package CDev_XPaymentsCloud 19 | * @copyright (c) 2010-present Qualiteam software Ltd . All rights reserved 20 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 21 | */ 22 | 23 | namespace CDev\XPaymentsCloud\Block\System\Config; 24 | 25 | /** 26 | * X-Payments Cloud configuration iframe 27 | */ 28 | class CloudIframe extends \Magento\Config\Block\System\Config\Form\Field 29 | { 30 | /** 31 | * Layout 32 | * 33 | * @var \Magento\Framework\View\LayoutInterface 34 | */ 35 | protected $layout; 36 | 37 | /** 38 | * Constructor 39 | * 40 | * @param \Magento\Backend\Block\Template\Context $context 41 | * @param \Magento\Framework\View\LayoutInterface $layout 42 | * @param array $data 43 | * 44 | * @return void 45 | */ 46 | public function __construct( 47 | \Magento\Backend\Block\Template\Context $context, 48 | \Magento\Framework\View\LayoutInterface $layout, 49 | array $data = array() 50 | ) { 51 | $this->layout = $layout; 52 | parent::__construct($context); 53 | } 54 | 55 | /** 56 | * Retrieve HTML markup for given form element 57 | * 58 | * @param \Magento\Framework\Data\Form\Element\AbstractElement $element 59 | * 60 | * @return string 61 | */ 62 | public function render(\Magento\Framework\Data\Form\Element\AbstractElement $element) 63 | { 64 | $html = $this->layout 65 | ->createBlock(\CDev\XPaymentsCloud\Block\Adminhtml\Connect\Widget::class) 66 | ->toHtml(); 67 | 68 | return $this->_decorateRowHtml($element, $html); 69 | } 70 | 71 | /** 72 | * Decorate field row html 73 | * 74 | * @param \Magento\Framework\Data\Form\Element\AbstractElement $element 75 | * @param string $html 76 | * 77 | * @return string 78 | */ 79 | protected function _decorateRowHtml( 80 | \Magento\Framework\Data\Form\Element\AbstractElement $element, 81 | $html 82 | ) { 83 | $html = sprintf('%s', $html); 84 | 85 | return parent::_decorateRowHtml($element, $html); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Helper/Client.php: -------------------------------------------------------------------------------- 1 | 17 | * @category CDev 18 | * @package CDev_XPaymentsCloud 19 | * @copyright (c) 2010-present Qualiteam software Ltd . All rights reserved 20 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 21 | */ 22 | 23 | namespace CDev\XPaymentsCloud\Helper; 24 | 25 | /** 26 | * Helper for X-Payments SDK Client 27 | */ 28 | class Client extends \Magento\Framework\App\Helper\AbstractHelper 29 | { 30 | /** 31 | * X-Payments SDK Client 32 | * 33 | * @var \XPaymentsCloud\Client 34 | */ 35 | protected $client = null; 36 | 37 | /** 38 | * Scope config 39 | * 40 | * @var \Magento\Framework\App\Config\ScopeConfigInterface 41 | */ 42 | protected $scopeConfig = null; 43 | 44 | /** 45 | * Logger 46 | * 47 | * @var \CDev\XPaymentsCloud\Logger\Logger 48 | */ 49 | protected $xpaymentsLogger = null; 50 | 51 | /** 52 | * Constructor 53 | * 54 | * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig 55 | * @param \CDev\XPaymentsCloud\Logger\Logger $xpaymentsLogger 56 | * 57 | * @return void 58 | */ 59 | public function __construct( 60 | \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, 61 | \CDev\XPaymentsCloud\Logger\Logger $xpaymentsLogger 62 | ) { 63 | $this->scopeConfig = $scopeConfig; 64 | } 65 | 66 | /** 67 | * Get SDK Client 68 | * 69 | * @return \XPaymentsCloud\Client 70 | */ 71 | public function getClient() 72 | { 73 | if (null === $this->client) { 74 | 75 | $this->client = false; 76 | 77 | try { 78 | 79 | $this->client = new \XPaymentsCloud\Client( 80 | $this->scopeConfig->getValue('payment/xpayments_cloud/account'), 81 | $this->scopeConfig->getValue('payment/xpayments_cloud/api_key'), 82 | $this->scopeConfig->getValue('payment/xpayments_cloud/secret_key') 83 | ); 84 | 85 | } catch (\Exception $exception) { 86 | 87 | $message = $this->xpaymentsLogger->processException($exception); 88 | 89 | throw new \Magento\Framework\Exception\LocalizedException(__($message)); 90 | } 91 | } 92 | 93 | return $this->client; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /Model/Order/Payment.php: -------------------------------------------------------------------------------- 1 | 17 | * @category CDev 18 | * @package CDev_XPaymentsCloud 19 | * @copyright (c) 2010-present Qualiteam software Ltd . All rights reserved 20 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 21 | */ 22 | 23 | namespace CDev\XPaymentsCloud\Model\Order; 24 | 25 | /** 26 | * Auth/Capture/Sale logic 27 | */ 28 | class Payment extends \Magento\Sales\Model\Order\Payment 29 | { 30 | /** 31 | * Check if it was a Sale action 32 | * 33 | * @return bool 34 | */ 35 | protected function isSaleAction() 36 | { 37 | $transId = $this->getOrder()->getPayment()->getLastTransId(); 38 | 39 | return 'sale' == substr($transId, -4); 40 | } 41 | 42 | /** 43 | * Implement Auth/Capture/Sale logic 44 | * This method is called for all actions for authorize_capture Payment Action: 45 | * - authorize only 46 | * - authorize and capture (sale) 47 | * - capture (after initial auth) 48 | * 49 | * @param \Magento\Sales\Api\Data\InvoiceInterface $invoice 50 | * 51 | * @return \Magento\Sales\Api\Data\OrderPaymentInterface 52 | */ 53 | public function capture($invoice = null) 54 | { 55 | $order = $this->getOrder(); 56 | 57 | if ('xpayments_cloud' !== $order->getPayment()->getMethodInstance()->getCode()) { 58 | return parent::capture($invoice); 59 | } 60 | 61 | if (!$order->getState()) { 62 | 63 | // Order is just created 64 | // Execute 'pay' API action 65 | 66 | $this->authorize(true, $order->getBaseTotalDue()); 67 | $this->setAmountAuthorized($order->getTotalDue()); 68 | 69 | if ($this->isSaleAction()) { 70 | 71 | // This was a Sale action 72 | // So create Invoice and mark it as Paid 73 | 74 | $invoice = $this->getOrder()->prepareInvoice(); 75 | $invoice->register(); 76 | $invoice->setTransactionId($this->getOrder()->getPayment()->getLastTransId()); 77 | $invoice->pay(); 78 | 79 | $this->getOrder()->addRelatedObject($invoice); 80 | } 81 | 82 | } elseif (null === $invoice) { 83 | 84 | // Order State is 'processing' or similar 85 | // Execute 'capture online' operation via Invoice creation 86 | 87 | $invoice = $this->_invoice(); 88 | $this->setCreatedInvoice($invoice); 89 | 90 | } else { 91 | 92 | // Execute 'capture' API action 93 | 94 | parent::capture($invoice); 95 | } 96 | 97 | return $this; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /Transport/WidgetSettings.php: -------------------------------------------------------------------------------- 1 | 17 | * @category CDev 18 | * @package CDev_XPaymentsCloud 19 | * @copyright (c) 2010-present Qualiteam software Ltd . All rights reserved 20 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 21 | */ 22 | 23 | namespace CDev\XPaymentsCloud\Transport; 24 | 25 | /** 26 | * Transport for widget settings 27 | */ 28 | class WidgetSettings extends DataObject 29 | { 30 | /** 31 | * X-Payments cart helper 32 | * 33 | * @var \CDev\XPaymentsCloud\Helper\Cart 34 | */ 35 | protected $cartHelper = null; 36 | 37 | /** 38 | * Constructor 39 | * 40 | * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig 41 | * @param \Magento\Store\Model\StoreManagerInterface $storeManager 42 | * @param \CDev\XPaymentsCloud\Helper\Cart $cartHelper 43 | * 44 | * @return \Magento\Framework\DataObject 45 | */ 46 | public function __construct( 47 | \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, 48 | \Magento\Store\Model\StoreManagerInterface $storeManager, 49 | \CDev\XPaymentsCloud\Helper\Cart $cartHelper 50 | ) { 51 | 52 | $this->cartHelper = $cartHelper; 53 | 54 | $data = array( 55 | 'account' => $scopeConfig->getValue('payment/xpayments_cloud/account'), 56 | 'widgetKey' => $scopeConfig->getValue('payment/xpayments_cloud/widget_key'), 57 | 'devUrl' => (string)$scopeConfig->getValue('payment/xpayments_cloud/dev_url'), 58 | 'container' => '#xpayments-iframe-container', 59 | 'tokenInputId' => 'xpayments-token', 60 | 'language' => 'en', 61 | 'customerId' => '', 62 | 'autoload' => false, 63 | 'autoSubmit' => false, 64 | 'debug' => (bool)$scopeConfig->getValue('payment/xpayments_cloud/debug'), 65 | 'order' => array( 66 | 'currency' => $storeManager->getStore()->getCurrentCurrency()->getCode(), 67 | ), 68 | 'company' => array( 69 | 'name' => $scopeConfig->getValue('general/store_information/name'), 70 | 'countryCode' => $scopeConfig->getValue('general/country/default'), 71 | ), 72 | ); 73 | 74 | return $this->setData($data); 75 | } 76 | 77 | /** 78 | * Set order total 79 | * 80 | * @param float|string $value 81 | * 82 | * @return \Magento\Framework\DataObject 83 | */ 84 | public function setTotal($value) 85 | { 86 | $order = $this->getOrder(); 87 | 88 | $order['total'] = $this->cartHelper->preparePrice($value); 89 | 90 | return $this->setOrder($order); 91 | } 92 | 93 | /** 94 | * Set tokenize card flag 95 | * 96 | * @param bool $value 97 | * 98 | * @return \Magento\Framework\DataObject 99 | */ 100 | public function setTokenizeCard($value) 101 | { 102 | $order = $this->getOrder(); 103 | 104 | $order['tokenizeCard'] = (bool)$value; 105 | 106 | return $this->setOrder($order); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /Block/Adminhtml/Connect/Widget.php: -------------------------------------------------------------------------------- 1 | 17 | * @category CDev 18 | * @package CDev_XPaymentsCloud 19 | * @copyright (c) 2010-present Qualiteam software Ltd . All rights reserved 20 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 21 | */ 22 | 23 | namespace CDev\XPaymentsCloud\Block\Adminhtml\Connect; 24 | 25 | /** 26 | * X-Payments Cloud Connect Widget 27 | */ 28 | class Widget extends \Magento\Backend\Block\Template 29 | { 30 | /** 31 | * Scope config 32 | * 33 | * @var \Magento\Framework\App\Config\ScopeConfigInterface 34 | */ 35 | protected $scopeConfig = null; 36 | 37 | /** 38 | * Request 39 | * 40 | * @var \Magento\Framework\App\RequestInterface 41 | */ 42 | protected $request = null; 43 | 44 | /** 45 | * Store Manager 46 | * 47 | * @var \Magento\Store\Model\StoreManagerInterface 48 | */ 49 | protected $storeManager = null; 50 | 51 | /** 52 | * Backend URL builder 53 | * 54 | * @var \Magento\Backend\Model\UrlInterface 55 | */ 56 | protected $backendUrl = null; 57 | 58 | /** 59 | * PayPal Structure Plugin 60 | * 61 | * @var \Magento\Paypal\Model\Config\StructurePlugin 62 | */ 63 | protected $paypalStructure; 64 | 65 | /** 66 | * Constructor 67 | * 68 | * @param \Magento\Backend\Block\Template\Context $context 69 | * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig 70 | * @param \Magento\Framework\App\RequestInterface $request 71 | * @param \Magento\Store\Model\StoreManagerInterface $storeManager 72 | * @param \Magento\Backend\Model\UrlInterface $backendUrl 73 | * @param \Magento\Paypal\Model\Config\StructurePlugin $paypalStructure 74 | * @param array $data 75 | * 76 | * @return void 77 | */ 78 | public function __construct( 79 | \Magento\Backend\Block\Template\Context $context, 80 | \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, 81 | \Magento\Framework\App\RequestInterface $request, 82 | \Magento\Store\Model\StoreManagerInterface $storeManager, 83 | \Magento\Backend\Model\UrlInterface $backendUrl, 84 | \Magento\Paypal\Model\Config\StructurePlugin $paypalStructure, 85 | array $data = array() 86 | ) { 87 | $this->_template = 'connect/widget.phtml'; 88 | 89 | $this->scopeConfig = $scopeConfig; 90 | $this->request = $request; 91 | $this->storeManager = $storeManager; 92 | $this->backendUrl = $backendUrl; 93 | $this->paypalStructure = $paypalStructure; 94 | 95 | parent::__construct($context, $data); 96 | } 97 | 98 | /** 99 | * Get hash of widget settings 100 | * 101 | * @return \CDev\XPaymentsCloud\Transport\ConnectSettings 102 | */ 103 | public function getConnectWidgetSettings() 104 | { 105 | return new \CDev\XPaymentsCloud\Transport\ConnectSettings( 106 | $this->scopeConfig, 107 | $this->request, 108 | $this->storeManager, 109 | $this->backendUrl, 110 | $this->paypalStructure 111 | ); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /Controller/Adminhtml/System/Config/Save.php: -------------------------------------------------------------------------------- 1 | 17 | * @category CDev 18 | * @package CDev_XPaymentsCloud 19 | * @copyright (c) 2010-present Qualiteam software Ltd . All rights reserved 20 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 21 | */ 22 | 23 | namespace CDev\XPaymentsCloud\Controller\Adminhtml\System\Config; 24 | 25 | /** 26 | * Save X-Payments Cloud connect settings 27 | */ 28 | class Save extends \Magento\Config\Controller\Adminhtml\System\Config\Save 29 | { 30 | /** 31 | * Resource config 32 | * 33 | * @var \Magento\Config\Model\ResourceModel\Config 34 | */ 35 | protected $resourceConfig = null; 36 | 37 | /** 38 | * Tiny function to enhance functionality of ucwords 39 | * Will capitalize first letters and convert separators if needed 40 | * Doesn't exist in Magento 2 unfortunately 41 | * 42 | * @param string $str 43 | * @param string $destSep 44 | * @param string $srcSep 45 | * 46 | * @return string 47 | */ 48 | protected function ucWords($str, $destSep = '_', $srcSep = '_') 49 | { 50 | return str_replace(' ', $destSep, ucwords(str_replace($srcSep, ' ', $str))); 51 | } 52 | 53 | /** 54 | * @param \Magento\Backend\App\Action\Context $context 55 | * @param \Magento\Config\Model\Config\Structure $configStructure 56 | * @param \Magento\Config\Controller\Adminhtml\System\ConfigSectionChecker $sectionChecker 57 | * @param \Magento\Config\Model\Config\Factory $configFactory 58 | * @param \Magento\Framework\Cache\FrontendInterface $cache 59 | * @param \Magento\Framework\Stdlib\StringUtils $string 60 | * @param \Magento\Config\Model\ResourceModel\Config $resourceConfig 61 | */ 62 | public function __construct( 63 | \Magento\Backend\App\Action\Context $context, 64 | \Magento\Config\Model\Config\Structure $configStructure, 65 | \Magento\Config\Controller\Adminhtml\System\ConfigSectionChecker $sectionChecker, 66 | \Magento\Config\Model\Config\Factory $configFactory, 67 | \Magento\Framework\Cache\FrontendInterface $cache, 68 | \Magento\Framework\Stdlib\StringUtils $string, 69 | \Magento\Config\Model\ResourceModel\Config $resourceConfig 70 | ) { 71 | parent::__construct($context, $configStructure, $sectionChecker, $configFactory, $cache, $string); 72 | $this->resourceConfig = $resourceConfig; 73 | } 74 | 75 | /** 76 | * Save configuration 77 | * 78 | * @return void 79 | */ 80 | public function execute() 81 | { 82 | $fields = array( 83 | 'account', 84 | 'api_key', 85 | 'secret_key', 86 | 'widget_key', 87 | 'quick_access_key', 88 | ); 89 | 90 | $data = $this->getRequest()->getPost(); 91 | 92 | foreach ($fields as $field) { 93 | 94 | $path = 'payment/xpayments_cloud/' . $field; 95 | 96 | $key = lcfirst($this->ucWords($field, '')); 97 | 98 | $value = isset($data[$key]) ? $data[$key] : ''; 99 | 100 | $this->resourceConfig->saveConfig( 101 | $path, 102 | $value 103 | ); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # X-Payments Cloud connector for Magento 2 2 | This extension connects your Magento 2 store with X-Payments Cloud - a PSD2/SCA ready PCI Level 1 certified credit card processing app which allows you to store customers’ credit card information and still be compliant with PCI security mandates. 3 | 4 | The credit card form can be embedded right into checkout page, so your customers won’t leave your site to complete an order. 5 | 6 | ### Installation 7 | Via composer: 8 | ```sh 9 | composer.phar require cdev/x-payments-cloud 10 | bin/magento module:enable CDev_XPaymentsCloud 11 | bin/magento setup:di:compile 12 | bin/magento setup:static-content:deploy -f 13 | ``` 14 | Or copy these files into the `/app/code/CDev/XPaymentsCloud/` directory and run: 15 | ```sh 16 | bin/magento setup:upgrade 17 | bin/magento module:enable CDev_XPaymentsCloud 18 | bin/magento setup:di:compile 19 | bin/magento setup:static-content:deploy -f 20 | ``` 21 | ### Configuration 22 | First, you shuld create the X-Payments Cloud account. 23 | - Navigate **Stores -> Configuration -> Sales -> Payment Methods** 24 | - Expand the **X-Payments Cloud** section 25 | - Start the signup process to create an X-Payments Cloud account and follow the Wizard instructions 26 | - In the end you will be prompted to set a password. Then complete 2-step user authentication setup for your account 27 | 28 | Now X-Payments Cloud payment method is available at checkout in demo mode. Just don't forget to enable it. 29 | To proceed with accepting real payments get back to the X-Payments Cloud payment method configuration and: 30 | - Select the necessary payment gateway from the **Add payment configuration** list 31 | - Enter you gateway credentials and adjust the necessary settings specific to this payment gateway 32 | 33 | Refer to the manual for the detailed instructions: https://www.x-payments.com/wp-content/uploads/help_uploads/Using-X-Payments-Cloud-with-Magento-2.pdf 34 | 35 | 36 | ### Supported payment gateways 37 | X-Payments Cloud supports more than 60 [payment gateway integrations](https://www.x-payments.com/help/XP_Cloud:Supported_payment_gateways): ANZ eGate, American Express Web-Services API Integration, Authorize.Net, Bambora (Beanstream), Beanstream (legacy API), Bendigo Bank, BillriantPay, BluePay, BlueSnap Payment API (XML), Braintree, BluePay Canada (Caledon), Cardinal Commerce Centinel, Chase Paymentech, CommWeb - Commonwealth Bank, BAC Credomatic, CyberSource - SOAP Toolkit API, X-Payments Demo Pay, X-Payments Demo Pay 3-D Secure, DIBS, DirectOne - Direct Interface, eProcessing Network - Transparent Database Engine, SecurePay Australia, Moneris eSELECTplus, Elavon (Realex API), ePDQ MPI XML (Phased out), eWAY Rapid - Direct Connection, eWay Realtime Payments XML, Sparrow (5th Dimension Gateway), First Data Payeezy Gateway (ex- Global Gateway e4), Global Iris, Global Payments, GoEmerchant - XML Gateway API, HeidelPay, Innovative Gateway, iTransact XML, Payment XP (Meritus) Web Host, NAB - National Australia Bank, NMI (Network Merchants Inc.), Netbilling - Direct Mode, Netevia, Ingenico ePayments (Ogone e-Commerce), PayGate South Africa, Payflow Pro, PayPal REST API, PayPal Payments Pro (PayPal API), PayPal Payments Pro (Payflow API), PSiGate XML API, QuantumGateway - XML Requester, Intuit QuickBooks Payments, QuickPay, Worldpay Corporate Gateway - Direct Model, Global Payments (ex. Realex), Opayo Direct (ex. Sage Pay Go - Direct Interface), Paya (ex. Sage Payments US), Simplify Commerce by MasterCard, SkipJack, Suncorp, TranSafe, powered by Monetra, 2Checkout, USA ePay - Transaction Gateway API, Elavon Converge (ex VirtualMerchant), WebXpress, Worldpay Total US, Worldpay US (Lynk Systems). 38 | 39 | ### Supported Fraud-screening services: 40 | - Kount 41 | - NoFraud 42 | - Signifyd 43 | 44 | ### Refference 45 | - [X-Payments Cloud API](https://xpayments.stoplight.io/docs/server-side-api/) 46 | - [X-Payments Cloud PHP SDK](https://github.com/xpayments/cloud-sdk-php) 47 | 48 | ### Support 49 | If you have any questions please free to [contact us](https://www.x-payments.com/contact-us). 50 | -------------------------------------------------------------------------------- /view/frontend/layout/checkout_index_index.xml: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | uiComponent 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | CDev_XPaymentsCloud/js/view/payment/xpayments-cloud 47 | 48 | 49 | true 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /Logger/Logger.php: -------------------------------------------------------------------------------- 1 | 17 | * @category CDev 18 | * @package CDev_XPaymentsCloud 19 | * @copyright (c) 2010-present Qualiteam software Ltd . All rights reserved 20 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 21 | */ 22 | 23 | namespace CDev\XPaymentsCloud\Logger; 24 | 25 | /** 26 | * Logger 27 | */ 28 | class Logger extends \Monolog\Logger 29 | { 30 | /** 31 | * Store manager 32 | * 33 | * @var \Magento\Store\Model\StoreManagerInterface 34 | */ 35 | protected $storeManager = null; 36 | 37 | /** 38 | * Current URL 39 | * 40 | * @var string 41 | */ 42 | protected $url = null; 43 | 44 | /** 45 | * Constructor 46 | * 47 | * @param string $name 48 | * @param \Magento\Store\Model\StoreManagerInterface $storeManager 49 | * @param HandlerInterface[] $handlers 50 | * @param callable[] $processors 51 | * 52 | * @return void 53 | */ 54 | public function __construct( 55 | $name, 56 | \Magento\Store\Model\StoreManagerInterface $storeManager, 57 | array $handlers = array(), 58 | array $processors = array() 59 | ) { 60 | 61 | $this->storeManager = $storeManager; 62 | 63 | parent::__construct($name, $handlers, $processors); 64 | } 65 | 66 | /** 67 | * Process exception 68 | * 69 | * @param \Exception $exception 70 | * @param string $title 71 | * @param bool $trace Include backtrace or not 72 | * 73 | * @return string 74 | */ 75 | public function processException(\Exception $exception, $title = false, $trace = false) 76 | { 77 | if ( 78 | method_exists($exception, 'getPublicMessage') 79 | && $exception->getPublicMessage() 80 | ) { 81 | $message = $exception->getPublicMessage(); 82 | } else { 83 | $message = $exception->getMessage(); 84 | } 85 | 86 | $data = array(); 87 | 88 | if (!empty($title)) { 89 | $data[] = $message; 90 | } else { 91 | $title = $message; 92 | } 93 | 94 | $data[] = get_class($exception); 95 | 96 | $data = implode(PHP_EOL, $data); 97 | 98 | $this->writeLog($title, $data, $trace); 99 | 100 | return $message; 101 | } 102 | 103 | /** 104 | * Get current URL 105 | * 106 | * @return string 107 | */ 108 | protected function getUrl() 109 | { 110 | if (null === $this->url) { 111 | 112 | // Remove session key from URL 113 | $this->url = preg_replace( 114 | array('/\/key\/\w+\//', '/\?.*$/'), 115 | array('/', ''), 116 | $this->storeManager->getStore()->getCurrentUrl() 117 | ); 118 | } 119 | 120 | return $this->url; 121 | } 122 | 123 | /** 124 | * Write log record 125 | * 126 | * @param string $title Log title 127 | * @param mixed $data Data to log 128 | * @param bool $trace Include backtrace or not 129 | * 130 | * @return bool Whether the record has been processed 131 | */ 132 | public function writeLog($title, $data = '', $trace = false) 133 | { 134 | if (!is_string($data)) { 135 | $data = var_export($data, true); 136 | } 137 | 138 | $message = $title . PHP_EOL 139 | . date('Y-m-d H:i:s') . PHP_EOL 140 | . $data . PHP_EOL 141 | . $this->getUrl() . PHP_EOL; 142 | 143 | if ($trace) { 144 | $message .= '--------------------------' . PHP_EOL 145 | . \Magento\Framework\Debug::backtrace(true, false, false) 146 | . PHP_EOL; 147 | } 148 | 149 | return $this->debug($message); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /Setup/Patch/Data/AddXPaymentsCustomerIDAttribute.php: -------------------------------------------------------------------------------- 1 | 17 | * @category CDev 18 | * @package CDev_XPaymentsCloud 19 | * @copyright (c) 2010-present Qualiteam software Ltd . All rights reserved 20 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 21 | */ 22 | declare(strict_types=1); 23 | 24 | namespace CDev\XPaymentsCloud\Setup\Patch\Data; 25 | 26 | /** 27 | * Add EAV attribute for X-Payments Customer ID 28 | */ 29 | class AddXPaymentsCustomerIDAttribute implements \Magento\Framework\Setup\Patch\DataPatchInterface 30 | { 31 | /** 32 | * @var ModuleDataSetupInterface $moduleDataSetup 33 | */ 34 | private $moduleDataSetup; 35 | 36 | /** 37 | * Customer setup factory 38 | * 39 | * @var \Magento\Customer\Setup\CustomerSetupFactory $customerSetupFactory 40 | */ 41 | protected $customerSetupFactory = null; 42 | 43 | /** 44 | * Attribute set factory 45 | * 46 | * @var \Magento\Eav\Model\Entity\Attribute\SetFactory 47 | */ 48 | private $attributeSetFactory = null; 49 | 50 | /** 51 | * Constructor 52 | * 53 | * @param \Magento\Framework\Setup\ModuleDataSetupInterface $moduleDataSetup 54 | * @param \Magento\Customer\Setup\CustomerSetupFactory $customerSetupFactory 55 | * @param \Magento\Eav\Model\Entity\Attribute\SetFactory $attributeSetFactory 56 | * 57 | * @return void 58 | */ 59 | public function __construct( 60 | \Magento\Framework\Setup\ModuleDataSetupInterface $moduleDataSetup, 61 | \Magento\Customer\Setup\CustomerSetupFactory $customerSetupFactory, 62 | \Magento\Eav\Model\Entity\Attribute\SetFactory $attributeSetFactory 63 | ) { 64 | $this->moduleDataSetup = $moduleDataSetup; 65 | 66 | $this->customerSetupFactory = $customerSetupFactory; 67 | $this->attributeSetFactory = $attributeSetFactory; 68 | } 69 | 70 | /** 71 | * Do Upgrade 72 | * 73 | * @return void 74 | */ 75 | public function apply() 76 | { 77 | $customerSetup = $this->customerSetupFactory->create(array('setup' => $this->moduleDataSetup)); 78 | 79 | $customerEntity = $customerSetup->getEavConfig()->getEntityType('customer'); 80 | $attributeSetId = $customerEntity->getDefaultAttributeSetId(); 81 | 82 | $attributeSet = $this->attributeSetFactory->create(); 83 | $attributeGroupId = $attributeSet->getDefaultGroupId($attributeSetId); 84 | 85 | $customerSetup->addAttribute( 86 | \Magento\Customer\Model\Customer::ENTITY, 87 | 'xpayments_customer_id', 88 | array( 89 | 'type' => 'varchar', 90 | 'label' => 'X-Payments Cloud customer ID', 91 | 'input' => 'text', 92 | 'required' => false, 93 | 'visible' => false, 94 | 'user_defined' => true, 95 | 'sort_order' => 1000, 96 | 'position' => 1000, 97 | 'system' => 0, 98 | ) 99 | ); 100 | 101 | $attribute = $customerSetup->getEavConfig() 102 | ->getAttribute( 103 | \Magento\Customer\Model\Customer::ENTITY, 104 | 'xpayments_customer_id' 105 | )->addData( 106 | array( 107 | 'attribute_set_id' => $attributeSetId, 108 | 'attribute_group_id' => $attributeGroupId, 109 | ) 110 | ); 111 | 112 | $attribute->save(); 113 | } 114 | 115 | /** 116 | * @inheritdoc 117 | */ 118 | public function getAliases() 119 | { 120 | return array(); 121 | } 122 | 123 | /** 124 | * @inheritdoc 125 | */ 126 | public static function getDependencies() 127 | { 128 | return array(); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /view/adminhtml/templates/connect/widget.phtml: -------------------------------------------------------------------------------- 1 | 17 | * @category CDev 18 | * @package CDev_XPaymentsCloud 19 | * @copyright (c) 2010-present Qualiteam software Ltd . All rights reserved 20 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 21 | */ 22 | ?> 23 | 28 | 29 |
30 | 31 | 154 | -------------------------------------------------------------------------------- /Ui/XPaymentsCloud/ConfigProvider.php: -------------------------------------------------------------------------------- 1 | 17 | * @category CDev 18 | * @package CDev_XPaymentsCloud 19 | * @copyright (c) 2010-present Qualiteam software Ltd . All rights reserved 20 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 21 | */ 22 | 23 | namespace CDev\XPaymentsCloud\Ui\XPaymentsCloud; 24 | 25 | /** 26 | * Configuration provider for XPC method at checkout 27 | */ 28 | class ConfigProvider implements \Magento\Checkout\Model\ConfigProviderInterface 29 | { 30 | /** 31 | * Payment method object 32 | * 33 | * @var \Magento\Payment\Model\MethodInterface 34 | */ 35 | protected $method = null; 36 | 37 | /** 38 | * Scope config 39 | * 40 | * @var \Magento\Framework\App\Config\ScopeConfigInterface 41 | */ 42 | protected $scopeConfig = null; 43 | 44 | /** 45 | * Store manager 46 | * 47 | * @var \Magento\Store\Model\StoreManagerInterface 48 | */ 49 | protected $storeManager = null; 50 | 51 | /** 52 | * X-Payments cart helper 53 | * 54 | * @var \CDev\XPaymentsCloud\Helper\Cart 55 | */ 56 | protected $cartHelper = null; 57 | 58 | /** 59 | * Customer session 60 | * 61 | * @var \Magento\Customer\Model\Session 62 | */ 63 | protected $customerSession = null; 64 | 65 | /** 66 | * Checkout session 67 | * 68 | * @var \Magento\Checkout\Model\Session 69 | */ 70 | protected $checkoutSession = null; 71 | 72 | /** 73 | * Constructor 74 | * 75 | * @param \Magento\Payment\Helper\Data $paymentHelper 76 | * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig 77 | * @param \Magento\Store\Model\StoreManagerInterface $storeManager 78 | * @param \CDev\XPaymentsCloud\Helper\Cart $cartHelper 79 | * @param \Magento\Customer\Model\Session $customerSession 80 | * @param \Magento\Checkout\Model\Session $checkoutSession 81 | * 82 | * @return void 83 | */ 84 | public function __construct( 85 | \Magento\Payment\Helper\Data $paymentHelper, 86 | \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, 87 | \Magento\Store\Model\StoreManagerInterface $storeManager, 88 | \CDev\XPaymentsCloud\Helper\Cart $cartHelper, 89 | \Magento\Customer\Model\Session $customerSession, 90 | \Magento\Checkout\Model\Session $checkoutSession 91 | ) { 92 | 93 | $this->method = $paymentHelper->getMethodInstance( 94 | \CDev\XPaymentsCloud\Model\Payment\Method\XPaymentsCloud::CODE 95 | ); 96 | 97 | $this->scopeConfig = $scopeConfig; 98 | $this->storeManager = $storeManager; 99 | 100 | $this->cartHelper = $cartHelper; 101 | 102 | $this->customerSession = $customerSession; 103 | $this->checkoutSession = $checkoutSession; 104 | } 105 | 106 | /** 107 | * Get X-Payments Customer ID 108 | * 109 | * @return string 110 | */ 111 | protected function getXpaymentsCustomerId() 112 | { 113 | $xpaymentsCustomerId = ''; 114 | 115 | if ($this->customerSession->isLoggedIn()) { 116 | 117 | $xpaymentsCustomerId = (string)$this->customerSession 118 | ->getCustomer() 119 | ->getXpaymentsCustomerId(); 120 | } 121 | 122 | return $xpaymentsCustomerId; 123 | } 124 | 125 | /** 126 | * Retrieve assoc array of checkout configuration 127 | * 128 | * @return array 129 | */ 130 | public function getConfig() 131 | { 132 | $total = $this->checkoutSession->getQuote() 133 | ->getGrandTotal(); 134 | 135 | $showSaveCard = $this->customerSession->isLoggedIn(); 136 | 137 | $settings = new \CDev\XPaymentsCloud\Transport\WidgetSettings( 138 | $this->scopeConfig, 139 | $this->storeManager, 140 | $this->cartHelper 141 | ); 142 | 143 | $settings->setShowSaveCard($showSaveCard) 144 | ->setTokenizeCard(false) 145 | ->setAutoSubmit(false) 146 | ->setCustomerId($this->getXpaymentsCustomerId()) 147 | ->setForm('#co-payment-form') 148 | ->setTokenInputName('payment[xpayments_token]') 149 | ->setTotal($total); 150 | 151 | return array( 152 | 'payment' => array( 153 | $this->method::CODE => $settings->getData() 154 | ), 155 | ); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /view/frontend/web/js/view/payment/method-renderer/xpayments-cloud.js: -------------------------------------------------------------------------------- 1 | // vim: set ts=2 sw=2 sts=2 et: 2 | /** 3 | * Magento 4 | * 5 | * NOTICE OF LICENSE 6 | * 7 | * This source file is subject to the Open Software License (OSL 3.0) 8 | * that is bundled with this package in the file LICENSE.txt. 9 | * It is also available through the world-wide-web at this URL: 10 | * http://opensource.org/licenses/osl-3.0.php 11 | * If you did not receive a copy of the license and are unable to 12 | * obtain it through the world-wide-web, please send an email 13 | * to license@magentocommerce.com so we can send you a copy immediately. 14 | * 15 | * @author Qualiteam Software 16 | * @category CDev 17 | * @package CDev_XPaymentsCloud 18 | * @copyright (c) 2010-present Qualiteam software Ltd . All rights reserved 19 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 20 | */ 21 | define( 22 | [ 23 | 'Magento_Checkout/js/view/payment/default', 24 | 'Magento_Checkout/js/checkout-data', 25 | ], 26 | function (Component, checkoutData) { 27 | 'use strict'; 28 | 29 | return Component.extend({ 30 | 31 | /** 32 | * Component defaults 33 | */ 34 | defaults: { 35 | template: 'CDev_XPaymentsCloud/payment/form', 36 | }, 37 | 38 | /** 39 | * Get payment method code 40 | * 41 | * @return string 42 | */ 43 | getCode: function() { 44 | return 'xpayments_cloud'; 45 | }, 46 | 47 | /** 48 | * Check if payment method is active 49 | * 50 | * @return bool 51 | */ 52 | isActive: function() { 53 | 54 | var active = (this.getCode() === this.isChecked()); 55 | 56 | window.xpayments.onSwitchPaymentMethod(); 57 | 58 | return active; 59 | }, 60 | 61 | /** 62 | * Initialize payment method 63 | * 64 | * @return void 65 | */ 66 | initialize: function() 67 | { 68 | this._super(); 69 | 70 | var self = this; 71 | 72 | /** 73 | * Check if X-Payments Cloud is currently selected payment method 74 | * 75 | * @return bool 76 | */ 77 | XPayments.prototype.isCurrent = function () { 78 | return 'undefined' != typeof checkoutData 79 | && ( 80 | 'xpayments_cloud' == checkoutData.getSelectedPaymentMethod() 81 | || ( 82 | jQuery('#xpayments_cloud').next('label').is(':visible') 83 | && jQuery('#xpayments_cloud').get(0).checked 84 | ) 85 | ); 86 | } 87 | 88 | /** 89 | * Toggle Apple Pay button 90 | * 91 | * @return bool 92 | */ 93 | XPayments.prototype.toggleApplePayButton = function (isApple) { 94 | $('xpayments-place-order').toggleClassName('apple-pay-button', isApple); 95 | } 96 | 97 | /** 98 | * On success event 99 | * 100 | * @return void 101 | */ 102 | XPayments.prototype.onSuccess = XPayments.prototype.onSuccess.wrap( 103 | function (parentMethod, params) { 104 | 105 | self.xpaymentsToken = params.token; 106 | 107 | parentMethod(params); 108 | } 109 | ); 110 | 111 | window.xpayments = new XPayments(window.checkoutConfig.payment.xpayments_cloud); 112 | 113 | window.xpayments.load(); 114 | }, 115 | 116 | /** 117 | * Get payment method data which is send to controller after order is submitted 118 | * 119 | * @return JSON 120 | */ 121 | getData: function() 122 | { 123 | return { 124 | method: this.item.method, 125 | additional_data: { 126 | xpayments_token: this.xpaymentsToken, 127 | } 128 | }; 129 | }, 130 | 131 | /** 132 | * Place order 133 | * 134 | * @return bool 135 | */ 136 | placeOrder: function () 137 | { 138 | window.xpayments.onSubmitPayment(this._super.bind(this)); 139 | }, 140 | 141 | /** 142 | * Place order fail 143 | * 144 | * @return void 145 | */ 146 | placeOrderFail: function () 147 | { 148 | window.xpayments.onSwitchPaymentMethod(); 149 | }, 150 | 151 | /** 152 | * Get place order deferred object 153 | * 154 | * @return {*} 155 | */ 156 | getPlaceOrderDeferredObject: function() 157 | { 158 | return this._super().fail(this.placeOrderFail); 159 | }, 160 | }); 161 | } 162 | ); 163 | -------------------------------------------------------------------------------- /view/adminhtml/web/js/lib/connect.js: -------------------------------------------------------------------------------- 1 | /* 2 | * X-Payments Cloud SDK - Connect Widget 3 | */ 4 | 5 | function XPaymentsConnect(elmSelector, quickAccessKey, handlers) { 6 | this.serverDomain = 'xpayments.com'; 7 | this.messageNamespace = 'xpayments.connect.'; 8 | 9 | this.previousHeight = -1; 10 | 11 | this.config = { 12 | debug: false, 13 | account: '', 14 | container: '', 15 | topElement: '', 16 | referrerUrl: document.location.href, 17 | applePayOnly: false, 18 | quickAccessKey: '' 19 | } 20 | 21 | this.handlers = {}; 22 | 23 | this.bindedListener = false; 24 | 25 | } 26 | 27 | XPaymentsConnect.prototype.init = function(settings) 28 | { 29 | for (var key in settings) { 30 | if ('undefined' !== typeof this.config[key]) { 31 | this.config[key] = settings[key]; 32 | } 33 | } 34 | 35 | // Set default handlers 36 | this.on('alert', function(params) { 37 | window.alert(params.message); 38 | }).on('config', function() { 39 | console.error('X-Payments Widget is not configured properly!'); 40 | }); 41 | 42 | this.bindedListener = this.messageListener.bind(this); 43 | window.addEventListener('message', this.bindedListener); 44 | 45 | return this; 46 | } 47 | 48 | XPaymentsConnect.prototype.getContainerElm = function() 49 | { 50 | return this.safeQuerySelector(this.config.container); 51 | } 52 | 53 | XPaymentsConnect.prototype.getIframeId = function() 54 | { 55 | return 'xpayments-connect'; 56 | } 57 | 58 | XPaymentsConnect.prototype.getIframeElm = function() 59 | { 60 | return document.getElementById(this.getIframeId()); 61 | } 62 | 63 | XPaymentsConnect.prototype.safeQuerySelector = function(selector) 64 | { 65 | var elm = false; 66 | if (selector) { 67 | elm = document.querySelector(selector); 68 | } 69 | return elm; 70 | } 71 | 72 | XPaymentsConnect.prototype.resize = function(height) 73 | { 74 | var elm = this.getIframeElm(); 75 | if (elm) { 76 | this.previousHeight = elm.style.height; 77 | elm.style.height = height + 'px'; 78 | } 79 | } 80 | 81 | XPaymentsConnect.prototype.load = function() 82 | { 83 | var containerElm = this.getContainerElm(); 84 | if (!containerElm) { 85 | return this; 86 | } 87 | 88 | var elm = document.createElement('iframe'); 89 | elm.id = this.getIframeId(); 90 | elm.style.width = '100%'; 91 | elm.style.height = '0'; 92 | elm.style.overflow = 'hidden'; 93 | elm.setAttribute('scrolling', 'no') 94 | containerElm.appendChild(elm); 95 | 96 | elm.src = this.getRedirectUrl(); 97 | 98 | } 99 | 100 | XPaymentsConnect.prototype.getRedirectUrl = function() 101 | { 102 | return 'https://' + this.getServerHost() + '/' + 103 | '?ref=' + encodeURIComponent(this.config.referrerUrl) + 104 | '&account=' + encodeURIComponent(this.config.account) + 105 | '&apple_pay=' + (this.config.applePayOnly ? 'Y' : 'N') + 106 | '&quickaccess=' + encodeURIComponent(this.config.quickAccessKey); 107 | } 108 | 109 | XPaymentsConnect.prototype.on = function(event, handler) 110 | { 111 | this.handlers[event] = handler.bind(this); 112 | return this; 113 | } 114 | 115 | XPaymentsConnect.prototype.trigger = function(event, params) 116 | { 117 | if ('function' === typeof this.handlers[event]) { 118 | this.handlers[event](params); 119 | } 120 | return this; 121 | } 122 | 123 | XPaymentsConnect.prototype.getServerHost = function() 124 | { 125 | return 'connect.' + this.serverDomain; 126 | } 127 | 128 | XPaymentsConnect.prototype.messageListener = function(event) 129 | { 130 | if (window.JSON) { 131 | var msg = false; 132 | 133 | try { 134 | msg = window.JSON.parse(event.data); 135 | } catch (e) { 136 | // Skip invalid messages 137 | } 138 | 139 | if (msg && msg.event && 0 === msg.event.indexOf(this.messageNamespace)) { 140 | this.log('X-Payments Event: ' + msg.event + "\n" + window.JSON.stringify(msg.params)); 141 | 142 | var eventType = msg.event.substr(this.messageNamespace.length); 143 | 144 | if ('loaded' === eventType) { 145 | if (-1 !== this.previousHeight) { 146 | var topElm = (this.config.topElement) 147 | ? this.safeQuerySelector(this.config.topElement) 148 | : this.getContainerElm(); 149 | if (topElm) { 150 | topElm.scrollIntoView(true); 151 | } 152 | } 153 | this.resize(msg.params.height); 154 | } else if ('resize' === eventType) { 155 | this.resize(msg.params.height); 156 | } else if ('alert' === eventType) { 157 | msg.params.message = msg.params.message.replace(/<\/?[^>]+>/gi, ''); 158 | } 159 | 160 | this.trigger(eventType, msg.params); 161 | } 162 | } 163 | } 164 | 165 | XPaymentsConnect.prototype.postMessage = function(message) 166 | { 167 | var elm = this.getIframeElm(); 168 | if ( 169 | window.postMessage 170 | && window.JSON 171 | && elm 172 | && elm.contentWindow 173 | ) { 174 | this.log('Sent to X-Payments: ' + message.event + "\n" + window.JSON.stringify(message.params)); 175 | elm.contentWindow.postMessage(window.JSON.stringify(message), '*'); 176 | } else { 177 | this.log('Error sending message - iframe wasn\'t initialized!'); 178 | } 179 | } 180 | 181 | XPaymentsConnect.prototype.log = function(msg) { 182 | if (this.config.debug) { 183 | console.log(msg); 184 | } 185 | } -------------------------------------------------------------------------------- /Helper/Address.php: -------------------------------------------------------------------------------- 1 | 17 | * @category CDev 18 | * @package CDev_XPaymentsCloud 19 | * @copyright (c) 2010-present Qualiteam software Ltd . All rights reserved 20 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 21 | */ 22 | 23 | namespace CDev\XPaymentsCloud\Helper; 24 | 25 | /** 26 | * Helper for address 27 | */ 28 | class Address extends \Magento\Framework\App\Helper\AbstractHelper 29 | { 30 | /** 31 | * Placeholder for empty email (something which will pass X-Payments validation) 32 | */ 33 | protected const EMPTY_USER_EMAIL = 'user@example.com'; 34 | 35 | /** 36 | * Placeholder for not available cart data 37 | */ 38 | protected const NOT_AVAILABLE = 'N/A'; 39 | 40 | /** 41 | * Billing and shipping address names 42 | */ 43 | protected const BILLING_ADDRESS = 'Billing'; 44 | protected const SHIPPING_ADDRESS = 'Shipping'; 45 | 46 | /** 47 | * Address Repository 48 | * 49 | * @var \Magento\Customer\Api\AddressRepositoryInterface 50 | */ 51 | protected $addressRepository = null; 52 | 53 | /** 54 | * Region factory 55 | * 56 | * @var \Magento\Directory\Model\RegionFactory 57 | */ 58 | protected $regionFactory = null; 59 | 60 | /** 61 | * Constructor 62 | * 63 | * @param \Magento\Customer\Api\AddressRepositoryInterface $addressRepository 64 | * @param \Magento\Directory\Model\RegionFactory $regionFactory 65 | * 66 | * @return void 67 | */ 68 | public function __construct( 69 | \Magento\Customer\Api\AddressRepositoryInterface $addressRepository, 70 | \Magento\Directory\Model\RegionFactory $regionFactory 71 | ) { 72 | 73 | $this->addressRepository = $addressRepository; 74 | $this->regionFactory = $regionFactory; 75 | } 76 | 77 | /** 78 | * Prepare state 79 | * 80 | * @param array $data Address data 81 | * 82 | * @return string 83 | */ 84 | private function prepareState($data) 85 | { 86 | $state = self::NOT_AVAILABLE; 87 | 88 | if (!empty($data['region_id'])) { 89 | 90 | $region = $this->regionFactory->create()->load($data['region_id']); 91 | 92 | if ( 93 | $region 94 | && $region->getCode() 95 | ) { 96 | $state = $region->getCode(); 97 | } 98 | } 99 | 100 | return $state; 101 | } 102 | 103 | /** 104 | * Prepare street (Address lines 1 and 2) 105 | * 106 | * @param array $data Address data 107 | * 108 | * @return string 109 | */ 110 | private function prepareStreet($data) 111 | { 112 | $street = self::NOT_AVAILABLE; 113 | 114 | if (!empty($data['street'])) { 115 | 116 | $street = $data['street']; 117 | 118 | if (is_array($street)) { 119 | $street = array_filter($street); 120 | $street = implode("\n", $street); 121 | } 122 | } 123 | 124 | return $street; 125 | } 126 | 127 | /** 128 | * Prepare address hash 129 | * 130 | * @param \Magento\Sales\Api\Data\OrderInterface $order Order 131 | * @param string $type Address type, Billing or Shipping 132 | * 133 | * @return array 134 | */ 135 | protected function prepareAddress(\Magento\Sales\Api\Data\OrderInterface $order, $type = self::BILLING_ADDRESS) 136 | { 137 | $method = 'get' . $type . 'Address'; 138 | 139 | $data = $order->$method()->getData(); 140 | 141 | if (!empty($data['email'])) { 142 | $email = $data['email']; 143 | } elseif ($order->getCustomerEmail()) { 144 | $email = $order->getCustomerEmail(); 145 | } else { 146 | $email = self::EMPTY_USER_EMAIL; 147 | } 148 | 149 | $address = array( 150 | 'firstname' => !empty($data['firstname']) ? $data['firstname'] : self::NOT_AVAILABLE, 151 | 'lastname' => !empty($data['lastname']) ? $data['lastname'] : self::NOT_AVAILABLE, 152 | 'address' => $this->prepareStreet($data), 153 | 'city' => !empty($data['city']) ? $data['city'] : self::NOT_AVAILABLE, 154 | 'state' => $this->prepareState($data), 155 | 'country' => !empty($data['country_id']) ? $data['country_id'] : 'XX', // WA fix for MySQL 5.7 with strict mode 156 | 'zipcode' => !empty($data['postcode']) ? $data['postcode'] : self::NOT_AVAILABLE, 157 | 'phone' => !empty($data['telephone']) ? $data['telephone'] : '', 158 | 'company' => '', 159 | 'email' => $email, 160 | ); 161 | 162 | return $address; 163 | } 164 | 165 | /** 166 | * Prepare billing address 167 | * 168 | * @param \Magento\Sales\Api\Data\OrderInterface $order 169 | * 170 | * @return array 171 | */ 172 | public function prepareBillingAddress(\Magento\Sales\Api\Data\OrderInterface $order) 173 | { 174 | return $this->prepareAddress($order, self::BILLING_ADDRESS); 175 | } 176 | 177 | /** 178 | * Prepare shipping address 179 | * 180 | * @param \Magento\Sales\Api\Data\OrderInterface $order 181 | * 182 | * @return array 183 | */ 184 | public function prepareShippingAddress(\Magento\Sales\Api\Data\OrderInterface $order) 185 | { 186 | return $this->prepareAddress($order, self::SHIPPING_ADDRESS); 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /Transport/ConnectSettings.php: -------------------------------------------------------------------------------- 1 | 17 | * @category CDev 18 | * @package CDev_XPaymentsCloud 19 | * @copyright (c) 2010-present Qualiteam software Ltd . All rights reserved 20 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 21 | */ 22 | 23 | namespace CDev\XPaymentsCloud\Transport; 24 | 25 | /** 26 | * Transport for connect settings 27 | */ 28 | class ConnectSettings extends DataObject 29 | { 30 | /** 31 | * Request 32 | * 33 | * @var \Magento\Framework\App\RequestInterface 34 | */ 35 | protected $request = null; 36 | 37 | /** 38 | * Store Manager 39 | * 40 | * @var \Magento\Store\Model\StoreManagerInterface 41 | */ 42 | protected $storeManager = null; 43 | 44 | /** 45 | * Scope Config 46 | * 47 | * @var \Magento\Framework\App\Config\ScopeConfigInterface 48 | */ 49 | protected $scopeConfig = null; 50 | 51 | /** 52 | * Backend URL builder 53 | * 54 | * @var \Magento\Backend\Model\UrlInterface 55 | */ 56 | protected $backendUrl = null; 57 | 58 | /** 59 | * PayPal Structure Plugin 60 | * 61 | * @var \Magento\Paypal\Model\Config\StructurePlugin 62 | */ 63 | protected $paypalStructure = null; 64 | 65 | /** 66 | * Section ID 67 | * 68 | * @var string 69 | */ 70 | protected $sectionId = null; 71 | 72 | /** 73 | * Constructor 74 | * 75 | * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig 76 | * @param \Magento\Framework\App\RequestInterface $request 77 | * @param \Magento\Store\Model\StoreManagerInterface $storeManager 78 | * @param \Magento\Backend\Model\UrlInterface $backendUrl 79 | * @param \Magento\Paypal\Model\Config\StructurePlugin $paypalStructure 80 | * 81 | * @return \Magento\Framework\DataObject 82 | */ 83 | public function __construct( 84 | \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, 85 | \Magento\Framework\App\RequestInterface $request, 86 | \Magento\Store\Model\StoreManagerInterface $storeManager, 87 | \Magento\Backend\Model\UrlInterface $backendUrl, 88 | \Magento\Paypal\Model\Config\StructurePlugin $paypalStructure 89 | ) { 90 | $this->request = $request; 91 | $this->storeManager = $storeManager; 92 | $this->backendUrl = $backendUrl; 93 | $this->scopeConfig = $scopeConfig; 94 | $this->paypalStructure = $paypalStructure; 95 | 96 | $data = array( 97 | 'account' => $scopeConfig->getValue('payment/xpayments_cloud/account'), 98 | 'quickAccessKey' => $scopeConfig->getValue('payment/xpayments_cloud/quick_access_key'), 99 | 'devUrl' => (string)$scopeConfig->getValue('payment/xpayments_cloud/dev_url'), 100 | 'topElement' => '', 101 | 'container' => '#xpayments-iframe-container', 102 | 'sectionId' => $this->getSectionId(), 103 | 'loaded' => false, 104 | 'referrerUrl' => $this->storeManager->getStore()->getBaseUrl(), 105 | 'saveUrl' => $this->getSaveUrl(), 106 | 'configMap' => $this->getConfigMap(), 107 | 'debug' => (bool)$scopeConfig->getValue('payment/xpayments_cloud/debug'), 108 | ); 109 | 110 | return $this->setData($data); 111 | } 112 | 113 | /** 114 | * Get map of the configuration fields: { 115 | * field: payment_us_xpayments_cloud_connection_some_option 116 | * param: someOption 117 | * } 118 | * 119 | * @return array 120 | */ 121 | protected function getConfigMap() 122 | { 123 | $fields = array( 124 | 'account', 125 | 'api_key', 126 | 'secret_key', 127 | 'widget_key', 128 | 'quick_access_key', 129 | ); 130 | 131 | $map = array(); 132 | 133 | foreach ($fields as $field) { 134 | 135 | $map[] = array( 136 | 'field' => $this->getSectionId() . '_connection_' . $field, 137 | 'param' => lcfirst($this->ucWords($field, '')), 138 | ); 139 | } 140 | 141 | return $map; 142 | } 143 | 144 | /** 145 | * Get X-Payments Config save URL 146 | * 147 | * @return string 148 | */ 149 | protected function getSaveUrl() 150 | { 151 | $params = array( 152 | 'section' => 'payment', 153 | ); 154 | 155 | if ($this->request->getParam('website')) { 156 | $params['website'] = $this->request->getParam('website'); 157 | } 158 | 159 | if ($this->request->getParam('store')) { 160 | $params['store'] = $this->request->getParam('store'); 161 | } 162 | 163 | return $this->backendUrl->getUrl('xpayments_cloud/system_config/save', $params); 164 | } 165 | 166 | /** 167 | * Get ID of section 168 | * 169 | * @return string 170 | */ 171 | protected function getSectionId() 172 | { 173 | if (null !== $this->sectionId) { 174 | return $this->sectionId; 175 | } 176 | 177 | if ($this->request->getParam('paypal_country')) { 178 | $merchantCountry = $this->request->getParam('paypal_country'); 179 | } elseif ($this->scopeConfig->getValue('paypal/general/merchant_country')) { 180 | $merchantCountry = $this->scopeConfig->getValue('paypal/general/merchant_country'); 181 | } elseif ($this->scopeConfig->getValue('general/country/default')) { 182 | $merchantCountry = $this->scopeConfig->getValue('general/country/default'); 183 | } else { 184 | $merchantCountry = 'US'; 185 | } 186 | 187 | $merchantCountry = 'payment_' . strtolower($merchantCountry); 188 | 189 | $paypalCountries = $this->paypalStructure->getPaypalConfigCountries(); 190 | 191 | if (!in_array($merchantCountry, $paypalCountries)) { 192 | $merchantCountry = 'payment_other'; 193 | } 194 | 195 | $this->sectionId = $merchantCountry . '_xpayments_cloud'; 196 | 197 | return $this->sectionId; 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /Helper/Cart.php: -------------------------------------------------------------------------------- 1 | 17 | * @category CDev 18 | * @package CDev_XPaymentsCloud 19 | * @copyright (c) 2010-present Qualiteam software Ltd . All rights reserved 20 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 21 | */ 22 | 23 | namespace CDev\XPaymentsCloud\Helper; 24 | 25 | /** 26 | * Helper for cart 27 | */ 28 | class Cart extends \Magento\Framework\App\Helper\AbstractHelper 29 | { 30 | /** 31 | * Default string length 32 | */ 33 | protected const DEFAULT_STRING_LENGTH = 255; 34 | 35 | /** 36 | * Store information 37 | * 38 | * @var \Magento\Store\Model\Information 39 | */ 40 | private $storeInfo = null; 41 | 42 | /** 43 | * Store manager 44 | * 45 | * @var \Magento\Store\Model\StoreManagerInterface 46 | */ 47 | private $storeManager = null; 48 | 49 | /** 50 | * Scope config 51 | * 52 | * @var \Magento\Framework\App\Config\ScopeConfigInterface 53 | */ 54 | protected $scopeConfig = null; 55 | 56 | /** 57 | * Helper for address 58 | * 59 | * @var \CDev\XPaymentsCloud\Helper\Address 60 | */ 61 | protected $addressHelper = null; 62 | 63 | /** 64 | * Constructor 65 | * 66 | * @param \Magento\Store\Model\Information $storeInfo 67 | * @param \Magento\Store\Model\StoreManagerInterface $storeManager 68 | * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig 69 | * @param \CDev\XPaymentsCloud\Helper\Address $addressHelper 70 | * 71 | * @return void 72 | */ 73 | public function __construct( 74 | \Magento\Store\Model\Information $storeInfo, 75 | \Magento\Store\Model\StoreManagerInterface $storeManager, 76 | \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, 77 | \CDev\XPaymentsCloud\Helper\Address $addressHelper 78 | ) { 79 | $this->storeInfo = $storeInfo; 80 | $this->storeManager = $storeManager; 81 | $this->scopeConfig = $scopeConfig; 82 | 83 | $this->addressHelper = $addressHelper; 84 | } 85 | 86 | /** 87 | * Format price in 1234.56 format 88 | * 89 | * @param mixed $price 90 | * 91 | * @return string 92 | */ 93 | public function preparePrice($price) 94 | { 95 | return number_format($price, 2, '.', ''); 96 | } 97 | 98 | /** 99 | * Convert passed value to a string of limited length 100 | * 101 | * @param mixed $value 102 | * @param int $length 103 | * 104 | * @return string 105 | */ 106 | protected function prepareString($value, $length = self::DEFAULT_STRING_LENGTH) 107 | { 108 | return substr((string)$value, 0, $length); 109 | } 110 | 111 | /** 112 | * Check if quantity is positive integer 113 | * 114 | * @param int|float|string $quantity Quantity 115 | * 116 | * @return bool 117 | */ 118 | protected function isNaturalNumber($quantity) 119 | { 120 | return (int)$quantity == $quantity 121 | && (int)$quantity > 0; 122 | } 123 | 124 | /** 125 | * Prepare items from quote for initial payment request 126 | * 127 | * @param \Magento\Sales\Api\Data\OrderInterface $order 128 | * 129 | * @return array 130 | */ 131 | protected function prepareItems(\Magento\Sales\Api\Data\OrderInterface $order) 132 | { 133 | $items = array(); 134 | 135 | foreach ($order->getAllVisibleItems() as $item) { 136 | 137 | if (\Magento\ConfigurableProduct\Model\Product\Type\Configurable::TYPE_CODE == $item->getProductType()) { 138 | continue; 139 | } 140 | 141 | $name = $item->getName(); 142 | $sku = $item->getSku(); 143 | $quantity = $item->getQtyOrdered(); 144 | 145 | if ($item->getParentItem()) { 146 | $currentItem = $item->getParentItem(); 147 | } else { 148 | $currentItem = $item; 149 | } 150 | 151 | $quantity = $item->getQtyOrdered(); 152 | 153 | if ($this->isNaturalNumber($quantity)) { 154 | 155 | $price = $currentItem->getPrice(); 156 | $quantity = (int)$quantity; 157 | 158 | } else { 159 | 160 | $name = sprintf('%s (x%s)', $name, round($quantity, 2)); 161 | $quantity = 1; 162 | $price = $currentItem->getBaseRowTotal(); 163 | } 164 | 165 | $items[] = array( 166 | 'quantity' => $quantity, 167 | 'name' => $this->prepareString($name), 168 | 'sku' => $this->prepareString($sku), 169 | 'price' => $this->preparePrice($price), 170 | ); 171 | } 172 | 173 | return $items; 174 | } 175 | 176 | /** 177 | * Prepare cart for initial payment request 178 | * 179 | * @param \Magento\Sales\Api\Data\OrderInterface $order 180 | * 181 | * @return array 182 | */ 183 | public function prepareCart(\Magento\Sales\Api\Data\OrderInterface $order) 184 | { 185 | $description = 'Order #' . $order->getIncrementId(); 186 | 187 | $billingAddress = $this->addressHelper->prepareBillingAddress($order); 188 | 189 | if ($order->getShippingAddress()) { 190 | $shippingAddress = $this->addressHelper->prepareShippingAddress($order); 191 | } else { 192 | // For downloadable products 193 | $shippingAddress = $billingAddress; 194 | } 195 | 196 | $cart = array( 197 | 'login' => $order->getCustomerEmail(), 198 | 'billingAddress' => $billingAddress, 199 | 'shippingAddress' => $shippingAddress, 200 | 'items' => $this->prepareItems($order), 201 | 'currency' => $order->getBaseCurrencyCode(), 202 | 'shippingCost' => $this->preparePrice($order->getShippingAmount()), 203 | 'taxCost' => $this->preparePrice($order->getTaxAmount()), 204 | 'discount' => $this->preparePrice($order->getDiscountAmount()), 205 | 'totalCost' => $this->preparePrice($order->getGrandTotal()), 206 | 'description' => $description, 207 | 'merchantEmail' => $this->scopeConfig->getValue('trans_email/ident_sales/email'), 208 | ); 209 | 210 | return $cart; 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /view/frontend/web/js/base.js: -------------------------------------------------------------------------------- 1 | // vim: set ts=2 sw=2 sts=2 et: 2 | /** 3 | * Magento 4 | * 5 | * NOTICE OF LICENSE 6 | * 7 | * This source file is subject to the Open Software License (OSL 3.0) 8 | * that is bundled with this package in the file LICENSE.txt. 9 | * It is also available through the world-wide-web at this URL: 10 | * http://opensource.org/licenses/osl-3.0.php 11 | * If you did not receive a copy of the license and are unable to 12 | * obtain it through the world-wide-web, please send an email 13 | * to license@magentocommerce.com so we can send you a copy immediately. 14 | * 15 | * @author Qualiteam Software 16 | * @category Cdev 17 | * @package Cdev_XPaymentsCloud 18 | * @copyright (c) 2010-present Qualiteam software Ltd . All rights reserved 19 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 20 | */ 21 | 22 | window.XPaymentsLoader = Class.create(); 23 | 24 | window.XPaymentsLoader.prototype = { 25 | 26 | /** 27 | * ID of the loader element 28 | */ 29 | elementId: 'xpayments-loader', 30 | 31 | /** 32 | * Constructor. Create loader element 33 | */ 34 | initialize: function (container, elementId) { 35 | 36 | if ('undefined' != typeof elementId) { 37 | this.elementId = elementId; 38 | } 39 | 40 | if ($(this.elementId)) { 41 | return this; 42 | } 43 | 44 | container = document.querySelector(container); 45 | 46 | if (container) { 47 | 48 | var loaderIcon = document.createElement('div'); 49 | loaderIcon.id = 'xpayments-loader-icon'; 50 | 51 | var loader = document.createElement('div'); 52 | loader.id = 'xpayments-loader'; 53 | loader.appendChild(loaderIcon); 54 | 55 | container.appendChild(loader); 56 | } 57 | 58 | return this; 59 | }, 60 | 61 | /** 62 | * Show loader 63 | */ 64 | show: function () { 65 | 66 | if ($(this.elementId)) { 67 | $(this.elementId).show(); 68 | } 69 | 70 | return this; 71 | }, 72 | 73 | /** 74 | * Hide loader 75 | */ 76 | hide: function () { 77 | 78 | if ($(this.elementId)) { 79 | $(this.elementId).hide(); 80 | } 81 | 82 | return this; 83 | } 84 | }; 85 | 86 | /** 87 | * Initialize X-Payments widget 88 | */ 89 | window.XPaymentsWidget.prototype.init = XPaymentsWidget.prototype.init.wrap( 90 | function(parentMethod, settings) { 91 | 92 | Object.extend( 93 | this.config, 94 | { 95 | devUrl: '', 96 | } 97 | ); 98 | 99 | parentMethod(settings); 100 | 101 | return this; 102 | } 103 | ); 104 | 105 | /** 106 | * Redefine server URL (if necessary) 107 | */ 108 | window.XPaymentsWidget.prototype.getServerUrl = XPaymentsWidget.prototype.getServerUrl.wrap( 109 | function (parentMethod) { 110 | 111 | var devUrl = this.config.devUrl; 112 | 113 | if (devUrl) { 114 | 115 | if ('/' === devUrl.substr(-1)) { 116 | devUrl = devUrl.substr(0, devUrl.length - 1); 117 | } 118 | 119 | var url = devUrl; 120 | 121 | } else { 122 | 123 | var url = parentMethod(); 124 | } 125 | 126 | return url; 127 | } 128 | ); 129 | 130 | window.XPayments = Class.create(); 131 | 132 | window.XPayments.prototype = { 133 | 134 | /** 135 | * Original submit payment form function 136 | */ 137 | origSubmitPayment: function () { 138 | return false; 139 | }, 140 | 141 | /** 142 | * Check if X-Payments Cloud is currently used payment method 143 | */ 144 | isCurrent: function () { 145 | return false; 146 | }, 147 | 148 | /** 149 | * Toggle Apple Pay button 150 | */ 151 | toggleApplePayButton: function (isApple) { 152 | return false; 153 | }, 154 | 155 | /** 156 | * Constructor 157 | */ 158 | initialize: function (settings) { 159 | 160 | this.settings = settings; 161 | 162 | this.loader = new XPaymentsLoader(this.settings.container); 163 | this.getWidget(); 164 | }, 165 | 166 | /** 167 | * Initialize widget 168 | */ 169 | getWidget: function () { 170 | 171 | try { 172 | 173 | if (!window._widgetInstance) { 174 | 175 | window._widgetInstance = new XPaymentsWidget(); 176 | window._widgetInstance.init(this.settings); 177 | 178 | window._widgetInstance.on( 179 | 'success', 180 | (function (params) { this.onSuccess(params); }).bind(this) 181 | ); 182 | 183 | window._widgetInstance.on( 184 | 'fail', 185 | (function () { this.onFail(); }).bind(this) 186 | ); 187 | 188 | window._widgetInstance.on( 189 | 'loaded', 190 | (function () { this.onLoaded(); }).bind(this) 191 | ); 192 | 193 | window._widgetInstance.on( 194 | 'paymentmethod.change', 195 | (function (params) { this.toggleApplePayButton('apple_pay' === params.newId); }).bind(this) 196 | ); 197 | } 198 | 199 | } catch (error) { 200 | 201 | console.error(error); 202 | } 203 | 204 | return window._widgetInstance; 205 | }, 206 | 207 | /** 208 | * Get input for X-Payments token 209 | */ 210 | getTokenInput: function () { 211 | 212 | var input = $(this.settings.tokenInputId); 213 | 214 | if (!input) { 215 | input = document.createElement('input'); 216 | input.type = 'hidden'; 217 | input.name = this.settings.tokenInputName; 218 | input.id = this.settings.tokenInputId; 219 | 220 | this.getWidget().getFormElm().appendChild(input); 221 | } 222 | 223 | return input; 224 | }, 225 | 226 | /** 227 | * Load X-Payments Cloud widget 228 | */ 229 | load: function () { 230 | this.loader.show(); 231 | this.getWidget().load(); 232 | }, 233 | 234 | /** 235 | * Process widget loaded event 236 | */ 237 | onLoaded: function () { 238 | this.loader.hide(); 239 | }, 240 | 241 | /** 242 | * Switch payment method event 243 | */ 244 | onSwitchPaymentMethod: function () { 245 | if (this.isCurrent()) { 246 | this.load(); 247 | } else { 248 | this.getWidget().resize(0); 249 | } 250 | }, 251 | 252 | /** 253 | * Submit payment form event 254 | */ 255 | onSubmitPayment: function (origSubmitPayment) { 256 | 257 | if ('function' == typeof origSubmitPayment) { 258 | this.origSubmitPayment = origSubmitPayment; 259 | } 260 | 261 | if (this.isCurrent()) { 262 | this.loader.show(); 263 | this.getWidget().submit(); 264 | } else { 265 | this.origSubmitPayment(); 266 | } 267 | }, 268 | 269 | /** 270 | * Successfully tokenized payment event 271 | */ 272 | onSuccess: function (params) { 273 | 274 | var formElm = this.getWidget().getFormElm(); 275 | 276 | if (formElm) { 277 | 278 | var inputElm = this.getTokenInput(); 279 | 280 | inputElm.value = params.token; 281 | 282 | if (this.settings.autoSubmit) { 283 | formElm.submit(); 284 | } else { 285 | this.origSubmitPayment(); 286 | } 287 | } 288 | }, 289 | 290 | /** 291 | * Something went wronng 292 | */ 293 | onFail: function (params) { 294 | this.loader.hide(); 295 | } 296 | }; 297 | -------------------------------------------------------------------------------- /etc/adminhtml/system.xml: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 | 32 | 33 | 1 34 | Magento\Config\Block\System\Config\Form\Fieldset 35 | 36 | 37 | payment/xpayments_cloud/account 38 | 39 | 1 40 | 41 | 42 | 43 | 44 | payment/xpayments_cloud/api_key 45 | 46 | 1 47 | 48 | 49 | 50 | 51 | payment/xpayments_cloud/secret_key 52 | 53 | 1 54 | 55 | 56 | 57 | 58 | payment/xpayments_cloud/widget_key 59 | 60 | 1 61 | 62 | 63 | 64 | 65 | payment/xpayments_cloud/quick_access_key 66 | 67 | 1 68 | 69 | 70 | 71 | 72 | 73 | CDev\XPaymentsCloud\Block\System\Config\CloudIframe 74 | 75 | 76 | 77 | 78 | 79 | 80 | 1 81 | Magento\Config\Block\System\Config\Form\Fieldset 82 | 83 | 84 | Magento\Config\Model\Config\Source\Yesno 85 | payment/xpayments_cloud/active 86 | 87 | 88 | 89 | payment/xpayments_cloud/title 90 | 91 | 92 | 93 | payment/xpayments_cloud/sort_order 94 | validate-number 95 | 96 | 97 | 98 | 99 | 100 | 0 101 | Magento\Config\Block\System\Config\Form\Fieldset 102 | 103 | 104 | payment/xpayments_cloud/min_order_total 105 | validate-number validate-zero-or-greater 106 | 107 | 108 | 109 | payment/xpayments_cloud/max_order_total 110 | validate-number validate-zero-or-greater 111 | 112 | 113 | 114 | Magento\Payment\Model\Config\Source\Allspecificcountries 115 | payment/xpayments_cloud/allowspecific 116 | 117 | 118 | 119 | Magento\Directory\Model\Config\Source\Country 120 | payment/xpayments_cloud/specificcountry 121 | 122 | 123 | 124 | 125 | 126 | 0 127 | Magento\Config\Block\System\Config\Form\Fieldset 128 | 129 | 130 | Magento\Config\Model\Config\Source\Yesno 131 | payment/xpayments_cloud/debug 132 | 133 | 134 | 135 | 136 |
137 |
138 |
139 | -------------------------------------------------------------------------------- /Model/Payment/Method/XPaymentsCloud.php: -------------------------------------------------------------------------------- 1 | 17 | * @category CDev 18 | * @package CDev_XPaymentsCloud 19 | * @copyright (c) 2010-present Qualiteam software Ltd . All rights reserved 20 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 21 | */ 22 | 23 | namespace CDev\XPaymentsCloud\Model\Payment\Method; 24 | 25 | /** 26 | * X-Payments Cloud payment method 27 | */ 28 | class XPaymentsCloud extends \Magento\Payment\Model\Method\AbstractMethod 29 | { 30 | /** 31 | * Payment method code 32 | */ 33 | public const CODE = 'xpayments_cloud'; 34 | 35 | /** 36 | * Payment method code 37 | * 38 | * @var string 39 | */ 40 | protected $_code = self::CODE; 41 | 42 | /** 43 | * Payment Info block 44 | * 45 | * @var string 46 | */ 47 | protected $_infoBlockType = \CDev\XPaymentsCloud\Block\Payment\Info::class; 48 | 49 | /** 50 | * Payment method flags 51 | * 52 | * @var bool 53 | */ 54 | protected $_isGateway = false; 55 | 56 | protected $_canUseCheckout = true; 57 | protected $_canUseInternal = false; 58 | protected $_canUseForMultishipping = false; 59 | 60 | protected $_canCapture = true; 61 | protected $_canCapturePartial = true; 62 | 63 | protected $_canRefund = true; 64 | protected $_canRefundInvoicePartial = true; 65 | 66 | protected $_canVoid = true; 67 | 68 | protected $_canReviewPayment = true; 69 | 70 | /** 71 | * Customer repository 72 | * 73 | * @var \Magento\Customer\Api\CustomerRepositoryInterface 74 | */ 75 | protected $customerRepository = null; 76 | 77 | /** 78 | * Customer model 79 | * 80 | * @var \Magento\Sales\Api\Data\CustomerInterface 81 | */ 82 | protected $customer = null; 83 | 84 | /** 85 | * URL builder 86 | * 87 | * @var \Magento\Framework\UrlInterface 88 | */ 89 | protected $urlBuilder = null; 90 | 91 | /** 92 | * Cart helper 93 | * 94 | * @var \CDev\XPaymentsCloud\Helper\Cart 95 | */ 96 | protected $cartHelper = null; 97 | 98 | /** 99 | * SDK Client helper 100 | * 101 | * @var \CDev\XPaymentsCloud\Helper\Client 102 | */ 103 | protected $clientHelper = null; 104 | 105 | /** 106 | * Logger 107 | * 108 | * @var \CDev\XPaymentsCloud\Logger\Logger 109 | */ 110 | protected $xpaymentsLogger = null; 111 | 112 | /** 113 | * Constructor 114 | * 115 | * @param \Magento\Framework\Model\Context $context 116 | * @param \Magento\Framework\Registry $registry 117 | * @param \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory 118 | * @param \Magento\Framework\Api\AttributeValueFactory $customAttributeFactory 119 | * @param \Magento\Payment\Helper\Data $paymentData 120 | * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig 121 | * @param \Magento\Payment\Model\Method\Logger $logger 122 | * @param \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository 123 | * @param \Magento\Framework\UrlInterface $urlBuilder 124 | * @param \CDev\XPaymentsCloud\Helper\Cart $cartHelper 125 | * @param \CDev\XPaymentsCloud\Helper\Client $clientHelper 126 | * @param \CDev\XPaymentsCloud\Logger\Logger $xpaymentsLogger 127 | * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource 128 | * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection 129 | * @param array $data 130 | * @param \Magento\Directory\Helper\Data $directory 131 | * 132 | * @SuppressWarnings(PHPMD.ExcessiveParameterList) 133 | */ 134 | public function __construct( 135 | \Magento\Framework\Model\Context $context, 136 | \Magento\Framework\Registry $registry, 137 | \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory, 138 | \Magento\Framework\Api\AttributeValueFactory $customAttributeFactory, 139 | \Magento\Payment\Helper\Data $paymentData, 140 | \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, 141 | \Magento\Payment\Model\Method\Logger $logger, 142 | \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository, 143 | \Magento\Framework\UrlInterface $urlBuilder, 144 | \CDev\XPaymentsCloud\Helper\Cart $cartHelper, 145 | \CDev\XPaymentsCloud\Helper\Client $clientHelper, 146 | \CDev\XPaymentsCloud\Logger\Logger $xpaymentsLogger, 147 | \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null, 148 | \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null, 149 | array $data = [], 150 | \Magento\Directory\Helper\Data $directory = null 151 | ) { 152 | 153 | parent::__construct( 154 | $context, 155 | $registry, 156 | $extensionFactory, 157 | $customAttributeFactory, 158 | $paymentData, 159 | $scopeConfig, 160 | $logger, 161 | $resource, 162 | $resourceCollection, 163 | $data, 164 | $directory 165 | ); 166 | 167 | $this->customerRepository = $customerRepository; 168 | 169 | $this->urlBuilder = $urlBuilder; 170 | 171 | $this->cartHelper = $cartHelper; 172 | $this->clientHelper = $clientHelper; 173 | 174 | $this->xpaymentsLogger = $xpaymentsLogger; 175 | } 176 | 177 | /** 178 | * Get xpid from parent transaction 179 | * 180 | * @param \Magento\Payment\Model\InfoInterface $payment 181 | * 182 | * @return string 183 | */ 184 | protected function getParentXpid(\Magento\Payment\Model\InfoInterface $payment) 185 | { 186 | return substr($payment->getParentTransactionId(), 0, 32); 187 | } 188 | 189 | /** 190 | * Get xpid from last transaction 191 | * 192 | * @param \Magento\Payment\Model\InfoInterface $payment 193 | * 194 | * @return string 195 | */ 196 | protected function getLastXpid(\Magento\Payment\Model\InfoInterface $payment) 197 | { 198 | return substr($payment->getLastTransId(), 0, 32); 199 | } 200 | 201 | /** 202 | * Get customer 203 | * 204 | * @param \Magento\Payment\Model\InfoInterface $payment 205 | * 206 | * @return \Magento\Sales\Api\Data\CustomerInterface 207 | */ 208 | protected function getCustomer(\Magento\Payment\Model\InfoInterface $payment) 209 | { 210 | if ( 211 | null === $this->customer 212 | && $payment->getOrder()->getCustomerId() 213 | ) { 214 | $this->customer = $this->customerRepository 215 | ->getById($payment->getOrder()->getCustomerId()); 216 | } 217 | 218 | return $this->customer; 219 | } 220 | 221 | /** 222 | * Get X-Payments customer ID 223 | * 224 | * @param \Magento\Payment\Model\InfoInterface $payment 225 | * 226 | * @return string 227 | */ 228 | protected function getXpaymentsCustomerId(\Magento\Payment\Model\InfoInterface $payment) 229 | { 230 | $xpaymentsCustomerId = ''; 231 | 232 | if ($this->getcustomer($payment)) { 233 | 234 | $attribute = $this->getCustomer($payment) 235 | ->getCustomAttribute('xpayments_customer_id'); 236 | 237 | if ($attribute) { 238 | $xpaymentsCustomerId = $attribute->getValue(); 239 | } 240 | } 241 | 242 | return $xpaymentsCustomerId; 243 | } 244 | 245 | /** 246 | * Set X-Payments customer ID 247 | * 248 | * @param \Magento\Payment\Model\InfoInterface $payment 249 | * @param string $xpaymentsCustomerId 250 | * 251 | * @return void 252 | */ 253 | protected function setXpaymentsCustomerId(\Magento\Payment\Model\InfoInterface $payment, $xpaymentsCustomerId) 254 | { 255 | if ($this->getcustomer($payment)) { 256 | 257 | $payment->setXpaymentsCustomerId($xpaymentsCustomerId); 258 | 259 | // TODO: Rework via fieldsets 260 | $this->getCustomer($payment) 261 | ->setCustomAttribute('xpayments_customer_id', $xpaymentsCustomerId); 262 | 263 | $this->customerRepository->save($this->getCustomer($payment)); 264 | } 265 | 266 | return $xpaymentsCustomerId; 267 | } 268 | 269 | /** 270 | * Compose URL for action 271 | * 272 | * @param string $action 273 | * 274 | * @return string 275 | */ 276 | protected function composeUrl($action) 277 | { 278 | return $this->urlBuilder->getUrl('xpayments_cloud/processing/' . $action); 279 | } 280 | 281 | /** 282 | * Authorize payment 283 | * 284 | * @param \Magento\Payment\Model\InfoInterface $payment 285 | * @param float $amount 286 | * 287 | * @throws \Magento\Framework\Exception\LocalizedException 288 | * 289 | * @return $this 290 | */ 291 | public function authorize(\Magento\Payment\Model\InfoInterface $payment, $amount) 292 | { 293 | try { 294 | 295 | $cart = $this->cartHelper 296 | ->prepareCart($payment->getOrder()); 297 | 298 | $refId = $payment->getOrder()->getIncrementId(); 299 | 300 | $token = $payment->getAdditionalInformation()['xpayments_token']; 301 | 302 | $response = $this->clientHelper 303 | ->getClient() 304 | ->doPay( 305 | $token, 306 | $refId, 307 | $this->getXpaymentsCustomerId($payment), 308 | $cart, 309 | $this->composeUrl('return'), 310 | $this->composeUrl('callback') 311 | ); 312 | 313 | $this->processResponse($response, $payment); 314 | 315 | } catch (\Exception $exception) { 316 | 317 | $message = $this->xpaymentsLogger->processException($exception); 318 | 319 | throw new \Magento\Framework\Exception\LocalizedException(__($message)); 320 | } 321 | 322 | return $this; 323 | } 324 | 325 | /** 326 | * Capture specified amount for payment 327 | * 328 | * @param \Magento\Payment\Model\InfoInterface $payment 329 | * @param float $amount 330 | * 331 | * @throws \Magento\Framework\Exception\LocalizedException 332 | * 333 | * @return $this 334 | */ 335 | public function capture(\Magento\Payment\Model\InfoInterface $payment, $amount) 336 | { 337 | try { 338 | 339 | $response = $this->clientHelper 340 | ->getClient() 341 | ->doCapture( 342 | $this->getParentXpid($payment), 343 | $amount 344 | ); 345 | 346 | $this->processResponse($response, $payment); 347 | 348 | } catch (\Exception $exception) { 349 | 350 | $message = $this->xpaymentsLogger->processException($exception); 351 | 352 | throw new \Magento\Framework\Exception\LocalizedException(__($message)); 353 | } 354 | 355 | return $this; 356 | } 357 | 358 | /** 359 | * Refund specified amount for payment 360 | * 361 | * @param \Magento\Payment\Model\InfoInterface $payment 362 | * @param float $amount 363 | * 364 | * @throws \Magento\Framework\Exception\LocalizedException 365 | * 366 | * @return $this 367 | */ 368 | public function refund(\Magento\Payment\Model\InfoInterface $payment, $amount) 369 | { 370 | try { 371 | 372 | $response = $this->clientHelper 373 | ->getClient() 374 | ->doRefund( 375 | $this->getParentXpid($payment), 376 | $amount 377 | ); 378 | 379 | $this->processResponse($response, $payment); 380 | 381 | } catch (\Exception $exception) { 382 | 383 | $message = $this->xpaymentsLogger->processException($exception); 384 | 385 | throw new \Magento\Framework\Exception\LocalizedException(__($message)); 386 | } 387 | 388 | return $this; 389 | } 390 | 391 | /** 392 | * Void payment 393 | * 394 | * @param \Magento\Payment\Model\InfoInterface $payment 395 | * 396 | * @throws \Magento\Framework\Exception\LocalizedException 397 | * 398 | * @return $this 399 | */ 400 | public function void(\Magento\Payment\Model\InfoInterface $payment) 401 | { 402 | try { 403 | 404 | $response = $this->clientHelper 405 | ->getClient() 406 | ->doVoid($this->getParentXpid($payment)); 407 | 408 | $this->processResponse($response, $payment); 409 | 410 | } catch (\Exception $exception) { 411 | 412 | $message = $this->xpaymentsLogger->processException($exception); 413 | 414 | throw new \Magento\Framework\Exception\LocalizedException(__($message)); 415 | } 416 | 417 | return $this; 418 | } 419 | 420 | /** 421 | * Cancel payment 422 | * 423 | * @param \Magento\Payment\Model\InfoInterface $payment 424 | * 425 | * @throws \Magento\Framework\Exception\LocalizedException 426 | * 427 | * @return $this 428 | */ 429 | public function cancel(\Magento\Payment\Model\InfoInterface $payment) 430 | { 431 | return $this->void($payment); 432 | } 433 | 434 | /** 435 | * Accept payment 436 | * 437 | * @param \Magento\Payment\Model\InfoInterface $payment 438 | * 439 | * @throws \Magento\Framework\Exception\LocalizedException 440 | * 441 | * @return bool 442 | */ 443 | public function acceptPayment(\Magento\Payment\Model\InfoInterface $payment) 444 | { 445 | try { 446 | 447 | $xpid = $this->getLastXpid($payment); 448 | 449 | $response = $this->clientHelper 450 | ->getClient() 451 | ->doAccept($xpid); 452 | 453 | $result = (bool)$response->result; 454 | 455 | } catch (\Exception $exception) { 456 | 457 | $message = $this->xpaymentsLogger->processException($exception); 458 | 459 | throw new \Magento\Framework\Exception\LocalizedException(__($message)); 460 | } 461 | 462 | return $result; 463 | } 464 | 465 | /** 466 | * Decline payment 467 | * 468 | * @param \Magento\Payment\Model\InfoInterface $payment 469 | * 470 | * @throws \Magento\Framework\Exception\LocalizedException 471 | * 472 | * @return bool 473 | */ 474 | public function denyPayment(\Magento\Payment\Model\InfoInterface $payment) 475 | { 476 | try { 477 | 478 | $xpid = $this->getLastXpid($payment); 479 | 480 | $response = $this->clientHelper 481 | ->getClient() 482 | ->doDecline($xpid); 483 | 484 | $result = (bool)$response->result; 485 | 486 | } catch (\Exception $exception) { 487 | 488 | $message = $this->xpaymentsLogger->processException($exception); 489 | 490 | throw new \Magento\Framework\Exception\LocalizedException(__($message)); 491 | } 492 | 493 | return $result; 494 | } 495 | 496 | /** 497 | * Process X-Payments Cloud payment response 498 | * 499 | * @param \XPaymentsCloud\Response $response 500 | * @param \Magento\Payment\Model\InfoInterface $payment 501 | * 502 | * @return \Cdev\XPaymentsCloud\Model\Payment\Cloud 503 | */ 504 | protected function processResponse( 505 | \XPaymentsCloud\Response $response, 506 | \Magento\Payment\Model\InfoInterface $payment 507 | ) { 508 | if (!$response->isLastTransactionSuccessful()) { 509 | throw new \Magento\Framework\Exception\LocalizedException(__($response->message)); 510 | } 511 | 512 | $info = $response->getPayment(); 513 | 514 | // Compose transaction ID preventing duplicates 515 | $transactionId = sprintf('%s-%s', $info->xpid, $info->lastTransaction->action); 516 | 517 | // Set some basic information about the payment 518 | $payment->setStatus(self::STATUS_APPROVED) 519 | ->setCcTransId($info->lastTransaction->txnId) 520 | ->setLastTransId($info->lastTransaction->txnId) 521 | ->setTransactionId($transactionId) 522 | ->setIsTransactionClosed(false) 523 | ->setAmount($info->amount) 524 | ->setShouldCloseParentTransaction(false); 525 | 526 | // Set information about the card 527 | $payment->setCcLast4($info->card->last4) 528 | ->setCcFirst6($info->card->first6) 529 | ->setCcType($info->card->type) 530 | ->setCcExpMonth($info->card->expireMonth) 531 | ->setCcExpYear($info->card->expireYear) 532 | ->setCcOwner($info->card->cardholderName); 533 | 534 | // Set transaction details 535 | if (!empty($info->details)) { 536 | 537 | $details = array_filter( 538 | get_object_vars($info->details) 539 | ); 540 | 541 | $payment->setTransactionAdditionalInfo( 542 | \Magento\Sales\Model\Order\Payment\Transaction::RAW_DETAILS, 543 | $details 544 | ); 545 | } 546 | 547 | // Set fraudulent flag 548 | $payment->setIsTransactionPending( 549 | (bool)$info->isFraudulent 550 | ); 551 | 552 | // Set X-Payments Cloud customerId 553 | $this->setXpaymentsCustomerId($payment, $info->customerId); 554 | 555 | return $this; 556 | } 557 | } 558 | -------------------------------------------------------------------------------- /view/frontend/web/js/lib/widget.js: -------------------------------------------------------------------------------- 1 | /* 2 | * X-Payments Cloud SDK - Payment Widget 3 | */ 4 | 5 | window.XPaymentsWidget = function() 6 | { 7 | this.serverDomain = 'xpayments.com'; 8 | this.messageNamespace = 'xpayments.widget.'; 9 | this.receiverNamespace = 'xpayments.checkout.'; 10 | this.widgetId = this.generateId(); 11 | this.previousHeight = -1; 12 | this.applePay = { 13 | session: null, 14 | supportedNetworks: [], 15 | merchantCapabilities: [], 16 | merchantId: '', 17 | }; 18 | this.paymentMethod = null; 19 | 20 | this.config = { 21 | debug: false, 22 | account: '', 23 | widgetKey: '', 24 | container: '', 25 | form: '', 26 | language: '', 27 | customerId: '', 28 | tokenName: 'xpaymentsToken', 29 | showSaveCard: true, 30 | enableWallets: true, 31 | applePay: { 32 | enabled: true, 33 | checkoutMode: false, 34 | shippingMethods: [], 35 | requiredShippingFields: [ 36 | 'email', 37 | 'name', 38 | 'phone', 39 | 'postalAddress' 40 | ], 41 | requiredBillingFields: [ 42 | 'postalAddress' 43 | ] 44 | }, 45 | company: { 46 | name: '', 47 | domain: document.location.hostname, 48 | countryCode: '', 49 | }, 50 | order: { 51 | tokenizeCard: false, 52 | total: -1, 53 | currency: '' 54 | } 55 | }; 56 | 57 | this.handlers = {}; 58 | 59 | this.bindedListener = false; 60 | this.bindedSubmit = false; 61 | 62 | } 63 | 64 | XPaymentsWidget.prototype.on = function(event, handler, context) 65 | { 66 | if ('undefined' === typeof context) { 67 | context = this; 68 | } 69 | 70 | if ('formSubmit' !== event) { 71 | 72 | this.handlers[event] = handler.bind(context); 73 | 74 | } else { 75 | var formElm = this.getFormElm(); 76 | 77 | if (formElm) { 78 | if (this.bindedSubmit) { 79 | formElm.removeEventListener('submit', this.bindedSubmit); 80 | } 81 | this.bindedSubmit = handler.bind(context); 82 | formElm.addEventListener('submit', this.bindedSubmit); 83 | } 84 | } 85 | 86 | return this; 87 | } 88 | 89 | 90 | XPaymentsWidget.prototype.trigger = function(event, params) 91 | { 92 | if ('function' === typeof this.handlers[event]) { 93 | this.handlers[event](params); 94 | } 95 | 96 | this._log('X-Payments widget triggered: ' + event, params); 97 | 98 | return this; 99 | } 100 | 101 | XPaymentsWidget.prototype.init = function(settings) 102 | { 103 | for (var key in settings) { 104 | if ('undefined' !== typeof this.config[key]) { 105 | if ('object' === typeof this.config[key]) { 106 | for (var subkey in settings[key]) { 107 | if ('undefined' !== typeof this.config[key][subkey]) { 108 | this.config[key][subkey] = settings[key][subkey]; 109 | } 110 | } 111 | } else { 112 | this.config[key] = settings[key]; 113 | } 114 | } 115 | } 116 | 117 | if (this.config.order.tokenizeCard) { 118 | this.config.showSaveCard = false; 119 | } 120 | 121 | // Set default handlers 122 | this.on('formSubmit', function (domEvent) { 123 | // "this" here is the widget 124 | if (this.isValid()) { 125 | this.submit(); 126 | domEvent.preventDefault(); 127 | } 128 | }) 129 | .on('success', this._defaultSuccessHandler) 130 | .on('applepay.paymentauthorized', this._applePayAuthorized) 131 | .on('alert', function(params) { 132 | window.alert(params.message); 133 | }); 134 | 135 | this.bindedListener = this.messageListener.bind(this); 136 | window.addEventListener('message', this.bindedListener); 137 | 138 | if ( 139 | 'undefined' !== typeof settings.autoload 140 | && settings.autoload 141 | ) { 142 | this.load(); 143 | } 144 | 145 | return this; 146 | } 147 | 148 | XPaymentsWidget.prototype.initCheckoutWithApplePay = function(settings) 149 | { 150 | this.config.container = 'body'; 151 | this.config.applePay.checkoutMode = true; 152 | this.init(settings); 153 | } 154 | 155 | XPaymentsWidget.prototype.generateId = function() 156 | { 157 | return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); 158 | } 159 | 160 | XPaymentsWidget.prototype.getIframeId = function() 161 | { 162 | return 'xpayments-' + this.widgetId; 163 | } 164 | 165 | XPaymentsWidget.prototype.getIframeElm = function() 166 | { 167 | return document.getElementById(this.getIframeId()); 168 | } 169 | 170 | XPaymentsWidget.prototype.getContainerElm = function() 171 | { 172 | return this.safeQuerySelector(this.config.container); 173 | } 174 | 175 | XPaymentsWidget.prototype.getFormElm = function() 176 | { 177 | return this.safeQuerySelector(this.config.form); 178 | } 179 | 180 | XPaymentsWidget.prototype.isValid = function() 181 | { 182 | return this.getIframeElm() && this.getFormElm(); 183 | } 184 | 185 | XPaymentsWidget.prototype.safeQuerySelector = function(selector) 186 | { 187 | var elm = false; 188 | if (selector) { 189 | elm = document.querySelector(selector); 190 | } 191 | return elm; 192 | } 193 | 194 | XPaymentsWidget.prototype.load = function() 195 | { 196 | var containerElm = this.getContainerElm(); 197 | if (!containerElm) { 198 | return this; 199 | } 200 | 201 | var elm = this.getIframeElm(); 202 | if (!elm) { 203 | elm = document.createElement('iframe'); 204 | elm.id = this.getIframeId(); 205 | elm.style.width = '100%'; 206 | elm.style.height = '0'; 207 | elm.style.overflow = 'hidden'; 208 | elm.style.border = 'none'; 209 | if (this.config.applePay.checkoutMode) { 210 | elm.style.display = 'none'; 211 | } 212 | elm.setAttribute('scrolling', 'no'); 213 | containerElm.appendChild(elm); 214 | } 215 | 216 | var url = 217 | this.getServerUrl() + '/payment.php' + 218 | '?widget_key=' + encodeURIComponent(this.config.widgetKey) + 219 | '&widget_id=' + encodeURIComponent(this.widgetId); 220 | if (this.config.customerId) { 221 | url += '&customer_id=' + encodeURIComponent(this.config.customerId); 222 | } 223 | if (this.config.language) { 224 | url += '&language=' + encodeURIComponent(this.config.language); 225 | } 226 | if (this.config.applePay.checkoutMode) { 227 | url += '&target=checkout_apple_pay'; 228 | } 229 | elm.src = url; 230 | 231 | return this; 232 | } 233 | 234 | XPaymentsWidget.prototype.getServerHost = function() 235 | { 236 | return this.config.account + '.' + this.serverDomain; 237 | } 238 | 239 | XPaymentsWidget.prototype.getServerUrl = function() 240 | { 241 | return 'https://' + this.getServerHost(); 242 | } 243 | 244 | XPaymentsWidget.prototype.submit = function() 245 | { 246 | if (!this.config.applePay.checkoutMode) { 247 | this._sendEvent('submit'); 248 | } else { 249 | this.beginCheckoutWithApplePay(); 250 | } 251 | } 252 | 253 | XPaymentsWidget.prototype.beginCheckoutWithApplePay = function() 254 | { 255 | if (this._isApplePayAvailable()) { 256 | this.trigger('applepay.start'); 257 | this._applePayStart(); 258 | } 259 | } 260 | 261 | XPaymentsWidget.prototype._afterLoad = function(params) 262 | { 263 | this.showSaveCard(); 264 | if (this.config.enableWallets) { 265 | if (this._isApplePayAvailable()) { 266 | this._sendEvent('applepay.enable'); 267 | } 268 | } 269 | this.setOrder(); 270 | this.resize(params.height); 271 | } 272 | 273 | XPaymentsWidget.prototype._defaultSuccessHandler = function(params) { 274 | var formElm = this.getFormElm(); 275 | if (formElm) { 276 | var input = document.getElementById(this.config.tokenName); 277 | if (!input) { 278 | input = document.createElement('input'); 279 | input.type = 'hidden'; 280 | input.name = input.id = this.config.tokenName; 281 | formElm.appendChild(input); 282 | } 283 | input.value = params.token; 284 | formElm.submit(); 285 | } 286 | } 287 | 288 | XPaymentsWidget.prototype.getPaymentMethod = function() 289 | { 290 | return (!this.config.applePay.checkoutMode) ? this.paymentMethod : 'apple_pay'; 291 | } 292 | 293 | XPaymentsWidget.prototype._paymentMethodChange = function(params) 294 | { 295 | this.paymentMethod = params.newId; 296 | } 297 | 298 | XPaymentsWidget.prototype._applePayValidated = function(params) 299 | { 300 | try { 301 | this.applePay.session.completeMerchantValidation(params.data); 302 | } catch (e) { 303 | } 304 | } 305 | 306 | XPaymentsWidget.prototype._applePayAuthorized = function(params) 307 | { 308 | this.succeedApplePayPayment(params); 309 | } 310 | 311 | XPaymentsWidget.prototype._applePayCompleted = function(params) 312 | { 313 | this.completeApplePayPayment({ status: ApplePaySession.STATUS_SUCCESS, errors: [] }); 314 | } 315 | 316 | XPaymentsWidget.prototype._applePayError = function(params) 317 | { 318 | try { 319 | this.applePay.session.abort(); 320 | } catch (e) { 321 | // Skip errors if any 322 | } 323 | } 324 | 325 | XPaymentsWidget.prototype._applePayStart = function() 326 | { 327 | var request = { 328 | countryCode: this.config.company.countryCode, 329 | currencyCode: this.config.order.currency, 330 | supportedNetworks: this.applePay.supportedNetworks, 331 | merchantCapabilities: this.applePay.merchantCapabilities, 332 | total: { 333 | label: this.config.company.name, 334 | amount: this.config.order.total 335 | }, 336 | }; 337 | 338 | this.applePayCustomerAddress = null; 339 | if (this.config.applePay.checkoutMode) { 340 | if (this.config.applePay.shippingMethods) { 341 | request.shippingMethods = this.config.applePay.shippingMethods; 342 | } 343 | if (this.config.applePay.requiredShippingFields) { 344 | request.requiredShippingContactFields = this.config.applePay.requiredShippingFields; 345 | } 346 | if (this.config.applePay.requiredBillingFields) { 347 | request.requiredBillingContactFields = this.config.applePay.requiredBillingFields; 348 | } 349 | } 350 | 351 | this.applePay.session = new ApplePaySession(3, request); 352 | 353 | this.applePay.session.onvalidatemerchant = (function(event) { 354 | this._sendEvent('applepay.validatemerchant', { 355 | validationURL: event.validationURL, 356 | displayName: this.config.company.name, 357 | context: this.config.company.domain, 358 | }); 359 | }).bind(this); 360 | 361 | this.applePay.session.onpaymentauthorized = (function(event) { 362 | this.trigger('applepay.paymentauthorized', event.payment); 363 | }).bind(this); 364 | 365 | this.applePay.session.oncancel = (function(event) { 366 | this._sendEvent('applepay.cancel'); 367 | }).bind(this); 368 | 369 | if (this.config.applePay.checkoutMode) { 370 | this.applePay.session.onshippingcontactselected = (function(event) { 371 | this.trigger('applepay.shippingcontactselected', event.shippingContact); 372 | }).bind(this); 373 | this.applePay.session.onshippingmethodselected = (function(event) { 374 | this.trigger('applepay.shippingmethodselected', event.shippingMethod); 375 | }).bind(this); 376 | } 377 | 378 | this.applePay.session.begin(); 379 | 380 | } 381 | 382 | XPaymentsWidget.prototype._parseApplePayNewTotal = function(updateData) 383 | { 384 | this.setOrder(updateData.newTotal.amount); 385 | if ('undefined' != typeof updateData.newTotal && 'undefined' == typeof updateData.newTotal.label) { 386 | updateData.newTotal.label = this.config.company.name; 387 | } 388 | return updateData; 389 | } 390 | 391 | XPaymentsWidget.prototype.completeApplePayShippingContactSelection = function(updateData) { 392 | this.applePay.session.completeShippingContactSelection(this._parseApplePayNewTotal(updateData)); 393 | } 394 | 395 | XPaymentsWidget.prototype.completeApplePayShippingMethodSelection = function(updateData) { 396 | this.applePay.session.completeShippingMethodSelection(this._parseApplePayNewTotal(updateData)); 397 | } 398 | 399 | XPaymentsWidget.prototype.completeApplePayPayment = function(updateData) { 400 | this.applePay.session.completePayment(updateData); 401 | } 402 | 403 | XPaymentsWidget.prototype.succeedApplePayPayment = function(payment) { 404 | this._sendEvent('applepay.paymentauthorized', { payment: payment }); 405 | } 406 | 407 | 408 | XPaymentsWidget.prototype.isApplePaySupportedByDevice = function() { 409 | return (window.ApplePaySession && ApplePaySession.canMakePayments()); 410 | } 411 | 412 | XPaymentsWidget.prototype._isApplePayAvailable = function() { 413 | return this.config.applePay.enabled && this.isApplePaySupportedByDevice(); 414 | } 415 | 416 | XPaymentsWidget.prototype._checkApplePayActiveCard = function() 417 | { 418 | var promise = ApplePaySession.canMakePaymentsWithActiveCard(this.applePay.merchantId); 419 | promise.then((function (canMakePayments) { 420 | if (canMakePayments) { 421 | this.trigger('applepay.forceselect'); 422 | this._sendEvent('applepay.select'); 423 | } 424 | }).bind(this)); 425 | } 426 | 427 | XPaymentsWidget.prototype._applePayInit = function(params) 428 | { 429 | this.applePay.supportedNetworks = params.supportedNetworks; 430 | this.applePay.merchantCapabilities = params.merchantCapabilities; 431 | this.applePay.merchantId = params.merchantId; 432 | this._checkApplePayActiveCard(); 433 | } 434 | 435 | XPaymentsWidget.prototype.showSaveCard = function(value) 436 | { 437 | if ('undefined' === typeof value) { 438 | value = this.config.showSaveCard; 439 | } else { 440 | this.config.showSaveCard = (true === value); 441 | } 442 | this._sendEvent('savecard', { show: value }); 443 | } 444 | 445 | 446 | XPaymentsWidget.prototype.refresh = function() 447 | { 448 | this._sendEvent('refresh'); 449 | } 450 | 451 | XPaymentsWidget.prototype.resize = function(height) 452 | { 453 | var elm = this.getIframeElm(); 454 | if (elm) { 455 | this.previousHeight = elm.style.height; 456 | elm.style.height = height + 'px'; 457 | } 458 | } 459 | 460 | XPaymentsWidget.prototype.setOrder = function(total, currency) 461 | { 462 | if ('undefined' !== typeof total) { 463 | this.config.order.total = total; 464 | } 465 | if ('undefined' !== typeof currency) { 466 | this.config.order.currency = currency; 467 | } 468 | 469 | this._sendEvent('details', { 470 | tokenizeCard: this.config.order.tokenizeCard, 471 | total: this.config.order.total, 472 | currency: this.config.order.currency 473 | }); 474 | } 475 | 476 | XPaymentsWidget.prototype.destroy = function() 477 | { 478 | if (this.bindedListener) { 479 | window.removeEventListener('message', this.bindedListener); 480 | } 481 | 482 | var formElm = this.getFormElm(); 483 | if (this.bindedSubmit && formElm) { 484 | formElm.removeEventListener('submit', this.bindedSubmit); 485 | } 486 | 487 | var containerElm = this.getContainerElm(); 488 | if (containerElm) { 489 | var elm = this.getIframeElm(); 490 | if (elm && containerElm.contains(elm)) { 491 | containerElm.removeChild(elm); 492 | } 493 | } 494 | } 495 | 496 | XPaymentsWidget.prototype.messageListener = function(event) 497 | { 498 | if (window.JSON) { 499 | var msg = false; 500 | if (-1 !== this.getServerUrl().toLowerCase().indexOf(event.origin.toLowerCase())) { 501 | try { 502 | msg = window.JSON.parse(event.data); 503 | } catch (e) { 504 | // Skip invalid messages 505 | } 506 | } 507 | 508 | if ( 509 | msg && 510 | msg.event && 511 | 0 === msg.event.indexOf(this.messageNamespace) && 512 | (!msg.widgetId || msg.widgetId === this.widgetId) 513 | ) { 514 | this._log('Received from X-Payments: ' + msg.event); 515 | 516 | var eventType = msg.event.substr(this.messageNamespace.length); 517 | 518 | if ('loaded' === eventType) { 519 | this._afterLoad(msg.params); 520 | } else if ('applepay.start' === eventType) { 521 | this._applePayStart(msg.params); 522 | } else if ('applepay.init' === eventType) { 523 | this._applePayInit(msg.params); 524 | } else if ('applepay.merchantvalidated' === eventType) { 525 | this._applePayValidated(msg.params); 526 | } else if ('applepay.completed' === eventType) { 527 | this._applePayCompleted(msg.params); 528 | } else if ('applepay.error' === eventType) { 529 | this._applePayError(msg.params); 530 | } else if ('paymentmethod.change' === eventType) { 531 | this._paymentMethodChange(msg.params); 532 | } else if ('resize' === eventType) { 533 | this.resize(msg.params.height); 534 | } else if ('alert' === eventType) { 535 | msg.params.message = 536 | ('string' === typeof msg.params.message) 537 | ? msg.params.message.replace(/<\/?[^>]+>/gi, '') 538 | : ''; 539 | } 540 | 541 | this.trigger(eventType, msg.params); 542 | } 543 | 544 | } 545 | } 546 | 547 | XPaymentsWidget.prototype._isDebugMode = function() 548 | { 549 | return this.config.debug; 550 | } 551 | 552 | XPaymentsWidget.prototype._log = function(msg, params) 553 | { 554 | if (this._isDebugMode()) { 555 | if ('undefined' !== typeof params) { 556 | msg = msg + "\n" + JSON.stringify(params); 557 | } 558 | console.log(msg); 559 | } 560 | } 561 | 562 | XPaymentsWidget.prototype._sendEvent = function(eventName, eventParams) 563 | { 564 | if ('undefined' === typeof eventParams) { 565 | eventParams = {}; 566 | } 567 | 568 | this._postMessage({ 569 | event: this.receiverNamespace + eventName, 570 | params: eventParams 571 | }) 572 | } 573 | 574 | XPaymentsWidget.prototype._postMessage = function(message) 575 | { 576 | var elm = this.getIframeElm(); 577 | if ( 578 | window.postMessage 579 | && window.JSON 580 | && elm 581 | && elm.contentWindow 582 | ) { 583 | this._log('Sent to X-Payments: ' + message.event, message.params); 584 | elm.contentWindow.postMessage(window.JSON.stringify(message), '*'); 585 | } else { 586 | this._log('Error sending message - iframe wasn\'t initialized!'); 587 | } 588 | } 589 | --------------------------------------------------------------------------------