666999 - Version 0.1.2

Version Notes

First Release

Download this release

Release Info

Developer Demac Media
Extension 666999
Version 0.1.2
Comparing to
See all releases


Version 0.1.2

Files changed (35) hide show
  1. app/code/community/Demac/Optimal/Block/Adminhtml/Risk.php +19 -0
  2. app/code/community/Demac/Optimal/Block/Adminhtml/Risk/Edit.php +32 -0
  3. app/code/community/Demac/Optimal/Block/Adminhtml/Risk/Edit/Form.php +26 -0
  4. app/code/community/Demac/Optimal/Block/Adminhtml/Risk/Edit/Tab/Form.php +70 -0
  5. app/code/community/Demac/Optimal/Block/Adminhtml/Risk/Edit/Tabs.php +31 -0
  6. app/code/community/Demac/Optimal/Block/Adminhtml/Risk/Grid.php +65 -0
  7. app/code/community/Demac/Optimal/Block/Threat.php +89 -0
  8. app/code/community/Demac/Optimal/Helper/Data.php +27 -0
  9. app/code/community/Demac/Optimal/Helpers/Data.php +13 -0
  10. app/code/community/Demac/Optimal/Model/Client/Abstract.php +13 -0
  11. app/code/community/Demac/Optimal/Model/Config/Mode.php +34 -0
  12. app/code/community/Demac/Optimal/Model/Config/Status.php +13 -0
  13. app/code/community/Demac/Optimal/Model/Config/Transaction.php +38 -0
  14. app/code/community/Demac/Optimal/Model/Hosted/Client.php +384 -0
  15. app/code/community/Demac/Optimal/Model/Method.php +16 -0
  16. app/code/community/Demac/Optimal/Model/Method/Hosted.php +299 -0
  17. app/code/community/Demac/Optimal/Model/Mysql4/Risk.php +38 -0
  18. app/code/community/Demac/Optimal/Model/Mysql4/Risk/Collection.php +17 -0
  19. app/code/community/Demac/Optimal/Model/Observer.php +389 -0
  20. app/code/community/Demac/Optimal/Model/Resource/Mysql4/Setup.php +13 -0
  21. app/code/community/Demac/Optimal/Model/Risk.php +20 -0
  22. app/code/community/Demac/Optimal/Model/Web/Client.php +13 -0
  23. app/code/community/Demac/Optimal/Test/Model/Hosted/Client.php +16 -0
  24. app/code/community/Demac/Optimal/Test/Model/Method/Hosted.php +17 -0
  25. app/code/community/Demac/Optimal/Test/Model/Observer.php +9 -0
  26. app/code/community/Demac/Optimal/controllers/Adminhtml/ThreatController.php +106 -0
  27. app/code/community/Demac/Optimal/etc/adminhtml.xml +41 -0
  28. app/code/community/Demac/Optimal/etc/config.xml +161 -0
  29. app/code/community/Demac/Optimal/etc/system.xml +385 -0
  30. app/code/community/Demac/Optimal/sql/optimal_setup/install-0.1.1.php +24 -0
  31. app/code/community/Demac/Optimal/sql/optimal_setup/mysql4-install-0.1.1.php +24 -0
  32. app/design/frontend/base/default/layout/optimal.xml +8 -0
  33. app/design/frontend/base/default/template/demac/threatmeter.phtml +15 -0
  34. app/etc/modules/Demac_Optimal.xml +11 -0
  35. package.xml +26 -0
