diff --git a/.phpcs.xml b/.phpcs.xml index 6118f7a..aab5a6c 100644 --- a/.phpcs.xml +++ b/.phpcs.xml @@ -5,4 +5,6 @@ */vendor/* + *.min.js + *.min.css diff --git a/.pronto.yml b/.pronto.yml deleted file mode 100644 index 752c7a0..0000000 --- a/.pronto.yml +++ /dev/null @@ -1,6 +0,0 @@ -github: - slug: eMerchantPay/opencart4-emp-plugin - access_token: ENV['PRONTO_GITHUB_ACCESS_TOKEN'] - api_endpoint: ENV['PRONTO_GITHUB_API_ENDPOINT'] - web_endpoint: ENV['PRONTO_GITHUB_WEB_ENDPOINT'] -verbose: false diff --git a/Gemfile b/Gemfile deleted file mode 100644 index 5f29bc2..0000000 --- a/Gemfile +++ /dev/null @@ -1,6 +0,0 @@ -source 'http://rubygems.org' - -# code analysis -gem 'pronto', '~> 0.9.5' -gem 'pronto-phpcs', '~> 0.4.0', require: false -gem 'pronto-phpmd', '~> 0.4.0', require: false diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index 925f5be..0000000 --- a/Gemfile.lock +++ /dev/null @@ -1,53 +0,0 @@ -GEM - remote: http://rubygems.org/ - specs: - addressable (2.8.1) - public_suffix (>= 2.0.2, < 6.0) - faraday (1.0.1) - multipart-post (>= 1.2, < 3) - gitlab (4.14.0) - httparty (~> 0.14, >= 0.14.0) - terminal-table (~> 1.5, >= 1.5.1) - httparty (0.21.0) - mini_mime (>= 1.0.0) - multi_xml (>= 0.5.2) - mini_mime (1.1.2) - multi_xml (0.6.0) - multipart-post (2.3.0) - octokit (4.25.1) - faraday (>= 1, < 3) - sawyer (~> 0.9) - pronto (0.9.5) - gitlab (~> 4.0, >= 4.0.0) - httparty (>= 0.13.7) - octokit (~> 4.7, >= 4.7.0) - rainbow (~> 2.1) - rugged (~> 0.24, >= 0.23.0) - thor (~> 0.19.0) - pronto-phpcs (0.4.0) - pronto (~> 0.9.0) - pronto-phpmd (0.4.0) - pronto (~> 0.9.0) - public_suffix (4.0.7) - rainbow (2.2.2) - rake - rake (13.0.6) - rugged (0.99.0) - sawyer (0.9.2) - addressable (>= 2.3.5) - faraday (>= 0.17.3, < 3) - terminal-table (1.8.0) - unicode-display_width (~> 1.1, >= 1.1.1) - thor (0.19.4) - unicode-display_width (1.8.0) - -PLATFORMS - ruby - -DEPENDENCIES - pronto (~> 0.9.5) - pronto-phpcs (~> 0.4.0) - pronto-phpmd (~> 0.4.0) - -BUNDLED WITH - 1.17.3 diff --git a/README.md b/README.md index 54d234f..679b124 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Requirements ------------ * OpenCart 4.0.2.X (due to architectural changes, this module is __incompatible__ with older OpenCart versions) -* [GenesisPHP v1.24.0](https://github.com/GenesisGateway/genesis_php/tree/1.24.0) - (Integrated in Module) +* [GenesisPHP v1.24.2](https://github.com/GenesisGateway/genesis_php/tree/1.24.2) - (Integrated in Module) * PCI-certified server in order to use ```emerchantpay Direct``` GenesisPHP Requirements diff --git a/admin/controller/payment/emerchantpay_direct.php b/admin/controller/payment/emerchantpay_direct.php index 45bf787..51e2d5a 100644 --- a/admin/controller/payment/emerchantpay_direct.php +++ b/admin/controller/payment/emerchantpay_direct.php @@ -66,7 +66,7 @@ protected function validate(): bool { parent::validate(); - if (@empty($this->request->post["{$this->module_name}_token"])) { + if (empty($this->request->post["{$this->module_name}_token"])) { $this->error['token'] = $this->language->get('error_token'); } diff --git a/admin/language/en-gb/payment/emerchantpay_checkout.php b/admin/language/en-gb/payment/emerchantpay_checkout.php index 4a435a5..d8279b4 100644 --- a/admin/language/en-gb/payment/emerchantpay_checkout.php +++ b/admin/language/en-gb/payment/emerchantpay_checkout.php @@ -37,30 +37,34 @@ $_['text_select_status'] = 'Select Status'; // Entry -$_['entry_username'] = 'Genesis Username'; -$_['entry_password'] = 'Genesis Password'; -$_['entry_token'] = 'Genesis Token'; -$_['entry_sandbox'] = 'Test Mode'; -$_['entry_transaction_type'] = 'Transaction Types'; -$_['entry_wpf_tokenization'] = 'WPF Tokenization Enabled'; -$_['entry_supports_partial_capture'] = 'Partial Capture'; -$_['entry_supports_partial_refund'] = 'Partial Refund'; -$_['entry_supports_void'] = 'Cancel Transaction'; -$_['entry_total'] = 'Total'; -$_['entry_order_status'] = 'Order Status'; -$_['entry_order_status_failure'] = 'Order Status (Failed)'; -$_['entry_geo_zone'] = 'Geo Zone'; -$_['entry_status'] = 'Status'; -$_['entry_debug'] = 'Error Logging'; -$_['entry_sort_order'] = 'Sort Order'; -$_['entry_supports_recurring'] = 'Recurring Payments'; -$_['entry_recurring_transaction_type'] = 'Recurring Transaction Types'; -$_['entry_recurring_log'] = 'Recurring Log'; -$_['entry_recurring_token'] = 'Recurring Token'; -$_['entry_cron_time_limit'] = 'Processing time for re-billing'; -$_['entry_cron_allowed_ip'] = 'IP address'; -$_['entry_cron_last_execution'] = 'Cron/schtasks last execution'; -$_['entry_bank_codes'] = 'Bank code(s) for Online banking'; +$_['entry_username'] = 'Genesis Username'; +$_['entry_password'] = 'Genesis Password'; +$_['entry_token'] = 'Genesis Token'; +$_['entry_sandbox'] = 'Test Mode'; +$_['entry_transaction_type'] = 'Transaction Types'; +$_['entry_wpf_tokenization'] = 'WPF Tokenization Enabled'; +$_['entry_supports_partial_capture'] = 'Partial Capture'; +$_['entry_supports_partial_refund'] = 'Partial Refund'; +$_['entry_supports_void'] = 'Cancel Transaction'; +$_['entry_total'] = 'Total'; +$_['entry_order_status'] = 'Order Status'; +$_['entry_order_status_failure'] = 'Order Status (Failed)'; +$_['entry_geo_zone'] = 'Geo Zone'; +$_['entry_status'] = 'Status'; +$_['entry_debug'] = 'Error Logging'; +$_['entry_sort_order'] = 'Sort Order'; +$_['entry_supports_recurring'] = 'Recurring Payments'; +$_['entry_recurring_transaction_type'] = 'Recurring Transaction Types'; +$_['entry_recurring_log'] = 'Recurring Log'; +$_['entry_recurring_token'] = 'Recurring Token'; +$_['entry_cron_time_limit'] = 'Processing time for re-billing'; +$_['entry_cron_allowed_ip'] = 'IP address'; +$_['entry_cron_last_execution'] = 'Cron/schtasks last execution'; +$_['entry_bank_codes'] = 'Bank code(s) for Online banking'; +$_['entry_threeds_allowed'] = 'Enable 3DSv2'; +$_['entry_threeds_challenge_indicator'] = '3DSv2 Challenge'; +$_['entry_sca_exemption'] = 'SCA Exemption'; +$_['entry_sca_exemption_amount'] = 'Exemption Amount'; // Transaction Types //$_ = array_merge($_, EmerchantpayHelper::getTransactionTypeNames()); @@ -138,6 +142,10 @@ $_['help_cron_time_limit'] = 'Тhe total time in seconds allowed for re-billing recurring orders in a single execution of the cron / schtasks. If there is a re-billing in process while reaching this limit, it will try to continue and respectively the execution time will exceed the allowed time.'; $_['help_cron_allowed_ip'] = 'The IP address allowed to send HTTP requests to the cron-handling URLs.'; $_['help_cron_last_execution'] = 'The time the cron / schtasks was last executed.'; +$_['help_threeds_allowed'] = 'Enable 3DSv2 optional parameters.'; +$_['help_threeds_challenge_indicator'] = 'The value has weight and might impact the decision whether a challenge will be required for the transaction or not.'; +$_['help_sca_exemption'] = 'Exemption for the Strong Customer Authentication.'; +$_['help_sca_exemption_amount'] = 'Exemption Amount determinate if the SCA Exemption should be included in the request to the Gateway.'; // Error $_['error_permission'] = 'Warning: You do not have permission to modify payment module emerchantpay!'; @@ -147,6 +155,7 @@ $_['error_controls_invalidated'] = 'Warning: You have to fill-in all the required fields'; $_['error_order_status'] = 'Order Status is Required'; $_['error_order_failure_status'] = 'Order Status (Failed) is Required'; +$_['error_sca_exemption_amount'] = 'SCA Exemption amount must have positive value'; //Alert $_['alert_disable_recurring'] = 'Warning: Disabling the Recurring Payments disables placing new recurring orders. It does not disable the re-billing of the existing ones.'; diff --git a/admin/language/en-gb/payment/emerchantpay_direct.php b/admin/language/en-gb/payment/emerchantpay_direct.php index 657202f..ac322ba 100644 --- a/admin/language/en-gb/payment/emerchantpay_direct.php +++ b/admin/language/en-gb/payment/emerchantpay_direct.php @@ -61,6 +61,10 @@ $_['entry_cron_time_limit'] = 'Processing time for re-billing'; $_['entry_cron_allowed_ip'] = 'IP address'; $_['entry_cron_last_execution'] = 'Cron/schtasks last execution'; +$_['entry_threeds_allowed'] = 'Enable 3DSv2'; +$_['entry_threeds_challenge_indicator'] = '3DSv2 Challenge'; +$_['entry_sca_exemption'] = 'SCA Exemption'; +$_['entry_sca_exemption_amount'] = 'Exemption Amount'; // Transaction Types //$_ = array_merge($_, EmerchantpayHelper::getTransactionTypeNames()); @@ -138,6 +142,10 @@ $_['help_cron_time_limit'] = 'Тhe total time in seconds allowed for re-billing recurring orders in a single execution of the cron / schtasks. If there is a re-billing in process while reaching this limit, it will try to continue and respectively the actual the execution time will exceed the allowed time.'; $_['help_cron_allowed_ip'] = 'The IP address allowed to send HTTP requests to the cron-handling URLs.'; $_['help_cron_last_execution'] = 'The time the cron / schtasks was last executed.'; +$_['help_threeds_allowed'] = 'Enable 3DSv2 optional parameters.'; +$_['help_threeds_challenge_indicator'] = 'The value has weight and might impact the decision whether a challenge will be required for the transaction or not.'; +$_['help_sca_exemption'] = 'Exemption for the Strong Customer Authentication.'; +$_['help_sca_exemption_amount'] = 'Exemption Amount determinate if the SCA Exemption should be included in the request to the Gateway.'; // Error $_['error_permission'] = 'Warning: You do not have permission to modify payment module emerchantpay!'; @@ -150,6 +158,7 @@ $_['error_order_status'] = 'Order Status is Required'; $_['error_order_failure_status'] = 'Order Status (Failed) is Required'; $_['error_async_order_status'] = 'Order Status (Async) is Required'; +$_['error_sca_exemption_amount'] = 'SCA Exemption amount must have positive value'; //Alert $_['alert_disable_recurring'] = 'Warning: Disabling the Recurring Payments disables placing new recurring orders. It does not disable the re-billing of the existing ones.'; diff --git a/admin/model/payment/emerchantpay/base_model.php b/admin/model/payment/emerchantpay/base_model.php new file mode 100644 index 0000000..30fefe2 --- /dev/null +++ b/admin/model/payment/emerchantpay/base_model.php @@ -0,0 +1,62 @@ + 'Low risk', + ScaExemptions::EXEMPTION_LOW_VALUE => 'Low value', + ]; + + foreach ($sca_exemptions as $value => $label) { + $data[] = [ + 'id' => $value, + 'name' => $label + ]; + } + + return $data; + } +} diff --git a/admin/model/payment/emerchantpay_checkout.php b/admin/model/payment/emerchantpay_checkout.php index a1108f2..ec827d4 100644 --- a/admin/model/payment/emerchantpay_checkout.php +++ b/admin/model/payment/emerchantpay_checkout.php @@ -30,27 +30,19 @@ use Genesis\API\Request\Financial\Alternatives\Klarna\Items as KlarnaItems; use Genesis\Config; use Genesis\Genesis; +use Opencart\Admin\Model\Extension\Emerchantpay\Payment\emerchantpay\BaseModel; use Opencart\Extension\Emerchantpay\System\DbHelper; use Opencart\Extension\Emerchantpay\System\EmerchantpayHelper; -use Opencart\System\Engine\Model; /** * Backend model for the "emerchantpay Checkout" module * * @package EMerchantpayCheckout */ -class EmerchantpayCheckout extends Model +class EmerchantpayCheckout extends BaseModel { protected $module_name = 'emerchantpay_checkout'; - /** - * Holds the current module version - * Will be displayed on Admin Settings Form - * - * @var string - */ - protected $module_version = '1.1.3'; - /** * Perform installation logic * @@ -70,7 +62,7 @@ public function install(): void `message` VARCHAR(255) NULL, `technical_message` VARCHAR(255) NULL, `terminal_token` VARCHAR(255) NULL, - `amount` DECIMAL( 10, 2 ) DEFAULT NULL, + `amount` DECIMAL( 15, 4 ) DEFAULT NULL, `currency` CHAR(3) NULL, PRIMARY KEY (`unique_id`) ) ENGINE=InnoDB DEFAULT COLLATE=utf8_general_ci; @@ -243,7 +235,7 @@ public function capture($type, $reference_id, $amount, $currency, $usage, $order $this->genTransactionId('ocart-') ) ->setRemoteIp( - $this->request->server['REMOTE_ADDR'] + EmerchantpayHelper::getFirstRemoteAddress($this->request->server['REMOTE_ADDR']) ) ->setUsage($usage) ->setReferenceId($reference_id) @@ -292,7 +284,7 @@ public function refund($type, $reference_id, $amount, $currency, $usage = '', $t $this->genTransactionId('ocart-') ) ->setRemoteIp( - $this->request->server['REMOTE_ADDR'] + EmerchantpayHelper::getFirstRemoteAddress($this->request->server['REMOTE_ADDR']) ) ->setUsage($usage) ->setReferenceId($reference_id) @@ -335,7 +327,7 @@ public function void($reference_id, $usage = '', $token = null): object|string $this->genTransactionId('ocart-') ) ->setRemoteIp( - $this->request->server['REMOTE_ADDR'] + EmerchantpayHelper::getFirstRemoteAddress($this->request->server['REMOTE_ADDR']) ) ->setUsage($usage) ->setReferenceId($reference_id); diff --git a/admin/model/payment/emerchantpay_direct.php b/admin/model/payment/emerchantpay_direct.php index 804fb4d..7a05e8e 100644 --- a/admin/model/payment/emerchantpay_direct.php +++ b/admin/model/payment/emerchantpay_direct.php @@ -25,27 +25,19 @@ use Genesis\API\Constants\Transaction\Types; use Genesis\Config; use Genesis\Genesis; +use Opencart\Admin\Model\Extension\Emerchantpay\Payment\emerchantpay\BaseModel; use Opencart\Extension\Emerchantpay\System\DbHelper; use Opencart\Extension\Emerchantpay\System\EmerchantpayHelper; -use Opencart\System\Engine\Model; /** * Backend model for the "emerchantpay Direct" module * * @package EMerchantpayDirect */ -class EmerchantpayDirect extends Model +class EmerchantpayDirect extends BaseModel { protected $module_name = "emerchantpay_direct"; - /** - * Holds the current module version - * Will be displayed on Admin Settings Form - * - * @var string - */ - protected $module_version = '1.1.3'; - /** * Perform installation logic * @@ -64,7 +56,7 @@ public function install(): void `status` CHAR(32) NOT NULL, `message` VARCHAR(255) NULL, `technical_message` VARCHAR(255) NULL, - `amount` DECIMAL( 10, 2 ) DEFAULT NULL, + `amount` DECIMAL( 15, 4 ) DEFAULT NULL, `currency` CHAR(3) NULL, PRIMARY KEY (`unique_id`) ) ENGINE=InnoDB DEFAULT COLLATE=utf8_general_ci; @@ -224,7 +216,7 @@ public function capture($type, $reference_id, $amount, $currency, $usage): objec $this->genTransactionId('ocart-') ) ->setRemoteIp( - $this->request->server['REMOTE_ADDR'] + EmerchantpayHelper::getFirstRemoteAddress($this->request->server['REMOTE_ADDR']) ) ->setUsage($usage) ->setReferenceId($reference_id) @@ -266,7 +258,7 @@ public function refund($type, $reference_id, $amount, $currency, $usage = ''): o $this->genTransactionId('ocart-') ) ->setRemoteIp( - $this->request->server['REMOTE_ADDR'] + EmerchantpayHelper::getFirstRemoteAddress($this->request->server['REMOTE_ADDR']) ) ->setUsage($usage) ->setReferenceId($reference_id) @@ -304,7 +296,7 @@ public function void($reference_id, $usage = ''): object|string $this->genTransactionId('ocart-') ) ->setRemoteIp( - $this->request->server['REMOTE_ADDR'] + EmerchantpayHelper::getFirstRemoteAddress($this->request->server['REMOTE_ADDR']) ) ->setUsage($usage) ->setReferenceId($reference_id); diff --git a/admin/view/javascript/emerchantpay/treegrid/js/jquery.treegrid.js b/admin/view/javascript/emerchantpay/treegrid/js/jquery.treegrid.js index 1785e53..600f231 100644 --- a/admin/view/javascript/emerchantpay/treegrid/js/jquery.treegrid.js +++ b/admin/view/javascript/emerchantpay/treegrid/js/jquery.treegrid.js @@ -1,619 +1,619 @@ -/* - * jQuery treegrid Plugin 0.2.0 - * https://github.com/maxazan/jquery-treegrid - * - * Copyright 2013, Pomazan Max - * Licensed under the MIT licenses. - */ -(function($) { - - var methods = { - /** - * Initialize tree - * - * @param {Object} options - * @returns {Object[]} - */ - initTree: function(options) { - var settings = $.extend({}, this.treegrid.defaults, options); - return this.each(function() { - var $this = $(this); - $this.treegrid('setTreeContainer', $(this)); - $this.treegrid('setSettings', settings); - settings.getRootNodes.apply(this, [$(this)]).treegrid('initNode', settings); - }); - }, - /** - * Initialize node - * - * @param {Object} settings - * @returns {Object[]} - */ - initNode: function(settings) { - return this.each(function() { - var $this = $(this); - $this.treegrid('setTreeContainer', settings.getTreeGridContainer.apply(this)); - $this.treegrid('getChildNodes').treegrid('initNode', settings); - $this.treegrid('initExpander').treegrid('initIndent').treegrid('initEvents').treegrid('initState').treegrid("initSettingsEvents"); - }); - }, - /** - * Initialize node events - * - * @returns {Node} - */ - initEvents: function() { - var $this = $(this); - //Save state on change - $this.on("change", function() { - var $this = $(this); - $this.treegrid('render'); - if ($this.treegrid('getSetting', 'saveState')) { - $this.treegrid('saveState'); - } - }); - //Default behavior on collapse - $this.on("collapse", function() { - var $this = $(this); - $this.removeClass('treegrid-expanded'); - $this.addClass('treegrid-collapsed'); - }); - //Default behavior on expand - $this.on("expand", function() { - var $this = $(this); - $this.removeClass('treegrid-collapsed'); - $this.addClass('treegrid-expanded'); - }); - - return $this; - }, - /** - * Initialize events from settings - * - * @returns {Node} - */ - initSettingsEvents: function() { - var $this = $(this); - //Save state on change - $this.on("change", function() { - var $this = $(this); - if (typeof ($this.treegrid('getSetting', 'onChange')) === "function") { - $this.treegrid('getSetting', 'onChange').apply($this); - } - }); - //Default behavior on collapse - $this.on("collapse", function() { - var $this = $(this); - if (typeof ($this.treegrid('getSetting', 'onCollapse')) === "function") { - $this.treegrid('getSetting', 'onCollapse').apply($this); - } - }); - //Default behavior on expand - $this.on("expand", function() { - var $this = $(this); - if (typeof ($this.treegrid('getSetting', 'onExpand')) === "function") { - $this.treegrid('getSetting', 'onExpand').apply($this); - } - - }); - - return $this; - }, - /** - * Initialize expander for node - * - * @returns {Node} - */ - initExpander: function() { - var $this = $(this); - var cell = $this.find('td').get($this.treegrid('getSetting', 'treeColumn')); - var tpl = $this.treegrid('getSetting', 'expanderTemplate'); - var expander = $this.treegrid('getSetting', 'getExpander').apply(this); - if (expander) { - expander.remove(); - } - $(tpl).prependTo(cell).click(function() { - $($(this).closest('tr')).treegrid('toggle'); - }); - return $this; - }, - /** - * Initialize indent for node - * - * @returns {Node} - */ - initIndent: function() { - var $this = $(this); - $this.find('.treegrid-indent').remove(); - for (var i = 0; i < $(this).treegrid('getDepth'); i++) { - $($this.treegrid('getSetting', 'indentTemplate')).insertBefore($this.find('.treegrid-expander')); - } - return $this; - }, - /** - * Initialise state of node - * - * @returns {Node} - */ - initState: function() { - var $this = $(this); - if ($this.treegrid('getSetting', 'saveState') && !$this.treegrid('isFirstInit')) { - $this.treegrid('restoreState'); - } else { - if ($this.treegrid('getSetting', 'initialState') === "expanded") { - $this.treegrid('expand'); - } else { - $this.treegrid('collapse'); - } - } - return $this; - }, - /** - * Return true if this tree was never been initialised - * - * @returns {Boolean} - */ - isFirstInit: function() { - var tree = $(this).treegrid('getTreeContainer'); - if (tree.data('first_init') === undefined) { - tree.data('first_init', $.cookie(tree.treegrid('getSetting', 'saveStateName')) === undefined); - } - return tree.data('first_init'); - }, - /** - * Save state of current node - * - * @returns {Node} - */ - saveState: function() { - var $this = $(this); - if ($this.treegrid('getSetting', 'saveStateMethod') === 'cookie') { - - var stateArrayString = $.cookie($this.treegrid('getSetting', 'saveStateName')) || ''; - var stateArray = (stateArrayString === '' ? [] : stateArrayString.split(',')); - var nodeId = $this.treegrid('getNodeId'); - - if ($this.treegrid('isExpanded')) { - if ($.inArray(nodeId, stateArray) === -1) { - stateArray.push(nodeId); - } - } else if ($this.treegrid('isCollapsed')) { - if ($.inArray(nodeId, stateArray) !== -1) { - stateArray.splice($.inArray(nodeId, stateArray), 1); - } - } - $.cookie($this.treegrid('getSetting', 'saveStateName'), stateArray.join(',')); - } - return $this; - }, - /** - * Restore state of current node. - * - * @returns {Node} - */ - restoreState: function() { - var $this = $(this); - if ($this.treegrid('getSetting', 'saveStateMethod') === 'cookie') { - var stateArray = $.cookie($this.treegrid('getSetting', 'saveStateName')).split(','); - if ($.inArray($this.treegrid('getNodeId'), stateArray) !== -1) { - $this.treegrid('expand'); - } else { - $this.treegrid('collapse'); - } - - } - return $this; - }, - /** - * Method return setting by name - * - * @param {type} name - * @returns {unresolved} - */ - getSetting: function(name) { - if (!$(this).treegrid('getTreeContainer')) { - return null; - } - return $(this).treegrid('getTreeContainer').data('settings')[name]; - }, - /** - * Add new settings - * - * @param {Object} settings - */ - setSettings: function(settings) { - $(this).treegrid('getTreeContainer').data('settings', settings); - }, - /** - * Return tree container - * - * @returns {HtmlElement} - */ - getTreeContainer: function() { - return $(this).data('treegrid'); - }, - /** - * Set tree container - * - * @param {HtmlE;ement} container - */ - setTreeContainer: function(container) { - return $(this).data('treegrid', container); - }, - /** - * Method return all root nodes of tree. - * - * Start init all child nodes from it. - * - * @returns {Array} - */ - getRootNodes: function() { - return $(this).treegrid('getSetting', 'getRootNodes').apply(this, [$(this).treegrid('getTreeContainer')]); - }, - /** - * Method return all nodes of tree. - * - * @returns {Array} - */ - getAllNodes: function() { - return $(this).treegrid('getSetting', 'getAllNodes').apply(this, [$(this).treegrid('getTreeContainer')]); - }, - /** - * Mthod return true if element is Node - * - * @returns {String} - */ - isNode: function() { - return $(this).treegrid('getNodeId') !== null; - }, - /** - * Mthod return id of node - * - * @returns {String} - */ - getNodeId: function() { - if ($(this).treegrid('getSetting', 'getNodeId') === null) { - return null; - } else { - return $(this).treegrid('getSetting', 'getNodeId').apply(this); - } - }, - /** - * Method return parent id of node or null if root node - * - * @returns {String} - */ - getParentNodeId: function() { - return $(this).treegrid('getSetting', 'getParentNodeId').apply(this); - }, - /** - * Method return parent node or null if root node - * - * @returns {Object[]} - */ - getParentNode: function() { - if ($(this).treegrid('getParentNodeId') === null) { - return null; - } else { - return $(this).treegrid('getSetting', 'getNodeById').apply(this, [$(this).treegrid('getParentNodeId'), $(this).treegrid('getTreeContainer')]); - } - }, - /** - * Method return array of child nodes or null if node is leaf - * - * @returns {Object[]} - */ - getChildNodes: function() { - return $(this).treegrid('getSetting', 'getChildNodes').apply(this, [$(this).treegrid('getNodeId'), $(this).treegrid('getTreeContainer')]); - }, - /** - * Method return depth of tree. - * - * This method is needs for calculate indent - * - * @returns {Number} - */ - getDepth: function() { - if ($(this).treegrid('getParentNode') === null) { - return 0; - } - return $(this).treegrid('getParentNode').treegrid('getDepth') + 1; - }, - /** - * Method return true if node is root - * - * @returns {Boolean} - */ - isRoot: function() { - return $(this).treegrid('getDepth') === 0; - }, - /** - * Method return true if node has no child nodes - * - * @returns {Boolean} - */ - isLeaf: function() { - return $(this).treegrid('getChildNodes').length === 0; - }, - /** - * Method return true if node last in branch - * - * @returns {Boolean} - */ - isLast: function() { - if ($(this).treegrid('isNode')) { - var parentNode = $(this).treegrid('getParentNode'); - if (parentNode === null) { - if ($(this).treegrid('getNodeId') === $(this).treegrid('getRootNodes').last().treegrid('getNodeId')) { - return true; - } - } else { - if ($(this).treegrid('getNodeId') === parentNode.treegrid('getChildNodes').last().treegrid('getNodeId')) { - return true; - } - } - } - return false; - }, - /** - * Method return true if node first in branch - * - * @returns {Boolean} - */ - isFirst: function() { - if ($(this).treegrid('isNode')) { - var parentNode = $(this).treegrid('getParentNode'); - if (parentNode === null) { - if ($(this).treegrid('getNodeId') === $(this).treegrid('getRootNodes').first().treegrid('getNodeId')) { - return true; - } - } else { - if ($(this).treegrid('getNodeId') === parentNode.treegrid('getChildNodes').first().treegrid('getNodeId')) { - return true; - } - } - } - return false; - }, - /** - * Return true if node expanded - * - * @returns {Boolean} - */ - isExpanded: function() { - return $(this).hasClass('treegrid-expanded'); - }, - /** - * Return true if node collapsed - * - * @returns {Boolean} - */ - isCollapsed: function() { - return $(this).hasClass('treegrid-collapsed'); - }, - /** - * Return true if at least one of parent node is collapsed - * - * @returns {Boolean} - */ - isOneOfParentsCollapsed: function() { - var $this = $(this); - if ($this.treegrid('isRoot')) { - return false; - } else { - if ($this.treegrid('getParentNode').treegrid('isCollapsed')) { - return true; - } else { - return $this.treegrid('getParentNode').treegrid('isOneOfParentsCollapsed'); - } - } - }, - /** - * Expand node - * - * @returns {Node} - */ - expand: function() { - return $(this).each(function() { - var $this = $(this); - if (!$this.treegrid('isLeaf') && !$this.treegrid("isExpanded")) { - $this.trigger("expand"); - $this.trigger("change"); - } - }); - }, - /** - * Expand all nodes - * - * @returns {Node} - */ - expandAll: function() { - var $this = $(this); - $this.treegrid('getRootNodes').treegrid('expandRecursive'); - return $this; - }, - /** - * Expand current node and all child nodes begin from current - * - * @returns {Node} - */ - expandRecursive: function() { - return $(this).each(function() { - var $this = $(this); - $this.treegrid('expand'); - if (!$this.treegrid('isLeaf')) { - $this.treegrid('getChildNodes').treegrid('expandRecursive'); - } - }); - }, - /** - * Collapse node - * - * @returns {Node} - */ - collapse: function() { - return $(this).each(function() { - var $this = $(this); - if (!$this.treegrid('isLeaf') && !$this.treegrid("isCollapsed")) { - $this.trigger("collapse"); - $this.trigger("change"); - } - }); - }, - /** - * Collapse all nodes - * - * @returns {Node} - */ - collapseAll: function() { - var $this = $(this); - $this.treegrid('getRootNodes').treegrid('collapseRecursive'); - return $this; - }, - /** - * Collapse current node and all child nodes begin from current - * - * @returns {Node} - */ - collapseRecursive: function() { - return $(this).each(function() { - var $this = $(this); - $this.treegrid('collapse'); - if (!$this.treegrid('isLeaf')) { - $this.treegrid('getChildNodes').treegrid('collapseRecursive'); - } - }); - }, - /** - * Expand if collapsed, Collapse if expanded - * - * @returns {Node} - */ - toggle: function() { - var $this = $(this); - if ($this.treegrid('isExpanded')) { - $this.treegrid('collapse'); - } else { - $this.treegrid('expand'); - } - return $this; - }, - /** - * Rendering node - * - * @returns {Node} - */ - render: function() { - return $(this).each(function() { - var $this = $(this); - - if ($this.treegrid('isOneOfParentsCollapsed')) { - $this.hide(); - } else { - $this.show(); - } - if (!$this.treegrid('isLeaf')) { - $this.treegrid('renderExpander'); - $this.treegrid('getChildNodes').treegrid('render'); - } - }); - }, - /** - * Rendering expander depends on node state - * - * @returns {Node} - */ - renderExpander: function() { - return $(this).each(function() { - var $this = $(this); - var expander = $this.treegrid('getSetting', 'getExpander').apply(this); - if (expander) { - - if (!$this.treegrid('isCollapsed')) { - expander.removeClass($this.treegrid('getSetting', 'expanderCollapsedClass')); - expander.addClass($this.treegrid('getSetting', 'expanderExpandedClass')); - } else { - expander.removeClass($this.treegrid('getSetting', 'expanderExpandedClass')); - expander.addClass($this.treegrid('getSetting', 'expanderCollapsedClass')); - } - } else { - $this.treegrid('initExpander'); - $this.treegrid('renderExpander'); - } - }); - } - }; - $.fn.treegrid = function(method) { - if (methods[method]) { - return methods[ method ].apply(this, Array.prototype.slice.call(arguments, 1)); - } else if (typeof method === 'object' || !method) { - return methods.initTree.apply(this, arguments); - } else { - $.error('Method with name ' + method + ' does not exists for jQuery.treegrid'); - } - }; - /** - * Plugin's default options - */ - $.fn.treegrid.defaults = { - initialState: 'expanded', - saveState: false, - saveStateMethod: 'cookie', - saveStateName: 'tree-grid-state', - expanderTemplate: '', - indentTemplate: '', - expanderExpandedClass: 'treegrid-expander-expanded', - expanderCollapsedClass: 'treegrid-expander-collapsed', - treeColumn: 0, - getExpander: function() { - return $(this).find('.treegrid-expander'); - }, - getNodeId: function() { - var template = /treegrid-([A-Za-z0-9_-]+)/; - if (template.test($(this).attr('class'))) { - return template.exec($(this).attr('class'))[1]; - } - return null; - }, - getParentNodeId: function() { - var template = /treegrid-parent-([A-Za-z0-9_-]+)/; - if (template.test($(this).attr('class'))) { - return template.exec($(this).attr('class'))[1]; - } - return null; - }, - getNodeById: function(id, treegridContainer) { - var templateClass = "treegrid-" + id; - return treegridContainer.find('tr.' + templateClass); - }, - getChildNodes: function(id, treegridContainer) { - var templateClass = "treegrid-parent-" + id; - return treegridContainer.find('tr.' + templateClass); - }, - getTreeGridContainer: function() { - return $(this).closest('table'); - }, - getRootNodes: function(treegridContainer) { - var result = $.grep(treegridContainer.find('tr'), function(element) { - var classNames = $(element).attr('class'); - var templateClass = /treegrid-([A-Za-z0-9_-]+)/; - var templateParentClass = /treegrid-parent-([A-Za-z0-9_-]+)/; - return templateClass.test(classNames) && !templateParentClass.test(classNames); - }); - return $(result); - }, - getAllNodes: function(treegridContainer) { - var result = $.grep(treegridContainer.find('tr'), function(element) { - var classNames = $(element).attr('class'); - var templateClass = /treegrid-([A-Za-z0-9_-]+)/; - return templateClass.test(classNames); - }); - return $(result); - }, - //Events - onCollapse: null, - onExpand: null, - onChange: null - - }; +/* + * jQuery treegrid Plugin 0.2.0 + * https://github.com/maxazan/jquery-treegrid + * + * Copyright 2013, Pomazan Max + * Licensed under the MIT licenses. + */ +(function($) { + + var methods = { + /** + * Initialize tree + * + * @param {Object} options + * @returns {Object[]} + */ + initTree: function(options) { + var settings = $.extend({}, this.treegrid.defaults, options); + return this.each(function() { + var $this = $(this); + $this.treegrid('setTreeContainer', $(this)); + $this.treegrid('setSettings', settings); + settings.getRootNodes.apply(this, [$(this)]).treegrid('initNode', settings); + }); + }, + /** + * Initialize node + * + * @param {Object} settings + * @returns {Object[]} + */ + initNode: function(settings) { + return this.each(function() { + var $this = $(this); + $this.treegrid('setTreeContainer', settings.getTreeGridContainer.apply(this)); + $this.treegrid('getChildNodes').treegrid('initNode', settings); + $this.treegrid('initExpander').treegrid('initIndent').treegrid('initEvents').treegrid('initState').treegrid("initSettingsEvents"); + }); + }, + /** + * Initialize node events + * + * @returns {Node} + */ + initEvents: function() { + var $this = $(this); + //Save state on change + $this.on("change", function() { + var $this = $(this); + $this.treegrid('render'); + if ($this.treegrid('getSetting', 'saveState')) { + $this.treegrid('saveState'); + } + }); + //Default behavior on collapse + $this.on("collapse", function() { + var $this = $(this); + $this.removeClass('treegrid-expanded'); + $this.addClass('treegrid-collapsed'); + }); + //Default behavior on expand + $this.on("expand", function() { + var $this = $(this); + $this.removeClass('treegrid-collapsed'); + $this.addClass('treegrid-expanded'); + }); + + return $this; + }, + /** + * Initialize events from settings + * + * @returns {Node} + */ + initSettingsEvents: function() { + var $this = $(this); + //Save state on change + $this.on("change", function() { + var $this = $(this); + if (typeof ($this.treegrid('getSetting', 'onChange')) === "function") { + $this.treegrid('getSetting', 'onChange').apply($this); + } + }); + //Default behavior on collapse + $this.on("collapse", function() { + var $this = $(this); + if (typeof ($this.treegrid('getSetting', 'onCollapse')) === "function") { + $this.treegrid('getSetting', 'onCollapse').apply($this); + } + }); + //Default behavior on expand + $this.on("expand", function() { + var $this = $(this); + if (typeof ($this.treegrid('getSetting', 'onExpand')) === "function") { + $this.treegrid('getSetting', 'onExpand').apply($this); + } + + }); + + return $this; + }, + /** + * Initialize expander for node + * + * @returns {Node} + */ + initExpander: function() { + var $this = $(this); + var cell = $this.find('td').get($this.treegrid('getSetting', 'treeColumn')); + var tpl = $this.treegrid('getSetting', 'expanderTemplate'); + var expander = $this.treegrid('getSetting', 'getExpander').apply(this); + if (expander) { + expander.remove(); + } + $(tpl).prependTo(cell).click(function() { + $($(this).closest('tr')).treegrid('toggle'); + }); + return $this; + }, + /** + * Initialize indent for node + * + * @returns {Node} + */ + initIndent: function() { + var $this = $(this); + $this.find('.treegrid-indent').remove(); + for (var i = 0; i < $(this).treegrid('getDepth'); i++) { + $($this.treegrid('getSetting', 'indentTemplate')).insertBefore($this.find('.treegrid-expander')); + } + return $this; + }, + /** + * Initialise state of node + * + * @returns {Node} + */ + initState: function() { + var $this = $(this); + if ($this.treegrid('getSetting', 'saveState') && !$this.treegrid('isFirstInit')) { + $this.treegrid('restoreState'); + } else { + if ($this.treegrid('getSetting', 'initialState') === "expanded") { + $this.treegrid('expand'); + } else { + $this.treegrid('collapse'); + } + } + return $this; + }, + /** + * Return true if this tree was never been initialised + * + * @returns {Boolean} + */ + isFirstInit: function() { + var tree = $(this).treegrid('getTreeContainer'); + if (tree.data('first_init') === undefined) { + tree.data('first_init', $.cookie(tree.treegrid('getSetting', 'saveStateName')) === undefined); + } + return tree.data('first_init'); + }, + /** + * Save state of current node + * + * @returns {Node} + */ + saveState: function() { + var $this = $(this); + if ($this.treegrid('getSetting', 'saveStateMethod') === 'cookie') { + + var stateArrayString = $.cookie($this.treegrid('getSetting', 'saveStateName')) || ''; + var stateArray = (stateArrayString === '' ? [] : stateArrayString.split(',')); + var nodeId = $this.treegrid('getNodeId'); + + if ($this.treegrid('isExpanded')) { + if ($.inArray(nodeId, stateArray) === -1) { + stateArray.push(nodeId); + } + } else if ($this.treegrid('isCollapsed')) { + if ($.inArray(nodeId, stateArray) !== -1) { + stateArray.splice($.inArray(nodeId, stateArray), 1); + } + } + $.cookie($this.treegrid('getSetting', 'saveStateName'), stateArray.join(',')); + } + return $this; + }, + /** + * Restore state of current node. + * + * @returns {Node} + */ + restoreState: function() { + var $this = $(this); + if ($this.treegrid('getSetting', 'saveStateMethod') === 'cookie') { + var stateArray = $.cookie($this.treegrid('getSetting', 'saveStateName')).split(','); + if ($.inArray($this.treegrid('getNodeId'), stateArray) !== -1) { + $this.treegrid('expand'); + } else { + $this.treegrid('collapse'); + } + + } + return $this; + }, + /** + * Method return setting by name + * + * @param {type} name + * @returns {unresolved} + */ + getSetting: function(name) { + if (!$(this).treegrid('getTreeContainer')) { + return null; + } + return $(this).treegrid('getTreeContainer').data('settings')[name]; + }, + /** + * Add new settings + * + * @param {Object} settings + */ + setSettings: function(settings) { + $(this).treegrid('getTreeContainer').data('settings', settings); + }, + /** + * Return tree container + * + * @returns {HtmlElement} + */ + getTreeContainer: function() { + return $(this).data('treegrid'); + }, + /** + * Set tree container + * + * @param {HtmlE;ement} container + */ + setTreeContainer: function(container) { + return $(this).data('treegrid', container); + }, + /** + * Method return all root nodes of tree. + * + * Start init all child nodes from it. + * + * @returns {Array} + */ + getRootNodes: function() { + return $(this).treegrid('getSetting', 'getRootNodes').apply(this, [$(this).treegrid('getTreeContainer')]); + }, + /** + * Method return all nodes of tree. + * + * @returns {Array} + */ + getAllNodes: function() { + return $(this).treegrid('getSetting', 'getAllNodes').apply(this, [$(this).treegrid('getTreeContainer')]); + }, + /** + * Mthod return true if element is Node + * + * @returns {String} + */ + isNode: function() { + return $(this).treegrid('getNodeId') !== null; + }, + /** + * Mthod return id of node + * + * @returns {String} + */ + getNodeId: function() { + if ($(this).treegrid('getSetting', 'getNodeId') === null) { + return null; + } else { + return $(this).treegrid('getSetting', 'getNodeId').apply(this); + } + }, + /** + * Method return parent id of node or null if root node + * + * @returns {String} + */ + getParentNodeId: function() { + return $(this).treegrid('getSetting', 'getParentNodeId').apply(this); + }, + /** + * Method return parent node or null if root node + * + * @returns {Object[]} + */ + getParentNode: function() { + if ($(this).treegrid('getParentNodeId') === null) { + return null; + } else { + return $(this).treegrid('getSetting', 'getNodeById').apply(this, [$(this).treegrid('getParentNodeId'), $(this).treegrid('getTreeContainer')]); + } + }, + /** + * Method return array of child nodes or null if node is leaf + * + * @returns {Object[]} + */ + getChildNodes: function() { + return $(this).treegrid('getSetting', 'getChildNodes').apply(this, [$(this).treegrid('getNodeId'), $(this).treegrid('getTreeContainer')]); + }, + /** + * Method return depth of tree. + * + * This method is needs for calculate indent + * + * @returns {Number} + */ + getDepth: function() { + if ($(this).treegrid('getParentNode') === null) { + return 0; + } + return $(this).treegrid('getParentNode').treegrid('getDepth') + 1; + }, + /** + * Method return true if node is root + * + * @returns {Boolean} + */ + isRoot: function() { + return $(this).treegrid('getDepth') === 0; + }, + /** + * Method return true if node has no child nodes + * + * @returns {Boolean} + */ + isLeaf: function() { + return $(this).treegrid('getChildNodes').length === 0; + }, + /** + * Method return true if node last in branch + * + * @returns {Boolean} + */ + isLast: function() { + if ($(this).treegrid('isNode')) { + var parentNode = $(this).treegrid('getParentNode'); + if (parentNode === null) { + if ($(this).treegrid('getNodeId') === $(this).treegrid('getRootNodes').last().treegrid('getNodeId')) { + return true; + } + } else { + if ($(this).treegrid('getNodeId') === parentNode.treegrid('getChildNodes').last().treegrid('getNodeId')) { + return true; + } + } + } + return false; + }, + /** + * Method return true if node first in branch + * + * @returns {Boolean} + */ + isFirst: function() { + if ($(this).treegrid('isNode')) { + var parentNode = $(this).treegrid('getParentNode'); + if (parentNode === null) { + if ($(this).treegrid('getNodeId') === $(this).treegrid('getRootNodes').first().treegrid('getNodeId')) { + return true; + } + } else { + if ($(this).treegrid('getNodeId') === parentNode.treegrid('getChildNodes').first().treegrid('getNodeId')) { + return true; + } + } + } + return false; + }, + /** + * Return true if node expanded + * + * @returns {Boolean} + */ + isExpanded: function() { + return $(this).hasClass('treegrid-expanded'); + }, + /** + * Return true if node collapsed + * + * @returns {Boolean} + */ + isCollapsed: function() { + return $(this).hasClass('treegrid-collapsed'); + }, + /** + * Return true if at least one of parent node is collapsed + * + * @returns {Boolean} + */ + isOneOfParentsCollapsed: function() { + var $this = $(this); + if ($this.treegrid('isRoot')) { + return false; + } else { + if ($this.treegrid('getParentNode').treegrid('isCollapsed')) { + return true; + } else { + return $this.treegrid('getParentNode').treegrid('isOneOfParentsCollapsed'); + } + } + }, + /** + * Expand node + * + * @returns {Node} + */ + expand: function() { + return $(this).each(function() { + var $this = $(this); + if (!$this.treegrid('isLeaf') && !$this.treegrid("isExpanded")) { + $this.trigger("expand"); + $this.trigger("change"); + } + }); + }, + /** + * Expand all nodes + * + * @returns {Node} + */ + expandAll: function() { + var $this = $(this); + $this.treegrid('getRootNodes').treegrid('expandRecursive'); + return $this; + }, + /** + * Expand current node and all child nodes begin from current + * + * @returns {Node} + */ + expandRecursive: function() { + return $(this).each(function() { + var $this = $(this); + $this.treegrid('expand'); + if (!$this.treegrid('isLeaf')) { + $this.treegrid('getChildNodes').treegrid('expandRecursive'); + } + }); + }, + /** + * Collapse node + * + * @returns {Node} + */ + collapse: function() { + return $(this).each(function() { + var $this = $(this); + if (!$this.treegrid('isLeaf') && !$this.treegrid("isCollapsed")) { + $this.trigger("collapse"); + $this.trigger("change"); + } + }); + }, + /** + * Collapse all nodes + * + * @returns {Node} + */ + collapseAll: function() { + var $this = $(this); + $this.treegrid('getRootNodes').treegrid('collapseRecursive'); + return $this; + }, + /** + * Collapse current node and all child nodes begin from current + * + * @returns {Node} + */ + collapseRecursive: function() { + return $(this).each(function() { + var $this = $(this); + $this.treegrid('collapse'); + if (!$this.treegrid('isLeaf')) { + $this.treegrid('getChildNodes').treegrid('collapseRecursive'); + } + }); + }, + /** + * Expand if collapsed, Collapse if expanded + * + * @returns {Node} + */ + toggle: function() { + var $this = $(this); + if ($this.treegrid('isExpanded')) { + $this.treegrid('collapse'); + } else { + $this.treegrid('expand'); + } + return $this; + }, + /** + * Rendering node + * + * @returns {Node} + */ + render: function() { + return $(this).each(function() { + var $this = $(this); + + if ($this.treegrid('isOneOfParentsCollapsed')) { + $this.hide(); + } else { + $this.show(); + } + if (!$this.treegrid('isLeaf')) { + $this.treegrid('renderExpander'); + $this.treegrid('getChildNodes').treegrid('render'); + } + }); + }, + /** + * Rendering expander depends on node state + * + * @returns {Node} + */ + renderExpander: function() { + return $(this).each(function() { + var $this = $(this); + var expander = $this.treegrid('getSetting', 'getExpander').apply(this); + if (expander) { + + if (!$this.treegrid('isCollapsed')) { + expander.removeClass($this.treegrid('getSetting', 'expanderCollapsedClass')); + expander.addClass($this.treegrid('getSetting', 'expanderExpandedClass')); + } else { + expander.removeClass($this.treegrid('getSetting', 'expanderExpandedClass')); + expander.addClass($this.treegrid('getSetting', 'expanderCollapsedClass')); + } + } else { + $this.treegrid('initExpander'); + $this.treegrid('renderExpander'); + } + }); + } + }; + $.fn.treegrid = function(method) { + if (methods[method]) { + return methods[ method ].apply(this, Array.prototype.slice.call(arguments, 1)); + } else if (typeof method === 'object' || !method) { + return methods.initTree.apply(this, arguments); + } else { + $.error('Method with name ' + method + ' does not exists for jQuery.treegrid'); + } + }; + /** + * Plugin's default options + */ + $.fn.treegrid.defaults = { + initialState: 'expanded', + saveState: false, + saveStateMethod: 'cookie', + saveStateName: 'tree-grid-state', + expanderTemplate: '', + indentTemplate: '', + expanderExpandedClass: 'treegrid-expander-expanded', + expanderCollapsedClass: 'treegrid-expander-collapsed', + treeColumn: 0, + getExpander: function() { + return $(this).find('.treegrid-expander'); + }, + getNodeId: function() { + var template = /treegrid-([A-Za-z0-9_-]+)/; + if (template.test($(this).attr('class'))) { + return template.exec($(this).attr('class'))[1]; + } + return null; + }, + getParentNodeId: function() { + var template = /treegrid-parent-([A-Za-z0-9_-]+)/; + if (template.test($(this).attr('class'))) { + return template.exec($(this).attr('class'))[1]; + } + return null; + }, + getNodeById: function(id, treegridContainer) { + var templateClass = "treegrid-" + id; + return treegridContainer.find('tr.' + templateClass); + }, + getChildNodes: function(id, treegridContainer) { + var templateClass = "treegrid-parent-" + id; + return treegridContainer.find('tr.' + templateClass); + }, + getTreeGridContainer: function() { + return $(this).closest('table'); + }, + getRootNodes: function(treegridContainer) { + var result = $.grep(treegridContainer.find('tr'), function(element) { + var classNames = $(element).attr('class'); + var templateClass = /treegrid-([A-Za-z0-9_-]+)/; + var templateParentClass = /treegrid-parent-([A-Za-z0-9_-]+)/; + return templateClass.test(classNames) && !templateParentClass.test(classNames); + }); + return $(result); + }, + getAllNodes: function(treegridContainer) { + var result = $.grep(treegridContainer.find('tr'), function(element) { + var classNames = $(element).attr('class'); + var templateClass = /treegrid-([A-Za-z0-9_-]+)/; + return templateClass.test(classNames); + }); + return $(result); + }, + //Events + onCollapse: null, + onExpand: null, + onChange: null + + }; })(jQuery); \ No newline at end of file diff --git a/admin/view/template/extension/payment/emerchantpay_checkout.twig b/admin/view/template/extension/payment/emerchantpay_checkout.twig index 9a38257..fdbde37 100644 --- a/admin/view/template/extension/payment/emerchantpay_checkout.twig +++ b/admin/view/template/extension/payment/emerchantpay_checkout.twig @@ -147,6 +147,69 @@
+ +
+ + +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+ +
+ + +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+ + + + + + +
@@ -105,4 +112,6 @@ }); }); }); + + empPopulateBrowserParams.execute(document); diff --git a/composer.json b/composer.json index 7617012..f6b9d93 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,7 @@ "description": "emerchantpay Gateway Module for OpenCart", "type": "opencart-module", "license": "GPL-2.0", - "version": "1.1.3", + "version": "1.1.4", "authors": [ { "name": "emerchantpay", diff --git a/install.json b/install.json index b818387..ca75182 100644 --- a/install.json +++ b/install.json @@ -1,6 +1,6 @@ { "name": "emerchantpay Payments", - "version": "1.1.3", + "version": "1.1.4", "author": "emerchantpay Ltd.", "link": "https://emerchantpay.com" } diff --git a/system/admin/base_controller.php b/system/admin/base_controller.php index fb11a8b..b9d9c84 100644 --- a/system/admin/base_controller.php +++ b/system/admin/base_controller.php @@ -23,8 +23,12 @@ require DIR_STORAGE . 'vendor/genesisgateway/genesis_php/vendor/autoload.php'; } +use Exception; +use Genesis\API\Constants\Transaction\Parameters\ScaExemptions; use Genesis\API\Constants\Transaction\States; use Genesis\API\Constants\Transaction\Types; +use Opencart\Extension\Emerchantpay\System\Catalog\SettingsHelper; +use Opencart\Extension\Emerchantpay\System\Catalog\ThreedsHelper; use Opencart\Extension\Emerchantpay\System\EmerchantpayHelper; use Opencart\System\Engine\Controller; @@ -75,7 +79,8 @@ abstract class BaseController extends Controller 'transaction_type', 'order_status', 'order_async_status', - 'order_failure_status' + 'order_failure_status', + 'error_sca_exemption_amount', ); /** @@ -89,14 +94,14 @@ abstract protected function isModuleRequiresSsl(): bool; * BaseController constructor. * @param $registry * - * @throws \Exception + * @throws Exception */ public function __construct($registry) { parent::__construct($registry); if (is_null($this->module_name)) { - throw new \Exception('Module name not supplied in EMerchantPay controller'); + throw new Exception('Module name not supplied in EMerchantPay controller'); } } @@ -109,15 +114,18 @@ public function index() { if ($this->isInstallRequest()) { $this->install(); + return true; } elseif ($this->isUninstallRequest()) { $this->uninstall(); + return true; } elseif ($this->isOrderInfoRequest()) { return $this->orderAction(); } else if ($this->isModuleSubActionRequest(['getModalForm', 'capture', 'refund', 'void'])) { $method = $this->request->get['action']; call_user_func(array($this, $method)); + return true; } @@ -200,13 +208,11 @@ public function order() // 2. Sort by relations, i.e. every parent has the child nodes immediately after // Ascending Date/Timestamp sorting - // TODO Remove @ uasort($transactions, function ($element1, $element2) { - // sort by timestamp (date) first - if (@$element1["timestamp"] == @$element2["timestamp"]) { - return 0; - } - return (@$element1["timestamp"] > @$element2["timestamp"]) ? 1 : -1; + $timestamp1 = $element1['timestamp'] ?? null; + $timestamp2 = $element2['timestamp'] ?? null; + + return $timestamp1 <=> $timestamp2; }); // Create the parent/child relations from a flat array @@ -450,10 +456,8 @@ public function refund(): void if (isset($this->request->post['reference_id']) && trim($this->request->post['reference_id']) != '') { $this->loadPaymentMethodModel(); - $transaction = $this->getModelInstance()->getTransactionById($this->request->post['reference_id']); - - $terminal_token = - array_key_exists('terminal_token', $transaction) ? $transaction['terminal_token'] : null; + $transaction = $this->getModelInstance()->getTransactionById($this->request->post['reference_id']); + $terminal_token = array_key_exists('terminal_token', $transaction) ? $transaction['terminal_token'] : null; if (isset($transaction['order_id']) && intval($transaction['order_id']) > 0) { $amount = $this->request->post['amount']; @@ -470,8 +474,7 @@ public function refund(): void if (isset($refund->unique_id)) { $timestamp = ($refund->timestamp instanceof \DateTime) ? $refund->timestamp->format('c') : $refund->timestamp; - - $data = array( + $data = array( 'order_id' => $transaction['order_id'], 'reference_id' => $transaction['unique_id'], 'unique_id' => $refund->unique_id, @@ -480,8 +483,8 @@ public function refund(): void 'amount' => $refund->amount, 'currency' => $refund->currency, 'timestamp' => $timestamp, - 'message' => isset($refund->message) ? $refund->message : '', - 'technical_message' => isset($refund->technical_message) ? $refund->technical_message : '', + 'message' => $refund->message ?? '', + 'technical_message' => $refund->technical_message ?? '', ); if (array_key_exists('terminal_token', $transaction)) { @@ -542,10 +545,7 @@ public function refund(): void } $this->response->addHeader('Content-Type: application/json'); - - $this->response->setOutput( - json_encode($json) - ); + $this->response->setOutput(json_encode($json)); } /** @@ -1051,7 +1051,7 @@ protected function processPostIndexAction(): void $this->response->addHeader('Content-Type: application/json'); $this->response->setOutput(json_encode($json)); - } catch (\Exception $e) { + } catch (Exception $e) { $this->response->addHeader('HTTP/1.0 500 Internal Server Error'); } } @@ -1080,6 +1080,9 @@ protected function processGetIndexAction(): void $this->load->model('localisation/order_status'); $this->loadPaymentMethodModel(); + $threedshelper = new ThreedsHelper(); + $challenge_indicators = $threedshelper->getThreedsChallengeIndicators(); + $data = $this->buildLanguagePhrases(); $data += array( @@ -1091,31 +1094,6 @@ protected function processGetIndexAction(): void 'error_warning' => isset($this->error['warning']) ? $this->error['warning'] : '', 'enable_recurring_tab' => true, - // Settings - "{$this->module_name}_username" => $this->getFieldValue("{$this->module_name}_username"), - "{$this->module_name}_password" => $this->getFieldValue("{$this->module_name}_password"), - "{$this->module_name}_token" => $this->getFieldValue("{$this->module_name}_token"), - "{$this->module_name}_sandbox" => $this->getFieldValue("{$this->module_name}_sandbox"), - "{$this->module_name}_transaction_type" => $this->getFieldValue("{$this->module_name}_transaction_type"), - "{$this->module_name}_wpf_tokenization" => $this->getFieldValue("{$this->module_name}_wpf_tokenization"), - "{$this->module_name}_total" => $this->getFieldValue("{$this->module_name}_total"), - "{$this->module_name}_order_status_id" => $this->getFieldValue("{$this->module_name}_order_status_id"), - "{$this->module_name}_order_failure_status_id" => $this->getFieldValue("{$this->module_name}_order_failure_status_id"), - "{$this->module_name}_async_order_status_id" => $this->getFieldValue("{$this->module_name}_async_order_status_id"), - "{$this->module_name}_geo_zone_id" => $this->getFieldValue("{$this->module_name}_geo_zone_id"), - "{$this->module_name}_status" => $this->getFieldValue("{$this->module_name}_status"), - "{$this->module_name}_sort_order" => $this->getFieldValue("{$this->module_name}_sort_order"), - "{$this->module_name}_debug" => $this->getFieldValue("{$this->module_name}_debug"), - "{$this->module_name}_supports_partial_capture" => $this->getFieldValue("{$this->module_name}_supports_partial_capture"), - "{$this->module_name}_supports_partial_refund" => $this->getFieldValue("{$this->module_name}_supports_partial_refund"), - "{$this->module_name}_supports_void" => $this->getFieldValue("{$this->module_name}_supports_void"), - "{$this->module_name}_supports_recurring" => $this->getFieldValue("{$this->module_name}_supports_recurring"), - "{$this->module_name}_recurring_transaction_type" => $this->getFieldValue("{$this->module_name}_recurring_transaction_type"), - "{$this->module_name}_recurring_token" => $this->getFieldValue("{$this->module_name}_recurring_token"), - "{$this->module_name}_cron_allowed_ip" => $this->getFieldValue("{$this->module_name}_cron_allowed_ip"), - "{$this->module_name}_cron_time_limit" => $this->getFieldValue("{$this->module_name}_cron_time_limit"), - "{$this->module_name}_bank_codes" => $this->getFieldValue("{$this->module_name}_bank_codes"), - 'action' => $this->url->link("{$this->route_prefix}payment/{$this->module_name}", $this->getTokenParam() . '=' . $this->getToken(), true), // TODO I'm not sure if this is used somewhere 'cancel' => $this->getPaymentLink($this->getToken()), @@ -1127,27 +1105,23 @@ protected function processGetIndexAction(): void 'cron_last_execution' => $this->getLastCronExecTime(), 'cron_last_execution_status' => $this->getCronExecStatus(), - 'module_name' => $this->module_name + 'module_name' => $this->module_name, + 'threeds_challenge_indicators' => $challenge_indicators, + 'sca_exemptions' => $this->getModelInstance()->getScaExemptions() ); + $settings = new SettingsHelper($this); + + $data = array_merge($data, $settings->getBaseSettings($this->module_name)); + $data = array_merge($data, $settings->getModuleSettings($this->module_name)); + if ($this->module_name == 'emerchantpay_checkout') { - $data += ['bank_codes' => $this->getModelInstance()->getBankCodes()]; + $data += [ + 'bank_codes' => $this->getModelInstance()->getBankCodes(), + ]; } - $default_param_values = array( - "{$this->module_name}_sandbox" => 1, - "{$this->module_name}_status" => 0, - "{$this->module_name}_debug" => 1, - "{$this->module_name}_supports_partial_capture" => 1, - "{$this->module_name}_supports_partial_refund" => 1, - "{$this->module_name}_supports_void" => 1, - "{$this->module_name}_supports_recurring" => 0, - "{$this->module_name}_cron_allowed_ip" => $this->getServerAddress(), - "{$this->module_name}_cron_time_limit" => 25 - ); - - foreach ($default_param_values as $key => $default_value) - $data[$key] = (is_null($data[$key]) ? $default_value : $data[$key]); + $data = $settings->setDefaultOptions($data, $this->module_name); $data['breadcrumbs'] = array(); @@ -1218,6 +1192,10 @@ protected function buildLanguagePhrases(): array 'entry_cron_allowed_ip', 'entry_cron_last_execution', 'entry_bank_codes', + 'entry_threeds_allowed', + 'entry_threeds_challenge_indicator', + 'entry_sca_exemption', + 'entry_sca_exemption_value', 'entry_order_status', 'entry_async_order_status', @@ -1246,6 +1224,10 @@ protected function buildLanguagePhrases(): array 'help_cron_time_limit', 'help_cron_allowed_ip', 'help_cron_last_execution', + 'help_threeds_allowed', + 'help_threeds_challenge_indicator', + 'help_sca_exemption', + 'help_sca_exemption_value', 'button_save', 'button_cancel', @@ -1276,53 +1258,19 @@ protected function buildLanguagePhrases(): array */ protected function validate(): bool { + $this->validateRequiredFields(); + if (!$this->user->hasPermission('modify', "{$this->route_prefix}payment/{$this->module_name}")) { $this->error['warning'] = $this->language->get('error_permission'); } - if (empty($this->request->post["{$this->module_name}_username"])) { - $this->error['username'] = $this->language->get('error_username'); - } - - if (empty($this->request->post["{$this->module_name}_password"])) { - $this->error['password'] = $this->language->get('error_password'); - } - - if (empty($this->request->post["{$this->module_name}_transaction_type"])) { - $this->error['transaction_type'] = $this->language->get('error_transaction_type'); - } - - if (empty($this->request->post["{$this->module_name}_order_status_id"])) { - $this->error['order_status'] = $this->language->get('error_order_status'); - } - - if (empty($this->request->post["{$this->module_name}_order_failure_status_id"])) { - $this->error['order_failure_status'] = $this->language->get('error_order_failure_status'); - } - - if ($this->module_name === 'emerchantpay_direct' && empty($this->request->post["{$this->module_name}_async_order_status_id"])) { - $this->error['order_async_status'] = $this->language->get('error_async_order_status'); + if ((float)$this->request->post["{$this->module_name}_sca_exemption_amount"] < 0) { + $this->error['error_sca_exemption_amount'] = $this->language->get('error_sca_exemption_amount'); } return !$this->error; } - /** - * Check if there's a POST parameter or use the existing configuration value - * - * @param $key string - * - * @return mixed - */ - protected function getFieldValue($key): mixed - { - if (isset($this->request->post[$key])) { - return $this->request->post[$key]; - } - - return $this->config->get($key); - } - /** * Check if the current visitor is logged in and has permission to access * this page @@ -1600,20 +1548,6 @@ protected function getLink($link_parameters): string ); } - /** - * @return string - */ - protected function getServerAddress(): string - { - $server_name = $this->request->server['SERVER_NAME']; - - if (empty($server_name) || !function_exists('gethostbyname')) { - return $this->request->server['SERVER_ADDR']; - } - - return gethostbyname($server_name); - } - /** * Determine if Google Pay, PayPal ot Apple Pay Method is chosen inside the Payment settings * @@ -1706,8 +1640,6 @@ protected function checkReferenceActionByCustomAttr($action, $transaction_type): default: return false; } // end Switch - - return false; } /** @@ -1727,4 +1659,30 @@ protected function hasApprovedState($transaction_type): bool return $state->isApproved(); } + + /** + * Check if any of the required fields is empty + * + * @return void + */ + private function validateRequiredFields(): void + { + $required_fields = [ + "{$this->module_name}_username" => 'username', + "{$this->module_name}_password" => 'password', + "{$this->module_name}_transaction_type" => 'transaction_type', + "{$this->module_name}_order_status_id" => 'order_status', + "{$this->module_name}_order_failure_status_id" => 'order_failure_status', + ]; + + if ($this->module_name === 'emerchantpay_direct') { + $required_fields["{$this->module_name}_async_order_status_id"] = 'order_async_status'; + } + + foreach ($required_fields as $field => $error_key) { + if (empty($this->request->post[$field])) { + $this->error[$error_key] = $this->language->get("error_$error_key"); + } + } + } } diff --git a/system/catalog/base_controller.php b/system/catalog/base_controller.php index 5a55b6a..83f7991 100644 --- a/system/catalog/base_controller.php +++ b/system/catalog/base_controller.php @@ -23,13 +23,20 @@ require DIR_STORAGE . 'vendor/genesisgateway/genesis_php/vendor/autoload.php'; } +use Genesis\API\Constants\Transaction\Parameters\Threeds\V2\CardHolderAccount\RegistrationIndicators; +use Genesis\API\Constants\Transaction\Parameters\Threeds\V2\MerchantRisk\DeliveryTimeframes; +use Genesis\API\Constants\Transaction\Parameters\Threeds\V2\Purchase\Categories; +use Opencart\Catalog\Model\Extension\Emerchantpay\Payment\EmerchantpayCheckout as ModelEmerchantpayCheckout; use Opencart\Extension\Emerchantpay\System\EmerchantpayHelper; use Opencart\System\Engine\Controller; +use Opencart\System\Engine\Model; /** * Base Abstract Class for Method Front Controllers * * Class BaseController + * + * @SuppressWarnings(PHPMD.LongVariable) */ abstract class BaseController extends Controller { @@ -125,4 +132,236 @@ protected function populateAddresses($order_info, &$data): void ); } } + + /** + * Populate order data with 3DSv2 parameters + * + * @param Controller $controller + * @param array $product_info + * @param array $order_info + * @param $data + * + * @return array + */ + protected function populateTreedsParams($controller, $product_info, $order_info): array + { + $model_account_order = $controller->model_account_order; + $model_account_customer = $controller->model_account_customer; + + $emerchantpay_threeds_helper = new ThreedsHelper(); + + /** + * Get all customer's orders + * Default limit is 20, and they are sorted in descending order + */ + $customer_orders = $emerchantpay_threeds_helper->getCustomerOrders( + $controller->db, + $this->getCustomerId($controller), + (int)$controller->config->get('config_store_id'), + (int)$controller->config->get('config_language_id'), + ModelEmerchantpayCheckout::METHOD_CODE + ); + + $is_guest = !$controller->customer->isLogged(); + $has_physical_products = $emerchantpay_threeds_helper->hasPhysicalProduct($product_info); + $threeds_challenge_indicator = $controller->config->get('emerchantpay_checkout_threeds_challenge_indicator'); + + $threeds_purchase_category = $emerchantpay_threeds_helper->hasPhysicalProduct($product_info) ? Categories::GOODS : Categories::SERVICE; + $threeds_delivery_timeframe = ($has_physical_products) ? DeliveryTimeframes::ANOTHER_DAY : DeliveryTimeframes::ELECTRONICS; + $threeds_shipping_indicator = $emerchantpay_threeds_helper->getShippingIndicator($has_physical_products, $order_info, $is_guest); + $threeds_reorder_items_indicator = $emerchantpay_threeds_helper->getReorderItemsIndicator( + $model_account_order, + $is_guest, $product_info, + $customer_orders + ); + $threeds_registration_date = null; + $threeds_registration_indicator = RegistrationIndicators::GUEST_CHECKOUT; + + if (!$is_guest) { + $threeds_registration_date = $emerchantpay_threeds_helper->findFirstCustomerOrderDate($customer_orders); + $threeds_registration_indicator = $emerchantpay_threeds_helper->getRegistrationIndicator($threeds_registration_date); + $threeds_creation_date = $emerchantpay_threeds_helper->getCreationDate($model_account_customer, $order_info['customer_id']); + + $shipping_address_date_first_used = $emerchantpay_threeds_helper->findShippingAddressDateFirstUsed( + $model_account_order, + $order_info, + $customer_orders + ); + $threads_shipping_address_date_first_used = $shipping_address_date_first_used; + $threeds_shipping_address_usage_indicator = $emerchantpay_threeds_helper->getShippingAddressUsageIndicator($shipping_address_date_first_used); + + $orders_for_a_period = $emerchantpay_threeds_helper->findNumberOfOrdersForaPeriod( + $model_account_order, + $customer_orders + ); + $transactions_activity_last_24_hours = $orders_for_a_period['last_24h']; + $transactions_activity_previous_year = $orders_for_a_period['last_year']; + $purchases_count_last_6_months = $orders_for_a_period['last_6m']; + } + + $data = [ + 'is_guest' => $is_guest, + 'threeds_challenge_indicator' => $threeds_challenge_indicator, + 'threeds_purchase_category' => $threeds_purchase_category, + 'threeds_delivery_timeframe' => $threeds_delivery_timeframe, + 'threeds_shipping_indicator' => $threeds_shipping_indicator, + 'threeds_reorder_items_indicator' => $threeds_reorder_items_indicator, + 'threeds_registration_indicator' => $threeds_registration_indicator, + 'threeds_registration_date' => $threeds_registration_date, + 'sca_exemption_value' => $controller->config->get($controller->module_name . '_sca_exemption'), + 'sca_exemption_amount' => $controller->config->get($controller->module_name . '_sca_exemption_amount'), + ]; + + if (!$is_guest) { + $data['threeds_creation_date'] = $threeds_creation_date; + $data['threads_shipping_address_date_first_used'] = $threads_shipping_address_date_first_used; + $data['threeds_shipping_address_usage_indicator'] = $threeds_shipping_address_usage_indicator; + $data['transactions_activity_last_24_hours'] = $transactions_activity_last_24_hours; + $data['transactions_activity_previous_year'] = $transactions_activity_previous_year; + $data['purchases_count_last_6_months'] = $purchases_count_last_6_months; + } + + return $data; + } + + /** + * Return 0 if guest or customerId if customer is logged on + * + * @param $controller + * + * @return int + */ + protected function getCustomerId($controller): int + { + if ($controller->customer->isLogged()) { + return $controller->customer->getId(); + } + + return 0; + } + + /** + * Create the return urls + * + * @return array + */ + protected function buildActionUrls($module_name): array + { + return [ + 'notification_url' => + $this->buildUrl( + 'extension/emerchantpay/payment/' . $module_name, + 'callback' + ), + 'return_success_url' => + $this->buildUrl( + 'extension/emerchantpay/payment/' . $module_name, + 'success' + ), + 'return_failure_url' => + $this->buildUrl( + 'extension/emerchantpay/payment/' . $module_name, + 'failure' + ), + ]; + } + + /** + * Respond json error message + * + * @param $message + * + * @return void + */ + protected function respondWithError($message): void + { + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode(['error' => $message])); + } + + /** + * Return common request data + * + * @param Model $model + * @param $order_info + * + * @return array + */ + protected function populateCommonData($model, $order_info): array + { + return [ + 'transaction_id' => $model->genTransactionId(self::PLATFORM_TRANSACTION_PREFIX), + + 'remote_address' => EmerchantpayHelper::getFirstRemoteAddress($this->request->server['REMOTE_ADDR']), + + 'usage' => $model->getUsage(), + 'description' => $model->getOrderProducts($this->session->data['order_id']), + + 'currency' => $model->getCurrencyCode(), + 'amount' => (float)$order_info['total'], + + 'customer_email' => $order_info['email'], + 'customer_phone' => $order_info['telephone'], + ]; + } + + /** + * Get $data values upon UniqId + * + * @param $transaction + * @param $order_info + * + * @return array + */ + protected function populateDataUniqIdTrx($transaction, $order_info): array + { + $timestamp = ($transaction->timestamp instanceof \DateTime) ? $transaction->timestamp->format('c') : $transaction->timestamp; + + return [ + 'reference_id' => '0', + 'order_id' => $order_info['order_id'], + 'unique_id' => $transaction->unique_id, + 'type' => $transaction->transaction_type ?? 'checkout', + 'status' => $transaction->status, + 'message' => $transaction->message ?? '', + 'technical_message' => $transaction->technical_message ?? '', + 'amount' => $transaction->amount, + 'currency' => $transaction->currency, + 'timestamp' => $timestamp, + ]; + } + + /** + * Prepares data for the view when cart content is mixed + * + * @return array + */ + protected function prepareViewDataMixedCart(): array + { + return [ + 'text_loading' => $this->language->get('text_loading'), + 'text_payment_mixed_cart_content' => $this->language->get('text_payment_mixed_cart_content'), + 'button_shopping_cart' => $this->language->get('button_shopping_cart'), + 'button_target' => $this->buildUrl('checkout/cart') + ]; + } + + /** + * Adds recurring order + * + * @param string $payment_reference + * @param Model $model + * + * @return void + */ + public function addOrderRecurring($payment_reference, $model): void + { + $recurring_products = $this->cart->getRecurringProducts(); + if (!empty($recurring_products)) { + $model->addOrderRecurring( + $recurring_products, + $payment_reference + ); + } + } } diff --git a/system/catalog/settings_helper.php b/system/catalog/settings_helper.php new file mode 100644 index 0000000..4e85a84 --- /dev/null +++ b/system/catalog/settings_helper.php @@ -0,0 +1,159 @@ +controller = $controller; + } + + /** + * @param string $module_name + * + * @return array + */ + public function getBaseSettings($module_name) + { + return [ + "{$module_name}_username" => $this->getFieldValue("{$module_name}_username"), + "{$module_name}_password" => $this->getFieldValue("{$module_name}_password"), + "{$module_name}_token" => $this->getFieldValue("{$module_name}_token"), + "{$module_name}_sandbox" => $this->getFieldValue("{$module_name}_sandbox"), + ]; + + } + + /** + * @param string $module_name + * + * @return array + */ + public function getModuleSettings($module_name) + { + return [ + "{$module_name}_transaction_type" => $this->getFieldValue("{$module_name}_transaction_type"), + "{$module_name}_wpf_tokenization" => $this->getFieldValue("{$module_name}_wpf_tokenization"), + "{$module_name}_total" => $this->getFieldValue("{$module_name}_total"), + "{$module_name}_order_status_id" => $this->getFieldValue("{$module_name}_order_status_id"), + "{$module_name}_order_failure_status_id" => $this->getFieldValue("{$module_name}_order_failure_status_id"), + "{$module_name}_async_order_status_id" => $this->getFieldValue("{$module_name}_async_order_status_id"), + "{$module_name}_geo_zone_id" => $this->getFieldValue("{$module_name}_geo_zone_id"), + "{$module_name}_status" => $this->getFieldValue("{$module_name}_status"), + "{$module_name}_sort_order" => $this->getFieldValue("{$module_name}_sort_order"), + "{$module_name}_debug" => $this->getFieldValue("{$module_name}_debug"), + "{$module_name}_supports_partial_capture" => $this->getFieldValue("{$module_name}_supports_partial_capture"), + "{$module_name}_supports_partial_refund" => $this->getFieldValue("{$module_name}_supports_partial_refund"), + "{$module_name}_supports_void" => $this->getFieldValue("{$module_name}_supports_void"), + "{$module_name}_supports_recurring" => $this->getFieldValue("{$module_name}_supports_recurring"), + "{$module_name}_recurring_transaction_type" => $this->getFieldValue("{$module_name}_recurring_transaction_type"), + "{$module_name}_recurring_token" => $this->getFieldValue("{$module_name}_recurring_token"), + "{$module_name}_cron_allowed_ip" => $this->getFieldValue("{$module_name}_cron_allowed_ip"), + "{$module_name}_cron_time_limit" => $this->getFieldValue("{$module_name}_cron_time_limit"), + "{$module_name}_bank_codes" => $this->getFieldValue("{$module_name}_bank_codes"), + "{$module_name}_threeds_allowed" => $this->getFieldValue("{$module_name}_threeds_allowed"), + "{$module_name}_threeds_challenge_indicator" => $this->getFieldValue("{$module_name}_threeds_challenge_indicator"), + "{$module_name}_sca_exemption" => $this->getFieldValue("{$module_name}_sca_exemption"), + "{$module_name}_sca_exemption_amount" => $this->getFieldValue("{$module_name}_sca_exemption_amount"), + ]; + } + + /** + * @param array $data + * @param string $module_name + * + * @return mixed + */ + public function setDefaultOptions($data, $module_name) + { + $default_param_values = array( + "{$module_name}_sandbox" => 1, + "{$module_name}_status" => 0, + "{$module_name}_debug" => 1, + "{$module_name}_supports_partial_capture" => 1, + "{$module_name}_supports_partial_refund" => 1, + "{$module_name}_supports_void" => 1, + "{$module_name}_supports_recurring" => 0, + "{$module_name}_cron_allowed_ip" => $this->getServerAddress(), + "{$module_name}_cron_time_limit" => 25, + "{$module_name}_threeds_allowed" => 1, + "{$module_name}_threeds_challenge_indicator" => ChallengeIndicators::NO_PREFERENCE, + "{$module_name}_sca_exemption" => ScaExemptions::EXEMPTION_LOW_RISK, + "{$module_name}_sca_exemption_amount" => 100, + ); + + foreach ($default_param_values as $key => $default_value) + $data[$key] = $data[$key] ?? $default_value; + + return $data; + } + + /** + * @return string + */ + private function getServerAddress(): string + { + $server_name = $this->controller->request->server['SERVER_NAME']; + + if (empty($server_name) || !function_exists('gethostbyname')) { + return $this->controller->request->server['SERVER_ADDR']; + } + + return gethostbyname($server_name); + } + + /** + * Check if there's a POST parameter or use the existing configuration value + * + * @param string $key + * + * @return mixed + */ + public function getFieldValue($key): mixed + { + if (isset($this->controller->request->post[$key])) { + return $this->controller->request->post[$key]; + } + + return $this->controller->config->get($key); + } +} diff --git a/system/catalog/threeds_helper.php b/system/catalog/threeds_helper.php new file mode 100644 index 0000000..dc6ffad --- /dev/null +++ b/system/catalog/threeds_helper.php @@ -0,0 +1,466 @@ +areAddressesSame($order_info)) { + $indicator = ShippingIndicators::SAME_AS_BILLING; + } + } + + return $indicator; + } + + /** + * Get Reorder indicator + * + * @param Model $model + * @param bool $is_quest + * @param array $product_info + * + * @return string + */ + public function getReorderItemsIndicator($model, $is_quest, $product_info, $customer_orders) + { + if ($is_quest) { + return ReorderItemIndicators::FIRST_TIME; + } + + $bought_product_ids = $this->getBoughtProducts($model, $customer_orders); + $product_ids = array_column($product_info, 'product_id'); + + foreach ($product_ids as $product_id) { + if (in_array($product_id, $bought_product_ids)) { + return ReorderItemIndicators::REORDERED; + } + } + + return ReorderItemIndicators::FIRST_TIME; + } + + /** + * Get Shipping indicator + * + * @param string $date + * + * @return string + */ + public function getShippingAddressUsageIndicator($date) + { + return $this->getIndicatorValue($date, ShippingAddressUsageIndicators::class); + } + + /** + * Get Registration indicator + * + * @param string $order_date + * + * @return string + */ + public function getRegistrationIndicator($order_date) + { + return $this->getIndicatorValue($order_date, RegistrationIndicators::class); + } + + /** + * Find the date when customer placed first order + * + * @param Model $model + * + * @return string + */ + public function findFirstCustomerOrderDate($customer_orders) + { + $order_date = (new DateTime())->format(self::OC_DATETIME_FORMAT); + + if (CommonUtils::isValidArray($customer_orders)) { + $order_date = $customer_orders[0]['date_added']; + } + + return $order_date; + } + + /** + * Date when the customer has been registered + * + * @param Model $model + * @param string $customer_id + * + * @return string + */ + public function getCreationDate($model, $customer_id) + { + $customer = $model->getCustomer($customer_id); + + return $customer['date_added']; + } + + /** + * Finds the date when current shipping address has been used for the first time + * + * @param Model $model + * @param array $order_info + * + * @return string + */ + public function findShippingAddressDateFirstUsed($model, $order_info, $customer_orders) + { + $cart_shipping_address = [ + $order_info['shipping_firstname'], + $order_info['shipping_lastname'], + $order_info['shipping_address_1'], + $order_info['shipping_address_2'], + $order_info['shipping_postcode'], + $order_info['shipping_city'], + $order_info['shipping_zone_code'], + $order_info['shipping_country_id'], + ]; + + if (CommonUtils::isValidArray($customer_orders)) { + foreach ($customer_orders as $customer_order) { + $order = $model->getOrder($customer_order['order_id']); + $order_shipping_address = [ + $order['shipping_firstname'], + $order['shipping_lastname'], + $order['shipping_address_1'], + $order['shipping_address_2'], + $order['shipping_postcode'], + $order['shipping_city'], + $order['shipping_zone_code'], + $order['shipping_country_id'], + ]; + + if (count(array_diff($cart_shipping_address, $order_shipping_address)) === 0) { + return $customer_order['date_added']; + } + } + } + + return (new DateTime())->format(self::OC_DATETIME_FORMAT); + } + + /** + * How many orders has been placed for a given period + * + * @param Model $model + * + * @return array + * + * @throws Exception + */ + public function findNumberOfOrdersForaPeriod($model, $customer_orders) + { + $customer_orders = array_reverse($customer_orders); + $start_date_last_24h = (new DateTime())->sub(new DateInterval(self::ACTIVITY_24_HOURS)); + $start_date_last_6m = (new DateTime())->sub(new DateInterval(self::ACTIVITY_6_MONTHS)); + $start_date_last_year = (new DateTime())->sub(new DateInterval(self::ACTIVITY_1_YEAR)); + + $number_of_orders_last_24h = 0; + $number_of_orders_last_6m = 0; + $number_of_orders_last_year = 0; + + if (CommonUtils::isValidArray($customer_orders)) { + foreach ($customer_orders as $customer_order) { + $order_date = DateTime::createFromFormat( + self::OC_DATETIME_FORMAT, + $customer_order['date_added'] + ); + + // We don't need orders older than a year + if ($order_date < $start_date_last_year) { + break; + } + + // Get order details only if the order was placed within the last 6 months + if ($order_date >= $start_date_last_6m) { + $order = $model->getOrder($customer_order['order_id']); + + // Check if the order status is complete or shipped + $number_of_orders_last_6m += (in_array($order['order_status_id'], $this->complete_statuses)) ? 1 : 0; + } + + $number_of_orders_last_24h += ($order_date >= $start_date_last_24h) ? 1 : 0; + $number_of_orders_last_year++; + } + } + + return [ + 'last_24h' => $number_of_orders_last_24h, + 'last_6m' => $number_of_orders_last_6m, + 'last_year' => $number_of_orders_last_year + ]; + } + + /** + * Get list of customer orders, filtered by payment code + * + * @param object $db_obj database object + * @param int $customer_id current customer's id + * @param int $store_id Store id from config file + * @param int $language_id Language id from config, to have translated order's status + * @param string $payment_code We want to check for particular payment method + * + * @return array + */ + public static function getCustomerOrders($db_obj, $customer_id, $store_id, $language_id, $payment_code) + { + $raw_query = sprintf(" + SELECT + o.order_id, + o.firstname, + o.lastname, + os.name as status, + o.date_added, + o.total, + o.currency_code, + o.currency_value + FROM + `%1\$sorder` o + LEFT JOIN + %1\$sorder_status os ON (o.order_status_id = os.order_status_id) + WHERE + o.customer_id = '%2\$d' AND + o.order_status_id > 0 AND + o.store_id = '%3\$d' AND + os.language_id = '%4\$d' AND + JSON_SEARCH(o.payment_method, 'one', '%5\$s') IS NOT NULL + ORDER BY + o.date_added ASC", + DB_PREFIX, + $customer_id, + $store_id, + $language_id, + $payment_code + ); + $query = $db_obj->query($raw_query); + + return $query->rows; + } + + /** + * Returns formatted array with available threeds challenge indicators + * + * @return array + */ + public function getThreedsChallengeIndicators() + { + $data = []; + $challenge_indicators = [ + ChallengeIndicators::NO_PREFERENCE => 'No preference', + ChallengeIndicators::NO_CHALLENGE_REQUESTED => 'No challenge requested', + ChallengeIndicators::PREFERENCE => 'Preference', + ChallengeIndicators::MANDATE => 'Mandate' + ]; + + foreach ($challenge_indicators as $value => $label) { + $data[] = [ + 'id' => $value, + 'name' => $label + ]; + } + + return $data; + } + + /** + * Compare billing and shipping addresses + * + * @param array $order_info + * + * @return bool + */ + private function areAddressesSame($order_info) + { + $shipping = [ + $order_info['shipping_firstname'], + $order_info['shipping_lastname'], + $order_info['shipping_address_1'], + $order_info['shipping_address_2'], + $order_info['shipping_postcode'], + $order_info['shipping_city'], + $order_info['shipping_zone_code'], + $order_info['shipping_iso_code_2'], + ]; + + $billing = [ + $order_info['payment_firstname'], + $order_info['payment_lastname'], + $order_info['payment_address_1'], + $order_info['payment_address_2'], + $order_info['payment_postcode'], + $order_info['payment_city'], + $order_info['payment_zone_code'], + $order_info['payment_iso_code_2'], + ]; + + return count(array_diff($shipping, $billing) ) === 0; + } + + /** + * Returns distinct array of all bought products by this customer + * + * @param Model $model + * @param array $customer_orders + * + * @return array + */ + private function getBoughtProducts($model, $customer_orders) + { + $bought_products = []; + $order_ids = array_column($customer_orders, 'order_id'); + + foreach ($order_ids as $order_id) { + $order_products = $model->getProducts($order_id); + $bought_products = array_merge($bought_products, array_column($order_products, 'product_id')); + } + + return $bought_products; + } + + /** + * Get indicator value according the given period of time + * + * @param string $date + * @param string $indicator_class + * + * @return string + */ + private function getIndicatorValue($date, $indicator_class) + { + switch ($this->getDateIndicator($date)) { + case static::LESS_THAN_30_DAYS_INDICATOR: + return $indicator_class::LESS_THAN_30DAYS; + case static::MORE_THAN_30_LESS_THAN_60_INDICATOR: + return $indicator_class::FROM_30_TO_60_DAYS; + case static::MORE_THAN_60_DAYS_INDICATOR: + return $indicator_class::MORE_THAN_60DAYS; + default: + return $indicator_class::CURRENT_TRANSACTION; + } + } + + /** + * Check if date is less than 30, between 30 and 60 or more than 60 days + * + * @param string $date + * + * @return string + */ + private function getDateIndicator($date) + { + $now = new DateTime(); + $check_date = DateTime::createFromFormat(self::OC_DATETIME_FORMAT, $date); + $days = $check_date->diff($now)->days; + + if ($days < 1) { + return self::CURRENT_TRANSACTION_INDICATOR; + } + if ($days < 30) { + return self::LESS_THAN_30_DAYS_INDICATOR; + } + if ($days < 60) { + return self::MORE_THAN_30_LESS_THAN_60_INDICATOR; + } + + return self::MORE_THAN_60_DAYS_INDICATOR; + } +} diff --git a/system/emerchantpay_helper.php b/system/emerchantpay_helper.php index bf0d5f2..c80a8d8 100644 --- a/system/emerchantpay_helper.php +++ b/system/emerchantpay_helper.php @@ -248,4 +248,18 @@ public static function isSecureConnection($request): bool return false; } + + /** + * Return the first ip address from the list + * + * @param string $remote_address + * + * @return string + */ + public static function getFirstRemoteAddress($remote_address): string + { + $ips = explode(",", $remote_address); + + return trim($ips[0]); + } } diff --git a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Constants/BankAccountTypes.php b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Constants/BankAccountTypes.php index c659505..64eb841 100644 --- a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Constants/BankAccountTypes.php +++ b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Constants/BankAccountTypes.php @@ -46,12 +46,18 @@ class BankAccountTypes */ const MAESTRA_ACCOUNTS = 'M'; + /** + * P: for Payment accounts + */ + const PAYMENT_ACCOUNT = 'P'; + public static function getAll() { return [ self::CHECKING_ACCOUNT, self::SAVINGS_ACCOUNT, - self::MAESTRA_ACCOUNTS + self::MAESTRA_ACCOUNTS, + self::PAYMENT_ACCOUNT ]; } } diff --git a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Constants/Transaction/CustomRequiredParameters.php b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Constants/Transaction/CustomRequiredParameters.php index d29eaba..9418122 100644 --- a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Constants/Transaction/CustomRequiredParameters.php +++ b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Constants/Transaction/CustomRequiredParameters.php @@ -110,4 +110,16 @@ public static function forKlarnaAuthorize() 'billing_country' => Authorize::getAllowedCountries() ]; } + + /** + * Required custom attribute for Paysafecard + * + * @return array + */ + public static function forPaysafecard() + { + return [ + 'customer_id' => null + ]; + } } diff --git a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Constants/Transaction/States.php b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Constants/Transaction/States.php index c3e36ad..1da8126 100644 --- a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Constants/Transaction/States.php +++ b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Constants/Transaction/States.php @@ -54,6 +54,7 @@ * @method bool isTimeout() * @method bool isChargebacked() * @method bool isChargebackReversed() + * @method bool isRepresentmentReversed() * @method bool isPreArbitrated() * @method bool isActive() * @method bool isInvalidated() @@ -207,6 +208,11 @@ class States */ const CHARGEBACK_REVERSAL = 'chargeback_reversal'; + /** + * Once a represented transaction is reversed, the state changes to representment reversed. + */ + const REPRESENTMENT_REVERSED = 'representment_reversed'; + /** * The transaction is on hold, a manual review needs to be performed. */ diff --git a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request.php b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request.php index ab2032d..892c95f 100644 --- a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request.php +++ b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request.php @@ -349,8 +349,7 @@ protected function initApiGatewayConfiguration( $requestPath = 'process', $includeToken = true, $subdomain = 'gateway' - ) - { + ) { $this->setApiConfig( 'url', $this->buildRequestURL( diff --git a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Base/Financial.php b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Base/Financial.php index 95e91f0..a796a33 100644 --- a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Base/Financial.php +++ b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Base/Financial.php @@ -26,7 +26,8 @@ namespace Genesis\API\Request\Base; use Genesis\API\Traits\Request\BaseAttributes; -use Genesis\API\Validators\Request\Base\Validator as RequestValidator; +use Genesis\Config; +use Genesis\Exceptions\EnvironmentNotSet; use Genesis\Utils\Common as CommonUtils; /** @@ -35,11 +36,33 @@ * Base Abstract Class for all Financial Requests * * @package Genesis\API\Request\Base + * + * @method getUseSmartRouter() Get Smart Router usage. Whether Financial transaction endpoint is a Smart Router or not. */ abstract class Financial extends \Genesis\API\Request { use BaseAttributes; + /** + * Force Smart Router endpoint for Financial transactions + * + * @var bool + */ + protected $use_smart_router = false; + + /** + * Use Smart Router endpoint for Financial transactions + * + * @param $value + * @return $this + */ + public function setUseSmartRouter($value) + { + $this->use_smart_router = CommonUtils::toBoolean($value); + + return $this; + } + /** * Returns the Request transaction type * @return string @@ -54,27 +77,37 @@ abstract protected function getPaymentTransactionStructure(); /** * Initialize per-request configuration + * + * @throws EnvironmentNotSet */ protected function initConfiguration() { $this->initXmlConfiguration(); $this->initApiGatewayConfiguration(); + + if (Config::getForceSmartRouting()) { + $this->initializeSmartRouter(); + } } /** - * Perform field validation + * Process Request Params * * @return void - * @throws \Genesis\Exceptions\InvalidArgument + * + * @throws EnvironmentNotSet * @throws \Genesis\Exceptions\ErrorParameter + * @throws \Genesis\Exceptions\InvalidArgument * @throws \Genesis\Exceptions\InvalidClassMethod */ - protected function checkRequirements() + protected function processRequestParameters() { - parent::checkRequirements(); + if ($this->getUseSmartRouter()) { + $this->initializeSmartRouter(); + } - $this->validateConditionalValuesRequirements(); + parent::processRequestParameters(); } /** @@ -97,4 +130,15 @@ protected function populateStructure() $this->treeStructure = \Genesis\Utils\Common::createArrayObject($treeStructure); } + + /** + * Initialize Smart Router endpoint + * + * @return void + * @throws \Genesis\Exceptions\EnvironmentNotSet + */ + protected function initializeSmartRouter() + { + $this->initApiGatewayConfiguration('transactions', false, 'smart_router'); + } } diff --git a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Authorize.php b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Authorize.php index 6bd9935..9de00a3 100644 --- a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Authorize.php +++ b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Authorize.php @@ -39,6 +39,7 @@ use Genesis\API\Traits\Request\MotoAttributes; use Genesis\API\Traits\Request\AddressInfoAttributes; use Genesis\API\Traits\Request\RiskAttributes; +use Genesis\API\Traits\Request\Financial\AccountOwnerAttributes; use Genesis\API\Traits\Request\Financial\DescriptorAttributes; use Genesis\API\Traits\Request\Financial\TravelData\TravelDataAttributes; use Genesis\API\Traits\Request\Financial\FundingAttributes; @@ -56,7 +57,8 @@ class Authorize extends \Genesis\API\Request\Base\Financial\Cards\CreditCard use GamingAttributes, MotoAttributes, AddressInfoAttributes, RiskAttributes, DescriptorAttributes, PreauthorizationAttributes, TravelDataAttributes, FxRateAttributes, CryptoAttributes, BusinessAttributes, ScaAttributes, UcofAttributes, RecurringTypeAttributes, - ManagedRecurringAttributes, RecurringCategoryAttributes, ReferenceAttributes, FundingAttributes; + ManagedRecurringAttributes, RecurringCategoryAttributes, ReferenceAttributes, FundingAttributes, + AccountOwnerAttributes; /** * Returns the Request transaction type @@ -148,7 +150,8 @@ protected function getTransactionAttributes() 'managed_recurring' => $this->getManagedRecurringAttributesStructure(), 'recurring_category' => $this->recurring_category, 'reference_id' => $this->reference_id, - 'funding' => $this->getFundingAttributesStructure() + 'funding' => $this->getFundingAttributesStructure(), + 'account_owner' => $this->getAccountOwnerAttributesStructure() ], $this->getScaAttributesStructure(), $this->getUcofAttributesStructure() diff --git a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Authorize3D.php b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Authorize3D.php index 7b41837..5c277f6 100644 --- a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Authorize3D.php +++ b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Authorize3D.php @@ -39,6 +39,7 @@ use Genesis\API\Traits\Request\Financial\AsyncAttributes; use Genesis\API\Traits\Request\AddressInfoAttributes; use Genesis\API\Traits\Request\RiskAttributes; +use Genesis\API\Traits\Request\Financial\AccountOwnerAttributes; use Genesis\API\Traits\Request\Financial\DescriptorAttributes; use Genesis\API\Traits\Request\Financial\FundingAttributes; use Genesis\API\Traits\Request\Financial\TravelData\TravelDataAttributes; @@ -59,7 +60,7 @@ class Authorize3D extends \Genesis\API\Request\Base\Financial\Cards\CreditCard3D RiskAttributes, DescriptorAttributes, PreauthorizationAttributes, TravelDataAttributes, ScaAttributes, FxRateAttributes, CryptoAttributes, BusinessAttributes, RecurringTypeAttributes, ManagedRecurringAttributes, RecurringCategoryAttributes, - FundingAttributes; + FundingAttributes, AccountOwnerAttributes; /** * Returns the Request transaction type @@ -166,7 +167,8 @@ protected function getTransactionAttributes() 'recurring_type' => $this->getRecurringType(), 'managed_recurring' => $this->getManagedRecurringAttributesStructure(), 'recurring_category' => $this->recurring_category, - 'funding' => $this->getFundingAttributesStructure() + 'funding' => $this->getFundingAttributesStructure(), + 'account_owner' => $this->getAccountOwnerAttributesStructure() ], $this->getScaAttributesStructure(), $this->get3DSTransactionAttributes() diff --git a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Credit.php b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Credit.php index 0f973da..bc0a50f 100644 --- a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Credit.php +++ b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Credit.php @@ -25,6 +25,7 @@ namespace Genesis\API\Request\Financial\Cards; +use Genesis\API\Traits\Request\Financial\AccountOwnerAttributes; use Genesis\API\Traits\Request\Financial\CustomerIdentificationData; use Genesis\API\Traits\Request\Financial\SourceOfFundsAttributes; @@ -37,7 +38,7 @@ */ class Credit extends \Genesis\API\Request\Base\Financial\Reference { - use SourceOfFundsAttributes, CustomerIdentificationData; + use SourceOfFundsAttributes, CustomerIdentificationData, AccountOwnerAttributes; /** * Returns the Request transaction type @@ -59,7 +60,8 @@ protected function getPaymentTransactionStructure() parent::getPaymentTransactionStructure(), $this->getSourceOfFundsStructure(), [ - 'customer_identification' => $this->getCustomerIdentificationDataStructure() + 'customer_identification' => $this->getCustomerIdentificationDataStructure(), + 'account_owner' => $this->getAccountOwnerAttributesStructure() ] ); } diff --git a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Payout.php b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Payout.php index 84c7b7b..87e14ec 100644 --- a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Payout.php +++ b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Payout.php @@ -29,6 +29,7 @@ use Genesis\API\Traits\Request\Financial\DescriptorAttributes; use Genesis\API\Traits\Request\Financial\FxRateAttributes; use Genesis\API\Traits\Request\AddressInfoAttributes; +use Genesis\API\Traits\Request\Financial\AccountOwnerAttributes; use Genesis\API\Traits\Request\Financial\SourceOfFundsAttributes; use Genesis\API\Traits\Request\Payout\MoneyTransferPayoutAttributes; use Genesis\Utils\Common as CommonUtils; @@ -44,7 +45,7 @@ class Payout extends \Genesis\API\Request\Base\Financial\Cards\CreditCard { use AddressInfoAttributes, SourceOfFundsAttributes, FxRateAttributes, DescriptorAttributes, MoneyTransferPayoutAttributes, - CustomerIdentificationData; + CustomerIdentificationData, AccountOwnerAttributes; const MONEY_TRANSFER_SENDER_ACCOUNT_NUMBER_MAX_LENGTH = 33; const MONEY_TRANSFER_SERVICE_PROVIDER_NAME_MAX_LENGTH = 25; @@ -91,6 +92,7 @@ protected function getTransactionAttributes() 'dynamic_descriptor_params' => $this->getDynamicDescriptorParamsStructure(), 'money_transfer' => $this->getMoneyTransferPayoutStructure(), 'customer_identification' => $this->getCustomerIdentificationDataStructure(), + 'account_owner' => $this->getAccountOwnerAttributesStructure() ], $this->getSourceOfFundsStructure() ); diff --git a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Recurring/InitRecurringSale.php b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Recurring/InitRecurringSale.php index ddd5713..042ce9c 100644 --- a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Recurring/InitRecurringSale.php +++ b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Recurring/InitRecurringSale.php @@ -32,6 +32,7 @@ use Genesis\API\Traits\Request\MotoAttributes; use Genesis\API\Traits\Request\AddressInfoAttributes; use Genesis\API\Traits\Request\RiskAttributes; +use Genesis\API\Traits\Request\Financial\AccountOwnerAttributes; use Genesis\API\Traits\Request\Financial\DescriptorAttributes; use Genesis\API\Traits\Request\Financial\FundingAttributes; use Genesis\API\Traits\Request\Financial\TravelData\TravelDataAttributes; @@ -48,7 +49,7 @@ class InitRecurringSale extends \Genesis\API\Request\Base\Financial\Cards\Credit { use MotoAttributes, AddressInfoAttributes, RiskAttributes, DescriptorAttributes, TravelDataAttributes, FxRateAttributes, BusinessAttributes, - ManagedRecurringAttributes, RecurringCategoryAttributes, FundingAttributes; + ManagedRecurringAttributes, RecurringCategoryAttributes, FundingAttributes, AccountOwnerAttributes; /** * Returns the Request transaction type @@ -112,7 +113,8 @@ protected function getTransactionAttributes() 'business_attributes' => $this->getBusinessAttributesStructure(), 'managed_recurring' => $this->getManagedRecurringAttributesStructure(), 'recurring_category' => $this->recurring_category, - 'funding' => $this->getFundingAttributesStructure() + 'funding' => $this->getFundingAttributesStructure(), + 'account_owner' => $this->getAccountOwnerAttributesStructure() ]; } } diff --git a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Recurring/InitRecurringSale3D.php b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Recurring/InitRecurringSale3D.php index 282c845..db0fbea 100644 --- a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Recurring/InitRecurringSale3D.php +++ b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Recurring/InitRecurringSale3D.php @@ -35,6 +35,7 @@ use Genesis\API\Traits\Request\Financial\AsyncAttributes; use Genesis\API\Traits\Request\AddressInfoAttributes; use Genesis\API\Traits\Request\RiskAttributes; +use Genesis\API\Traits\Request\Financial\AccountOwnerAttributes; use Genesis\API\Traits\Request\Financial\DescriptorAttributes; use Genesis\API\Traits\Request\Financial\FundingAttributes; use Genesis\API\Traits\Request\Financial\TravelData\TravelDataAttributes; @@ -54,7 +55,7 @@ class InitRecurringSale3D extends \Genesis\API\Request\Base\Financial\Cards\Cred use MotoAttributes, NotificationAttributes, AsyncAttributes, AddressInfoAttributes, RiskAttributes, DescriptorAttributes, TravelDataAttributes, ScaAttributes, FxRateAttributes, BusinessAttributes, - ManagedRecurringAttributes, RecurringCategoryAttributes, FundingAttributes; + ManagedRecurringAttributes, RecurringCategoryAttributes, FundingAttributes, AccountOwnerAttributes; /** * Returns the Request transaction type @@ -154,7 +155,8 @@ protected function getTransactionAttributes() 'business_attributes' => $this->getBusinessAttributesStructure(), 'managed_recurring' => $this->getManagedRecurringAttributesStructure(), 'recurring_category' => $this->recurring_category, - 'funding' => $this->getFundingAttributesStructure() + 'funding' => $this->getFundingAttributesStructure(), + 'account_owner' => $this->getAccountOwnerAttributesStructure() ], $this->getScaAttributesStructure(), $this->get3DSTransactionAttributes() diff --git a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Sale.php b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Sale.php index 7f4d9d0..48ecd4e 100644 --- a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Sale.php +++ b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Sale.php @@ -37,6 +37,7 @@ use Genesis\API\Traits\Request\MotoAttributes; use Genesis\API\Traits\Request\AddressInfoAttributes; use Genesis\API\Traits\Request\RiskAttributes; +use Genesis\API\Traits\Request\Financial\AccountOwnerAttributes; use Genesis\API\Traits\Request\Financial\DescriptorAttributes; use Genesis\API\Traits\Request\Financial\ReferenceAttributes; use Genesis\API\Traits\Request\Financial\FundingAttributes; @@ -56,7 +57,7 @@ class Sale extends \Genesis\API\Request\Base\Financial\Cards\CreditCard use GamingAttributes, MotoAttributes, AddressInfoAttributes, RiskAttributes, DescriptorAttributes, ReferenceAttributes, TravelDataAttributes, FxRateAttributes, CryptoAttributes, BusinessAttributes, ScaAttributes, UcofAttributes, RecurringTypeAttributes, - ManagedRecurringAttributes, RecurringCategoryAttributes, FundingAttributes; + ManagedRecurringAttributes, RecurringCategoryAttributes, FundingAttributes, AccountOwnerAttributes; /** * Returns the Request transaction type @@ -147,7 +148,8 @@ protected function getTransactionAttributes() 'recurring_type' => $this->getRecurringType(), 'managed_recurring' => $this->getManagedRecurringAttributesStructure(), 'recurring_category' => $this->recurring_category, - 'funding' => $this->getFundingAttributesStructure() + 'funding' => $this->getFundingAttributesStructure(), + 'account_owner' => $this->getAccountOwnerAttributesStructure() ], $this->getScaAttributesStructure(), $this->getUcofAttributesStructure() diff --git a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Sale3D.php b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Sale3D.php index b676c3a..8369ebc 100644 --- a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Sale3D.php +++ b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Cards/Sale3D.php @@ -38,6 +38,7 @@ use Genesis\API\Traits\Request\Financial\AsyncAttributes; use Genesis\API\Traits\Request\AddressInfoAttributes; use Genesis\API\Traits\Request\RiskAttributes; +use Genesis\API\Traits\Request\Financial\AccountOwnerAttributes; use Genesis\API\Traits\Request\Financial\DescriptorAttributes; use Genesis\API\Traits\Request\Financial\ReferenceAttributes; use Genesis\API\Traits\Request\Financial\FundingAttributes; @@ -59,7 +60,7 @@ class Sale3D extends \Genesis\API\Request\Base\Financial\Cards\CreditCard3D AddressInfoAttributes, RiskAttributes, DescriptorAttributes, ReferenceAttributes, TravelDataAttributes, ScaAttributes, FxRateAttributes, CryptoAttributes, BusinessAttributes, RecurringTypeAttributes, - ManagedRecurringAttributes, RecurringCategoryAttributes, FundingAttributes; + ManagedRecurringAttributes, RecurringCategoryAttributes, FundingAttributes, AccountOwnerAttributes; /** * Returns the Request transaction type @@ -166,7 +167,8 @@ protected function getTransactionAttributes() 'recurring_type' => $this->getRecurringType(), 'managed_recurring' => $this->getManagedRecurringAttributesStructure(), 'recurring_category' => $this->recurring_category, - 'funding' => $this->getFundingAttributesStructure() + 'funding' => $this->getFundingAttributesStructure(), + 'account_owner' => $this->getAccountOwnerAttributesStructure() ], $this->getScaAttributesStructure(), $this->get3DSTransactionAttributes() diff --git a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Mobile/GooglePay.php b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Mobile/GooglePay.php index 15ad167..da9f67f 100644 --- a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Mobile/GooglePay.php +++ b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/Mobile/GooglePay.php @@ -29,10 +29,12 @@ use Genesis\API\Constants\Transaction\Types as TransactionType; use Genesis\API\Request\Base\Financial; use Genesis\API\Traits\Request\DocumentAttributes; +use Genesis\API\Traits\Request\Financial\AsyncAttributes; use Genesis\API\Traits\Request\Financial\BirthDateAttributes; use Genesis\API\Traits\Request\AddressInfoAttributes; use Genesis\API\Traits\Request\Financial\Business\BusinessAttributes; use Genesis\API\Traits\Request\Financial\DescriptorAttributes; +use Genesis\API\Traits\Request\Financial\NotificationAttributes; use Genesis\API\Traits\Request\Financial\PaymentAttributes; use Genesis\API\Traits\Request\Financial\Threeds\V2\AllAttributes as AllThreedsV2Attributes; use Genesis\API\Traits\Request\Mobile\GooglePayAttributes; @@ -51,7 +53,7 @@ class GooglePay extends Financial { use AddressInfoAttributes, PaymentAttributes, GooglePayAttributes, BirthDateAttributes, BusinessAttributes, DocumentAttributes, - DescriptorAttributes, AllThreedsV2Attributes; + DescriptorAttributes, AllThreedsV2Attributes, NotificationAttributes, AsyncAttributes; /** * Used in Google token for signatures array @@ -156,6 +158,9 @@ public function getPaymentTransactionStructure() 'customer_email' => $this->customer_email, 'customer_phone' => $this->customer_phone, 'birth_date' => $this->getBirthDate(), + 'notification_url' => $this->notification_url, + 'return_success_url' => $this->return_success_url, + 'return_failure_url' => $this->return_failure_url, 'billing_address' => $this->getBillingAddressParamsStructure(), 'shipping_address' => $this->getShippingAddressParamsStructure(), 'business_attributes' => $this->getBusinessAttributesStructure(), diff --git a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/OnlineBankingPayments/OnlineBanking/Payout.php b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/OnlineBankingPayments/OnlineBanking/Payout.php index 8a3a411..4d01f6c 100644 --- a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/OnlineBankingPayments/OnlineBanking/Payout.php +++ b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/OnlineBankingPayments/OnlineBanking/Payout.php @@ -134,6 +134,7 @@ class Payout extends \Genesis\API\Request\Base\Financial * C: for Checking accounts * S: for Savings accounts * M: for Maestra accounts(Only Peru) + * P: for Payment accounts * * @var string $bank_account_type */ @@ -456,16 +457,13 @@ protected function validateBRLCurrency() } $requiredFieldsGroups = [ - 'currency' => ['bank_code', 'bank_name'], + 'BRL Currency' => ['bank_code', 'bank_name'] ]; $this->requiredFieldsGroups = Common::createArrayObject($requiredFieldsGroups); - // Allow empty bank_name with non-empty bank_code - if (!empty($this->bank_code)) { - $requiredFieldValuesConditional = (array)$this->requiredFieldValuesConditional; - $requiredFieldValuesConditional['currency']['BRL'][] = ['bank_code' => $this->bank_code]; - - $this->requiredFieldValuesConditional = Common::createArrayObject($requiredFieldValuesConditional); + // Allow empty bank_name, only with Group bank_code and bank_name requirement + if (empty($this->bank_name)) { + unset($this->requiredFieldValuesConditional['currency']['BRL']); } } } diff --git a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/SDD/Sale.php b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/SDD/Sale.php index 56765c2..9ac86f1 100644 --- a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/SDD/Sale.php +++ b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/Financial/SDD/Sale.php @@ -29,6 +29,7 @@ use Genesis\API\Traits\Request\AddressInfoAttributes; use Genesis\API\Traits\Request\Financial\BankAttributes; use Genesis\API\Traits\Request\Financial\AsyncAttributes; +use Genesis\API\Traits\Request\Financial\PendingPaymentAttributes; /** * Class Sale @@ -39,7 +40,7 @@ */ class Sale extends \Genesis\API\Request\Base\Financial { - use PaymentAttributes, AddressInfoAttributes, BankAttributes, AsyncAttributes; + use PaymentAttributes, AddressInfoAttributes, BankAttributes, AsyncAttributes, PendingPaymentAttributes; /** * Name of the company @@ -113,7 +114,8 @@ protected function getPaymentTransactionStructure() 'billing_address' => $this->getBillingAddressParamsStructure(), 'shipping_address' => $this->getShippingAddressParamsStructure(), 'return_success_url' => $this->return_success_url, - 'return_failure_url' => $this->return_failure_url + 'return_failure_url' => $this->return_failure_url, + 'return_pending_url' => $this->getReturnPendingUrl() ]; } } diff --git a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/WPF/Create.php b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/WPF/Create.php index 307b663..3b5ad69 100755 --- a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/WPF/Create.php +++ b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Request/WPF/Create.php @@ -39,6 +39,7 @@ use Genesis\API\Traits\Request\RiskAttributes; use Genesis\API\Traits\Request\Financial\DescriptorAttributes; use Genesis\API\Traits\Request\Financial\FundingAttributes; +use Genesis\API\Traits\Request\Financial\AccountOwnerAttributes; use Genesis\Exceptions\ErrorParameter; use Genesis\Exceptions\InvalidArgument; use Genesis\Utils\Common; @@ -78,7 +79,7 @@ class Create extends \Genesis\API\Request NotificationAttributes, RiskAttributes, DescriptorAttributes, BusinessAttributes, WpfThreedsV2Attributes, PendingPaymentAttributes, RecurringCategoryAttributes, - FundingAttributes; + FundingAttributes, AccountOwnerAttributes; const REMINDERS_CHANNEL_EMAIL = 'email'; const REMINDERS_CHANNEL_SMS = 'sms'; @@ -702,7 +703,8 @@ protected function populateStructure() 'threeds_v2_params' => $this->getThreedsV2ParamsStructure(), 'web_payment_form_id' => $this->web_payment_form_id, 'recurring_category' => $this->recurring_category, - 'funding' => $this->getFundingAttributesStructure() + 'funding' => $this->getFundingAttributesStructure(), + 'account_owner' => $this->getAccountOwnerAttributesStructure() ] ]; diff --git a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Traits/Request/Financial/AccountOwnerAttributes.php b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Traits/Request/Financial/AccountOwnerAttributes.php new file mode 100644 index 0000000..42fddf6 --- /dev/null +++ b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Traits/Request/Financial/AccountOwnerAttributes.php @@ -0,0 +1,78 @@ + $this->account_first_name, + 'middle_name' => $this->account_middle_name, + 'last_name' => $this->account_last_name + ]; + } +} diff --git a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Traits/Request/Mobile/ApplePayAttributes.php b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Traits/Request/Mobile/ApplePayAttributes.php index 99eb639..f71b717 100644 --- a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Traits/Request/Mobile/ApplePayAttributes.php +++ b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/API/Traits/Request/Mobile/ApplePayAttributes.php @@ -37,6 +37,13 @@ * @method $this setTokenNetwork($value) Sets payment network describes the backing the card * @method $this setTokenType($value) Sets card’s type * @method $this setTokenTransactionIdentifier($value) Sets a unique identifier for this payment. +* @method $this setTokenApplicationData($value) Optional. Hash of the applicationData property of the original +* PKPaymentRequest object for transactions that initiate in apps. +* For transactions that initiate in Apple Pay on the Web, the value is +* the hash of applicationData in ApplePayPaymentRequest or of +* applicationData in ApplePayRequest. This key is omitted if the value of +* that property is nil. +* @method $this setTokenWrappedKey($value) The symmetric key wrapped using your RSA public key. RSA_v1 only. */ trait ApplePayAttributes { @@ -116,6 +123,25 @@ trait ApplePayAttributes */ protected $token_transaction_identifier; + /** + * Optional. Hash of the applicationData property of the original PKPaymentRequest object for transactions that + * initiate in apps. For transactions that initiate in Apple Pay on the Web, the value is the hash of + * applicationData in ApplePayPaymentRequest or of applicationData in ApplePayRequest. + * + * This key is omitted if the value of that property is nil. + * + * @var string + */ + protected $token_application_data; + + /** + * The symmetric key wrapped using your RSA public key. + * RSA_v1 only. + * + * @var string + */ + protected $token_wrapped_key; + public function getPaymentTokenStructure() { return json_encode([ @@ -124,7 +150,9 @@ public function getPaymentTokenStructure() 'data' => $this->token_data, 'signature' => $this->token_signature, 'header' => [ + 'applicationData' => $this->token_application_data, 'ephemeralPublicKey' => $this->token_ephemeral_public_key, + 'wrappedKey' => $this->token_wrapped_key, 'publicKeyHash' => $this->token_public_key_hash, 'transactionId' => $this->token_transaction_id ] diff --git a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/Config.php b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/Config.php index 4114712..a1bec82 100644 --- a/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/Config.php +++ b/system/storage/vendor/genesisgateway/genesis_php/src/Genesis/Config.php @@ -24,6 +24,8 @@ */ namespace Genesis; +use Genesis\Utils\Common as CommonUtils; + /** * Class Config * @@ -31,20 +33,21 @@ * * @package Genesis * - * @method static string getUsername() Get the Username, set in configuration - * @method static string getPassword() Get the Password, set in the configuration - * @method static string getToken() Get the Terminal Token, set in configuration + * @method static string getUsername() Get the Username, set in configuration + * @method static string getPassword() Get the Password, set in the configuration + * @method static string getToken() Get the Terminal Token, set in configuration + * @method static bool getForceSmartRouting() Get whether Smart Routing endpoint will be used for Financial types * - * @method static \Genesis\Config setUsername($value) Set the Username - * @method static \Genesis\Config setPassword($value) Set the Password - * @method static \Genesis\Config setToken($value) Set the Terminal + * @method static null setUsername($value) Set the Username + * @method static null setPassword($value) Set the Password + * @method static null setToken($value) Set the Terminal */ final class Config { /** * Library Version */ - const VERSION = '1.23.0'; + const VERSION = '1.24.2'; /** * Core configuration settings @@ -52,11 +55,12 @@ final class Config * @var array */ public static $vault = [ - 'endpoint' => null, - 'username' => null, - 'password' => null, - 'token' => null, - 'environment' => \Genesis\API\Constants\Environments::STAGING + 'endpoint' => null, + 'username' => null, + 'password' => null, + 'token' => null, + 'environment' => \Genesis\API\Constants\Environments::STAGING, + 'force_smart_routing' => false ]; /** @@ -77,17 +81,21 @@ final class Config * @var array */ public static $domains = [ - 'gateway' => [ + 'gateway' => [ 'production' => 'gate.', 'sandbox' => 'staging.gate.' ], - 'wpf' => [ + 'wpf' => [ 'production' => 'wpf.', 'sandbox' => 'staging.wpf.' ], - 'kyc' => [ + 'kyc' => [ 'production' => 'kyc.', 'sandbox' => 'staging.kyc.' + ], + 'smart_router' => [ + 'production' => 'prod.api.', + 'sandbox' => 'staging.api.' ] ]; @@ -101,9 +109,9 @@ final class Config */ public static function __callStatic($method, $args) { - $keySetting = strtolower(substr($method, 3)); + list($action, $keySetting) = CommonUtils::resolveDynamicMethod($method); - switch (substr($method, 0, 3)) { + switch ($action) { case 'get': if (isset(self::$vault[$keySetting])) { return self::$vault[$keySetting]; @@ -117,26 +125,6 @@ public static function __callStatic($method, $args) return null; } - /** - * Get the CA PEM - * - * @return string - Path to the Genesis CA Bundle; false otherwise - * - * @throws \Genesis\Exceptions\InvalidArgument - */ - public static function getCertificateBundle() - { - $bundle = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'Certificates' . DIRECTORY_SEPARATOR . 'ca-bundle.pem'; - - if (!file_exists($bundle)) { - throw new \Genesis\Exceptions\InvalidArgument( - 'CA Bundle file is missing or inaccessible' - ); - } - - return $bundle; - } - /** * Get configuration for an interface * @@ -312,6 +300,17 @@ public static function getVersion() return self::VERSION; } + /** + * Set Force Smart Routing endpoint for Financial types + * + * @param $value + * @return bool + */ + public static function setForceSmartRouting($value) + { + return self::$vault['force_smart_routing'] = CommonUtils::toBoolean($value); + } + /** * Load settings from an ini File * @@ -331,7 +330,9 @@ public static function loadSettings($iniFile) foreach ($settings['Genesis'] as $option => $value) { if (array_key_exists($option, self::$vault)) { - self::$vault[$option] = $value; + $method = 'set' . CommonUtils::snakeCaseToCamelCase($option); + + self::{$method}($value); } }