Ampersand_PaymentGateway - Version 0.1.4

Version Notes

Ampersand_PaymentGateway v0.1.4

Download this release

Release Info

Developer Magento Core Team
Extension Ampersand_PaymentGateway
Version 0.1.4
Comparing to
See all releases


Version 0.1.4

Files changed (119) hide show
  1. app/code/core/Ampersand/PaymentGateway/Block/Adminhtml/Subscription.php +20 -0
  2. app/code/core/Ampersand/PaymentGateway/Block/Adminhtml/Subscription/Edit.php +31 -0
  3. app/code/core/Ampersand/PaymentGateway/Block/Adminhtml/Subscription/Edit/Form.php +103 -0
  4. app/code/core/Ampersand/PaymentGateway/Block/Adminhtml/Subscription/Grid.php +174 -0
  5. app/code/core/Ampersand/PaymentGateway/Block/Adminhtml/Subscription/Order.php +20 -0
  6. app/code/core/Ampersand/PaymentGateway/Block/Adminhtml/Subscription/Order/Grid.php +151 -0
  7. app/code/core/Ampersand/PaymentGateway/Block/Adminhtml/System/Config/Fieldset/Hint.php +23 -0
  8. app/code/core/Ampersand/PaymentGateway/Block/Checkout/Cart/Subscription.php +67 -0
  9. app/code/core/Ampersand/PaymentGateway/Block/Checkout/Onepage/Review/Subscription.php +37 -0
  10. app/code/core/Ampersand/PaymentGateway/Block/Customer/Account/Subscription.php +165 -0
  11. app/code/core/Ampersand/PaymentGateway/Block/Payment/Form/BillingAgreement.php +110 -0
  12. app/code/core/Ampersand/PaymentGateway/Block/Payment/Form/BillingAgreementCheckbox.php +16 -0
  13. app/code/core/Ampersand/PaymentGateway/Block/Payment/Form/BillingAgreementCv2.php +16 -0
  14. app/code/core/Ampersand/PaymentGateway/Block/Payment/Form/Redirect.php +77 -0
  15. app/code/core/Ampersand/PaymentGateway/Block/Payment/Form/Subscription.php +16 -0
  16. app/code/core/Ampersand/PaymentGateway/Block/Payment/Info/Redirect.php +47 -0
  17. app/code/core/Ampersand/PaymentGateway/Block/Redirect/Form.php +84 -0
  18. app/code/core/Ampersand/PaymentGateway/Block/Redirect/Iframe.php +82 -0
  19. app/code/core/Ampersand/PaymentGateway/Block/Redirect/Location.php +65 -0
  20. app/code/core/Ampersand/PaymentGateway/Helper/Data.php +492 -0
  21. app/code/core/Ampersand/PaymentGateway/Helper/Subscription.php +168 -0
  22. app/code/core/Ampersand/PaymentGateway/Model/Adapter/Abstract.php +264 -0
  23. app/code/core/Ampersand/PaymentGateway/Model/Adapter/Direct/Agreement/ManageInterface.php +13 -0
  24. app/code/core/Ampersand/PaymentGateway/Model/Adapter/Direct/AuthCaptureInterface.php +108 -0
  25. app/code/core/Ampersand/PaymentGateway/Model/Adapter/Direct/PartialInterface.php +33 -0
  26. app/code/core/Ampersand/PaymentGateway/Model/Adapter/Direct/RefundInterface.php +33 -0
  27. app/code/core/Ampersand/PaymentGateway/Model/Adapter/Interface.php +105 -0
  28. app/code/core/Ampersand/PaymentGateway/Model/Adapter/Redirect/Agreement/ManageInterface.php +8 -0
  29. app/code/core/Ampersand/PaymentGateway/Model/Adapter/Redirect/AuthCaptureInterface.php +68 -0
  30. app/code/core/Ampersand/PaymentGateway/Model/Adapter/Redirect/PartialInterface.php +33 -0
  31. app/code/core/Ampersand/PaymentGateway/Model/Adapter/Redirect/RefundInterface.php +33 -0
  32. app/code/core/Ampersand/PaymentGateway/Model/Agreement.php +164 -0
  33. app/code/core/Ampersand/PaymentGateway/Model/Compatibility/Mage/Sales/Model/Order/Payment.php +130 -0
  34. app/code/core/Ampersand/PaymentGateway/Model/Config/Abstract.php +88 -0
  35. app/code/core/Ampersand/PaymentGateway/Model/Cron.php +46 -0
  36. app/code/core/Ampersand/PaymentGateway/Model/Email.php +281 -0
  37. app/code/core/Ampersand/PaymentGateway/Model/Exception/DenyPayment.php +14 -0
  38. app/code/core/Ampersand/PaymentGateway/Model/Exception/Error.php +56 -0
  39. app/code/core/Ampersand/PaymentGateway/Model/Method/AgreementAbstract.php +450 -0
  40. app/code/core/Ampersand/PaymentGateway/Model/Method/DirectAbstract.php +383 -0
  41. app/code/core/Ampersand/PaymentGateway/Model/Method/RedirectAbstract.php +316 -0
  42. app/code/core/Ampersand/PaymentGateway/Model/Observer.php +145 -0
  43. app/code/core/Ampersand/PaymentGateway/Model/Resource/Agreement.php +29 -0
  44. app/code/core/Ampersand/PaymentGateway/Model/Resource/Agreement/Collection.php +34 -0
  45. app/code/core/Ampersand/PaymentGateway/Model/Resource/Subscription.php +29 -0
  46. app/code/core/Ampersand/PaymentGateway/Model/Resource/Subscription/Collection.php +107 -0
  47. app/code/core/Ampersand/PaymentGateway/Model/Resource/Subscription/Order.php +30 -0
  48. app/code/core/Ampersand/PaymentGateway/Model/Resource/Subscription/Order/Collection.php +14 -0
  49. app/code/core/Ampersand/PaymentGateway/Model/Resource/Transaction.php +29 -0
  50. app/code/core/Ampersand/PaymentGateway/Model/Resource/Transaction/Collection.php +39 -0
  51. app/code/core/Ampersand/PaymentGateway/Model/Service/Abstract.php +1738 -0
  52. app/code/core/Ampersand/PaymentGateway/Model/Service/Direct/AgreementAbstract.php +187 -0
  53. app/code/core/Ampersand/PaymentGateway/Model/Service/DirectAbstract.php +43 -0
  54. app/code/core/Ampersand/PaymentGateway/Model/Service/Redirect/AgreementAbstract.php +174 -0
  55. app/code/core/Ampersand/PaymentGateway/Model/Service/RedirectAbstract.php +58 -0
  56. app/code/core/Ampersand/PaymentGateway/Model/Source/AgreementMethod.php +42 -0
  57. app/code/core/Ampersand/PaymentGateway/Model/Source/CardType.php +97 -0
  58. app/code/core/Ampersand/PaymentGateway/Model/Source/OrderStatus.php +35 -0
  59. app/code/core/Ampersand/PaymentGateway/Model/Source/PaymentAction.php +58 -0
  60. app/code/core/Ampersand/PaymentGateway/Model/Source/SubscriptionPeriods.php +65 -0
  61. app/code/core/Ampersand/PaymentGateway/Model/Subscription.php +151 -0
  62. app/code/core/Ampersand/PaymentGateway/Model/Subscription/Order.php +29 -0
  63. app/code/core/Ampersand/PaymentGateway/Model/Transaction.php +175 -0
  64. app/code/core/Ampersand/PaymentGateway/Model/Utility/Cleanup.php +62 -0
  65. app/code/core/Ampersand/PaymentGateway/Model/Utility/Subscription.php +348 -0
  66. app/code/core/Ampersand/PaymentGateway/Model/Versioning.php +27 -0
  67. app/code/core/Ampersand/PaymentGateway/changelog.txt +12 -0
  68. app/code/core/Ampersand/PaymentGateway/controllers/Adminhtml/Subscription/OrderController.php +36 -0
  69. app/code/core/Ampersand/PaymentGateway/controllers/Adminhtml/SubscriptionController.php +92 -0
  70. app/code/core/Ampersand/PaymentGateway/controllers/Checkout/Cart/SubscriptionController.php +103 -0
  71. app/code/core/Ampersand/PaymentGateway/controllers/Checkout/OnepageController.php +81 -0
  72. app/code/core/Ampersand/PaymentGateway/controllers/Customer/Account/SubscriptionController.php +121 -0
  73. app/code/core/Ampersand/PaymentGateway/controllers/RedirectController.php +38 -0
  74. app/code/core/Ampersand/PaymentGateway/etc/adminhtml.xml +65 -0
  75. app/code/core/Ampersand/PaymentGateway/etc/config.xml +300 -0
  76. app/code/core/Ampersand/PaymentGateway/etc/system.xml +184 -0
  77. app/code/core/Ampersand/PaymentGateway/sql/ampersand_paymentgateway_setup/mysql4-install-0.0.1.php +21 -0
  78. app/code/core/Ampersand/PaymentGateway/sql/ampersand_paymentgateway_setup/mysql4-upgrade-0.0.1-0.0.2.php +9 -0
  79. app/code/core/Ampersand/PaymentGateway/sql/ampersand_paymentgateway_setup/mysql4-upgrade-0.0.10-0.0.11.php +9 -0
  80. app/code/core/Ampersand/PaymentGateway/sql/ampersand_paymentgateway_setup/mysql4-upgrade-0.0.11-0.0.12.php +10 -0
  81. app/code/core/Ampersand/PaymentGateway/sql/ampersand_paymentgateway_setup/mysql4-upgrade-0.0.12-0.0.13.php +9 -0
  82. app/code/core/Ampersand/PaymentGateway/sql/ampersand_paymentgateway_setup/mysql4-upgrade-0.0.13-0.0.14.php +9 -0
  83. app/code/core/Ampersand/PaymentGateway/sql/ampersand_paymentgateway_setup/mysql4-upgrade-0.0.2-0.0.3.php +9 -0
  84. app/code/core/Ampersand/PaymentGateway/sql/ampersand_paymentgateway_setup/mysql4-upgrade-0.0.3-0.0.4.php +23 -0
  85. app/code/core/Ampersand/PaymentGateway/sql/ampersand_paymentgateway_setup/mysql4-upgrade-0.0.4-0.0.5.php +9 -0
  86. app/code/core/Ampersand/PaymentGateway/sql/ampersand_paymentgateway_setup/mysql4-upgrade-0.0.5-0.0.6.php +9 -0
  87. app/code/core/Ampersand/PaymentGateway/sql/ampersand_paymentgateway_setup/mysql4-upgrade-0.0.6-0.0.7.php +34 -0
  88. app/code/core/Ampersand/PaymentGateway/sql/ampersand_paymentgateway_setup/mysql4-upgrade-0.0.7-0.0.8.php +12 -0
  89. app/code/core/Ampersand/PaymentGateway/sql/ampersand_paymentgateway_setup/mysql4-upgrade-0.0.8-0.0.9.php +12 -0
  90. app/code/core/Ampersand/PaymentGateway/sql/ampersand_paymentgateway_setup/mysql4-upgrade-0.0.9-0.0.10.php +9 -0
  91. app/code/local/Ampersand/BillingAgreementFix/Rewrite/Mage/Paypal/Helper/Data.php +28 -0
  92. app/code/local/Ampersand/BillingAgreementFix/Rewrite/Mage/Paypal/Model/Express/Checkout.php +37 -0
  93. app/code/local/Ampersand/BillingAgreementFix/Rewrite/Mage/Paypal/Model/Method/Agreement.php +27 -0
  94. app/code/local/Ampersand/BillingAgreementFix/Rewrite/Mage/Sales/Block/Payment/Form/Billing/Agreement.php +31 -0
  95. app/code/local/Ampersand/BillingAgreementFix/Rewrite/Mage/Sales/Model/Billing/Agreement.php +26 -0
  96. app/code/local/Ampersand/BillingAgreementFix/etc/config.xml +37 -0
  97. app/design/adminhtml/base/default/layout/ampersand_paymentgateway.xml +8 -0
  98. app/design/adminhtml/base/default/template/ampersand_paymentgateway/system/config/fieldset/hint.phtml +4 -0
  99. app/design/frontend/base/default/layout/ampersand_paymentgateway.xml +77 -0
  100. app/design/frontend/base/default/template/ampersand_paymentgateway/checkout/cart/subscription.phtml +45 -0
  101. app/design/frontend/base/default/template/ampersand_paymentgateway/checkout/onepage/review/subscription.phtml +8 -0
  102. app/design/frontend/base/default/template/ampersand_paymentgateway/customer/account/subscription.phtml +83 -0
  103. app/design/frontend/base/default/template/ampersand_paymentgateway/payment/form/billing-agreement-checkbox.phtml +29 -0
  104. app/design/frontend/base/default/template/ampersand_paymentgateway/payment/form/billing-agreement-cv2.phtml +10 -0
  105. app/design/frontend/base/default/template/ampersand_paymentgateway/payment/form/redirect.phtml +21 -0
  106. app/design/frontend/base/default/template/ampersand_paymentgateway/redirect/form.phtml +23 -0
  107. app/design/frontend/base/default/template/ampersand_paymentgateway/redirect/iframe.phtml +6 -0
  108. app/design/frontend/base/default/template/ampersand_paymentgateway/redirect/location.phtml +12 -0
  109. app/design/frontend/base/default/template/ampersand_paymentgateway/sales/payment/form/billing/agreement.phtml +42 -0
  110. app/etc/modules/Ampersand_BillingAgreementFix.xml +9 -0
  111. app/etc/modules/Ampersand_PaymentGateway.xml +23 -0
  112. app/locale/en_US/template/email/ampersand_paymentgateway/notification.html +25 -0
  113. app/locale/en_US/template/email/ampersand_paymentgateway/subscription_reminder.html +43 -0
  114. js/ampersand_paymentgateway/validation.js +11 -0
  115. package.xml +18 -0
  116. skin/adminhtml/base/default/ampersand_paymentgateway/css/styles.css +16 -0
  117. skin/adminhtml/base/default/ampersand_paymentgateway/images/logo.gif +0 -0
  118. skin/frontend/base/default/ampersand_paymentgateway/css/cart.css +1 -0
  119. skin/frontend/base/default/ampersand_paymentgateway/css/checkout.css +2 -0
app/code/core/Ampersand/PaymentGateway/Block/Adminhtml/Subscription.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Block_Adminhtml_Subscription
3
+ extends Mage_Adminhtml_Block_Widget_Grid_Container
4
+ {
5
+ /**
6
+ * Initialize the grid container.
7
+ *
8
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
9
+ */
10
+ public function __construct()
11
+ {
12
+ $this->_controller = 'subscription';
13
+ $this->_blockGroup = 'ampersand_paymentgateway_admin';
14
+ $this->_headerText = Mage::helper('ampersand_paymentgateway')->__('Subscriptions');
15
+
16
+ parent::__construct();
17
+
18
+ $this->_removeButton('add');
19
+ }
20
+ }
app/code/core/Ampersand/PaymentGateway/Block/Adminhtml/Subscription/Edit.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Block_Adminhtml_Subscription_Edit
3
+ extends Mage_Adminhtml_Block_Widget_Form_Container
4
+ {
5
+ /**
6
+ * Prepare the form container.
7
+ *
8
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
9
+ */
10
+ public function __construct()
11
+ {
12
+ $this->_controller = 'subscription';
13
+ $this->_blockGroup = 'ampersand_paymentgateway_admin';
14
+ $this->_mode = 'edit';
15
+
16
+ $this->_headerText = Mage::helper('ampersand_paymentgateway')->__('Edit Subscription');
17
+
18
+ parent::__construct();
19
+
20
+ $this->_removeButton('delete');
21
+
22
+ $this->_addButton('save_and_continue_edit', array(
23
+ 'label' => Mage::helper('ampersand_paymentgateway')->__('Save and Continue Edit'),
24
+ 'onclick' => "editForm.submit('{$this->getUrl('*/*/*', array(
25
+ '_current' => true,
26
+ 'continue' => '1',
27
+ ))}');",
28
+ 'class' => 'save',
29
+ ), 2);
30
+ }
31
+ }
app/code/core/Ampersand/PaymentGateway/Block/Adminhtml/Subscription/Edit/Form.php ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Block_Adminhtml_Subscription_Edit_Form
3
+ extends Mage_Adminhtml_Block_Widget_Form
4
+ {
5
+ /**
6
+ * Prepare the form.
7
+ *
8
+ * @return Ampersand_PaymentGateway_Block_Adminhtml_Subscription_Edit_Form
9
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
10
+ */
11
+ protected function _prepareForm()
12
+ {
13
+ $form = new Varien_Data_Form(array(
14
+ 'id' => 'edit_form',
15
+ 'action' => $this->getUrl('*/*/*', array(
16
+ '_current' => true,
17
+ 'continue' => 0,
18
+ )),
19
+ 'method' => 'post',
20
+ ));
21
+ $form->setUseContainer(true);
22
+ $this->setForm($form);
23
+
24
+ $fieldset = $form->addFieldset('general', array(
25
+ 'legend' => $this->__('Subscription details'),
26
+ 'comment' => $this->__('Only fields which can be modified are displayed. Please take care when making changes.'),
27
+ ));
28
+
29
+ $this->_addFieldsToFieldset($fieldset, array(
30
+ 'is_active' => array(
31
+ 'label' => $this->__('Is Active?'),
32
+ 'input' => 'text',
33
+ 'required' => true,
34
+ 'note' => '1 for active. 0 for inactive.',
35
+ ),
36
+ 'frequency' => array(
37
+ 'label' => $this->__('Frequency'),
38
+ 'input' => 'text',
39
+ 'required' => true,
40
+ 'note' => 'Subscription frequency in days.',
41
+ ),
42
+ 'next_order_date' => array(
43
+ 'label' => $this->__('Next Order Date'),
44
+ 'input' => 'text',
45
+ 'required' => true,
46
+ 'note' => 'Next order date in format YYYY-MM-DD HH:MM:SS.',
47
+ ),
48
+ ));
49
+
50
+ return $this;
51
+ }
52
+
53
+ /**
54
+ * Add fields to the fieldset.
55
+ *
56
+ * @return Ampersand_PaymentGateway_Block_Adminhtml_Subscription_Edit_Form
57
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
58
+ */
59
+ protected function _addFieldsToFieldset(Varien_Data_Form_Element_Fieldset $fieldset, $fields)
60
+ {
61
+ $requestData = new Varien_Object($this->getRequest()->getPost('object'));
62
+
63
+ foreach ($fields as $name => $_data) {
64
+ if ($requestValue = $requestData->getData($name)) {
65
+ $_data['value'] = $requestValue;
66
+ }
67
+
68
+ $_data['title'] = $_data['label'];
69
+ $_data['name'] = "object[$name]";
70
+
71
+ if (!array_key_exists('value', $_data)) {
72
+ $_data['value'] = $this->_getSubscription()->getData($name);
73
+ }
74
+
75
+ if ('note' == $_data['input'] && !array_key_exists('text', $_data)) {
76
+ $_data['text'] = $_data['value'];
77
+ }
78
+
79
+ $element = $fieldset->addField($name, $_data['input'], $_data);
80
+ }
81
+
82
+ return $this;
83
+ }
84
+
85
+ /**
86
+ * Retrieve the current subscription,
87
+ *
88
+ * @return Ampersand_PaymentGateway_Model_Subscription
89
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
90
+ */
91
+ protected function _getSubscription()
92
+ {
93
+ if (!$this->hasSubscription()) {
94
+ $subscription = Mage::getModel('ampersand_paymentgateway/subscription');
95
+ if ($id = $this->getRequest()->getParam('id')) {
96
+ $subscription->load($id);
97
+ }
98
+ $this->setSubscription($subscription);
99
+ }
100
+
101
+ return $this->getData('subscription');
102
+ }
103
+ }
app/code/core/Ampersand/PaymentGateway/Block/Adminhtml/Subscription/Grid.php ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Block_Adminhtml_Subscription_Grid
3
+ extends Mage_Adminhtml_Block_Widget_Grid
4
+ {
5
+ /**
6
+ * Initialize the grid.
7
+ *
8
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
9
+ */
10
+ public function __construct()
11
+ {
12
+ parent::__construct();
13
+
14
+ $this->setId('subscription_grid');
15
+ $this->setUseAjax(true);
16
+ $this->setDefaultSort('created_at');
17
+ $this->setDefaultDir('DESC');
18
+ $this->setSaveParametersInSession(true);
19
+ }
20
+
21
+ /**
22
+ * Prepare the grid collection.
23
+ *
24
+ * @return Ampersand_PaymentGateway_Block_Adminhtml_Subscription_Grid
25
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
26
+ */
27
+ protected function _prepareCollection()
28
+ {
29
+ $collection = Mage::getResourceModel('ampersand_paymentgateway/subscription_collection');
30
+
31
+ // join the customer table
32
+ $collection->joinLeft(
33
+ 'customer/entity',
34
+ '`customer/entity`.`entity_id`=`main_table`.`customer_id`',
35
+ 'email'
36
+ );
37
+
38
+ // join the order table
39
+ $collection->joinLeft(
40
+ 'sales/order',
41
+ '`sales/order`.`entity_id`=`main_table`.`order_id`',
42
+ 'increment_id'
43
+ );
44
+
45
+ $this->setCollection($collection);
46
+
47
+ return parent::_prepareCollection();
48
+ }
49
+
50
+ /**
51
+ * Prepare the grid columns.
52
+ *
53
+ * @return Ampersand_PaymentGateway_Block_Adminhtml_Subscription_Grid
54
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
55
+ */
56
+ protected function _prepareColumns()
57
+ {
58
+ $this->addColumn('entity_id', array(
59
+ 'header' => $this->_getHelper()->__('ID'),
60
+ 'type' => 'number',
61
+ 'index' => 'entity_id',
62
+ 'filter_index' => '`main_table`.`entity_id`',
63
+ 'width' => '1px',
64
+ ));
65
+
66
+ $this->addColumn('created_at', array(
67
+ 'header' => $this->_getHelper()->__('Created'),
68
+ 'type' => 'datetime',
69
+ 'index' => 'created_at',
70
+ 'filter_index' => '`main_table`.`created_at`',
71
+ 'width' => '1px',
72
+ ));
73
+
74
+ $this->addColumn('email', array(
75
+ 'header' => $this->_getHelper()->__('Customer Email'),
76
+ 'type' => 'text',
77
+ 'index' => 'email',
78
+ 'filter_index' => '`customer/entity`.`email`',
79
+ 'width' => '1px',
80
+ ));
81
+
82
+ $this->addColumn('increment_id', array(
83
+ 'header' => $this->_getHelper()->__('Master Order #'),
84
+ 'type' => 'number',
85
+ 'index' => 'increment_id',
86
+ 'filter_index' => '`sales/order`.`increment_id`',
87
+ 'width' => '1px',
88
+ ));
89
+
90
+ $this->addColumn('frequency', array(
91
+ 'header' => $this->_getHelper()->__('Frequency (days)'),
92
+ 'type' => 'number',
93
+ 'index' => 'frequency',
94
+ 'filter_index' => '`main_table`.`frequency`',
95
+ 'width' => '1px',
96
+ ));
97
+
98
+ $this->addColumn('remaining_updates_current', array(
99
+ 'header' => $this->_getHelper()->__('Remaining Orders'),
100
+ 'type' => 'number',
101
+ 'index' => 'remaining_updates_current',
102
+ 'filter_index' => '`main_table`.`remaining_updates_current`',
103
+ 'getter' => 'getRemainingSubscriptions',
104
+ 'width' => '1px',
105
+ ));
106
+
107
+ $this->addColumn('next_order_date', array(
108
+ 'header' => $this->_getHelper()->__('Next Order Date'),
109
+ 'type' => 'date',
110
+ 'index' => 'next_order_date',
111
+ 'filter_index' => '`main_table`.`next_order_date`',
112
+ 'width' => '1px',
113
+ ));
114
+
115
+ $this->addColumn('is_active', array(
116
+ 'header' => $this->_getHelper()->__('Active?'),
117
+ 'type' => 'number',
118
+ 'index' => 'is_active',
119
+ 'filter_index' => '`main_table`.`is_active`',
120
+ 'width' => '1px',
121
+ ));
122
+
123
+ $this->addColumn('is_reminder_sent', array(
124
+ 'header' => $this->_getHelper()->__('Reminder Sent?'),
125
+ 'type' => 'number',
126
+ 'index' => 'is_reminder_sent',
127
+ 'filter_index' => '`main_table`.`is_reminder_sent`',
128
+ 'width' => '1px',
129
+ ));
130
+
131
+ $this->addColumn('action', array(
132
+ 'header' => $this->_getHelper()->__('Action'),
133
+ 'width' => '50px',
134
+ 'type' => 'action',
135
+ 'actions' => array(
136
+ array(
137
+ 'caption' => $this->_getHelper()->__('Edit'),
138
+ 'url' => array(
139
+ 'base' => '*/*/edit',
140
+ ),
141
+ 'field' => 'id'
142
+ ),
143
+ ),
144
+ 'filter' => false,
145
+ 'sortable' => false,
146
+ 'index' => 'entity_id',
147
+ 'width' => '1px',
148
+ ));
149
+
150
+ return parent::_prepareColumns();
151
+ }
152
+
153
+ /**
154
+ * Retrieve the URL to redirect to when the grid row is clicked.
155
+ *
156
+ * @return string
157
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
158
+ */
159
+ public function getRowUrl($row)
160
+ {
161
+ return $this->getUrl('*/*/edit', array('id' => $row->getId()));
162
+ }
163
+
164
+ /**
165
+ * Retrieve the helper.
166
+ *
167
+ * @return Ampersand_PaymentGateway_Helper_Data
168
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
169
+ */
170
+ protected function _getHelper()
171
+ {
172
+ return Mage::helper('ampersand_paymentgateway');
173
+ }
174
+ }
app/code/core/Ampersand/PaymentGateway/Block/Adminhtml/Subscription/Order.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Block_Adminhtml_Subscription_Order
3
+ extends Mage_Adminhtml_Block_Widget_Grid_Container
4
+ {
5
+ /**
6
+ * Initialize the grid container.
7
+ *
8
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
9
+ */
10
+ public function __construct()
11
+ {
12
+ $this->_controller = 'subscription_order';
13
+ $this->_blockGroup = 'ampersand_paymentgateway_admin';
14
+ $this->_headerText = Mage::helper('ampersand_paymentgateway')->__('Subscription Orders');
15
+
16
+ parent::__construct();
17
+
18
+ $this->_removeButton('add');
19
+ }
20
+ }
app/code/core/Ampersand/PaymentGateway/Block/Adminhtml/Subscription/Order/Grid.php ADDED
@@ -0,0 +1,151 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Block_Adminhtml_Subscription_Order_Grid
3
+ extends Mage_Adminhtml_Block_Widget_Grid
4
+ {
5
+ /**
6
+ * Initialize the grid.
7
+ *
8
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
9
+ */
10
+ public function __construct()
11
+ {
12
+ parent::__construct();
13
+
14
+ $this->setId('subscription_order_grid');
15
+ $this->setUseAjax(true);
16
+ $this->setDefaultSort('created_at');
17
+ $this->setDefaultDir('DESC');
18
+ $this->setSaveParametersInSession(true);
19
+ }
20
+
21
+ /**
22
+ * Prepare the grid collection.
23
+ *
24
+ * @return Ampersand_PaymentGateway_Block_Adminhtml_Subscription_Order_Grid
25
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
26
+ */
27
+ protected function _prepareCollection()
28
+ {
29
+ $collection = Mage::getResourceModel('ampersand_paymentgateway/subscription_order_collection');
30
+
31
+ // join the subscription table
32
+ $collection->join(
33
+ 'ampersand_paymentgateway/subscription',
34
+ '`ampersand_paymentgateway/subscription`.`entity_id`=`main_table`.`subscription_id`',
35
+ 'customer_id'
36
+ );
37
+
38
+ // join the customer table
39
+ $collection->join(
40
+ 'customer/entity',
41
+ '`customer/entity`.`entity_id`=`ampersand_paymentgateway/subscription`.`customer_id`',
42
+ 'email'
43
+ );
44
+
45
+ // join the order table
46
+ $collection->join(
47
+ 'sales/order',
48
+ '`sales/order`.`entity_id`=`main_table`.`order_id`',
49
+ 'increment_id'
50
+ );
51
+
52
+ $this->setCollection($collection);
53
+
54
+ return parent::_prepareCollection();
55
+ }
56
+
57
+ /**
58
+ * Prepare the grid columns.
59
+ *
60
+ * @return Ampersand_PaymentGateway_Block_Adminhtml_Subscription_Order_Grid
61
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
62
+ */
63
+ protected function _prepareColumns()
64
+ {
65
+ $this->addColumn('entity_id', array(
66
+ 'header' => $this->_getHelper()->__('ID'),
67
+ 'type' => 'number',
68
+ 'index' => 'entity_id',
69
+ 'width' => '1px',
70
+ ));
71
+
72
+ $this->addColumn('created_at', array(
73
+ 'header' => $this->_getHelper()->__('Created'),
74
+ 'type' => 'datetime',
75
+ 'index' => 'created_at',
76
+ 'width' => '1px',
77
+ ));
78
+
79
+ $this->addColumn('subscription_id', array(
80
+ 'header' => $this->_getHelper()->__('Subscription ID'),
81
+ 'type' => 'number',
82
+ 'index' => 'subscription_id',
83
+ 'width' => '1px',
84
+ ));
85
+
86
+ $this->addColumn('increment_id', array(
87
+ 'header' => $this->_getHelper()->__('Order #'),
88
+ 'type' => 'number',
89
+ 'index' => 'increment_id',
90
+ 'width' => '1px',
91
+ ));
92
+
93
+ $this->addColumn('email', array(
94
+ 'header' => $this->_getHelper()->__('Customer Email'),
95
+ 'type' => 'text',
96
+ 'index' => 'email',
97
+ 'width' => '1px',
98
+ ));
99
+
100
+ $this->addColumn('view_order', array(
101
+ 'header' => $this->_getHelper()->__('View Order'),
102
+ 'width' => '50px',
103
+ 'type' => 'action',
104
+ 'actions' => array(
105
+ array(
106
+ 'caption' => $this->_getHelper()->__('Order'),
107
+ 'url' => array(
108
+ 'base' => 'adminhtml/sales_order/view',
109
+ ),
110
+ 'field' => 'order_id'
111
+ ),
112
+ ),
113
+ 'filter' => false,
114
+ 'sortable' => false,
115
+ 'index' => 'order_id',
116
+ 'width' => '1px',
117
+ ));
118
+
119
+ $this->addColumn('view_subscription', array(
120
+ 'header' => $this->_getHelper()->__('View Subsctiption'),
121
+ 'width' => '50px',
122
+ 'type' => 'action',
123
+ 'actions' => array(
124
+ array(
125
+ 'caption' => $this->_getHelper()->__('Subscription'),
126
+ 'url' => array(
127
+ 'base' => 'ampersand_paymentgateway_admin/subscription/edit',
128
+ ),
129
+ 'field' => 'id'
130
+ ),
131
+ ),
132
+ 'filter' => false,
133
+ 'sortable' => false,
134
+ 'index' => 'subscription_id',
135
+ 'width' => '1px',
136
+ ));
137
+
138
+ return parent::_prepareColumns();
139
+ }
140
+
141
+ /**
142
+ * Retrieve the helper.
143
+ *
144
+ * @return Ampersand_PaymentGateway_Helper_Data
145
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
146
+ */
147
+ protected function _getHelper()
148
+ {
149
+ return Mage::helper('ampersand_paymentgateway');
150
+ }
151
+ }
app/code/core/Ampersand/PaymentGateway/Block/Adminhtml/System/Config/Fieldset/Hint.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Block_Adminhtml_System_Config_Fieldset_Hint
3
+ extends Mage_Adminhtml_Block_Abstract
4
+ implements Varien_Data_Form_Element_Renderer_Interface
5
+ {
6
+ /**
7
+ * Location of our hint template file.
8
+ *
9
+ * @var string $_template
10
+ */
11
+ protected $_template = 'ampersand_paymentgateway/system/config/fieldset/hint.phtml';
12
+
13
+ /**
14
+ * Render fieldset html.
15
+ *
16
+ * @param Varien_Data_Form_Element_Abstract $element
17
+ * @return string
18
+ */
19
+ public function render(Varien_Data_Form_Element_Abstract $element)
20
+ {
21
+ return $this->toHtml();
22
+ }
23
+ }
app/code/core/Ampersand/PaymentGateway/Block/Checkout/Cart/Subscription.php ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Block_Checkout_Cart_Subscription
3
+ extends Mage_Core_Block_Template
4
+ {
5
+ /**
6
+ * Retrieve whether subscriptions are available.
7
+ *
8
+ * @return bool
9
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
10
+ */
11
+ public function isActive()
12
+ {
13
+ return $this->_getHelper()->isActive(true);
14
+ }
15
+
16
+ /**
17
+ * Retrieve whether the customer is logged in.
18
+ *
19
+ * @return bool
20
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
21
+ */
22
+ public function isLoggedIn()
23
+ {
24
+ return Mage::helper('customer')->isLoggedIn();
25
+ }
26
+
27
+ /**
28
+ * Retrieve the available periods.
29
+ *
30
+ * @return array
31
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
32
+ */
33
+ public function getPeriods()
34
+ {
35
+ $options = Mage::getModel('ampersand_paymentgateway/source_subscriptionPeriods')
36
+ ->toOptionArray();
37
+
38
+ array_unshift($options, array(
39
+ 'value' => 'do_not_subscribe',
40
+ 'label' => $this->_getHelper()->__('None'),
41
+ ));
42
+
43
+ return $options;
44
+ }
45
+
46
+ /**
47
+ * Retrieve the selected period.
48
+ *
49
+ * @return string
50
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
51
+ */
52
+ public function getSubscriptionPeriod()
53
+ {
54
+ return $this->_getHelper()->getSubscriptionData('period');
55
+ }
56
+
57
+ /**
58
+ * Retrieve the subscription helper.
59
+ *
60
+ * @return Ampersand_PaymentGateway_Helper_Subscription
61
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
62
+ */
63
+ protected function _getHelper()
64
+ {
65
+ return Mage::helper('ampersand_paymentgateway/subscription');
66
+ }
67
+ }
app/code/core/Ampersand/PaymentGateway/Block/Checkout/Onepage/Review/Subscription.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Block_Checkout_Onepage_Review_Subscription
3
+ extends Mage_Core_Block_Template
4
+ {
5
+ /**
6
+ * Has the customer selected to create a subscription for this order.
7
+ *
8
+ * @return bool
9
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
10
+ */
11
+ public function isActive()
12
+ {
13
+ return $this->_getHelper()->getSubscriptionData('active');
14
+ }
15
+
16
+ /**
17
+ * Retrieve details of the customers selections.
18
+ *
19
+ * @return Ampersand_Object
20
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
21
+ */
22
+ public function getSubscriptionInfo()
23
+ {
24
+ return new Ampersand_Object($this->_getHelper()->getSubscriptionData());
25
+ }
26
+
27
+ /**
28
+ * Retrieve the subscription helper.
29
+ *
30
+ * @return Ampersand_PaymentGateway_Helper_Subscription
31
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
32
+ */
33
+ protected function _getHelper()
34
+ {
35
+ return Mage::helper('ampersand_paymentgateway/subscription');
36
+ }
37
+ }
app/code/core/Ampersand/PaymentGateway/Block/Customer/Account/Subscription.php ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Block_Customer_Account_Subscription
3
+ extends Mage_Core_Block_Template
4
+ {
5
+ /**
6
+ * Initialize collection of subscriptions for the logged in customer.
7
+ *
8
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
9
+ */
10
+ protected function _construct()
11
+ {
12
+ $subscriptions = Mage::getModel('ampersand_paymentgateway/subscription')->getCollection()
13
+ ->addFieldToFilter('customer_id', $this->_getCustomerId())
14
+ ->addFieldToFilter('is_active', '1')
15
+ ->setOrder('created_at', 'DESC');
16
+
17
+ $this->setSubscriptions($subscriptions);
18
+ }
19
+
20
+ /**
21
+ * Initialize the pager.
22
+ *
23
+ * @return Ampersand_PaymentGateway_Block_Customer_Account_Subscription
24
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
25
+ */
26
+ protected function _prepareLayout()
27
+ {
28
+ parent::_prepareLayout();
29
+
30
+ $pager = $this->getLayout()->createBlock(
31
+ 'page/html_pager',
32
+ 'ampersand_paymentgateway_subscription_pager'
33
+ );
34
+ $pager->setCollection($this->getSubscriptions());
35
+ $this->setChild('pager', $pager);
36
+ $this->getSubscriptions()->load();
37
+
38
+ return $this;
39
+ }
40
+
41
+ /**
42
+ * Retrieve the pager.
43
+ *
44
+ * @return string
45
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
46
+ */
47
+ public function getPagerHtml()
48
+ {
49
+ return $this->getChildHtml('pager');
50
+ }
51
+
52
+ /**
53
+ * Retrieve an order given an order ID.
54
+ *
55
+ * @param int $orderId
56
+ * @return Mage_Sales_Model_Order
57
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
58
+ */
59
+ public function getOrder($orderId)
60
+ {
61
+ return Mage::getModel('sales/order')->load($orderId);
62
+ }
63
+
64
+ /**
65
+ * Retrieve an order URL given an order object or ID.
66
+ *
67
+ * @param mixed $order
68
+ * @return string
69
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
70
+ */
71
+ public function getOrderUrl($order)
72
+ {
73
+ if (!$order instanceof Mage_Sales_Model_Order) {
74
+ $order = $this->getOrder($order);
75
+ }
76
+
77
+ return Mage::getUrl('sales/order/view', array('order_id' => $order->getId()));
78
+ }
79
+
80
+ /**
81
+ * Retrieve the name of the payment gateway from a payment code.
82
+ *
83
+ * @param string $code
84
+ * @return string
85
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
86
+ */
87
+ public function getPaymentMethod($code)
88
+ {
89
+ return Mage::getStoreConfig(
90
+ Mage_Payment_Helper_Data::XML_PATH_PAYMENT_METHODS . '/' . $code . '/title'
91
+ );
92
+ }
93
+
94
+ /**
95
+ * Retrieve more information about a billing agreement.
96
+ *
97
+ * @param int $agreementId
98
+ * @return Ampersand_PaymentGateway_Model_Agreement
99
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
100
+ */
101
+ public function getPaymentMethodCardDetails($agreementId)
102
+ {
103
+ return Mage::getModel('ampersand_paymentgateway/agreement')->getCollection()
104
+ ->addFieldToFilter('entity_id', $agreementId)
105
+ ->getFirstItem();
106
+ }
107
+
108
+ /**
109
+ * Retrieve friendly name of Magento card types.
110
+ *
111
+ * @param string $type
112
+ * @return string
113
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
114
+ */
115
+ public function getCardType($type)
116
+ {
117
+ return Mage::getSingleton('ampersand_paymentgateway/source_cardType')
118
+ ->getMagentoCardType($type);
119
+ }
120
+
121
+ /**
122
+ * Retrieve the URL for a customer to cancel a subscription.
123
+ * Note: The subscription ID needs to be appended to this URL.
124
+ *
125
+ * @return string
126
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
127
+ */
128
+ public function getCancelUrl()
129
+ {
130
+ return Mage::getUrl(
131
+ 'customer/account/subscriptions',
132
+ array(
133
+ 'action' => 'cancel',
134
+ )
135
+ );
136
+ }
137
+
138
+ /**
139
+ * Retrieve the URL for a customer to skip a subscription order.
140
+ * Note: The subscription ID needs to be appended to this URL.
141
+ *
142
+ * @return string
143
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
144
+ */
145
+ public function getSkipNextUrl()
146
+ {
147
+ return Mage::getUrl(
148
+ 'customer/account/subscriptions',
149
+ array(
150
+ 'action' => 'skip',
151
+ )
152
+ );
153
+ }
154
+
155
+ /**
156
+ * Retrieve the logged in customer ID.
157
+ *
158
+ * @return int
159
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
160
+ */
161
+ protected function _getCustomerId()
162
+ {
163
+ return Mage::helper('customer')->getCustomer()->getId();
164
+ }
165
+ }
app/code/core/Ampersand/PaymentGateway/Block/Payment/Form/BillingAgreement.php ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @todo this file does not belong here, should be same as Magento, but possibly:
4
+ * Ampersand_PaymentGateway_Block_Sales_Payment_Form_Billing_Agreement
5
+ */
6
+ class Ampersand_PaymentGateway_Block_Payment_Form_BillingAgreement
7
+ extends Ampersand_BillingAgreementFix_Rewrite_Mage_Sales_Block_Payment_Form_Billing_Agreement
8
+ {
9
+ /**
10
+ * Set the default template for the form.
11
+ *
12
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
13
+ */
14
+ public function __construct()
15
+ {
16
+ parent::__construct();
17
+ $this->setTemplate('ampersand_paymentgateway/sales/payment/form/billing/agreement.phtml');
18
+ }
19
+
20
+ /**
21
+ * Retrieve available customer billing agreements
22
+ *
23
+ * @return array
24
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
25
+ */
26
+ public function getBillingAgreements()
27
+ {
28
+ $billingAgreements = parent::getBillingAgreements();
29
+
30
+ $collection = Mage::getModel('ampersand_paymentgateway/agreement')->getCollection()
31
+ ->addFieldToFilter('reference_id', $billingAgreements);
32
+
33
+ $ampersandAgreements = array();
34
+ foreach ($collection as $_agreement) {
35
+ $this->_prepareAgreementData($_agreement);
36
+ $ampersandAgreements[$_agreement->getReferenceId()] = $_agreement;
37
+ }
38
+
39
+ foreach ($billingAgreements as $_id => &$_referenceId) {
40
+ if (!array_key_exists($_referenceId, $ampersandAgreements)) {
41
+ unset($billingAgreements[$_id]);
42
+ } else {
43
+ $_referenceId = $ampersandAgreements[$_referenceId];
44
+ }
45
+ }
46
+
47
+ return $billingAgreements;
48
+ }
49
+
50
+ /**
51
+ * Retrieve friendly name of Magento card types.
52
+ *
53
+ * @param string $type
54
+ * @return string
55
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
56
+ */
57
+ public function getCardType($type)
58
+ {
59
+ return Mage::getSingleton('ampersand_paymentgateway/source_cardType')
60
+ ->getMagentoCardType($type);
61
+ }
62
+
63
+ /**
64
+ * Retrieve card details from reference ID if they are not explicitly stored.
65
+ *
66
+ * @param Ampersand_PaymentGateway_Model_Agreement $agreement
67
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
68
+ */
69
+ protected function _prepareAgreementData($agreement)
70
+ {
71
+ $referenceId = $agreement->getReferenceId();
72
+
73
+ // Format of Reference ID = 1234567890-****1234-01-2000
74
+ $referenceIdParts = false;
75
+ $pattern = '#\d{10}-\*{4}\d{4}-\d{2}-\d{4}#';
76
+ if (preg_match($pattern, $referenceId) === 1) {
77
+ $referenceIdParts = explode('-', $referenceId);
78
+ }
79
+
80
+ $data = array(
81
+ 'card_type' => 'Unknown',
82
+ 'card_last_four' => $referenceIdParts ? substr($referenceIdParts[1], -4) : '????',
83
+ 'card_expiry_month' => $referenceIdParts ? $referenceIdParts[2] : '??',
84
+ 'card_expiry_year' => $referenceIdParts ? $referenceIdParts[3] : '????',
85
+ );
86
+
87
+ foreach ($data as $_field => $_defaultValue) {
88
+ if ($agreement->getData($_field) == '') {
89
+ $agreement->setData($_field, $_defaultValue);
90
+ }
91
+ }
92
+
93
+ return $this;
94
+ }
95
+
96
+ /**
97
+ * Render block HTML
98
+ *
99
+ * @return string
100
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
101
+ */
102
+ protected function _toHtml()
103
+ {
104
+ Mage::dispatchEvent('payment_form_block_to_html_before', array(
105
+ 'block' => $this
106
+ ));
107
+
108
+ return parent::_toHtml();
109
+ }
110
+ }
app/code/core/Ampersand/PaymentGateway/Block/Payment/Form/BillingAgreementCheckbox.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Block_Payment_Form_BillingAgreementCheckbox
3
+ extends Mage_Core_Block_Template
4
+ {
5
+ /**
6
+ * Set the default template for the block.
7
+ *
8
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
9
+ */
10
+ protected function _construct()
11
+ {
12
+ parent::_construct();
13
+
14
+ $this->setTemplate('ampersand_paymentgateway/payment/form/billing-agreement-checkbox.phtml');
15
+ }
16
+ }
app/code/core/Ampersand/PaymentGateway/Block/Payment/Form/BillingAgreementCv2.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Block_Payment_Form_BillingAgreementCv2
3
+ extends Mage_Core_Block_Template
4
+ {
5
+ /**
6
+ * Set the default template for the block.
7
+ *
8
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
9
+ */
10
+ protected function _construct()
11
+ {
12
+ parent::_construct();
13
+
14
+ $this->setTemplate('ampersand_paymentgateway/payment/form/billing-agreement-cv2.phtml');
15
+ }
16
+ }
app/code/core/Ampersand/PaymentGateway/Block/Payment/Form/Redirect.php ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Block_Payment_Form_Redirect extends Mage_Payment_Block_Form
3
+ {
4
+ /**
5
+ * Set the default template for the form.
6
+ *
7
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
8
+ */
9
+ protected function _construct()
10
+ {
11
+ parent::_construct();
12
+
13
+ $this->setTemplate('ampersand_paymentgateway/payment/form/redirect.phtml');
14
+ }
15
+
16
+ /**
17
+ * Retrieve whether credit card type is required for this payment method.
18
+ *
19
+ * @return bool
20
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
21
+ */
22
+ public function isCcTypeRequired()
23
+ {
24
+ return $this->getMethod()->getIsCcTypeRequired();
25
+ }
26
+
27
+ /**
28
+ * Retrieve availables credit card types
29
+ *
30
+ * @return array
31
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
32
+ */
33
+ public function getCcAvailableTypes()
34
+ {
35
+ $types = $this->_getConfig()->getCcTypes();
36
+
37
+ if ($method = $this->getMethod()) {
38
+ $availableTypes = $method->getConfigData('cctypes');
39
+ if ($availableTypes) {
40
+ $availableTypes = explode(',', $availableTypes);
41
+ foreach ($types as $code => $name) {
42
+ if (!in_array($code, $availableTypes)) {
43
+ unset($types[$code]);
44
+ }
45
+ }
46
+ }
47
+ }
48
+
49
+ return $types;
50
+ }
51
+
52
+ /**
53
+ * Retrieve payment configuration object
54
+ *
55
+ * @return Mage_Payment_Model_Config
56
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
57
+ */
58
+ protected function _getConfig()
59
+ {
60
+ return Mage::getSingleton('payment/config');
61
+ }
62
+
63
+ /**
64
+ * Render block HTML
65
+ *
66
+ * @return string
67
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
68
+ */
69
+ protected function _toHtml()
70
+ {
71
+ Mage::dispatchEvent('payment_form_block_to_html_before', array(
72
+ 'block' => $this
73
+ ));
74
+
75
+ return parent::_toHtml();
76
+ }
77
+ }
app/code/core/Ampersand/PaymentGateway/Block/Payment/Form/Subscription.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Block_Payment_Form_Subscription
3
+ extends Mage_Core_Block_Template
4
+ {
5
+ /**
6
+ * Set the default template for the block.
7
+ *
8
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
9
+ */
10
+ protected function _construct()
11
+ {
12
+ parent::_construct();
13
+
14
+ $this->setTemplate('ampersand_paymentgateway/payment/form/subscription.phtml');
15
+ }
16
+ }
app/code/core/Ampersand/PaymentGateway/Block/Payment/Info/Redirect.php ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Block_Payment_Info_Redirect extends Mage_Payment_Block_Info
3
+ {
4
+ /**
5
+ * Retrieve credit card type name.
6
+ *
7
+ * @return string
8
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
9
+ */
10
+ public function getCcTypeName()
11
+ {
12
+ $ccType = $this->getInfo()->getCcType();
13
+
14
+ $types = Mage::getSingleton('payment/config')->getCcTypes();
15
+ if (isset($types[$ccType])) {
16
+ return $types[$ccType];
17
+ }
18
+
19
+ return (empty($ccType)) ? Mage::helper('payment')->__('N/A') : $ccType;
20
+ }
21
+
22
+ /**
23
+ * Prepare credit card related payment info.
24
+ *
25
+ * @param Varien_Object|array $transport
26
+ * @return Varien_Object
27
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
28
+ */
29
+ protected function _prepareSpecificInformation($transport = null)
30
+ {
31
+ if (null !== $this->_paymentSpecificInformation) {
32
+ return $this->_paymentSpecificInformation;
33
+ }
34
+
35
+ $transport = parent::_prepareSpecificInformation($transport);
36
+
37
+ $data = array();
38
+
39
+ $method = $this->getMethod();
40
+
41
+ if ($method->getIsCcTypeRequired() && ($ccType = $this->getCcTypeName())) {
42
+ $data[Mage::helper('payment')->__('Credit Card Type')] = $ccType;
43
+ }
44
+
45
+ return $transport->setData(array_merge($data, $transport->getData()));
46
+ }
47
+ }
app/code/core/Ampersand/PaymentGateway/Block/Redirect/Form.php ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Block_Redirect_Form extends Mage_Core_Block_Template
3
+ {
4
+ /**
5
+ * Session keys for redirect information.
6
+ */
7
+ const SESSION_KEY_REDIRECT_URL = 'ampersand_paymentgateway_redirect_form_url';
8
+ const SESSION_KEY_REDIRECT_DATA = 'ampersand_paymentgateway_redirect_form_data';
9
+
10
+ /**
11
+ * Set the default template for the redirect form.
12
+ *
13
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
14
+ */
15
+ protected function _construct()
16
+ {
17
+ parent::_construct();
18
+
19
+ $this->setTemplate('ampersand_paymentgateway/redirect/form.phtml');
20
+ }
21
+
22
+ /**
23
+ * Retrieve the page title.
24
+ *
25
+ * @return string
26
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
27
+ */
28
+ public function getTitle()
29
+ {
30
+ if (!$this->hasTitle()) {
31
+ $this->setData('title', 'Please wait while you are redirected...');
32
+ }
33
+
34
+ return $this->getData('title');
35
+ }
36
+
37
+ /**
38
+ * Retrieve the Redirect URL value stored from the response.
39
+ *
40
+ * @return string
41
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
42
+ */
43
+ public function getRedirectUrl()
44
+ {
45
+ return $this->_getHelper()->getAndClearSessionKey(self::SESSION_KEY_REDIRECT_URL);
46
+ }
47
+
48
+ /**
49
+ * Set any hidden fields to be posted in the redirect POST.
50
+ *
51
+ * @return array
52
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
53
+ */
54
+ public function getHiddenFields()
55
+ {
56
+ return $this->_getHelper()->getAndClearSessionKey(self::SESSION_KEY_REDIRECT_DATA);
57
+ }
58
+
59
+ /**
60
+ * Retrieve the message to display if no redirect URL was provided.
61
+ *
62
+ * @return string
63
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
64
+ */
65
+ public function getNoRedirectUrlMessage()
66
+ {
67
+ if (!$this->hasNoRedirectUrlMessage()) {
68
+ $this->setData('no_redirect_url_message', 'Unable to redirect.');
69
+ }
70
+
71
+ return $this->getData('no_redirect_url_message');
72
+ }
73
+
74
+ /**
75
+ * Retrieve the helper class.
76
+ *
77
+ * @return Ampersand_PaymentGateway_Helper_Data
78
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
79
+ */
80
+ protected function _getHelper()
81
+ {
82
+ return Mage::helper('ampersand_paymentgateway/data');
83
+ }
84
+ }
app/code/core/Ampersand/PaymentGateway/Block/Redirect/Iframe.php ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Block_Redirect_Iframe extends Mage_Core_Block_Template
3
+ {
4
+ /**
5
+ * Set the default template for the iframe container.
6
+ *
7
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
8
+ */
9
+ protected function _construct()
10
+ {
11
+ parent::_construct();
12
+
13
+ $this->setTemplate('ampersand_paymentgateway/redirect/iframe.phtml');
14
+ }
15
+
16
+ /**
17
+ * Set the iframe source by frontname/controller/action.
18
+ *
19
+ * @param string $route
20
+ * @param array $params
21
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
22
+ */
23
+ public function setSrcByRoute($route, $params = array())
24
+ {
25
+ $params['_forced_secure'] = true;
26
+ $this->setSrc(Mage::getUrl($route, $params));
27
+
28
+ return $this;
29
+ }
30
+
31
+ /**
32
+ * Retrieve the iframe source.
33
+ *
34
+ * @return string
35
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
36
+ */
37
+ public function getSrc()
38
+ {
39
+ return $this->getData('src');
40
+ }
41
+
42
+ /**
43
+ * Retrieve the iframe width.
44
+ *
45
+ * @return string
46
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
47
+ */
48
+ public function getWidth()
49
+ {
50
+ if (!$this->hasWidth()) {
51
+ $this->setWidth('100%');
52
+ }
53
+
54
+ return $this->getData('width');
55
+ }
56
+
57
+ /**
58
+ * Retrieve the iframe height.
59
+ *
60
+ * @return string
61
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
62
+ */
63
+ public function getHeight()
64
+ {
65
+ if (!$this->hasHeight()) {
66
+ $this->setHeight('500px');
67
+ }
68
+
69
+ return $this->getData('height');
70
+ }
71
+
72
+ /**
73
+ * Retrieve the helper class.
74
+ *
75
+ * @return Ampersand_PaymentGateway_Helper_Data
76
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
77
+ */
78
+ protected function _getHelper()
79
+ {
80
+ return Mage::helper('ampersand_paymentgateway/data');
81
+ }
82
+ }
app/code/core/Ampersand/PaymentGateway/Block/Redirect/Location.php ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Block_Redirect_Location extends Mage_Core_Block_Template
3
+ {
4
+ /**
5
+ * Registry key for setting the iframe redirect URL.
6
+ */
7
+ const REGISTRY_KEY_REDIRECT_URL = 'ampersand_paymentgateway_redirect_location_url';
8
+
9
+ /**
10
+ * Set the default template for the redirect.
11
+ *
12
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
13
+ */
14
+ protected function _construct()
15
+ {
16
+ parent::_construct();
17
+
18
+ $this->setTemplate('ampersand_paymentgateway/redirect/location.phtml');
19
+ }
20
+
21
+ /**
22
+ * Retrieve the page title.
23
+ *
24
+ * @return string
25
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
26
+ */
27
+ public function getTitle()
28
+ {
29
+ if (!$this->hasTitle()) {
30
+ $this->setData('title', 'Please wait while you are redirected...');
31
+ }
32
+
33
+ return $this->getData('title');
34
+ }
35
+
36
+ /**
37
+ * Retrieve the redirect url.
38
+ *
39
+ * @return string
40
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
41
+ */
42
+ public function getRedirectUrl()
43
+ {
44
+ if (!$this->hasRedirectUrl()) {
45
+ if (!$redirectUrl = Mage::registry(self::REGISTRY_KEY_REDIRECT_URL)) {
46
+ // added the homepage URL here to prevent infinite redirect loop
47
+ $redirectUrl = Mage::getUrl();
48
+ }
49
+ $this->setData('redirect_url', $redirectUrl);
50
+ }
51
+
52
+ return $this->getData('redirect_url');
53
+ }
54
+
55
+ /**
56
+ * Retrieve the helper class.
57
+ *
58
+ * @return Ampersand_PaymentGateway_Helper_Data
59
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
60
+ */
61
+ protected function _getHelper()
62
+ {
63
+ return Mage::helper('ampersand_paymentgateway/data');
64
+ }
65
+ }
app/code/core/Ampersand/PaymentGateway/Helper/Data.php ADDED
@@ -0,0 +1,492 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Helper_Data extends Mage_Core_Helper_Abstract
3
+ {
4
+ /**
5
+ * Registry key for the unique transaction reference.
6
+ */
7
+ const REGISTRY_KEY_UNIQUE_TRANSACTION_REFERENCE = 'ampersand_unique_transaction_reference';
8
+ const REGISTRY_KEY_BILLING_AGREEMENT_CV2 = 'ampersand_billing_agreement_cv2';
9
+
10
+ /**
11
+ * Session keys for customers selections during checkout.
12
+ */
13
+ const SESSION_KEY_BILLING_AGREEMENT_SELECTION = 'ampersand_paymentgateway_billing_agreement_selection';
14
+
15
+ /**
16
+ * Max number of decimal places for price formatting.
17
+ */
18
+ const MAX_DECIMAL_PLACES = 2;
19
+
20
+ /**
21
+ * Registry key for storing redirect URL.
22
+ */
23
+ const REGISTRY_KEY_REDIRECT_URL = 'ampersand_paymentgateway_redirect_url';
24
+
25
+ /**
26
+ * Customer facing failure messages.
27
+ */
28
+ protected $_failureMessages = array(
29
+ Ampersand_PaymentGateway_Model_Service_Abstract::FAILURE_TYPE_DENIED
30
+ => 'Your order was unsuccessful. Payment has not been taken and your order will not be processed.',
31
+ Ampersand_PaymentGateway_Model_Service_Abstract::FAILURE_TYPE_ERROR
32
+ => 'An unexpected error occured. Please contact customer services quoting the above reference number.',
33
+ );
34
+
35
+ /**
36
+ * Cache of removed session values after first accessed.
37
+ *
38
+ * @var array $_cache
39
+ */
40
+ protected $_cache = array();
41
+
42
+ /**
43
+ * Generate a unique identifier for the transaction.
44
+ *
45
+ * @param Varien_Object $order
46
+ * @return string
47
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
48
+ */
49
+ public function getUniqueTransactionReference(Varien_Object $order = null)
50
+ {
51
+ $uniqueTransactionReference
52
+ = Mage::registry(self::REGISTRY_KEY_UNIQUE_TRANSACTION_REFERENCE);
53
+
54
+ if (!is_null($uniqueTransactionReference)) {
55
+ return $uniqueTransactionReference;
56
+ }
57
+
58
+ if (!$order->getIncrementId()) {
59
+ throw new Exception(
60
+ $this->__('Order required to generate unique transaction reference.')
61
+ );
62
+ }
63
+
64
+ $uniqueTransactionReference = $this->_generateUniqueString($order->getIncrementId());
65
+ $this->setUniqueTransactionReference($uniqueTransactionReference);
66
+
67
+ return $uniqueTransactionReference;
68
+ }
69
+
70
+ /**
71
+ * Return a unique string based on time, random numbers, or some other algorithm.
72
+ *
73
+ * @param string $prefix
74
+ * @return string
75
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
76
+ */
77
+ protected function _generateUniqueString($prefix)
78
+ {
79
+ return $prefix . '-' . time() . '-' . mt_rand(111111,999999);
80
+ }
81
+
82
+ /**
83
+ * Force the value for a unique identifier for the transaction.
84
+ *
85
+ * @param string $newTransactionReference
86
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
87
+ */
88
+ public function setUniqueTransactionReference($newTransactionReference)
89
+ {
90
+ $uniqueTransactionReference
91
+ = Mage::registry(self::REGISTRY_KEY_UNIQUE_TRANSACTION_REFERENCE);
92
+
93
+ if (!is_null($uniqueTransactionReference)) {
94
+ throw new Exception(
95
+ $this->__('A unique transaction reference has already been set.')
96
+ );
97
+ }
98
+
99
+ Mage::register(
100
+ self::REGISTRY_KEY_UNIQUE_TRANSACTION_REFERENCE,
101
+ $newTransactionReference
102
+ );
103
+
104
+ return $this;
105
+ }
106
+
107
+ /**
108
+ * Retrieve the number of decimal places assumed in formatAmount().
109
+ * Countries with no decimal places, like JPY, will not contain a decimal point.
110
+ *
111
+ * @return int
112
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
113
+ */
114
+ public function getDecimalPlaces()
115
+ {
116
+ $localeCode = Mage::app()->getLocale()->getLocaleCode();
117
+ $currencyCode = Mage::app()->getStore()->getCurrentCurrencyCode();
118
+
119
+ // we need access to external entities to get this locale data
120
+ $entityLoaderStatus = libxml_disable_entity_loader(false);
121
+
122
+ $decimalPlaces = Zend_Locale_Data::getContent($localeCode, 'currencyfraction', $currencyCode);
123
+ if ($decimalPlaces === false) {
124
+ $decimalPlaces = Zend_Locale_Data::getContent($localeCode, 'currencyfraction');
125
+ }
126
+
127
+ // reset libxml_entity_loader status back to what it was before
128
+ libxml_disable_entity_loader($entityLoaderStatus);
129
+
130
+ if ($decimalPlaces > self::MAX_DECIMAL_PLACES) {
131
+ $decimalPlaces = self::MAX_DECIMAL_PLACES;
132
+ }
133
+
134
+ return $decimalPlaces;
135
+ }
136
+
137
+ /**
138
+ * Retrieve the region code if available for the provided address country.
139
+ *
140
+ * @param Varien_Object $address
141
+ * @return string
142
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
143
+ */
144
+ public function getRegionCode(Varien_Object $address = null)
145
+ {
146
+ if (!is_object($address) || !$address->getCountryId() || !$address->getRegionCode()) {
147
+ return null;
148
+ }
149
+
150
+ $region = $this->_getRegion($address->getCountryId(), $address->getRegionCode());
151
+ return ($region instanceof Mage_Directory_Model_Region) ? $region->getCode() : null;
152
+ }
153
+
154
+ /**
155
+ * Retrieve the region name if available for the provided address country.
156
+ *
157
+ * @param Varien_Object $address
158
+ * @return string
159
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
160
+ */
161
+ public function getRegionName(Varien_Object $address = null)
162
+ {
163
+ if (!is_object($address) || !$address->getCountryId() || !$address->getRegionCode()) {
164
+ return null;
165
+ }
166
+
167
+ $region = $this->_getRegion($address->getCountryId(), $address->getRegionCode());
168
+ return ($region instanceof Mage_Directory_Model_Region) ? $region->getName() : null;
169
+ }
170
+
171
+ /**
172
+ * Retrieve a region object by country code and region code.
173
+ *
174
+ * @param string $countryCode
175
+ * @param string $regionCode
176
+ * @return string
177
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
178
+ */
179
+ protected function _getRegion($countryCode, $regionCode)
180
+ {
181
+ return Mage::getModel('directory/country')
182
+ ->loadByCode($countryCode)
183
+ ->getRegionCollection()
184
+ ->addFieldToFilter('code', $regionCode)
185
+ ->getFirstItem();
186
+ }
187
+
188
+ /**
189
+ * Retrieve the current customers IP address.
190
+ *
191
+ * @return string
192
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
193
+ */
194
+ public function getClientIpAddress()
195
+ {
196
+ return Mage::app()->getRequest()->getClientIp();
197
+ }
198
+
199
+ /**
200
+ * Retrieve the current customers session ID.
201
+ *
202
+ * @return string
203
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
204
+ */
205
+ public function getSessionId()
206
+ {
207
+ /**
208
+ * @todo Use Magento functionality to achieve this
209
+ */
210
+ return session_id();
211
+ }
212
+
213
+ /**
214
+ * Retrieve the current customers HTTP ACCEPT value.
215
+ *
216
+ * @return string
217
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
218
+ */
219
+ public function getHttpAccept()
220
+ {
221
+ /**
222
+ * @todo Use Magento functionality to achieve this
223
+ */
224
+ return array_key_exists('HTTP_ACCEPT', $_SERVER) ? $_SERVER['HTTP_ACCEPT'] : '';
225
+ }
226
+
227
+ /**
228
+ * Retrieve the current customers HTTP USER AGENT value.
229
+ *
230
+ * @return string
231
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
232
+ */
233
+ public function getHttpUserAgent()
234
+ {
235
+ /**
236
+ * @todo Use Magento functionality to achieve this
237
+ */
238
+ return array_key_exists('HTTP_USER_AGENT', $_SERVER) ? $_SERVER['HTTP_USER_AGENT'] : '';
239
+ }
240
+
241
+ /**
242
+ * Retrieve the order items which are not children.
243
+ *
244
+ * @param Mage_Sales_Model_Order $order
245
+ * @return array
246
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
247
+ */
248
+ public function getOrderItems(Mage_Sales_Model_Order $order)
249
+ {
250
+ return $order->getItemsCollection(array(), true);
251
+ }
252
+
253
+ /**
254
+ * Save customers selection for creating a billing agreement.
255
+ *
256
+ * @param string $selection
257
+ * @return Ampersand_PaymentGateway_Helper_Data
258
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
259
+ */
260
+ public function setBillingAgreementSelection($selection)
261
+ {
262
+ $selection = $selection == '1' ? true : false;
263
+ $this->addSessionData(self::SESSION_KEY_BILLING_AGREEMENT_SELECTION, $selection);
264
+
265
+ return $this;
266
+ }
267
+
268
+ /**
269
+ * Retrieve customers selection for creating a billing agreement.
270
+ *
271
+ * @return bool
272
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
273
+ */
274
+ public function getBillingAgreementSelection()
275
+ {
276
+ // retrieve the selection made by the customer
277
+ $selection = $this->_getSession()->getData(self::SESSION_KEY_BILLING_AGREEMENT_SELECTION);
278
+ if (is_null($selection)) {
279
+ $selection = false;
280
+ }
281
+
282
+ // force billing agreement if subscription selected
283
+ if ($selection == false) {
284
+ $subscriptionSelected = Mage::helper('ampersand_paymentgateway/subscription')
285
+ ->getSubscriptionData('active');
286
+ if ($subscriptionSelected == true) {
287
+ $selection = true;
288
+ $this->setBillingAgreementSelection($selection);
289
+ }
290
+ }
291
+
292
+ return $selection;
293
+ }
294
+
295
+ /**
296
+ * Temporarily store the billing agreement CV2 in memory.
297
+ *
298
+ * @param string $cv2
299
+ * @return Ampersand_PaymentGateway_Helper_Data
300
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
301
+ */
302
+ public function setBillingAgreementCv2($cv2)
303
+ {
304
+ Mage::register(self::REGISTRY_KEY_BILLING_AGREEMENT_CV2, $cv2);
305
+
306
+ return $this;
307
+ }
308
+
309
+ /**
310
+ * Retrieve the billing agreement CV2 from memory.
311
+ *
312
+ * @return string
313
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
314
+ */
315
+ public function getBillingAgreementCv2()
316
+ {
317
+ return Mage::registry(self::REGISTRY_KEY_BILLING_AGREEMENT_CV2);
318
+ }
319
+
320
+ /**
321
+ * Set the redirect URL.
322
+ *
323
+ * @param string $redirect
324
+ * @return Ampersand_PaymentGateway_Helper_Data
325
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
326
+ */
327
+ public function setRedirectUrl($redirect)
328
+ {
329
+ Mage::unregister(self::REGISTRY_KEY_REDIRECT_URL);
330
+ Mage::register(self::REGISTRY_KEY_REDIRECT_URL, $redirect);
331
+
332
+ return $this;
333
+ }
334
+
335
+ /**
336
+ * Retrieve the redirect URL.
337
+ *
338
+ * @return string
339
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
340
+ */
341
+ public function getRedirectUrl()
342
+ {
343
+ $redirect = Mage::registry(self::REGISTRY_KEY_REDIRECT_URL);
344
+ Mage::unregister(self::REGISTRY_KEY_REDIRECT_URL);
345
+
346
+ return $redirect;
347
+ }
348
+
349
+ /**
350
+ * Retrieve error message based on type.
351
+ *
352
+ * @param string $type
353
+ * @return string
354
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
355
+ */
356
+ public function getErrorMessage($type)
357
+ {
358
+ $message = array_key_exists($type, $this->_failureMessages)
359
+ ? $this->_failureMessages[$type]
360
+ : $this->_failureMessages[Ampersand_PaymentGateway_Model_Service_Abstract::FAILURE_TYPE_ERROR];
361
+
362
+ return $this->__($message);
363
+ }
364
+
365
+ /**
366
+ * Set the error message to inform the customer what went wrong on the failure page.
367
+ *
368
+ * @param string $message
369
+ * @return Ampersand_PaymentGateway_Helper_Data
370
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
371
+ */
372
+ public function setSessionErrorMessage($message)
373
+ {
374
+ $this->_getSession()->setErrorMessage($message);
375
+
376
+ return $this;
377
+ }
378
+
379
+ /**
380
+ * Repopulate the cart with order items.
381
+ *
382
+ * @param Mage_Sales_Model_Order $order
383
+ * @return Ampersand_PaymentGateway_Helper_Data
384
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
385
+ */
386
+ public function reorder($order)
387
+ {
388
+ /**
389
+ * @todo retrieve other orders (multishipping)
390
+ */
391
+
392
+ if (is_null($order)) {
393
+ return $this;
394
+ }
395
+
396
+ $cart = Mage::getSingleton('checkout/cart');
397
+ if ($cart->getItemsCount() > 0) {
398
+ return $this;
399
+ }
400
+
401
+ if (!$order instanceof Mage_Sales_Model_Order) {
402
+ $order = Mage::getModel('sales/order')->load($order);
403
+ }
404
+ if (!$order->getId()) {
405
+ return $this;
406
+ }
407
+
408
+ foreach ($order->getItemsCollection() as $_item) {
409
+ try {
410
+ $cart->addOrderItem($_item);
411
+ } catch (Exception $e) {
412
+ // nothing to do
413
+ }
414
+ }
415
+
416
+ $cart->save();
417
+
418
+ return $this;
419
+ }
420
+
421
+ /**
422
+ * Add session data.
423
+ *
424
+ * @param mixed $key
425
+ * @param mixed $value
426
+ * @return Ampersand_PaymentGateway_Helper_Data
427
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
428
+ */
429
+ public function addSessionData($key, $value = null)
430
+ {
431
+ if (is_array($key)) {
432
+ $this->_getSession()->addData($key);
433
+ } else {
434
+ $this->_getSession()->setData($key, $value);
435
+ }
436
+
437
+ return $this;
438
+ }
439
+
440
+ /**
441
+ * Retrieve session data.
442
+ *
443
+ * @param string $key
444
+ * @return mixed
445
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
446
+ */
447
+ public function getSessionData($key = null)
448
+ {
449
+ return $this->_getSession()->getData($key);
450
+ }
451
+
452
+ /**
453
+ * Retrieve a value from the session and remove it.
454
+ *
455
+ * @param string $key
456
+ * @return mixed
457
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
458
+ */
459
+ public function getAndClearSessionKey($key)
460
+ {
461
+ if (!array_key_exists($key, $this->_cache)) {
462
+ $this->_cache[$key] = $this->_getSession()->getData($key);
463
+ $this->_getSession()->setData($key, null);
464
+ }
465
+
466
+ return $this->_cache[$key];
467
+ }
468
+
469
+ /**
470
+ * Reset any items related to a single transaction.
471
+ *
472
+ * @return Ampersand_PaymentGateway_Helper_Data
473
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
474
+ */
475
+ public function resetPaymentGateway()
476
+ {
477
+ Mage::unregister(self::REGISTRY_KEY_UNIQUE_TRANSACTION_REFERENCE);
478
+
479
+ return $this;
480
+ }
481
+
482
+ /**
483
+ * Retrieve the checkout session.
484
+ *
485
+ * @return Mage_Checkout_Model_Session
486
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
487
+ */
488
+ protected function _getSession()
489
+ {
490
+ return Mage::getSingleton('checkout/session');
491
+ }
492
+ }
app/code/core/Ampersand/PaymentGateway/Helper/Subscription.php ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Helper_Subscription extends Mage_Core_Helper_Abstract
3
+ {
4
+ /**
5
+ * Session keys for customers selections during checkout.
6
+ */
7
+ const SESSION_KEY_SUBSCRIPTION_DATA = 'ampersand_paymentgateway_subscription_data';
8
+
9
+ /**
10
+ * Retrieve whether subscriptions are active.
11
+ *
12
+ * @return bool
13
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
14
+ */
15
+ public function isActive($checkForAvailableMethod = false)
16
+ {
17
+ if (!Mage::getModel('ampersand_paymentgateway/versioning')->isBillingAgreementAvailable()) {
18
+ return false;
19
+ }
20
+
21
+ // check for at least one available payment method supporting subscriptions
22
+ if ($checkForAvailableMethod) {
23
+ $found = false;
24
+ $storeMethods = Mage::helper('payment')->getStoreMethods(
25
+ Mage::app()->getStore(),
26
+ Mage::getSingleton('checkout/session')->getQuote()
27
+ );
28
+ foreach ($storeMethods as $_method) {
29
+ if ($this->getCanManageSubscriptions($_method)) {
30
+ // ensure we have at least one method that can manage subscriptions
31
+ $found = true;
32
+ break;
33
+ }
34
+ }
35
+ if (!$found) {
36
+ return false;
37
+ }
38
+ }
39
+
40
+ return Mage::getStoreConfig('ampersand_paymentgateway/subscription/active') == '1';
41
+ }
42
+
43
+ /**
44
+ * Retrieve subscription frequency from period.
45
+ *
46
+ * @param string $period
47
+ * @return string
48
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
49
+ */
50
+ public function getSubscriptionFrequency($period)
51
+ {
52
+ return Mage::getStoreConfig("ampersand_paymentgateway/subscription/frequency_{$period}");
53
+ }
54
+
55
+ /**
56
+ * Add to customers selection data for creating a subscription.
57
+ *
58
+ * @param array $data
59
+ * @return Ampersand_PaymentGateway_Helper_Data
60
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
61
+ */
62
+ public function addSubscriptionData(array $data)
63
+ {
64
+ foreach ($data as $_key => $_value) {
65
+ $this->setSubscriptionData($_key, $_value);
66
+ }
67
+
68
+ return $this;
69
+ }
70
+
71
+ /**
72
+ * Save customers selection data for creating a subscription.
73
+ *
74
+ * @param mixed $key
75
+ * @param mixed $value
76
+ * @return Ampersand_PaymentGateway_Helper_Data
77
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
78
+ */
79
+ public function setSubscriptionData($key, $value = null)
80
+ {
81
+ $data = $this->getSubscriptionData();
82
+
83
+ if (is_array($key)) {
84
+ $data = $key;
85
+ } else {
86
+ $data[$key] = $value;
87
+ }
88
+
89
+ Mage::helper('ampersand_paymentgateway/data')
90
+ ->addSessionData(self::SESSION_KEY_SUBSCRIPTION_DATA, $data);
91
+
92
+ return $this;
93
+ }
94
+
95
+ /**
96
+ * Retrieve customers selection data for creating a subscription.
97
+ *
98
+ * @param string $key
99
+ * @return bool
100
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
101
+ */
102
+ public function getSubscriptionData($key = null)
103
+ {
104
+ if (!$this->isActive(true)) {
105
+ return is_null($key) ? array() : null;
106
+ }
107
+
108
+ // subscriptions are only available to logged in customers
109
+ if (!Mage::helper('customer')->isLoggedIn()) {
110
+ return is_null($key) ? array() : null;
111
+ }
112
+
113
+ $data = Mage::helper('ampersand_paymentgateway/data')
114
+ ->getSessionData(self::SESSION_KEY_SUBSCRIPTION_DATA);
115
+
116
+ if (!is_array($data)) {
117
+ return array();
118
+ }
119
+
120
+ if (is_null($key)) {
121
+ return $data;
122
+ }
123
+
124
+ return array_key_exists($key, $data) ? $data[$key] : null;
125
+ }
126
+
127
+ /**
128
+ * Determine whether a payment method can manage subscriptions.
129
+ *
130
+ * This includes whether a non-agreement method can create a billing agreement as
131
+ * part of the checkout process, which in turn would have an associated subscription.
132
+ *
133
+ * @param Mage_Payment_Model_Method_Abstract $paymentMethod
134
+ * @return bool
135
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
136
+ */
137
+ public function getCanManageSubscriptions($paymentMethod)
138
+ {
139
+ if (!$paymentMethod->getCanManageSubscriptions()) {
140
+ // if the current method cannot trigger billing agreements, no subscription can happen
141
+ if (!$paymentMethod->getCanTriggerBillingAgreementCreation()) {
142
+ return false;
143
+ }
144
+
145
+ // if the current method does not have an associated ba, no subscription can happen
146
+ $baMethodCode = $paymentMethod->getConfigData('billing_agreement_method_code');
147
+ if ($baMethodCode == '') {
148
+ return false;
149
+ }
150
+
151
+ // if the associated ba cannot manage subscriptions, no subscription can happen
152
+ $paymentMethod = Mage::helper('payment')->getMethodInstance($baMethodCode);
153
+ if (!$paymentMethod instanceof Ampersand_PaymentGateway_Model_Method_AgreementAbstract
154
+ || $paymentMethod->getConfigData('active') != '1'
155
+ || !$paymentMethod->getCanManageSubscriptions())
156
+ {
157
+ return false;
158
+ }
159
+ }
160
+
161
+ // note: $paymentMethod could either be the provided method or related agreement method
162
+ if ($paymentMethod->getConfigData('can_manage_subscriptions') != '1') {
163
+ return false;
164
+ }
165
+
166
+ return true;
167
+ }
168
+ }
app/code/core/Ampersand/PaymentGateway/Model/Adapter/Abstract.php ADDED
@@ -0,0 +1,264 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ abstract class Ampersand_PaymentGateway_Model_Adapter_Abstract
3
+ extends Ampersand_Object
4
+ implements Ampersand_PaymentGateway_Model_Adapter_Interface
5
+ {
6
+ /**
7
+ * Payment object.
8
+ *
9
+ * @var Varien_Object $_payment
10
+ */
11
+ protected $_payment;
12
+
13
+ /**
14
+ * Order object.
15
+ *
16
+ * @var Varien_Object $_order
17
+ */
18
+ protected $_order;
19
+
20
+ /**
21
+ * Response object.
22
+ *
23
+ * @var Varien_Object $_response
24
+ */
25
+ protected $_response;
26
+
27
+ /**
28
+ * Reference transaction object.
29
+ *
30
+ * @var Ampersand_PaymentGateway_Model_Transaction $_transaction
31
+ */
32
+ protected $_transaction;
33
+
34
+ /**
35
+ * Debug object.
36
+ *
37
+ * @var Ampersand_Integration_Debug_DebugInterface $_debug
38
+ */
39
+ protected $_debug;
40
+
41
+ /**
42
+ * Queue of service messages defined by the Payment Gateway adapter.
43
+ *
44
+ * @var array $_serviceMessages
45
+ */
46
+ protected $_serviceMessages = array();
47
+
48
+ /**
49
+ * Transformed redirect data.
50
+ *
51
+ * @var array $_transformedRedirectData
52
+ */
53
+ protected $_transformedRedirectData = array();
54
+
55
+ /**
56
+ * Store the payment object against this adapter so it can be accessed elsewhere.
57
+ *
58
+ * @param Varien_Object $payment
59
+ * @return Ampersand_PaymentGateway_Model_Adapter_Abstract
60
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
61
+ */
62
+ public function setPayment(Varien_Object $payment)
63
+ {
64
+ $this->_payment = $payment;
65
+
66
+ return $this;
67
+ }
68
+
69
+ /**
70
+ * Retrieve the payment object stored against this service.
71
+ *
72
+ * @return Varien_Object
73
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
74
+ */
75
+ public function getPayment()
76
+ {
77
+ return $this->_payment;
78
+ }
79
+
80
+ /**
81
+ * Store the order object against this adapter so it can be accessed elsewhere.
82
+ *
83
+ * @param Varien_Object $order
84
+ * @return Ampersand_PaymentGateway_Model_Adapter_Abstract
85
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
86
+ */
87
+ public function setOrder(Varien_Object $order)
88
+ {
89
+ $this->_order = $order;
90
+
91
+ return $this;
92
+ }
93
+
94
+ /**
95
+ * Retrieve the order object stored against this adapter.
96
+ *
97
+ * @return Varien_Object
98
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
99
+ */
100
+ public function getOrder()
101
+ {
102
+ return $this->_order;
103
+ }
104
+
105
+ /**
106
+ * Set the transformed redirect data against the adapter for use elsewhere.
107
+ *
108
+ * @param array $data
109
+ * @return Ampersand_PaymentGateway_Model_Adapter_Abstract
110
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
111
+ */
112
+ public function setTransformedRedirectData($data)
113
+ {
114
+ $this->_transformedRedirectData = $data;
115
+
116
+ return $this;
117
+ }
118
+
119
+ /**
120
+ * Retrieve the transformed redirect data.
121
+ *
122
+ * @return array
123
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
124
+ */
125
+ public function getTransformedRedirectData()
126
+ {
127
+ return $this->_transformedRedirectData;
128
+ }
129
+
130
+ /**
131
+ * Store the Payment Gateway response against this adapter so it can be accessed elsewhere.
132
+ *
133
+ * @param Varien_Object $response
134
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
135
+ */
136
+ public function setResponse(Varien_Object $response)
137
+ {
138
+ $this->_response = $response;
139
+
140
+ return $this;
141
+ }
142
+
143
+ /**
144
+ * Retrieve the Payment Gateway response stored against this adapter.
145
+ *
146
+ * @return Varien_Object
147
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
148
+ */
149
+ public function getResponse()
150
+ {
151
+ return $this->_response;
152
+ }
153
+
154
+ /**
155
+ * Store the reference transaction against this adapter so it can be accessed elsewhere.
156
+ *
157
+ * @param Ampersand_PaymentGateway_Model_Transaction $transaction
158
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
159
+ */
160
+ public function setTransaction(Ampersand_PaymentGateway_Model_Transaction $transaction)
161
+ {
162
+ $this->_transaction = $transaction;
163
+
164
+ return $this;
165
+ }
166
+
167
+ /**
168
+ * Retrieve the reference transaction stored against this adapter.
169
+ *
170
+ * @return Ampersand_PaymentGateway_Model_Transaction
171
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
172
+ */
173
+ public function getTransaction()
174
+ {
175
+ return $this->_transaction;
176
+ }
177
+
178
+ /**
179
+ * Store the debug object against this adapter so it can be accessed elsewhere.
180
+ *
181
+ * @param Ampersand_Integration_Debug_DebugInterface $debug
182
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
183
+ */
184
+ public function setDebug(Ampersand_Integration_Debug_DebugInterface $debug)
185
+ {
186
+ $this->_debug = $debug;
187
+
188
+ return $this;
189
+ }
190
+
191
+ /**
192
+ * Retrieve the debug object stored against this adapter.
193
+ *
194
+ * @return Ampersand_Integration_Debug_DebugInterface
195
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
196
+ */
197
+ public function getDebug()
198
+ {
199
+ return $this->_debug;
200
+ }
201
+
202
+ /**
203
+ * Add a new service message to be called, including the name, the adapter method to retrieve
204
+ * the data from and the adapter method to callback to with the message response.
205
+ *
206
+ * @param string $name
207
+ * @param string $dataMethod
208
+ * @param string $callbackMethod
209
+ * @return Ampersand_PaymentGateway_Model_Adapter_Abstract
210
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
211
+ */
212
+ public function addServiceMessageToQueue($name, $dataMethod = null, $callbackMethod = null)
213
+ {
214
+ if (is_null($dataMethod)) {
215
+ $dataMethod = 'dataFor' . Ampersand_Object::camelize($name);
216
+ }
217
+
218
+ if (is_null($callbackMethod)) {
219
+ $callbackMethod = 'callbackFor' . Ampersand_Object::camelize($name);
220
+ }
221
+
222
+ $this->_serviceMessages[] = array(
223
+ 'name' => $name,
224
+ 'data' => $dataMethod,
225
+ 'callback' => $callbackMethod,
226
+ );
227
+
228
+ return $this;
229
+ }
230
+
231
+ /**
232
+ * Retrieve the next service message from the queue.
233
+ *
234
+ * @return array
235
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
236
+ */
237
+ public function getNextServiceMessage()
238
+ {
239
+ $message = array_shift($this->_serviceMessages);
240
+ return !empty($message) ? $message : false;
241
+ }
242
+
243
+ /**
244
+ * Retrieve the method code for the associated billing agreement payment method.
245
+ *
246
+ * @return string
247
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
248
+ */
249
+ public function getBillingAgreementMethodCode()
250
+ {
251
+ return false;
252
+ }
253
+
254
+ /**
255
+ * Retrieve whether any redirects should use an iframe.
256
+ *
257
+ * @return bool
258
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
259
+ */
260
+ public function getIsUseIframe()
261
+ {
262
+ return true;
263
+ }
264
+ }
app/code/core/Ampersand/PaymentGateway/Model/Adapter/Direct/Agreement/ManageInterface.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ interface Ampersand_PaymentGateway_Model_Adapter_Direct_Agreement_ManageInterface
3
+ extends Ampersand_PaymentGateway_Model_Adapter_Interface
4
+ {
5
+ public function prepareBillingAgreementRequest();
6
+
7
+ public function getBillingAgreementCredentials();
8
+
9
+ /**
10
+ * @todo this should really be here, but is an optional feature...
11
+ */
12
+ // public function prepareBillingAgreementCancel();
13
+ }
app/code/core/Ampersand/PaymentGateway/Model/Adapter/Direct/AuthCaptureInterface.php ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ interface Ampersand_PaymentGateway_Model_Adapter_Direct_AuthCaptureInterface
3
+ extends Ampersand_PaymentGateway_Model_Adapter_Interface
4
+ {
5
+ /**
6
+ * Retrieve the payment transaction ID to be saved against a Magento payment.
7
+ *
8
+ * This method should only return a value if the transaction is completed without the need
9
+ * for a redirect to a third party system and the transaction completes immediately.
10
+ *
11
+ * @return string
12
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
13
+ */
14
+ public function getTransactionReference();
15
+
16
+ /**
17
+ * Queue any service messages to be sent to the Payment Gateway by calling
18
+ * Ampersand_PaymentGateway_Model_Adapter_Abstract::addServiceMessageToQueue().
19
+ *
20
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
21
+ */
22
+ public function prepareRegisterRequest();
23
+
24
+ /**
25
+ * Retrieve any additional information contained in the Payment Gateway register response that
26
+ * should be saved against the transaction. This could be some information that is required in
27
+ * the Payment Gateway callback, or required to perform refunds or additional transactions.
28
+ *
29
+ * @return array
30
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
31
+ */
32
+ public function getTransactionDataFromRegister();
33
+
34
+ /**
35
+ * Based on the register response from the Payment Gateway,
36
+ * determine whether 3D Secure authentication is required for this transaction.
37
+ *
38
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
39
+ */
40
+ public function isThreedSecureRequired();
41
+
42
+ /**
43
+ * Retrieve the MD value required for 3D Secure authentication from the callback response.
44
+ *
45
+ * @return string
46
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
47
+ */
48
+ public function getMd();
49
+
50
+ /**
51
+ * Retrieve the ACS URL value required for 3D Secure authentication from the callback response.
52
+ *
53
+ * @return string
54
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
55
+ */
56
+ public function getAcsUrl();
57
+
58
+ /**
59
+ * Retrieve the PAREQ value required for 3D Secure authentication from the callback response.
60
+ *
61
+ * @return string
62
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
63
+ */
64
+ public function getPareq();
65
+
66
+ /**
67
+ * Retrieve the service message to be called upon completion of 3D Secure authentication.
68
+ *
69
+ * @return string
70
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
71
+ */
72
+ public function getTermUrlMessageName();
73
+
74
+ /**
75
+ * Retrieve the method code for the associated billing agreement payment method.
76
+ *
77
+ * @return string
78
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
79
+ */
80
+ public function getBillingAgreementMethodCode();
81
+
82
+ /**
83
+ * Retrieve whether any redirects should use an iframe.
84
+ *
85
+ * @return bool
86
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
87
+ */
88
+ public function getIsUseIframe();
89
+
90
+ /**
91
+ * Queue any service messages to be sent to the Payment Gateway by calling
92
+ * Ampersand_PaymentGateway_Model_Adapter_Abstract::addServiceMessageToQueue().
93
+ *
94
+ * @param string
95
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
96
+ */
97
+ public function processCallbackResponse();
98
+
99
+ /**
100
+ * Retrieve any additional information contained in the Payment Gateway callback response that
101
+ * should be saved against the transaction. This could be some information that is required to
102
+ * perform refunds or additional transactions.
103
+ *
104
+ * @return array
105
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
106
+ */
107
+ public function getTransactionDataFromCallback();
108
+ }
app/code/core/Ampersand/PaymentGateway/Model/Adapter/Direct/PartialInterface.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ interface Ampersand_PaymentGateway_Model_Adapter_Direct_PartialInterface
3
+ extends Ampersand_PaymentGateway_Model_Adapter_Interface
4
+ {
5
+ /**
6
+ * Queue any service messages to be sent to the Payment Gateway by calling
7
+ * Ampersand_PaymentGateway_Model_Adapter_Abstract::addServiceMessageToQueue().
8
+ *
9
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
10
+ */
11
+ public function prepareRegisterRequest();
12
+
13
+ /**
14
+ * Retrieve the payment transaction ID to be saved against a Magento payment.
15
+ *
16
+ * This method should only return a value if the transaction is completed without the need
17
+ * for a redirect to a third party system and the transaction completes immediately.
18
+ *
19
+ * @return string
20
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
21
+ */
22
+ public function getTransactionReference();
23
+
24
+ /**
25
+ * Retrieve any additional information contained in the Payment Gateway register response that
26
+ * should be saved against the transaction. This could be some information that is required in
27
+ * the Payment Gateway callback, or required to perform refunds or additional transactions.
28
+ *
29
+ * @return array
30
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
31
+ */
32
+ public function getTransactionDataFromRegister();
33
+ }
app/code/core/Ampersand/PaymentGateway/Model/Adapter/Direct/RefundInterface.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ interface Ampersand_PaymentGateway_Model_Adapter_Direct_RefundInterface
3
+ extends Ampersand_PaymentGateway_Model_Adapter_Interface
4
+ {
5
+ /**
6
+ * Queue any service messages to be sent to the Payment Gateway by calling
7
+ * Ampersand_PaymentGateway_Model_Adapter_Abstract::addServiceMessageToQueue().
8
+ *
9
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
10
+ */
11
+ public function prepareRegisterRequest();
12
+
13
+ /**
14
+ * Retrieve the payment transaction ID to be saved against a Magento payment.
15
+ *
16
+ * This method should only return a value if the transaction is completed without the need
17
+ * for a redirect to a third party system and the transaction completes immediately.
18
+ *
19
+ * @return string
20
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
21
+ */
22
+ public function getTransactionReference();
23
+
24
+ /**
25
+ * Retrieve any additional information contained in the Payment Gateway register response that
26
+ * should be saved against the transaction. This could be some information that is required in
27
+ * the Payment Gateway callback, or required to perform refunds or additional transactions.
28
+ *
29
+ * @return array
30
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
31
+ */
32
+ public function getTransactionDataFromRegister();
33
+ }
app/code/core/Ampersand/PaymentGateway/Model/Adapter/Interface.php ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ interface Ampersand_PaymentGateway_Model_Adapter_Interface
3
+ {
4
+ /**
5
+ * Store the payment object against this adapter so it can be accessed elsewhere.
6
+ *
7
+ * @param Varien_Object $payment
8
+ * @return Ampersand_PaymentGateway_Model_Adapter_Abstract
9
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
10
+ */
11
+ public function setPayment(Varien_Object $payment);
12
+
13
+ /**
14
+ * Retrieve the payment object stored against this service.
15
+ *
16
+ * @return Varien_Object
17
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
18
+ */
19
+ public function getPayment();
20
+
21
+ /**
22
+ * Store the order object against this adapter so it can be accessed elsewhere.
23
+ *
24
+ * @param Varien_Object $order
25
+ * @return Ampersand_PaymentGateway_Model_Adapter_Abstract
26
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
27
+ */
28
+ public function setOrder(Varien_Object $order);
29
+
30
+ /**
31
+ * Retrieve the order object stored against this adapter.
32
+ *
33
+ * @return Varien_Object
34
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
35
+ */
36
+ public function getOrder();
37
+
38
+ /**
39
+ * Store the Payment Gateway response against this adapter so it can be accessed elsewhere.
40
+ *
41
+ * @param Varien_Object $response
42
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
43
+ */
44
+ public function setResponse(Varien_Object $response);
45
+
46
+ /**
47
+ * Retrieve the Payment Gateway response stored against this adapter.
48
+ *
49
+ * @return Varien_Object
50
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
51
+ */
52
+ public function getResponse();
53
+
54
+ /**
55
+ * Store the reference transaction against this adapter so it can be accessed elsewhere.
56
+ *
57
+ * @param Ampersand_PaymentGateway_Model_Transaction $transaction
58
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
59
+ */
60
+ public function setTransaction(Ampersand_PaymentGateway_Model_Transaction $transaction);
61
+
62
+ /**
63
+ * Retrieve the reference transaction stored against this adapter.
64
+ *
65
+ * @return Ampersand_PaymentGateway_Model_Transaction
66
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
67
+ */
68
+ public function getTransaction();
69
+
70
+ /**
71
+ * Store the debug object against this adapter so it can be accessed elsewhere.
72
+ *
73
+ * @param Ampersand_Integration_Debug_DebugInterface $debug
74
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
75
+ */
76
+ public function setDebug(Ampersand_Integration_Debug_DebugInterface $debug);
77
+
78
+ /**
79
+ * Retrieve the debug object stored against this adapter.
80
+ *
81
+ * @return Ampersand_Integration_Debug_DebugInterface
82
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
83
+ */
84
+ public function getDebug();
85
+
86
+ /**
87
+ * Add a new service message to be called, including the name, the adapter method to retrieve
88
+ * the data from and the adapter method to callback to with the message response.
89
+ *
90
+ * @param string $name
91
+ * @param string $dataMethod
92
+ * @param string $callbackMethod
93
+ * @return Ampersand_PaymentGateway_Model_Adapter_Abstract
94
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
95
+ */
96
+ public function addServiceMessageToQueue($name, $dataMethod = null, $callbackMethod = null);
97
+
98
+ /**
99
+ * Retrieve the next service message from the queue.
100
+ *
101
+ * @return array
102
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
103
+ */
104
+ public function getNextServiceMessage();
105
+ }
app/code/core/Ampersand/PaymentGateway/Model/Adapter/Redirect/Agreement/ManageInterface.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php
2
+ interface Ampersand_PaymentGateway_Model_Adapter_Redirect_Agreement_ManageInterface
3
+ extends Ampersand_PaymentGateway_Model_Adapter_Interface
4
+ {
5
+ public function prepareBillingAgreementRequest();
6
+
7
+ public function getBillingAgreementCredentials();
8
+ }
app/code/core/Ampersand/PaymentGateway/Model/Adapter/Redirect/AuthCaptureInterface.php ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ interface Ampersand_PaymentGateway_Model_Adapter_Redirect_AuthCaptureInterface
3
+ extends Ampersand_PaymentGateway_Model_Adapter_Interface
4
+ {
5
+ /**
6
+ * Retrieve the payment transaction ID to be saved against a Magento payment.
7
+ *
8
+ * This method should only return a value if the transaction is completed without the need
9
+ * for a redirect to a third party system and the transaction completes immediately.
10
+ *
11
+ * @return string
12
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
13
+ */
14
+ public function getTransactionReference();
15
+
16
+ /**
17
+ * Queue any service messages to be sent to the Payment Gateway by calling
18
+ * Ampersand_PaymentGateway_Model_Adapter_Abstract::addServiceMessageToQueue().
19
+ *
20
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
21
+ */
22
+ public function prepareRegisterRequest();
23
+
24
+ /**
25
+ * Retrieve any additional information contained in the Payment Gateway register response that
26
+ * should be saved against the transaction. This could be some information that is required in
27
+ * the Payment Gateway callback, or required to perform refunds or additional transactions.
28
+ *
29
+ * @return array
30
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
31
+ */
32
+ public function getTransactionDataFromRegister();
33
+
34
+ /**
35
+ * Retrieve the method code for the associated billing agreement payment method.
36
+ *
37
+ * @return string
38
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
39
+ */
40
+ public function getBillingAgreementMethodCode();
41
+
42
+ /**
43
+ * Retrieve whether any redirects should use an iframe.
44
+ *
45
+ * @return bool
46
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
47
+ */
48
+ public function getIsUseIframe();
49
+
50
+ /**
51
+ * Queue any service messages to be sent to the Payment Gateway by calling
52
+ * Ampersand_PaymentGateway_Model_Adapter_Abstract::addServiceMessageToQueue().
53
+ *
54
+ * @param string
55
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
56
+ */
57
+ public function processCallbackResponse();
58
+
59
+ /**
60
+ * Retrieve any additional information contained in the Payment Gateway callback response that
61
+ * should be saved against the transaction. This could be some information that is required to
62
+ * perform refunds or additional transactions.
63
+ *
64
+ * @return array
65
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
66
+ */
67
+ public function getTransactionDataFromCallback();
68
+ }
app/code/core/Ampersand/PaymentGateway/Model/Adapter/Redirect/PartialInterface.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ interface Ampersand_PaymentGateway_Model_Adapter_Redirect_PartialInterface
3
+ extends Ampersand_PaymentGateway_Model_Adapter_Interface
4
+ {
5
+ /**
6
+ * Queue any service messages to be sent to the Payment Gateway by calling
7
+ * Ampersand_PaymentGateway_Model_Adapter_Abstract::addServiceMessageToQueue().
8
+ *
9
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
10
+ */
11
+ public function prepareRegisterRequest();
12
+
13
+ /**
14
+ * Retrieve the payment transaction ID to be saved against a Magento payment.
15
+ *
16
+ * This method should only return a value if the transaction is completed without the need
17
+ * for a redirect to a third party system and the transaction completes immediately.
18
+ *
19
+ * @return string
20
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
21
+ */
22
+ public function getTransactionReference();
23
+
24
+ /**
25
+ * Retrieve any additional information contained in the Payment Gateway register response that
26
+ * should be saved against the transaction. This could be some information that is required in
27
+ * the Payment Gateway callback, or required to perform refunds or additional transactions.
28
+ *
29
+ * @return array
30
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
31
+ */
32
+ public function getTransactionDataFromRegister();
33
+ }
app/code/core/Ampersand/PaymentGateway/Model/Adapter/Redirect/RefundInterface.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ interface Ampersand_PaymentGateway_Model_Adapter_Redirect_RefundInterface
3
+ extends Ampersand_PaymentGateway_Model_Adapter_Interface
4
+ {
5
+ /**
6
+ * Queue any service messages to be sent to the Payment Gateway by calling
7
+ * Ampersand_PaymentGateway_Model_Adapter_Abstract::addServiceMessageToQueue().
8
+ *
9
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
10
+ */
11
+ public function prepareRegisterRequest();
12
+
13
+ /**
14
+ * Retrieve the payment transaction ID to be saved against a Magento payment.
15
+ *
16
+ * This method should only return a value if the transaction is completed without the need
17
+ * for a redirect to a third party system and the transaction completes immediately.
18
+ *
19
+ * @return string
20
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
21
+ */
22
+ public function getTransactionReference();
23
+
24
+ /**
25
+ * Retrieve any additional information contained in the Payment Gateway register response that
26
+ * should be saved against the transaction. This could be some information that is required in
27
+ * the Payment Gateway callback, or required to perform refunds or additional transactions.
28
+ *
29
+ * @return array
30
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
31
+ */
32
+ public function getTransactionDataFromRegister();
33
+ }
app/code/core/Ampersand/PaymentGateway/Model/Agreement.php ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Model_Agreement extends Mage_Core_Model_Abstract
3
+ {
4
+ /**
5
+ * Prefix of model events names
6
+ *
7
+ * @var string
8
+ */
9
+ protected $_eventPrefix = 'ampersand_paymentgateway_agreement';
10
+
11
+ /**
12
+ * Parameter name in event
13
+ *
14
+ * In observe method you can use $observer->getEvent()->getObject() in this case
15
+ *
16
+ * @var string
17
+ */
18
+ protected $_eventObject = 'agreement';
19
+
20
+ /**
21
+ * Initialise model.
22
+ *
23
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
24
+ */
25
+ protected function _construct()
26
+ {
27
+ $this->_init('ampersand_paymentgateway/agreement');
28
+ }
29
+
30
+ /**
31
+ * Load the agreement by service and billing agreement id, ensuring there is only one match.
32
+ *
33
+ * @param string $serviceCode
34
+ * @param string $referenceId
35
+ * @return Ampersand_PaymentGateway_Model_Agreement
36
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
37
+ */
38
+ public function loadByReferenceId($serviceCode, $referenceId)
39
+ {
40
+ $collection = $this->getCollection()
41
+ ->addFieldToFilter('service_code', $serviceCode)
42
+ ->addFieldToFilter('reference_id', $referenceId);
43
+
44
+ if ($collection->count() !== 1) {
45
+ throw new Exception($this->_getHelper()
46
+ ->__("Unable to load agreement for Billing Agreement ID '{$referenceId}'"));
47
+ }
48
+
49
+ $id = $collection->getFirstItem()->getId();
50
+ $this->load($id);
51
+
52
+ return $this;
53
+ }
54
+
55
+ /**
56
+ * Retrieve additional information from the agreement.
57
+ *
58
+ * @param string $key
59
+ * @return string
60
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
61
+ */
62
+ public function getAdditionalInformation($key = null)
63
+ {
64
+ $agreementData = $this->getData('additional_information');
65
+
66
+ if (is_null($key)) {
67
+ return $agreementData;
68
+ }
69
+
70
+ return array_key_exists($key, $agreementData) ? $agreementData[$key] : null;
71
+ }
72
+
73
+ /**
74
+ * Retrieve additional information from the agreement.
75
+ *
76
+ * @param mixed $key
77
+ * @param string $value
78
+ * @return string
79
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
80
+ */
81
+ public function addAdditionalInformation($key, $value = null)
82
+ {
83
+ if (is_array($key)) {
84
+ foreach ($key as $_key => $_value) {
85
+ $this->addAdditionalInformation($_key, $_value);
86
+ }
87
+ }
88
+
89
+ $agreementData = $this->getData('additional_information');
90
+ $agreementData[$key] = $value;
91
+
92
+ return $this;
93
+ }
94
+
95
+ /**
96
+ * Retrieve additional information from the agreement.
97
+ *
98
+ * @param string $key
99
+ * @return string
100
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
101
+ */
102
+ public function unsAdditionalInformation($key)
103
+ {
104
+ $agreementData = $this->getData('additional_information');
105
+ if (!array_key_exists($key, $agreementData)) {
106
+ return $this;
107
+ }
108
+
109
+ unset($agreementData[$key]);
110
+ $this->setData('additional_information', $agreementData);
111
+
112
+ return $this;
113
+ }
114
+
115
+ /**
116
+ * Serialize the additional_information attribute value.
117
+ *
118
+ * @return Ampersand_PaymentGateway_Model_Agreement
119
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
120
+ */
121
+ protected function _beforeSave()
122
+ {
123
+ $additionalInformation = $this->getData('additional_information');
124
+ if (is_array($additionalInformation)) {
125
+ foreach ($additionalInformation as &$_data) {
126
+ $_data = Mage::helper('core')->encrypt($_data);
127
+ }
128
+ $this->setData('additional_information', serialize($additionalInformation));
129
+ }
130
+
131
+ return parent::_beforeSave();
132
+ }
133
+
134
+ /**
135
+ * Unserialize the additional_information attribute value.
136
+ *
137
+ * @return Ampersand_PaymentGateway_Model_Agreement
138
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
139
+ */
140
+ protected function _afterLoad()
141
+ {
142
+ $additionalInformation = $this->getData('additional_information');
143
+ if ($additionalInformation != '') {
144
+ $additionalInformationData = unserialize($additionalInformation);
145
+ foreach ($additionalInformationData as &$_data) {
146
+ $_data = Mage::helper('core')->decrypt($_data);
147
+ }
148
+ $this->setData('additional_information', $additionalInformationData);
149
+ }
150
+
151
+ return parent::_afterLoad();
152
+ }
153
+
154
+ /**
155
+ * Retrieve the helper class.
156
+ *
157
+ * @return Ampersand_PaymentGateway_Helper_Data
158
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
159
+ */
160
+ protected function _getHelper()
161
+ {
162
+ return Mage::helper('ampersand_paymentgateway/data');
163
+ }
164
+ }
app/code/core/Ampersand/PaymentGateway/Model/Compatibility/Mage/Sales/Model/Order/Payment.php ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Model_Compatibility_Mage_Sales_Model_Order_Payment
3
+ extends Mage_Sales_Model_Order_Payment
4
+ {
5
+ /**
6
+ * Pulled together from Mage_Sales_Model_Order_Payment in Magento EE 1.12.0.0,
7
+ * as this method does not exist in Magento versions before EE 1.9.0.0.
8
+ *
9
+ * @param Mage_Sales_Model_Order_Payment $payment
10
+ * @param string $action
11
+ * @return Mage_Sales_Model_Order_Payment
12
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
13
+ */
14
+ public function registerPaymentReviewAction($payment, $action)
15
+ {
16
+ $order = $payment->getOrder();
17
+
18
+ $transactionId = $payment->getLastTransId();
19
+ $invoice = $this->_getInvoiceForTransactionId($order, $transactionId);
20
+
21
+ $result = null;
22
+ $message = null;
23
+
24
+ switch ($action) {
25
+ case Ampersand_PaymentGateway_Model_Service_Abstract::PAYMENT_ACCEPT:
26
+ if ($payment->getMethodInstance()->setStore($order->getStoreId())->acceptPayment($payment)) {
27
+ $result = true;
28
+ $message = Mage::helper('ampersand_paymentgateway')->__('Approved the payment online.');
29
+ } else {
30
+ $result = -1;
31
+ $message = Mage::helper('ampersand_paymentgateway')->__('There is no need to approve this payment.');
32
+ }
33
+ break;
34
+
35
+ case Ampersand_PaymentGateway_Model_Service_Abstract::PAYMENT_DENY:
36
+ if ($payment->getMethodInstance()->setStore($order->getStoreId())->denyPayment($payment)) {
37
+ $result = false;
38
+ $message = Mage::helper('ampersand_paymentgateway')->__('Denied the payment online.');
39
+ } else {
40
+ $result = -1;
41
+ $message = Mage::helper('ampersand_paymentgateway')->__('There is no need to deny this payment.');
42
+ }
43
+ break;
44
+
45
+ default:
46
+ throw new Exception('Not implemented.');
47
+ break;
48
+ }
49
+
50
+ $message = $payment->_prependMessage($message);
51
+
52
+ if ($transactionId) {
53
+ $message .= ' ' . Mage::helper('ampersand_paymentgateway')
54
+ ->__('Transaction ID: "%s".', $transactionId);
55
+ }
56
+
57
+ // process payment in case of positive or negative result, or add a comment
58
+ if (-1 === $result) { // switch won't work with such $result!
59
+ $order->addStatusHistoryComment($message);
60
+ } elseif (true === $result) {
61
+ if ($invoice) {
62
+ $invoice->pay();
63
+ $payment->_updateTotals(array('base_amount_paid_online' => $invoice->getBaseGrandTotal()));
64
+ $order->addRelatedObject($invoice);
65
+ }
66
+ if ($order->getState() == Mage_Sales_Model_Order::STATE_HOLDED) {
67
+ $this->_unhold($order, $message);
68
+ } else {
69
+ $order->setState(Mage_Sales_Model_Order::STATE_PROCESSING, true, $message);
70
+ }
71
+ } elseif (false === $result) {
72
+ if ($invoice) {
73
+ $invoice->cancel();
74
+ $order->addRelatedObject($invoice);
75
+ }
76
+ $order->setState(Mage_Sales_Model_Order::STATE_PROCESSING);
77
+ $order->registerCancellation($message, false);
78
+ }
79
+
80
+ return $this;
81
+ }
82
+
83
+ /**
84
+ * Pulled together from Mage_Sales_Model_Order_Payment in Magento EE 1.12.0.0,
85
+ * as this method does not exist in Magento versions before EE 1.9.0.0.
86
+ *
87
+ * @param Mage_Sales_Model_Order $order
88
+ * @param string $transactionId
89
+ * @return Mage_Sales_Model_Order_Invoice
90
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
91
+ */
92
+ protected function _getInvoiceForTransactionId($order, $transactionId)
93
+ {
94
+ foreach ($order->getInvoiceCollection() as $invoice) {
95
+ if ($invoice->getTransactionId() == $transactionId) {
96
+ $invoice->load($invoice->getId()); // to make sure all data will properly load (maybe not required)
97
+ return $invoice;
98
+ }
99
+ }
100
+
101
+ foreach ($order->getInvoiceCollection() as $invoice) {
102
+ if ($invoice->getState() == Mage_Sales_Model_Order_Invoice::STATE_OPEN
103
+ && $invoice->load($invoice->getId())
104
+ ) {
105
+ $invoice->setTransactionId($transactionId);
106
+ return $invoice;
107
+ }
108
+ }
109
+
110
+ return false;
111
+ }
112
+
113
+ /**
114
+ * Slightly modified Mage_Sales_Model_Order::unhold() method so we can add the message at the
115
+ * same time as updating the state and status, so we don't get two entries in the comments.
116
+ *
117
+ * @param Mage_Sales_Model_Order $order
118
+ * @param string $message
119
+ * @return Ampersand_PaymentGateway_Model_Compatibility_Mage_Sales_Model_Order_Payment
120
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
121
+ */
122
+ protected function _unhold($order, $message = null)
123
+ {
124
+ $order->setState($order->getHoldBeforeState(), $order->getHoldBeforeStatus(), $message, false);
125
+ $order->setHoldBeforeState(null);
126
+ $order->setHoldBeforeStatus(null);
127
+
128
+ return $this;
129
+ }
130
+ }
app/code/core/Ampersand/PaymentGateway/Model/Config/Abstract.php ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ abstract class Ampersand_PaymentGateway_Model_Config_Abstract
3
+ {
4
+ /**
5
+ * Payment method code.
6
+ *
7
+ * @var string $_paymentMethodCode
8
+ */
9
+ protected $_paymentMethodCode = null;
10
+
11
+ /**
12
+ * Payment Gateway addresses.
13
+ *
14
+ * @var array $_gatewayAddresses
15
+ */
16
+ protected $_gatewayAddresses = array();
17
+
18
+ /**
19
+ * Retrieve gateway URL based on service, current mode and type of request.
20
+ *
21
+ * @param string $type
22
+ * @return string
23
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
24
+ */
25
+ public function getGatewayAddress($type)
26
+ {
27
+ $mode = $this->getMode();
28
+
29
+ if (!array_key_exists($mode, $this->_gatewayAddresses)
30
+ || !array_key_exists($type, $this->_gatewayAddresses[$mode])) {
31
+ throw new Exception($this->_getHelper()
32
+ ->__("Unable to retrieve gateway address for {$mode} / {$type}."));
33
+ }
34
+
35
+ return $this->_gatewayAddresses[$mode][$type];
36
+ }
37
+
38
+ /**
39
+ * Retrieve payment gateway mode.
40
+ *
41
+ * @return string
42
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
43
+ */
44
+ public function getMode()
45
+ {
46
+ return $this->_getStoreConfig('mode');
47
+ }
48
+
49
+ /**
50
+ * Set the appropriate config against the service object for easy access in message XML files.
51
+ *
52
+ * @param Varien_Object $object
53
+ * @return Varien_Object
54
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
55
+ */
56
+ public function addConfigToService(Varien_Object $object)
57
+ {
58
+ $object->setConfig($this);
59
+
60
+ return $object;
61
+ }
62
+
63
+ /**
64
+ * Retrieve Magento store config setting.
65
+ *
66
+ * @return string
67
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
68
+ */
69
+ protected function _getStoreConfig($node)
70
+ {
71
+ if (is_null($this->_paymentMethodCode)) {
72
+ throw new Exception('Payment method code is required.');
73
+ }
74
+
75
+ return Mage::getStoreConfig("payment/{$this->_paymentMethodCode}/{$node}");
76
+ }
77
+
78
+ /**
79
+ * Retrieve the helper class.
80
+ *
81
+ * @return Ampersand_PaymentGateway_Helper_Data
82
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
83
+ */
84
+ protected function _getHelper()
85
+ {
86
+ return Mage::helper('ampersand_paymentgateway/data');
87
+ }
88
+ }
app/code/core/Ampersand/PaymentGateway/Model/Cron.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Model_Cron
3
+ {
4
+ /**
5
+ * Cleanup orders, such as incomplete payments that were redirected to 3D Secure.
6
+ *
7
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
8
+ */
9
+ public function orderCleanup()
10
+ {
11
+ if (!Mage::getStoreConfig('ampersand_paymentgateway/cleanup/active')) {
12
+ return;
13
+ }
14
+
15
+ $hours = Mage::getStoreConfig('ampersand_paymentgateway/cleanup/order_timeframe');
16
+ Mage::getModel('ampersand_paymentgateway/utility_cleanup')->cancelPaymentReviewOrders($hours);
17
+ }
18
+
19
+ /**
20
+ * Process subscription reminders.
21
+ *
22
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
23
+ */
24
+ public function processSubscriptionReminders()
25
+ {
26
+ if (!Mage::helper('ampersand_paymentgateway/subscription')->isActive()) {
27
+ return;
28
+ }
29
+
30
+ Mage::getModel('ampersand_paymentgateway/utility_subscription')->sendReminders();
31
+ }
32
+
33
+ /**
34
+ * Process subscriptions.
35
+ *
36
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
37
+ */
38
+ public function processSubscriptions()
39
+ {
40
+ if (!Mage::helper('ampersand_paymentgateway/subscription')->isActive()) {
41
+ return;
42
+ }
43
+
44
+ Mage::getModel('ampersand_paymentgateway/utility_subscription')->process();
45
+ }
46
+ }
app/code/core/Ampersand/PaymentGateway/Model/Email.php ADDED
@@ -0,0 +1,281 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Model_Email
3
+ {
4
+ /**
5
+ * Notification types.
6
+ */
7
+ const NOTIFICATION_TYPE_WARNING = 'warning';
8
+ const NOTIFICATION_TYPE_CRITICAL = 'critical';
9
+
10
+ /**
11
+ * Notification email settings.
12
+ */
13
+ const XML_PATH_NOTIFICATION_EMAIL_BASE = 'ampersand_paymentgateway/notification/';
14
+ const XML_PATH_NOTIFICATION_EMAIL_TEMPLATE = 'email_template';
15
+ const XML_PATH_NOTIFICATION_EMAIL_IDENTITY = 'email_identity';
16
+
17
+ /**
18
+ * Data for email content.
19
+ */
20
+ protected $_title = '';
21
+ protected $_summary = '';
22
+ protected $_exception = null;
23
+ protected $_items = array();
24
+
25
+ /**
26
+ * Send an email of type warning.
27
+ *
28
+ * @return bool
29
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
30
+ */
31
+ public function sendWarning()
32
+ {
33
+ return $this->_send(self::NOTIFICATION_TYPE_WARNING);
34
+ }
35
+
36
+ /**
37
+ * Send an email of type critical.
38
+ *
39
+ * @return bool
40
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
41
+ */
42
+ public function sendCritical()
43
+ {
44
+ return $this->_send(self::NOTIFICATION_TYPE_CRITICAL);
45
+ }
46
+
47
+ /**
48
+ * Set the email title.
49
+ *
50
+ * @param string $title
51
+ * @return Ampersand_PaymentGateway_Model_Email
52
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
53
+ */
54
+ public function setTitle($title)
55
+ {
56
+ $this->_title = $title;
57
+
58
+ return $this;
59
+ }
60
+
61
+ /**
62
+ * Set the email summary.
63
+ *
64
+ * @param string $summary
65
+ * @return Ampersand_PaymentGateway_Model_Email
66
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
67
+ */
68
+ public function setSummary($summary)
69
+ {
70
+ $this->_summary = $summary;
71
+
72
+ return $this;
73
+ }
74
+
75
+ /**
76
+ * Set the related exception.
77
+ *
78
+ * @param Exception $exception
79
+ * @return Ampersand_PaymentGateway_Model_Email
80
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
81
+ */
82
+ public function setException(Exception $exception)
83
+ {
84
+ $this->_exception = $exception;
85
+
86
+ return $this;
87
+ }
88
+
89
+ /**
90
+ * Add email data by name and value.
91
+ *
92
+ * @param string $name
93
+ * @param string $value
94
+ * @return Ampersand_PaymentGateway_Model_Email
95
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
96
+ */
97
+ public function addItem($name, $value)
98
+ {
99
+ $this->_items[] = array(
100
+ 'name' => $name,
101
+ 'value' => $value,
102
+ );
103
+
104
+ return $this;
105
+ }
106
+
107
+ /**
108
+ * Reset all email data.
109
+ *
110
+ * @return Ampersand_PaymentGateway_Model_Email
111
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
112
+ */
113
+ public function reset()
114
+ {
115
+ $this->_title = '';
116
+ $this->_summary = '';
117
+ $this->_exception = null;
118
+ $this->_items = array();
119
+
120
+ return $this;
121
+ }
122
+
123
+ /**
124
+ * Send a transactional email.
125
+ *
126
+ * @param string $type
127
+ * @return bool
128
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
129
+ */
130
+ protected function _send($type)
131
+ {
132
+ // turn translation off
133
+ $translate = Mage::getSingleton('core/translate');
134
+ $translate->setTranslateInline(false);
135
+
136
+ // set the template
137
+ $template = Mage::getStoreConfig(
138
+ self::XML_PATH_NOTIFICATION_EMAIL_BASE
139
+ . self::XML_PATH_NOTIFICATION_EMAIL_TEMPLATE
140
+ );
141
+
142
+ // set the identity
143
+ $identity = Mage::getStoreConfig(
144
+ self::XML_PATH_NOTIFICATION_EMAIL_BASE
145
+ . self::XML_PATH_NOTIFICATION_EMAIL_IDENTITY
146
+ );
147
+
148
+ // set the design config
149
+ $designConfig = array(
150
+ 'area' => 'frontend',
151
+ 'store' => Mage::app()->getStore()->getId()
152
+ );
153
+
154
+ // retrieve email content
155
+ $emailData = array(
156
+ 'title' => $this->_getTitle(),
157
+ 'summary' => $this->_getSummary(),
158
+ 'base_url' => Mage::getBaseUrl(),
159
+ 'items' => $this->_getItems(),
160
+ 'exception_message' => $this->_getExceptionMessage(),
161
+ 'exception_trace' => $this->_getExceptionTrace(),
162
+ );
163
+
164
+ // retrieve all of the email addresses to send to
165
+ $emailAddresses = $this->_getEmailAddresses(
166
+ self::XML_PATH_NOTIFICATION_EMAIL_BASE . $type
167
+ );
168
+
169
+ // send the emails
170
+ foreach ($emailAddresses as $_emailAddress) {
171
+ Mage::getModel('core/email_template')
172
+ ->setDesignConfig($designConfig)
173
+ ->sendTransactional($template, $identity, $_emailAddress, $_emailAddress, $emailData);
174
+ }
175
+
176
+ // reset translation
177
+ $translate->setTranslateInline(true);
178
+
179
+ /**
180
+ * @todo need to determine successes / failures and return them
181
+ */
182
+ return true;
183
+ }
184
+
185
+ /**
186
+ * Retrieve the email title.
187
+ *
188
+ * @return string
189
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
190
+ */
191
+ protected function _getTitle()
192
+ {
193
+ $title = strip_tags($this->_title);
194
+ if ($title == '') {
195
+ $title = 'Ampersand PaymentGateway notification';
196
+ }
197
+
198
+ return $title;
199
+ }
200
+
201
+ /**
202
+ * Retrieve the summary.
203
+ *
204
+ * @return string
205
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
206
+ */
207
+ protected function _getSummary()
208
+ {
209
+ return nl2br($this->_summary);
210
+ }
211
+
212
+ /**
213
+ * Retrieve the email data items.
214
+ *
215
+ * @return string
216
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
217
+ */
218
+ protected function _getItems()
219
+ {
220
+ $items = '';
221
+
222
+ foreach ($this->_items as $_item) {
223
+ $items .= "<strong>{$_item['name']}:</strong><br />{$_item['value']}<br /><br />";
224
+ }
225
+
226
+ return $items;
227
+ }
228
+
229
+ /**
230
+ * Retrieve the exception message, if provided.
231
+ *
232
+ * @return string
233
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
234
+ */
235
+ protected function _getExceptionMessage()
236
+ {
237
+ $exception = $this->_exception;
238
+ if (!$exception instanceof Exception) {
239
+ return '';
240
+ }
241
+
242
+ return $exception->getMessage();
243
+ }
244
+
245
+ /**
246
+ * Retrieve the exception trace, if provided.
247
+ *
248
+ * @return string
249
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
250
+ */
251
+ protected function _getExceptionTrace()
252
+ {
253
+ $exception = $this->_exception;
254
+ if (!$exception instanceof Exception) {
255
+ return '';
256
+ }
257
+
258
+ return nl2br($exception->getTraceAsString());
259
+ }
260
+
261
+ /**
262
+ * Retrieve array of email addresses from path, which are stored comma seperated.
263
+ *
264
+ * @param string $path
265
+ * @return array
266
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
267
+ */
268
+ protected function _getEmailAddresses($path)
269
+ {
270
+ $emails = array();
271
+
272
+ foreach (explode(',', Mage::getStoreConfig($path)) as $_emailAddress) {
273
+ $_emailAddress = strtolower(trim($_emailAddress));
274
+ if ($_emailAddress != '') {
275
+ $emails[] = $_emailAddress;
276
+ }
277
+ }
278
+
279
+ return $emails;
280
+ }
281
+ }
app/code/core/Ampersand/PaymentGateway/Model/Exception/DenyPayment.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This exception should be used when something has occured during a transaction which
4
+ * means you want to deny the payment and update the order to cancelled.
5
+ *
6
+ * Examples of this are when a customer has failed 3D Secure authentication,
7
+ * pressed the cancel button whilst on the payment gateway pages, or when the
8
+ * payment gateway response stating the bank has declined the payment.
9
+ */
10
+ class Ampersand_PaymentGateway_Model_Exception_DenyPayment
11
+ extends Ampersand_PaymentGateway_Model_Exception_Error
12
+ {
13
+
14
+ }
app/code/core/Ampersand/PaymentGateway/Model/Exception/Error.php ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This exception should be used when something has gone wrong during a transaction, meaning
4
+ * the transaction cannot be completed, however you have handled the error appropriately.
5
+ *
6
+ * Examples of this are when an invalid response is returned from the payment gateway or
7
+ * some security fields to not match to suggest the message might have been tampered with.
8
+ */
9
+ class Ampersand_PaymentGateway_Model_Exception_Error extends Exception
10
+ {
11
+ /**
12
+ * Error data associated with the exception.
13
+ *
14
+ * @var array $_errorData
15
+ */
16
+ protected $_errorData = array();
17
+
18
+ /**
19
+ * Initialise exception.
20
+ *
21
+ * @param string $message
22
+ * @param string $code
23
+ * @param array $data
24
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
25
+ */
26
+ public function __construct($message, $code = '0', $data = array())
27
+ {
28
+ $this->setErrorData($data);
29
+ parent::__construct($message, (int)$code);
30
+ }
31
+
32
+ /**
33
+ * Set some error data associated with the exception.
34
+ *
35
+ * @param array $data
36
+ * @return Ampersand_PaymentGateway_Model_Exception_Error
37
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
38
+ */
39
+ public function setErrorData($data)
40
+ {
41
+ $this->_errorData = $data;
42
+
43
+ return $this;
44
+ }
45
+
46
+ /**
47
+ * Retrieve the error data associated with the exception.
48
+ *
49
+ * @return array
50
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
51
+ */
52
+ public function getErrorData()
53
+ {
54
+ return $this->_errorData;
55
+ }
56
+ }
app/code/core/Ampersand/PaymentGateway/Model/Method/AgreementAbstract.php ADDED
@@ -0,0 +1,450 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if (!Mage::getModel('ampersand_paymentgateway/versioning')->isBillingAgreementAvailable()) {
3
+ abstract class Ampersand_PaymentGateway_Model_Method_AgreementAbstract
4
+ {
5
+ public function isAvailable($quote = null)
6
+ {
7
+ return false;
8
+ }
9
+
10
+ public function setStore($store)
11
+ {
12
+ return $this;
13
+ }
14
+ }
15
+ } else {
16
+ abstract class Ampersand_PaymentGateway_Model_Method_AgreementAbstract
17
+ extends Mage_Sales_Model_Payment_Method_Billing_AgreementAbstract
18
+ implements Mage_Payment_Model_Billing_Agreement_MethodInterface
19
+ {
20
+ /**
21
+ * Object keys.
22
+ */
23
+ const OBJECT_KEY_IS_SUBSCRIPTION = 'ampersand_paymentgateway_is_subscription';
24
+
25
+ /**
26
+ * Transport fields.
27
+ */
28
+ const TRANSPORT_BILLING_AGREEMENT_CV2 = 'billing_agreement_cv2';
29
+
30
+ /**
31
+ * Magento payment block types.
32
+ *
33
+ * @var string
34
+ */
35
+ protected $_formBlockType = 'ampersand_paymentgateway/payment_form_billingAgreement';
36
+
37
+ /**
38
+ * Payment Method features
39
+ *
40
+ * @var bool
41
+ */
42
+ protected $_isGateway = true;
43
+ protected $_canOrder = false;
44
+ protected $_canAuthorize = false;
45
+ protected $_canCapture = false;
46
+ protected $_canCapturePartial = false;
47
+ protected $_canRefund = false;
48
+ protected $_canRefundInvoicePartial = false;
49
+ protected $_canVoid = false;
50
+ protected $_canUseInternal = false;
51
+ protected $_canUseCheckout = true;
52
+ protected $_canUseForMultishipping = false;
53
+ protected $_isInitializeNeeded = false;
54
+ protected $_canFetchTransactionInfo = false;
55
+ protected $_canReviewPayment = false;
56
+ protected $_canCreateBillingAgreement = false;
57
+ protected $_canManageRecurringProfiles = false;
58
+ protected $_canCancelInvoice = false;
59
+ protected $_canSaveCc = false;
60
+ protected $_canManageSubscriptions = false;
61
+ protected $_canCallbackAccessSession = true;
62
+
63
+ /**
64
+ * Does this method support billing agreement updates.
65
+ *
66
+ * @var bool $_canUpdateBillingAgreement
67
+ */
68
+ protected $_canUpdateBillingAgreement = false;
69
+
70
+ /**
71
+ * Ampersand Integration service for the Payment Gateway.
72
+ *
73
+ * @var Ampersand_PaymentGateway_Model_Service_Abstract $_service
74
+ */
75
+ protected $_service = null;
76
+
77
+ /**
78
+ * Due to a bug in Magento we have to check that there are agreements available
79
+ * for this particular method. Magento simply checks for any agreements.
80
+ *
81
+ * @param Mage_Sales_Model_Quote $quote
82
+ * @return bool
83
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
84
+ */
85
+ protected function _isAvailable($quote)
86
+ {
87
+ if (!is_object($quote) || !$quote->getCustomer()) {
88
+ return false;
89
+ }
90
+
91
+ $collection = Mage::getModel('sales/billing_agreement')
92
+ ->getAvailableCustomerBillingAgreements($quote->getCustomer()->getId())
93
+ ->addFieldToFilter('method_code', $this->_code);
94
+
95
+ return $collection->count() > 0;
96
+ }
97
+
98
+ /**
99
+ * Assign data to info model instance
100
+ *
101
+ * @param mixed $data
102
+ * @return Mage_Payment_Model_Info
103
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
104
+ */
105
+ public function assignData($data)
106
+ {
107
+ $result = parent::assignData($data);
108
+
109
+ // correctly assign additional information, if provided
110
+ $additionalInformation = array();
111
+ if (is_array($data)) {
112
+ $additionalInformation = array_key_exists('additional_information', $data)
113
+ ? $data['additional_information']
114
+ : array();
115
+ } elseif ($data instanceof Varien_Object) {
116
+ $additionalInformation = $data->getData('additional_information');
117
+ }
118
+ if (is_array($additionalInformation)) {
119
+ foreach ($additionalInformation as $_key => $_value) {
120
+ $this->getInfoInstance()->setAdditionalInformation($_key, $_value);
121
+ }
122
+ }
123
+
124
+ // update the billing agreement CV2 if provided
125
+ $billingAgreementCv2 = '';
126
+ $key = self::TRANSPORT_BILLING_AGREEMENT_CV2;;
127
+ if (is_array($data) && array_key_exists($key, $data)) {
128
+ $billingAgreementCv2 = $data[$key];
129
+ } elseif ($data instanceof Varien_Object) {
130
+ $billingAgreementCv2 = $data->getData($key);
131
+ }
132
+ Mage::helper('ampersand_paymentgateway')->setBillingAgreementCv2($billingAgreementCv2);
133
+
134
+ return $result;
135
+ }
136
+
137
+ /**
138
+ * Init billing agreement
139
+ *
140
+ * @param Mage_Payment_Model_Billing_AgreementAbstract $agreement
141
+ * @return Ampersand_PaymentGateway_Model_Method_Agreement_Direct
142
+ */
143
+ public function initBillingAgreementToken(Mage_Payment_Model_Billing_AgreementAbstract $agreement)
144
+ {
145
+ $this->getService()->initBillingAgreementToken($agreement);
146
+
147
+ return $this;
148
+ }
149
+
150
+ /**
151
+ * Retrieve billing agreement customer details by token
152
+ *
153
+ * @param Mage_Payment_Model_Billing_AgreementAbstract $agreement
154
+ * @return array
155
+ */
156
+ public function getBillingAgreementTokenInfo(Mage_Payment_Model_Billing_AgreementAbstract $agreement)
157
+ {
158
+ /**
159
+ * @todo where is this information saved?
160
+ * looks like we have to save this in some manually created table?
161
+ */
162
+ return $this->getService()->getBillingAgreementTokenInfo($agreement);
163
+ }
164
+
165
+ /**
166
+ * Create billing agreement by token specified in request
167
+ *
168
+ * @param Mage_Payment_Model_Billing_AgreementAbstract $agreement
169
+ * @return Ampersand_PaymentGateway_Model_Method_Agreement_Direct
170
+ */
171
+ public function placeBillingAgreement(Mage_Payment_Model_Billing_AgreementAbstract $agreement)
172
+ {
173
+ $this->getService()->placeBillingAgreement($agreement);
174
+
175
+ return $this;
176
+ }
177
+
178
+ /**
179
+ * Update billing agreement status.
180
+ * This is currently only called by Mage_Sales_Model_Billing_Agreement::cancel().
181
+ *
182
+ * @param Mage_Payment_Model_Billing_AgreementAbstract $agreement
183
+ * @return Ampersand_PaymentGateway_Model_Method_Agreement_Direct
184
+ */
185
+ public function updateBillingAgreementStatus(Mage_Payment_Model_Billing_AgreementAbstract $agreement)
186
+ {
187
+ if (!$this->canUpdateBillingAgreement()) {
188
+ return $this;
189
+ }
190
+
191
+ Mage::dispatchEvent(
192
+ 'ampersand_paymentgateway_update_billing_agreement_status_before',
193
+ array('agreement' => $agreement)
194
+ );
195
+
196
+ switch ($agreement->getStatus()) {
197
+ case Mage_Sales_Model_Billing_Agreement::STATUS_CANCELED:
198
+ $this->getService()->cancelBillingAgreement($agreement);
199
+ break;
200
+
201
+ default:
202
+ break;
203
+ }
204
+
205
+ return $this;
206
+ }
207
+
208
+ /**
209
+ * Authorize payment.
210
+ *
211
+ * @param Varien_Object $payment
212
+ * @param float $amount
213
+ * @return Ampersand_PaymentGateway_Model_Method_Agreement_Direct
214
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
215
+ */
216
+ public function authorize(Varien_Object $payment, $amount)
217
+ {
218
+ parent::authorize($payment, $amount);
219
+
220
+ if ($payment->getAdditionalInformation(self::OBJECT_KEY_IS_SUBSCRIPTION) === true) {
221
+ $this->getService()->subscriptionAuthorize($payment, $amount);
222
+ } else {
223
+ $this->getService()->authorize($payment, $amount);
224
+ }
225
+
226
+ return $this;
227
+ }
228
+
229
+ /**
230
+ * Capture payment.
231
+ *
232
+ * @param Varien_Object $payment
233
+ * @param float $amount
234
+ * @return Ampersand_PaymentGateway_Model_Method_Agreement_Direct
235
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
236
+ */
237
+ public function capture(Varien_Object $payment, $amount)
238
+ {
239
+ parent::capture($payment, $amount);
240
+
241
+ if ($payment->getAdditionalInformation(self::OBJECT_KEY_IS_SUBSCRIPTION) === true) {
242
+ $this->getService()->subscriptionCapture($payment, $amount);
243
+ } else {
244
+ $this->getService()->capture($payment, $amount);
245
+ }
246
+
247
+ return $this;
248
+ }
249
+
250
+ /**
251
+ * Refund payment.
252
+ *
253
+ * @param Varien_Object $payment
254
+ * @param float $amount
255
+ * @return Ampersand_PaymentGateway_Model_Method_Agreement_Direct
256
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
257
+ */
258
+ public function refund(Varien_Object $payment, $amount)
259
+ {
260
+ parent::refund($payment, $amount);
261
+
262
+ $this->getService()->refund($payment, $amount);
263
+
264
+ return $this;
265
+ }
266
+
267
+ /**
268
+ * Retrieve a method specific error message by code.
269
+ *
270
+ * @param string $code
271
+ * @param array $data
272
+ * @return string
273
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
274
+ */
275
+ public function getErrorMessage($code, $data = array())
276
+ {
277
+ return false;
278
+ }
279
+
280
+ /**
281
+ * Attempt to accept a payment that is under review.
282
+ *
283
+ * @param Mage_Payment_Model_Info $payment
284
+ * @return bool
285
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
286
+ */
287
+ public function acceptPayment(Mage_Payment_Model_Info $payment)
288
+ {
289
+ if (method_exists(get_parent_class(), 'acceptPayment')) {
290
+ parent::acceptPayment($payment);
291
+ } else {
292
+ if (is_null($this->_canReviewPayment) || !$this->_canReviewPayment) {
293
+ Mage::throwException(Mage::helper('ampersand_paymentgateway')
294
+ ->__('The payment review action is unavailable.'));
295
+ }
296
+ }
297
+
298
+ if (true !== $payment->getData(Ampersand_PaymentGateway_Model_Service_Abstract::PAYMENT_ACCEPT)) {
299
+ Mage::throwException($this->_getPaymentGatewayHelper()
300
+ ->__('Online payments cannot be accepted manually.'));
301
+ }
302
+
303
+ $requiredState = Mage::getModel('ampersand_paymentgateway/versioning')
304
+ ->getPaymentReviewOrderState();
305
+
306
+ if ($payment->getOrder()->getStatus() !== $requiredState) {
307
+ $comment = $payment->getOrder()->addStatusHistoryComment($this->_getPaymentGatewayHelper()
308
+ ->__('Warning: An attempt was made to accept this payment.'));
309
+ $comment->save();
310
+
311
+ throw new Exception($this->_getPaymentGatewayHelper()
312
+ ->__("Only orders with status '{$requiredState}' can be accepted online."));
313
+ }
314
+
315
+ return true;
316
+ }
317
+
318
+ /**
319
+ * Attempt to deny a payment that is under review.
320
+ *
321
+ * @param Mage_Payment_Model_Info $payment
322
+ * @return bool
323
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
324
+ */
325
+ public function denyPayment(Mage_Payment_Model_Info $payment)
326
+ {
327
+ if (method_exists(get_parent_class(), 'denyPayment')) {
328
+ parent::denyPayment($payment);
329
+ } else {
330
+ if (is_null($this->_canReviewPayment) || !$this->_canReviewPayment) {
331
+ Mage::throwException(Mage::helper('ampersand_paymentgateway')
332
+ ->__('The payment review action is unavailable.'));
333
+ }
334
+ }
335
+
336
+ if (true !== $payment->getData(Ampersand_PaymentGateway_Model_Service_Abstract::PAYMENT_DENY)) {
337
+ Mage::throwException($this->_getPaymentGatewayHelper()
338
+ ->__('Online payments cannot be denied manually.'));
339
+ }
340
+
341
+ $requiredState = Mage::getModel('ampersand_paymentgateway/versioning')
342
+ ->getPaymentReviewOrderState();
343
+
344
+ if ($payment->getOrder()->getStatus() !== $requiredState) {
345
+ $comment = $payment->getOrder()->addStatusHistoryComment($this->_getPaymentGatewayHelper()
346
+ ->__('Warning: An attempt was made to deny this payment.'));
347
+ $comment->save();
348
+
349
+ throw new Exception($this->_getPaymentGatewayHelper()
350
+ ->__("Only orders with status '{$requiredState}' can be denied online."));
351
+ }
352
+
353
+ return true;
354
+ }
355
+
356
+ /**
357
+ * Retrieve the redirect URL.
358
+ *
359
+ * @return string
360
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
361
+ */
362
+ public function getOrderPlaceRedirectUrl()
363
+ {
364
+ return $this->_getPaymentGatewayHelper()->getRedirectUrl();
365
+ }
366
+
367
+ /**
368
+ * Retrieve the Ampersand Integration service for the Payment Gateway.
369
+ *
370
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
371
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
372
+ */
373
+ public function getService()
374
+ {
375
+ if (is_null($this->_service)) {
376
+ $this->_service = $this->_getService();
377
+ $this->_service->setMethodInstance($this);
378
+ }
379
+
380
+ return $this->_service;
381
+ }
382
+
383
+ /**
384
+ * This method must be implemented to retrieve the Ampersand Integration service
385
+ * associated with a particular payment method.
386
+ *
387
+ * This service must extend Ampersand_PaymentGateway_Model_Service.
388
+ *
389
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
390
+ */
391
+ abstract protected function _getService();
392
+
393
+ /**
394
+ * Accessor method for payment method property values.
395
+ *
396
+ * @return mixed
397
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
398
+ */
399
+ public function getPropertyValue($property)
400
+ {
401
+ return property_exists($this, $property) ? $this->$property : null;
402
+ }
403
+
404
+ /**
405
+ * Can this method update a billing agreement in the Payment Gateway.
406
+ *
407
+ * @return bool
408
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
409
+ */
410
+ public function canUpdateBillingAgreement()
411
+ {
412
+ return $this->_canUpdateBillingAgreement;
413
+ }
414
+
415
+ /**
416
+ * Can this method be used for order subscriptions.
417
+ * Only billing agreement methods can manage subscroptions.
418
+ *
419
+ * @return bool
420
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
421
+ */
422
+ public function getCanManageSubscriptions()
423
+ {
424
+ return $this->_canManageSubscriptions;
425
+ }
426
+
427
+ /**
428
+ * Can the callback notification access the customer session.
429
+ * This is required for customer error messages, repopulating cart, etc.
430
+ *
431
+ * @return bool
432
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
433
+ */
434
+ public function getCanCallbackAccessSession()
435
+ {
436
+ return $this->_canCallbackAccessSession;
437
+ }
438
+
439
+ /**
440
+ * Retrieve the Payment Gateway helper.
441
+ *
442
+ * @return Ampersand_PaymentGateway_Helper_Data
443
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
444
+ */
445
+ protected function _getPaymentGatewayHelper()
446
+ {
447
+ return Mage::helper('ampersand_paymentgateway/data');
448
+ }
449
+ }
450
+ }
app/code/core/Ampersand/PaymentGateway/Model/Method/DirectAbstract.php ADDED
@@ -0,0 +1,383 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ abstract class Ampersand_PaymentGateway_Model_Method_DirectAbstract
3
+ extends Mage_Payment_Model_Method_Cc
4
+ {
5
+ /**
6
+ * Custom card types.
7
+ */
8
+ const AMPERSAND_CARTES_BANCAIRES = 'AMPERSAND_CARTES_BANCAIRES';
9
+ const AMPERSAND_MASTERCARD_DEBIT = 'AMPERSAND_MASTERCARD_DEBIT';
10
+ const AMPERSAND_VISA_DELTA = 'AMPERSAND_VISA_DELTA';
11
+ const AMPERSAND_VISA_ELECTRON = 'AMPERSAND_VISA_ELECTRON';
12
+ const AMPERSAND_VISA_PURCHASING = 'AMPERSAND_VISA_PURCHASING';
13
+ const AMPERSAND_LASER = 'AMPERSAND_LASER';
14
+ const AMPERSAND_DINERS_CLUB = 'AMPERSAND_DINERS_CLUB';
15
+ const AMPERSAND_VPAY = 'AMPERSAND_VPAY';
16
+
17
+ /**
18
+ * Payment Method features
19
+ *
20
+ * @var bool
21
+ */
22
+ protected $_isGateway = true;
23
+ protected $_canOrder = false;
24
+ protected $_canAuthorize = false;
25
+ protected $_canCapture = false;
26
+ protected $_canCapturePartial = false;
27
+ protected $_canRefund = false;
28
+ protected $_canRefundInvoicePartial = false;
29
+ protected $_canVoid = false;
30
+ protected $_canUseInternal = false;
31
+ protected $_canUseCheckout = true;
32
+ protected $_canUseForMultishipping = false;
33
+ protected $_isInitializeNeeded = false;
34
+ protected $_canFetchTransactionInfo = false;
35
+ protected $_canReviewPayment = false;
36
+ protected $_canCreateBillingAgreement = false;
37
+ protected $_canManageRecurringProfiles = false;
38
+ protected $_canCancelInvoice = false;
39
+ protected $_canSaveCc = false;
40
+ protected $_canCallbackAccessSession = true;
41
+
42
+ /**
43
+ * Ampersand Integration service for the Payment Gateway.
44
+ *
45
+ * @var Ampersand_PaymentGateway_Model_Service_Abstract $_service
46
+ */
47
+ protected $_service = null;
48
+
49
+ /**
50
+ * Can this method trigger a billing agreement creation.
51
+ *
52
+ * @var bool $_canTriggerBillingAgreementCreation
53
+ */
54
+ protected $_canTriggerBillingAgreementCreation = false;
55
+
56
+ /**
57
+ * Validation for credit card number of custom card types.
58
+ * Note: Any changes here must also be reflected in ampersand_paymentgateway/validation.js
59
+ *
60
+ * @var array $_ampersandCustomCcNumberRegex
61
+ */
62
+ protected $_ampersandCustomCcNumberRegex = array(
63
+ self::AMPERSAND_CARTES_BANCAIRES => false,
64
+ self::AMPERSAND_MASTERCARD_DEBIT => false,
65
+ self::AMPERSAND_VISA_DELTA => false,
66
+ self::AMPERSAND_VISA_ELECTRON => false,
67
+ self::AMPERSAND_VISA_PURCHASING => false,
68
+ self::AMPERSAND_LASER => false,
69
+ self::AMPERSAND_DINERS_CLUB => false,
70
+ self::AMPERSAND_VPAY => false,
71
+ );
72
+
73
+ /**
74
+ * Validation for CSV number of custom card types.
75
+ * Note: Any changes here must also be reflected in ampersand_paymentgateway/validation.js
76
+ *
77
+ * @var array $_ampersandCustomCcNumberRegex
78
+ */
79
+ protected $_ampersandCustomCsvRegex = array(
80
+ self::AMPERSAND_CARTES_BANCAIRES => '/^([0-9]{3}|[0-9]{4})?$/',
81
+ self::AMPERSAND_MASTERCARD_DEBIT => '/^([0-9]{3}|[0-9]{4})?$/',
82
+ self::AMPERSAND_VISA_DELTA => '/^([0-9]{3}|[0-9]{4})?$/',
83
+ self::AMPERSAND_VISA_ELECTRON => '/^([0-9]{3}|[0-9]{4})?$/',
84
+ self::AMPERSAND_VISA_PURCHASING => '/^([0-9]{3}|[0-9]{4})?$/',
85
+ self::AMPERSAND_LASER => '/^([0-9]{3}|[0-9]{4})?$/',
86
+ self::AMPERSAND_DINERS_CLUB => '/^([0-9]{3}|[0-9]{4})?$/',
87
+ self::AMPERSAND_VPAY => '/^([0-9]{3}|[0-9]{4})?$/',
88
+ );
89
+
90
+ /**
91
+ * Assign data to info model instance
92
+ *
93
+ * @param mixed $data
94
+ * @return Mage_Payment_Model_Info
95
+ */
96
+ public function assignData($data)
97
+ {
98
+ parent::assignData($data);
99
+
100
+ if (!($data instanceof Varien_Object)) {
101
+ $data = new Varien_Object($data);
102
+ }
103
+
104
+ $this->_getPaymentGatewayHelper()->setBillingAgreementSelection($data->getBillingAgreementSelection());
105
+
106
+ return $this;
107
+ }
108
+
109
+ /**
110
+ * Validate payment method information object
111
+ *
112
+ * @param Mage_Payment_Model_Info $info
113
+ * @return Mage_Payment_Model_Abstract
114
+ */
115
+ public function validate()
116
+ {
117
+ $info = $this->getInfoInstance();
118
+
119
+ // we are only interested in validating custom card types here
120
+ if (!array_key_exists($info->getCcType(), $this->_ampersandCustomCcNumberRegex)) {
121
+ return parent::validate();
122
+ }
123
+
124
+ // remove credit card number delimiters such as "-" and space
125
+ $ccNumber = preg_replace('/[\-\s]+/', '', $info->getCcNumber());
126
+ $info->setCcNumber($ccNumber);
127
+
128
+ // validate the entered card number
129
+ $ccTypeRegExp = $this->_ampersandCustomCcNumberRegex[$info->getCcType()];
130
+ if ($ccTypeRegExp && (!$ccNumber || !preg_match($ccTypeRegExp, $ccNumber))) {
131
+ Mage::throwException($this->_getPaymentGatewayHelper()->__('Credit card number mismatch with credit card type.'));
132
+ }
133
+
134
+ // validate the CSV number
135
+ if ($this->hasVerification() && array_key_exists($info->getCcType(), $this->_ampersandCustomCsvRegex)) {
136
+ $verifcationRegEx = $this->_ampersandCustomCsvRegex[$info->getCcType()];
137
+ if (!$info->getCcCid() || !preg_match($verifcationRegEx, $info->getCcCid())) {
138
+ Mage::throwException($this->_getPaymentGatewayHelper()->__('Please enter a valid credit card verification number.'));
139
+ }
140
+ }
141
+
142
+ // validate the expiry date
143
+ if (!$this->_validateExpDate($info->getCcExpYear(), $info->getCcExpMonth())) {
144
+ Mage::throwException($this->_getPaymentGatewayHelper()->__('Incorrect credit card expiration date.'));
145
+ }
146
+
147
+ return $this;
148
+ }
149
+
150
+ /**
151
+ * Authorize payment.
152
+ *
153
+ * @param Varien_Object $payment
154
+ * @param float $amount
155
+ * @return Ampersand_PaymentGateway_Model_Method_Direct
156
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
157
+ */
158
+ public function authorize(Varien_Object $payment, $amount)
159
+ {
160
+ parent::authorize($payment, $amount);
161
+
162
+ $this->getService()->authorize($payment, $amount);
163
+
164
+ return $this;
165
+ }
166
+
167
+ /**
168
+ * Capture payment.
169
+ *
170
+ * @param Varien_Object $payment
171
+ * @param float $amount
172
+ * @return Ampersand_PaymentGateway_Model_Method_Direct
173
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
174
+ */
175
+ public function capture(Varien_Object $payment, $amount)
176
+ {
177
+ parent::capture($payment, $amount);
178
+
179
+ $this->getService()->capture($payment, $amount);
180
+
181
+ return $this;
182
+ }
183
+
184
+ /**
185
+ * Refund payment.
186
+ *
187
+ * @param Varien_Object $payment
188
+ * @param float $amount
189
+ * @return Ampersand_PaymentGateway_Model_Method_Direct
190
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
191
+ */
192
+ public function refund(Varien_Object $payment, $amount)
193
+ {
194
+ parent::refund($payment, $amount);
195
+
196
+ $this->getService()->refund($payment, $amount);
197
+
198
+ return $this;
199
+ }
200
+
201
+ /**
202
+ * Retrieve a method specific error message by code.
203
+ *
204
+ * @param string $code
205
+ * @param array $data
206
+ * @return string
207
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
208
+ */
209
+ public function getErrorMessage($code, $data = array())
210
+ {
211
+ return false;
212
+ }
213
+
214
+ /**
215
+ * Attempt to accept a payment that is under review.
216
+ *
217
+ * @param Mage_Payment_Model_Info $payment
218
+ * @return bool
219
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
220
+ */
221
+ public function acceptPayment(Mage_Payment_Model_Info $payment)
222
+ {
223
+ if (method_exists(get_parent_class(), 'acceptPayment')) {
224
+ parent::acceptPayment($payment);
225
+ } else {
226
+ if (is_null($this->_canReviewPayment) || !$this->_canReviewPayment) {
227
+ Mage::throwException(Mage::helper('ampersand_paymentgateway')
228
+ ->__('The payment review action is unavailable.'));
229
+ }
230
+ }
231
+
232
+ if (true !== $payment->getData(Ampersand_PaymentGateway_Model_Service_Abstract::PAYMENT_ACCEPT)) {
233
+ Mage::throwException($this->_getPaymentGatewayHelper()
234
+ ->__('Online payments cannot be accepted manually.'));
235
+ }
236
+
237
+ $requiredState = Mage::getModel('ampersand_paymentgateway/versioning')
238
+ ->getPaymentReviewOrderState();
239
+
240
+ if ($payment->getOrder()->getStatus() !== $requiredState) {
241
+ $comment = $payment->getOrder()->addStatusHistoryComment($this->_getPaymentGatewayHelper()
242
+ ->__('Warning: An attempt was made to accept this payment.'));
243
+ $comment->save();
244
+
245
+ throw new Exception($this->_getPaymentGatewayHelper()
246
+ ->__("Only orders with status '{$requiredState}' can be accepted online."));
247
+ }
248
+
249
+ return true;
250
+ }
251
+
252
+ /**
253
+ * Attempt to deny a payment that is under review.
254
+ *
255
+ * @param Mage_Payment_Model_Info $payment
256
+ * @return bool
257
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
258
+ */
259
+ public function denyPayment(Mage_Payment_Model_Info $payment)
260
+ {
261
+ if (method_exists(get_parent_class(), 'denyPayment')) {
262
+ parent::denyPayment($payment);
263
+ } else {
264
+ if (is_null($this->_canReviewPayment) || !$this->_canReviewPayment) {
265
+ Mage::throwException(Mage::helper('ampersand_paymentgateway')
266
+ ->__('The payment review action is unavailable.'));
267
+ }
268
+ }
269
+
270
+ if (true !== $payment->getData(Ampersand_PaymentGateway_Model_Service_Abstract::PAYMENT_DENY)) {
271
+ Mage::throwException($this->_getPaymentGatewayHelper()
272
+ ->__('Online payments cannot be denied manually.'));
273
+ }
274
+
275
+ $requiredState = Mage::getModel('ampersand_paymentgateway/versioning')
276
+ ->getPaymentReviewOrderState();
277
+
278
+ if ($payment->getOrder()->getStatus() !== $requiredState) {
279
+ $comment = $payment->getOrder()->addStatusHistoryComment($this->_getPaymentGatewayHelper()
280
+ ->__('Warning: An attempt was made to deny this payment.'));
281
+ $comment->save();
282
+
283
+ throw new Exception($this->_getPaymentGatewayHelper()
284
+ ->__("Only orders with status '{$requiredState}' can be denied online."));
285
+ }
286
+
287
+ return true;
288
+ }
289
+
290
+ /**
291
+ * Retrieve the redirect URL.
292
+ *
293
+ * @return string
294
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
295
+ */
296
+ public function getOrderPlaceRedirectUrl()
297
+ {
298
+ return $this->_getPaymentGatewayHelper()->getRedirectUrl();
299
+ }
300
+
301
+ /**
302
+ * Retrieve the Ampersand Integration service for the Payment Gateway.
303
+ *
304
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
305
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
306
+ */
307
+ public function getService()
308
+ {
309
+ if (is_null($this->_service)) {
310
+ $this->_service = $this->_getService();
311
+ $this->_service->setMethodInstance($this);
312
+ }
313
+
314
+ return $this->_service;
315
+ }
316
+
317
+ /**
318
+ * This method must be implemented to retrieve the Ampersand Integration service
319
+ * associated with a particular payment method.
320
+ *
321
+ * This service must extend Ampersand_PaymentGateway_Model_Service.
322
+ *
323
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
324
+ */
325
+ abstract protected function _getService();
326
+
327
+ /**
328
+ * Accessor method for payment method property values.
329
+ *
330
+ * @return mixed
331
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
332
+ */
333
+ public function getPropertyValue($property)
334
+ {
335
+ return property_exists($this, $property) ? $this->$property : null;
336
+ }
337
+
338
+ /**
339
+ * Can this method trigger a billing agreement creation.
340
+ *
341
+ * @return bool
342
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
343
+ */
344
+ public function getCanTriggerBillingAgreementCreation()
345
+ {
346
+ return $this->_canTriggerBillingAgreementCreation;
347
+ }
348
+
349
+ /**
350
+ * Can this method be used for order subscriptions.
351
+ * Only billing agreement methods can manage subscroptions.
352
+ *
353
+ * @return bool
354
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
355
+ */
356
+ final public function getCanManageSubscriptions()
357
+ {
358
+ return false;
359
+ }
360
+
361
+ /**
362
+ * Can the callback notification access the customer session.
363
+ * This is required for customer error messages, repopulating cart, etc.
364
+ *
365
+ * @return bool
366
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
367
+ */
368
+ public function getCanCallbackAccessSession()
369
+ {
370
+ return $this->_canCallbackAccessSession;
371
+ }
372
+
373
+ /**
374
+ * Retrieve the Payment Gateway helper.
375
+ *
376
+ * @return Ampersand_PaymentGateway_Helper_Data
377
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
378
+ */
379
+ protected function _getPaymentGatewayHelper()
380
+ {
381
+ return Mage::helper('ampersand_paymentgateway/data');
382
+ }
383
+ }
app/code/core/Ampersand/PaymentGateway/Model/Method/RedirectAbstract.php ADDED
@@ -0,0 +1,316 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ abstract class Ampersand_PaymentGateway_Model_Method_RedirectAbstract
3
+ extends Mage_Payment_Model_Method_Abstract
4
+ {
5
+ /**
6
+ * Magento payment block types.
7
+ *
8
+ * @var string
9
+ */
10
+ protected $_formBlockType = 'ampersand_paymentgateway/payment_form_redirect';
11
+ protected $_infoBlockType = 'ampersand_paymentgateway/payment_info_redirect';
12
+
13
+ /**
14
+ * Payment Method features
15
+ *
16
+ * @var bool
17
+ */
18
+ protected $_isGateway = true;
19
+ protected $_canOrder = false;
20
+ protected $_canAuthorize = false;
21
+ protected $_canCapture = false;
22
+ protected $_canCapturePartial = false;
23
+ protected $_canRefund = false;
24
+ protected $_canRefundInvoicePartial = false;
25
+ protected $_canVoid = false;
26
+ protected $_canUseInternal = false;
27
+ protected $_canUseCheckout = true;
28
+ protected $_canUseForMultishipping = false;
29
+ protected $_isInitializeNeeded = false;
30
+ protected $_canFetchTransactionInfo = false;
31
+ protected $_canReviewPayment = false;
32
+ protected $_canCreateBillingAgreement = false;
33
+ protected $_canManageRecurringProfiles = false;
34
+ protected $_canCancelInvoice = false;
35
+ protected $_canSaveCc = false;
36
+ protected $_isCcTypeRequired = false;
37
+ protected $_canCallbackAccessSession = false;
38
+
39
+ /**
40
+ * Ampersand Integration service for the Payment Gateway.
41
+ *
42
+ * @var Ampersand_PaymentGateway_Model_Service_Abstract $_service
43
+ */
44
+ protected $_service = null;
45
+
46
+ /**
47
+ * Can this method trigger a billing agreement creation.
48
+ *
49
+ * @var bool $_canTriggerBillingAgreementCreation
50
+ */
51
+ protected $_canTriggerBillingAgreementCreation = false;
52
+
53
+ /**
54
+ * Assign data to info model instance
55
+ *
56
+ * @param mixed $data
57
+ * @return Mage_Payment_Model_Info
58
+ */
59
+ public function assignData($data)
60
+ {
61
+ parent::assignData($data);
62
+
63
+ if (!($data instanceof Varien_Object)) {
64
+ $data = new Varien_Object($data);
65
+ }
66
+
67
+ $this->_getPaymentGatewayHelper()->setBillingAgreementSelection($data->getBillingAgreementSelection());
68
+
69
+ return $this;
70
+ }
71
+
72
+ /**
73
+ * Authorize payment.
74
+ *
75
+ * @param Varien_Object $payment
76
+ * @param float $amount
77
+ * @return Ampersand_PaymentGateway_Model_Method_Redirect
78
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
79
+ */
80
+ public function authorize(Varien_Object $payment, $amount)
81
+ {
82
+ parent::authorize($payment, $amount);
83
+
84
+ $this->getService()->authorize($payment, $amount);
85
+
86
+ return $this;
87
+ }
88
+
89
+ /**
90
+ * Capture payment.
91
+ *
92
+ * @param Varien_Object $payment
93
+ * @param float $amount
94
+ * @return Ampersand_PaymentGateway_Model_Method_Redirect
95
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
96
+ */
97
+ public function capture(Varien_Object $payment, $amount)
98
+ {
99
+ parent::capture($payment, $amount);
100
+
101
+ $this->getService()->capture($payment, $amount);
102
+
103
+ return $this;
104
+ }
105
+
106
+ /**
107
+ * Refund payment.
108
+ *
109
+ * @param Varien_Object $payment
110
+ * @param float $amount
111
+ * @return Ampersand_PaymentGateway_Model_Method_Redirect
112
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
113
+ */
114
+ public function refund(Varien_Object $payment, $amount)
115
+ {
116
+ parent::refund($payment, $amount);
117
+
118
+ $this->getService()->refund($payment, $amount);
119
+
120
+ return $this;
121
+ }
122
+
123
+ /**
124
+ * Retrieve a method specific error message by code.
125
+ *
126
+ * @param string $code
127
+ * @param array $data
128
+ * @return string
129
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
130
+ */
131
+ public function getErrorMessage($code, $data = array())
132
+ {
133
+ return false;
134
+ }
135
+
136
+ /**
137
+ * Attempt to accept a payment that is under review.
138
+ *
139
+ * @param Mage_Payment_Model_Info $payment
140
+ * @return bool
141
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
142
+ */
143
+ public function acceptPayment(Mage_Payment_Model_Info $payment)
144
+ {
145
+ if (method_exists(get_parent_class(), 'acceptPayment')) {
146
+ parent::acceptPayment($payment);
147
+ } else {
148
+ if (is_null($this->_canReviewPayment) || !$this->_canReviewPayment) {
149
+ Mage::throwException(Mage::helper('ampersand_paymentgateway')
150
+ ->__('The payment review action is unavailable.'));
151
+ }
152
+ }
153
+
154
+ if (true !== $payment->getData(Ampersand_PaymentGateway_Model_Service_Abstract::PAYMENT_ACCEPT)) {
155
+ Mage::throwException($this->_getPaymentGatewayHelper()
156
+ ->__('Online payments cannot be accepted manually.'));
157
+ }
158
+
159
+ $requiredState = Mage::getModel('ampersand_paymentgateway/versioning')
160
+ ->getPaymentReviewOrderState();
161
+
162
+ if ($payment->getOrder()->getStatus() !== $requiredState) {
163
+ $comment = $payment->getOrder()->addStatusHistoryComment($this->_getPaymentGatewayHelper()
164
+ ->__('Warning: An attempt was made to accept this payment.'));
165
+ $comment->save();
166
+
167
+ throw new Exception($this->_getPaymentGatewayHelper()
168
+ ->__("Only orders with status '{$requiredState}' can be accepted online."));
169
+ }
170
+
171
+ return true;
172
+ }
173
+
174
+ /**
175
+ * Attempt to deny a payment that is under review.
176
+ *
177
+ * @param Mage_Payment_Model_Info $payment
178
+ * @return bool
179
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
180
+ */
181
+ public function denyPayment(Mage_Payment_Model_Info $payment)
182
+ {
183
+ if (method_exists(get_parent_class(), 'denyPayment')) {
184
+ parent::denyPayment($payment);
185
+ } else {
186
+ if (is_null($this->_canReviewPayment) || !$this->_canReviewPayment) {
187
+ Mage::throwException(Mage::helper('ampersand_paymentgateway')
188
+ ->__('The payment review action is unavailable.'));
189
+ }
190
+ }
191
+
192
+ if (true !== $payment->getData(Ampersand_PaymentGateway_Model_Service_Abstract::PAYMENT_DENY)) {
193
+ Mage::throwException($this->_getPaymentGatewayHelper()
194
+ ->__('Online payments cannot be denied manually.'));
195
+ }
196
+
197
+ $requiredState = Mage::getModel('ampersand_paymentgateway/versioning')
198
+ ->getPaymentReviewOrderState();
199
+
200
+ if ($payment->getOrder()->getStatus() !== $requiredState) {
201
+ $comment = $payment->getOrder()->addStatusHistoryComment($this->_getPaymentGatewayHelper()
202
+ ->__('Warning: An attempt was made to deny this payment.'));
203
+ $comment->save();
204
+
205
+ throw new Exception($this->_getPaymentGatewayHelper()
206
+ ->__("Only orders with status '{$requiredState}' can be denied online."));
207
+ }
208
+
209
+ return true;
210
+ }
211
+
212
+ /**
213
+ * Retrieve the redirect URL.
214
+ *
215
+ * @return string
216
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
217
+ */
218
+ public function getOrderPlaceRedirectUrl()
219
+ {
220
+ return $this->_getPaymentGatewayHelper()->getRedirectUrl();
221
+ }
222
+
223
+ /**
224
+ * Retrieve the Ampersand Integration service for the Payment Gateway.
225
+ *
226
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
227
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
228
+ */
229
+ public function getService()
230
+ {
231
+ if (is_null($this->_service)) {
232
+ $this->_service = $this->_getService();
233
+ $this->_service->setMethodInstance($this);
234
+ }
235
+
236
+ return $this->_service;
237
+ }
238
+
239
+ /**
240
+ * This method must be implemented to retrieve the Ampersand Integration service
241
+ * associated with a particular payment method.
242
+ *
243
+ * This service must extend Ampersand_PaymentGateway_Model_Service.
244
+ *
245
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
246
+ */
247
+ abstract protected function _getService();
248
+
249
+ /**
250
+ * Accessor method for payment method property values.
251
+ *
252
+ * @return mixed
253
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
254
+ */
255
+ public function getPropertyValue($property)
256
+ {
257
+ return property_exists($this, $property) ? $this->$property : null;
258
+ }
259
+
260
+ /**
261
+ * Can this method trigger a billing agreement creation.
262
+ *
263
+ * @return bool
264
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
265
+ */
266
+ public function getCanTriggerBillingAgreementCreation()
267
+ {
268
+ return $this->_canTriggerBillingAgreementCreation;
269
+ }
270
+
271
+ /**
272
+ * Can this method be used for order subscriptions.
273
+ * Only billing agreement methods can manage subscroptions.
274
+ *
275
+ * @return bool
276
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
277
+ */
278
+ final public function getCanManageSubscriptions()
279
+ {
280
+ return false;
281
+ }
282
+
283
+ /**
284
+ * Can the callback notification access the customer session.
285
+ * This is required for customer error messages, repopulating cart, etc.
286
+ *
287
+ * @return bool
288
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
289
+ */
290
+ public function getCanCallbackAccessSession()
291
+ {
292
+ return $this->_canCallbackAccessSession;
293
+ }
294
+
295
+ /**
296
+ * Should this method display credit card type for selection.
297
+ *
298
+ * @return bool
299
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
300
+ */
301
+ public function getIsCcTypeRequired()
302
+ {
303
+ return $this->_isCcTypeRequired;
304
+ }
305
+
306
+ /**
307
+ * Retrieve the Payment Gateway helper.
308
+ *
309
+ * @return Ampersand_PaymentGateway_Helper_Data
310
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
311
+ */
312
+ protected function _getPaymentGatewayHelper()
313
+ {
314
+ return Mage::helper('ampersand_paymentgateway/data');
315
+ }
316
+ }
app/code/core/Ampersand/PaymentGateway/Model/Observer.php ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Model_Observer
3
+ {
4
+ /**
5
+ * Append forms related to billing agreements.
6
+ *
7
+ * @param Varien_Event_Observer $observer
8
+ * @return Ampersand_PaymentGateway_Model_Observer
9
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
10
+ */
11
+ public function appendBillingAgreementForms(Varien_Event_Observer $observer)
12
+ {
13
+ if (!Mage::getModel('ampersand_paymentgateway/versioning')->isBillingAgreementAvailable()) {
14
+ return $this;
15
+ }
16
+
17
+ if (!$this->_getIsCustomerLoggedIn()) {
18
+ return $this;
19
+ }
20
+
21
+ $block = $observer->getEvent()->getBlock();
22
+
23
+ $this->_appendBillingAgreementCheckboxBlock($block);
24
+ $this->_appendBillingAgreementCv2Block($block);
25
+ }
26
+
27
+ /**
28
+ * Append billing agreement checkbox.
29
+ *
30
+ * @param Mage_Core_Block_Abstract $block
31
+ * @return Ampersand_PaymentGateway_Model_Observer
32
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
33
+ */
34
+ protected function _appendBillingAgreementCheckboxBlock($block)
35
+ {
36
+ $paymentMethod = $block->getMethod();
37
+
38
+ // check if the payment method has an assocaited agreement
39
+ $baMethodCode = $paymentMethod->getConfigData('billing_agreement_method_code');
40
+ if ($baMethodCode == '' || !$paymentMethod->getCanTriggerBillingAgreementCreation()) {
41
+ return $this;
42
+ }
43
+
44
+ // ensure the associated BA is active
45
+ $baPaymentMethod = Mage::helper('payment')->getMethodInstance($baMethodCode);
46
+ if (!$baPaymentMethod instanceof Ampersand_PaymentGateway_Model_Method_AgreementAbstract
47
+ || $baPaymentMethod->getConfigData('active') != '1')
48
+ {
49
+ return $this;
50
+ }
51
+
52
+ $billingAgreementCheckboxBlock = Mage::app()->getLayout()
53
+ ->createBlock('ampersand_paymentgateway/payment_form_billingAgreementCheckbox');
54
+
55
+ if ($this->_getSubscriptionHelper()->getSubscriptionData('active')) {
56
+ $billingAgreementCheckboxBlock->setForceBillingAgreement(true);
57
+ }
58
+
59
+ $block->append($billingAgreementCheckboxBlock);
60
+
61
+ return $this;
62
+ }
63
+
64
+ /**
65
+ * Append billing agreement CV2 field.
66
+ *
67
+ * @param Mage_Core_Block_Abstract $block
68
+ * @return Ampersand_PaymentGateway_Model_Observer
69
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
70
+ */
71
+ protected function _appendBillingAgreementCv2Block($block)
72
+ {
73
+ $paymentMethod = $block->getMethod();
74
+
75
+ if (!$paymentMethod instanceof Ampersand_PaymentGateway_Model_Method_AgreementAbstract) {
76
+ return $this;
77
+ }
78
+
79
+ $billingAgreementCv2Block = Mage::app()->getLayout()
80
+ ->createBlock('ampersand_paymentgateway/payment_form_billingAgreementCv2');
81
+
82
+ $block->append($billingAgreementCv2Block);
83
+
84
+ return $this;
85
+ }
86
+
87
+ /**
88
+ * Apply restrictions to available payment methods.
89
+ *
90
+ * @param Varien_Event_Observer $observer
91
+ * @return Ampersand_PaymentGateway_Model_Observer
92
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
93
+ */
94
+ public function updateAvailablePaymentMethods(Varien_Event_Observer $observer)
95
+ {
96
+ $block = $observer->getEvent()->getBlock();
97
+ if (!$block instanceof Mage_Payment_Block_Form_Container) {
98
+ return $this;
99
+ }
100
+
101
+ if (!Mage::getModel('ampersand_paymentgateway/versioning')->isBillingAgreementAvailable()) {
102
+ return $this;
103
+ }
104
+
105
+ if (!$this->_getSubscriptionHelper()->getSubscriptionData('active')) {
106
+ return $this;
107
+ }
108
+
109
+ if (!$this->_getIsCustomerLoggedIn()) {
110
+ return;
111
+ }
112
+
113
+ $methods = $block->getMethods();
114
+ foreach ($methods as $_key => $_method) {
115
+ if (!$this->_getSubscriptionHelper()->getCanManageSubscriptions($_method)) {
116
+ unset($methods[$_key]);
117
+ $block->unsetChild('payment.method.' . $_method->getCode());
118
+ }
119
+ }
120
+ $block->setMethods($methods);
121
+ }
122
+
123
+ /**
124
+ * Determine whether a customer is currently logged in.
125
+ *
126
+ * @return bool
127
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
128
+ */
129
+ protected function _getIsCustomerLoggedIn()
130
+ {
131
+ $customer = Mage::getSingleton('customer/session')->getCustomer();
132
+ return (($customer instanceof Mage_Customer_Model_Customer) && $customer->getId()) ? true : false;
133
+ }
134
+
135
+ /**
136
+ * Retrieve the Payment Gateway subscription helper.
137
+ *
138
+ * @return Ampersand_PaymentGateway_Helper_Subscription
139
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
140
+ */
141
+ protected function _getSubscriptionHelper()
142
+ {
143
+ return Mage::helper('ampersand_paymentgateway/subscription');
144
+ }
145
+ }
app/code/core/Ampersand/PaymentGateway/Model/Resource/Agreement.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Model_Resource_Agreement extends Mage_Core_Model_Mysql4_Abstract
3
+ {
4
+ /**
5
+ * Initialise resource model.
6
+ *
7
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
8
+ */
9
+ protected function _construct()
10
+ {
11
+ $this->_init('ampersand_paymentgateway/agreement', 'entity_id');
12
+ }
13
+
14
+ /**
15
+ * Automatically set the created and updated times.
16
+ *
17
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
18
+ */
19
+ protected function _prepareDataForSave(Mage_Core_Model_Abstract $object)
20
+ {
21
+ $now = now();
22
+ if (!$object->getId() || $object->isObjectNew()) {
23
+ $object->setCreatedAt($now);
24
+ }
25
+ $object->setUpdatedAt($now);
26
+
27
+ return parent::_prepareDataForSave($object);
28
+ }
29
+ }
app/code/core/Ampersand/PaymentGateway/Model/Resource/Agreement/Collection.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Model_Resource_Agreement_Collection
3
+ extends Mage_Core_Model_Mysql4_Collection_Abstract
4
+ {
5
+ /**
6
+ * Initialise collection.
7
+ *
8
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
9
+ */
10
+ protected function _construct()
11
+ {
12
+ $this->_init('ampersand_paymentgateway/agreement');
13
+ }
14
+
15
+ /**
16
+ * Unserialize the additional_information attribute value
17
+ *
18
+ * @return Ampersand_PaymentGateway_Model_Resource_Agreement_Collection
19
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
20
+ */
21
+ protected function _afterLoad()
22
+ {
23
+ foreach ($this->_items as $_item) {
24
+ $_additionalInformation = $_item->getData('additional_information');
25
+ if ($_additionalInformation != '') {
26
+ $_item->setData('additional_information', unserialize($_additionalInformation));
27
+ }
28
+ }
29
+
30
+ parent::_afterLoad();
31
+
32
+ return $this;
33
+ }
34
+ }
app/code/core/Ampersand/PaymentGateway/Model/Resource/Subscription.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Model_Resource_Subscription extends Mage_Core_Model_Mysql4_Abstract
3
+ {
4
+ /**
5
+ * Initialise resource model.
6
+ *
7
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
8
+ */
9
+ protected function _construct()
10
+ {
11
+ $this->_init('ampersand_paymentgateway/subscription', 'entity_id');
12
+ }
13
+
14
+ /**
15
+ * Automatically set the created and updated times.
16
+ *
17
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
18
+ */
19
+ protected function _prepareDataForSave(Mage_Core_Model_Abstract $object)
20
+ {
21
+ $now = now();
22
+ if (!$object->getId() || $object->isObjectNew()) {
23
+ $object->setCreatedAt($now);
24
+ }
25
+ $object->setUpdatedAt($now);
26
+
27
+ return parent::_prepareDataForSave($object);
28
+ }
29
+ }
app/code/core/Ampersand/PaymentGateway/Model/Resource/Subscription/Collection.php ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Model_Resource_Subscription_Collection
3
+ extends Ampersand_Core_Model_Mysql4_Collection_Abstract
4
+ {
5
+ /**
6
+ * Initialise collection.
7
+ *
8
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
9
+ */
10
+ protected function _construct()
11
+ {
12
+ $this->_init('ampersand_paymentgateway/subscription');
13
+ }
14
+
15
+ /**
16
+ * Filter the subscriptions that are active.
17
+ *
18
+ * @return Ampersand_PaymentGateway_Model_Resource_Subscription_Collection
19
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
20
+ */
21
+ public function filterActive()
22
+ {
23
+ $this->addFieldToFilter('is_active', '1');
24
+
25
+ return $this;
26
+ }
27
+
28
+ /**
29
+ * Filter the subscriptions that are ready to be reminded.
30
+ *
31
+ * @return Ampersand_PaymentGateway_Model_Resource_Subscription_Collection
32
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
33
+ */
34
+ public function filterReadyToSendReminder()
35
+ {
36
+ $this->addFieldToFilter('is_reminder_sent', '0');
37
+
38
+ $filterDate = $this->_getFilterDate($this->_getLeadTime() + $this->_getReminderTime());
39
+ $this->addFieldToFilter('next_order_date', array('lt' => $filterDate));
40
+
41
+ return $this;
42
+ }
43
+
44
+ /**
45
+ * Filter the subscriptions that are ready to be processed.
46
+ *
47
+ * @return Ampersand_PaymentGateway_Model_Resource_Subscription_Collection
48
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
49
+ */
50
+ public function filterReadyToProcess()
51
+ {
52
+ $filterDate = $this->_getFilterDate($this->_getLeadTime());
53
+ $this->addFieldToFilter('next_order_date', array('lt' => $filterDate));
54
+
55
+ return $this;
56
+ }
57
+
58
+ /**
59
+ * Format the filter date, given a number of days lead time.
60
+ *
61
+ * @param int $days
62
+ * @return string
63
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
64
+ */
65
+ protected function _getFilterDate($days = 0)
66
+ {
67
+ return date('Y-m-d H:i:s', strtotime("+{$days} days"));
68
+ }
69
+
70
+ /**
71
+ * Retrieve the reminder time for order creation.
72
+ *
73
+ * @return int
74
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
75
+ */
76
+ protected function _getReminderTime()
77
+ {
78
+ $reminderTime = Mage::getStoreConfig('ampersand_paymentgateway/subscription/reminder_time');
79
+
80
+ if (!Mage::helper('ampersand_core/validate')->isInt($reminderTime) || $reminderTime < 0) {
81
+ Mage::throwException(
82
+ 'A value must be provided for the reminder time in hours.'
83
+ );
84
+ }
85
+
86
+ return $reminderTime;
87
+ }
88
+
89
+ /**
90
+ * Retrieve the lead time for order creation.
91
+ *
92
+ * @return int
93
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
94
+ */
95
+ protected function _getLeadTime()
96
+ {
97
+ $leadTime = Mage::getStoreConfig('ampersand_paymentgateway/subscription/lead_time');
98
+
99
+ if (!Mage::helper('ampersand_core/validate')->isInt($leadTime) || $leadTime < 0) {
100
+ Mage::throwException(
101
+ 'A value must be provided for the lead time in hours.'
102
+ );
103
+ }
104
+
105
+ return $leadTime;
106
+ }
107
+ }
app/code/core/Ampersand/PaymentGateway/Model/Resource/Subscription/Order.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Model_Resource_Subscription_Order
3
+ extends Mage_Core_Model_Mysql4_Abstract
4
+ {
5
+ /**
6
+ * Initialise resource model.
7
+ *
8
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
9
+ */
10
+ protected function _construct()
11
+ {
12
+ $this->_init('ampersand_paymentgateway/subscription_order', 'entity_id');
13
+ }
14
+
15
+ /**
16
+ * Automatically set the created and updated times.
17
+ *
18
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
19
+ */
20
+ protected function _prepareDataForSave(Mage_Core_Model_Abstract $object)
21
+ {
22
+ $now = now();
23
+ if (!$object->getId() || $object->isObjectNew()) {
24
+ $object->setCreatedAt($now);
25
+ }
26
+ $object->setUpdatedAt($now);
27
+
28
+ return parent::_prepareDataForSave($object);
29
+ }
30
+ }
app/code/core/Ampersand/PaymentGateway/Model/Resource/Subscription/Order/Collection.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Model_Resource_Subscription_Order_Collection
3
+ extends Mage_Core_Model_Mysql4_Collection_Abstract
4
+ {
5
+ /**
6
+ * Initialise collection.
7
+ *
8
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
9
+ */
10
+ protected function _construct()
11
+ {
12
+ $this->_init('ampersand_paymentgateway/subscription_order');
13
+ }
14
+ }
app/code/core/Ampersand/PaymentGateway/Model/Resource/Transaction.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Model_Resource_Transaction extends Mage_Core_Model_Mysql4_Abstract
3
+ {
4
+ /**
5
+ * Initialise resource model.
6
+ *
7
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
8
+ */
9
+ protected function _construct()
10
+ {
11
+ $this->_init('ampersand_paymentgateway/transaction', 'entity_id');
12
+ }
13
+
14
+ /**
15
+ * Automatically set the created and updated times.
16
+ *
17
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
18
+ */
19
+ protected function _prepareDataForSave(Mage_Core_Model_Abstract $object)
20
+ {
21
+ $now = now();
22
+ if (!$object->getId() || $object->isObjectNew()) {
23
+ $object->setCreatedAt($now);
24
+ }
25
+ $object->setUpdatedAt($now);
26
+
27
+ return parent::_prepareDataForSave($object);
28
+ }
29
+ }
app/code/core/Ampersand/PaymentGateway/Model/Resource/Transaction/Collection.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Model_Resource_Transaction_Collection
3
+ extends Mage_Core_Model_Mysql4_Collection_Abstract
4
+ {
5
+ /**
6
+ * Initialise collection.
7
+ *
8
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
9
+ */
10
+ protected function _construct()
11
+ {
12
+ $this->_init('ampersand_paymentgateway/transaction');
13
+ }
14
+
15
+ /**
16
+ * Unserialize the additional_information attribute value
17
+ *
18
+ * @return Ampersand_PaymentGateway_Model_Resource_Transaction_Collection
19
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
20
+ */
21
+ protected function _afterLoad()
22
+ {
23
+ foreach ($this->_items as $_item) {
24
+ $_additionalInformation = $_item->getData('additional_information');
25
+ if ($_additionalInformation != '') {
26
+ $_item->setData('additional_information', unserialize($_additionalInformation));
27
+ }
28
+
29
+ $_subscriptionData = $_item->getData('subscription_data');
30
+ if ($_subscriptionData != '') {
31
+ $_item->setData('subscription_data', unserialize($_subscriptionData));
32
+ }
33
+ }
34
+
35
+ parent::_afterLoad();
36
+
37
+ return $this;
38
+ }
39
+ }
app/code/core/Ampersand/PaymentGateway/Model/Service/Abstract.php ADDED
@@ -0,0 +1,1738 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ abstract class Ampersand_PaymentGateway_Model_Service_Abstract
3
+ extends Ampersand_Integration_Model_Service
4
+ {
5
+ /**
6
+ * Additional transaction type definitions.
7
+ * Where possible these should match Mage_Sales_Model_Order_Payment_Transaction constants.
8
+ */
9
+ const TRANSACTION_TYPE_AUTH = 'authorization';
10
+ const TRANSACTION_TYPE_CAPTURE = 'capture';
11
+ const TRANSACTION_TYPE_PARTIAL = 'partial';
12
+ const TRANSACTION_TYPE_AGREEMENT_MANAGE = 'manage';
13
+ const TRANSACTION_TYPE_REFUND = 'refund';
14
+ const TRANSACTION_TYPE_SUBSCRIPTION_AUTH = 'subscription_authorization';
15
+ const TRANSACTION_TYPE_SUBSCRIPTION_CAPTURE = 'subscription_capture';
16
+ const TRANSACTION_TYPE_SUBSCRIPTION_PARTIAL = 'subscription_partial';
17
+
18
+ /**
19
+ * Constants for validating Payment accept or deny requests.
20
+ */
21
+ const PAYMENT_ACCEPT = 'ampersand_paymentgateway_payment_accept';
22
+ const PAYMENT_DENY = 'ampersand_paymentgateway_payment_deny';
23
+
24
+ /**
25
+ * Constants for storing information against a payment object.
26
+ */
27
+ const PAYMENT_OBJECT_FIELD_PAYMENT_AMOUNT = 'payment_amount';
28
+
29
+ /**
30
+ * Added this constant for backwards compatability with < EE 1.9.0.0.
31
+ * Should match value of Mage_Sales_Model_Order_Payment_Transaction::RAW_DETAILS
32
+ */
33
+ const PAYMENT_TRANSACTION_RAW_DETAILS = 'raw_details_info';
34
+
35
+ /**
36
+ * Failure types.
37
+ */
38
+ const FAILURE_TYPE_DENIED = 'denied';
39
+ const FAILURE_TYPE_ERROR = 'error';
40
+ const FAILURE_TYPE_NONE = 'none';
41
+
42
+ /**
43
+ * Payment method instance.
44
+ *
45
+ * @var Mage_Payment_Model_Method_Abstract $_methodInstance
46
+ */
47
+ protected $_methodInstance;
48
+
49
+ /**
50
+ * Payment Gateway adapter.
51
+ *
52
+ * @var array $_adapter
53
+ */
54
+ protected $_adapter = array();
55
+
56
+ /**
57
+ * Order object.
58
+ *
59
+ * @var Varien_Object $_order
60
+ */
61
+ protected $_order;
62
+
63
+ /**
64
+ * Response object.
65
+ *
66
+ * @var Varien_Object $_response
67
+ */
68
+ protected $_response;
69
+
70
+ /**
71
+ * Payment object.
72
+ *
73
+ * @var Varien_Object
74
+ */
75
+ protected $_payment;
76
+
77
+ /**
78
+ * Transaction reference object.
79
+ *
80
+ * @var Ampersand_PaymentGateway_Model_Transaction $_transaction
81
+ */
82
+ protected $_transaction;
83
+
84
+ /**
85
+ * Current transaction type.
86
+ *
87
+ * @var string $_transactionType
88
+ */
89
+ protected $_transactionType;
90
+
91
+ /**
92
+ * Current transaction reference.
93
+ *
94
+ * @var string $_transactionReference
95
+ */
96
+ protected $_transactionReference;
97
+
98
+ /**
99
+ * Ampersand Integration debug object.
100
+ *
101
+ * @var Ampersand_Integration_Debug_DebugInterface $_debug
102
+ */
103
+ protected $_debug;
104
+
105
+ /**
106
+ * Allowed transaction types.
107
+ *
108
+ * @var array $_allowedTransactionTypes
109
+ */
110
+ protected $_allowedTransactionTypes = array(
111
+ self::TRANSACTION_TYPE_AUTH,
112
+ self::TRANSACTION_TYPE_CAPTURE,
113
+ self::TRANSACTION_TYPE_REFUND,
114
+ self::TRANSACTION_TYPE_PARTIAL,
115
+ self::TRANSACTION_TYPE_AGREEMENT_MANAGE,
116
+ self::TRANSACTION_TYPE_SUBSCRIPTION_AUTH,
117
+ self::TRANSACTION_TYPE_SUBSCRIPTION_CAPTURE,
118
+ self::TRANSACTION_TYPE_SUBSCRIPTION_PARTIAL,
119
+ );
120
+
121
+ /**
122
+ * Flag to determine whether redirect is required.
123
+ *
124
+ * @var bool $_redirectRequired
125
+ */
126
+ protected $_redirectRequired = false;
127
+
128
+ /**
129
+ * Authorize payment service message.
130
+ *
131
+ * @param Varien_Object $payment
132
+ * @param float $amount
133
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
134
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
135
+ */
136
+ public function authorize(Varien_Object $payment, $amount)
137
+ {
138
+ $this->_addParentTransactionDataToPayment($payment);
139
+
140
+ $this->setTransactionType(self::TRANSACTION_TYPE_AUTH);
141
+
142
+ $this->_setPayment($payment);
143
+ $this->_setOrder($payment->getOrder());
144
+ $payment->setData(self::PAYMENT_OBJECT_FIELD_PAYMENT_AMOUNT, $amount);
145
+
146
+ $transactionReference = $this->getAdapter()->getTransactionReference();
147
+ $this->setTransactionReference($transactionReference);
148
+ if ($transactionReference == '') {
149
+ throw new Exception('Unable to retrieve transaction reference from adapter.');
150
+ }
151
+
152
+ $this->_addBillingAgreementDataToPayment($payment);
153
+
154
+ try {
155
+ $this->_beforePrepareRegisterRequest();
156
+ $this->getAdapter()->prepareRegisterRequest();
157
+ $this->_processServiceMessages();
158
+ } catch (Exception $e) {
159
+ // retrieve custom exception message if available
160
+ if ($methodException = $this->_getMethodException($e)) {
161
+ $e = $methodException;
162
+ }
163
+
164
+ // create a flag against the message
165
+ $this->_updateMessageForFailure($e);
166
+
167
+ // re-throw
168
+ throw $e;
169
+ }
170
+
171
+ $this->_processRegisterRedirect();
172
+
173
+ $payment
174
+ ->setIsTransactionClosed(false)
175
+ ->setShouldCloseParentTransaction(false)
176
+ ->setTransactionId($transactionReference)
177
+ ->setTransactionAdditionalInfo(
178
+ self::PAYMENT_TRANSACTION_RAW_DETAILS,
179
+ $this->getAdapter()->getTransactionDataFromRegister()
180
+ );
181
+
182
+ if ($this->_redirectRequired == false) {
183
+ $this->_processBillingAgreement();
184
+ $this->_addBillingAgreementToOrder();
185
+ $this->_createSubscription();
186
+ }
187
+
188
+ $this->_prepareCustomerNote();
189
+
190
+ return $this;
191
+ }
192
+
193
+ /**
194
+ * Capture payment service message.
195
+ *
196
+ * @param Varien_Object $payment
197
+ * @param float $amount
198
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
199
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
200
+ */
201
+ public function capture(Varien_Object $payment, $amount)
202
+ {
203
+ $this->_addParentTransactionDataToPayment($payment);
204
+
205
+ if ($payment->hasParentTransactionData()) {
206
+ $this->setTransactionType(self::TRANSACTION_TYPE_PARTIAL);
207
+ return $this->_partialCapture($payment, $amount);
208
+ } else {
209
+ $this->setTransactionType(self::TRANSACTION_TYPE_CAPTURE);
210
+ return $this->_authorizeAndCapture($payment, $amount);
211
+ }
212
+ }
213
+
214
+ /**
215
+ * Authorize and capture service message.
216
+ *
217
+ * @param Varien_Object $payment
218
+ * @param float $amount
219
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
220
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
221
+ */
222
+ protected function _authorizeAndCapture(Varien_Object $payment, $amount)
223
+ {
224
+ $this->_setPayment($payment);
225
+ $this->_setOrder($payment->getOrder());
226
+ $payment->setData(self::PAYMENT_OBJECT_FIELD_PAYMENT_AMOUNT, $amount);
227
+
228
+ $transactionReference = $this->getAdapter()->getTransactionReference();
229
+ $this->setTransactionReference($transactionReference);
230
+ if ($transactionReference == '') {
231
+ throw new Exception('Unable to retrieve transaction reference from adapter.');
232
+ }
233
+
234
+ $this->_addBillingAgreementDataToPayment($payment);
235
+
236
+ try {
237
+ $this->_beforePrepareRegisterRequest();
238
+ $this->getAdapter()->prepareRegisterRequest();
239
+ $this->_processServiceMessages();
240
+ } catch (Exception $e) {
241
+ // retrieve custom exception message if available
242
+ if ($methodException = $this->_getMethodException($e)) {
243
+ $e = $methodException;
244
+ }
245
+
246
+ // create a flag against the message
247
+ $this->_updateMessageForFailure($e);
248
+
249
+ // re-throw
250
+ throw $e;
251
+ }
252
+
253
+ $this->_processRegisterRedirect();
254
+
255
+ $payment
256
+ ->setIsTransactionClosed(false)
257
+ ->setShouldCloseParentTransaction(false)
258
+ ->setTransactionId($transactionReference)
259
+ ->setTransactionAdditionalInfo(
260
+ self::PAYMENT_TRANSACTION_RAW_DETAILS,
261
+ $this->getAdapter()->getTransactionDataFromRegister()
262
+ );
263
+
264
+ if ($this->_redirectRequired == false) {
265
+ $this->_processBillingAgreement();
266
+ $this->_addBillingAgreementToOrder();
267
+ $this->_createSubscription();
268
+ }
269
+
270
+ $this->_prepareCustomerNote();
271
+
272
+ return $this;
273
+ }
274
+
275
+ /**
276
+ * Partial capture of a previously authorized payment.
277
+ *
278
+ * @param Varien_Object $payment
279
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
280
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
281
+ */
282
+ protected function _partialCapture(Varien_Object $payment, $amount)
283
+ {
284
+ $this->_setPayment($payment);
285
+ $this->_setOrder($payment->getOrder());
286
+ $payment->setData(self::PAYMENT_OBJECT_FIELD_PAYMENT_AMOUNT, $amount);
287
+
288
+ $transactionReference = $this->getAdapter()->getTransactionReference();
289
+ $transactionReference = $this->_incrementTransactionId($payment, $transactionReference);
290
+ $this->setTransactionReference($transactionReference);
291
+ if ($transactionReference == '') {
292
+ throw new Exception('Unable to retrieve transaction reference from adapter.');
293
+ }
294
+
295
+ $this->_addBillingAgreementDataToPayment($payment);
296
+
297
+ try {
298
+ $this->_beforePrepareRegisterRequest();
299
+ $this->getAdapter()->prepareRegisterRequest();
300
+ $this->_processServiceMessages();
301
+ } catch (Exception $e) {
302
+ // retrieve custom exception message if available
303
+ if ($methodException = $this->_getMethodException($e)) {
304
+ $e = $methodException;
305
+ }
306
+
307
+ // create a flag against the message
308
+ $this->_updateMessageForFailure($e);
309
+
310
+ // re-throw
311
+ throw $e;
312
+ }
313
+
314
+ $payment
315
+ ->setIsTransactionClosed(false)
316
+ ->setShouldCloseParentTransaction(false)
317
+ ->setTransactionId($transactionReference)
318
+ ->setTransactionAdditionalInfo(
319
+ self::PAYMENT_TRANSACTION_RAW_DETAILS,
320
+ $this->getAdapter()->getTransactionDataFromRegister()
321
+ );
322
+
323
+ return $this;
324
+ }
325
+
326
+ /**
327
+ * Authorize payment service message, triggered by a subscription.
328
+ *
329
+ * @param Varien_Object $payment
330
+ * @param float $amount
331
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
332
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
333
+ */
334
+ public function subscriptionAuthorize(Varien_Object $payment, $amount)
335
+ {
336
+ if (!$this->_getSubscriptionHelper()->isActive()) {
337
+ throw new Exception('Subscriptions are disabled due to configuration settings.');
338
+ }
339
+
340
+ $this->setTransactionType(self::TRANSACTION_TYPE_SUBSCRIPTION_AUTH);
341
+ return $this->_subscriptionTransaction($payment, $amount);
342
+ }
343
+
344
+ /**
345
+ * Capture payment service message, triggered by a subscription.
346
+ *
347
+ * @param Varien_Object $payment
348
+ * @param float $amount
349
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
350
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
351
+ */
352
+ public function subscriptionCapture(Varien_Object $payment, $amount)
353
+ {
354
+ if (!$this->_getSubscriptionHelper()->isActive()) {
355
+ throw new Exception('Subscriptions are disabled due to configuration settings.');
356
+ }
357
+
358
+ $this->_addParentTransactionDataToPayment($payment);
359
+
360
+ if ($payment->hasParentTransactionData()) {
361
+ $this->setTransactionType(self::TRANSACTION_TYPE_SUBSCRIPTION_PARTIAL);
362
+ return $this->_partialCapture($payment, $amount);
363
+ } else {
364
+ $this->setTransactionType(self::TRANSACTION_TYPE_SUBSCRIPTION_CAPTURE);
365
+ return $this->_subscriptionTransaction($payment, $amount);
366
+ }
367
+ }
368
+
369
+ /**
370
+ * Common subscription logic between authorize and capture methods.
371
+ *
372
+ * @param Varien_Object $payment
373
+ * @param float $amount
374
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
375
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
376
+ */
377
+ protected function _subscriptionTransaction(Varien_Object $payment, $amount)
378
+ {
379
+ $this->_setPayment($payment);
380
+ $this->_setOrder($payment->getOrder());
381
+ $payment->setData(self::PAYMENT_OBJECT_FIELD_PAYMENT_AMOUNT, $amount);
382
+
383
+ $transactionReference = $this->getAdapter()->getTransactionReference();
384
+ $this->setTransactionReference($transactionReference);
385
+ if ($transactionReference == '') {
386
+ throw new Exception('Unable to retrieve transaction reference from adapter.');
387
+ }
388
+
389
+ $this->_addBillingAgreementDataToPayment($payment);
390
+
391
+ try {
392
+ $this->_beforePrepareRegisterRequest();
393
+ $this->getAdapter()->prepareRegisterRequest();
394
+ $this->_processServiceMessages();
395
+ } catch (Exception $e) {
396
+ // retrieve custom exception message if available
397
+ if ($methodException = $this->_getMethodException($e)) {
398
+ $e = $methodException;
399
+ }
400
+
401
+ // create a flag against the message
402
+ $this->_updateMessageForFailure($e);
403
+
404
+ // re-throw
405
+ throw $e;
406
+ }
407
+
408
+ $payment
409
+ ->setIsTransactionClosed(false)
410
+ ->setShouldCloseParentTransaction(false)
411
+ ->setTransactionId($transactionReference)
412
+ ->setTransactionAdditionalInfo(
413
+ self::PAYMENT_TRANSACTION_RAW_DETAILS,
414
+ $this->getAdapter()->getTransactionDataFromRegister()
415
+ );
416
+
417
+ $this->_addBillingAgreementToOrder();
418
+
419
+ return $this;
420
+ }
421
+
422
+ /**
423
+ * Refund payment service message.
424
+ *
425
+ * @param Varien_Object $payment
426
+ * @param float $amount
427
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
428
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
429
+ */
430
+ public function refund(Varien_Object $payment, $amount)
431
+ {
432
+ $payment->setData(self::PAYMENT_OBJECT_FIELD_PAYMENT_AMOUNT, $amount);
433
+
434
+ $this->_addParentTransactionDataToPayment($payment);
435
+ $this->_addBillingAgreementDataToPayment($payment);
436
+
437
+ $this->setTransactionType(self::TRANSACTION_TYPE_REFUND);
438
+
439
+ $this->_setPayment($payment);
440
+ $this->_setOrder($payment->getOrder());
441
+
442
+ $transactionReference = $this->getAdapter()->getTransactionReference();
443
+ $transactionReference = $this->_incrementTransactionId($payment, $transactionReference);
444
+ $this->setTransactionReference($transactionReference);
445
+ if ($transactionReference == '') {
446
+ throw new Exception('Unable to retrieve transaction reference from adapter.');
447
+ }
448
+
449
+ try {
450
+ $this->_beforePrepareRegisterRequest();
451
+ $this->getAdapter()->prepareRegisterRequest();
452
+ $this->_processServiceMessages();
453
+ } catch (Exception $e) {
454
+ // retrieve custom exception message if available
455
+ if ($methodException = $this->_getMethodException($e)) {
456
+ $e = $methodException;
457
+ }
458
+
459
+ // create a flag against the message
460
+ $this->_updateMessageForFailure($e);
461
+
462
+ // re-throw
463
+ throw $e;
464
+ }
465
+
466
+ $payment
467
+ ->setIsTransactionClosed(false)
468
+ ->setShouldCloseParentTransaction(false)
469
+ ->setTransactionId($transactionReference)
470
+ ->setTransactionAdditionalInfo(
471
+ self::PAYMENT_TRANSACTION_RAW_DETAILS,
472
+ $this->getAdapter()->getTransactionDataFromRegister()
473
+ );
474
+
475
+ return $this;
476
+ }
477
+
478
+ /**
479
+ * Add related transaction data to payment object.
480
+ *
481
+ * @param Varien_Object $payment
482
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
483
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
484
+ */
485
+ protected function _addParentTransactionDataToPayment(Varien_Object $payment)
486
+ {
487
+ if ($parentTransactionId = $payment->getParentTransactionId()) {
488
+ $parentTransaction = $payment->getTransaction($parentTransactionId);
489
+ $parentTransactionData = $parentTransaction->getAdditionalInformation();
490
+ $payment->setParentTransactionData(
491
+ $parentTransactionData[self::PAYMENT_TRANSACTION_RAW_DETAILS]
492
+ );
493
+ }
494
+
495
+ return $this;
496
+ }
497
+
498
+ /**
499
+ * Add related billing agreement data to payment object.
500
+ *
501
+ * @param Varien_Object $payment
502
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
503
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
504
+ */
505
+ protected function _addBillingAgreementDataToPayment(Varien_Object $payment)
506
+ {
507
+ if (!Mage::getModel('ampersand_paymentgateway/versioning')->isBillingAgreementAvailable()) {
508
+ return $this;
509
+ }
510
+
511
+ if (!$payment->getMethodInstance()->canManageBillingAgreements()) {
512
+ return $this;
513
+ }
514
+
515
+ $billingAgreement = Mage::getModel('ampersand_paymentgateway/agreement')
516
+ ->loadByReferenceId(
517
+ $this->_getServiceCode(),
518
+ $payment->getAdditionalInformation('ba_reference_id')
519
+ );
520
+
521
+ /**
522
+ * @todo NOTE: setting this as billing_agreement_data causes payment to try and create a new
523
+ * billing agreement on completion in Mage_Sales_Model_Order_Payment::_createBillingAgreement()
524
+ */
525
+ $billingAgreementCredentials = $billingAgreement->getAdditionalInformation();
526
+
527
+ $cv2Field = Ampersand_PaymentGateway_Model_Method_AgreementAbstract
528
+ ::TRANSPORT_BILLING_AGREEMENT_CV2;
529
+ $billingAgreementCredentials[$cv2Field]= $this->_getHelper()->getBillingAgreementCv2();
530
+ $payment->setBillingAgreementCredentials($billingAgreementCredentials);
531
+
532
+ return $this;
533
+ }
534
+
535
+ /**
536
+ * Process all queued service messages.
537
+ *
538
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
539
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
540
+ */
541
+ protected function _processServiceMessages()
542
+ {
543
+ while ($_message = $this->getAdapter()->getNextServiceMessage()) {
544
+ $this->_setResponse(
545
+ $this->sendMessage(
546
+ $_message['name'],
547
+ $this->getAdapter()->{$_message['data']}()
548
+ )
549
+ );
550
+ $this->_setDebug($this->getLastMessageDebug());
551
+ $this->getAdapter()->{$_message['callback']}();
552
+
553
+ $this->_updateMessageState(Ampersand_Integration_Flag_FlagInterface::TYPE_SUCCESS);
554
+ }
555
+
556
+ return $this;
557
+ }
558
+
559
+ /**
560
+ * Retrieve payment method specific error message for exception.
561
+ *
562
+ * @param Exception $e
563
+ * @return Exception $e
564
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
565
+ */
566
+ protected function _getMethodException(Exception $e)
567
+ {
568
+ $code = (string)$e->getCode();
569
+ if ($code == '0') {
570
+ return false;
571
+ }
572
+
573
+ $errorData = array();
574
+ if ($e instanceof Ampersand_PaymentGateway_Model_Exception_Error) {
575
+ $errorData = $e->getErrorData();
576
+ }
577
+ $message = (string)$this->getMethodInstance()->getErrorMessage($code, $errorData);
578
+ if ($message == '') {
579
+ return false;
580
+ }
581
+
582
+ return new Mage_Core_Exception($message, $code, $e);
583
+ }
584
+
585
+ /**
586
+ * Check existing transactions and increment if the provided ID already exists.
587
+ *
588
+ * @param Mage_Sales_Model_Order_Payment $payment
589
+ * @param string $transactionId
590
+ * @return string
591
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
592
+ */
593
+ protected function _incrementTransactionId(Mage_Sales_Model_Order_Payment $payment, $transactionId)
594
+ {
595
+ if (!$payment->getTransaction($transactionId)) {
596
+ return $transactionId;
597
+ }
598
+
599
+ $_parts = explode('-', $transactionId);
600
+
601
+ if (Mage::helper('ampersand_core/validate')->isInt(end($_parts))) {
602
+ $lastNumber = array_pop($_parts);
603
+ $_parts[] = $lastNumber + 1;
604
+ } else {
605
+ $_parts[] = '1';
606
+ }
607
+
608
+ $transactionId = implode('-', $_parts);
609
+
610
+ return $this->_incrementTransactionId($payment, $transactionId);
611
+ }
612
+
613
+ /**
614
+ * Perform any tasks that must be run before the service messages are processed.
615
+ *
616
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
617
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
618
+ */
619
+ protected function _beforePrepareRegisterRequest()
620
+ {
621
+ $termUrlData = array();
622
+
623
+ $termUrlMessageNames = $this->getAdapter()->getTermUrlData();
624
+ if (is_array($termUrlMessageNames)) {
625
+ foreach ($termUrlMessageNames as $_field => $_messageName) {
626
+ $termUrlData[$_field] = $this->_buildTermUrl($_messageName);
627
+ }
628
+ }
629
+
630
+ $this->_getPayment()->setTermUrlData($termUrlData);
631
+
632
+ return $this;
633
+ }
634
+
635
+ /**
636
+ * If the Payment Gateway requires a redirect to complete the transaction, collect the
637
+ * required information from the adapter and set the redirect URL to the appropriate value.
638
+ *
639
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
640
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
641
+ */
642
+ protected function _processRegisterRedirect()
643
+ {
644
+ return $this;
645
+ }
646
+
647
+ /**
648
+ * For any payment method involving a redirect to a third party we save a reference to
649
+ * retrieve the related payment and order information during the Payment Gateway callback.
650
+ *
651
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
652
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
653
+ */
654
+ protected function _saveTransactionReference()
655
+ {
656
+ $transaction = Mage::getModel('ampersand_paymentgateway/transaction')
657
+ ->setData(array(
658
+ 'service_code' => $this->_serviceCode,
659
+ 'transaction_reference' => $this->getTransactionReference(),
660
+ 'payment_id' => $this->_getPayment()->getId(),
661
+ 'order_id' => $this->_getOrder()->getId(),
662
+ 'transaction_type' => $this->getTransactionType(),
663
+ 'payment_amount' => $this->_getPayment()->getData(self::PAYMENT_OBJECT_FIELD_PAYMENT_AMOUNT),
664
+ 'additional_information' => $this->getAdapter()->getTransactionDataFromRegister(),
665
+ 'subscription_data' => $this->_getSubscriptionHelper()->getSubscriptionData(),
666
+ ))
667
+ ->save();
668
+
669
+ $this->_setTransaction($transaction);
670
+
671
+ return $this;
672
+ }
673
+
674
+ protected function _buildTermUrl($messageName)
675
+ {
676
+ $termUrl = Mage::getUrl(
677
+ 'ampersand_integration' . '/'
678
+ . $this->getServiceCode() . '/'
679
+ . $messageName,
680
+ array(
681
+ '_forced_secure' => true,
682
+ 'transaction_type' => $this->getTransactionType(),
683
+ 'transaction_reference' => $this->getTransactionReference(),
684
+ )
685
+ );
686
+
687
+ return $termUrl;
688
+ }
689
+
690
+ /**
691
+ * Add error flag to message.
692
+ *
693
+ * @param Exception $e
694
+ * @param Ampersand_Integration_Debug_DebugInterface $debug
695
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
696
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
697
+ */
698
+ protected function _updateMessageForFailure(Exception $e,
699
+ Ampersand_Integration_Debug_DebugInterface $debug = null)
700
+ {
701
+ // update the message status
702
+ $this->_updateMessageState(Ampersand_Integration_Flag_FlagInterface::TYPE_CRITICAL);
703
+
704
+ // prepare the flag data
705
+ $flagData = array(
706
+ 'message_id' => $this->getLastMessageId(),
707
+ 'short_text' => $e->getMessage(),
708
+ 'text' => $e->getTraceAsString(),
709
+ 'type' => Ampersand_Integration_Flag_FlagInterface::TYPE_CRITICAL,
710
+ );
711
+
712
+ $lastMessageDebug = $this->getLastMessageDebug();
713
+ if ($lastMessageDebug instanceof Ampersand_Integration_Debug_DebugInterface) {
714
+ $lastMessageDebug->setState(Ampersand_Integration_Flag_FlagInterface::TYPE_CRITICAL);
715
+ $this->createFlag($flagData);
716
+
717
+ /**
718
+ * if a debug was provided, but a message has been processed since with errors,
719
+ * update the original debug for success since it is not the point of failure.
720
+ */
721
+ if (!is_null($debug)) {
722
+ $debug->setState(Ampersand_Integration_Flag_FlagInterface::TYPE_SUCCESS);
723
+ }
724
+ } else if (!is_null($debug)) {
725
+ $debug->setState(Ampersand_Integration_Flag_FlagInterface::TYPE_CRITICAL);
726
+ $flag = new Ampersand_Integration_Flag($flagData);
727
+ $debug->addFlag($flag);
728
+ }
729
+
730
+ return $this;
731
+ }
732
+
733
+ protected function _processRedirect($url, $data)
734
+ {
735
+ $this->_getSession()->addData(array(
736
+ Ampersand_PaymentGateway_Block_Redirect_Form::SESSION_KEY_REDIRECT_URL => $url,
737
+ Ampersand_PaymentGateway_Block_Redirect_Form::SESSION_KEY_REDIRECT_DATA => $data,
738
+ ));
739
+
740
+ if ($this->getAdapter()->getIsUseIframe()) {
741
+ $redirectUrlPath = 'ampersand_paymentgateway/redirect/iframe';
742
+ } else {
743
+ $redirectUrlPath = 'ampersand_paymentgateway/redirect/form';
744
+ }
745
+
746
+ $this->_getHelper()->setRedirectUrl(
747
+ Mage::getUrl($redirectUrlPath, array('_forced_secure' => true))
748
+ );
749
+
750
+ $this->_redirectRequired = true;
751
+
752
+ return $this;
753
+ }
754
+
755
+ /**
756
+ * Link the billing agreement to the current order.
757
+ *
758
+ * @param bool $saveAgreement
759
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
760
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
761
+ */
762
+ protected function _addBillingAgreementToOrder($saveAgreement = false)
763
+ {
764
+ if (!Mage::getModel('ampersand_paymentgateway/versioning')->isBillingAgreementAvailable()) {
765
+ return $this;
766
+ }
767
+
768
+ $billingAgreementId = $this->_getPayment()->getAdditionalInformation('ba_agreement_id');
769
+ if (!$billingAgreementId) {
770
+ return $this;
771
+ }
772
+
773
+ $salesBillingAgreement = Mage::getModel('sales/billing_agreement')
774
+ ->load($billingAgreementId);
775
+
776
+ $order = $this->_getOrder();
777
+
778
+ $order->addRelatedObject($salesBillingAgreement);
779
+
780
+ $salesBillingAgreement->setIsObjectChanged(true);
781
+ $salesBillingAgreement->addOrderRelation($order->getId());
782
+
783
+ /**
784
+ * We need to call getPaymentMethodInstance() to instantiate property
785
+ * Mage_Payment_Model_Billing_AgreementAbstract::_paymentMethodInstance
786
+ * in order for isValid() to succeed in earlier versions of Magento.
787
+ */
788
+ $salesBillingAgreement->getPaymentMethodInstance();
789
+
790
+ if ($saveAgreement) {
791
+ $salesBillingAgreement->save();
792
+ }
793
+
794
+ return $this;
795
+ }
796
+
797
+ /**
798
+ * Update the customer note related to this order.
799
+ *
800
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
801
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
802
+ */
803
+ protected function _prepareCustomerNote()
804
+ {
805
+ $order = $this->_getOrder();
806
+ $noteStack = new Ampersand_Stack();
807
+ if ($defaultNote = $order->getCustomerNote()) {
808
+ $noteStack->addToStack($defaultNote, 'default');
809
+ }
810
+
811
+ // subscription creation notice
812
+ if (Mage::getModel('ampersand_paymentgateway/versioning')->isBillingAgreementAvailable()
813
+ && $this->_getSubscriptionHelper()->getSubscriptionData('active'))
814
+ {
815
+ $message = $this->_getHelper()->__(
816
+ 'A %s subscription will be created for this order.',
817
+ $this->_getSubscriptionHelper()->getSubscriptionData('period')
818
+ );
819
+
820
+ $noteStack->addToStack("<strong>{$message}</strong>", 'subscription');
821
+ }
822
+
823
+ // provide opportunity for third party applications to update
824
+ Mage::dispatchEvent(
825
+ 'ampersand_paymentgateway_prepare_customer_note',
826
+ array(
827
+ 'order' => $order,
828
+ 'note_stack' => $noteStack,
829
+ )
830
+ );
831
+
832
+ // prepare and set the note
833
+ $note = implode('<br /><br />', $noteStack->getStack());
834
+ $order->setCustomerNote($note);
835
+
836
+ return $this;
837
+ }
838
+
839
+ /**
840
+ * Handle the callback from the Payment Gateway. For direct payment methods this might be
841
+ * the 3D Secure response data, and for redirect payment methods this would be the overall
842
+ * success or failure of the transaction.
843
+ *
844
+ * @param Ampersand_Integration_Debug_DebugInterface $debug
845
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
846
+ */
847
+ public function callback(Ampersand_Integration_Debug_DebugInterface $debug)
848
+ {
849
+ try {
850
+ // initialise objects
851
+ $this->_initCallback($debug);
852
+
853
+ // process the callback response and any additional messages
854
+ $this->getAdapter()->processCallbackResponse();
855
+ $this->_processServiceMessages();
856
+
857
+ // update the transaction data and accept the payment
858
+ $this->_updateTransactionAfterCallback();
859
+ $this->_acceptPayment();
860
+
861
+ // update the redirect url from failure page to success page
862
+ $this->_getHelper()->setRedirectUrl($this->_getRedirectSuccessUrl());
863
+
864
+ // update the incoming message for success
865
+ $debug->setState(Ampersand_Integration_Flag_FlagInterface::TYPE_SUCCESS);
866
+
867
+ // create a new billing agreement with the credentials used for this transaction
868
+ $this->_processBillingAgreement();
869
+
870
+ // create a subscription if a valid billing agreement is related to this order
871
+ $this->_createSubscription();
872
+ } catch (Ampersand_PaymentGateway_Model_Exception_DenyPayment $e) {
873
+ // no need to log the exception here, as it is a genuine denied transaction
874
+ // Mage::logException($e);
875
+
876
+ // process the failure redirect URL and error messages
877
+ $this->_processCallbackFailure($e, self::FAILURE_TYPE_DENIED, $debug);
878
+
879
+ // update the transaction data and deny the payment
880
+ $this->_updateTransactionAfterCallback();
881
+ $this->_denyPayment();
882
+
883
+ // re-populate the customers basket
884
+ $this->_getHelper()->reorder($this->_getOrder());
885
+ } catch (Ampersand_PaymentGateway_Model_Exception_Error $e) {
886
+ // something went wrong with the transaction, but we have handled it appropriately
887
+ Mage::logException($e);
888
+
889
+ // process the failure redirect URL and error messages
890
+ $this->_processCallbackFailure($e, self::FAILURE_TYPE_ERROR, $debug);
891
+
892
+ // re-populate the customers basket
893
+ $this->_getHelper()->reorder($this->_getOrder());
894
+ } catch (Exception $e) {
895
+ // something went wrong that we were not expecting
896
+ Mage::logException($e);
897
+
898
+ // process the failure redirect URL and error messages
899
+ $this->_processCallbackFailure($e, self::FAILURE_TYPE_ERROR, $debug);
900
+
901
+ // notify the administrator of this critical issue, since payment could have been taken
902
+ $this->_notifyCriticalError($e, $debug);
903
+
904
+ // re-populate the customers basket
905
+ $this->_getHelper()->reorder($this->_getOrder());
906
+ }
907
+
908
+ // initialize response data
909
+ $responseData = array();
910
+
911
+ // retrieve the callback redirect url
912
+ $redirectUrl = $this->_getHelper()->getRedirectUrl();
913
+ $callbackRedirectUrl = $this->_getCallbackRedirectUrl($redirectUrl);
914
+
915
+ // update the controller to redirect or update the response data
916
+ if ($this->_isSetControllerRedirect()) {
917
+ Mage::helper('ampersand_integration/message')
918
+ ->setControllerRedirectUrl($callbackRedirectUrl);
919
+ } else {
920
+ $responseData['redirect_url'] = $redirectUrl;
921
+ $responseData['callback_redirect_url'] = $callbackRedirectUrl;
922
+ $responseData['exception'] = isset($e) ? $e : self::FAILURE_TYPE_NONE;
923
+ }
924
+
925
+ return $responseData;
926
+ }
927
+
928
+ /**
929
+ * Initialise objects required for payment handling after callback.
930
+ *
931
+ * @param Ampersand_Integration_Debug_DebugInterface $debug
932
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
933
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
934
+ */
935
+ protected function _initCallback(Ampersand_Integration_Debug_DebugInterface $debug)
936
+ {
937
+ $this->setTransactionType(Mage::app()->getRequest()->getParam('transaction_type'));
938
+
939
+ $transactionReference = Mage::app()->getRequest()->getParam('transaction_reference');
940
+ $this->setTransactionReference($transactionReference);
941
+
942
+ $this->_setDebug($debug);
943
+ $response = $debug->getRequestObject();
944
+ $this->_setResponse($response);
945
+
946
+ $transaction = Mage::getModel('ampersand_paymentgateway/transaction')
947
+ ->loadByServiceTransactionReference($this->_serviceCode, $transactionReference);
948
+ $this->_setTransaction($transaction);
949
+ if ($transaction->getTransactionType() != $this->getTransactionType()) {
950
+ throw new Exception($this->_getHelper()
951
+ ->__("Transaction type '{$this->getTransactionType()}' does not match expected '{$transaction->getTransactionType()}'."));
952
+ }
953
+
954
+ $order = Mage::getModel('sales/order')->load($transaction->getOrderId());
955
+ $this->_setOrder($order);
956
+ if (!$order->getId()) {
957
+ throw new Exception($this->_getHelper()
958
+ ->__("Unable to load order for Transaction '{$transactionReference}'"));
959
+ }
960
+
961
+ /**
962
+ * @todo overlap here with Ampersand_PaymentGateway_Model_Method_Xxx::accept() / deny()
963
+ */
964
+ $requiredState = Mage::getModel('ampersand_paymentgateway/versioning')
965
+ ->getPaymentReviewOrderState();
966
+ if ($order->getStatus() !== $requiredState) {
967
+ $comment = $order->addStatusHistoryComment($this->_getHelper()
968
+ ->__('Warning: A payment gateway callback occured for this order.'));
969
+ $comment->save();
970
+
971
+ throw new Exception($this->_getHelper()
972
+ ->__("Only orders with status '{$requiredState}' can be accepted or denied."));
973
+ }
974
+
975
+ $payment = Mage::getModel('sales/order_payment')->load($transaction->getPaymentId());
976
+ $payment->setOrder($order);
977
+ $this->_setPayment($payment);
978
+ if (!$payment->getId()) {
979
+ throw new Exception($this->_getHelper()
980
+ ->__("Unable to load payment for Transaction '{$transactionReference}'"));
981
+ }
982
+ $this->setMethodInstance($payment->getMethodInstance());
983
+
984
+ /**
985
+ * @todo Test if we 'must' save here, or if we can just associate with the order?
986
+ */
987
+ // assign the billing agreement to the order
988
+ $this->_addBillingAgreementToOrder(true);
989
+
990
+ return $this;
991
+ }
992
+
993
+ /**
994
+ * Set the failure redirect and failure error messages.
995
+ *
996
+ * @param Exception $e
997
+ * @param string $type
998
+ * @param Ampersand_Integration_Debug_DebugInterface $debug
999
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
1000
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1001
+ */
1002
+ protected function _processCallbackFailure(Exception $e, $type,
1003
+ Ampersand_Integration_Debug_DebugInterface $debug)
1004
+ {
1005
+ // set the redirect url to the failure page
1006
+ $redirectUrl = $this->_getRedirectFailureUrl($type, $e->getCode());
1007
+ $this->_getHelper()->setRedirectUrl($redirectUrl);
1008
+
1009
+ // set the error message to inform the customer what went wrong
1010
+ $errorMessage = $this->_getHelper()->getErrorMessage($type);
1011
+ if ($methodException = $this->_getMethodException($e)) {
1012
+ $e = $methodException;
1013
+ $errorMessage = $e->getMessage();
1014
+ }
1015
+ $this->_getHelper()->setSessionErrorMessage($errorMessage);
1016
+
1017
+ // save against the transaction in case notification cannot access session
1018
+ $transaction = $this->_getTransaction();
1019
+ if ($transaction instanceof Ampersand_PaymentGateway_Model_Transaction
1020
+ && $transaction->getId()
1021
+ && (string)$transaction->getErrorMessage() == '') {
1022
+ // fully load and save in case this has been altered
1023
+ Mage::getModel('ampersand_paymentgateway/transaction')
1024
+ ->load($transaction->getId())
1025
+ ->setErrorMessage($errorMessage)
1026
+ ->save();
1027
+ }
1028
+
1029
+ // create a flag against the message
1030
+ $this->_updateMessageForFailure($e, $debug);
1031
+
1032
+ return $this;
1033
+ }
1034
+
1035
+ /**
1036
+ * Update the payment transaction with data from the callback.
1037
+ *
1038
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
1039
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1040
+ */
1041
+ protected function _updateTransactionAfterCallback()
1042
+ {
1043
+ $transaction = $this->_getPayment()->getTransaction(
1044
+ $this->getTransactionReference()
1045
+ );
1046
+
1047
+ $transaction
1048
+ ->setIsClosed(false)
1049
+ ->setShouldCloseParentTransaction(false)
1050
+ ->setAdditionalInformation(
1051
+ self::PAYMENT_TRANSACTION_RAW_DETAILS,
1052
+ $this->getAdapter()->getTransactionDataFromCallback()
1053
+ ); // no chain as setTransactionAdditionalInfo() returns null
1054
+
1055
+ $transaction->save();
1056
+
1057
+ return $this;
1058
+ }
1059
+
1060
+ /**
1061
+ * If the transaction was successful in the Payment Gateway, accept the payment in Magento.
1062
+ *
1063
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
1064
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1065
+ */
1066
+ protected function _acceptPayment()
1067
+ {
1068
+ $payment = $this->_getPayment()
1069
+ ->setData(self::PAYMENT_ACCEPT, true);
1070
+
1071
+ if (method_exists($payment, 'accept')) {
1072
+ $payment->accept();
1073
+ } else {
1074
+ Mage::getModel('ampersand_paymentgateway/compatibility_mage_sales_model_order_payment')
1075
+ ->registerPaymentReviewAction($payment, self::PAYMENT_ACCEPT);
1076
+ }
1077
+
1078
+ $order = $this->_getOrder()
1079
+ ->sendNewOrderEmail()
1080
+ ->save();
1081
+
1082
+ /**
1083
+ * We must set the order status (not state) manually here as default status forced in
1084
+ * Mage_Sales_Model_Order_Payment::registerPaymentReviewAction()
1085
+ */
1086
+ $orderStatus = $payment->getMethodInstance()->getConfigData('order_status');
1087
+ if ($orderStatus != '' && $orderStatus != $order->getStatus()) {
1088
+ $order->setStatus($orderStatus);
1089
+ $comment = $order->addStatusHistoryComment($this->_getHelper()
1090
+ ->__("Order status updated."));
1091
+ $comment->save();
1092
+
1093
+ // need to perform this save after the previous one for logical comment history
1094
+ $order->save();
1095
+ }
1096
+
1097
+ return $this;
1098
+ }
1099
+
1100
+ /**
1101
+ * If the transaction failed in the Payment Gateway, deny the payment in Magento.
1102
+ *
1103
+ * Magento will first set the state to PROCESSING before setting the appropriate state for
1104
+ * a denied payment order. See the bottom of Mage_Sales_Model_Order_Invoice::cancel().
1105
+ *
1106
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
1107
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1108
+ */
1109
+ protected function _denyPayment()
1110
+ {
1111
+ $payment = $this->_getPayment()
1112
+ ->setData(self::PAYMENT_DENY, true);
1113
+
1114
+ if (method_exists($payment, 'deny')) {
1115
+ $payment->deny();
1116
+ } else {
1117
+ Mage::getModel('ampersand_paymentgateway/compatibility_mage_sales_model_order_payment')
1118
+ ->registerPaymentReviewAction($payment, self::PAYMENT_DENY);
1119
+ }
1120
+
1121
+ $this->_getOrder()->save();
1122
+
1123
+ return $this;
1124
+ }
1125
+
1126
+ /**
1127
+ * Create or update a billing agreement if applicable.
1128
+ * @todo Need to also save this against transaction reference in case we dont have session.
1129
+ *
1130
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
1131
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1132
+ */
1133
+ protected function _processBillingAgreement()
1134
+ {
1135
+ if (!Mage::getModel('ampersand_paymentgateway/versioning')->isBillingAgreementAvailable()) {
1136
+ return $this;
1137
+ }
1138
+
1139
+ try {
1140
+ if ($this->_getHelper()->getBillingAgreementSelection() !== true) {
1141
+ return $this;
1142
+ }
1143
+
1144
+ $customer = $this->_getCustomer();
1145
+ if (!$customer->getId()) {
1146
+ return $this;
1147
+ }
1148
+
1149
+ if (!$methodCode = $this->getAdapter()->getBillingAgreementMethodCode()) {
1150
+ return $this;
1151
+ }
1152
+
1153
+ /**
1154
+ * @todo this can actually be triggered in Magento:
1155
+ * Mage_Sales_Model_Order_Payment::_createBillingAgreement()
1156
+ */
1157
+ $salesBillingAgreement = Mage::getModel('sales/billing_agreement')
1158
+ ->setMethodCode($methodCode)
1159
+ ->setPayment($this->_getPayment())
1160
+ ->setCustomer($customer)
1161
+ ->setStoreId($this->_getOrder()->getStoreId())
1162
+ ->place();
1163
+
1164
+ $this->_getPayment()->setBillingAgreementObject($salesBillingAgreement);
1165
+ } catch (Exception $e) {
1166
+ Mage::logException($e);
1167
+
1168
+ Mage::getModel('ampersand_paymentgateway/email')
1169
+ ->setTitle('Billing Agreement creation failed.')
1170
+ ->setSummary(__METHOD__)
1171
+ ->addItem('Order ID', $this->_getOrder()->getId())
1172
+ ->sendWarning();
1173
+ }
1174
+
1175
+ return $this;
1176
+ }
1177
+
1178
+ /**
1179
+ * Create a new subscription if applicable.
1180
+ *
1181
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
1182
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1183
+ */
1184
+ protected function _createSubscription()
1185
+ {
1186
+ if (!Mage::getModel('ampersand_paymentgateway/versioning')->isBillingAgreementAvailable()) {
1187
+ return $this;
1188
+ }
1189
+
1190
+ if (!$this->_getSubscriptionHelper()->isActive()) {
1191
+ return $this;
1192
+ }
1193
+
1194
+ // retrieve subscription data from the session or transaction
1195
+ $transaction = $this->_getTransaction();
1196
+ if (!is_null($transaction)) {
1197
+ $subscriptionData = $transaction->getSubscriptionData();
1198
+ } else {
1199
+ $subscriptionData = $this->_getSubscriptionHelper()->getSubscriptionData();
1200
+ }
1201
+ if (!is_array($subscriptionData)) {
1202
+ return $this;
1203
+ }
1204
+
1205
+ // prepare the values we are interested in
1206
+ $active = array_key_exists('active', $subscriptionData)
1207
+ ? $subscriptionData['active'] : false;
1208
+ $period = array_key_exists('period', $subscriptionData)
1209
+ ? $subscriptionData['period'] : '';
1210
+ $remainingUpdates = array_key_exists('remaining_updates', $subscriptionData)
1211
+ ? $subscriptionData['remaining_updates'] : null;
1212
+
1213
+ // nothing to do if subscription not active
1214
+ if ($active !== true) {
1215
+ return $this;
1216
+ }
1217
+
1218
+ $billingAgreement = null;
1219
+ if ($agreementId = $this->_getPayment()->getAdditionalInformation('ba_agreement_id')) {
1220
+ // the billing agreement was used to purchase this order
1221
+ $billingAgreement = Mage::getModel('sales/billing_agreement')->load($agreementId);
1222
+ } else {
1223
+ // the billing agreement was created during the processing of this order
1224
+ $billingAgreement = $this->_getPayment()->getBillingAgreementObject();
1225
+ }
1226
+
1227
+ if (!is_object($billingAgreement) || !$billingAgreement->getId()) {
1228
+ Mage::getModel('ampersand_paymentgateway/email')
1229
+ ->setTitle('Subscription creation failed.')
1230
+ ->setSummary(__METHOD__)
1231
+ ->addItem('Order ID', $this->_getOrder()->getId())
1232
+ ->sendWarning();
1233
+
1234
+ return $this;
1235
+ }
1236
+
1237
+ $order = $this->_getOrder();
1238
+
1239
+ Mage::getModel('ampersand_paymentgateway/subscription')
1240
+ ->addData(array(
1241
+ 'order_id' => $order->getId(),
1242
+ 'agreement_id' => $billingAgreement->getId(),
1243
+ 'method_code' => $billingAgreement->getMethodCode(),
1244
+ 'frequency' => $this->_getSubscriptionHelper()->getSubscriptionFrequency($period),
1245
+ 'frequency_type' => 'days', // @todo hard coded until we need different types
1246
+ 'customer_id' => $order->getCustomerId(),
1247
+ 'is_active' => '1',
1248
+ 'is_reminder_sent' => '0',
1249
+ ))
1250
+ ->setRemainingUpdates($remainingUpdates)
1251
+ ->updateNextOrderDate()
1252
+ ->save();
1253
+
1254
+ return $this;
1255
+ }
1256
+
1257
+ /**
1258
+ * Update an Ampersand Integration message with a success flag.
1259
+ *
1260
+ * @param string $state
1261
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
1262
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1263
+ */
1264
+ protected function _updateMessageState($state)
1265
+ {
1266
+ $lastMessageId = $this->getLastMessageId();
1267
+ if (is_null($lastMessageId)) {
1268
+ return $this;
1269
+ }
1270
+
1271
+ Mage::getModel('ampersand_integration/message')
1272
+ ->load($lastMessageId)
1273
+ ->setState($state)
1274
+ ->save();
1275
+
1276
+ return $this;
1277
+ }
1278
+
1279
+ /**
1280
+ * Send a critical email and raise an Integration flag to alert administrators of this issue.
1281
+ *
1282
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
1283
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1284
+ */
1285
+ protected function _notifyCriticalError(Exception $exception,
1286
+ Ampersand_Integration_Debug_DebugInterface $debug)
1287
+ {
1288
+ // initialize email model
1289
+ $emailModel = Mage::getModel('ampersand_paymentgateway/email');
1290
+
1291
+ // prepare the email data
1292
+ $emailModel
1293
+ ->setTitle(
1294
+ $this->_serviceCode
1295
+ . ' :: Order failure when payment may have already been processed.'
1296
+ )
1297
+ ->setSummary(
1298
+ 'Order processing failed in Magento, '
1299
+ . 'but payment may have already been taken from the customer.'
1300
+ )
1301
+ ->setException($exception)
1302
+ ->addItem('Service Code', $this->_serviceCode)
1303
+ ->addItem('Transaction Reference', $this->_transactionReference);
1304
+
1305
+ // append order information
1306
+ $order = $this->_getOrder();
1307
+ if ($order instanceof Mage_Sales_Model_Order) {
1308
+ $emailModel
1309
+ ->addItem('Order ID', $order->getId())
1310
+ ->addItem('Order Increment ID', $order->getIncrementId())
1311
+ ->addItem(
1312
+ 'Order Link',
1313
+ Mage::getUrl(
1314
+ 'adminhtml/sales_order/view',
1315
+ array('_forced_secure' => true, 'order_id' => $order->getId())
1316
+ )
1317
+ )
1318
+ ->addItem(
1319
+ 'Customer Name',
1320
+ $order->getCustomerFirstname() . ' ' . $order->getCustomerLastname()
1321
+ )
1322
+ ->addItem('Customer Email', $order->getCustomerEmail());
1323
+ } else {
1324
+ $emailModel->addItem('Order Information', 'Unavailable');
1325
+ }
1326
+
1327
+ // send the email
1328
+ $emailModel->sendCritical();
1329
+
1330
+ return $this;
1331
+ }
1332
+
1333
+ /**
1334
+ * Retrieve the callback redirect url.
1335
+ *
1336
+ * @param string $redirectUrl
1337
+ * @return string
1338
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1339
+ */
1340
+ protected function _getCallbackRedirectUrl($redirectUrl)
1341
+ {
1342
+ // we do not always have an adapter at this point
1343
+ try {
1344
+ $adapter = $this->getAdapter();
1345
+ } catch (Exception $e) {
1346
+ // no adapter defined
1347
+ $adapter = null;
1348
+ }
1349
+
1350
+ /**
1351
+ * @todo use iframe or not is a config option for the payment method,
1352
+ * it doesn't actaully belong in the adapter (or service for that matter).
1353
+ */
1354
+
1355
+ // if no adapter, assume they used iFrame so we always get a redirect
1356
+ if (is_null($adapter) || $adapter->getIsUseIframe()) {
1357
+ $callbackRedirectUrl = Mage::getUrl(
1358
+ 'ampersand_paymentgateway/redirect/location',
1359
+ array('_forced_secure' => true)
1360
+ );
1361
+
1362
+ // we have to append this as a query string due to the value being a URL
1363
+ if (strpos($callbackRedirectUrl, '?') !== FALSE) {
1364
+ $callbackRedirectUrl .= '&';
1365
+ } else {
1366
+ $callbackRedirectUrl .= '?';
1367
+ }
1368
+ $callbackRedirectUrl .= 'redirect_url=' . $redirectUrl;
1369
+ } else {
1370
+ $callbackRedirectUrl = $redirectUrl;
1371
+ }
1372
+
1373
+ return $callbackRedirectUrl;
1374
+ }
1375
+
1376
+ /**
1377
+ * Whether to redirect the customer after the payment gateway callback.
1378
+ * If this is set to false, the redirect url will be passed back to the callback message.
1379
+ *
1380
+ * @return bool
1381
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1382
+ */
1383
+ protected function _isSetControllerRedirect()
1384
+ {
1385
+ /**
1386
+ * @todo this has nothing to do with service, should be a payment method option
1387
+ */
1388
+
1389
+ return true;
1390
+ }
1391
+
1392
+ /**
1393
+ * Retrieve the URL for redirecting a failed transaction.
1394
+ *
1395
+ * @return string
1396
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1397
+ */
1398
+ protected function _getRedirectFailureUrl($failureType = self::FAILURE_TYPE_ERROR, $errorCode = null)
1399
+ {
1400
+ return Mage::getUrl(
1401
+ 'ampersand_paymentgateway/checkout_onepage/failure',
1402
+ array(
1403
+ '_forced_secure' => true,
1404
+ )
1405
+ );
1406
+ }
1407
+
1408
+ /**
1409
+ * Retrieve the URL for redirecting a successful transaction.
1410
+ *
1411
+ * @return string
1412
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1413
+ */
1414
+ protected function _getRedirectSuccessUrl()
1415
+ {
1416
+ return Mage::getUrl(
1417
+ 'checkout/onepage/success',
1418
+ array(
1419
+ '_forced_secure' => true,
1420
+ )
1421
+ );
1422
+ }
1423
+
1424
+ /**
1425
+ * Retrieve the last message id, first checking for a valid object from getLastMessageDebug().
1426
+ *
1427
+ * @return string
1428
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1429
+ */
1430
+ public function getLastMessageId()
1431
+ {
1432
+ $lastMessageDebug = $this->getLastMessageDebug();
1433
+ if (!$lastMessageDebug instanceof Ampersand_Integration_Debug_DebugInterface) {
1434
+ return null;
1435
+ }
1436
+
1437
+ return $lastMessageDebug->getMessageId();
1438
+ }
1439
+
1440
+ /**
1441
+ * Set the transaction type.
1442
+ *
1443
+ * @param string $transactionType
1444
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
1445
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1446
+ */
1447
+ public function setTransactionType($transactionType)
1448
+ {
1449
+ if (!in_array($transactionType, $this->_allowedTransactionTypes)) {
1450
+ throw new Exception("Invalid transaction type: {$transactionType}");
1451
+ }
1452
+
1453
+ $this->_transactionType = $transactionType;
1454
+
1455
+ return $this;
1456
+ }
1457
+
1458
+ /**
1459
+ * Retrieve the transaction type.
1460
+ *
1461
+ * @return string
1462
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1463
+ */
1464
+ public function getTransactionType()
1465
+ {
1466
+ return $this->_transactionType;
1467
+ }
1468
+
1469
+ /**
1470
+ * Set the transaction reference.
1471
+ *
1472
+ * @param string $transactionReference
1473
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
1474
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1475
+ */
1476
+ public function setTransactionReference($transactionReference)
1477
+ {
1478
+ if (!$transactionReference) {
1479
+ throw new Exception('Transaction reference not provided.');
1480
+ }
1481
+
1482
+ if ($this->_transactionReference && $transactionReference != $this->_transactionReference) {
1483
+ throw new Exception('Transaction reference already set.');
1484
+ }
1485
+
1486
+ $this->_transactionReference = $transactionReference;
1487
+
1488
+ return $this;
1489
+ }
1490
+
1491
+ /**
1492
+ * Retrieve the transaction reference.
1493
+ *
1494
+ * @return string
1495
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1496
+ */
1497
+ public function getTransactionReference()
1498
+ {
1499
+ if ($this->_transactionReference == '') {
1500
+ throw new Exception('Transaction reference not set.');
1501
+ }
1502
+
1503
+ return $this->_transactionReference;
1504
+ }
1505
+
1506
+ /**
1507
+ * Store the payment method instance against this service so it can be accessed elsewhere.
1508
+ *
1509
+ * @param Mage_Payment_Model_Method_Abstract $payment
1510
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
1511
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1512
+ */
1513
+ public function setMethodInstance(Mage_Payment_Model_Method_Abstract $methodInstance)
1514
+ {
1515
+ if (!$methodInstance instanceof Mage_Payment_Model_Method_Abstract) {
1516
+ throw new Exception('Invalid payment method instance provided.');
1517
+ }
1518
+
1519
+ $this->_methodInstance = $methodInstance;
1520
+
1521
+ return $this;
1522
+ }
1523
+
1524
+ /**
1525
+ * Retrieve the payment method instance stored against this service.
1526
+ *
1527
+ * @return Mage_Payment_Model_Method_Abstract
1528
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1529
+ */
1530
+ public function getMethodInstance()
1531
+ {
1532
+ return $this->_methodInstance;
1533
+ }
1534
+
1535
+ /**
1536
+ * Retrieve the Payment Gateway adapter.
1537
+ *
1538
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1539
+ */
1540
+ public function getAdapter()
1541
+ {
1542
+ $transactionType = $this->getTransactionType();
1543
+ if (empty($transactionType)) {
1544
+ throw new Exception('Transaction type not set.');
1545
+ }
1546
+
1547
+ if (!array_key_exists($transactionType, $this->_adapter)
1548
+ || is_null($this->_adapter[$transactionType]))
1549
+ {
1550
+ $this->_adapter[$transactionType] = $this->_getAdapter($transactionType);
1551
+ if (is_null($this->_adapter[$transactionType])) {
1552
+ throw new Exception("Adapter not found for transaction type '{$transactionType}'.");
1553
+ }
1554
+ }
1555
+
1556
+ return $this->_adapter[$transactionType];
1557
+ }
1558
+
1559
+ /**
1560
+ * Implement this method to retrieve the Payment Gateway adapter with getAdapter().
1561
+ * This adapter must implement Ampersand_PaymentGateway_Model_Adapter_Interface.
1562
+ *
1563
+ * @param string $transactionType
1564
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1565
+ */
1566
+ abstract protected function _getAdapter($transactionType);
1567
+
1568
+ /**
1569
+ * Store the payment object against this service so it can be accessed elsewhere.
1570
+ *
1571
+ * @param Varien_Object $payment
1572
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
1573
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1574
+ */
1575
+ protected function _setPayment(Varien_Object $payment)
1576
+ {
1577
+ $this->_payment = $payment;
1578
+ $this->getAdapter()->setPayment($payment);
1579
+
1580
+ return $this;
1581
+ }
1582
+
1583
+ /**
1584
+ * Retrieve the payment object stored against this service.
1585
+ *
1586
+ * @return Varien_Object
1587
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1588
+ */
1589
+ protected function _getPayment()
1590
+ {
1591
+ return $this->_payment;
1592
+ }
1593
+
1594
+ /**
1595
+ * Store the order object against this service so it can be accessed elsewhere.
1596
+ *
1597
+ * @param Varien_Object $order
1598
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
1599
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1600
+ */
1601
+ protected function _setOrder(Varien_Object $order)
1602
+ {
1603
+ $this->_order = $order;
1604
+ $this->getAdapter()->setOrder($order);
1605
+
1606
+ return $this;
1607
+ }
1608
+
1609
+ /**
1610
+ * Retrieve the order object stored against this service.
1611
+ *
1612
+ * @return Varien_Object
1613
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1614
+ */
1615
+ protected function _getOrder()
1616
+ {
1617
+ return $this->_order;
1618
+ }
1619
+
1620
+ /**
1621
+ * Store the response object against this service so it can be accessed elsewhere.
1622
+ *
1623
+ * @param Varien_Object $order
1624
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
1625
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1626
+ */
1627
+ protected function _setResponse(Varien_Object $response)
1628
+ {
1629
+ $this->_response = $response;
1630
+ $this->getAdapter()->setResponse($response);
1631
+
1632
+ return $this;
1633
+ }
1634
+
1635
+ /**
1636
+ * Retrieve the response object stored against this service.
1637
+ *
1638
+ * @return Varien_Object
1639
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1640
+ */
1641
+ protected function _getResponse()
1642
+ {
1643
+ return $this->_response;
1644
+ }
1645
+
1646
+ /**
1647
+ * Store the reference transaction object against this service so it can be accessed elsewhere.
1648
+ *
1649
+ * @param Ampersand_PaymentGateway_Model_Transaction $transaction
1650
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
1651
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1652
+ */
1653
+ protected function _setTransaction(Ampersand_PaymentGateway_Model_Transaction $transaction)
1654
+ {
1655
+ $this->_transaction = $transaction;
1656
+ $this->getAdapter()->setTransaction($transaction);
1657
+
1658
+ return $this;
1659
+ }
1660
+
1661
+ /**
1662
+ * Retrieve the reference transaction object stored against this service.
1663
+ *
1664
+ * @return Ampersand_PaymentGateway_Model_Transaction
1665
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1666
+ */
1667
+ protected function _getTransaction()
1668
+ {
1669
+ return $this->_transaction;
1670
+ }
1671
+
1672
+ /**
1673
+ * Store the debug object against this service so it can be accessed elsewhere.
1674
+ *
1675
+ * @param Ampersand_Integration_Debug_DebugInterface $debug
1676
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1677
+ */
1678
+ protected function _setDebug(Ampersand_Integration_Debug_DebugInterface $debug)
1679
+ {
1680
+ $this->_debug = $debug;
1681
+ $this->getAdapter()->setDebug($debug);
1682
+ }
1683
+
1684
+ /**
1685
+ * Retrieve the debug object stored against this service.
1686
+ *
1687
+ * @return Ampersand_Integration_Debug_DebugInterface
1688
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1689
+ */
1690
+ protected function _getDebug()
1691
+ {
1692
+ return $this->_debug;
1693
+ }
1694
+
1695
+ /**
1696
+ * Retrieve the current customer.
1697
+ *
1698
+ * @return Mage_Customer_Model_Customer
1699
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1700
+ */
1701
+ protected function _getCustomer()
1702
+ {
1703
+ return Mage::getSingleton('customer/session')->getCustomer();
1704
+ }
1705
+
1706
+ /**
1707
+ * Retrieve the Payment Gateway helper.
1708
+ *
1709
+ * @return Ampersand_PaymentGateway_Helper_Data
1710
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1711
+ */
1712
+ protected function _getHelper()
1713
+ {
1714
+ return Mage::helper('ampersand_paymentgateway/data');
1715
+ }
1716
+
1717
+ /**
1718
+ * Retrieve the Payment Gateway subscription helper.
1719
+ *
1720
+ * @return Ampersand_PaymentGateway_Helper_Subscroiption
1721
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1722
+ */
1723
+ protected function _getSubscriptionHelper()
1724
+ {
1725
+ return Mage::helper('ampersand_paymentgateway/subscription');
1726
+ }
1727
+
1728
+ /**
1729
+ * Retrieve the checkout session.
1730
+ *
1731
+ * @return Mage_Checkout_Model_Session
1732
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
1733
+ */
1734
+ protected function _getSession()
1735
+ {
1736
+ return Mage::getSingleton('checkout/session');
1737
+ }
1738
+ }
app/code/core/Ampersand/PaymentGateway/Model/Service/Direct/AgreementAbstract.php ADDED
@@ -0,0 +1,187 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ abstract class Ampersand_PaymentGateway_Model_Service_Direct_AgreementAbstract
3
+ extends Ampersand_PaymentGateway_Model_Service_DirectAbstract
4
+ {
5
+ /**
6
+ * This method is only ever called from
7
+ * Mage_Sales_Billing_AgreementController::startWizardAction
8
+ *
9
+ * When using the Wizard, this method is called to define the redirect URL that the customer
10
+ * will be sent to in order to create a new billing token.
11
+ *
12
+ * For direct we should redirect to our own controller for collecting card details.
13
+ * For redirect we can forward the customer on to the payment gateway.
14
+ *
15
+ * The end of the process should be a post with the payment_method and token to
16
+ * Mage_Sales_Billing_AgreementController::returnWizardAction
17
+ *
18
+ * @param Mage_Payment_Model_Billing_AgreementAbstract $agreement
19
+ * @return Ampersand_PaymentGateway_Model_Service_Direct_AgreementAbstract
20
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
21
+ */
22
+ public function initBillingAgreementToken(Mage_Payment_Model_Billing_AgreementAbstract $agreement)
23
+ {
24
+ return $this;
25
+
26
+ // $api = $this->_pro->getApi()
27
+ // ->setReturnUrl($agreement->getReturnUrl())
28
+ // ->setCancelUrl($agreement->getCancelUrl())
29
+ // ->setBillingType($this->_pro->getApi()->getBillingAgreementType());
30
+ //
31
+ // $api->callSetCustomerBillingAgreement();
32
+ // $agreement->setRedirectUrl(
33
+ // $this->_pro->getConfig()->getStartBillingAgreementUrl($api->getToken())
34
+ // );
35
+ // return $this;
36
+ }
37
+
38
+ /**
39
+ * Don't really see the point of this method, since placeBillingAgreement() is
40
+ * called immediately afterwards, we might as well put all of our logic in there...
41
+ *
42
+ * @param Mage_Payment_Model_Billing_AgreementAbstract $agreement
43
+ * @return Ampersand_PaymentGateway_Model_Service_Direct_AgreementAbstract
44
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
45
+ */
46
+ public function getBillingAgreementTokenInfo(Mage_Payment_Model_Billing_AgreementAbstract $agreement)
47
+ {
48
+ return $this;
49
+ }
50
+
51
+ /**
52
+ * Create a billing agreement with the payment gateway.
53
+ *
54
+ * @param Mage_Payment_Model_Billing_AgreementAbstract $agreement
55
+ * @return Ampersand_PaymentGateway_Model_Service_Direct_AgreementAbstract
56
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
57
+ */
58
+ public function placeBillingAgreement(Mage_Payment_Model_Billing_AgreementAbstract $agreement)
59
+ {
60
+ $this->_setTransactionType();
61
+ $this->getAdapter()->setPayment($agreement->getPayment());
62
+
63
+ try {
64
+ $this->getAdapter()->prepareBillingAgreementRequest();
65
+ $this->_processServiceMessages();
66
+ $this->_saveBillingAgreement($agreement);
67
+ } catch (Exception $e) {
68
+ // retrieve custom exception message if available
69
+ if ($methodException = $this->_getMethodException($e)) {
70
+ $e = $methodException;
71
+ }
72
+
73
+ // create a flag against the message
74
+ $this->_updateMessageForFailure($e);
75
+
76
+ // re-throw
77
+ throw $e;
78
+ }
79
+
80
+ return $this;
81
+ }
82
+
83
+ /**
84
+ * Cancel a billing agreement.
85
+ *
86
+ * @param Mage_Payment_Model_Billing_AgreementAbstract $agreement
87
+ * @return Ampersand_PaymentGateway_Model_Service_Direct_AgreementAbstract
88
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
89
+ */
90
+ public function cancelBillingAgreement(Mage_Payment_Model_Billing_AgreementAbstract $agreement)
91
+ {
92
+ $this->_setTransactionType();
93
+
94
+ // retrieve the additional information for this agreement
95
+ $ampersandAgreement = Mage::getModel('ampersand_paymentgateway/agreement')
96
+ ->loadByReferenceId($agreement->getMethodCode(), $agreement->getReferenceId());
97
+ $this->getAdapter()->setAgreement($ampersandAgreement);
98
+
99
+ try {
100
+ $this->getAdapter()->prepareBillingAgreementCancel();
101
+ $this->_processServiceMessages();
102
+ } catch (Exception $e) {
103
+ // retrieve custom exception message if available
104
+ if ($methodException = $this->_getMethodException($e)) {
105
+ $e = $methodException;
106
+ }
107
+
108
+ // create a flag against the message
109
+ $this->_updateMessageForFailure($e);
110
+
111
+ // re-throw
112
+ throw $e;
113
+ }
114
+
115
+ return $this;
116
+ }
117
+
118
+ /**
119
+ * Save the billing agreement data for use in future transactions,
120
+ * linked to the Magento billing agreement by a unique reference ID.
121
+ *
122
+ * @param Mage_Payment_Model_Billing_AgreementAbstract $agreement
123
+ * @return Ampersand_PaymentGateway_Model_Service_Direct_AgreementAbstract
124
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
125
+ */
126
+ protected function _saveBillingAgreement(Mage_Payment_Model_Billing_AgreementAbstract $agreement)
127
+ {
128
+ $this->_setTransactionType();
129
+
130
+ $agreement->setBillingAgreementId($this->_generateBillingAgreementId($agreement));
131
+
132
+ Mage::getModel('ampersand_paymentgateway/agreement')
133
+ ->setServiceCode($agreement->getMethodCode())
134
+ ->setReferenceId($agreement->getBillingAgreementId())
135
+ ->setCustomerId($agreement->getCustomer()->getId())
136
+ ->setStoreId($agreement->getStoreId())
137
+ ->setAdditionalInformation($this->getAdapter()->getBillingAgreementCredentials())
138
+ ->setCardType($agreement->getPayment()->getCcType())
139
+ ->setCardLastFour($agreement->getPayment()->getCcLast4())
140
+ ->setCardExpiryMonth(str_pad($agreement->getPayment()->getCcExpMonth(), 2, 0, STR_PAD_LEFT))
141
+ ->setCardExpiryYear($agreement->getPayment()->getCcExpYear())
142
+ ->save();
143
+
144
+ return $this;
145
+ }
146
+
147
+ /**
148
+ * Generate a unique billing agreemend reference for a customer and card combination.
149
+ * The maximum length of the billing agreement ID is 32 characters.
150
+ *
151
+ * @param Mage_Payment_Model_Billing_AgreementAbstract $agreement
152
+ * @return string
153
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
154
+ */
155
+ protected function _generateBillingAgreementId(Mage_Payment_Model_Billing_AgreementAbstract $agreement)
156
+ {
157
+ /**
158
+ * @todo
159
+ * - remove the stars as they are irrelevant
160
+ * - crossover here between direct and redirect.
161
+ * - this should also be available to be used as externally (eg. for Realex) ?
162
+ */
163
+ $payment = $agreement->getPayment();
164
+
165
+ $billingAgreementId = time() . '-';
166
+ $billingAgreementId .= '****' . $payment->getCcLast4() . '-';
167
+ $billingAgreementId .= str_pad($payment->getCcExpMonth(), 2, '0', STR_PAD_LEFT) . '-';
168
+ $billingAgreementId .= $payment->getCcExpYear();
169
+
170
+ return $billingAgreementId;
171
+ }
172
+
173
+ /**
174
+ * Set the current transaction type for creating a new agreement.
175
+ *
176
+ * @return Ampersand_PaymentGateway_Model_Service_Direct_AgreementAbstract
177
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
178
+ */
179
+ public function _setTransactionType()
180
+ {
181
+ $this->setTransactionType(
182
+ Ampersand_PaymentGateway_Model_Service_Abstract::TRANSACTION_TYPE_AGREEMENT_MANAGE
183
+ );
184
+
185
+ return $this;
186
+ }
187
+ }
app/code/core/Ampersand/PaymentGateway/Model/Service/DirectAbstract.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ abstract class Ampersand_PaymentGateway_Model_Service_DirectAbstract
3
+ extends Ampersand_PaymentGateway_Model_Service_Abstract
4
+ {
5
+ /**
6
+ * If the Payment Gateway requires a redirect to complete the transaction, collect the
7
+ * required information from the adapter and set the redirect URL to the appropriate value.
8
+ *
9
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
10
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
11
+ */
12
+ protected function _processRegisterRedirect()
13
+ {
14
+ if (!$this->getAdapter()->isThreedSecureRequired()) {
15
+ return $this;
16
+ }
17
+
18
+ $md = $this->getAdapter()->getMd();
19
+ $acsUrl = $this->getAdapter()->getAcsUrl();
20
+ $pareq = $this->getAdapter()->getPareq();
21
+
22
+ if (!$md || !$acsUrl || !$pareq) {
23
+ throw new Exception($this->_getHelper()
24
+ ->__('Payment failed. Invalid 3D Secure information returned by Gateway.'));
25
+ }
26
+
27
+ // save a transaction reference so we can access the payment upon callback
28
+ $this->_saveTransactionReference();
29
+
30
+ // set the payment to pending in Magento, awaiting an accept or deny response
31
+ $this->_getPayment()->setIsTransactionPending(true);
32
+
33
+ // prepare 3D Secure redirect
34
+ $threedSecureData = array(
35
+ 'MD' => $md,
36
+ 'PaReq' => $pareq,
37
+ 'TermUrl' => $this->_buildTermUrl($this->getAdapter()->getTermUrlMessageName()),
38
+ );
39
+ $this->_processRedirect($acsUrl, $threedSecureData);
40
+
41
+ return $this;
42
+ }
43
+ }
app/code/core/Ampersand/PaymentGateway/Model/Service/Redirect/AgreementAbstract.php ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ abstract class Ampersand_PaymentGateway_Model_Service_Redirect_AgreementAbstract
3
+ extends Ampersand_PaymentGateway_Model_Service_RedirectAbstract
4
+ {
5
+ /**
6
+ * This method is only ever called from
7
+ * Mage_Sales_Billing_AgreementController::startWizardAction
8
+ *
9
+ * When using the Wizard, this method is called to define the redirect URL that the customer
10
+ * will be sent to in order to create a new billing token.
11
+ *
12
+ * For direct we should redirect to our own controller for collecting card details.
13
+ * For redirect we can forward the customer on to the payment gateway.
14
+ *
15
+ * The end of the process should be a post with the payment_method and token to
16
+ * Mage_Sales_Billing_AgreementController::returnWizardAction
17
+ *
18
+ * @param Mage_Payment_Model_Billing_AgreementAbstract $agreement
19
+ * @return Ampersand_PaymentGateway_Model_Service_Redirect_AgreementAbstract
20
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
21
+ */
22
+ public function initBillingAgreementToken(Mage_Payment_Model_Billing_AgreementAbstract $agreement)
23
+ {
24
+ return $this;
25
+
26
+ // $api = $this->_pro->getApi()
27
+ // ->setReturnUrl($agreement->getReturnUrl())
28
+ // ->setCancelUrl($agreement->getCancelUrl())
29
+ // ->setBillingType($this->_pro->getApi()->getBillingAgreementType());
30
+ //
31
+ // $api->callSetCustomerBillingAgreement();
32
+ // $agreement->setRedirectUrl(
33
+ // $this->_pro->getConfig()->getStartBillingAgreementUrl($api->getToken())
34
+ // );
35
+ // return $this;
36
+ }
37
+
38
+ /**
39
+ * Don't really see the point of this method, since placeBillingAgreement() is
40
+ * called immediately afterwards, we might as well put all of our logic in there...
41
+ *
42
+ * @param Mage_Payment_Model_Billing_AgreementAbstract $agreement
43
+ * @return Ampersand_PaymentGateway_Model_Service_Redirect_AgreementAbstract
44
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
45
+ */
46
+ public function getBillingAgreementTokenInfo(Mage_Payment_Model_Billing_AgreementAbstract $agreement)
47
+ {
48
+ return $this;
49
+ }
50
+
51
+ /**
52
+ * Create a billing agreement with the payment gateway.
53
+ *
54
+ * @param Mage_Payment_Model_Billing_AgreementAbstract $agreement
55
+ * @return Ampersand_PaymentGateway_Model_Service_Redirect_AgreementAbstract
56
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
57
+ */
58
+ public function placeBillingAgreement(Mage_Payment_Model_Billing_AgreementAbstract $agreement)
59
+ {
60
+ $this->_setTransactionType();
61
+ $this->getAdapter()->setPayment($agreement->getPayment());
62
+
63
+ try {
64
+ $this->getAdapter()->prepareBillingAgreementRequest();
65
+ $this->_processServiceMessages();
66
+ $this->_saveBillingAgreement($agreement);
67
+ } catch (Exception $e) {
68
+ // retrieve custom exception message if available
69
+ if ($methodException = $this->_getMethodException($e)) {
70
+ $e = $methodException;
71
+ }
72
+
73
+ // create a flag against the message
74
+ $this->_updateMessageForFailure($e);
75
+
76
+ // re-throw
77
+ throw $e;
78
+ }
79
+
80
+ return $this;
81
+ }
82
+
83
+ /**
84
+ * Cancel a billing agreement.
85
+ *
86
+ * @param Mage_Payment_Model_Billing_AgreementAbstract $agreement
87
+ * @return Ampersand_PaymentGateway_Model_Service_Redirect_AgreementAbstract
88
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
89
+ */
90
+ public function cancelBillingAgreement(Mage_Payment_Model_Billing_AgreementAbstract $agreement)
91
+ {
92
+ $this->_setTransactionType();
93
+
94
+ // retrieve the additional information for this agreement
95
+ $ampersandAgreement = Mage::getModel('ampersand_paymentgateway/agreement')
96
+ ->loadByReferenceId($agreement->getMethodCode(), $agreement->getReferenceId());
97
+ $this->getAdapter()->setAgreement($ampersandAgreement);
98
+
99
+ $this->getAdapter()->prepareBillingAgreementCancel();
100
+ $this->_processServiceMessages();
101
+
102
+ return $this;
103
+ }
104
+
105
+ /**
106
+ * Save the billing agreement data for use in future transactions,
107
+ * linked to the Magento billing agreement by a unique reference ID.
108
+ *
109
+ * @param Mage_Payment_Model_Billing_AgreementAbstract $agreement
110
+ * @return Ampersand_PaymentGateway_Model_Service_Redirect_AgreementAbstract
111
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
112
+ */
113
+ protected function _saveBillingAgreement(Mage_Payment_Model_Billing_AgreementAbstract $agreement)
114
+ {
115
+ $this->_setTransactionType();
116
+
117
+ $agreement->setBillingAgreementId($this->_generateBillingAgreementId($agreement));
118
+
119
+ Mage::getModel('ampersand_paymentgateway/agreement')
120
+ ->setServiceCode($agreement->getMethodCode())
121
+ ->setReferenceId($agreement->getBillingAgreementId())
122
+ ->setCustomerId($agreement->getCustomer()->getId())
123
+ ->setStoreId($agreement->getStoreId())
124
+ ->setAdditionalInformation($this->getAdapter()->getBillingAgreementCredentials())
125
+ ->setCardType($agreement->getPayment()->getCcType())
126
+ ->setCardLastFour($agreement->getPayment()->getCcLast4())
127
+ ->setCardExpiryMonth(str_pad($agreement->getPayment()->getCcExpMonth(), 2, 0, STR_PAD_LEFT))
128
+ ->setCardExpiryYear($agreement->getPayment()->getCcExpYear())
129
+ ->save();
130
+
131
+ return $this;
132
+ }
133
+
134
+ /**
135
+ * Generate a unique billing agreemend reference for a customer and card combination.
136
+ * The maximum length of the billing agreement ID is 32 characters.
137
+ *
138
+ * @param Mage_Payment_Model_Billing_AgreementAbstract $agreement
139
+ * @return string
140
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
141
+ */
142
+ protected function _generateBillingAgreementId(Mage_Payment_Model_Billing_AgreementAbstract $agreement)
143
+ {
144
+ /**
145
+ * @todo
146
+ * - remove the stars as they are irrelevant
147
+ * - crossover here between direct and redirect.
148
+ * - this should also be available to be used as externally (eg. for Realex) ?
149
+ */
150
+ $payment = $agreement->getPayment();
151
+
152
+ $billingAgreementId = time() . '-';
153
+ $billingAgreementId .= '****' . $payment->getCcLast4() . '-';
154
+ $billingAgreementId .= str_pad($payment->getCcExpMonth(), 2, '0', STR_PAD_LEFT) . '-';
155
+ $billingAgreementId .= $payment->getCcExpYear();
156
+
157
+ return $billingAgreementId;
158
+ }
159
+
160
+ /**
161
+ * Set the current transaction type for creating a new agreement.
162
+ *
163
+ * @return Ampersand_PaymentGateway_Model_Service_Redirect_AgreementAbstract
164
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
165
+ */
166
+ public function _setTransactionType()
167
+ {
168
+ $this->setTransactionType(
169
+ Ampersand_PaymentGateway_Model_Service_Abstract::TRANSACTION_TYPE_AGREEMENT_MANAGE
170
+ );
171
+
172
+ return $this;
173
+ }
174
+ }
app/code/core/Ampersand/PaymentGateway/Model/Service/RedirectAbstract.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ abstract class Ampersand_PaymentGateway_Model_Service_RedirectAbstract
3
+ extends Ampersand_PaymentGateway_Model_Service_Abstract
4
+ {
5
+ /**
6
+ * If the Payment Gateway requires a redirect to complete the transaction, collect the
7
+ * required information from the adapter and set the redirect URL to the appropriate value.
8
+ *
9
+ * @return Ampersand_PaymentGateway_Model_Service_Abstract
10
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
11
+ */
12
+ protected function _processRegisterRedirect()
13
+ {
14
+ $redirectUrl = $this->getAdapter()->getRedirectUrl();
15
+
16
+ $redirectData = array_merge(
17
+ $this->_transformRedirectData(),
18
+ $this->_getPayment()->getTermUrlData()
19
+ );
20
+ $this->getAdapter()->setTransformedRedirectData($redirectData);
21
+
22
+ if (!$redirectUrl || empty($redirectData)) {
23
+ throw new Exception($this->_getHelper()->__('Insufficient redirect data provided.'));
24
+ }
25
+
26
+ // save a transaction reference so we can access the payment upon callback
27
+ $this->_saveTransactionReference();
28
+
29
+ // set the payment to pending in Magento, awaiting an accept or deny response
30
+ $this->_getPayment()->setIsTransactionPending(true);
31
+
32
+ // prepare redirect to payment gateway
33
+ $this->_processRedirect($redirectUrl, $redirectData);
34
+
35
+ return $this;
36
+ }
37
+
38
+ protected function _transformRedirectData()
39
+ {
40
+ $nodeName = $this->getAdapter()->getTransformRedirectDataNodeName();
41
+ if ($nodeName == '') {
42
+ return array();
43
+ }
44
+
45
+ $messageXml = Mage::getSingleton('ampersand_integration/config')->getTypesXml('outgoing');
46
+
47
+ $mapConfig = new Ampersand_Map_Config();
48
+ $mapConfig->addXml($messageXml)
49
+ ->setNodeToMap($this->getServiceCode() . ':' . $nodeName);
50
+
51
+ $result = Ampersand_Map::map($mapConfig, $this->_getPayment());
52
+ $mappedXml = $result->getOutput();
53
+
54
+ $transformedRedirectData = Ampersand_Render::renderArray($mappedXml);
55
+
56
+ return $transformedRedirectData;
57
+ }
58
+ }
app/code/core/Ampersand/PaymentGateway/Model/Source/AgreementMethod.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Model_Source_AgreementMethod
3
+ {
4
+ /**
5
+ * Allowed billing agreement methods.
6
+ *
7
+ * @var array $_allowedMethods
8
+ */
9
+ protected $_allowedMethods = array();
10
+
11
+ /**
12
+ * Retrieve the options.
13
+ *
14
+ * @return array
15
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
16
+ */
17
+ public function toOptionArray()
18
+ {
19
+ $options = array(
20
+ array(
21
+ 'value' => '',
22
+ 'label' => 'None',
23
+ ),
24
+ );
25
+
26
+ if (!Mage::getModel('ampersand_paymentgateway/versioning')->isBillingAgreementAvailable()) {
27
+ return $options;
28
+ }
29
+
30
+ foreach (Mage::helper('payment')->getAllBillingAgreementMethods() as $_code => $_name) {
31
+ if (empty($this->_allowedMethods)
32
+ || in_array($_code, $this->_allowedMethods)) {
33
+ $options[] = array(
34
+ 'value' => $_code,
35
+ 'label' => $_name
36
+ );
37
+ }
38
+ }
39
+
40
+ return $options;
41
+ }
42
+ }
app/code/core/Ampersand/PaymentGateway/Model/Source/CardType.php ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Model_Source_CardType extends Mage_Payment_Model_Source_Cctype
3
+ {
4
+ /**
5
+ * Gateway supported credit cards.
6
+ * The key : value pairs are Magento Code : Gateway Code.
7
+ *
8
+ * @var array $_supportedCcTypes
9
+ */
10
+ protected $_supportedCcTypes = array(
11
+ 'AE' => 'American Express',
12
+ 'VI' => 'Visa',
13
+ 'MC' => 'MasterCard',
14
+ 'DI' => 'Discover',
15
+ 'SM' => 'Maestro/Switch',
16
+ 'SO' => 'Solo',
17
+ 'JCB' => 'JCB',
18
+ // 'OT' => 'Other',
19
+ Ampersand_PaymentGateway_Model_Method_DirectAbstract::AMPERSAND_CARTES_BANCAIRES => 'Cartes Bancaires',
20
+ Ampersand_PaymentGateway_Model_Method_DirectAbstract::AMPERSAND_MASTERCARD_DEBIT => 'MasterCard Debit',
21
+ Ampersand_PaymentGateway_Model_Method_DirectAbstract::AMPERSAND_VISA_DELTA => 'Visa Delta',
22
+ Ampersand_PaymentGateway_Model_Method_DirectAbstract::AMPERSAND_VISA_ELECTRON => 'Visa Electron',
23
+ Ampersand_PaymentGateway_Model_Method_DirectAbstract::AMPERSAND_VISA_PURCHASING => 'Visa Purchasing',
24
+ Ampersand_PaymentGateway_Model_Method_DirectAbstract::AMPERSAND_LASER => 'Laser',
25
+ Ampersand_PaymentGateway_Model_Method_DirectAbstract::AMPERSAND_DINERS_CLUB => 'Diners Club',
26
+ Ampersand_PaymentGateway_Model_Method_DirectAbstract::AMPERSAND_VPAY => 'V Pay',
27
+ );
28
+
29
+ /**
30
+ * Retrieve the options.
31
+ *
32
+ * @return array
33
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
34
+ */
35
+ public function toOptionArray()
36
+ {
37
+ $this->setAllowedTypes(array_keys($this->getSupportedCardTypes()));
38
+
39
+ return parent::toOptionArray();
40
+ }
41
+
42
+ /**
43
+ * Retrieve supported credit card types.
44
+ *
45
+ * @return array
46
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
47
+ */
48
+ public function getSupportedCardTypes()
49
+ {
50
+ return $this->_supportedCcTypes;
51
+ }
52
+
53
+ /**
54
+ * Retrieve the payment gateway specific card type.
55
+ *
56
+ * @param string $type
57
+ * @return string
58
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
59
+ */
60
+ public function getGatewayCardType($type)
61
+ {
62
+ $supportedCardTypes = $this->getSupportedCardTypes();
63
+
64
+ if (!array_key_exists($type, $supportedCardTypes)) {
65
+ throw new Exception(
66
+ $this->_getHelper()->__("Gateway does not support card type '{$type}'.")
67
+ );
68
+ }
69
+
70
+ return $supportedCardTypes[$type];
71
+ }
72
+
73
+ /**
74
+ * Retrieve friendly name of Magento card types.
75
+ *
76
+ * @param string $type
77
+ * @return string
78
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
79
+ */
80
+ public function getMagentoCardType($type)
81
+ {
82
+ return array_key_exists($type, $this->_supportedCcTypes)
83
+ ? $this->_supportedCcTypes[$type]
84
+ : $type;
85
+ }
86
+
87
+ /**
88
+ * Retrieve the PaymentGateway helper class.
89
+ *
90
+ * @return Ampersand_PaymentGateway_Helper_Data
91
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
92
+ */
93
+ protected function _getHelper()
94
+ {
95
+ return Mage::helper('ampersand_paymentgateway/data');
96
+ }
97
+ }
app/code/core/Ampersand/PaymentGateway/Model/Source/OrderStatus.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Model_Source_OrderStatus
3
+ {
4
+ /**
5
+ * Supported Magento new order statuses.
6
+ *
7
+ * @var array $_stateStatuses
8
+ */
9
+ protected $_stateStatuses = array(
10
+ Mage_Sales_Model_Order::STATE_NEW,
11
+ Mage_Sales_Model_Order::STATE_PROCESSING,
12
+ );
13
+
14
+ /**
15
+ * Retrieve the options.
16
+ *
17
+ * @return array
18
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
19
+ */
20
+ public function toOptionArray()
21
+ {
22
+ $statuses = Mage::getSingleton('sales/order_config')
23
+ ->getStateStatuses($this->_stateStatuses);
24
+
25
+ $options = array();
26
+ foreach ($statuses as $code => $label) {
27
+ $options[] = array(
28
+ 'value' => $code,
29
+ 'label' => $label
30
+ );
31
+ }
32
+
33
+ return $options;
34
+ }
35
+ }
app/code/core/Ampersand/PaymentGateway/Model/Source/PaymentAction.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Model_Source_PaymentAction extends Mage_Payment_Model_Method_Abstract
3
+ {
4
+ /**
5
+ * Allowed payment actions.
6
+ *
7
+ * @var array $_allowedActions
8
+ */
9
+ protected $_allowedActions = array(
10
+ self::ACTION_AUTHORIZE,
11
+ self::ACTION_AUTHORIZE_CAPTURE,
12
+ );
13
+
14
+ /**
15
+ * Available payment actions.
16
+ *
17
+ * @var array $_actions
18
+ */
19
+ protected $_actions = array(
20
+ self::ACTION_AUTHORIZE => 'Authorize Only',
21
+ self::ACTION_AUTHORIZE_CAPTURE => 'Authorize and Capture',
22
+ );
23
+
24
+ /**
25
+ * Retrieve the options.
26
+ *
27
+ * @return array
28
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
29
+ */
30
+ public function toOptionArray()
31
+ {
32
+ $paymentActions = array();
33
+
34
+ foreach ($this->_allowedActions as $_action) {
35
+ if (!array_key_exists($_action, $this->_actions)) {
36
+ continue;
37
+ }
38
+
39
+ $paymentActions[] = array(
40
+ 'value' => $_action,
41
+ 'label' => $this->_getHelper()->__($this->_actions[$_action])
42
+ );
43
+ }
44
+
45
+ return $paymentActions;
46
+ }
47
+
48
+ /**
49
+ * Retrieve the PaymentGateway helper class.
50
+ *
51
+ * @return Ampersand_PaymentGateway_Helper_Data
52
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
53
+ */
54
+ protected function _getHelper()
55
+ {
56
+ return Mage::helper('ampersand_paymentgateway/data');
57
+ }
58
+ }
app/code/core/Ampersand/PaymentGateway/Model/Source/SubscriptionPeriods.php ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Model_Source_SubscriptionPeriods
3
+ extends Mage_Payment_Model_Method_Abstract
4
+ {
5
+ /**
6
+ * Period values.
7
+ */
8
+ const WEEKLY = 'weekly';
9
+ const MONTHLY = 'monthly';
10
+
11
+ /**
12
+ * Available subscription periods.
13
+ *
14
+ * @var array $_periods
15
+ */
16
+ protected $_periods = array(
17
+ self::WEEKLY => 'Weekly',
18
+ self::MONTHLY => 'Monthly',
19
+ );
20
+
21
+ /**
22
+ * Retrieve the options.
23
+ *
24
+ * @return array
25
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
26
+ */
27
+ public function toOptionArray()
28
+ {
29
+ $periods = array();
30
+
31
+ foreach ($this->_periods as $_value => $_label) {
32
+ $periods[] = array(
33
+ 'value' => $_value,
34
+ 'label' => $this->_getHelper()->__($_label)
35
+ );
36
+ }
37
+
38
+ return $periods;
39
+ }
40
+
41
+ /**
42
+ * Retrieve the allowed options.
43
+ *
44
+ * @return array
45
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
46
+ */
47
+ public function getAllowedOptions()
48
+ {
49
+ /**
50
+ * @todo limit this in admin panel
51
+ */
52
+ return array_keys($this->_periods);
53
+ }
54
+
55
+ /**
56
+ * Retrieve the PaymentGateway helper class.
57
+ *
58
+ * @return Ampersand_PaymentGateway_Helper_Data
59
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
60
+ */
61
+ protected function _getHelper()
62
+ {
63
+ return Mage::helper('ampersand_paymentgateway/data');
64
+ }
65
+ }
app/code/core/Ampersand/PaymentGateway/Model/Subscription.php ADDED
@@ -0,0 +1,151 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Model_Subscription extends Mage_Core_Model_Abstract
3
+ {
4
+ /**
5
+ * Effectively infinite value for remaining updates.
6
+ */
7
+ const REMAINING_UPDATES_MAX = 999999999;
8
+
9
+ /**
10
+ * Prefix of model events names
11
+ *
12
+ * @var string
13
+ */
14
+ protected $_eventPrefix = 'ampersand_paymentgateway_subscription';
15
+
16
+ /**
17
+ * Parameter name in event
18
+ *
19
+ * In observe method you can use $observer->getEvent()->getObject() in this case
20
+ *
21
+ * @var string
22
+ */
23
+ protected $_eventObject = 'subscription';
24
+
25
+ /**
26
+ * Initialise model.
27
+ *
28
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
29
+ */
30
+ protected function _construct()
31
+ {
32
+ $this->_init('ampersand_paymentgateway/subscription');
33
+ }
34
+
35
+ /**
36
+ * Set the number of times this subscription can have its nextOrderData generated.
37
+ * If no value is provided, a non-expiring subscription is assumed.
38
+ *
39
+ * @param int $remainingUpdates
40
+ * @return Ampersand_PaymentGateway_Model_Subscription
41
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
42
+ */
43
+ public function setRemainingUpdates($remainingUpdates = null)
44
+ {
45
+ if (is_null($remainingUpdates)) {
46
+ $remainingUpdates = self::REMAINING_UPDATES_MAX;
47
+ }
48
+
49
+ $this->addData(array(
50
+ 'remaining_updates_orig' => $remainingUpdates,
51
+ 'remaining_updates_current' => $remainingUpdates,
52
+ ));
53
+
54
+ return $this;
55
+ }
56
+
57
+ /**
58
+ * Retrieve the number of remaining updates +1 to signify the number of remaining subscriptions.
59
+ *
60
+ * @return int
61
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
62
+ */
63
+ public function getRemainingSubscriptions()
64
+ {
65
+ return $this->getRemainingUpdatesCurrent() + 1;
66
+ }
67
+
68
+ /**
69
+ * Calculate the next order date for this subscription.
70
+ *
71
+ * @return Ampersand_PaymentGateway_Model_Subscription
72
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
73
+ */
74
+ public function updateNextOrderDate()
75
+ {
76
+ $startDate = $this->getStartDate();
77
+ if ($startDate == '') {
78
+ $startDate = date('Y-m-d H:i:s');
79
+ $this->setStartDate($startDate);
80
+ }
81
+
82
+ $nextOrderDate = $this->getNextOrderDate();
83
+ if ($nextOrderDate != '') {
84
+ $startDate = $nextOrderDate;
85
+ }
86
+
87
+ $frequency = $this->getFrequency();
88
+
89
+ $newTimeStamp = strtotime($startDate . " +{$frequency} days");
90
+ $newNextOrderDate = date('Y-m-d H:i:s', $newTimeStamp);
91
+
92
+ $this->setNextOrderDate($newNextOrderDate);
93
+
94
+ /**
95
+ * Note that the number saved as remaining_updates_current is not the same
96
+ * as the number of orders remaining under this subscription. It is the number
97
+ * of times we can call this function, updateNextOrderData(), and therefore
98
+ * the number of remaining orders is actually remaining_updates_current + 1.
99
+ */
100
+ $remainingUpdates = $this->getRemainingUpdatesCurrent() - 1;
101
+ if ($remainingUpdates < 0) {
102
+ $this->setIsActive(0);
103
+ }
104
+ $this->setRemainingUpdatesCurrent($remainingUpdates);
105
+
106
+ return $this;
107
+ }
108
+
109
+ /**
110
+ * Reset relevant fields for calculating order dates.
111
+ *
112
+ * @return Ampersand_PaymentGateway_Model_Subscription
113
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
114
+ */
115
+ public function resetDateCalculationData()
116
+ {
117
+ $this->setStartDate(null);
118
+ $this->setNextOrderDate(null);
119
+ $this->setRemainingUpdatesCurrent($this->getRemainingUpdatesOrig());
120
+
121
+ return $this;
122
+ }
123
+
124
+ /**
125
+ * Cancel the subscription.
126
+ *
127
+ * @return Ampersand_PaymentGateway_Model_Subscription
128
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
129
+ */
130
+ public function cancel()
131
+ {
132
+ $this->setIsActive(false)
133
+ ->save();
134
+
135
+ return $this;
136
+ }
137
+
138
+ /**
139
+ * Skip the next order date.
140
+ *
141
+ * @return Ampersand_PaymentGateway_Model_Subscription
142
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
143
+ */
144
+ public function skipNext()
145
+ {
146
+ $this->updateNextOrderDate()
147
+ ->save();
148
+
149
+ return $this;
150
+ }
151
+ }
app/code/core/Ampersand/PaymentGateway/Model/Subscription/Order.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Model_Subscription_Order extends Mage_Core_Model_Abstract
3
+ {
4
+ /**
5
+ * Prefix of model events names
6
+ *
7
+ * @var string
8
+ */
9
+ protected $_eventPrefix = 'ampersand_paymentgateway_subscription_order';
10
+
11
+ /**
12
+ * Parameter name in event
13
+ *
14
+ * In observe method you can use $observer->getEvent()->getObject() in this case
15
+ *
16
+ * @var string
17
+ */
18
+ protected $_eventObject = 'subscription_order';
19
+
20
+ /**
21
+ * Initialise model.
22
+ *
23
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
24
+ */
25
+ protected function _construct()
26
+ {
27
+ $this->_init('ampersand_paymentgateway/subscription_order');
28
+ }
29
+ }
app/code/core/Ampersand/PaymentGateway/Model/Transaction.php ADDED
@@ -0,0 +1,175 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Model_Transaction extends Mage_Core_Model_Abstract
3
+ {
4
+ /**
5
+ * Initialise model.
6
+ *
7
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
8
+ */
9
+ protected function _construct()
10
+ {
11
+ $this->_init('ampersand_paymentgateway/transaction');
12
+ }
13
+
14
+ /**
15
+ * Load the transaction by service code and reference, ensuring there is only one match.
16
+ *
17
+ * @param string $serviceCode
18
+ * @param string $transactionReference
19
+ * @return Ampersand_PaymentGateway_Model_Transaction
20
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
21
+ */
22
+ public function loadByServiceTransactionReference($serviceCode, $transactionReference)
23
+ {
24
+ $collection = $this->getCollection()
25
+ ->addFieldToFilter('service_code', $serviceCode)
26
+ ->addFieldToFilter('transaction_reference', $transactionReference);
27
+
28
+ if ($collection->count() !== 1) {
29
+ throw new Exception($this->_getHelper()
30
+ ->__("Unable to load transaction for reference '{$transactionReference}'"));
31
+ }
32
+
33
+ $id = $collection->getFirstItem()->getId();
34
+ $this->load($id);
35
+
36
+ return $this;
37
+ }
38
+
39
+ /**
40
+ * Load the transaction by order ID, ensuring there is only one match.
41
+ *
42
+ * @param string $orderId
43
+ * @return Ampersand_PaymentGateway_Model_Transaction
44
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
45
+ */
46
+ public function loadByOrder($orderId)
47
+ {
48
+ $collection = $this->getCollection()
49
+ ->addFieldToFilter('order_id', $orderId);
50
+
51
+ if ($collection->count() !== 1) {
52
+ throw new Exception($this->_getHelper()
53
+ ->__("Unable to load transaction for order ID '{$orderId}'"));
54
+ }
55
+
56
+ $id = $collection->getFirstItem()->getId();
57
+ $this->load($id);
58
+
59
+ return $this;
60
+ }
61
+
62
+ /**
63
+ * Retrieve additional information from the transaction.
64
+ *
65
+ * @param string $key
66
+ * @return string
67
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
68
+ */
69
+ public function getAdditionalInformation($key = null)
70
+ {
71
+ $transactionData = $this->getData('additional_information');
72
+
73
+ if (is_null($key)) {
74
+ return $transactionData;
75
+ }
76
+
77
+ return array_key_exists($key, $transactionData) ? $transactionData[$key] : null;
78
+ }
79
+
80
+ /**
81
+ * Retrieve additional information from the transaction.
82
+ *
83
+ * @param mixed $key
84
+ * @param string $value
85
+ * @return string
86
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
87
+ */
88
+ public function addAdditionalInformation($key, $value = null)
89
+ {
90
+ if (is_array($key)) {
91
+ foreach ($key as $_key => $_value) {
92
+ $this->addAdditionalInformation($_key, $_value);
93
+ }
94
+ }
95
+
96
+ $additionalInformation = $this->getData('additional_information');
97
+ $additionalInformation[$key] = $value;
98
+ $this->setData('additional_information', $additionalInformation);
99
+
100
+ return $this;
101
+ }
102
+
103
+ /**
104
+ * Retrieve additional information from the transaction.
105
+ *
106
+ * @param string $key
107
+ * @return string
108
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
109
+ */
110
+ public function unsAdditionalInformation($key)
111
+ {
112
+ $transactionData = $this->getData('additional_information');
113
+ if (!array_key_exists($key, $transactionData)) {
114
+ return $this;
115
+ }
116
+
117
+ unset($transactionData[$key]);
118
+ $this->setData('additional_information', $transactionData);
119
+
120
+ return $this;
121
+ }
122
+
123
+ /**
124
+ * Serialize any array attribute values.
125
+ *
126
+ * @return Ampersand_PaymentGateway_Model_Transaction
127
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
128
+ */
129
+ protected function _beforeSave()
130
+ {
131
+ $additionalInformation = $this->getData('additional_information');
132
+ if (is_array($additionalInformation)) {
133
+ $this->setData('additional_information', serialize($additionalInformation));
134
+ }
135
+
136
+ $subscriptionData = $this->getData('subscription_data');
137
+ if (is_array($subscriptionData)) {
138
+ $this->setData('subscription_data', serialize($subscriptionData));
139
+ }
140
+
141
+ return parent::_beforeSave();
142
+ }
143
+
144
+ /**
145
+ * Unserialize any array attribute values.
146
+ *
147
+ * @return Ampersand_PaymentGateway_Model_Transaction
148
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
149
+ */
150
+ protected function _afterLoad()
151
+ {
152
+ $additionalInformation = $this->getData('additional_information');
153
+ if ($additionalInformation != '') {
154
+ $this->setData('additional_information', unserialize($additionalInformation));
155
+ }
156
+
157
+ $subscriptionData = $this->getData('subscription_data');
158
+ if ($subscriptionData != '') {
159
+ $this->setData('subscription_data', unserialize($subscriptionData));
160
+ }
161
+
162
+ return parent::_afterLoad();
163
+ }
164
+
165
+ /**
166
+ * Retrieve the helper class.
167
+ *
168
+ * @return Ampersand_PaymentGateway_Helper_Data
169
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
170
+ */
171
+ protected function _getHelper()
172
+ {
173
+ return Mage::helper('ampersand_paymentgateway/data');
174
+ }
175
+ }
app/code/core/Ampersand/PaymentGateway/Model/Utility/Cleanup.php ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Model_Utility_Cleanup
3
+ {
4
+ /**
5
+ * Cancel orders that remain in the payment_review state longer than a defined period of time.
6
+ *
7
+ * @param type $hours
8
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
9
+ */
10
+ public function cancelPaymentReviewOrders($hours)
11
+ {
12
+ if (!Mage::helper('ampersand_core/validate')->isInt($hours) || $hours < 1) {
13
+ Mage::throwException(
14
+ 'A value must be provided for the age, in hours, of orders to cancel.'
15
+ );
16
+ }
17
+
18
+ $reviewState = Mage::getModel('ampersand_paymentgateway/versioning')
19
+ ->getPaymentReviewOrderState();
20
+
21
+ $lastUpdated = date('Y-m-d H:i:s', strtotime("-{$hours} hours"));
22
+ $orderCollection = Mage::getModel('sales/order')->getCollection()
23
+ ->addAttributeToFilter('state', $reviewState)
24
+ ->addAttributeToFilter('updated_at', array('lt' => $lastUpdated))
25
+ ->addAttributeToSort('entity_id', 'ASC');
26
+
27
+ foreach ($orderCollection as $_order) {
28
+ try {
29
+ $_order = Mage::getModel('sales/order')->load($_order->getId());
30
+ if ($_order->getState() != $reviewState) {
31
+ continue;
32
+ }
33
+
34
+ $_payment = $_order->getPayment();
35
+
36
+ if (substr($_payment->getMethod(), 0, 10) != 'ampersand_') {
37
+ continue;
38
+ }
39
+
40
+ $_payment->setData(Ampersand_PaymentGateway_Model_Service_Abstract::PAYMENT_DENY, true);
41
+
42
+ if (method_exists($_payment, 'deny')) {
43
+ $_payment->deny();
44
+ } else {
45
+ Mage::getModel('ampersand_paymentgateway/compatibility_mage_sales_model_order_payment')
46
+ ->registerPaymentReviewAction($_payment, Ampersand_PaymentGateway_Model_Service_Abstract::PAYMENT_DENY);
47
+ }
48
+
49
+ $_order->save();
50
+
51
+ $_comment = $_order->addStatusHistoryComment(
52
+ Mage::helper('ampersand_paymentgateway')->__(
53
+ "Order cancelled as not converted within {$hours} hours."
54
+ )
55
+ );
56
+ $_comment->save();
57
+ } catch (Exception $e) {
58
+ Mage::logException($e);
59
+ }
60
+ }
61
+ }
62
+ }
app/code/core/Ampersand/PaymentGateway/Model/Utility/Subscription.php ADDED
@@ -0,0 +1,348 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Model_Utility_Subscription
3
+ {
4
+ /**
5
+ * Subscription reminder email settings.
6
+ */
7
+ const XML_PATH_REMINDER_EMAIL_TEMPLATE = 'ampersand_paymentgateway/subscription/email_template';
8
+ const XML_PATH_REMINDER_EMAIL_IDENTITY = 'ampersand_paymentgateway/subscription/email_identity';
9
+
10
+ /**
11
+ * Process subscription reminders.
12
+ *
13
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
14
+ */
15
+ public function sendReminders()
16
+ {
17
+ // add ampersand_paymentgateway event area
18
+ Mage::app()->addEventArea('ampersand_paymentgateway');
19
+
20
+ // if billing agreements are not available, we cannot process subscriptions
21
+ if (!Mage::getModel('ampersand_paymentgateway/versioning')->isBillingAgreementAvailable()) {
22
+ return $this;
23
+ }
24
+
25
+ // retrieve a collection of subscription orders ready to be reminded
26
+ $collection = Mage::getModel('ampersand_paymentgateway/subscription')
27
+ ->getCollection()
28
+ ->filterActive()
29
+ ->filterReadyToSendReminder();
30
+
31
+ // turn translation off
32
+ $translate = Mage::getSingleton('core/translate');
33
+ $translate->setTranslateInline(false);
34
+
35
+ // set the template and identity
36
+ $template = Mage::getStoreConfig(self::XML_PATH_REMINDER_EMAIL_TEMPLATE);
37
+ $identity = Mage::getStoreConfig(self::XML_PATH_REMINDER_EMAIL_IDENTITY);
38
+
39
+ // start store emulation process to get the current settings
40
+ $appEmulation = Mage::getSingleton('core/app_emulation');
41
+ $initialEnvironmentInfo = $appEmulation->startEnvironmentEmulation(
42
+ Mage::app()->getStore()->getId()
43
+ );
44
+
45
+ foreach ($collection as $_subscription) {
46
+ try {
47
+ // validate the subscription
48
+ $this->_validateSubscription($_subscription);
49
+
50
+ // retrieve the order which was first used to create the subscription
51
+ $_order = Mage::getModel('sales/order')->load($_subscription->getOrderId());
52
+ $this->_validateOrder($_order);
53
+
54
+ // retrieve the customer
55
+ $_customer = Mage::getModel('customer/customer')
56
+ ->load($_subscription->getCustomerId());
57
+ $this->_validateCustomer($_customer);
58
+
59
+ // retrieve email content
60
+ $emailData = array(
61
+ 'order' => $_order,
62
+ 'customer' => $_customer,
63
+ 'subscription' => $_subscription,
64
+ );
65
+
66
+ // set the design config
67
+ $designConfig = array(
68
+ 'area' => 'frontend',
69
+ 'store' => $_order->getStoreId(),
70
+ );
71
+
72
+ // start store emulation process
73
+ $appEmulation->startEnvironmentEmulation($_order->getStoreId());
74
+
75
+ // send the email
76
+ $emailTemplate = Mage::getModel('core/email_template')
77
+ ->setStoreId($_order->getStoreId())
78
+ ->setDesignConfig($designConfig)
79
+ ->sendTransactional(
80
+ $template,
81
+ $identity,
82
+ $_customer->getEmail(),
83
+ $_customer->getEmail(),
84
+ $emailData
85
+ );
86
+
87
+ // check if the send was successful
88
+ if ($emailTemplate->getSentSuccess() !== true) {
89
+ throw new Exception('Email sending failure.');
90
+ }
91
+
92
+ // update the subscription
93
+ $_subscription->setIsReminderSent('1')->save();
94
+ } catch (Exception $reminderException) {
95
+ // we want to log the exception, but continue processing other subscriptions
96
+ Mage::logException($reminderException);
97
+
98
+ // send a warning email
99
+ try {
100
+ $warningEmail = Mage::getModel('ampersand_paymentgateway/email')
101
+ ->setTitle('Subscription reminder email sending failed.')
102
+ ->setSummary(__METHOD__)
103
+ ->setException($reminderException)
104
+ ->addItem('Subscription ID', $_subscription->getId());
105
+
106
+ // API exceptions sometimes contain additional information
107
+ if ($reminderException instanceof Mage_Api_Exception
108
+ && $reminderException->getCustomMessage())
109
+ {
110
+ $warningEmail->addItem(
111
+ 'Custom Message',
112
+ $reminderException->getCustomMessage()
113
+ );
114
+ }
115
+
116
+ $warningEmail->sendWarning();
117
+ } catch (Exception $emailException) {
118
+ Mage::logException($emailException);
119
+ }
120
+ }
121
+ }
122
+
123
+ // reset translation
124
+ $translate->setTranslateInline(true);
125
+
126
+ // Stop store emulation process
127
+ $appEmulation->stopEnvironmentEmulation($initialEnvironmentInfo);
128
+ }
129
+
130
+ /**
131
+ * Process any subscriptions that are ready to have orders created.
132
+ *
133
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
134
+ */
135
+ public function process()
136
+ {
137
+ // add ampersand_paymentgateway event area
138
+ Mage::app()->addEventArea('ampersand_paymentgateway');
139
+
140
+ // if billing agreements are not available, we cannot process subscriptions
141
+ if (!Mage::getModel('ampersand_paymentgateway/versioning')->isBillingAgreementAvailable()) {
142
+ return $this;
143
+ }
144
+
145
+ // retrieve a collection of subscription orders ready to be processed
146
+ $collection = Mage::getModel('ampersand_paymentgateway/subscription')
147
+ ->getCollection()
148
+ ->filterActive()
149
+ ->filterReadyToProcess();
150
+
151
+ foreach ($collection as $_subscription) {
152
+ try {
153
+ $this->_validateSubscription($_subscription);
154
+
155
+ // retrieve the order which was first used to create the subscription
156
+ $_order = Mage::getModel('sales/order')->load($_subscription->getOrderId());
157
+ $this->_validateOrder($_order);
158
+
159
+ // create the quote based on the order we already have
160
+ $_quoteId = Mage::getModel('ampersand_api/sales_quote')
161
+ ->createFromOrder($_order->getId());
162
+
163
+ // update the quote with our amendments
164
+ $_quote = Mage::getModel('sales/quote')->loadByIdWithoutStore($_quoteId);
165
+
166
+ // prepare the payment data
167
+ $_paymentData = array(
168
+ 'method' => $_subscription->getMethodCode(),
169
+ 'ba_agreement_id' => $_subscription->getAgreementId(),
170
+ 'additional_information' => array(
171
+ Ampersand_PaymentGateway_Model_Method_AgreementAbstract
172
+ ::OBJECT_KEY_IS_SUBSCRIPTION => true,
173
+ ),
174
+ );
175
+ $_quote->getPayment()->importData($_paymentData);
176
+
177
+ // allow external modules to modify the quote before creating the order
178
+ Mage::dispatchEvent(
179
+ 'ampersand_paymentgateway_subscription_order_create_before',
180
+ array(
181
+ 'order' => $_order,
182
+ 'quote' => $_quote,
183
+ 'subscription' => $_subscription,
184
+ )
185
+ );
186
+
187
+ // collect totals and save quote instance to database
188
+ $_quote->setTotalsCollectedFlag(false)->collectTotals()->save();
189
+
190
+ // reset the payment gateway for each subscription order
191
+ Mage::helper('ampersand_paymentgateway')->resetPaymentGateway();
192
+
193
+ // convert the quote to an order
194
+ $_orderData = array(
195
+ 'relation_parent_id' => $_order->getId(),
196
+ 'relation_parent_real_id' => $_order->getIncrementId(),
197
+ );
198
+ $_orderId = Mage::getModel('ampersand_api/sales_quote')
199
+ ->convertToOrder($_quote->getId(), $_orderData);
200
+
201
+ // write the order to the subscription history
202
+ Mage::getModel('ampersand_paymentgateway/subscription_order')
203
+ ->addData(array(
204
+ 'subscription_id' => $_subscription->getId(),
205
+ 'order_id' => $_orderId,
206
+ ))
207
+ ->save();
208
+
209
+ // update the next order date on the subscription we just processed
210
+ Mage::getModel('ampersand_paymentgateway/subscription')
211
+ ->load($_subscription->getId())
212
+ ->updateNextOrderDate()
213
+ ->setIsReminderSent('0')
214
+ ->save();
215
+
216
+ // send order confirmation email as the very last step
217
+ $_newOrder = Mage::getModel('sales/order')->load($_orderId);
218
+ $_newOrder->sendNewOrderEmail();
219
+ } catch (Exception $subscriptionException) {
220
+ // we want to log the exception, but continue processing other subscriptions
221
+ Mage::logException($subscriptionException);
222
+
223
+ // send a warning email
224
+ try {
225
+ $warningEmail = Mage::getModel('ampersand_paymentgateway/email')
226
+ ->setTitle('Subscription order generation failed.')
227
+ ->setSummary(__METHOD__)
228
+ ->setException($subscriptionException)
229
+ ->addItem('Subscription ID', $_subscription->getId());
230
+
231
+ // API exceptions sometimes contain additional information
232
+ if ($subscriptionException instanceof Mage_Api_Exception
233
+ && $subscriptionException->getCustomMessage())
234
+ {
235
+ $warningEmail->addItem(
236
+ 'Custom Message',
237
+ $subscriptionException->getCustomMessage()
238
+ );
239
+ }
240
+
241
+ $warningEmail->sendWarning();
242
+ } catch (Exception $emailException) {
243
+ Mage::logException($emailException);
244
+ }
245
+ }
246
+ }
247
+ }
248
+
249
+ /**
250
+ * Validate customer.
251
+ *
252
+ * @param Mage_Customer_Model_Customer $customer
253
+ * @return Ampersand_PaymentGateway_Model_Utility_Subscription
254
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
255
+ */
256
+ protected function _validateCustomer($customer)
257
+ {
258
+ // validate all required fields
259
+ $requiredFields = array(
260
+ 'entity_id',
261
+ 'email',
262
+ );
263
+ foreach ($requiredFields as $_field) {
264
+ if ($customer->getData($_field) == '') {
265
+ throw new Exception(
266
+ "Invalid data for '{$_field}' of Customer ID: {$customer->getId()}."
267
+ );
268
+ }
269
+ }
270
+
271
+ return $this;
272
+ }
273
+
274
+ /**
275
+ * Validate subscription.
276
+ *
277
+ * @param Ampersand_PaymentGateway_Model_Subscription $subscription
278
+ * @return Ampersand_PaymentGateway_Model_Utility_Subscription
279
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
280
+ */
281
+ protected function _validateSubscription($subscription)
282
+ {
283
+ // validate all required fields
284
+ $requiredFields = array(
285
+ 'entity_id',
286
+ 'order_id',
287
+ 'agreement_id',
288
+ 'method_code',
289
+ 'frequency',
290
+ 'frequency_type',
291
+ 'next_order_date',
292
+ 'is_active',
293
+ 'customer_id',
294
+ 'remaining_updates_orig',
295
+ 'remaining_updates_current',
296
+ );
297
+ foreach ($requiredFields as $_field) {
298
+ if ($subscription->getData($_field) == '') {
299
+ throw new Exception(
300
+ "Invalid data for '{$_field}' of Subscription ID: {$subscription->getId()}."
301
+ );
302
+ }
303
+ }
304
+
305
+ // a date with 1970 indicates something has gone wrong
306
+ $nextOrderDate = $subscription->getNextOrderDate();
307
+ if (substr($nextOrderDate, 0, 4) == '1970') {
308
+ throw new Exception(
309
+ "Invalid next order date: {$nextOrderDate}"
310
+ );
311
+ }
312
+
313
+ // ensure the related billing agreement is active
314
+ $agreementId = $subscription->getAgreementId();
315
+ $agreement = Mage::getModel('sales/billing_agreement')->load($agreementId);
316
+ if ($agreement->getStatus() != Mage_Sales_Model_Billing_Agreement::STATUS_ACTIVE) {
317
+ throw new Exception(
318
+ "Billing agreement does not exist or has been cancelled: {$agreementId}"
319
+ );
320
+ }
321
+
322
+ return $this;
323
+ }
324
+
325
+ /**
326
+ * Validate order.
327
+ *
328
+ * @param Mage_Sales_Model_Order $order
329
+ * @return Ampersand_PaymentGateway_Model_Utility_Subscription
330
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
331
+ */
332
+ protected function _validateOrder($order)
333
+ {
334
+ // validate all required fields
335
+ $requiredFields = array(
336
+ 'entity_id',
337
+ );
338
+ foreach ($requiredFields as $_field) {
339
+ if ($order->getData($_field) == '') {
340
+ throw new Exception(
341
+ "Invalid data for '{$_field}' of Order ID: {$order->getId()}."
342
+ );
343
+ }
344
+ }
345
+
346
+ return $this;
347
+ }
348
+ }
app/code/core/Ampersand/PaymentGateway/Model/Versioning.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Model_Versioning extends Ampersand_Core_Model_Versioning
3
+ {
4
+ public function isBillingAgreementAvailable()
5
+ {
6
+ if (
7
+ $this->compare(Ampersand_Core_Model_Versioning::EDITION_CE, '1.4.1.0')
8
+ || $this->compare(Ampersand_Core_Model_Versioning::EDITION_EE, '1.9.0.0')
9
+ ) {
10
+ return true;
11
+ }
12
+
13
+ return false;
14
+ }
15
+
16
+ public function getPaymentReviewOrderState()
17
+ {
18
+ if (
19
+ $this->compare(Ampersand_Core_Model_Versioning::EDITION_CE, '1.4.1.0')
20
+ || $this->compare(Ampersand_Core_Model_Versioning::EDITION_EE, '1.9.0.0')
21
+ ) {
22
+ return Mage_Sales_Model_Order::STATE_PAYMENT_REVIEW;
23
+ }
24
+
25
+ return Mage_Sales_Model_Order::STATE_HOLDED;
26
+ }
27
+ }
app/code/core/Ampersand/PaymentGateway/changelog.txt ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 24/01/2013 - v0.1.4 - Improved error logging on billing agreement creation failure.
2
+
3
+ 16/01/2013 - v0.1.3 - Moved cron expressions to system configuration.
4
+
5
+ 16/01/2013 - v0.1.2 - Updated Ampersand_PaymentGateway_Block_Payment_Form_BillingAgreement to depend
6
+ on changes from Ampersand_BillingAgreementFix due to billing agreements from
7
+ incorrect methods appearing on the checkout pages.
8
+
9
+ 16/01/2013 - v0.1.1 - Improved integration message logging and flags,
10
+ and added custom error message functionality to all transaction types.
11
+
12
+ 07/01/2013 - v0.1.0 - Initial release.
app/code/core/Ampersand/PaymentGateway/controllers/Adminhtml/Subscription/OrderController.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Adminhtml_Subscription_OrderController
3
+ extends Mage_Adminhtml_Controller_Action
4
+ {
5
+ /**
6
+ * Display the subscription order grid container.
7
+ *
8
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
9
+ */
10
+ public function indexAction()
11
+ {
12
+ if ($this->getRequest()->getQuery('ajax')) {
13
+ $this->_forward('grid');
14
+ return;
15
+ }
16
+
17
+ $this->loadLayout()
18
+ ->_addContent(
19
+ $this->getLayout()->createBlock('ampersand_paymentgateway_admin/subscription_order')
20
+ )
21
+ ->renderLayout();
22
+ }
23
+
24
+ /**
25
+ * Display the subscription order grid for use in AJAX requests.
26
+ *
27
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
28
+ */
29
+ public function gridAction()
30
+ {
31
+ $this->getResponse()->setBody(
32
+ $this->loadLayout()->getLayout()
33
+ ->createBlock('ampersand_paymentgateway_admin/subscription_order_grid')->toHtml()
34
+ );
35
+ }
36
+ }
app/code/core/Ampersand/PaymentGateway/controllers/Adminhtml/SubscriptionController.php ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Adminhtml_SubscriptionController
3
+ extends Mage_Adminhtml_Controller_Action
4
+ {
5
+ /**
6
+ * Only these fields can be directly modified from the admin panel.
7
+ *
8
+ * @var array $_adminEditableFields
9
+ */
10
+ protected $_adminEditableFields = array(
11
+ 'is_active',
12
+ 'next_order_date',
13
+ 'frequency',
14
+ );
15
+
16
+ /**
17
+ * Display the subscription grid container.
18
+ *
19
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
20
+ */
21
+ public function indexAction()
22
+ {
23
+ if ($this->getRequest()->getQuery('ajax')) {
24
+ $this->_forward('grid');
25
+ return;
26
+ }
27
+
28
+ $this->loadLayout()
29
+ ->_addContent(
30
+ $this->getLayout()->createBlock('ampersand_paymentgateway_admin/subscription')
31
+ )
32
+ ->renderLayout();
33
+ }
34
+
35
+ /**
36
+ * Display the subscription grid for use in AJAX requests.
37
+ *
38
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
39
+ */
40
+ public function gridAction()
41
+ {
42
+ $this->getResponse()->setBody(
43
+ $this->loadLayout()
44
+ ->getLayout()
45
+ ->createBlock('ampersand_paymentgateway_admin/subscription_grid')->toHtml()
46
+ );
47
+ }
48
+
49
+ /**
50
+ * Process modifications to the subscription from the admin panel form.
51
+ *
52
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
53
+ */
54
+ public function editAction()
55
+ {
56
+ $subscriptionId = $this->getRequest()->getParam('id', false);
57
+ $subscription = Mage::getModel('ampersand_paymentgateway/subscription')
58
+ ->load($subscriptionId);
59
+
60
+ if (!$subscription->getId()) {
61
+ $this->_getSession()->addError(
62
+ "Unable to load subscription with ID '{$subscriptionId}'."
63
+ );
64
+ $this->_redirect('*/*/index');
65
+ return;
66
+ }
67
+
68
+ if ($postData = $this->getRequest()->getPost('object')) {
69
+ foreach ($postData as $_field => $_value) {
70
+ if (!in_array($_field, $this->_adminEditableFields)) {
71
+ unset($postData[$_field]);
72
+ }
73
+ }
74
+
75
+ $subscription->addData($postData)->save();
76
+ $this->_getSession()->addSuccess('Subscription saved successfully.');
77
+
78
+ if ($this->getRequest()->getParam('continue')) {
79
+ $this->_redirect('*/*/*', array('id' => $subscription->getId(), '_current'=>true));
80
+ return;
81
+ }
82
+
83
+ $this->_redirect('*/*/index');
84
+ }
85
+
86
+ $this->loadLayout()
87
+ ->_addContent(
88
+ $this->getLayout()->createBlock('ampersand_paymentgateway_admin/subscription_edit')
89
+ )
90
+ ->renderLayout();
91
+ }
92
+ }
app/code/core/Ampersand/PaymentGateway/controllers/Checkout/Cart/SubscriptionController.php ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_Checkout_Cart_SubscriptionController
3
+ extends Mage_Core_Controller_Front_Action
4
+ {
5
+ /**
6
+ * Action predispatch.
7
+ *
8
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
9
+ */
10
+ public function preDispatch()
11
+ {
12
+ parent::preDispatch();
13
+
14
+ if (!$this->_getHelper()->isActive()) {
15
+ $this->_redirect('customer/account');
16
+ return;
17
+ }
18
+ }
19
+
20
+ /**
21
+ * Process the customers selections for order subscription.
22
+ *
23
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
24
+ */
25
+ public function postAction()
26
+ {
27
+ $error = false;
28
+
29
+ $request = $this->getRequest();
30
+ if ($this->getRequest()->getPost()) {
31
+ $remove = $request->getPost('remove');
32
+ $period = $request->getPost('period');
33
+ if ($period == 'do_not_subscribe') {
34
+ $remove = '1';
35
+ }
36
+
37
+ if ($remove == '1') {
38
+ $this->_getHelper()->setSubscriptionData(array());
39
+ $this->_addSuccess('Subscription removed successfuly.');
40
+ $this->_redirect('checkout/cart/index');
41
+ return;
42
+ }
43
+
44
+ $allowedPeriods = Mage::getModel('ampersand_paymentgateway/source_subscriptionPeriods')
45
+ ->getAllowedOptions();
46
+ if (!in_array($period, $allowedPeriods)) {
47
+ $error = true;
48
+ $this->_addError('Invalid subscription period selected.');
49
+ }
50
+
51
+ if ($error == false) {
52
+ $this->_getHelper()->setSubscriptionData(array(
53
+ 'active' => true,
54
+ 'period' => $period,
55
+ ));
56
+ $this->_addSuccess('Order subscription selections updated successfuly.');
57
+ }
58
+ } else {
59
+ $this->_addError('Unable to update subscription selections.');
60
+ }
61
+
62
+ $this->_redirect('checkout/cart/index');
63
+ }
64
+
65
+ /**
66
+ * Inform the customer of success.
67
+ *
68
+ * @param string $message
69
+ * @return Ampersand_PaymentGateway_Checkout_Cart_SubscriptionController
70
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
71
+ */
72
+ protected function _addSuccess($message)
73
+ {
74
+ Mage::getSingleton('core/session')->addSuccess($message);
75
+
76
+ return $this;
77
+ }
78
+
79
+ /**
80
+ * Inform the customer of failure.
81
+ *
82
+ * @param string $message
83
+ * @return Ampersand_PaymentGateway_Checkout_Cart_SubscriptionController
84
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
85
+ */
86
+ protected function _addError($message)
87
+ {
88
+ Mage::getSingleton('core/session')->addError($message);
89
+
90
+ return $this;
91
+ }
92
+
93
+ /**
94
+ * Retrieve the subscription helper.
95
+ *
96
+ * @return Ampersand_PaymentGateway_Helper_Subscription
97
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
98
+ */
99
+ protected function _getHelper()
100
+ {
101
+ return Mage::helper('ampersand_paymentgateway/subscription');
102
+ }
103
+ }
app/code/core/Ampersand/PaymentGateway/controllers/Checkout/OnepageController.php ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once('Mage/Checkout/controllers/OnepageController.php');
3
+ class Ampersand_PaymentGateway_Checkout_OnepageController extends Mage_Checkout_OnepageController
4
+ {
5
+ /**
6
+ * States which indicate a successful order.
7
+ *
8
+ * @var array $_orderSuccessStates
9
+ */
10
+ protected $_orderSuccessStates = array(
11
+ Mage_Sales_Model_Order::STATE_PROCESSING,
12
+ Mage_Sales_Model_Order::STATE_COMPLETE,
13
+ );
14
+
15
+ /**
16
+ * Payment Gateways can optionally use this action for a single redirect URL.
17
+ * Success or failure will be determined by the order status, and the customer is forwarded.
18
+ *
19
+ * Note: preferably the payment gateway determines the final URL instead of using this action.
20
+ *
21
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
22
+ */
23
+ public function completeAction()
24
+ {
25
+ /**
26
+ * @todo handle multishipping
27
+ */
28
+
29
+ // set defaults (use null when value matches current context)
30
+ $module = null;
31
+ $controller = null;
32
+ $action = 'failure';
33
+ $params = $this->getRequest()->getParams();
34
+
35
+ // determine whether the last order placed by this customer was successful
36
+ $lastOrderId = $this->getOnepage()->getCheckout()->getLastOrderId();
37
+ $order = Mage::getModel('sales/order')->load($lastOrderId);
38
+ if ($order->getId() && in_array($order->getState(), $this->_orderSuccessStates)) {
39
+ $module = 'checkout';
40
+ $controller = 'onepage';
41
+ $action = 'success';
42
+ }
43
+
44
+ // forward to the provided location
45
+ $this->_forward($action, $controller, $module, $params);
46
+ }
47
+
48
+ /**
49
+ * Customised failure page for when the payment method does not have access
50
+ * to the customers session during the callback notification.
51
+ *
52
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
53
+ */
54
+ public function failureAction()
55
+ {
56
+ // retrieve the last order ID for this customer
57
+ $lastOrderId = $this->getOnepage()->getCheckout()->getLastOrderId();
58
+ if (!$lastOrderId) {
59
+ return parent::failureAction();
60
+ }
61
+
62
+ // retrieve the transaction related to this order
63
+ try {
64
+ $transaction = Mage::getModel('ampersand_paymentgateway/transaction')
65
+ ->loadByOrder($lastOrderId);
66
+ } catch (Exception $e) {
67
+ return parent::failureAction();
68
+ }
69
+
70
+ // initialise the helper
71
+ $helper = Mage::helper('ampersand_paymentgateway/data');
72
+
73
+ // set the error message to display to the customer
74
+ $helper->setSessionErrorMessage($transaction->getErrorMessage());
75
+
76
+ // repopulate the customers basket
77
+ $helper->reorder($lastOrderId);
78
+
79
+ return parent::failureAction();
80
+ }
81
+ }
app/code/core/Ampersand/PaymentGateway/controllers/Customer/Account/SubscriptionController.php ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once('Mage/Customer/controllers/AccountController.php');
3
+ class Ampersand_PaymentGateway_Customer_Account_SubscriptionController
4
+ extends Mage_Customer_AccountController
5
+ {
6
+ /**
7
+ * Action predispatch.
8
+ *
9
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
10
+ */
11
+ public function preDispatch()
12
+ {
13
+ parent::preDispatch();
14
+
15
+ if (!$this->_getHelper()->isActive()) {
16
+ $this->_redirect('customer/account');
17
+ return;
18
+ }
19
+ }
20
+
21
+ /**
22
+ * Display the index page.
23
+ *
24
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
25
+ */
26
+ public function indexAction()
27
+ {
28
+ $this->loadLayout();
29
+ $this->_initLayoutMessages('customer/session');
30
+
31
+ $this->getLayout()->getBlock('head')->setTitle($this->__('My Subscriptions'));
32
+
33
+ if ($block = $this->getLayout()->getBlock('customer.account.link.back')) {
34
+ $block->setRefererUrl($this->_getRefererUrl());
35
+ }
36
+
37
+ $this->renderLayout();
38
+ }
39
+
40
+ /**
41
+ * Cancel the subscription.
42
+ *
43
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
44
+ */
45
+ public function cancelAction()
46
+ {
47
+ if ($subscription = $this->_getSubscription()) {
48
+ $subscription->cancel();
49
+
50
+ $this->_getSession()->addSuccess(
51
+ $this->_getHelper()->__('Subscription cancelled successfully.')
52
+ );
53
+ }
54
+
55
+ $this->_redirect('customer/account/subscriptions');
56
+ }
57
+
58
+ /**
59
+ * Skip the next subscription date.
60
+ *
61
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
62
+ */
63
+ public function skipAction()
64
+ {
65
+ if ($subscription = $this->_getSubscription()) {
66
+ $subscription->skipNext();
67
+
68
+ $this->_getSession()->addSuccess(
69
+ $this->_getHelper()->__('Subscription next order date updated successfully.')
70
+ );
71
+ }
72
+
73
+ $this->_redirect('customer/account/subscriptions');
74
+ }
75
+
76
+ /**
77
+ * Retrieve the current subscription.
78
+ *
79
+ * @return Ampersand_PaymentGateway_Model_Subscription
80
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
81
+ */
82
+ protected function _getSubscription()
83
+ {
84
+ $subscription = false;
85
+
86
+ if ($subscriptionId = $this->getRequest()->getParam('id', false)) {
87
+ $subscription = Mage::getModel('ampersand_paymentgateway/subscription')
88
+ ->load($subscriptionId);
89
+
90
+ // check logged in customer has access to this subscription
91
+ $customerId = $this->_getCustomerId();
92
+ if (!$customerId || $subscription->getCustomerId() != $customerId) {
93
+ $subscription = false;
94
+ }
95
+ }
96
+
97
+ return $subscription;
98
+ }
99
+
100
+ /**
101
+ * Retrieve the logged in customer id.
102
+ *
103
+ * @return int
104
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
105
+ */
106
+ protected function _getCustomerId()
107
+ {
108
+ return Mage::helper('customer')->getCustomer()->getId();
109
+ }
110
+
111
+ /**
112
+ * Retrieve the subscription helper.
113
+ *
114
+ * @return Ampersand_PaymentGateway_Helper_Subscription
115
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
116
+ */
117
+ protected function _getHelper()
118
+ {
119
+ return Mage::helper('ampersand_paymentgateway/subscription');
120
+ }
121
+ }
app/code/core/Ampersand/PaymentGateway/controllers/RedirectController.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_PaymentGateway_RedirectController extends Mage_Core_Controller_Front_Action
3
+ {
4
+ /**
5
+ * Display the form which will be auto-submitted to redirect the customer.
6
+ *
7
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
8
+ */
9
+ public function formAction()
10
+ {
11
+ $this->loadLayout()->renderLayout();
12
+ }
13
+
14
+ /**
15
+ * Display a page with an iframe containing the above formAction() content.
16
+ *
17
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
18
+ */
19
+ public function iframeAction()
20
+ {
21
+ $this->loadLayout()->renderLayout();
22
+ }
23
+
24
+ /**
25
+ * Display a page which will set the top browser window location to a provided URL.
26
+ *
27
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
28
+ */
29
+ public function locationAction()
30
+ {
31
+ Mage::register(
32
+ Ampersand_PaymentGateway_Block_Redirect_Location::REGISTRY_KEY_REDIRECT_URL,
33
+ $this->getRequest()->getParam('redirect_url')
34
+ );
35
+
36
+ $this->loadLayout()->renderLayout();
37
+ }
38
+ }
app/code/core/Ampersand/PaymentGateway/etc/adminhtml.xml ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <config>
3
+ <menu>
4
+ <sales>
5
+ <children>
6
+ <ampersand_paymentgateway_subscriptions translate="title" module="ampersand_paymentgateway">
7
+ <title>Subscriptions</title>
8
+ <sort_order>75</sort_order>
9
+ <depends>
10
+ <module>Ampersand_PaymentGateway</module>
11
+ </depends>
12
+ <children>
13
+ <subscription_manage translate="title" module="ampersand_paymentgateway">
14
+ <title>Manage Subscriptions</title>
15
+ <sort_order>10</sort_order>
16
+ <action>ampersand_paymentgateway_admin/subscription</action>
17
+ </subscription_manage>
18
+ <subscription_orders translate="title" module="ampersand_paymentgateway">
19
+ <title>Subscriptions Orders</title>
20
+ <sort_order>20</sort_order>
21
+ <action>ampersand_paymentgateway_admin/subscription_order</action>
22
+ </subscription_orders>
23
+ </children>
24
+ </ampersand_paymentgateway_subscriptions>
25
+ </children>
26
+ </sales>
27
+ </menu>
28
+ <acl>
29
+ <resources>
30
+ <admin>
31
+ <children>
32
+ <system>
33
+ <children>
34
+ <config>
35
+ <children>
36
+ <ampersand_paymentgateway translate="title" module="ampersand_paymentgateway">
37
+ <title>Payment Gateways</title>
38
+ </ampersand_paymentgateway>
39
+ </children>
40
+ </config>
41
+ </children>
42
+ </system>
43
+ <sales>
44
+ <children>
45
+ <ampersand_paymentgateway_subscriptions translate="title" module="ampersand_paymentgateway">
46
+ <title>Subscriptions</title>
47
+ <sort_order>75</sort_order>
48
+ <children>
49
+ <subscription_manage translate="title" module="ampersand_paymentgateway">
50
+ <title>Manage Subscriptions</title>
51
+ <sort_order>10</sort_order>
52
+ </subscription_manage>
53
+ <subscription_orders translate="title" module="ampersand_paymentgateway">
54
+ <title>Subscriptions Orders</title>
55
+ <sort_order>20</sort_order>
56
+ </subscription_orders>
57
+ </children>
58
+ </ampersand_paymentgateway_subscriptions>
59
+ </children>
60
+ </sales>
61
+ </children>
62
+ </admin>
63
+ </resources>
64
+ </acl>
65
+ </config>
app/code/core/Ampersand/PaymentGateway/etc/config.xml ADDED
@@ -0,0 +1,300 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <config>
3
+ <modules>
4
+ <Ampersand_PaymentGateway>
5
+ <version>0.1.4</version>
6
+ </Ampersand_PaymentGateway>
7
+ </modules>
8
+ <global>
9
+ <blocks>
10
+ <ampersand_paymentgateway>
11
+ <class>Ampersand_PaymentGateway_Block</class>
12
+ </ampersand_paymentgateway>
13
+ <ampersand_paymentgateway_admin>
14
+ <class>Ampersand_PaymentGateway_Block_Adminhtml</class>
15
+ </ampersand_paymentgateway_admin>
16
+ </blocks>
17
+ <helpers>
18
+ <ampersand_paymentgateway>
19
+ <class>Ampersand_PaymentGateway_Helper</class>
20
+ </ampersand_paymentgateway>
21
+ </helpers>
22
+ <models>
23
+ <ampersand_paymentgateway>
24
+ <class>Ampersand_PaymentGateway_Model</class>
25
+ <resourceModel>ampersand_paymentgateway_resource</resourceModel>
26
+ </ampersand_paymentgateway>
27
+ <ampersand_paymentgateway_resource>
28
+ <class>Ampersand_PaymentGateway_Model_Resource</class>
29
+ <entities>
30
+ <agreement><table>ampersand_paymentgateway_agreement</table></agreement>
31
+ <transaction><table>ampersand_paymentgateway_transaction</table></transaction>
32
+ <subscription><table>ampersand_paymentgateway_subscription</table></subscription>
33
+ <subscription_order><table>ampersand_paymentgateway_subscription_order</table></subscription_order>
34
+ </entities>
35
+ </ampersand_paymentgateway_resource>
36
+ </models>
37
+ <resources>
38
+ <ampersand_paymentgateway_setup>
39
+ <setup>
40
+ <module>Ampersand_PaymentGateway</module>
41
+ </setup>
42
+ <connection>
43
+ <use>core_setup</use>
44
+ </connection>
45
+ </ampersand_paymentgateway_setup>
46
+ <ampersand_paymentgateway_write>
47
+ <connection>
48
+ <use>core_write</use>
49
+ </connection>
50
+ </ampersand_paymentgateway_write>
51
+ <ampersand_paymentgateway_read>
52
+ <connection>
53
+ <use>core_read</use>
54
+ </connection>
55
+ </ampersand_paymentgateway_read>
56
+ </resources>
57
+ <events>
58
+ <core_block_abstract_prepare_layout_after>
59
+ <observers>
60
+ <ampersand_paymentgateway>
61
+ <type>singleton</type>
62
+ <class>ampersand_paymentgateway/observer</class>
63
+ <method>updateAvailablePaymentMethods</method>
64
+ </ampersand_paymentgateway>
65
+ </observers>
66
+ </core_block_abstract_prepare_layout_after>
67
+ <payment_form_block_to_html_before>
68
+ <observers>
69
+ <ampersand_paymentgateway>
70
+ <type>singleton</type>
71
+ <class>ampersand_paymentgateway/observer</class>
72
+ <method>appendBillingAgreementForms</method>
73
+ </ampersand_paymentgateway>
74
+ </observers>
75
+ </payment_form_block_to_html_before>
76
+ </events>
77
+ <template>
78
+ <email>
79
+ <ampersand_paymentgateway_notification translate="label" module="ampersand_paymentgateway">
80
+ <label>Payment Gateway Issue Notification</label>
81
+ <file>ampersand_paymentgateway/notification.html</file>
82
+ <type>html</type>
83
+ </ampersand_paymentgateway_notification>
84
+ <ampersand_paymentgateway_subscription_reminder translate="label" module="ampersand_paymentgateway">
85
+ <label>Payment Gateway Subscription Reminder</label>
86
+ <file>ampersand_paymentgateway/subscription_reminder.html</file>
87
+ <type>html</type>
88
+ </ampersand_paymentgateway_subscription_reminder>
89
+ </email>
90
+ </template>
91
+ <payment>
92
+ <cc>
93
+ <types>
94
+ <AMPERSAND_CARTES_BANCAIRES>
95
+ <code>AMPERSAND_CARTES_BANCAIRES</code>
96
+ <name>Cartes Bancaires</name>
97
+ <order>2003</order>
98
+ </AMPERSAND_CARTES_BANCAIRES>
99
+ <AMPERSAND_MASTERCARD_DEBIT>
100
+ <code>AMPERSAND_MASTERCARD_DEBIT</code>
101
+ <name>MasterCard Debit</name>
102
+ <order>2004</order>
103
+ </AMPERSAND_MASTERCARD_DEBIT>
104
+ <AMPERSAND_VISA_DELTA>
105
+ <code>AMPERSAND_VISA_DELTA</code>
106
+ <name>Visa Delta</name>
107
+ <order>2005</order>
108
+ </AMPERSAND_VISA_DELTA>
109
+ <AMPERSAND_VISA_ELECTRON>
110
+ <code>AMPERSAND_VISA_ELECTRON</code>
111
+ <name>Visa Electron</name>
112
+ <order>2006</order>
113
+ </AMPERSAND_VISA_ELECTRON>
114
+ <AMPERSAND_VISA_PURCHASING>
115
+ <code>AMPERSAND_VISA_PURCHASING</code>
116
+ <name>Visa Purchasing</name>
117
+ <order>2007</order>
118
+ </AMPERSAND_VISA_PURCHASING>
119
+ <AMPERSAND_LASER>
120
+ <code>AMPERSAND_LASER</code>
121
+ <name>Laser</name>
122
+ <order>2008</order>
123
+ </AMPERSAND_LASER>
124
+ <AMPERSAND_DINERS_CLUB>
125
+ <code>AMPERSAND_DINERS_CLUB</code>
126
+ <name>Diners Club</name>
127
+ <order>2009</order>
128
+ </AMPERSAND_DINERS_CLUB>
129
+ <AMPERSAND_VPAY>
130
+ <code>AMPERSAND_VPAY</code>
131
+ <name>V Pay</name>
132
+ <order>2010</order>
133
+ </AMPERSAND_VPAY>
134
+ </types>
135
+ </cc>
136
+ </payment>
137
+ <rewrite>
138
+ <ampersand_paymentgateway_customer_account_subscription_cancel>
139
+ <from>#^/?customer/account/subscriptions/action/cancel(.+)#</from>
140
+ <to>/payment-gateway/customer_account_subscription/cancel$1</to>
141
+ </ampersand_paymentgateway_customer_account_subscription_cancel>
142
+ <ampersand_paymentgateway_customer_account_subscription_skip>
143
+ <from>#^/?customer/account/subscriptions/action/skip(.+)#</from>
144
+ <to>/payment-gateway/customer_account_subscription/skip$1</to>
145
+ </ampersand_paymentgateway_customer_account_subscription_skip>
146
+ <ampersand_paymentgateway_customer_account_subscription>
147
+ <from>#^/?customer/account/subscriptions#</from>
148
+ <to>/payment-gateway/customer_account_subscription/index</to>
149
+ </ampersand_paymentgateway_customer_account_subscription>
150
+ </rewrite>
151
+ </global>
152
+ <admin>
153
+ <routers>
154
+ <ampersand_paymentgateway_admin>
155
+ <use>admin</use>
156
+ <args>
157
+ <module>Ampersand_PaymentGateway_Adminhtml</module>
158
+ <frontName>payment-gateway-admin</frontName>
159
+ </args>
160
+ </ampersand_paymentgateway_admin>
161
+ </routers>
162
+ </admin>
163
+ <frontend>
164
+ <routers>
165
+ <ampersand_paymentgateway>
166
+ <use>standard</use>
167
+ <args>
168
+ <module>Ampersand_PaymentGateway</module>
169
+ <frontName>payment-gateway</frontName>
170
+ </args>
171
+ </ampersand_paymentgateway>
172
+ </routers>
173
+ <layout>
174
+ <updates>
175
+ <ampersand_paymentgateway>
176
+ <file>ampersand_paymentgateway.xml</file>
177
+ </ampersand_paymentgateway>
178
+ </updates>
179
+ </layout>
180
+ </frontend>
181
+ <adminhtml>
182
+ <layout>
183
+ <updates>
184
+ <ampersand_paymentgateway>
185
+ <file>ampersand_paymentgateway.xml</file>
186
+ </ampersand_paymentgateway>
187
+ </updates>
188
+ </layout>
189
+ </adminhtml>
190
+ <crontab>
191
+ <jobs>
192
+ <ampersand_paymentgateway_orderCleanup>
193
+ <schedule>
194
+ <config_path>ampersand_paymentgateway/cron_expressions/order_cleanup</config_path>
195
+ </schedule>
196
+ <run>
197
+ <model>ampersand_paymentgateway/cron::orderCleanup</model>
198
+ </run>
199
+ </ampersand_paymentgateway_orderCleanup>
200
+ <ampersand_paymentgateway_processSubscriptions>
201
+ <schedule>
202
+ <config_path>ampersand_paymentgateway/cron_expressions/process_subscriptions</config_path>
203
+ </schedule>
204
+ <run>
205
+ <model>ampersand_paymentgateway/cron::processSubscriptions</model>
206
+ </run>
207
+ </ampersand_paymentgateway_processSubscriptions>
208
+ <ampersand_paymentgateway_processSubscriptionReminders>
209
+ <schedule>
210
+ <config_path>ampersand_paymentgateway/cron_expressions/process_subscription_reminders</config_path>
211
+ </schedule>
212
+ <run>
213
+ <model>ampersand_paymentgateway/cron::processSubscriptionReminders</model>
214
+ </run>
215
+ </ampersand_paymentgateway_processSubscriptionReminders>
216
+ </jobs>
217
+ </crontab>
218
+ <default>
219
+ <ampersand_paymentgateway>
220
+ <notification>
221
+ <email_identity>general</email_identity>
222
+ <email_template>ampersand_paymentgateway_notification</email_template>
223
+ </notification>
224
+ <cleanup>
225
+ <active>1</active>
226
+ <order_timeframe>24</order_timeframe>
227
+ </cleanup>
228
+ <subscription>
229
+ <active>0</active>
230
+ <frequency_weekly>7</frequency_weekly>
231
+ <frequency_monthly>28</frequency_monthly>
232
+ <lead_time>0</lead_time>
233
+ <reminder_time>1</reminder_time>
234
+ <email_identity>general</email_identity>
235
+ <email_template>ampersand_paymentgateway_subscription_reminder</email_template>
236
+ </subscription>
237
+ <cron_expressions>
238
+ <order_cleanup>*/5 * * * *</order_cleanup>
239
+ <process_subscriptions>30 * * * *</process_subscriptions>
240
+ <process_subscription_reminders>* 4 * * *</process_subscription_reminders>
241
+ </cron_expressions>
242
+ </ampersand_paymentgateway>
243
+ </default>
244
+ <ampersand_paymentgateway>
245
+ <events>
246
+
247
+ <!-- START: Mage_Downloadable frontend -->
248
+ <sales_order_item_save_commit_after>
249
+ <observers>
250
+ <downloadable_observer>
251
+ <class>downloadable/observer</class>
252
+ <method>saveDownloadableOrderItem</method>
253
+ </downloadable_observer>
254
+ </observers>
255
+ </sales_order_item_save_commit_after>
256
+ <sales_order_save_commit_after>
257
+ <observers>
258
+ <downloadable_observer>
259
+ <class>downloadable/observer</class>
260
+ <method>setLinkStatus</method>
261
+ </downloadable_observer>
262
+ </observers>
263
+ </sales_order_save_commit_after>
264
+ <checkout_type_onepage_save_order_after>
265
+ <observers>
266
+ <checkout_type_onepage_save_order_after>
267
+ <class>downloadable/observer</class>
268
+ <method>setHasDownloadableProducts</method>
269
+ </checkout_type_onepage_save_order_after>
270
+ </observers>
271
+ </checkout_type_onepage_save_order_after>
272
+ <checkout_type_multishipping_create_orders_single>
273
+ <observers>
274
+ <checkout_type_multishipping_create_orders_single>
275
+ <class>downloadable/observer</class>
276
+ <method>setHasDownloadableProducts</method>
277
+ </checkout_type_multishipping_create_orders_single>
278
+ </observers>
279
+ </checkout_type_multishipping_create_orders_single>
280
+ <checkout_allow_guest>
281
+ <observers>
282
+ <checkout_allow_guest>
283
+ <class>downloadable/observer</class>
284
+ <method>isAllowedGuestCheckout</method>
285
+ </checkout_allow_guest>
286
+ </observers>
287
+ </checkout_allow_guest>
288
+ <product_option_renderer_init>
289
+ <observers>
290
+ <downloadable_observer>
291
+ <class>downloadable/observer</class>
292
+ <method>initOptionRenderer</method>
293
+ </downloadable_observer>
294
+ </observers>
295
+ </product_option_renderer_init>
296
+ <!-- END: Mage_Downloadable frontend -->
297
+
298
+ </events>
299
+ </ampersand_paymentgateway>
300
+ </config>
app/code/core/Ampersand/PaymentGateway/etc/system.xml ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <config>
3
+ <sections>
4
+ <payment>
5
+ <groups>
6
+ <ampersand_paymentgateway_hint>
7
+ <frontend_model>ampersand_paymentgateway/adminhtml_system_config_fieldset_hint</frontend_model>
8
+ <sort_order>9999</sort_order>
9
+ <show_in_default>1</show_in_default>
10
+ <show_in_website>1</show_in_website>
11
+ <show_in_store>1</show_in_store>
12
+ </ampersand_paymentgateway_hint>
13
+ </groups>
14
+ </payment>
15
+ <ampersand_paymentgateway translate="label" module="ampersand_paymentgateway">
16
+ <label>Payment Gateways</label>
17
+ <tab>ampersand_commerce</tab>
18
+ <frontend_type>text</frontend_type>
19
+ <sort_order>150</sort_order>
20
+ <show_in_default>1</show_in_default>
21
+ <show_in_website>1</show_in_website>
22
+ <show_in_store>1</show_in_store>
23
+ <groups>
24
+ <notification translate="label" module="ampersand_paymentgateway">
25
+ <label>Issue Notification</label>
26
+ <comment>Please enter comma seperated email addresses to be contacted in each of the scenarios relating to payment gateways. eg. &lt;em&gt;foo@bar.com, joe@bloggs.co.uk, etc.&lt;/em&gt;</comment>
27
+ <sort_order>10</sort_order>
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
+ <fields>
32
+ <email_identity translate="label">
33
+ <label>Email Sender</label>
34
+ <frontend_type>select</frontend_type>
35
+ <source_model>adminhtml/system_config_source_email_identity</source_model>
36
+ <sort_order>10</sort_order>
37
+ <show_in_default>1</show_in_default>
38
+ <show_in_website>1</show_in_website>
39
+ <show_in_store>0</show_in_store>
40
+ </email_identity>
41
+ <critical translate="label">
42
+ <label>Critical Issues</label>
43
+ <frontend_type>text</frontend_type>
44
+ <sort_order>20</sort_order>
45
+ <show_in_default>1</show_in_default>
46
+ <show_in_website>1</show_in_website>
47
+ <show_in_store>0</show_in_store>
48
+ <comment>eg. Magento encountered a problem when payment might have been already taken from customer.</comment>
49
+ </critical>
50
+ <warning translate="label">
51
+ <label>Warning Issues</label>
52
+ <frontend_type>text</frontend_type>
53
+ <sort_order>30</sort_order>
54
+ <show_in_default>1</show_in_default>
55
+ <show_in_website>1</show_in_website>
56
+ <show_in_store>0</show_in_store>
57
+ <comment>eg. The generation of a subscription order failed.</comment>
58
+ </warning>
59
+ </fields>
60
+ </notification>
61
+ <cleanup translate="label" module="ampersand_paymentgateway">
62
+ <label>Cleanup Tasks</label>
63
+ <sort_order>20</sort_order>
64
+ <show_in_default>1</show_in_default>
65
+ <show_in_website>0</show_in_website>
66
+ <show_in_store>0</show_in_store>
67
+ <fields>
68
+ <active translate="label">
69
+ <label>Enabled</label>
70
+ <frontend_type>select</frontend_type>
71
+ <source_model>adminhtml/system_config_source_yesno</source_model>
72
+ <sort_order>10</sort_order>
73
+ <show_in_default>1</show_in_default>
74
+ <show_in_website>1</show_in_website>
75
+ <show_in_store>0</show_in_store>
76
+ </active>
77
+ <order_timeframe translate="label">
78
+ <label>Order Timeframe</label>
79
+ <frontend_type>text</frontend_type>
80
+ <sort_order>20</sort_order>
81
+ <show_in_default>1</show_in_default>
82
+ <show_in_website>0</show_in_website>
83
+ <show_in_store>0</show_in_store>
84
+ <comment>This is the amount of time, in hours, to allow an order to be in the payment_review/on_hold state, before it is automatically cancelled.</comment>
85
+ </order_timeframe>
86
+ </fields>
87
+ </cleanup>
88
+ <subscription translate="label" module="ampersand_paymentgateway">
89
+ <label>Subscriptions</label>
90
+ <sort_order>30</sort_order>
91
+ <show_in_default>1</show_in_default>
92
+ <show_in_website>1</show_in_website>
93
+ <show_in_store>0</show_in_store>
94
+ <fields>
95
+ <active translate="label">
96
+ <label>Enabled</label>
97
+ <frontend_type>select</frontend_type>
98
+ <source_model>adminhtml/system_config_source_yesno</source_model>
99
+ <sort_order>10</sort_order>
100
+ <show_in_default>1</show_in_default>
101
+ <show_in_website>1</show_in_website>
102
+ <show_in_store>0</show_in_store>
103
+ </active>
104
+ <frequency_weekly translate="label">
105
+ <label>Days in a Week</label>
106
+ <frontend_type>text</frontend_type>
107
+ <sort_order>20</sort_order>
108
+ <show_in_default>1</show_in_default>
109
+ <show_in_website>1</show_in_website>
110
+ <show_in_store>0</show_in_store>
111
+ </frequency_weekly>
112
+ <frequency_monthly translate="label">
113
+ <label>Days in a Month</label>
114
+ <frontend_type>text</frontend_type>
115
+ <sort_order>30</sort_order>
116
+ <show_in_default>1</show_in_default>
117
+ <show_in_website>1</show_in_website>
118
+ <show_in_store>0</show_in_store>
119
+ </frequency_monthly>
120
+ <lead_time translate="label">
121
+ <label>Lead Time</label>
122
+ <frontend_type>text</frontend_type>
123
+ <sort_order>40</sort_order>
124
+ <show_in_default>1</show_in_default>
125
+ <show_in_website>1</show_in_website>
126
+ <show_in_store>0</show_in_store>
127
+ <comment>The number of days before each subscription date to process the subscription order.</comment>
128
+ </lead_time>
129
+ <email_identity translate="label">
130
+ <label>Reminder Email Sender</label>
131
+ <frontend_type>select</frontend_type>
132
+ <source_model>adminhtml/system_config_source_email_identity</source_model>
133
+ <sort_order>50</sort_order>
134
+ <show_in_default>1</show_in_default>
135
+ <show_in_website>1</show_in_website>
136
+ <show_in_store>0</show_in_store>
137
+ </email_identity>
138
+ <reminder_time translate="label">
139
+ <label>Reminder Time</label>
140
+ <frontend_type>text</frontend_type>
141
+ <sort_order>60</sort_order>
142
+ <show_in_default>1</show_in_default>
143
+ <show_in_website>1</show_in_website>
144
+ <show_in_store>0</show_in_store>
145
+ <comment>The number of days before each subscription date to remind the customer of the subscription order.</comment>
146
+ </reminder_time>
147
+ </fields>
148
+ </subscription>
149
+ <cron_expressions translate="label comment">
150
+ <label>Cron Expressions</label>
151
+ <frontend_type>text</frontend_type>
152
+ <sort_order>40</sort_order>
153
+ <show_in_default>1</show_in_default>
154
+ <show_in_website>0</show_in_website>
155
+ <show_in_store>0</show_in_store>
156
+ <comment><![CDATA[<strong>These are advanced settings - do not modify unless you fully understand cron expressions.</strong>]]></comment>
157
+ <fields>
158
+ <order_cleanup translate="label">
159
+ <label>Order Cleanup</label>
160
+ <sort_order>10</sort_order>
161
+ <show_in_default>1</show_in_default>
162
+ <show_in_website>0</show_in_website>
163
+ <show_in_store>0</show_in_store>
164
+ </order_cleanup>
165
+ <process_subscriptions translate="label">
166
+ <label>Process Subscriptions</label>
167
+ <sort_order>20</sort_order>
168
+ <show_in_default>1</show_in_default>
169
+ <show_in_website>0</show_in_website>
170
+ <show_in_store>0</show_in_store>
171
+ </process_subscriptions>
172
+ <process_subscription_reminders translate="label">
173
+ <label>Process Subscription Reminders</label>
174
+ <sort_order>30</sort_order>
175
+ <show_in_default>1</show_in_default>
176
+ <show_in_website>0</show_in_website>
177
+ <show_in_store>0</show_in_store>
178
+ </process_subscription_reminders>
179
+ </fields>
180
+ </cron_expressions>
181
+ </groups>
182
+ </ampersand_paymentgateway>
183
+ </sections>
184
+ </config>
app/code/core/Ampersand/PaymentGateway/sql/ampersand_paymentgateway_setup/mysql4-install-0.0.1.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $this->startSetup();
3
+
4
+ $this->run("
5
+ CREATE TABLE `{$this->getTable('ampersand_paymentgateway/transaction')}` (
6
+ `entity_id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
7
+ `created_at` DATETIME NOT NULL,
8
+ `updated_at` DATETIME NOT NULL,
9
+ `service_code` VARCHAR(255) NOT NULL,
10
+ `transaction_reference` VARCHAR(255) NOT NULL,
11
+ `payment_id` INT(10) NOT NULL,
12
+ `order_id` INT(10) NOT NULL,
13
+ PRIMARY KEY (`entity_id`),
14
+ UNIQUE KEY (`service_code`, `transaction_reference`),
15
+ INDEX (`transaction_reference`),
16
+ INDEX (`payment_id`),
17
+ INDEX (`order_id`)
18
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
19
+ ");
20
+
21
+ $this->endSetup();
app/code/core/Ampersand/PaymentGateway/sql/ampersand_paymentgateway_setup/mysql4-upgrade-0.0.1-0.0.2.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $this->startSetup();
3
+
4
+ $this->run("
5
+ ALTER TABLE `{$this->getTable('ampersand_paymentgateway/transaction')}`
6
+ ADD `additional_information` TEXT NULL;
7
+ ");
8
+
9
+ $this->endSetup();
app/code/core/Ampersand/PaymentGateway/sql/ampersand_paymentgateway_setup/mysql4-upgrade-0.0.10-0.0.11.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $this->startSetup();
3
+
4
+ $this->run("
5
+ ALTER TABLE `{$this->getTable('ampersand_paymentgateway/transaction')}`
6
+ ADD `subscription_data` TEXT NULL;
7
+ ");
8
+
9
+ $this->endSetup();
app/code/core/Ampersand/PaymentGateway/sql/ampersand_paymentgateway_setup/mysql4-upgrade-0.0.11-0.0.12.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $this->startSetup();
3
+
4
+ $this->run("
5
+ ALTER TABLE `{$this->getTable('ampersand_paymentgateway/subscription')}`
6
+ ADD `remaining_updates_orig` INT(10) DEFAULT NULL,
7
+ ADD `remaining_updates_current` INT(10) DEFAULT NULL;
8
+ ");
9
+
10
+ $this->endSetup();
app/code/core/Ampersand/PaymentGateway/sql/ampersand_paymentgateway_setup/mysql4-upgrade-0.0.12-0.0.13.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $this->startSetup();
3
+
4
+ $this->run("
5
+ ALTER TABLE `{$this->getTable('ampersand_paymentgateway/subscription')}`
6
+ ADD `is_reminder_sent` TINYINT(1) DEFAULT '0';
7
+ ");
8
+
9
+ $this->endSetup();
app/code/core/Ampersand/PaymentGateway/sql/ampersand_paymentgateway_setup/mysql4-upgrade-0.0.13-0.0.14.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $this->startSetup();
3
+
4
+ $this->run("
5
+ ALTER TABLE `{$this->getTable('ampersand_paymentgateway/transaction')}`
6
+ ADD `error_message` TEXT NULL;
7
+ ");
8
+
9
+ $this->endSetup();
app/code/core/Ampersand/PaymentGateway/sql/ampersand_paymentgateway_setup/mysql4-upgrade-0.0.2-0.0.3.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $this->startSetup();
3
+
4
+ $this->run("
5
+ ALTER TABLE `{$this->getTable('ampersand_paymentgateway/transaction')}`
6
+ ADD `transaction_type` VARCHAR(20) NULL;
7
+ ");
8
+
9
+ $this->endSetup();
app/code/core/Ampersand/PaymentGateway/sql/ampersand_paymentgateway_setup/mysql4-upgrade-0.0.3-0.0.4.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $this->startSetup();
3
+
4
+ $this->run("
5
+ CREATE TABLE `{$this->getTable('ampersand_paymentgateway/agreement')}` (
6
+ `entity_id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
7
+ `created_at` DATETIME NOT NULL,
8
+ `updated_at` DATETIME NOT NULL,
9
+ `service_code` VARCHAR(255) NOT NULL,
10
+ `reference_id` VARCHAR(32) NOT NULL,
11
+ `token` VARCHAR(255) NOT NULL,
12
+ `customer_id` INT(10) NOT NULL,
13
+ `store_id` SMALLINT(5) NOT NULL,
14
+ `additional_information` TEXT NULL,
15
+ PRIMARY KEY (`entity_id`),
16
+ UNIQUE KEY (`service_code`, `reference_id`),
17
+ UNIQUE KEY (`token`),
18
+ INDEX (`customer_id`),
19
+ INDEX (`store_id`)
20
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
21
+ ");
22
+
23
+ $this->endSetup();
app/code/core/Ampersand/PaymentGateway/sql/ampersand_paymentgateway_setup/mysql4-upgrade-0.0.4-0.0.5.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $this->startSetup();
3
+
4
+ $this->run("
5
+ ALTER TABLE `{$this->getTable('ampersand_paymentgateway/agreement')}`
6
+ DROP `token`;
7
+ ");
8
+
9
+ $this->endSetup();
app/code/core/Ampersand/PaymentGateway/sql/ampersand_paymentgateway_setup/mysql4-upgrade-0.0.5-0.0.6.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $this->startSetup();
3
+
4
+ $this->run("
5
+ ALTER TABLE `{$this->getTable('ampersand_paymentgateway/transaction')}`
6
+ ADD `payment_amount` DECIMAL(12,4) NULL;
7
+ ");
8
+
9
+ $this->endSetup();
app/code/core/Ampersand/PaymentGateway/sql/ampersand_paymentgateway_setup/mysql4-upgrade-0.0.6-0.0.7.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $this->startSetup();
3
+
4
+ $this->run("
5
+ CREATE TABLE `{$this->getTable('ampersand_paymentgateway/subscription')}` (
6
+ `entity_id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
7
+ `created_at` DATETIME NOT NULL,
8
+ `updated_at` DATETIME NOT NULL,
9
+ `order_id` INT(10) NOT NULL,
10
+ `agreement_id` INT(10) NOT NULL,
11
+ `method_code` VARCHAR(32) NOT NULL,
12
+ `frequency` VARCHAR(10) NOT NULL,
13
+ `frequency_type` VARCHAR(10) NOT NULL,
14
+ `start_date` DATETIME NOT NULL,
15
+ `next_order_date` DATETIME NOT NULL,
16
+ `is_active` TINYINT(1) NOT NULL,
17
+ PRIMARY KEY (`entity_id`),
18
+ UNIQUE KEY (`order_id`)
19
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
20
+ ");
21
+
22
+ $this->run("
23
+ CREATE TABLE `{$this->getTable('ampersand_paymentgateway/subscription_order')}` (
24
+ `entity_id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
25
+ `created_at` DATETIME NOT NULL,
26
+ `updated_at` DATETIME NOT NULL,
27
+ `subscription_id` INT(10) NOT NULL,
28
+ `order_id` INT(10) NOT NULL,
29
+ PRIMARY KEY (`entity_id`),
30
+ UNIQUE KEY (`subscription_id`, `order_id`)
31
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
32
+ ");
33
+
34
+ $this->endSetup();
app/code/core/Ampersand/PaymentGateway/sql/ampersand_paymentgateway_setup/mysql4-upgrade-0.0.7-0.0.8.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $this->startSetup();
3
+
4
+ $this->run("
5
+ ALTER TABLE `{$this->getTable('ampersand_paymentgateway/subscription')}`
6
+ DROP INDEX `order_id`;
7
+
8
+ ALTER TABLE `{$this->getTable('ampersand_paymentgateway/subscription')}`
9
+ ADD INDEX (`order_id`);
10
+ ");
11
+
12
+ $this->endSetup();
app/code/core/Ampersand/PaymentGateway/sql/ampersand_paymentgateway_setup/mysql4-upgrade-0.0.8-0.0.9.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $this->startSetup();
3
+
4
+ $this->run("
5
+ ALTER TABLE `{$this->getTable('ampersand_paymentgateway/agreement')}`
6
+ ADD `card_type` VARCHAR(255) NULL,
7
+ ADD `card_last_four` VARCHAR(4) NULL,
8
+ ADD `card_expiry_month` VARCHAR(2) NULL,
9
+ ADD `card_expiry_year` VARCHAR(4) NULL;
10
+ ");
11
+
12
+ $this->endSetup();
app/code/core/Ampersand/PaymentGateway/sql/ampersand_paymentgateway_setup/mysql4-upgrade-0.0.9-0.0.10.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $this->startSetup();
3
+
4
+ $this->run("
5
+ ALTER TABLE `{$this->getTable('ampersand_paymentgateway/subscription')}`
6
+ ADD `customer_id` INT(10) NOT NULL;
7
+ ");
8
+
9
+ $this->endSetup();
app/code/local/Ampersand/BillingAgreementFix/Rewrite/Mage/Paypal/Helper/Data.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_BillingAgreementFix_Rewrite_Mage_Paypal_Helper_Data extends Mage_Paypal_Helper_Data
3
+ {
4
+ /**
5
+ * Rewritten to check for a specific payment method.
6
+ *
7
+ * @param Mage_Paypal_Model_Config $config
8
+ * @param int $customerId
9
+ * @return bool
10
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
11
+ */
12
+ public function shouldAskToCreateBillingAgreement(Mage_Paypal_Model_Config $config, $customerId)
13
+ {
14
+ if (null === self::$_shouldAskToCreateBillingAgreement) {
15
+ self::$_shouldAskToCreateBillingAgreement = false;
16
+ if ($customerId && $config->shouldAskToCreateBillingAgreement()) {
17
+ $methodCode = Mage_Paypal_Model_Config::METHOD_BILLING_AGREEMENT;
18
+ $needToCreateForCustomer = Mage::getModel('sales/billing_agreement')
19
+ ->needToCreateForCustomer($customerId, $methodCode);
20
+
21
+ if ($needToCreateForCustomer) {
22
+ self::$_shouldAskToCreateBillingAgreement = true;
23
+ }
24
+ }
25
+ }
26
+ return self::$_shouldAskToCreateBillingAgreement;
27
+ }
28
+ }
app/code/local/Ampersand/BillingAgreementFix/Rewrite/Mage/Paypal/Model/Express/Checkout.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_BillingAgreementFix_Rewrite_Mage_Paypal_Model_Express_Checkout
3
+ extends Mage_Paypal_Model_Express_Checkout
4
+ {
5
+ /**
6
+ * Rewritten to check for a specific payment method.
7
+ *
8
+ * @return Mage_Paypal_Model_Express_Checkout
9
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
10
+ */
11
+ protected function _setBillingAgreementRequest()
12
+ {
13
+ if (!$this->_customerId || $this->_quote->hasNominalItems()) {
14
+ return $this;
15
+ }
16
+
17
+ $isRequested = $this->_isBARequested || $this->_quote->getPayment()
18
+ ->getAdditionalInformation(self::PAYMENT_INFO_TRANSPORT_BILLING_AGREEMENT);
19
+
20
+ if (!($this->_config->allow_ba_signup == Mage_Paypal_Model_Config::EC_BA_SIGNUP_AUTO
21
+ || $isRequested && $this->_config->shouldAskToCreateBillingAgreement())) {
22
+ return $this;
23
+ }
24
+
25
+ $methodCode = Mage_Paypal_Model_Config::METHOD_BILLING_AGREEMENT;
26
+ $needToCreateForCustomer = Mage::getModel('sales/billing_agreement')
27
+ ->needToCreateForCustomer($this->_customerId, $methodCode);
28
+
29
+ if (!$needToCreateForCustomer) {
30
+ return $this;
31
+ }
32
+
33
+ $this->_api->setBillingType($this->_api->getBillingAgreementType());
34
+
35
+ return $this;
36
+ }
37
+ }
app/code/local/Ampersand/BillingAgreementFix/Rewrite/Mage/Paypal/Model/Method/Agreement.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_BillingAgreementFix_Rewrite_Mage_Paypal_Model_Method_Agreement
3
+ extends Mage_Paypal_Model_Method_Agreement
4
+ {
5
+ /**
6
+ * Rewritten to include the method code in the call to getAvailableCustomerBillingAgreements().
7
+ *
8
+ * @param Mage_Sales_Model_Quote $quote
9
+ * @return bool
10
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
11
+ */
12
+ public function isAvailable($quote = null)
13
+ {
14
+ // we need to call the parent first otherwise it will override our checks below
15
+ $this->_isAvailable = parent::isAvailable($quote);
16
+
17
+ if (is_object($quote) && $quote->getCustomer()) {
18
+ $availableBA = Mage::getModel('sales/billing_agreement')
19
+ ->getAvailableCustomerBillingAgreements($quote->getCustomer()->getId())
20
+ ->addFieldToFilter('method_code', $this->_code);
21
+ $isAvailableBA = count($availableBA) > 0;
22
+ $this->_canUseCheckout = $this->_canUseInternal = $isAvailableBA;
23
+ }
24
+
25
+ return $this->_isAvailable;
26
+ }
27
+ }
app/code/local/Ampersand/BillingAgreementFix/Rewrite/Mage/Sales/Block/Payment/Form/Billing/Agreement.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_BillingAgreementFix_Rewrite_Mage_Sales_Block_Payment_Form_Billing_Agreement
3
+ extends Mage_Sales_Block_Payment_Form_Billing_Agreement
4
+ {
5
+ /**
6
+ * Rewritten to restrict billing agreements to the appropriate payment method.
7
+ *
8
+ * @todo Add versioning to this method once Magento sort the problem
9
+ * @return array
10
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
11
+ */
12
+ public function getBillingAgreements()
13
+ {
14
+ $data = array();
15
+
16
+ $quote = $this->getParentBlock()->getQuote();
17
+ if (!$quote || !$quote->getCustomer()) {
18
+ return $data;
19
+ }
20
+
21
+ $collection = Mage::getModel('sales/billing_agreement')
22
+ ->getAvailableCustomerBillingAgreements($quote->getCustomer()->getId())
23
+ ->addFieldToFilter('method_code', $this->getMethod()->getCode());
24
+
25
+ foreach ($collection as $item) {
26
+ $data[$item->getId()] = $item->getReferenceId();
27
+ }
28
+
29
+ return $data;
30
+ }
31
+ }
app/code/local/Ampersand/BillingAgreementFix/Rewrite/Mage/Sales/Model/Billing/Agreement.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Ampersand_BillingAgreementFix_Rewrite_Mage_Sales_Model_Billing_Agreement
3
+ extends Mage_Sales_Model_Billing_Agreement
4
+ {
5
+ /**
6
+ * Rewritten to check for a specific payment method.
7
+ *
8
+ * @param int $customerId
9
+ * @return bool
10
+ * @author Joseph McDermott <joseph.mcdermott@ampersandcommerce.com>
11
+ */
12
+ public function needToCreateForCustomer($customerId)
13
+ {
14
+ // changing the accepted params would cause PHP Strict error due to parent declaration
15
+ $methodCode = func_get_arg(1);
16
+
17
+ if (!$customerId || !$methodCode) {
18
+ return false;
19
+ }
20
+
21
+ $collection = $this->getAvailableCustomerBillingAgreements($customerId)
22
+ ->addFieldToFilter('method_code', $methodCode);
23
+
24
+ return $collection->count() == 0;
25
+ }
26
+ }
app/code/local/Ampersand/BillingAgreementFix/etc/config.xml ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <config>
3
+ <modules>
4
+ <Ampersand_BillingAgreementFix>
5
+ <version>0.0.1</version>
6
+ </Ampersand_BillingAgreementFix>
7
+ </modules>
8
+ <global>
9
+ <blocks>
10
+ <sales>
11
+ <rewrite>
12
+ <payment_form_billing_agreement>Ampersand_BillingAgreementFix_Rewrite_Mage_Sales_Block_Payment_Form_Billing_Agreement</payment_form_billing_agreement>
13
+ </rewrite>
14
+ </sales>
15
+ </blocks>
16
+ <helpers>
17
+ <paypal>
18
+ <rewrite>
19
+ <data>Ampersand_BillingAgreementFix_Rewrite_Mage_Paypal_Helper_Data</data>
20
+ </rewrite>
21
+ </paypal>
22
+ </helpers>
23
+ <models>
24
+ <paypal>
25
+ <rewrite>
26
+ <express_checkout>Ampersand_BillingAgreementFix_Rewrite_Mage_Paypal_Model_Express_Checkout</express_checkout>
27
+ <method_agreement>Ampersand_BillingAgreementFix_Rewrite_Mage_Paypal_Model_Method_Agreement</method_agreement>
28
+ </rewrite>
29
+ </paypal>
30
+ <sales>
31
+ <rewrite>
32
+ <billing_agreement>Ampersand_BillingAgreementFix_Rewrite_Mage_Sales_Model_Billing_Agreement</billing_agreement>
33
+ </rewrite>
34
+ </sales>
35
+ </models>
36
+ </global>
37
+ </config>
app/design/adminhtml/base/default/layout/ampersand_paymentgateway.xml ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <layout>
3
+ <default>
4
+ <reference name="head">
5
+ <action method="addCss"><name>ampersand_paymentgateway/css/styles.css</name></action>
6
+ </reference>
7
+ </default>
8
+ </layout>
app/design/adminhtml/base/default/template/ampersand_paymentgateway/system/config/fieldset/hint.phtml ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <div class="ampersand-paymentgateway-payment-notice">
2
+ <h4><?php echo Mage::helper('ampersand_paymentgateway')->__('Payment Gateways by <a href="http://ampersandcommerce.com" title="_blank">Ampersand Commerce</a>.')?></h4>
3
+ <p><a href="<?php echo $this->escapeHtml($this->getUrl('adminhtml/system_config/edit', array('section' => 'ampersand_paymentgateway'))) ?>" title="<?php echo Mage::helper('ampersand_paymentgateway')->__('Ampersand Payment Gateways')?>">Click here</a> to manage the general configuration settings that apply to all of the below Payment Gateways.</p>
4
+ </div>
app/design/frontend/base/default/layout/ampersand_paymentgateway.xml ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <layout>
3
+ <default>
4
+ <reference name="head">
5
+ <action method="addJs"><script>ampersand_paymentgateway/validation.js</script></action>
6
+ </reference>
7
+ </default>
8
+
9
+ <ampersand_paymentgateway_redirect_form>
10
+ <remove name="root"/>
11
+ <block type="ampersand_paymentgateway/redirect_form" name="ampersand_paymentgateway_redirect_form" output="toHtml"/>
12
+ </ampersand_paymentgateway_redirect_form>
13
+
14
+ <ampersand_paymentgateway_redirect_iframe>
15
+ <reference name="content">
16
+ <block type="ampersand_paymentgateway/redirect_iframe" name="ampersand_paymentgateway_redirect_iframe">
17
+ <action method="setSrcByRoute"><route>ampersand_paymentgateway/redirect/form</route></action>
18
+ </block>
19
+ </reference>
20
+ </ampersand_paymentgateway_redirect_iframe>
21
+
22
+ <ampersand_paymentgateway_redirect_location>
23
+ <remove name="root"/>
24
+ <block type="ampersand_paymentgateway/redirect_location" name="ampersand_paymentgateway_redirect_location" output="toHtml"/>
25
+ </ampersand_paymentgateway_redirect_location>
26
+
27
+ <ampersand_paymentgateway_checkout_onepage_failure>
28
+ <update handle="checkout_onepage_failure" />
29
+ </ampersand_paymentgateway_checkout_onepage_failure>
30
+
31
+ <ampersand_paymentgateway_customer_account_subscription_index translate="label">
32
+ <label>Customer My Account Subscriptions</label>
33
+ <update handle="customer_account"/>
34
+ <reference name="my.account.wrapper">
35
+ <block type="ampersand_paymentgateway/customer_account_subscription" name="ampersand_paymentgateway_customer_account_subscription" template="ampersand_paymentgateway/customer/account/subscription.phtml"/>
36
+ <block type="customer/account_dashboard" name="customer.account.link.back" template="customer/account/link/back.phtml"/>
37
+ </reference>
38
+ </ampersand_paymentgateway_customer_account_subscription_index>
39
+
40
+ <checkout_cart_index>
41
+ <reference name="head">
42
+ <action method="addCss"><stylesheet>ampersand_paymentgateway/css/cart.css</stylesheet></action>
43
+ </reference>
44
+ <reference name="checkout.cart">
45
+ <block type="core/text_list" name="checkout.cart.extra"/>
46
+ </reference>
47
+ <reference name="checkout.cart.extra">
48
+ <block type="ampersand_paymentgateway/checkout_cart_subscription" name="ampersand_paymentgateway_cart_subscription" template="ampersand_paymentgateway/checkout/cart/subscription.phtml"/>
49
+ </reference>
50
+ </checkout_cart_index>
51
+
52
+ <checkout_onepage_index>
53
+ <reference name="head">
54
+ <action method="addCss"><stylesheet>ampersand_paymentgateway/css/checkout.css</stylesheet></action>
55
+ </reference>
56
+ </checkout_onepage_index>
57
+
58
+ <checkout_onepage_review>
59
+ <reference name="checkout.onepage.review.info.items.after">
60
+ <block type="ampersand_paymentgateway/checkout_onepage_review_subscription" name="ampersand_paymentgateway_checkout_review" template="ampersand_paymentgateway/checkout/onepage/review/subscription.phtml" />
61
+ </reference>
62
+ </checkout_onepage_review>
63
+
64
+ <customer_account_subscriptions>
65
+ <update handle="ampersand_paymentgateway_customer_account_subscription_index"/>
66
+ </customer_account_subscriptions>
67
+
68
+ <customer_account>
69
+ <reference name="customer_account_navigation">
70
+ <action method="addLink" translate="label" module="ampersand_paymentgateway" ifconfig="ampersand_paymentgateway/subscription/active">
71
+ <name>subscriptions</name>
72
+ <path>customer/account/subscriptions</path>
73
+ <label>My Subscriptions</label>
74
+ </action>
75
+ </reference>
76
+ </customer_account>
77
+ </layout>
app/design/frontend/base/default/template/ampersand_paymentgateway/checkout/cart/subscription.phtml ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if ($this->isActive()): ?>
2
+ <?php if ($this->isLoggedIn()): ?>
3
+ <div class="subscription">
4
+ <h2><?php echo $this->__('Subscribe to this order') ?></h2>
5
+ <form id="subscription-form" action="<?php echo $this->getUrl('ampersand_paymentgateway/checkout_cart_subscription/post') ?>" method="post">
6
+ <fieldset>
7
+ <input type="hidden" name="remove" id="remove-subscription" value="0" />
8
+
9
+ <label for="period"><?php echo $this->__('Select your subscription period.') ?></label>
10
+ <select name="period" id="period" title="<?php echo $this->__('Period') ?>" class="validate-select">
11
+ <?php foreach ($this->getPeriods() as $_period): ?>
12
+ <?php $_selected = ($_period['value'] == $this->getSubscriptionPeriod()) ? ' SELECTED' : ''; ?>
13
+ <option value="<?php echo $_period['value']; ?>"<?php echo $_selected; ?>><?php echo $_period['label']; ?></option>
14
+ <?php endforeach; ?>
15
+ </select>
16
+ <button type="button" class="button" onclick="subscriptionForm.submit(false)" value="<?php echo $this->__('Subscribe') ?>"><span><span><?php echo $this->__('Subscribe') ?></span></span></button>
17
+
18
+ <?php if ($this->getSubscriptionPeriod()): ?>
19
+ <button type="button" class="button cancel-btn" onclick="subscriptionForm.submit(true)" value="<?php echo $this->__('Cancel Subscription') ?>"><span><span><?php echo $this->__('Cancel Subscription') ?></span></span></button>
20
+ <?php endif; ?>
21
+ </fieldset>
22
+ </form>
23
+ <script type="text/javascript">
24
+ //<![CDATA[
25
+ var subscriptionForm = new VarienForm('subscription-form');
26
+ subscriptionForm.submit = function (isRemove) {
27
+ if (isRemove) {
28
+ $('period').removeClassName('required-entry');
29
+ $('remove-subscription').value = "1";
30
+ } else {
31
+ $('period').addClassName('required-entry');
32
+ $('remove-subscription').value = "0";
33
+ }
34
+ return VarienForm.prototype.submit.bind(subscriptionForm)();
35
+ }
36
+ //]]>
37
+ </script>
38
+ </div>
39
+ <?php else: ?>
40
+ <div class="subscription">
41
+ <h2><?php echo $this->__('Subscribe to this order') ?></h2>
42
+ <p><?php echo $this->__('You must be logged in to subscribe.'); ?></p>
43
+ </div>
44
+ <?php endif; ?>
45
+ <?php endif; ?>
app/design/frontend/base/default/template/ampersand_paymentgateway/checkout/onepage/review/subscription.phtml ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php if ($this->isActive()): ?>
2
+
3
+ <?php $info = $this->getSubscriptionInfo(); ?>
4
+ <div class="subscription-review">
5
+ <p class="f-right"><?php echo $this->__('A %s subscription will be created upon completion of this order.', $info->getPeriod()) ?></p>
6
+ </div>
7
+
8
+ <?php endif; ?>
app/design/frontend/base/default/template/ampersand_paymentgateway/customer/account/subscription.phtml ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php $_subscriptions = $this->getSubscriptions(); ?>
2
+ <?php echo $this->getMessagesBlock()->getGroupedHtml() ?>
3
+
4
+ <div class="page-title">
5
+ <h1><?php echo $this->__('My Subscriptions') ?></h1>
6
+ </div>
7
+
8
+ <?php if ($_subscriptions->getSize()): ?>
9
+
10
+ <?php echo $this->getPagerHtml(); ?>
11
+
12
+ <table class="data-table" id="my-subscriptions-table">
13
+ <col width="1" />
14
+ <col width="1" />
15
+ <col width="1" />
16
+ <col width="1" />
17
+ <col width="1" />
18
+ <thead>
19
+ <tr>
20
+ <th><?php echo $this->__('Date') ?></th>
21
+ <th><?php echo $this->__('Order #') ?></th>
22
+ <th><?php echo $this->__('Payment Method') ?></th>
23
+ <th><?php echo $this->__('Next Order') ?></th>
24
+ <th>&nbsp;</th>
25
+ </tr>
26
+ </thead>
27
+ <tbody>
28
+ <?php foreach ($_subscriptions as $_subscription): ?>
29
+ <?php $_order = $this->getOrder($_subscription->getOrderId()); ?>
30
+ <?php $_cardDetails = $this->getPaymentMethodCardDetails($_subscription->getAgreementId()); ?>
31
+ <tr>
32
+ <td><?php echo $this->formatDate($_subscription->getCreatedAt(), 'short') ?></td>
33
+ <td><a href="<?php echo $this->getOrderUrl($_order) ?>"><?php echo $_order->getRealOrderId() ?></a></td>
34
+ <td>
35
+ <?php echo $this->getPaymentMethod($_subscription->getMethodCode()) ?>
36
+ <br /><span class="nobr"><?php echo $this->__(
37
+ '(%s card ending %s, expiry %s/%s)',
38
+ $this->getCardType($_cardDetails->getCardType()),
39
+ $_cardDetails->getCardLastFour(),
40
+ $_cardDetails->getCardExpiryMonth(),
41
+ $_cardDetails->getCardExpiryYear()
42
+ ) ?></span>
43
+ </td>
44
+ <td><?php echo $this->formatDate($_subscription->getNextOrderDate(), 'short') ?></td>
45
+ <td class="a-center">
46
+ <span class="nobr">
47
+ <a href="#" onclick="return cancelSubscription('<?php echo $_subscription->getId() ?>');"><?php echo $this->__('Cancel') ?></a>
48
+ <span class="separator">|</span>
49
+ <a href="#" onclick="return skipSubscription('<?php echo $_subscription->getId() ?>');"><?php echo $this->__('Skip Next') ?></a>
50
+ </span>
51
+ </td>
52
+ </tr>
53
+ <?php endforeach; ?>
54
+ </tbody>
55
+ </table>
56
+
57
+ <?php echo $this->getPagerHtml(); ?>
58
+
59
+ <script type="text/javascript">
60
+ //<![CDATA[
61
+ decorateTable('my-subscriptions-table');
62
+
63
+ function cancelSubscription(subscriptionId) {
64
+ if (confirm('<?php echo $this->__('Are you sure you want to cancel this subscription?') ?>')) {
65
+ window.location='<?php echo $this->getCancelUrl() ?>id/' + subscriptionId;
66
+ }
67
+ return false;
68
+ }
69
+
70
+ function skipSubscription(subscriptionId) {
71
+ if (confirm('<?php echo $this->__('Are you sure you want to skip the next order for this subscription?') ?>')) {
72
+ window.location='<?php echo $this->getSkipNextUrl() ?>id/' + subscriptionId;
73
+ }
74
+ return false;
75
+ }
76
+ //]]>
77
+ </script>
78
+
79
+ <?php else: ?>
80
+
81
+ <p><?php echo $this->__('You have no active subscriptions.'); ?></p>
82
+
83
+ <?php endif ?>
app/design/frontend/base/default/template/ampersand_paymentgateway/payment/form/billing-agreement-checkbox.phtml ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php $_code = $this->getParentBlock()->getMethodCode() ?>
2
+ <li class="form-alt">
3
+
4
+ <?php if ($this->getForceBillingAgreement()): ?>
5
+
6
+ <label for="<?php echo $_code ?>_billing_agreement_selection">
7
+ <input type="checkbox" id="<?php echo $_code ?>_billing_agreement_selection" name="payment[billing_agreement_selection]" class="checkbox" value="1" disabled="disabled" checked="checked" />
8
+ <?php echo $this->__('A billing agreement will be created to process your order.') ?>
9
+ </label>
10
+
11
+ <script type="text/javascript">
12
+ //<![CDATA[
13
+ var agreementCheckbox = $('<?php echo $_code ?>_billing_agreement_selection');
14
+ agreementCheckbox.observe('click', function() {
15
+ agreementCheckbox.checked = 'checked';
16
+ });
17
+ //]]>
18
+ </script>
19
+
20
+ <?php else: ?>
21
+
22
+ <label for="<?php echo $_code ?>_billing_agreement_selection">
23
+ <input type="checkbox" id="<?php echo $_code ?>_billing_agreement_selection" name="payment[billing_agreement_selection]" class="checkbox" value="1" />
24
+ <?php echo $this->__('Create billing agreement with these details for future use?') ?>
25
+ </label>
26
+
27
+ <?php endif; ?>
28
+
29
+ </li>
app/design/frontend/base/default/template/ampersand_paymentgateway/payment/form/billing-agreement-cv2.phtml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php $_code = $this->getParentBlock()->getMethodCode() ?>
2
+ <li>
3
+ <label for="<?php echo $_code ?>_billing_agreement_cv2" class="required"><em>*</em><?php echo $this->__('Card Verification Number') ?></label>
4
+ <div class="input-box">
5
+ <div class="v-fix">
6
+ <input type="text" title="<?php echo $this->__('Card Verification Number') ?>" class="input-text cvv required-entry validate-cc-cvn" id="<?php echo $_code ?>_billing_agreement_cv2" name="payment[billing_agreement_cv2]" value="" />
7
+ </div>
8
+ <a href="#" class="cvv-what-is-this"><?php echo $this->__('What is this?') ?></a>
9
+ </div>
10
+ </li>
app/design/frontend/base/default/template/ampersand_paymentgateway/payment/form/redirect.phtml ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php $_code = $this->getMethodCode() ?>
2
+ <ul class="form-list" id="payment_form_<?php echo $_code ?>" style="display:none;">
3
+
4
+ <li><?php echo $this->__('You will be redirected to the payment gateway after placing your order.') ?></li>
5
+
6
+ <?php if ($this->isCcTypeRequired()): ?>
7
+ <li>
8
+ <label for="<?php echo $_code ?>_cc_type" class="required"><em>*</em><?php echo $this->__('Credit Card Type'); ?></label>
9
+ <div class="input-box">
10
+ <select id="<?php echo $_code ?>_cc_type" name="payment[cc_type]" class="required-entry">
11
+ <option value=""><?php echo $this->__('--Please Select--'); ?></option>
12
+ <?php $_ccType = $this->getInfoData('cc_type'); ?>
13
+ <?php foreach ($this->getCcAvailableTypes() as $_typeCode => $_typeName): ?>
14
+ <option value="<?php echo $_typeCode ?>"<?php if ($_typeCode == $_ccType): ?> selected="selected"<?php endif ?>><?php echo $_typeName; ?></option>
15
+ <?php endforeach; ?>
16
+ </select>
17
+ </div>
18
+ </li>
19
+ <?php endif; ?>
20
+
21
+ </ul>
app/design/frontend/base/default/template/ampersand_paymentgateway/redirect/form.phtml ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <html>
2
+ <head>
3
+ <title><?php echo $this->__($this->getTitle()) ?></title>
4
+ </head>
5
+ <body>
6
+ <?php if ($redirectUrl = $this->getRedirectUrl()): ?>
7
+ <form action="<?php echo $redirectUrl ?>" name="ampersand_redirect_form" method="POST" style="width:100%; text-align:center;">
8
+ <?php foreach ($this->getHiddenFields() as $_fieldName => $_value): ?>
9
+ <input type="hidden" name="<?php echo $_fieldName ?>" value="<?php echo $_value ?>" />
10
+ <?php endforeach; ?>
11
+
12
+ <input type="submit" value="<?php echo $this->__('Please click here if you are not automatically redirected after a few seconds...'); ?>" />
13
+ </form>
14
+ <script type="text/javascript">
15
+ //<![CDATA[
16
+ document.ampersand_redirect_form.submit();
17
+ //]]>
18
+ </script>
19
+ <?php else: ?>
20
+ <p><?php echo $this->__($this->getNoRedirectUrlMessage()) ?></p>
21
+ <?php endif; ?>
22
+ </body>
23
+ </html>
app/design/frontend/base/default/template/ampersand_paymentgateway/redirect/iframe.phtml ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <iframe
2
+ src="<?php echo $this->getSrc() ?>"
3
+ width="<?php echo $this->getWidth() ?>"
4
+ height="<?php echo $this->getHeight() ?>"
5
+ frameborder="0">
6
+ </iframe>
app/design/frontend/base/default/template/ampersand_paymentgateway/redirect/location.phtml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <html>
2
+ <head>
3
+ <title><?php echo $this->__($this->getTitle()) ?></title>
4
+ </head>
5
+ <body>
6
+ <script type="text/javascript">
7
+ //<![CDATA[
8
+ window.top.location.href='<?php echo $this->getRedirectUrl() ?>';
9
+ //]]>
10
+ </script>
11
+ </body>
12
+ </html>
app/design/frontend/base/default/template/ampersand_paymentgateway/sales/payment/form/billing/agreement.phtml ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php $_code = $this->getMethodCode() ?>
2
+ <ul class="form-list" id="payment_form_<?php echo $_code ?>" style="display:none;">
3
+
4
+ <li>
5
+ <table id="ampersand-billing-agreement-table" class="data-table">
6
+ <col width="1" />
7
+ <col width="1" />
8
+ <col width="1" />
9
+ <col width="1" />
10
+ <col width="1" />
11
+ <thead>
12
+ <tr>
13
+ <th><span class="nobr"><?php echo $this->__('Created') ?></span></th>
14
+ <th><span class="nobr"><?php echo $this->__('Card Type') ?></span></th>
15
+ <th><span class="nobr"><?php echo $this->__('Card Number') ?></span></th>
16
+ <th><span class="nobr"><?php echo $this->__('Card Expiry') ?></span></th>
17
+ <th>&nbsp;</th>
18
+ </tr>
19
+ </thead>
20
+ <tbody>
21
+ <?php foreach ($this->getBillingAgreements() as $id => $agreement): ?>
22
+ <tr>
23
+ <td><?php echo $this->formatDate($agreement->getCreatedAt(), 'short') ?></td>
24
+ <td><?php echo $this->getCardType($agreement->getCardType()) ?></td>
25
+ <td>**** **** **** <?php echo $agreement->getCardLastFour() ?></td>
26
+ <td><?php echo $agreement->getCardExpiryMonth() ?>/<?php echo $agreement->getCardExpiryYear() ?></td>
27
+ <td><input type="radio" name="payment[<?php echo $this->getTransportName(); ?>]" class="validate-one-required-by-name" value="<?php echo $id ?>" /></td>
28
+ </tr>
29
+ <?php endforeach; ?>
30
+ </tbody>
31
+ </table>
32
+
33
+ <script type="text/javascript">
34
+ //<![CDATA[
35
+ decorateTable('ampersand-billing-agreement-table');
36
+ //]]>
37
+ </script>
38
+ </li>
39
+
40
+ <?php echo $this->getChildHtml() ?>
41
+
42
+ </ul>
app/etc/modules/Ampersand_BillingAgreementFix.xml ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <config>
3
+ <modules>
4
+ <Ampersand_BillingAgreementFix>
5
+ <active>true</active>
6
+ <codePool>local</codePool>
7
+ </Ampersand_BillingAgreementFix>
8
+ </modules>
9
+ </config>
app/etc/modules/Ampersand_PaymentGateway.xml ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <config>
3
+ <modules>
4
+ <Ampersand_PaymentGateway>
5
+ <active>true</active>
6
+ <codePool>core</codePool>
7
+ <depends>
8
+ <Mage_Payment/>
9
+ <Mage_Checkout/>
10
+ <Ampersand_Core/>
11
+ <Ampersand_Api/>
12
+ <Ampersand_Integration/>
13
+
14
+ <!--
15
+ Ampersand_PaymentGateway_Block_Payment_Form_BillingAgreement
16
+ requires a class from Ampersand_BillingAgreementFix.
17
+ Once Magento provide an official fix, this dependency can be removed.
18
+ -->
19
+ <Ampersand_BillingAgreementFix/>
20
+ </depends>
21
+ </Ampersand_PaymentGateway>
22
+ </modules>
23
+ </config>
app/locale/en_US/template/email/ampersand_paymentgateway/notification.html ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!--@subject {{var title}} @-->
2
+ <!--@vars
3
+ {"var summary":"Summary"}
4
+ {"var base_url":"Magento Instance"}
5
+ {"var items":"Items"}
6
+ {"var exception_message":"Exception Message"}
7
+ {"var exception_trace":"Exception Trace"}
8
+ @-->
9
+ <strong>Summary:</strong><br />
10
+ {{var summary}}
11
+ <br /><br />
12
+
13
+ <strong>Magento Instance:</strong><br />
14
+ {{var base_url}}
15
+ <br /><br />
16
+
17
+ {{var items}}
18
+
19
+ <strong>Exception Message:</strong><br />
20
+ {{var exception_message}}
21
+ <br /><br />
22
+
23
+ <strong>Exception Trace:</strong><br />
24
+ {{var exception_trace}}
25
+ <br /><br />
app/locale/en_US/template/email/ampersand_paymentgateway/subscription_reminder.html ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!--@subject Your subscription will be processed soon, {{var customer.name}}! @-->
2
+ <!--@vars
3
+ {"store url=\"\"":"Store Url",
4
+ "var logo_url":"Email Logo Image Url",
5
+ "htmlescape var=$customer.name":"Customer Name",
6
+ "store url=\"customer/account/\"":"Customer Account Url"}
7
+ @-->
8
+
9
+ <!--@styles
10
+ body,td { color:#2f2f2f; font:11px/1.35em Verdana, Arial, Helvetica, sans-serif; }
11
+ @-->
12
+
13
+ <body style="background:#F6F6F6; font-family:Verdana, Arial, Helvetica, sans-serif; font-size:12px; margin:0; padding:0;">
14
+ <div style="background:#F6F6F6; font-family:Verdana, Arial, Helvetica, sans-serif; font-size:12px; margin:0; padding:0;">
15
+ <table cellspacing="0" cellpadding="0" border="0" height="100%" width="100%">
16
+ <tr>
17
+ <td align="center" valign="top" style="padding:20px 0 20px 0">
18
+ <table bgcolor="FFFFFF" cellspacing="0" cellpadding="10" border="0" width="650" style="border:1px solid #E0E0E0;">
19
+ <tr>
20
+ <td valign="top">
21
+ <a href="{{store url=""}}"><img src="{{var logo_url}}" alt="{{var logo_alt}}" style="margin-bottom:10px;" border="0"/></a></td>
22
+ </tr>
23
+ <tr>
24
+ <td valign="top">
25
+ <h1 style="font-size:22px; font-weight:normal; line-height:22px; margin:0 0 11px 0;"">Dear {{htmlescape var=$customer.name}},</h1>
26
+ <p style="font-size:12px; line-height:16px; margin:0 0 16px 0;">
27
+ This is just a reminder that your subscription at {{var store.getFrontendName()}} will be processed soon.
28
+ If you would like to cancel for any reason, you can do in your customer account area by clicking <a href="{{store url="customer/account/subscriptions"}}" style="color:#1E7EC8;">here</a>.
29
+ </p>
30
+ <p style="font-size:12px; line-height:16px; margin:0;">
31
+ If you have any questions about your subscription or any other matter, please feel free to contact us at <a href="mailto:{{config path='trans_email/ident_support/email'}}" style="color:#1E7EC8;">{{config path='trans_email/ident_support/email'}}</a> or by phone at {{config path='general/store_information/phone'}}.
32
+ </p>
33
+ </td>
34
+ </tr>
35
+ <tr>
36
+ <td bgcolor="#EAEAEA" align="center" style="background:#EAEAEA; text-align:center;"><center><p style="font-size:12px; margin:0;">Thank you again, <strong>{{var store.getFrontendName()}}</strong></p></center></td>
37
+ </tr>
38
+ </table>
39
+ </td>
40
+ </tr>
41
+ </table>
42
+ </div>
43
+ </body>
js/ampersand_paymentgateway/validation.js ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ // Notes:
2
+ // - Card number expressions must exactly identify a card type. ie. you cannot use the same regex for multiple cards.
3
+ // - All expressions must match the values in Ampersand_PaymentGateway_Model_Method_DirectAbstract.
4
+ Validation.creditCartTypes.set('AMPERSAND_CARTES_BANCAIRES', [false, new RegExp('^([0-9]{3}|[0-9]{4})?$'), true]);
5
+ Validation.creditCartTypes.set('AMPERSAND_MASTERCARD_DEBIT', [false, new RegExp('^([0-9]{3}|[0-9]{4})?$'), true]);
6
+ Validation.creditCartTypes.set('AMPERSAND_VISA_DELTA', [false, new RegExp('^([0-9]{3}|[0-9]{4})?$'), true]);
7
+ Validation.creditCartTypes.set('AMPERSAND_VISA_ELECTRON', [false, new RegExp('^([0-9]{3}|[0-9]{4})?$'), true]);
8
+ Validation.creditCartTypes.set('AMPERSAND_VISA_PURCHASING', [false, new RegExp('^([0-9]{3}|[0-9]{4})?$'), true]);
9
+ Validation.creditCartTypes.set('AMPERSAND_LASER', [false, new RegExp('^([0-9]{3}|[0-9]{4})?$'), true]);
10
+ Validation.creditCartTypes.set('AMPERSAND_DINERS_CLUB', [false, new RegExp('^([0-9]{3}|[0-9]{4})?$'), true]);
11
+ Validation.creditCartTypes.set('AMPERSAND_VPAY', [false, new RegExp('^([0-9]{3}|[0-9]{4})?$'), true]);
package.xml ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <package>
3
+ <name>Ampersand_PaymentGateway</name>
4
+ <version>0.1.4</version>
5
+ <stability>stable</stability>
6
+ <license uri="http://www.opensource.org/licenses/gpl-license.php">GNU General Public License (GPL)</license>
7
+ <channel>community</channel>
8
+ <extends/>
9
+ <summary>Ampersand Payment Gateway framework from Ampersand Commerce.</summary>
10
+ <description>Ampersand Payment Gateway framework from Ampersand Commerce.</description>
11
+ <notes>Ampersand_PaymentGateway v0.1.4</notes>
12
+ <authors><author><name>AmpersandHQ</name><user>auto-converted</user><email>magento@ampersandcommerce.com</email></author></authors>
13
+ <date>2013-01-24</date>
14
+ <time>16:55:09</time>
15
+ <contents><target name="magelocal"><dir name="Ampersand"><dir name="BillingAgreementFix"><dir name="etc"><file name="config.xml" hash="182ff5f59378cb85f2e640dab93e1d91"/></dir><dir name="Rewrite"><dir name="Mage"><dir name="Sales"><dir name="Block"><dir name="Payment"><dir name="Form"><dir name="Billing"><file name="Agreement.php" hash="ba18d3e86edacc6455e84e682e100190"/></dir></dir></dir></dir><dir name="Model"><dir name="Billing"><file name="Agreement.php" hash="09122c7aad1b186ef87e9c79fee62940"/></dir></dir></dir><dir name="Paypal"><dir name="Helper"><file name="Data.php" hash="5eb5f7e6fcad4ff6e48e12c7d9517a7a"/></dir><dir name="Model"><dir name="Express"><file name="Checkout.php" hash="9572f6a8a94b851ea2b9f5f7caf1fee7"/></dir><dir name="Method"><file name="Agreement.php" hash="d35b02f584e0359fb12aa685b1bc94a1"/></dir></dir></dir></dir></dir></dir></dir></target><target name="magecore"><dir name="Ampersand"><dir name="PaymentGateway"><dir name="Block"><dir name="Redirect"><file name="Iframe.php" hash="b896215490bb40fdbe3a50b45f73ec7b"/><file name="Form.php" hash="199184b410f7de50cd3cf2108021120f"/><file name="Location.php" hash="aabfaf8543541d11a098145f83d3e294"/></dir><dir name="Adminhtml"><dir name="System"><dir name="Config"><dir name="Fieldset"><file name="Hint.php" hash="389f6fc34bb33b049a6372a68a0f52f7"/></dir></dir></dir><dir name="Subscription"><dir name="Order"><file name="Grid.php" hash="4c1df2f20be9af3c4a0754cb1761ba48"/></dir><dir name="Edit"><file name="Form.php" hash="e070aa1106a6efb043313e959ac06195"/></dir><file name="Order.php" hash="493baa23d6c205002f06f26f49b84852"/><file name="Edit.php" hash="0bc4ad5fa46cd02740fb64c027502eed"/><file name="Grid.php" hash="a64d41c912d31995f2fc0fef37922773"/></dir><file name="Subscription.php" hash="5820166cc7762b370644936a01d51530"/></dir><dir name="Checkout"><dir name="Onepage"><dir name="Review"><file name="Subscription.php" hash="888e9b4af5749dfa58f31087591eab18"/></dir></dir><dir name="Cart"><file name="Subscription.php" hash="aefee3bff9660b4a360d8a0928c7cc46"/></dir></dir><dir name="Payment"><dir name="Form"><file name="BillingAgreementCheckbox.php" hash="2057de4e06ca0c92ccfe149e39e4df11"/><file name="Subscription.php" hash="c0c27e0802aab6bf98e0e6dc60f598d7"/><file name="Redirect.php" hash="7a0db3f83604c4bae31e49694d14d362"/><file name="BillingAgreement.php" hash="f022d1358e33976ccbd97629535a3dbb"/><file name="BillingAgreementCv2.php" hash="d402e86f22f044bc2b438d0f8370106c"/></dir><dir name="Info"><file name="Redirect.php" hash="befe27b6d3a0bad1dd79d9698d15ea16"/></dir></dir><dir name="Customer"><dir name="Account"><file name="Subscription.php" hash="fa70122cb56980ccb5b1d2ccd12fc8a8"/></dir></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="16c35ebeecaac1fdfb78b39fbfef8877"/><file name="config.xml" hash="d67a60ccf310829c26bdecd2eac5b745"/><file name="system.xml" hash="771dbf0516800e9005ed8a6d7e46ef5a"/></dir><dir name="sql"><dir name="ampersand_paymentgateway_setup"><file name="mysql4-upgrade-0.0.1-0.0.2.php" hash="b96f410245acdab1bac40be098cdf4ce"/><file name="mysql4-upgrade-0.0.9-0.0.10.php" hash="38eef68653f1a67fde4a2052d7689026"/><file name="mysql4-upgrade-0.0.2-0.0.3.php" hash="cd17a587f66e754b93038ba15aedf3a6"/><file name="mysql4-upgrade-0.0.12-0.0.13.php" hash="518960f36caf0083ba21657a18e08ccf"/><file name="mysql4-upgrade-0.0.5-0.0.6.php" hash="10082a8a8f0c087de164e99cf98f0f57"/><file name="mysql4-upgrade-0.0.7-0.0.8.php" hash="2bd23a19b2f5f95c317422965fc28e47"/><file name="mysql4-upgrade-0.0.4-0.0.5.php" hash="1c86fbd3c84be59c3c04a74e6f7d52c2"/><file name="mysql4-upgrade-0.0.8-0.0.9.php" hash="9e5e4daa4696083b1a2ce899c7b10a7c"/><file name="mysql4-install-0.0.1.php" hash="6496424212e5efd6e4cc5475b0daef07"/><file name="mysql4-upgrade-0.0.11-0.0.12.php" hash="d395b9cf9f98d8aeefd0d5817e3fd819"/><file name="mysql4-upgrade-0.0.10-0.0.11.php" hash="f29952c10a05f075d8afb73fd0d2468f"/><file name="mysql4-upgrade-0.0.3-0.0.4.php" hash="b43beea075582cfa471dd4ce2ec394ce"/><file name="mysql4-upgrade-0.0.6-0.0.7.php" hash="04f939ff1119ef282290256eb58229d9"/><file name="mysql4-upgrade-0.0.13-0.0.14.php" hash="a5bb6ff4cccb9e6302c6a0cd6ffd77e3"/></dir></dir><dir name="controllers"><dir name="Adminhtml"><dir name="Subscription"><file name="OrderController.php" hash="ddf95460175eccc37243df6e735290bc"/></dir><file name="SubscriptionController.php" hash="07bd75822d2bb18b953fca59ea9fc597"/></dir><dir name="Checkout"><dir name="Cart"><file name="SubscriptionController.php" hash="a7f345974379aff4803449df8c8cbf70"/></dir><file name="OnepageController.php" hash="21b5e60937833c31bcb9e0a136ced557"/></dir><dir name="Customer"><dir name="Account"><file name="SubscriptionController.php" hash="0a42fdbb7fd147f39e89c1f30e95ffee"/></dir></dir><file name="RedirectController.php" hash="35364646b7e0575e4e8c94d20f64bbc5"/></dir><dir name="Helper"><file name="Subscription.php" hash="1ae9df0ec8d95a679f61b07233f275f7"/><file name="Data.php" hash="2faf1fce37e89ab5921b0312c360cb01"/></dir><dir name="Model"><dir name="Exception"><file name="Error.php" hash="4ac369ee913575b427c6d15ff60ca27c"/><file name="DenyPayment.php" hash="b0c0b45291d220e490526ffd68e8dfc4"/></dir><dir name="Utility"><file name="Cleanup.php" hash="adb699e432fd13a81112ccb84952e570"/><file name="Subscription.php" hash="d03077eaf0873032cc5380b4574aea5a"/></dir><dir name="Resource"><dir name="Subscription"><dir name="Order"><file name="Collection.php" hash="9794d1183d0ffc7ce313e74170330c07"/></dir><file name="Order.php" hash="2958956cff03a6358c648bf5ecea564e"/><file name="Collection.php" hash="d316d3cf47157d2b4cdf1e5d2873ac08"/></dir><dir name="Agreement"><file name="Collection.php" hash="62e57e9e152d3fb54b0af1fdfd3776f4"/></dir><dir name="Transaction"><file name="Collection.php" hash="8b7be054183ad76cfb9c6b7c27595fbc"/></dir><file name="Agreement.php" hash="dcfc1ec7df22bd0ce24b64d332021e5a"/><file name="Subscription.php" hash="f5f927e1793f44fa384eb2aead41ee81"/><file name="Transaction.php" hash="7ca37cc46a5b24faa7658a61e47633e2"/></dir><dir name="Compatibility"><dir name="Mage"><dir name="Sales"><dir name="Model"><dir name="Order"><file name="Payment.php" hash="25de73c00d619ec65c2696906b35dfad"/></dir></dir></dir></dir></dir><dir name="Service"><dir name="Redirect"><file name="AgreementAbstract.php" hash="591733d0e48090a85899bf3701c1b0bc"/></dir><dir name="Direct"><file name="AgreementAbstract.php" hash="20ca0bebc7bceb30e0433aa316a5ed28"/></dir><file name="RedirectAbstract.php" hash="58ce2bcaa0197decba0bd17667e459fe"/><file name="Abstract.php" hash="3883464fa60b108b68a7ab5e3ee1553d"/><file name="DirectAbstract.php" hash="300c7144e500fd3e11489f2ef1b778c4"/></dir><dir name="Subscription"><file name="Order.php" hash="07c91afd16d567c6dcddee9374be97c8"/></dir><dir name="Method"><file name="RedirectAbstract.php" hash="fed166e8061a60c3730ace82612b343f"/><file name="AgreementAbstract.php" hash="73f51504d57b40de32a985e9c6d44465"/><file name="DirectAbstract.php" hash="41b092dfb0cfde9416d391c9e4b95ee5"/></dir><dir name="Adapter"><dir name="Redirect"><dir name="Agreement"><file name="ManageInterface.php" hash="06223d8ed9a015bf832450d829e4fd48"/></dir><file name="AuthCaptureInterface.php" hash="09405bde3024517a956a237b894f1808"/><file name="RefundInterface.php" hash="cb010029d08a9c1498356beea30f6627"/><file name="PartialInterface.php" hash="0593ecac5b49059960c7b185d550541e"/></dir><dir name="Direct"><dir name="Agreement"><file name="ManageInterface.php" hash="bfffa9aa8a4a5e5e1bba5d78a7475250"/></dir><file name="AuthCaptureInterface.php" hash="bea835c956bcf5c55a93074848e14a48"/><file name="RefundInterface.php" hash="b200ea17ac958bee2eefd5294ac4052e"/><file name="PartialInterface.php" hash="7b9b9f62e1b4ed310d281921f183b70d"/></dir><file name="Abstract.php" hash="a126350c16d111552caba7c422a3100d"/><file name="Interface.php" hash="887febfe4eafd98f285f9b6082462667"/></dir><dir name="Config"><file name="Abstract.php" hash="ebc3c7e63825c7e297ff9f19e8a10e1c"/></dir><dir name="Source"><file name="PaymentAction.php" hash="d94d62d900aac83e8bba6fe5d3459a70"/><file name="SubscriptionPeriods.php" hash="fdab5f7c2fdbb5f389facf94b9dae123"/><file name="AgreementMethod.php" hash="56add32f8838ac9a169c64ed6baa3318"/><file name="OrderStatus.php" hash="8a84a227a49229162a0310d604529165"/><file name="CardType.php" hash="b715c5b5605d84ce6561cc40418010ec"/></dir><file name="Email.php" hash="e03cb77df1a3d0fec0da4ebe26af2221"/><file name="Versioning.php" hash="ccf112f9a2e0a0c70003895989d42752"/><file name="Agreement.php" hash="f595fcd31730466fc8d11589d1e93f15"/><file name="Subscription.php" hash="0b8078fd132bd6290714aad293dfb332"/><file name="Transaction.php" hash="971544deae8e8cc4036e1f2fe9685435"/><file name="Cron.php" hash="3b53d7479628f06f769abbc53a6404e0"/><file name="Observer.php" hash="8f5d8cd814b821284c31ac7ba916f874"/></dir><file name="changelog.txt" hash="b15397608cc300b4a64c9e55f7b7ff02"/></dir></dir></target><target name="magedesign"><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><file name="ampersand_paymentgateway.xml" hash="3b70309300dfed71a62b73578869fc5d"/></dir><dir name="template"><dir name="ampersand_paymentgateway"><dir name="customer"><dir name="account"><file name="subscription.phtml" hash="73825035ff1e2b1bf17f85502317acc9"/></dir></dir><dir name="redirect"><file name="iframe.phtml" hash="129820e210e01662bab8afd5f24fac7d"/><file name="location.phtml" hash="aef0c86a5dea767c81b287b7ba8551d0"/><file name="form.phtml" hash="42f2ddb4f1473271d8ec5c3cd9814654"/></dir><dir name="payment"><dir name="form"><file name="billing-agreement-cv2.phtml" hash="f41a166c9d7b9b6cb780e0304890504b"/><file name="billing-agreement-checkbox.phtml" hash="57c5e2d3813acaaf6c054adb5cfd0d5f"/><file name="redirect.phtml" hash="1decc25cf3907d7ef05be8748aea6322"/></dir></dir><dir name="sales"><dir name="payment"><dir name="form"><dir name="billing"><file name="agreement.phtml" hash="fc256f93338c1a244efb0a74a27e11fb"/></dir></dir></dir></dir><dir name="checkout"><dir name="cart"><file name="subscription.phtml" hash="0bf84cb7a162e8b4936e261752b6c20e"/></dir><dir name="onepage"><dir name="review"><file name="subscription.phtml" hash="f3cc1076c65ee3ae0e959888b39b54c1"/></dir></dir></dir></dir></dir></dir></dir></dir><dir name="adminhtml"><dir name="base"><dir name="default"><dir name="layout"><file name="ampersand_paymentgateway.xml" hash="b7dfcf1a57cf6d79d261ad91d266db2e"/></dir><dir name="template"><dir name="ampersand_paymentgateway"><dir name="system"><dir name="config"><dir name="fieldset"><file name="hint.phtml" hash="3f10f63632a280153a96ec9f90784568"/></dir></dir></dir></dir></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Ampersand_PaymentGateway.xml" hash="80480a17487715a70e009757cd3c3dfe"/><file name="Ampersand_BillingAgreementFix.xml" hash="1d213328275ec29e62a7f580b7926604"/></dir></target><target name="magelocale"><dir name="en_US"><dir name="template"><dir name="email"><dir name="ampersand_paymentgateway"><file name="subscription_reminder.html" hash="79262315a694fcb63de89baf66ef6ce6"/><file name="notification.html" hash="dea93b8b048571ac1a527260838b15fd"/></dir></dir></dir></dir></target><target name="mageskin"><dir name="frontend"><dir name="base"><dir name="default"><dir name="ampersand_paymentgateway"><dir name="css"><file name="checkout.css" hash="dfa4f36777bb549531f550d32e25d96e"/><file name="cart.css" hash="65dc2c9e22a28242060f23871af9c38e"/></dir></dir></dir></dir></dir><dir name="adminhtml"><dir name="base"><dir name="default"><dir name="ampersand_paymentgateway"><dir name="images"><file name="logo.gif" hash="098947bdb00786d3632235ff1cebb9c6"/></dir><dir name="css"><file name="styles.css" hash="587ac33018919b134d96b04ea98b6359"/></dir></dir></dir></dir></dir></target><target name="mageweb"><dir name="js"><dir name="ampersand_paymentgateway"><file name="validation.js" hash="33042d5bd59da47ea0ba00af24f86894"/></dir></dir></target></contents>
16
+ <compatible/>
17
+ <dependencies/>
18
+ </package>
skin/adminhtml/base/default/ampersand_paymentgateway/css/styles.css ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* System > Config > Payments > Hint */
2
+
3
+ .ampersand-paymentgateway-payment-notice {
4
+ margin-top: 10px;
5
+ border: 1px solid #CCC;
6
+ padding: 10px 5px 5px 185px;
7
+ background: #FFF url("../images/logo.gif") 5px center no-repeat;
8
+ }
9
+
10
+ .ampersand-paymentgateway-payment-notice h4 {
11
+ margin: 0px;
12
+ }
13
+
14
+ .ampersand-paymentgateway-payment-notice p {
15
+ margin: 0px;
16
+ }
skin/adminhtml/base/default/ampersand_paymentgateway/images/logo.gif ADDED
Binary file
skin/frontend/base/default/ampersand_paymentgateway/css/cart.css ADDED
@@ -0,0 +1 @@
 
1
+ .cart .subscription { margin: 0 0 20px 0; }
skin/frontend/base/default/ampersand_paymentgateway/css/checkout.css ADDED
@@ -0,0 +1,2 @@
 
 
1
+ .subscription-review { margin: 20px; }
2
+ .subscription-review p { font-weight: bold; }