app/code/community/Demac/Optimal/Block/Adminhtml/Risk.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by JetBrains PhpStorm.
4
+ * User: Allan MacGregor - Magento Practice Lead <allan@demacmedia.com>
5
+ * Company: Demac Media Inc.
6
+ * Date: 9/11/13
7
+ * Time: 3:30 PM
8
+ */
9
+ class Demac_Optimal_Block_Adminhtml_Risk extends Mage_Adminhtml_Block_Widget_Grid_Container
10
+ {
11
+ public function __construct()
12
+ {
13
+ $this->_controller = 'adminhtml_risk';
14
+ $this->_blockGroup = 'optimal';
15
+ $this->_headerText = Mage::helper('optimal')->__('Risk Error Codes Manager');
16
+ $this->_addButtonLabel = Mage::helper('optimal')->__('Add Mapping');
17
+ parent::__construct();
18
+ }
19
+ }
app/code/community/Demac/Optimal/Block/Adminhtml/Risk/Edit.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by JetBrains PhpStorm.
4
+ * User: amacgregor
5
+ * Date: 7/5/11
6
+ * Time: 3:39 PM
7
+ * To change this template use File | Settings | File Templates.
8
+ */
9
+
10
+ class Demac_Optimal_Block_Adminhtml_Risk_Edit extends Mage_Adminhtml_Block_Widget_Form_Container
11
+ {
12
+ public function __construct()
13
+ {
14
+ parent::__construct();
15
+
16
+ $this->_objectId = 'id';
17
+ $this->_blockGroup = 'optimal';
18
+ $this->_controller = 'adminhtml_risk';
19
+
20
+ $this->_updateButton('save', 'label', Mage::helper('optimal')->__('Save Mapping'));
21
+ $this->_updateButton('delete', 'label', Mage::helper('optimal')->__('Delete Mapping'));
22
+ }
23
+
24
+ public function getHeaderText()
25
+ {
26
+ if( Mage::registry('mapping_data') && Mage::registry('mapping_data')->getId() ) {
27
+ return Mage::helper('optimal')->__("Edit Mapping '%s'", $this->htmlEscape(Mage::registry('mapping_data')->getTitle()));
28
+ } else {
29
+ return Mage::helper('optimal')->__('Add Mapping');
30
+ }
31
+ }
32
+ }
app/code/community/Demac/Optimal/Block/Adminhtml/Risk/Edit/Form.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by JetBrains PhpStorm.
4
+ * User: amacgregor
5
+ * Date: 7/5/11
6
+ * Time: 3:45 PM
7
+ * To change this template use File | Settings | File Templates.
8
+ */
9
+
10
+ class Demac_Optimal_Block_Adminhtml_Risk_Edit_Form extends Mage_Adminhtml_Block_Widget_Form
11
+ {
12
+ protected function _prepareForm()
13
+ {
14
+ $form = new Varien_Data_Form(array(
15
+ 'id' => 'edit_form',
16
+ 'action' => $this->getUrl('*/*/save', array('id' => $this->getRequest()->getParam('id'))),
17
+ 'method' => 'post',
18
+ 'enctype' => 'multipart/form-data'
19
+ ));
20
+
21
+
22
+ $form->setUseContainer(true);
23
+ $this->setForm($form);
24
+ return parent::_prepareForm();
25
+ }
26
+ }
app/code/community/Demac/Optimal/Block/Adminhtml/Risk/Edit/Tab/Form.php ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by JetBrains PhpStorm.
4
+ * User: amacgregor
5
+ * Date: 7/5/11
6
+ * Time: 3:48 PM
7
+ * To change this template use File | Settings | File Templates.
8
+ */
9
+
10
+ class Demac_Optimal_Block_Adminhtml_Risk_Edit_Tab_Form extends Mage_Adminhtml_Block_Widget_Form
11
+ {
12
+ protected function _prepareForm()
13
+ {
14
+ $form = new Varien_Data_Form();
15
+ $this->setForm($form);
16
+ $fieldset = $form->addFieldset('risk_form', array('legend'=>Mage::helper('optimal')->__('Risk Error - Order Status Mapping')));
17
+
18
+ $orderStatusCollection = Mage::getModel('sales/order_status')->getResourceCollection();
19
+ $statuses = array();
20
+ foreach($orderStatusCollection as $status)
21
+ {
22
+ $statuses[] = array(
23
+ 'value' => $status->getStatus(),
24
+ 'label' => Mage::helper('catalog')->__($status->getLabel())
25
+ );
26
+
27
+ }
28
+
29
+ $fieldset->addField('risk_code', 'text', array(
30
+ 'label' => Mage::helper('optimal')->__('Risk Code'),
31
+ 'class' => 'required-entry',
32
+ 'required' => true,
33
+ 'comment' => 'The ThreatMetrix error code',
34
+ 'name' => 'risk_code',
35
+ ));
36
+
37
+ $fieldset->addField('description', 'editor', array(
38
+ 'name' => 'description',
39
+ 'label' => Mage::helper('optimal')->__('Description'),
40
+ 'title' => Mage::helper('optimal')->__('Description'),
41
+ 'style' => 'width:500px; height:400px;',
42
+ 'wysiwyg' => false,
43
+ 'required' => true,
44
+ ));
45
+
46
+
47
+ $fieldset->addField('status', 'select', array(
48
+ 'name' => 'status',
49
+ 'label' => Mage::helper('optimal')->__('Magento Order Status'),
50
+ 'title' => Mage::helper('optimal')->__('Magento Order Status'),
51
+ 'style' => 'width:100px;',
52
+ 'values' => $statuses,
53
+ 'value' => 0,
54
+ ));
55
+
56
+ //Mage::log(Mage::getSingleton('adminhtml/session'));
57
+ if ( Mage::getSingleton('adminhtml/session')->getRiskData() )
58
+ {
59
+ $form->setValues(Mage::getSingleton('adminhtml/session')->getRiskData());
60
+ Mage::getSingleton('adminhtml/session')->setRiskData(null);
61
+
62
+
63
+ } elseif ( Mage::registry('mapping_data') ) {
64
+ $form->setValues(Mage::registry('mapping_data')->getData());
65
+ }
66
+
67
+ return parent::_prepareForm();
68
+ }
69
+
70
+ }
app/code/community/Demac/Optimal/Block/Adminhtml/Risk/Edit/Tabs.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by JetBrains PhpStorm.
4
+ * User: amacgregor
5
+ * Date: 7/5/11
6
+ * Time: 3:46 PM
7
+ * To change this template use File | Settings | File Templates.
8
+ */
9
+
10
+ class Demac_Optimal_Block_Adminhtml_Risk_Edit_Tabs extends Mage_Adminhtml_Block_Widget_Tabs
11
+ {
12
+
13
+ public function __construct()
14
+ {
15
+ parent::__construct();
16
+ $this->setId('risk_tabs');
17
+ $this->setDestElementId('edit_form');
18
+ $this->setTitle(Mage::helper('optimal')->__('General'));
19
+ }
20
+
21
+ protected function _beforeToHtml()
22
+ {
23
+ $this->addTab('form_section', array(
24
+ 'label' => Mage::helper('optimal')->__('General'),
25
+ 'title' => Mage::helper('optimal')->__('General'),
26
+ 'content' => $this->getLayout()->createBlock('optimal/adminhtml_risk_edit_tab_form')->toHtml(),
27
+ ));
28
+
29
+ return parent::_beforeToHtml();
30
+ }
31
+ }
app/code/community/Demac/Optimal/Block/Adminhtml/Risk/Grid.php ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by JetBrains PhpStorm.
4
+ * User: amacgregor
5
+ * Date: 7/5/11
6
+ * Time: 3:41 PM
7
+ * To change this template use File | Settings | File Templates.
8
+ */
9
+
10
+ class Demac_Optimal_Block_Adminhtml_Risk_Grid extends Mage_Adminhtml_Block_Widget_Grid
11
+ {
12
+ public function __construct()
13
+ {
14
+ parent::__construct();
15
+ $this->setId('riskGrid');
16
+ // This is the primary key of the database
17
+ $this->setDefaultSort('desc_id');
18
+ $this->setDefaultDir('ASC');
19
+ $this->setSaveParametersInSession(true);
20
+ }
21
+
22
+ protected function _prepareCollection()
23
+ {
24
+ $collection = Mage::getModel('optimal/risk')->getCollection();
25
+ $this->setCollection($collection);
26
+ return parent::_prepareCollection();
27
+ }
28
+
29
+ protected function _prepareColumns()
30
+ {
31
+ $this->addColumn('entity_id', array(
32
+ 'header' => Mage::helper('optimal')->__('ID'),
33
+ 'align' =>'right',
34
+ 'width' => '50px',
35
+ 'index' => 'entity_id',
36
+ ));
37
+
38
+ $this->addColumn('risk_code', array(
39
+ 'header' => Mage::helper('optimal')->__('Risk Error Code '),
40
+ 'align' =>'left',
41
+ 'width' => '150px',
42
+ 'index' => 'risk_code',
43
+ ));
44
+
45
+
46
+ $this->addColumn('description', array(
47
+ 'header' => Mage::helper('optimal')->__('Description'),
48
+ 'index' => 'description',
49
+ ));
50
+
51
+ $this->addColumn('status', array(
52
+ 'header' => Mage::helper('optimal')->__('Magento Order Status'),
53
+ 'index' => 'status',
54
+ ));
55
+
56
+ return parent::_prepareColumns();
57
+ }
58
+
59
+ public function getRowUrl($row)
60
+ {
61
+ return $this->getUrl('*/*/edit', array('id' => $row->getId()));
62
+ }
63
+
64
+
65
+ }
app/code/community/Demac/Optimal/Block/Threat.php ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by JetBrains PhpStorm.
4
+ * User: Allan MacGregor - Magento Practice Lead <allan@demacmedia.com>
5
+ * Company: Demac Media Inc.
6
+ * Date: 8/8/13
7
+ * Time: 7:29 AM
8
+ */
9
+
10
+ class Demac_Optimal_Block_Threat extends Mage_Core_Block_Template
11
+ {
12
+
13
+ protected function _construct()
14
+ {
15
+ $this->addData(array(
16
+ 'cache_lifetime' => null,
17
+ 'cache_tags' => array('OPTIMAL_THREATMETRIX'),
18
+ 'cache_key' => rand(),
19
+ ));
20
+ }
21
+
22
+ /**
23
+ *
24
+ *
25
+ * @return mixed
26
+ */
27
+ public function getOrgId()
28
+ {
29
+ $orgId = Mage::getStoreConfig('payment/threat_metrix/org_id');
30
+ return $orgId;
31
+ }
32
+
33
+ /**
34
+ * Check if treath Metrix is actige
35
+ *
36
+ * @return mixed
37
+ */
38
+ public function isThreatMetrixActive()
39
+ {
40
+ $enabled = Mage::getStoreConfig('payment/threat_metrix/active');
41
+ return $enabled;
42
+ }
43
+
44
+ /**
45
+ * Generate the Unique session key
46
+ *
47
+ * @param $sessionId
48
+ * @return bool|string
49
+ */
50
+ public function getSessionKey($sessionId)
51
+ {
52
+ $orgId = $this->getOrgId();
53
+ $time = round(microtime(true) * 1000);
54
+
55
+ if(isset($sessionId) && isset($orgId) && isset($time))
56
+ {
57
+ $key = "{$orgId}_{$time}_{$sessionId}";
58
+ Mage::getSingleton('core/session')->setThreatMetrixSessionKey($key);
59
+
60
+ return $key;
61
+ }
62
+
63
+ return false;
64
+ }
65
+
66
+ /**
67
+ * Generate the Threat Metrix url
68
+ *
69
+ * @param null $m
70
+ * @return string
71
+ */
72
+ public function getThreatMetrixUrl($m = null)
73
+ {
74
+
75
+ $orgId = $this->getOrgId();
76
+ $sessionId = $this->getSessionKey(Mage::getSingleton("core/session")->getEncryptedSessionId());
77
+
78
+ $url = "https://h.online-metrix.net/fp/check.js?org_id={$orgId}&session_id={$sessionId}";
79
+
80
+ if(isset($m))
81
+ {
82
+ $url .= "&m={$m}";
83
+ }
84
+
85
+ return $url;
86
+ }
87
+
88
+
89
+ }
app/code/community/Demac/Optimal/Helper/Data.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by JetBrains PhpStorm.
4
+ * User: Allan MacGregor - Magento Practice Lead <allan@demacmedia.com>
5
+ * Company: Demac Media Inc.
6
+ * Date: 6/20/13
7
+ * Time: 2:05 PM
8
+ */
9
+
10
+ class Demac_Optimal_Helper_Data extends Mage_Core_Helper_Abstract
11
+ {
12
+ public function formatAmount($amount)
13
+ {
14
+ $amount = (int)(string)((number_format($amount,2,'.','')) * 100);
15
+ return $amount;
16
+ }
17
+
18
+ public function getStreetDetails($address, $position)
19
+ {
20
+ if(isset($address[$position]))
21
+ {
22
+ return $address[$position];
23
+ } else {
24
+ return '';
25
+ }
26
+ }
27
+ }
app/code/community/Demac/Optimal/Helpers/Data.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by JetBrains PhpStorm.
4
+ * User: Allan MacGregor - Magento Practice Lead <allan@demacmedia.com>
5
+ * Company: Demac Media Inc.
6
+ * Date: 6/20/13
7
+ * Time: 2:05 PM
8
+ */
9
+
10
+ class Demac_Optimal_Helpers_Data extends Mage_Core_Helper_Abstract
11
+ {
12
+
13
+ }
app/code/community/Demac/Optimal/Model/Client/Abstract.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by JetBrains PhpStorm.
4
+ * User: Allan MacGregor - Magento Practice Lead <allan@demacmedia.com>
5
+ * Company: Demac Media Inc.
6
+ * Date: 6/20/13
7
+ * Time: 1:05 PM
8
+ */
9
+
10
+ class Demac_Optimal_Model_Client_Abstract
11
+ {
12
+
13
+ }
app/code/community/Demac/Optimal/Model/Config/Mode.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Demac Media
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the EULA
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://www.demacmedia.com/LICENSE-Magento.txt
11
+ *
12
+ * @category Demac
13
+ * @author Michael Kreitzer (michael@demacmedia.com), Allan MacGregor <allan@demacmedia.com>
14
+ * @package Demac_CanadaPost
15
+ * @copyright Copyright (c) 2010-2012 Demac Media (http://www.demacmedia.com)
16
+ * @license http://www.demacmedia.com/LICENSE-Magento.txt
17
+ */
18
+
19
+ class Demac_Optimal_Model_Config_Mode extends Mage_Core_Model_Config_Data
20
+ {
21
+ const DEV_VALUE = 'development';
22
+ const PROD_VALUE = 'production';
23
+
24
+ /**
25
+ * @return array
26
+ */
27
+ public function toOptionArray()
28
+ {
29
+ return array(
30
+ self::DEV_VALUE => Mage::helper('optimal')->__('Development'),
31
+ self::PROD_VALUE => Mage::helper('optimal')->__('Production'),
32
+ );
33
+ }
34
+ }
app/code/community/Demac/Optimal/Model/Config/Status.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by JetBrains PhpStorm.
4
+ * User: Allan MacGregor - Magento Practice Lead <allan@demacmedia.com>
5
+ * Company: Demac Media Inc.
6
+ * Date: 9/10/13
7
+ * Time: 2:03 PM
8
+ */
9
+ class Demac_Optimal_Model_Status extends Mage_Core_Model_Config_Data
10
+ {
11
+
12
+
13
+ }
app/code/community/Demac/Optimal/Model/Config/Transaction.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Demac Media
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the EULA
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://www.demacmedia.com/LICENSE-Magento.txt
11
+ *
12
+ * @category Demac
13
+ * @author Michael Kreitzer (michael@demacmedia.com), Allan MacGregor <allan@demacmedia.com>
14
+ * @package Demac_CanadaPost
15
+ * @copyright Copyright (c) 2010-2012 Demac Media (http://www.demacmedia.com)
16
+ * @license http://www.demacmedia.com/LICENSE-Magento.txt
17
+ */
18
+
19
+ class Demac_Optimal_Model_Config_Transaction extends Mage_Core_Model_Config_Data
20
+ {
21
+ const AUTH_VALUE = 'auth';
22
+ const CAPT_VALUE = 'purchase';
23
+
24
+ public function toOptionArray()
25
+ {
26
+ return array(
27
+ array(
28
+ 'value' => Demac_Optimal_Model_Method_Hosted::ACTION_AUTHORIZE,
29
+ 'label' => Mage::helper('optimal')->__('Authorize Only')
30
+ ),
31
+ array(
32
+ 'value' => Demac_Optimal_Model_Method_Hosted::ACTION_AUTHORIZE_CAPTURE,
33
+ 'label' => Mage::helper('optimal')->__('Authorize and Capture')
34
+ ),
35
+ );
36
+ }
37
+
38
+ }
app/code/community/Demac/Optimal/Model/Hosted/Client.php ADDED
@@ -0,0 +1,384 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by JetBrains PhpStorm.
4
+ * User: Allan MacGregor - Magento Practice Lead <allan@demacmedia.com>
5
+ * Company: Demac Media Inc.
6
+ * Date: 6/20/13
7
+ * Time: 12:53 PM
8
+ */
9
+
10
+ class Demac_Optimal_Model_Hosted_Client extends Mage_Core_Model_Abstract
11
+ {
12
+ protected $_merchantRefNum = null;
13
+ protected $_currencyCode = null;
14
+ protected $_totalAmount = null;
15
+ protected $_apiUrl = null;
16
+ protected $_restEndpoints = array();
17
+
18
+ const CONNECTION_RETRIES = 3;
19
+
20
+ public function _construct()
21
+ {
22
+ $this->_apiUrl = $this->_getApiUrl();
23
+
24
+ // Initialize methods array
25
+ $this->_restEndpoints = array(
26
+ 'create' => 'hosted/v1/orders',
27
+ 'cancel' => 'hosted/v1/orders/%s',
28
+ 'update' => 'hosted/v1/orders/%s',
29
+ 'info' => 'hosted/v1/orders/%s',
30
+ 'refund' => 'hosted/v1/orders/%s/refund',
31
+ 'settle' => 'hosted/v1/orders/%s/settlement',
32
+ 'resend' => 'hosted/v1/orders/%s/resend_callback',
33
+ 'report' => 'hosted/v1/orders',
34
+ 'rebill' => 'hosted/v1/orders/%s',
35
+ );
36
+ }
37
+
38
+ /**
39
+ *
40
+ * Create an Order in Netbanks.
41
+ *
42
+ * @param $data (
43
+ * merchantRefNum = (string) MagentoOrderId
44
+ * currencyCode = (ISO4217) Order currency code
45
+ * totalAmount = (int) Order Grand Total
46
+ * customerIP = (string) remote_ip
47
+ *
48
+ * customerNotificationEmail = (string) Order customer email
49
+ * merchantNotificationEmail = (string) Order contact email
50
+ * )
51
+ * @return bool|mixed
52
+ */
53
+ public function createOrder($data)
54
+ {
55
+ $mode = 'POST';
56
+ $url = $this->_getUrl('create');
57
+
58
+ return $this->callApi($url,$mode,$data);
59
+ }
60
+
61
+ /**
62
+ *
63
+ * Cancel an Order in Netbanks
64
+ *
65
+ * @param $id
66
+ * @internal param $data ( id = netbanksOrderId )
67
+ *
68
+ * @return bool|mixed
69
+ */
70
+ public function cancelOrder($id)
71
+ {
72
+ $mode = 'DELETE';
73
+ $url = $this->_getUrl('cancel', $id);
74
+
75
+ return $this->callApi($url,$mode);
76
+ }
77
+
78
+ /**
79
+ *
80
+ * Update Order in Netbanks
81
+ *
82
+ * @param $data
83
+ */
84
+ public function updateOrder($data,$id)
85
+ {
86
+ $mode = 'PUT';
87
+ $url = $this->_getUrl('update',$id);
88
+
89
+ return $this->callApi($url,$mode,$data);
90
+ }
91
+
92
+ /**
93
+ *
94
+ * Retrieve Order Information from Netbanks
95
+ *
96
+ * @param $id
97
+ * @internal param $data
98
+ * @return bool|mixed
99
+ */
100
+ public function retrieveOrder($id)
101
+ {
102
+ $mode = 'GET';
103
+ $url = $this->_getUrl('info',$id);
104
+
105
+ return $this->callApi($url,$mode);
106
+ }
107
+
108
+ /**
109
+ *
110
+ * Refund order in Netbanks
111
+ *
112
+ * @param $data
113
+ * @param $id
114
+ * @return bool|mixed
115
+ */
116
+ public function refundOrder($data,$id)
117
+ {
118
+ $mode = 'POST';
119
+ $url = $this->_getUrl('refund',$id);
120
+
121
+ return $this->callApi($url,$mode,$data);
122
+ }
123
+
124
+ /**
125
+ *
126
+ * Settle an order in Netbanks
127
+ *
128
+ * @param $data
129
+ * @param $id
130
+ * @return bool|mixed
131
+ */
132
+ public function settleOrder($data, $id)
133
+ {
134
+ $mode = 'POST';
135
+ $url = $this->_getUrl('settle', $id);
136
+
137
+ return $this->callApi($url,$mode,$data);
138
+ }
139
+
140
+ /**
141
+ *
142
+ * Get an order report form Netbanks
143
+ *
144
+ */
145
+ public function orderReport()
146
+ {
147
+ $mode = 'GET';
148
+ $url = $this->_getUrl('report');
149
+
150
+ return $this->callApi($url,$mode);
151
+ }
152
+
153
+ /**
154
+ *
155
+ * Resend Callback url to Netbanks
156
+ *
157
+ * @param $data
158
+ * @return bool|mixed
159
+ */
160
+ public function resendCallback($data)
161
+ {
162
+ $mode = 'GET';
163
+ $url = $this->_getUrl('resend');
164
+
165
+ return $this->callApi($url,$mode);
166
+ }
167
+
168
+ /**
169
+ *
170
+ * Rebill an order in Netbanks
171
+ *
172
+ * @param $data
173
+ * @return bool|mixed
174
+ */
175
+ public function rebillOrder($data)
176
+ {
177
+ $mode = 'POST';
178
+ $url = $this->_getUrl('rebill');
179
+
180
+ return $this->callApi($url,$mode);
181
+ }
182
+
183
+ /**
184
+ * Get the API url based on the configuration
185
+ *
186
+ * @return string
187
+ */
188
+ protected function _getApiUrl()
189
+ {
190
+ if(Mage::getStoreConfig('payment/optimal_hosted/mode') === 'development')
191
+ {
192
+ $url = 'https://api.test.netbanx.com';
193
+ }else {
194
+ $url = 'https://api.netbanx.com';
195
+ }
196
+ return $url;
197
+ }
198
+
199
+ /**
200
+ * Mapping of the RESTFul Api
201
+ *
202
+ * Create an Order - hosted/v1/orders [POST]
203
+ * Cancel an Order - hosted/v1/orders/{id} [DELETE]
204
+ * Update an Order - hosted/v1/orders/{id} [PUT]
205
+ * Get an Order - hosted/v1/orders/{id} [GET]
206
+ * Refund an Order - hosted/v1/orders/{id}/settlement [POST]
207
+ * Get an Order Report - hosted/v1/orders [GET]
208
+ * Resend Callbackk - hosted/v1/orders/{id}/resend_callback [GET]
209
+ * Process a Rebill - hosted/v1/orders/{id} [POST]
210
+ *
211
+ * @param $method
212
+ * @param $url
213
+ * @param $data = Array(id,content)
214
+ * @return bool|mixed
215
+ */
216
+ protected function callApi($url, $method, $data = array())
217
+ {
218
+
219
+ $response = json_decode($this->_callApi($url,$method,$data));
220
+
221
+ // Do I need extra logic here ?
222
+ // Yes I do
223
+ if(isset($response->error))
224
+ {
225
+ Mage:log('Netbanks Returned Error: ' . $response->error->message,null,'DemacOptimal_error.log');
226
+ Mage::throwException($response->error->message);
227
+ return false;
228
+ }
229
+ if(isset($response->transaction->errorCode))
230
+ {
231
+ $session = Mage::getSingleton('customer/session');
232
+ if (!$session->getCustomerId()) {
233
+ Mage::getSingleton('customer/session')->addError($response->transaction->errorMessage);
234
+ }
235
+ Mage::throwException($response->transaction->errorMessage);
236
+ return false;
237
+ }
238
+ return $response;
239
+ }
240
+
241
+ /**
242
+ * Makes CURL requests to the netbanks api
243
+ *
244
+ * @param $url
245
+ * @param $mode
246
+ * @param array $data
247
+ * @return mixed
248
+ */
249
+ protected function _callApi($url,$mode,$data = array())
250
+ {
251
+ $helper = Mage::helper('optimal');
252
+ $data = json_encode($data);
253
+
254
+ try {
255
+ $curl = curl_init($url);
256
+ $headers[] = "Content-Type: application/json";
257
+
258
+ curl_setopt($curl, CURLOPT_USERPWD, $this->_getUserPwd());
259
+ curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
260
+
261
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
262
+
263
+ switch ($mode) {
264
+ case "POST":
265
+ curl_setopt($curl, CURLOPT_POST, true);
266
+ curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
267
+ break;
268
+ case "DELETE":
269
+ curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $mode);
270
+ curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
271
+ break;
272
+ case "PUT":
273
+ curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $mode);
274
+ curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
275
+ break;
276
+ case "GET":
277
+ //hosted/v1/orders/{id}
278
+ break;
279
+ default:
280
+ Mage::throwException($this->__("{$mode} mode was not recognized. Please one of the valid REST actions GET, POST, PUT, DELETE"));
281
+ break;
282
+ }
283
+
284
+ $curl_response = curl_exec($curl);
285
+ curl_close($curl);
286
+
287
+ // Check if the response is false
288
+ if($curl_response === false)
289
+ {
290
+ Mage::throwException($this->__("Something went wrong while trying to retrieve the response from the REST api"));
291
+ }
292
+
293
+ // Check if the response threw an error
294
+ if($curl_response === false)
295
+ {
296
+ Mage::throwException($this->__("Something went wrong while trying to retrieve the response from the REST api"));
297
+ }
298
+
299
+
300
+ } catch (Mage_Exception $e) {
301
+ Mage::logException($e);
302
+ return false;
303
+ } catch (Exception $e) {
304
+ Mage::logException($e);
305
+ return false;
306
+ }
307
+
308
+ return $curl_response;
309
+ }
310
+
311
+ /**
312
+ * @return bool|string
313
+ *
314
+ * TODO: TEST MULTI STORE SCENARIOS
315
+ *
316
+ */
317
+ protected function _getUserPwd()
318
+ {
319
+ try {
320
+ $user = Mage::helper('core')->decrypt(Mage::getStoreConfig('payment/optimal_hosted/login'));
321
+ $pwd = Mage::helper('core')->decrypt(Mage::getStoreConfig('payment/optimal_hosted/trans_key'));
322
+
323
+ if($user != '' && $pwd != '')
324
+ {
325
+ return $user . ':' . $pwd;
326
+ }else{
327
+ Mage::throwException($this->__("Something went wrong with your api credentials"));
328
+ }
329
+ } catch (Exception $e) {
330
+ Mage::logException($e);
331
+ return false;
332
+ }
333
+ }
334
+
335
+
336
+ /**
337
+ * @param $url
338
+ * @param $data
339
+ * @return bool
340
+ */
341
+ public function submitPayment($url,$data)
342
+ {
343
+ $data_string = '';
344
+
345
+ try {
346
+ $curl = curl_init($url);
347
+
348
+ //url-ify the data for the POST
349
+ foreach($data as $key=>$value)
350
+ {
351
+ $data_string .= $key.'='.$value.'&';
352
+ }
353
+
354
+ $data_string = rtrim($data_string, '&');
355
+ curl_setopt($curl, CURLOPT_HTTPHEADER, 0);
356
+
357
+ //set the url, number of POST vars, POST data
358
+ curl_setopt($curl,CURLOPT_URL, $url);
359
+ curl_setopt($curl,CURLOPT_POST, true);
360
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
361
+ curl_setopt($curl,CURLOPT_POSTFIELDS, $data_string);
362
+ $curl_response = curl_exec($curl);
363
+ curl_close($curl);
364
+ return true;
365
+
366
+ } catch (Exception $e) {
367
+ Mage::logException($e);
368
+ return false;
369
+ }
370
+ }
371
+
372
+
373
+ /**
374
+ * Build the RESTful url
375
+ *
376
+ * @param $method
377
+ * @param null $id
378
+ * @return string
379
+ */
380
+ protected function _getUrl($method,$id = null)
381
+ {
382
+ return $this->_apiUrl . '/' . sprintf($this->_restEndpoints[$method],$id);
383
+ }
384
+ }
app/code/community/Demac/Optimal/Model/Method.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by JetBrains PhpStorm.
4
+ * User: Allan MacGregor - Magento Practice Lead <allan@demacmedia.com>
5
+ * Company: Demac Media Inc.
6
+ * Date: 6/20/13
7
+ * Time: 1:29 PM
8
+ */
9
+
10
+ class Demac_Optimal_Model_Method extends Mage_Payment_Model_Method_Cc
11
+ {
12
+ protected $_code = 'optimal';
13
+ protected $_canSaveCc = true;
14
+ protected $_formBlockType = 'payment/form_ccsave';
15
+ protected $_infoBlockType = 'payment/info_ccsave';
16
+ }
app/code/community/Demac/Optimal/Model/Method/Hosted.php ADDED
@@ -0,0 +1,299 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by JetBrains PhpStorm.
4
+ * User: Allan MacGregor - Magento Practice Lead <allan@demacmedia.com>
5
+ * Company: Demac Media Inc.
6
+ * Date: 6/20/13
7
+ * Time: 1:29 PM
8
+ */
9
+
10
+ class Demac_Optimal_Model_Method_Hosted extends Mage_Payment_Model_Method_Cc
11
+ {
12
+ const METHOD_CODE = 'optimal_hosted';
13
+
14
+ protected $_code = self::METHOD_CODE;
15
+ protected $_canSaveCc = false;
16
+ protected $_canAuthorize = true;
17
+ protected $_canVoid = true;
18
+ protected $_canCapture = true;
19
+ protected $_canCapturePartial = true;
20
+ protected $_isGateway = false;
21
+ protected $_canRefund = true;
22
+ protected $_canRefundInvoicePartial = true;
23
+
24
+ protected $_formBlockType = 'payment/form_ccsave';
25
+ protected $_infoBlockType = 'payment/info_ccsave';
26
+
27
+
28
+ /**
29
+ * @param Mage_Sales_Model_Order_Payment $payment
30
+ * @param $transactionId
31
+ * @param $transactionType
32
+ * @param array $transactionDetails
33
+ * @param array $transactionAdditionalInfo
34
+ * @param bool $message
35
+ * @return Mage_Sales_Model_Order_Payment_Transaction|null
36
+ */
37
+ protected function _addTransaction(Mage_Sales_Model_Order_Payment $payment, $transactionId, $transactionType,
38
+ array $transactionDetails = array(), array $transactionAdditionalInfo = array(), $message = false
39
+ ) {
40
+ $payment->setTransactionId($transactionId);
41
+ $payment->resetTransactionAdditionalInfo();
42
+ foreach ($transactionDetails as $key => $value) {
43
+ $payment->setData($key, $value);
44
+ }
45
+ foreach ($transactionAdditionalInfo as $key => $value) {
46
+ $payment->setTransactionAdditionalInfo($key, $value);
47
+ }
48
+ $transaction = $payment->addTransaction($transactionType, null, false , $message);
49
+ foreach ($transactionDetails as $key => $value) {
50
+ $payment->unsetData($key);
51
+ }
52
+ $payment->unsLastTransId();
53
+
54
+ /**
55
+ * Its for self using
56
+ */
57
+ $transaction->setMessage($message);
58
+
59
+ return $transaction;
60
+ }
61
+
62
+
63
+
64
+ /**
65
+ * Check refund availability
66
+ *
67
+ * @return bool
68
+ */
69
+ public function canRefund()
70
+ {
71
+ return $this->_canRefund;
72
+ }
73
+
74
+ /**
75
+ * Check void availability
76
+ *
77
+ * @param Varien_Object $payment
78
+ * @internal param \Varien_Object $invoicePayment
79
+ * @return bool
80
+ */
81
+ public function canVoid(Varien_Object $payment)
82
+ {
83
+ return $this->_canVoid;
84
+ }
85
+
86
+ public function authorize(Varien_Object $payment, $amount)
87
+ {
88
+ if (!$this->canAuthorize()) {
89
+ Mage::throwException(Mage::helper('payment')->__('Authorize action is not available.'));
90
+ }
91
+
92
+ try {
93
+
94
+ $additionalInformation = $payment->getAdditionalInformation();
95
+ if (isset($additionalInformation['transaction'])) {
96
+ $orderData = unserialize($additionalInformation['order']);
97
+ $payment->setTransactionId($orderData['id']);
98
+ $payment->hasIsTransactionClosed(true);
99
+ $payment->setIsTransactionClosed(false);
100
+ }
101
+
102
+ return $this;
103
+ } catch (Exception $e) {
104
+ Mage::logException($e);
105
+ return false;
106
+ }
107
+ }
108
+
109
+
110
+
111
+ /**
112
+ * Send capture request to gateway
113
+ *
114
+ * @param Varien_Object $payment
115
+ * @param decimal $amount
116
+ * @return Mage_Authorizenet_Model_Directpost
117
+ * @throws Mage_Core_Exception
118
+ */
119
+ public function capture(Varien_Object $payment, $amount)
120
+ {
121
+ $helper = Mage::helper('optimal');
122
+ if ($amount <= 0) {
123
+ Mage::throwException(Mage::helper('payment')->__('Invalid amount for capture.'));
124
+ }
125
+
126
+ try {
127
+ $additionalInformation = $payment->getAdditionalInformation();
128
+
129
+ if (isset($additionalInformation['transaction']))
130
+ {
131
+
132
+ $paymentData = unserialize($additionalInformation['transaction']);
133
+ $orderData = unserialize($additionalInformation['order']);
134
+ $client = Mage::getModel('optimal/hosted_client');
135
+
136
+ $payment->setAmount($amount);
137
+ $order = $payment->getOrder();
138
+
139
+
140
+ /**
141
+ * Commenting code because OPTIMAL API is broken
142
+ * For the record going live right now is bullshit
143
+ */
144
+
145
+ // if($paymentData->status == 'held')
146
+ // {
147
+ // $data = array(
148
+ // "transaction" => array(
149
+ // "status" => "success"
150
+ // )
151
+ // );
152
+ //
153
+ // $updateResponse = $client->updateOrder($data,$orderData['id']);
154
+ // $order->addStatusHistoryComment(
155
+ // 'Trans Type: Update<br/>' .
156
+ // 'Confirmation Number: ' . $updateResponse->transaction->confirmationNumber .'<br/>' .
157
+ // 'Transaction Status: ' . $updateResponse->transaction->status .'<br/>'
158
+ // );
159
+ //
160
+ // if($updateResponse->transaction->status != 'success'){
161
+ // Mage::throwException('There was a problem releasing the Transaction. Please contact support@demacmedia.com');
162
+ // }
163
+ // }
164
+
165
+ $data = array(
166
+ 'amount' => (int)$helper->formatAmount($amount),
167
+ 'merchantRefNum' => (string)$paymentData->merchantRefNum
168
+ );
169
+
170
+ $response = $client->settleOrder($data, $orderData['id']);
171
+ $orderStatus = $client->retrieveOrder($orderData['id']);
172
+ $transaction = $orderStatus->transaction;
173
+
174
+ $associatedTransactions = $transaction->associatedTransactions;
175
+
176
+ $payment->setAdditionalInformation('transaction', serialize($transaction));
177
+
178
+ $order->addStatusHistoryComment(
179
+ 'Trans Type: ' . $response->authType .'<br/>' .
180
+ 'Confirmation Number: ' . $response->confirmationNumber .'<br/>' .
181
+ 'Transaction Amount: ' . $response->amount/100 .'<br/>'
182
+ );
183
+
184
+ return $this;
185
+
186
+ } else {
187
+ Mage::throwException('Transaction information is not properly set. Please contact support@demacmedia.com');
188
+ }
189
+ } catch (Exception $e) {
190
+ Mage::logException($e);
191
+ return false;
192
+ }
193
+ }
194
+
195
+
196
+ /**
197
+ * Void the payment through gateway
198
+ *
199
+ * @param Varien_Object $payment
200
+ * @return Mage_Authorizenet_Model_Directpost
201
+ * @throws Mage_Core_Exception
202
+ */
203
+ public function void(Varien_Object $payment)
204
+ {
205
+ try {
206
+ $additionalInformation = $payment->getAdditionalInformation();
207
+
208
+ if (isset($additionalInformation['transaction'])) {
209
+ $client = Mage::getModel('optimal/hosted_client');
210
+
211
+ $paymentData = unserialize($additionalInformation['transaction']);
212
+ $orderData = unserialize($additionalInformation['order']);
213
+
214
+ $response = $client->cancelOrder($orderData['id']);
215
+
216
+ $payment
217
+ ->setIsTransactionClosed(1)
218
+ ->setShouldCloseParentTransaction(1);
219
+
220
+ $order = $payment->getOrder();
221
+
222
+ $order->addStatusHistoryComment(
223
+ 'Trans Type: ' . $response->authType .'<br/>'.
224
+ 'Confirmation Number: ' . $response->confirmationNumber .'<br/>'.
225
+ 'Transaction Amount: ' . $response->amount/100 .'<br/>'
226
+ );
227
+
228
+ return $this;
229
+
230
+
231
+ } else {
232
+ Mage::throwException('Transaction information is not properly set. Please contact support@demacmedia.com');
233
+ }
234
+ } catch (Exception $e) {
235
+ Mage::logException($e);
236
+ return false;
237
+ }
238
+
239
+ }
240
+
241
+
242
+ /**
243
+ * Refund the amount
244
+ * Need to decode Last 4 digits for request.
245
+ *
246
+ * @param Varien_Object $payment
247
+ * @param decimal $amount
248
+ * @return Mage_Authorizenet_Model_Directpost
249
+ * @throws Mage_Core_Exception
250
+ */
251
+ public function refund(Varien_Object $payment, $amount)
252
+ {
253
+ $helper = Mage::helper('optimal');
254
+
255
+ if ($amount <= 0) {
256
+ Mage::throwException(Mage::helper('paygate')->__('Invalid amount for refund.'));
257
+ }
258
+
259
+ if (!$payment->getParentTransactionId()) {
260
+ Mage::throwException(Mage::helper('paygate')->__('Invalid transaction ID.'));
261
+ }
262
+
263
+ try {
264
+ $additionalInformation = $payment->getAdditionalInformation();
265
+
266
+ if (isset($additionalInformation['transaction'])) {
267
+ $client = Mage::getModel('optimal/hosted_client');
268
+
269
+ $paymentData = unserialize($additionalInformation['transaction']);
270
+ $orderData = unserialize($additionalInformation['order']);
271
+
272
+ $data = array(
273
+ 'amount' => (int)$helper->formatAmount($amount),
274
+ 'merchantRefNum' => (string)$paymentData->merchantRefNum
275
+ );
276
+
277
+ $response = $client->refundOrder($data,$paymentData->associatedTransactions[0]->reference);
278
+
279
+ $order = $payment->getOrder();
280
+
281
+ $order->addStatusHistoryComment(
282
+ 'Trans Type: ' . $response->authType .'<br/>',
283
+ 'Confirmation Number: ' . $response->confirmationNumber .'<br/>',
284
+ 'Transaction Amount: ' . $response->amount/100 .'<br/>'
285
+ );
286
+ return $this;
287
+
288
+ } else {
289
+ Mage::throwException('Transaction information is not properly set. Please contact support@demacmedia.com');
290
+ }
291
+ } catch (Exception $e) {
292
+ Mage::logException($e);
293
+ return false;
294
+ }
295
+
296
+ return $this;
297
+ }
298
+
299
+ }
app/code/community/Demac/Optimal/Model/Mysql4/Risk.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by JetBrains PhpStorm.
4
+ * User: amacgregor
5
+ * Date: 12/09/13
6
+ * Time: 9:12 AM
7
+ * To change this template use File | Settings | File Templates.
8
+ */
9
+
10
+ class Demac_Optimal_Model_Mysql4_Risk extends Mage_Core_Model_Mysql4_Abstract
11
+ {
12
+ protected $_isPkAutoIncrement = true;
13
+
14
+ /**
15
+ * Resource initialization
16
+ */
17
+ protected function _construct()
18
+ {
19
+ $this->_init('optimal/risk', 'entity_id');
20
+ }
21
+
22
+ public function loadByCode(Demac_Optimal_Model_Risk $object, $errorCode)
23
+ {
24
+ $adapter = $this->_getReadAdapter();
25
+ $where = $adapter->quoteInto("risk_code = ?", $errorCode);
26
+
27
+ $select = $adapter->select()
28
+ ->from($this->getMainTable())
29
+ ->where($where);
30
+ if($data = $adapter->fetchRow($select))
31
+ {
32
+ $object->setData($data);
33
+ $this->_afterLoad($object);
34
+ }
35
+ return $this;
36
+
37
+ }
38
+ }
app/code/community/Demac/Optimal/Model/Mysql4/Risk/Collection.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by JetBrains PhpStorm.
4
+ * User: amacgregor
5
+ * Date: 12/09/13
6
+ * Time: 9:12 AM
7
+ * To change this template use File | Settings | File Templates.
8
+ */
9
+
10
+ class Demac_Optimal_Model_Mysql4_Risk_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
11
+ {
12
+ public function _construct()
13
+ {
14
+ parent::_construct();
15
+ $this->_init('optimal/risk');
16
+ }
17
+ }
app/code/community/Demac/Optimal/Model/Observer.php ADDED
@@ -0,0 +1,389 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by JetBrains PhpStorm.
4
+ * User: Allan MacGregor - Magento Head Developer <allan@demacmedia.com>
5
+ * Company: Demac Media Inc.
6
+ * Date: 6/24/13
7
+ * Time: 1:49 PM
8
+ */
9
+
10
+ class Demac_Optimal_Model_Observer
11
+ {
12
+ /**
13
+ *
14
+ * Before we actually submit an order we need to:
15
+ * 1- Create a netbanks order using their IP
16
+ * 2- Store the response inside the order object
17
+ * 3- Get the payment information entered by the customer
18
+ * 4- Post that directly to the callback url that we got from step 1
19
+ * 5- Handle the response from the silentpost form
20
+ *
21
+ * @param Varien_Event_Observer $observer
22
+ */
23
+ public function salesOrderPlaceBefore(Varien_Event_Observer $observer)
24
+ {
25
+ $order = $observer->getOrder();
26
+ $payment = $order->getPayment();
27
+ $postURL = null;
28
+
29
+ if($payment->getMethod() == Demac_Optimal_Model_Method_Hosted::METHOD_CODE)
30
+ {
31
+ $client = Mage::getModel('optimal/hosted_client');
32
+ $helper = Mage::helper('optimal');
33
+
34
+ $billingAddress = $order->getBillingAddress();
35
+ $shippingAddress = $order->getShippingAddress();
36
+ $shoppingCartArray = array();
37
+ $orderItems = $order->getAllVisibleItems();
38
+
39
+ // Minimum order information needed
40
+ $data = array(
41
+ 'merchantRefNum' => (string) $order->getIncrementId() . '-' . time(),
42
+ 'currencyCode' => (string) $order->getBaseCurrencyCode(),
43
+ 'totalAmount' => (int) $helper->formatAmount($order->getBaseGrandTotal()),
44
+ 'customerNotificationEmail' => (string) $order->getCustomerEmail(),
45
+ 'merchantNotificationEmail' => 'allan@demacmedia.com',
46
+ );
47
+
48
+ // Customer Profile information
49
+ $customer = Mage::getSingleton('customer/session');
50
+ $customerProfileArray = array(
51
+ 'merchantCustomerId' => (string) $order->getRemoteIp(),
52
+ );
53
+
54
+ if($customer->isLoggedIn()) {
55
+ $customerData = Mage::getModel('customer/customer')->load($customer->getId())->getData();
56
+ $customerProfile['firstName'] = (string) $customerData['firstname'];
57
+ $customerProfile['lastName'] = (string) $customerData['lastname'];;
58
+ } else {
59
+ $customerProfile['firstName'] = (string) 'Guest';
60
+ $customerProfile['lastName'] = (string) 'Customer';
61
+ }
62
+
63
+ // Order extended options
64
+ $extendedOptionsArray = array();
65
+
66
+ // Need to be sure this matches the store on which the order was placed
67
+ $transactionMode = Mage::getStoreConfig('payment/optimal_hosted/payment_action');
68
+
69
+ switch($transactionMode){
70
+ case Demac_Optimal_Model_Method_Hosted::ACTION_AUTHORIZE:
71
+ $extendedOptionsArray[] = array(
72
+ 'key' => (string) 'authType',
73
+ 'value' => (string) Demac_Optimal_Model_Config_Transaction::AUTH_VALUE
74
+ );
75
+ break;
76
+ case Demac_Optimal_Model_Method_Hosted::ACTION_AUTHORIZE_CAPTURE:
77
+ $extendedOptionsArray[] = array(
78
+ 'key' => (string) 'authType',
79
+ 'value' => (string) Demac_Optimal_Model_Config_Transaction::CAPT_VALUE
80
+ );
81
+ break;
82
+ default:
83
+ Mage::throwException($this->__("There is no transaction method set, please contact the website administrator."));
84
+ break;
85
+ }
86
+
87
+ $skip3d = Mage::getStoreConfig('payment/optimal_hosted/skip3d');
88
+
89
+ if($skip3d)
90
+ {
91
+ $extendedOptionsArray[] = array(
92
+ 'key' => (string) 'skip3D',
93
+ 'value' => true
94
+ );
95
+ }else {
96
+ $extendedOptionsArray[] = array(
97
+ 'key' => (string) 'skip3D',
98
+ 'value' => false
99
+ );
100
+ }
101
+
102
+ $addendumDataArray = array();
103
+ $threatMetrixId = Mage::getSingleton('core/session')->getThreatMetrixSessionKey();
104
+
105
+ if(isset($threatMetrixId) && Mage::getStoreConfig('payment/threat_metrix/active'))
106
+ {
107
+ $extendedOptionsArray[] = array(
108
+ 'key' => (string) 'threatMetrixSessionId',
109
+ 'value' => $threatMetrixId
110
+ );
111
+ }
112
+
113
+ // Ancillary fees information
114
+ $ancillaryFeesArray = array(
115
+ array(
116
+ 'amount' => (int)$helper->formatAmount($order->getBaseShippingAmount()),
117
+ 'description' => "Shipping Amount"
118
+ ),
119
+ array(
120
+ 'amount' => (int)$helper->formatAmount($order->getBaseTaxAmount()),
121
+ 'description' => "Tax Amount"
122
+ ),
123
+ array(
124
+ 'amount' => (int)$helper->formatAmount($order->getBaseDiscountAmount()),
125
+ 'description' => "Discount Amount"
126
+ ),
127
+ array(
128
+ 'amount' => (int)$helper->formatAmount($order->getBaseCustomerBalanceAmount()*-1),
129
+ 'description' => "Store Credit Amount"
130
+ )
131
+ );
132
+
133
+ // Billing Details information
134
+ $billingDetailsArray = array(
135
+ 'city' => (string) $billingAddress->getCity(),
136
+ 'country' => (string) $billingAddress->getCountryId(),
137
+ 'street' => (string) $helper->getStreetDetails($billingAddress->getStreet(),0),
138
+ 'street2' => (string) $helper->getStreetDetails($billingAddress->getStreet(),1),
139
+ 'zip' => (string) $billingAddress->getPostcode(),
140
+ 'phone' => (string) $billingAddress->getTelephone(),
141
+ );
142
+
143
+ if($billingDetailsArray['street2'] == '')
144
+ {
145
+ unset($billingDetailsArray['street2']);
146
+ }
147
+
148
+ if($billingAddress->getCountryId() === 'CA' || $billingAddress->getCountryId() === 'US')
149
+ {
150
+ $billingDetailsArray['state'] = (int) $billingAddress->getRegionCode();
151
+ }else {
152
+ $billingDetailsArray['state'] = (string) $billingAddress->getRegion();
153
+ }
154
+
155
+ if($billingAddress->getCustomerAddressId() === $shippingAddress->getCustomerAddressId())
156
+ {
157
+ $billingDetailsArray['useAsShippingAddress'] = true;
158
+ } else {
159
+ $billingDetailsArray['useAsShippingAddress'] = false;
160
+ }
161
+
162
+ // Shipping Details information
163
+ $shippingDetailsArray = array(
164
+ 'city' => (string) $shippingAddress->getCity(),
165
+ 'country' => (string) $shippingAddress->getCountryId(),
166
+ 'street' => (string) $helper->getStreetDetails($shippingAddress->getStreet(),0),
167
+ 'street2' => (string) $helper->getStreetDetails($shippingAddress->getStreet(),1),
168
+ 'zip' => (string) $shippingAddress->getPostcode(),
169
+ 'phone' => (string) $shippingAddress->getTelephone(),
170
+ );
171
+
172
+
173
+ if($shippingDetailsArray['street2'] == '')
174
+ {
175
+ unset($shippingDetailsArray['street2']);
176
+ }
177
+
178
+ $shippingDetailsArray['state'] = (string) $shippingAddress->getRegionCode();
179
+
180
+ if($shippingAddress->getCountryId() === 'CA' || $shippingAddress->getCountryId() === 'US')
181
+ {
182
+ $shippingDetailsArray['state'] = (int) $shippingAddress->getRegionCode();
183
+ }else {
184
+ $shippingDetailsArray['state'] = (string) $shippingAddress->getRegion();
185
+ }
186
+
187
+ // Shopping Cart Information
188
+ foreach($orderItems as $item)
189
+ {
190
+ $itemArray = array(
191
+ 'amount' => (int) $helper->formatAmount($item->getBasePrice()),
192
+ 'quantity' => (int) $item->getQtyOrdered(),
193
+ 'sku' => (string) $item->getSku(),
194
+ 'description' => (string) substr($item->getName(),0,45)
195
+ );
196
+
197
+ $shoppingCartArray[] = $itemArray;
198
+ }
199
+
200
+ // Callback information
201
+ $callbackArray = array();
202
+ $callbackArray[] = array(
203
+ 'format' => (string) 'json',
204
+ 'rel' => (string) 'on_success',
205
+ 'retries' => (int) Demac_Optimal_Model_Hosted_Client::CONNECTION_RETRIES,
206
+ 'returnKeys' => array(
207
+ 'id',
208
+ 'transaction.confirmationNumber',
209
+ 'transaction.status'
210
+ ),
211
+ 'synchronous' => true,
212
+ 'uri' => Mage::getBaseUrl()
213
+ );
214
+
215
+ // Callback information
216
+ $redirectArray = array();
217
+ $redirectArray[] = array(
218
+ 'rel' => (string) 'on_success',
219
+ 'returnKeys' => array(
220
+ 'id',
221
+ 'transaction.confirmationNumber',
222
+ 'transaction.status'
223
+ ),
224
+ 'uri' => Mage::getBaseUrl()
225
+ );
226
+ $redirectArray[] = array(
227
+ 'rel' => (string) 'on_error',
228
+ 'returnKeys' => array(
229
+ 'id',
230
+ 'transaction.confirmationNumber',
231
+ 'transaction.status'
232
+ ),
233
+ 'uri' => Mage::getBaseUrl()
234
+ );
235
+ $redirectArray[] = array(
236
+ 'rel' => (string) 'on_decline',
237
+ 'returnKeys' => array(
238
+ 'id',
239
+ 'transaction.confirmationNumber',
240
+ 'transaction.status'
241
+ ),
242
+ 'uri' => Mage::getBaseUrl()
243
+ );
244
+ $redirectArray[] = array(
245
+ 'rel' => (string) 'on_timeout',
246
+ 'returnKeys' => array(
247
+ 'id',
248
+ 'transaction.confirmationNumber',
249
+ 'transaction.status'
250
+ ),
251
+ 'uri' => Mage::getBaseUrl()
252
+ );
253
+ $redirectArray[] = array(
254
+ 'rel' => (string) 'on_hold',
255
+ 'returnKeys' => array(
256
+ 'id',
257
+ 'transaction.confirmationNumber',
258
+ 'transaction.status'
259
+ ),
260
+ 'uri' => Mage::getBaseUrl()
261
+ );
262
+
263
+ // Add extra information to the order Data
264
+ $data['shoppingCart'] = $shoppingCartArray;
265
+ $data['ancillaryFees'] = $ancillaryFeesArray;
266
+ $data['billingDetails'] = $billingDetailsArray;
267
+ $data['shippingDetails'] = $shippingDetailsArray;
268
+ $data['redirect'] = $redirectArray;
269
+ $data['profile'] = $customerProfile;
270
+ $data['extendedOptions'] = $extendedOptionsArray;
271
+ $data['addendumData'] = $addendumDataArray;
272
+
273
+ // Call Netbanks API and create the order
274
+ $response = $client->createOrder($data);
275
+ if (isset($response->link)) {
276
+ foreach ($response->link as $link) {
277
+ if($link->rel === 'hosted_payment') {
278
+ $postURL = $link->uri;
279
+ }
280
+ }
281
+ } else {
282
+ Mage::throwException($this->__("There was a problem creating the order"));
283
+ }
284
+
285
+ if(isset($postURL)){
286
+ $paymentData = $this->_preparePayment($order->getPayment()->getData());
287
+
288
+ $payment = $client->submitPayment($postURL,$paymentData);
289
+ $orderStatus = $client->retrieveOrder($response->id);
290
+ $transaction = $orderStatus->transaction;
291
+
292
+ // Now we need to check the payment status if the transaction is available
293
+ if(!isset($transaction) || $transaction->status == 'declined' || $transaction->status == 'cancelled')
294
+ {
295
+ Mage::throwException($this->__("There was a processing your payment"));
296
+ return false;
297
+ }else{
298
+ $order->addStatusHistoryComment(
299
+ 'Netbanks Order Id: ' . $orderStatus->id .'<br/>' .
300
+ 'Reference: # ' . $orderStatus->merchantRefNum .'<br/>' .
301
+ 'Transaction Id: ' . $transaction->confirmationNumber .'<br/>' .
302
+ 'Status: ' . $transaction->status .'<br/>'
303
+ );
304
+
305
+ $order->getPayment()->setAdditionalInformation('order', serialize(array('id' => $orderStatus->id)));
306
+ $order->getPayment()->setAdditionalInformation('transaction', serialize($transaction));
307
+ $order->getPayment()->setTransactionId($orderStatus->id);
308
+
309
+ return true;
310
+ }
311
+ }
312
+ }
313
+ }
314
+
315
+ /**
316
+ * Process the transaction response from
317
+ *
318
+ * @param Varien_Event_Observer $observer
319
+ */
320
+ public function salesOrderPlaceAfter(Varien_Event_Observer $observer)
321
+ {
322
+ $order = $observer->getOrder();
323
+ $payment = $order->getPayment();
324
+
325
+ $isCustomerNotified = false; // Customer Notification true/false.
326
+
327
+
328
+ if ($payment->getMethod() == 'optimal_hosted') {
329
+ $orderAdditionalInformation = $payment->getAdditionalInformation();
330
+ $transaction = unserialize($orderAdditionalInformation['transaction']);
331
+
332
+ if(!empty($transaction->riskReasonCode))
333
+ {
334
+ $riskCode = Mage::getModel('optimal/risk')->loadByCode($transaction->riskReasonCode);
335
+ }
336
+
337
+ switch ($transaction->status) {
338
+ case 'held':
339
+ $state = Mage_Sales_Model_Order::STATE_HOLDED;
340
+ $status = 'holded';
341
+ $comment = 'Order holded by ThreatMetrix.';
342
+
343
+ if ($riskCode->getStatus()) {
344
+ $status = $riskCode->getStatus();
345
+ $comment = 'ThreatMetrix Reason: ' . $transaction->description;
346
+ }
347
+ $order->setHoldBeforeState(Mage_Sales_Model_Order::STATE_PROCESSING);
348
+ $order->setHoldBeforeStatus('processing');
349
+
350
+ $order->setState($state, $status, $comment, $isCustomerNotified);
351
+ $order->save();
352
+ break;
353
+ case 'pending':
354
+ $state = Mage_Sales_Model_Order::STATE_PAYMENT_REVIEW;
355
+ $status = 'payment_review';
356
+ $comment = 'Order payment pending.';
357
+
358
+ $order->setState($state, $status, $comment, $isCustomerNotified);
359
+ $order->save();
360
+ break;
361
+ case 'abandoned':
362
+ $state = Mage_Sales_Model_Order::STATE_CANCELED;
363
+ $status = 'canceled';
364
+ $comment = 'Order was Abandoned.';
365
+
366
+ $order->setState($state, $status, $comment, $isCustomerNotified);
367
+ $order->save();
368
+ break;
369
+ }
370
+ }
371
+ }
372
+
373
+
374
+ /**
375
+ * @param $paymentData
376
+ * @return array
377
+ */
378
+ protected function _preparePayment($paymentData)
379
+ {
380
+ $fPaymentData = array(
381
+ 'cardNum' => (string) $paymentData['cc_number'],
382
+ 'cardExpiryMonth' => (int) $paymentData['cc_exp_month'],
383
+ 'cardExpiryYear' => (int) $paymentData['cc_exp_year'],
384
+ 'cvdNumber' => (string) $paymentData['cc_cid'],
385
+ );
386
+
387
+ return $fPaymentData;
388
+ }
389
+ }
app/code/community/Demac/Optimal/Model/Resource/Mysql4/Setup.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by JetBrains PhpStorm.
4
+ * User: amacgregor
5
+ * Date: 7/5/11
6
+ * Time: 3:31 PM
7
+ * To change this template use File | Settings | File Templates.
8
+ */
9
+
10
+ class Demac_Optimal_Model_Resource_Mysql4_Setup extends Mage_Core_Model_Resource_Setup
11
+ {
12
+
13
+ }
app/code/community/Demac/Optimal/Model/Risk.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Demac_Optimal_Model_Risk extends Mage_Core_Model_Abstract
4
+ {
5
+ public function __construct()
6
+ {
7
+ parent::_construct();
8
+ $this->_init('optimal/risk');
9
+ }
10
+
11
+ /**
12
+ * @param $manifestId
13
+ * @return Demac_CanadaPost_Model_Artifact
14
+ */
15
+ public function loadByCode($errorCode)
16
+ {
17
+ $this->_getResource()->loadByCode($this, $errorCode);
18
+ return $this;
19
+ }
20
+ }
app/code/community/Demac/Optimal/Model/Web/Client.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by JetBrains PhpStorm.
4
+ * User: Allan MacGregor - Magento Practice Lead <allan@demacmedia.com>
5
+ * Company: Demac Media Inc.
6
+ * Date: 6/20/13
7
+ * Time: 1:13 PM
8
+ */
9
+
10
+ class Demac_Optimal_Model_Web_Client extends Demac_Optimal_Model_Client_Abstract
11
+ {
12
+
13
+ }
app/code/community/Demac/Optimal/Test/Model/Hosted/Client.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Demac_Optimal_Test_Model_Hosted_Client extends EcomDev_PHPUnit_Test_Case
4
+ {
5
+
6
+
7
+ /**
8
+ * Test that the payment method can authorize
9
+ *
10
+ * @test
11
+ */
12
+ public function canAuthorize()
13
+ {
14
+ $this->assertEquals(true, false);
15
+ }
16
+ }
app/code/community/Demac/Optimal/Test/Model/Method/Hosted.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Demac_Optimal_Test_Model_Method_Hosted extends EcomDev_PHPUnit_Test_Case
4
+ {
5
+
6
+ /**
7
+ * Test that the payment method can authorize
8
+ *
9
+ * @test
10
+ */
11
+ public function canAuthorize()
12
+ {
13
+ $method = Mage::getModel('optimal/method_hosted');
14
+
15
+ $this->assertEquals(true, $method->canAuthorize());
16
+ }
17
+ }
app/code/community/Demac/Optimal/Test/Model/Observer.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Demac_Optimal_Test_Model_Observer extends EcomDev_PHPUnit_Test_Case
4
+ {
5
+ public function prepareOrderData()
6
+ {
7
+
8
+ }
9
+ }
app/code/community/Demac/Optimal/controllers/Adminhtml/ThreatController.php ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Demac_Optimal_Adminhtml_ThreatController extends Mage_Adminhtml_Controller_Action
4
+ {
5
+ public function _initAction()
6
+ {
7
+ $this->loadLayout()
8
+ ->_setActiveMenu('system/optimal/mapping')
9
+ ->_addBreadcrumb(Mage::helper('adminhtml')->__('Risk Code Status Manager'), Mage::helper('adminhtml')->__('Risk Code Status Manager'));
10
+ return $this;
11
+ }
12
+
13
+ public function indexAction()
14
+ {
15
+ $this->_initAction();
16
+ $this->_addContent($this->getLayout()->createBlock('optimal/adminhtml_risk'));
17
+ $this->renderLayout();
18
+ }
19
+
20
+ public function editAction()
21
+ {
22
+ $modelId = $this->getRequest()->getParam('id');
23
+ $model = Mage::getModel('optimal/risk')->load($modelId);
24
+
25
+ if ($model->getId() || $modelId == 0) {
26
+
27
+ $data = Mage::getSingleton('adminhtml/session')->getFormData(true);
28
+ if (!empty($data)) {
29
+ $model->setData($data);
30
+ }
31
+ Mage::register('mapping_data', $model);
32
+
33
+ $this->loadLayout();
34
+ $this->_setActiveMenu('system/optimal');
35
+
36
+ $this->_addBreadcrumb(Mage::helper('adminhtml')->__('Risk Error Codes Manager'), Mage::helper('adminhtml')->__('Risk Error Codes Manager'));
37
+ $this->_addBreadcrumb(Mage::helper('adminhtml')->__('Add Mapping'), Mage::helper('adminhtml')->__('Add Mapping'));
38
+
39
+ $this->getLayout()->getBlock('head')->setCanLoadExtJs(true);
40
+ if (Mage::getSingleton('cms/wysiwyg_config')->isEnabled()) {
41
+ $this->getLayout()->getBlock('head')->setCanLoadTinyMce(true);
42
+ }
43
+
44
+ $this->_addContent($this->getLayout()->createBlock('optimal/adminhtml_risk_edit'))
45
+ ->_addLeft($this->getLayout()->createBlock('optimal/adminhtml_risk_edit_tabs'));
46
+
47
+ $this->renderLayout();
48
+ } else {
49
+ Mage::getSingleton('adminhtml/session')->addError(Mage::helper('optimal')->__('Mapping does not exist'));
50
+ $this->_redirect('*/*/');
51
+ }
52
+ }
53
+
54
+ public function newAction()
55
+ {
56
+ $this->_forward('edit');
57
+ }
58
+
59
+ public function saveAction()
60
+ {
61
+ if ( $this->getRequest()->getPost() ) {
62
+ try {
63
+ $postData = $this->getRequest()->getPost();
64
+ $model = Mage::getModel('optimal/risk');
65
+
66
+ $model->setId($this->getRequest()->getParam('id'))
67
+ ->setDescription($postData['description'])
68
+ ->setRiskCode($postData['risk_code'])
69
+ ->setStatus($postData['status'])
70
+ ->save();
71
+
72
+ Mage::getSingleton('adminhtml/session')->addSuccess(Mage::helper('adminhtml')->__('Item was successfully saved'));
73
+ Mage::getSingleton('adminhtml/session')->setDescriptionData(false);
74
+
75
+ $this->_redirect('*/*/');
76
+ return;
77
+ } catch (Exception $e) {
78
+ Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
79
+ Mage::getSingleton('adminhtml/session')->setDescriptionData($this->getRequest()->getPost());
80
+ $this->_redirect('*/*/edit', array('id' => $this->getRequest()->getParam('id')));
81
+ return;
82
+ }
83
+ }
84
+ $this->_redirect('*/*/');
85
+ }
86
+
87
+ public function deleteAction()
88
+ {
89
+ if( $this->getRequest()->getParam('id') > 0 ) {
90
+ try {
91
+ $model = Mage::getModel('optimal/risk');
92
+
93
+ $model->setId($this->getRequest()->getParam('id'))
94
+ ->delete();
95
+
96
+ Mage::getSingleton('adminhtml/session')->addSuccess(Mage::helper('adminhtml')->__('Item was successfully deleted'));
97
+ $this->_redirect('*/*/');
98
+ } catch (Exception $e) {
99
+ Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
100
+ $this->_redirect('*/*/edit', array('id' => $this->getRequest()->getParam('id')));
101
+ }
102
+ }
103
+ $this->_redirect('*/*/');
104
+ }
105
+
106
+ }
app/code/community/Demac/Optimal/etc/adminhtml.xml ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <config>
2
+ <menu>
3
+ <system translate="title" module="optimal">
4
+ <children>
5
+ <optimal translate="title" module="optimal">
6
+ <title>Optimal Payments</title>
7
+ <sort_order>1</sort_order>
8
+ <children>
9
+ <mapping translate="title" module="optimal">
10
+ <title>Manage ThreatMetrix Mappings</title>
11
+ <sort_order>1</sort_order>
12
+ <action>adminhtml/threat/index</action>
13
+ </mapping>
14
+ </children>
15
+ </optimal>
16
+ </children>
17
+ </system>
18
+ </menu>
19
+ <acl>
20
+ <resources>
21
+ <admin>
22
+ <children>
23
+ <system translate="title" module="optimal">
24
+ <children>
25
+ <optimal translate="title" module="optimal">
26
+ <title>Optimal Payments</title>
27
+ <sort_order>1</sort_order>
28
+ <children>
29
+ <mapping translate="title" module="optimal">
30
+ <title>Manage ThreatMetrix Mappings</title>
31
+ <sort_order>1</sort_order>
32
+ </mapping>
33
+ </children>
34
+ </optimal>
35
+ </children>
36
+ </system>
37
+ </children>
38
+ </admin>
39
+ </resources>
40
+ </acl>
41
+ </config>
app/code/community/Demac/Optimal/etc/config.xml ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Demac_Optimal>
5
+ <version>0.1.2</version>
6
+ </Demac_Optimal>
7
+ </modules>
8
+
9
+ <phpunit>
10
+ <suite>
11
+ <modules>
12
+ <Demac_Optimal/>
13
+ </modules>
14
+ </suite>
15
+ </phpunit>
16
+
17
+ <adminhtml>
18
+ <layout>
19
+ <updates>
20
+ <optimal module="dcp">
21
+ <file>optimal.xml</file>
22
+ </optimal>
23
+ </updates>
24
+ </layout>
25
+ </adminhtml>
26
+
27
+ <frontend>
28
+ <layout>
29
+ <updates>
30
+ <optimal module="optimal">
31
+ <file>optimal.xml</file>
32
+ </optimal>
33
+ </updates>
34
+ </layout>
35
+ <routers>
36
+ <optimal>
37
+ <use>standard</use>
38
+ <args>
39
+ <module>Demac_Optimal</module>
40
+ <frontName>optimal</frontName>
41
+ </args>
42
+ </optimal>
43
+ </routers>
44
+ <frontend>
45
+ <translate>
46
+ <modules>
47
+ <translations>
48
+ <files>
49
+ <default>Demac_Optimal.csv</default>
50
+ </files>
51
+ </translations>
52
+ </modules>
53
+ </translate>
54
+ </frontend>
55
+
56
+ <events>
57
+ <sales_order_place_before>
58
+ <observers>
59
+ <optimal_hosted_order>
60
+ <type>singleton</type>
61
+ <class>Demac_Optimal_Model_Observer</class>
62
+ <method>salesOrderPlaceBefore</method>
63
+ </optimal_hosted_order>
64
+ </observers>
65
+ </sales_order_place_before>
66
+ <sales_order_place_after>
67
+ <observers>
68
+ <optimal_hosted_order_after>
69
+ <type>singleton</type>
70
+ <class>Demac_Optimal_Model_Observer</class>
71
+ <method>salesOrderPlaceAfter</method>
72
+ </optimal_hosted_order_after>
73
+ </observers>
74
+ </sales_order_place_after>
75
+ </events>
76
+
77
+ </frontend>
78
+ <global>
79
+ <models>
80
+ <optimal>
81
+ <class>Demac_Optimal_Model</class>
82
+ <resourceModel>optimal_mysql4</resourceModel>
83
+ </optimal>
84
+ <optimal_mysql4>
85
+ <class>Demac_Optimal_Model_Mysql4</class>
86
+ <entities>
87
+ <risk>
88
+ <table>demac_optimal_risk</table>
89
+ </risk>
90
+ </entities>
91
+ </optimal_mysql4>
92
+ </models>
93
+ <blocks>
94
+ <optimal>
95
+ <class>Demac_Optimal_Block</class>
96
+ </optimal>
97
+ </blocks>
98
+ <helpers>
99
+ <optimal>
100
+ <class>Demac_Optimal_Helper</class>
101
+ </optimal>
102
+ </helpers>
103
+ <resources>
104
+ <optimal_setup>
105
+ <setup>
106
+ <module>Demac_Optimal</module>
107
+ <class>Demac_Optimal_Model_Resource_Mysql4_Setup</class>
108
+ </setup>
109
+ <connection>
110
+ <use>core_setup</use>
111
+ </connection>
112
+ </optimal_setup>
113
+ <optimal_write>
114
+ <connection>
115
+ <use>core_write</use>
116
+ </connection>
117
+ </optimal_write>
118
+ <optimal_read>
119
+ <connection>
120
+ <use>core_read</use>
121
+ </connection>
122
+ </optimal_read>
123
+ </resources>
124
+ </global>
125
+
126
+ <admin>
127
+ <routers>
128
+ <adminhtml>
129
+ <args>
130
+ <modules>
131
+ <optimal before="Mage_Adminhtml">Demac_Optimal_Adminhtml</optimal>
132
+ </modules>
133
+ </args>
134
+ </adminhtml>
135
+ </routers>
136
+ </admin>
137
+
138
+
139
+ <!-- declare default configuration values for this module -->
140
+ <default>
141
+ <!-- 'payment' configuration section (tab) -->
142
+ <payment>
143
+ <!-- 'newmodule' configuration group (fieldset) -->
144
+ <optimal_hosted>
145
+ <!-- by default this payment method is inactive -->
146
+ <active>0</active>
147
+ <useccv>1</useccv>
148
+ <!-- model to handle logic for this payment method -->
149
+ <model>optimal/method_hosted</model>
150
+ <!-- order status for new orders paid by this payment method -->
151
+ <order_status>pending</order_status>
152
+ <!-- default title for payment checkout page and order view page -->
153
+ <title>Optimal Payments (Hosted)</title>
154
+ <payment_action>authorize</payment_action>
155
+ <cctypes>AE,VI,MC,DI</cctypes>
156
+ <!--<payment_action>authorize</payment_action>-->
157
+ <allowspecific>0</allowspecific>
158
+ </optimal_hosted>
159
+ </payment>
160
+ </default>
161
+ </config>
app/code/community/Demac/Optimal/etc/system.xml ADDED
@@ -0,0 +1,385 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <sections>
4
+ <payment>
5
+ <groups>
6
+ <optimal_hosted translate="label" module="optimal">
7
+ <label>Optimal Payments - Hosted</label>
8
+ <frontend_type>text</frontend_type>
9
+ <sort_order>34</sort_order>
10
+ <show_in_default>1</show_in_default>
11
+ <show_in_website>1</show_in_website>
12
+ <show_in_store>1</show_in_store>
13
+ <fields>
14
+ <active translate="label">
15
+ <label>Enabled</label>
16
+ <frontend_type>select</frontend_type>
17
+ <source_model>adminhtml/system_config_source_yesno</source_model>
18
+ <sort_order>10</sort_order>
19
+ <show_in_default>1</show_in_default>
20
+ <show_in_website>1</show_in_website>
21
+ <show_in_store>0</show_in_store>
22
+ </active>
23
+ <mode translate="label">
24
+ <label>Mode</label>
25
+ <frontend_type>select</frontend_type>
26
+ <sort_order>11</sort_order>
27
+ <source_model>optimal/config_mode</source_model>
28
+ <show_in_default>1</show_in_default>
29
+ <show_in_website>1</show_in_website>
30
+ <show_in_store>1</show_in_store>
31
+ </mode>
32
+ <payment_action>
33
+ <label>Transaction Type</label>
34
+ <frontend_type>select</frontend_type>
35
+ <sort_order>12</sort_order>
36
+ <source_model>optimal/config_transaction</source_model>
37
+ <show_in_default>1</show_in_default>
38
+ <show_in_website>1</show_in_website>
39
+ <show_in_store>1</show_in_store>
40
+ </payment_action>
41
+
42
+ <login translate="label">
43
+ <label>API Login ID</label>
44
+ <frontend_type>obscure</frontend_type>
45
+ <backend_model>adminhtml/system_config_backend_encrypted</backend_model>
46
+ <sort_order>21</sort_order>
47
+ <show_in_default>1</show_in_default>
48
+ <show_in_website>1</show_in_website>
49
+ <show_in_store>0</show_in_store>
50
+ </login>
51
+ <trans_key translate="label">
52
+ <label>Transaction Key</label>
53
+ <frontend_type>obscure</frontend_type>
54
+ <backend_model>adminhtml/system_config_backend_encrypted</backend_model>
55
+ <sort_order>22</sort_order>
56
+ <show_in_default>1</show_in_default>
57
+ <show_in_website>1</show_in_website>
58
+ <show_in_store>0</show_in_store>
59
+ </trans_key>
60
+
61
+ <title translate="label">
62
+ <label>Title</label>
63
+ <frontend_type>text</frontend_type>
64
+ <sort_order>30</sort_order>
65
+ <show_in_default>1</show_in_default>
66
+ <show_in_website>1</show_in_website>
67
+ <show_in_store>1</show_in_store>
68
+ </title>
69
+ <order_status translate="label">
70
+ <label>New Order Status</label>
71
+ <frontend_type>select</frontend_type>
72
+ <source_model>adminhtml/system_config_source_order_status_processing</source_model>
73
+ <sort_order>70</sort_order>
74
+ <show_in_default>1</show_in_default>
75
+ <show_in_website>1</show_in_website>
76
+ <show_in_store>0</show_in_store>
77
+ </order_status>
78
+ <debug translate="label">
79
+ <label>Debug</label>
80
+ <frontend_type>select</frontend_type>
81
+ <source_model>adminhtml/system_config_source_yesno</source_model>
82
+ <sort_order>110</sort_order>
83
+ <show_in_default>1</show_in_default>
84
+ <show_in_website>1</show_in_website>
85
+ <show_in_store>0</show_in_store>
86
+ </debug>
87
+ <email_customer translate="label">
88
+ <label>Email Customer</label>
89
+ <frontend_type>select</frontend_type>
90
+ <source_model>adminhtml/system_config_source_yesno</source_model>
91
+ <sort_order>120</sort_order>
92
+ <show_in_default>1</show_in_default>
93
+ <show_in_website>1</show_in_website>
94
+ <show_in_store>0</show_in_store>
95
+ </email_customer>
96
+ <merchant_email translate="label">
97
+ <label>Merchant's Email</label>
98
+ <frontend_type>text</frontend_type>
99
+ <validate>validate-email</validate>
100
+ <sort_order>130</sort_order>
101
+ <show_in_default>1</show_in_default>
102
+ <show_in_website>1</show_in_website>
103
+ <show_in_store>0</show_in_store>
104
+ </merchant_email>
105
+ <cctypes translate="label">
106
+ <label>Credit Card Types</label>
107
+ <frontend_type>multiselect</frontend_type>
108
+ <source_model>paygate/authorizenet_source_cctype</source_model>
109
+ <sort_order>140</sort_order>
110
+ <show_in_default>1</show_in_default>
111
+ <show_in_website>1</show_in_website>
112
+ <show_in_store>0</show_in_store>
113
+ </cctypes>
114
+ <skip3D translate="label">
115
+ <label>Skip 3D Secure Verification</label>
116
+ <frontend_type>select</frontend_type>
117
+ <source_model>adminhtml/system_config_source_yesno</source_model>
118
+ <sort_order>150</sort_order>
119
+ <show_in_default>1</show_in_default>
120
+ <show_in_website>1</show_in_website>
121
+ <show_in_store>0</show_in_store>
122
+ </skip3D>
123
+ <allowspecific translate="label">
124
+ <label>Payment from Applicable Countries</label>
125
+ <frontend_type>allowspecific</frontend_type>
126
+ <sort_order>160</sort_order>
127
+ <source_model>adminhtml/system_config_source_payment_allspecificcountries</source_model>
128
+ <show_in_default>1</show_in_default>
129
+ <show_in_website>1</show_in_website>
130
+ <show_in_store>0</show_in_store>
131
+ </allowspecific>
132
+ <specificcountry translate="label">
133
+ <label>Payment from Specific Countries</label>
134
+ <frontend_type>multiselect</frontend_type>
135
+ <sort_order>170</sort_order>
136
+ <source_model>adminhtml/system_config_source_country</source_model>
137
+ <show_in_default>1</show_in_default>
138
+ <show_in_website>1</show_in_website>
139
+ <show_in_store>0</show_in_store>
140
+ </specificcountry>
141
+ <min_order_total translate="label">
142
+ <label>Minimum Order Total</label>
143
+ <frontend_type>text</frontend_type>
144
+ <sort_order>180</sort_order>
145
+ <show_in_default>1</show_in_default>
146
+ <show_in_website>1</show_in_website>
147
+ <show_in_store>0</show_in_store>
148
+ </min_order_total>
149
+ <max_order_total translate="label">
150
+ <label>Maximum Order Total</label>
151
+ <frontend_type>text</frontend_type>
152
+ <sort_order>190</sort_order>
153
+ <show_in_default>1</show_in_default>
154
+ <show_in_website>1</show_in_website>
155
+ <show_in_store>0</show_in_store>
156
+ </max_order_total>
157
+ <sort_order translate="label">
158
+ <label>Sort Order</label>
159
+ <frontend_type>text</frontend_type>
160
+ <sort_order>200</sort_order>
161
+ <show_in_default>1</show_in_default>
162
+ <show_in_website>1</show_in_website>
163
+ <show_in_store>0</show_in_store>
164
+ <frontend_class>validate-number</frontend_class>
165
+ </sort_order>
166
+ </fields>
167
+ </optimal_hosted>
168
+ <threat_metrix translate="label" module="optimal">
169
+ <label>Optimal Payments - ThreatMetrix</label>
170
+ <frontend_type>text</frontend_type>
171
+ <sort_order>34</sort_order>
172
+ <show_in_default>1</show_in_default>
173
+ <show_in_website>1</show_in_website>
174
+ <show_in_store>1</show_in_store>
175
+ <fields>
176
+ <active translate="label">
177
+ <label>Enabled</label>
178
+ <frontend_type>select</frontend_type>
179
+ <source_model>adminhtml/system_config_source_yesno</source_model>
180
+ <sort_order>10</sort_order>
181
+ <show_in_default>1</show_in_default>
182
+ <show_in_website>1</show_in_website>
183
+ <show_in_store>0</show_in_store>
184
+ </active>
185
+ <org_id translate="label">
186
+ <label>Organization Id </label>
187
+ <frontend_type>text</frontend_type>
188
+ <sort_order>11</sort_order>
189
+ <show_in_default>1</show_in_default>
190
+ <show_in_website>1</show_in_website>
191
+ <show_in_store>0</show_in_store>
192
+ </org_id>
193
+ </fields>
194
+ </threat_metrix>
195
+ <!--<optimal_web translate="label" module="optimal">-->
196
+ <!--<label>Optimal Payments - Web API</label>-->
197
+ <!--<frontend_type>text</frontend_type>-->
198
+ <!--<sort_order>34</sort_order>-->
199
+ <!--<show_in_default>1</show_in_default>-->
200
+ <!--<show_in_website>1</show_in_website>-->
201
+ <!--<show_in_store>1</show_in_store>-->
202
+ <!--<fields>-->
203
+ <!--<active translate="label">-->
204
+ <!--<label>Enabled</label>-->
205
+ <!--<frontend_type>select</frontend_type>-->
206
+ <!--<source_model>adminhtml/system_config_source_yesno</source_model>-->
207
+ <!--<sort_order>10</sort_order>-->
208
+ <!--<show_in_default>1</show_in_default>-->
209
+ <!--<show_in_website>1</show_in_website>-->
210
+ <!--<show_in_store>0</show_in_store>-->
211
+ <!--</active>-->
212
+ <!--<payment_action translate="label">-->
213
+ <!--<label>Payment Action</label>-->
214
+ <!--<frontend_type>select</frontend_type>-->
215
+ <!--<source_model>paygate/authorizenet_source_paymentAction</source_model>-->
216
+ <!--<sort_order>20</sort_order>-->
217
+ <!--<show_in_default>1</show_in_default>-->
218
+ <!--<show_in_website>1</show_in_website>-->
219
+ <!--<show_in_store>0</show_in_store>-->
220
+ <!--</payment_action>-->
221
+ <!--<title translate="label">-->
222
+ <!--<label>Title</label>-->
223
+ <!--<frontend_type>text</frontend_type>-->
224
+ <!--<sort_order>30</sort_order>-->
225
+ <!--<show_in_default>1</show_in_default>-->
226
+ <!--<show_in_website>1</show_in_website>-->
227
+ <!--<show_in_store>1</show_in_store>-->
228
+ <!--</title>-->
229
+ <!--<login translate="label">-->
230
+ <!--<label>API Login ID</label>-->
231
+ <!--<frontend_type>obscure</frontend_type>-->
232
+ <!--<backend_model>adminhtml/system_config_backend_encrypted</backend_model>-->
233
+ <!--<sort_order>40</sort_order>-->
234
+ <!--<show_in_default>1</show_in_default>-->
235
+ <!--<show_in_website>1</show_in_website>-->
236
+ <!--<show_in_store>0</show_in_store>-->
237
+ <!--</login>-->
238
+ <!--<trans_key translate="label">-->
239
+ <!--<label>Transaction Key</label>-->
240
+ <!--<frontend_type>obscure</frontend_type>-->
241
+ <!--<backend_model>adminhtml/system_config_backend_encrypted</backend_model>-->
242
+ <!--<sort_order>50</sort_order>-->
243
+ <!--<show_in_default>1</show_in_default>-->
244
+ <!--<show_in_website>1</show_in_website>-->
245
+ <!--<show_in_store>0</show_in_store>-->
246
+ <!--</trans_key>-->
247
+ <!--<trans_md5 translate="label">-->
248
+ <!--<label>Merchant MD5</label>-->
249
+ <!--<frontend_type>obscure</frontend_type>-->
250
+ <!--<backend_model>adminhtml/system_config_backend_encrypted</backend_model>-->
251
+ <!--<sort_order>60</sort_order>-->
252
+ <!--<show_in_default>1</show_in_default>-->
253
+ <!--<show_in_website>1</show_in_website>-->
254
+ <!--<show_in_store>0</show_in_store>-->
255
+ <!--</trans_md5>-->
256
+ <!--<order_status translate="label">-->
257
+ <!--<label>New Order Status</label>-->
258
+ <!--<frontend_type>select</frontend_type>-->
259
+ <!--<source_model>adminhtml/system_config_source_order_status_processing</source_model>-->
260
+ <!--<sort_order>70</sort_order>-->
261
+ <!--<show_in_default>1</show_in_default>-->
262
+ <!--<show_in_website>1</show_in_website>-->
263
+ <!--<show_in_store>0</show_in_store>-->
264
+ <!--</order_status>-->
265
+ <!--<test translate="label">-->
266
+ <!--<label>Test Mode</label>-->
267
+ <!--<frontend_type>select</frontend_type>-->
268
+ <!--<source_model>adminhtml/system_config_source_yesno</source_model>-->
269
+ <!--<sort_order>80</sort_order>-->
270
+ <!--<show_in_default>1</show_in_default>-->
271
+ <!--<show_in_website>1</show_in_website>-->
272
+ <!--<show_in_store>0</show_in_store>-->
273
+ <!--</test>-->
274
+ <!--<cgi_url translate="label">-->
275
+ <!--<label>Gateway URL</label>-->
276
+ <!--<frontend_type>text</frontend_type>-->
277
+ <!--<sort_order>90</sort_order>-->
278
+ <!--<show_in_default>1</show_in_default>-->
279
+ <!--<show_in_website>1</show_in_website>-->
280
+ <!--<show_in_store>0</show_in_store>-->
281
+ <!--</cgi_url>-->
282
+ <!--<currency translate="label">-->
283
+ <!--<label>Accepted Currency</label>-->
284
+ <!--<frontend_type>select</frontend_type>-->
285
+ <!--<source_model>adminhtml/system_config_source_currency</source_model>-->
286
+ <!--<sort_order>100</sort_order>-->
287
+ <!--<show_in_default>1</show_in_default>-->
288
+ <!--<show_in_website>1</show_in_website>-->
289
+ <!--<show_in_store>0</show_in_store>-->
290
+ <!--</currency>-->
291
+ <!--<debug translate="label">-->
292
+ <!--<label>Debug</label>-->
293
+ <!--<frontend_type>select</frontend_type>-->
294
+ <!--<source_model>adminhtml/system_config_source_yesno</source_model>-->
295
+ <!--<sort_order>110</sort_order>-->
296
+ <!--<show_in_default>1</show_in_default>-->
297
+ <!--<show_in_website>1</show_in_website>-->
298
+ <!--<show_in_store>0</show_in_store>-->
299
+ <!--</debug>-->
300
+ <!--<email_customer translate="label">-->
301
+ <!--<label>Email Customer</label>-->
302
+ <!--<frontend_type>select</frontend_type>-->
303
+ <!--<source_model>adminhtml/system_config_source_yesno</source_model>-->
304
+ <!--<sort_order>120</sort_order>-->
305
+ <!--<show_in_default>1</show_in_default>-->
306
+ <!--<show_in_website>1</show_in_website>-->
307
+ <!--<show_in_store>0</show_in_store>-->
308
+ <!--</email_customer>-->
309
+ <!--<merchant_email translate="label">-->
310
+ <!--<label>Merchant's Email</label>-->
311
+ <!--<frontend_type>text</frontend_type>-->
312
+ <!--<validate>validate-email</validate>-->
313
+ <!--<sort_order>130</sort_order>-->
314
+ <!--<show_in_default>1</show_in_default>-->
315
+ <!--<show_in_website>1</show_in_website>-->
316
+ <!--<show_in_store>0</show_in_store>-->
317
+ <!--</merchant_email>-->
318
+ <!--<cctypes translate="label">-->
319
+ <!--<label>Credit Card Types</label>-->
320
+ <!--<frontend_type>multiselect</frontend_type>-->
321
+ <!--<source_model>paygate/authorizenet_source_cctype</source_model>-->
322
+ <!--<sort_order>140</sort_order>-->
323
+ <!--<show_in_default>1</show_in_default>-->
324
+ <!--<show_in_website>1</show_in_website>-->
325
+ <!--<show_in_store>0</show_in_store>-->
326
+ <!--</cctypes>-->
327
+ <!--<useccv translate="label">-->
328
+ <!--<label>Credit Card Verification</label>-->
329
+ <!--<frontend_type>select</frontend_type>-->
330
+ <!--<source_model>adminhtml/system_config_source_yesno</source_model>-->
331
+ <!--<sort_order>150</sort_order>-->
332
+ <!--<show_in_default>1</show_in_default>-->
333
+ <!--<show_in_website>1</show_in_website>-->
334
+ <!--<show_in_store>0</show_in_store>-->
335
+ <!--</useccv>-->
336
+ <!--<allowspecific translate="label">-->
337
+ <!--<label>Payment from Applicable Countries</label>-->
338
+ <!--<frontend_type>allowspecific</frontend_type>-->
339
+ <!--<sort_order>160</sort_order>-->
340
+ <!--<source_model>adminhtml/system_config_source_payment_allspecificcountries</source_model>-->
341
+ <!--<show_in_default>1</show_in_default>-->
342
+ <!--<show_in_website>1</show_in_website>-->
343
+ <!--<show_in_store>0</show_in_store>-->
344
+ <!--</allowspecific>-->
345
+ <!--<specificcountry translate="label">-->
346
+ <!--<label>Payment from Specific Countries</label>-->
347
+ <!--<frontend_type>multiselect</frontend_type>-->
348
+ <!--<sort_order>170</sort_order>-->
349
+ <!--<source_model>adminhtml/system_config_source_country</source_model>-->
350
+ <!--<show_in_default>1</show_in_default>-->
351
+ <!--<show_in_website>1</show_in_website>-->
352
+ <!--<show_in_store>0</show_in_store>-->
353
+ <!--</specificcountry>-->
354
+ <!--<min_order_total translate="label">-->
355
+ <!--<label>Minimum Order Total</label>-->
356
+ <!--<frontend_type>text</frontend_type>-->
357
+ <!--<sort_order>180</sort_order>-->
358
+ <!--<show_in_default>1</show_in_default>-->
359
+ <!--<show_in_website>1</show_in_website>-->
360
+ <!--<show_in_store>0</show_in_store>-->
361
+ <!--</min_order_total>-->
362
+ <!--<max_order_total translate="label">-->
363
+ <!--<label>Maximum Order Total</label>-->
364
+ <!--<frontend_type>text</frontend_type>-->
365
+ <!--<sort_order>190</sort_order>-->
366
+ <!--<show_in_default>1</show_in_default>-->
367
+ <!--<show_in_website>1</show_in_website>-->
368
+ <!--<show_in_store>0</show_in_store>-->
369
+ <!--</max_order_total>-->
370
+ <!--<sort_order translate="label">-->
371
+ <!--<label>Sort Order</label>-->
372
+ <!--<frontend_type>text</frontend_type>-->
373
+ <!--<sort_order>200</sort_order>-->
374
+ <!--<show_in_default>1</show_in_default>-->
375
+ <!--<show_in_website>1</show_in_website>-->
376
+ <!--<show_in_store>0</show_in_store>-->
377
+ <!--<frontend_class>validate-number</frontend_class>-->
378
+ <!--</sort_order>-->
379
+ <!--</fields>-->
380
+ <!--</optimal_web>-->
381
+
382
+ </groups>
383
+ </payment>
384
+ </sections>
385
+ </config>
app/code/community/Demac/Optimal/sql/optimal_setup/install-0.1.1.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ $installer = $this;
4
+
5
+ $installer->startSetup();
6
+
7
+ $installer->run("
8
+
9
+ DROP TABLE IF EXISTS `{$this->getTable('optimal/risk')}`;
10
+ CREATE TABLE IF NOT EXISTS `{$this->getTable('optimal/risk')}` (
11
+ `entity_id` int(20) unsigned NOT NULL AUTO_INCREMENT,
12
+ `risk_code` varchar(255) NOT NULL DEFAULT '',
13
+ `description` text NOT NULL,
14
+ `status` varchar(255) NOT NULL DEFAULT '',
15
+ `created_at` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
16
+ PRIMARY KEY (`entity_id`),
17
+ KEY `risk_code` (`risk_code`),
18
+ KEY `status` (`status`),
19
+ KEY `created_at` (`created_at`)
20
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
21
+
22
+ ");
23
+
24
+ $installer->endSetup();
app/code/community/Demac/Optimal/sql/optimal_setup/mysql4-install-0.1.1.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ $installer = $this;
4
+
5
+ $installer->startSetup();
6
+
7
+ $installer->run("
8
+
9
+ DROP TABLE IF EXISTS `{$this->getTable('optimal/risk')}`;
10
+ CREATE TABLE IF NOT EXISTS `{$this->getTable('optimal/risk')}` (
11
+ `entity_id` int(20) unsigned NOT NULL AUTO_INCREMENT,
12
+ `risk_code` varchar(255) NOT NULL DEFAULT '',
13
+ `description` text NOT NULL,
14
+ `status` varchar(255) NOT NULL DEFAULT '',
15
+ `created_at` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
16
+ PRIMARY KEY (`entity_id`),
17
+ KEY `risk_code` (`risk_code`),
18
+ KEY `status` (`status`),
19
+ KEY `created_at` (`created_at`)
20
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
21
+
22
+ ");
23
+
24
+ $installer->endSetup();
app/design/frontend/base/default/layout/optimal.xml ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <layout version="0.1.0"> i
3
+ <checkout_onepage_index translate="label" module="page">
4
+ <reference name="before_body_end">
5
+ <block type="optimal/threat" template="demac/threatmeter.phtml" name="optimal_threat" as="optimal_threat"/>
6
+ </reference>
7
+ </checkout_onepage_index>
8
+ </layout>
app/design/frontend/base/default/template/demac/threatmeter.phtml ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if($this->isThreatMetrixActive()): ?>
2
+
3
+ <!-Begin ThreatMetrix profiling tags below -->
4
+ <p style="background:url('<?php echo $this->getThreatMetrixUrl(1) ?>')"></p>
5
+ <img src="<?php echo $this->getThreatMetrixUrl(2) ?>" alt="" >
6
+
7
+ <script src="<?php echo $this->getThreatMetrixUrl() ?>" type="text/javascript">
8
+ </script>
9
+
10
+ <object type="application/x-shockwave-flash" data="<?php echo $this->getThreatMetrixUrl() ?>" width="1" height="1" id="obj_id">
11
+ <param name="movie" value="<?php echo $this->getThreatMetrixUrl() ?>" />
12
+ </object>
13
+ <!- End profiling tags -->
14
+
15
+ <?php endif; ?>
app/etc/modules/Demac_Optimal.xml ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <config>
2
+ <modules>
3
+ <Demac_Optimal>
4
+ <active>true</active>
5
+ <codePool>community</codePool>
6
+ <depends>
7
+ <Mage_Payment />
8
+ </depends>
9
+ </Demac_Optimal>
10
+ </modules>
11
+ </config>
package.xml ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <package>
3
+ <name>666999</name>
4
+ <version>0.1.2</version>
5
+ <stability>beta</stability>
6
+ <license uri="http://opensource.org/licenses/GPL-3.0">GPL 3.0</license>
7
+ <channel>community</channel>
8
+ <extends/>
9
+ <summary>Securely access and process online payments with the NETBANX payment gateway.&#xD;
10
+ </summary>
11
+ <description>The Optimal Payments Magento extension allows ecommerce businesses to securely accept and process online payments using Optimal&#x2019;s NETBANX payment gateway and services. The integration is easy to implement and provides the ultimate in payment processing capabilities, fraud management, and reporting.&#xD;
12
+ &lt;br /&gt; &lt;br /&gt;&#xD;
13
+ The Optimal Payments extension uses a Silent Post integration to the merchant&#x2019;s website. During checkout, payment information is entered on the merchant website and then transmitted securely via Silent Post for processing to the NETBANX payment gateway. The customer remains on the merchant&#x2019;s website at all times allowing the merchant to manage the customer experience. When the customer clicks on the Pay button, payment data is transmitted directly to NETBANX using a PCI-compliant process without accessing any merchant servers.&#xD;
14
+ &lt;br /&gt; &lt;br /&gt;&#xD;
15
+ This integration significantly reduces PCI compliance requirements and liability as all of the credit card information is processed in Optimal Payments Level 1 PCI compliant environment and servers leaving no sensitive customer payment information stored locally on merchant servers.&#xD;
16
+ &lt;br /&gt; &lt;br /&gt;&#xD;
17
+ Through the Optimal integration merchants also have the option to enable Threatmetrix fraud detection and management services. ThreatMetrix works by collecting relevant data about the customer and the order, and validating this information during the checkout. Fully integrated into the NETBANX payment gateway, enabling the ThreatMetrix option will allow merchants to automatically hold and flag suspicious orders, drastically reducing any fraud occurrences. Depending on the Score returned by ThreatMetrix an order can be held and flagged or altogether denied during the checkout.&#xD;
18
+ </description>
19
+ <notes>First Release</notes>
20
+ <authors><author><name>Demac Media</name><user>demacmedia</user><email>support@demacmedia.com</email></author></authors>
21
+ <date>2013-11-19</date>
22
+ <time>20:36:10</time>
23
+ <contents><target name="magecommunity"><dir name="Demac"><dir name="Optimal"><dir name="Block"><dir name="Adminhtml"><dir name="Risk"><dir name="Edit"><file name="Form.php" hash="09e5b7ad754d4ff2e69ff636028f61ea"/><dir name="Tab"><file name="Form.php" hash="0ba64205e934c124af3212b3e713a83f"/></dir><file name="Tabs.php" hash="61fead026636e4e61b3129f644ac8ede"/></dir><file name="Edit.php" hash="279c1697fcf3bbb706c6f647956fce73"/><file name="Grid.php" hash="e999f01578aac6084520029f86852c09"/></dir><file name="Risk.php" hash="6bf5127ba14f9dd38519c6b62203f1f8"/></dir><file name="Threat.php" hash="32e086b2e21ccc929bab4c091fb46867"/></dir><dir name="Helper"><file name="Data.php" hash="73d317a805f1353d88304b95f71a4b50"/></dir><dir name="Helpers"><file name="Data.php" hash="223cc3e79ab42ad3f9fcbf00038ab179"/></dir><dir name="Model"><dir name="Client"><file name="Abstract.php" hash="ca900162fdd6440fdf3814e0848a16c2"/></dir><dir name="Config"><file name="Mode.php" hash="798d2a9bab2c0fc2749116ac1a3fc926"/><file name="Status.php" hash="767ba25406456aae4a0bd86b11023b45"/><file name="Transaction.php" hash="ce132d61f09588649eb02c3dbefd5b84"/></dir><dir name="Hosted"><file name="Client.php" hash="2a90d60ccba0a071bcdb915f295a2e07"/></dir><dir name="Method"><file name="Hosted.php" hash="59cbfaa146fe00adba1609dbc634c2d7"/></dir><file name="Method.php" hash="9ed0757f2e2733bafc89150d9cb541eb"/><dir name="Mysql4"><dir name="Risk"><file name="Collection.php" hash="558dc26690672dc09ae6fbfa8e780302"/></dir><file name="Risk.php" hash="5c77111382678451da4dde209a43b0fa"/></dir><file name="Observer.php" hash="8c1c9ce48bfe9c3e10c5f5857a4c0f9f"/><dir name="Resource"><dir name="Mysql4"><file name="Setup.php" hash="e936830d9e4f74badc3b7663f60436dc"/></dir></dir><file name="Risk.php" hash="fab5519b0e257b8ef2f66f5f76d49f2b"/><dir name="Web"><file name="Client.php" hash="d565e254fc281e7c246cc9cfe8c2f39d"/></dir></dir><dir name="Test"><dir name="Model"><dir name="Hosted"><file name="Client.php" hash="83e69edc0636294a7e6a93e8cd745b33"/></dir><dir name="Method"><file name="Hosted.php" hash="2acc5b7427dc4bb36b8ec8f75987cd1e"/></dir><file name="Observer.php" hash="581a5f9151aaffad292670af5118926f"/></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="ThreatController.php" hash="5db39713fbd0ae13e943a891940bb22c"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="964295d91c6f5e1fcbebda18b9ad54b5"/><file name="config.xml" hash="02aa3f84dc7b3b32db7954f2acca67f6"/><file name="system.xml" hash="778c5fb098bfbd626d0648011327d948"/></dir><dir name="sql"><dir name="optimal_setup"><file name="install-0.1.1.php" hash="422b6afb2d2320f5d9c59cd5bff0dc3d"/><file name="mysql4-install-0.1.1.php" hash="422b6afb2d2320f5d9c59cd5bff0dc3d"/></dir></dir></dir></dir></target><target name="magedesign"><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><file name="optimal.xml" hash="4fbed573e9bd166897a4328cde044c19"/></dir><dir name="template"><dir name="demac"><file name="threatmeter.phtml" hash="3dd0ea7621038895aa1dd1e322ba7d99"/></dir></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Demac_Optimal.xml" hash="2ebfc5a3a1c5688639c0cc5eb34fded0"/></dir></target></contents>
24
+ <compatible/>
25
+ <dependencies><required><php><min>5.3.0</min><max>5.4.30</max></php></required></dependencies>
26
+ </package>