Bronto_Extension - Version 2.3.0

Version Notes

For installation and configuration instructions, as well as a full list of new features and known issues, please review the Implementation Guide.

Download this release

Release Info

Developer Chris Geiss
Extension Bronto_Extension
Version 2.3.0
Comparing to
See all releases


Code changes from version 2.2.2 to 2.3.0

Files changed (168) hide show
  1. app/code/community/Bronto/Common/Block/Adminhtml/System/Config/Cron/Queue.php +23 -0
  2. app/code/community/Bronto/Common/Block/Adminhtml/System/Config/Guide.php +2 -0
  3. app/code/community/Bronto/Common/Block/Adminhtml/System/Config/Suppressed.php +14 -1
  4. app/code/community/Bronto/Common/Block/Adminhtml/System/Config/Suppressed/Reset.php +23 -0
  5. app/code/community/Bronto/Common/Block/Adminhtml/Widget/Queue/Button/Run.php +28 -0
  6. app/code/community/Bronto/Common/Block/Popup.php +11 -0
  7. app/code/community/Bronto/Common/Helper/Api.php +55 -0
  8. app/code/community/Bronto/Common/Helper/Contact.php +105 -4
  9. app/code/community/Bronto/Common/Helper/Data.php +51 -12
  10. app/code/community/Bronto/Common/Helper/Salesrule.php +2 -40
  11. app/code/community/Bronto/Common/Model/Email/Template.php +210 -142
  12. app/code/community/Bronto/Common/Model/Email/Template/Filter.php +232 -18
  13. app/code/community/Bronto/Common/Model/List.php +1 -1
  14. app/code/community/Bronto/Common/Model/Mysql4/Queue.php +27 -0
  15. app/code/community/Bronto/Common/Model/Mysql4/Queue/Collection.php +43 -0
  16. app/code/community/Bronto/Common/Model/Observer.php +108 -1
  17. app/code/community/Bronto/Common/Model/Queue.php +187 -0
  18. app/code/community/Bronto/Common/Model/Resource/Abstract.php +179 -0
  19. app/code/community/Bronto/Common/Model/Resource/Setup.php +75 -1
  20. app/code/community/Bronto/Common/Model/System/Config/Backend/Cron/Queue.php +7 -0
  21. app/code/community/Bronto/Common/Model/System/Config/Backend/Token.php +1 -1
  22. app/code/community/Bronto/Common/Model/System/Config/Source/Coupon.php +73 -0
  23. app/code/community/Bronto/Common/Model/System/Config/Source/Limit.php +2 -0
  24. app/code/community/Bronto/Common/Model/System/Config/Source/Related.php +53 -0
  25. app/code/community/Bronto/Common/controllers/Adminhtml/DebugController.php +13 -0
  26. app/code/community/Bronto/Common/etc/adminhtml.xml +4 -0
  27. app/code/community/Bronto/Common/etc/config.xml +22 -1
  28. app/code/community/Bronto/Common/etc/system.xml +186 -13
  29. app/code/community/Bronto/Common/sql/bronto_common_setup/mysql4-install-2.3.0.php +13 -0
  30. app/code/community/Bronto/Common/sql/bronto_common_setup/mysql4-upgrade-2.2.2-2.3.0.php +7 -0
  31. app/code/community/Bronto/Customer/Block/Adminhtml/System/Config/Cron.php +1 -0
  32. app/code/community/Bronto/Customer/Block/Adminhtml/System/Config/Suppressed.php +9 -1
  33. app/code/community/Bronto/Customer/Block/Adminhtml/Widget/Button/Mark.php +18 -0
  34. app/code/community/Bronto/Customer/Model/Observer.php +28 -15
  35. app/code/community/Bronto/Customer/controllers/Adminhtml/CustomerController.php +33 -0
  36. app/code/community/Bronto/Customer/etc/system.xml +11 -0
  37. app/code/community/Bronto/Email/Block/Adminhtml/System/Email/Import/Grid.php +13 -3
  38. app/code/community/Bronto/Email/Block/Adminhtml/System/Email/Import/Grid/Renderer/Action.php +2 -2
  39. app/code/community/Bronto/Email/Block/Adminhtml/System/Email/Template/Edit/Form.php +26 -2
  40. app/code/community/Bronto/Email/Block/Adminhtml/System/Email/Template/Grid.php +10 -19
  41. app/code/community/Bronto/Email/Helper/Data.php +27 -1
  42. app/code/community/Bronto/Email/Model/Mysql4/Template/Collection.php +14 -1
  43. app/code/community/Bronto/Email/Model/Observer.php +28 -0
  44. app/code/community/Bronto/Email/Model/Resource/Setup.php +68 -1
  45. app/code/community/Bronto/Email/Model/System/Config/Source/Email/Template.php +2 -2
  46. app/code/community/Bronto/Email/Model/Template/Import.php +5 -4
  47. app/code/community/Bronto/Email/Model/Template/Mailer.php +2 -22
  48. app/code/community/Bronto/Email/controllers/Adminhtml/System/Email/TemplateController.php +9 -3
  49. app/code/community/Bronto/Email/etc/config.xml +6 -1
  50. app/code/community/Bronto/Email/etc/system.xml +26 -0
  51. app/code/community/Bronto/Email/sql/bronto_email_setup/mysql4-install-1.2.0.php +13 -0
  52. app/code/community/Bronto/Email/sql/bronto_email_setup/mysql4-upgrade-1.1.9-1.2.0.php +7 -0
  53. app/code/community/Bronto/Emailcapture/Block/Emailcapture.php +2 -1
  54. app/code/community/Bronto/Newsletter/Block/Adminhtml/System/Config/Cron.php +1 -0
  55. app/code/community/Bronto/Newsletter/Block/Adminhtml/System/Config/Suppressed.php +9 -1
  56. app/code/community/Bronto/Newsletter/Block/Adminhtml/Widget/Button/Mark.php +18 -0
  57. app/code/community/Bronto/Newsletter/Block/Checkout/Onepage/Newsletter.php +20 -2
  58. app/code/community/Bronto/Newsletter/Helper/Data.php +26 -0
  59. app/code/community/Bronto/Newsletter/Model/Observer.php +20 -5
  60. app/code/community/Bronto/Newsletter/controllers/Adminhtml/NewsletterController.php +39 -16
  61. app/code/community/Bronto/Newsletter/controllers/IndexController.php +22 -1
  62. app/code/community/Bronto/Newsletter/etc/config.xml +10 -0
  63. app/code/community/Bronto/Newsletter/etc/system.xml +40 -0
  64. app/code/community/Bronto/Order/Block/Adminhtml/System/Config/Cron.php +1 -0
  65. app/code/community/Bronto/Order/Block/Adminhtml/System/Config/Suppressed.php +9 -1
  66. app/code/community/Bronto/Order/Block/Adminhtml/Widget/Button/Mark.php +18 -0
  67. app/code/community/Bronto/Order/Block/Redemption.php +47 -0
  68. app/code/community/Bronto/Order/Helper/Data.php +8 -0
  69. app/code/community/Bronto/Order/Model/Observer.php +29 -16
  70. app/code/community/Bronto/Order/Model/System/Config/Source/Bulk.php +18 -0
  71. app/code/community/Bronto/Order/controllers/Adminhtml/OrderController.php +37 -0
  72. app/code/community/Bronto/Order/etc/config.xml +1 -0
  73. app/code/community/Bronto/Order/etc/system.xml +26 -2
  74. app/code/community/Bronto/Product/Block/Adminhtml/System/Config/About.php +15 -0
  75. app/code/community/Bronto/Product/Block/Adminhtml/System/Config/Cron.php +25 -0
  76. app/code/community/Bronto/Product/Block/Adminhtml/System/Config/Information.php +17 -0
  77. app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation.php +81 -0
  78. app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Default.php +14 -0
  79. app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Edit.php +141 -0
  80. app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Edit/Button.php +58 -0
  81. app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Edit/Form.php +266 -0
  82. app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Grid.php +170 -0
  83. app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Grid/Renderer/Action.php +35 -0
  84. app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Grid/Renderer/Description.php +19 -0
  85. app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Grid/Renderer/Image.php +17 -0
  86. app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Grid/Renderer/Price.php +21 -0
  87. app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Grid/Renderer/Url.php +18 -0
  88. app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Message/Form.php +36 -0
  89. app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Preview.php +126 -0
  90. app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Preview/Form.php +83 -0
  91. app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Preview/Grid.php +164 -0
  92. app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Preview/GridElement.php +24 -0
  93. app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Selected/Grid.php +223 -0
  94. app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Selected/Js.php +23 -0
  95. app/code/community/Bronto/Product/Block/Adminhtml/Widget/Button/Run.php +28 -0
  96. app/code/community/Bronto/Product/Helper/Data.php +348 -0
  97. app/code/community/Bronto/Product/Model/Collect.php +75 -0
  98. app/code/community/Bronto/Product/Model/Collect/Abstract.php +204 -0
  99. app/code/community/Bronto/Product/Model/Collect/Bestseller.php +24 -0
  100. app/code/community/Bronto/Product/Model/Collect/Crosssell.php +22 -0
  101. app/code/community/Bronto/Product/Model/Collect/Custom.php +19 -0
  102. app/code/community/Bronto/Product/Model/Collect/Mostviewed.php +23 -0
  103. app/code/community/Bronto/Product/Model/Collect/New.php +35 -0
  104. app/code/community/Bronto/Product/Model/Collect/Recentlyviewed.php +22 -0
  105. app/code/community/Bronto/Product/Model/Collect/Related.php +22 -0
  106. app/code/community/Bronto/Product/Model/Collect/Upsell.php +22 -0
  107. app/code/community/Bronto/Product/Model/Content.php +25 -0
  108. app/code/community/Bronto/Product/Model/Filter.php +96 -0
  109. app/code/community/Bronto/Product/Model/Mysql4/Recommendation.php +12 -0
  110. app/code/community/Bronto/Product/Model/Mysql4/Recommendation/Collection.php +91 -0
  111. app/code/community/Bronto/Product/Model/Observer.php +119 -0
  112. app/code/community/Bronto/Product/Model/Recommendation.php +225 -0
  113. app/code/community/Bronto/Product/Model/Resource/Setup.php +52 -0
  114. app/code/community/Bronto/Product/Model/System/Config/Cron.php +7 -0
  115. app/code/community/Bronto/Product/Model/System/Config/Source/Recommendation.php +61 -0
  116. app/code/community/Bronto/Product/controllers/Adminhtml/RecommendationsController.php +490 -0
  117. app/code/community/Bronto/Product/etc/adminhtml.xml +46 -0
  118. app/code/community/Bronto/Product/etc/config.xml +85 -0
  119. app/code/community/Bronto/Product/etc/system.xml +199 -0
  120. app/code/community/Bronto/Product/sql/bronto_product_setup/mysql4-install-1.0.0.php +14 -0
  121. app/code/community/Bronto/Reminder/Block/Adminhtml/Reminder/Edit/Tab/Customers.php +9 -0
  122. app/code/community/Bronto/Reminder/Block/Adminhtml/Reminder/Edit/Tab/General.php +10 -0
  123. app/code/community/Bronto/Reminder/Model/Email/Message.php +8 -0
  124. app/code/community/Bronto/Reminder/Model/Mysql4/Rule.php +8 -1
  125. app/code/community/Bronto/Reminder/Model/Resource/Setup.php +133 -0
  126. app/code/community/Bronto/Reminder/Model/Rule.php +15 -8
  127. app/code/community/Bronto/Reminder/controllers/LoadController.php +3 -0
  128. app/code/community/Bronto/Reminder/etc/config.xml +12 -1
  129. app/code/community/Bronto/Reminder/sql/bronto_reminder_setup/mysql4-install-1.4.17.php +13 -0
  130. app/code/community/Bronto/Reminder/sql/bronto_reminder_setup/mysql4-upgrade-1.4.16-1.4.17.php +7 -0
  131. app/code/community/Bronto/Reviews/Helper/Data.php +35 -9
  132. app/code/community/Bronto/Reviews/Model/Message.php +85 -0
  133. app/code/community/Bronto/Reviews/Model/Observer.php +33 -170
  134. app/code/community/Bronto/Reviews/Model/Queue.php +4 -5
  135. app/code/community/Bronto/Reviews/Model/System/Config/Source/Orderstatus.php +17 -7
  136. app/code/community/Bronto/Reviews/etc/system.xml +27 -1
  137. app/code/community/Bronto/Verify/Block/Adminhtml/System/Config/Form/Magecron.php +16 -8
  138. app/code/community/Bronto/Verify/Model/Core/Config.php +1 -1
  139. app/code/community/Bronto/Verify/Model/Path/Locator/IteratorAbstract.php +1 -1
  140. app/code/community/Bronto/Verify/Model/Roundtrip.php +2 -1
  141. app/code/community/Bronto/Verify/Model/System/Config/Backend/Magecron.php +2 -1
  142. app/code/community/Bronto/Verify/etc/config.xml +1 -0
  143. app/code/community/Bronto/Verify/etc/system.xml +25 -5
  144. app/design/adminhtml/default/default/layout/bronto/common.xml +2 -0
  145. app/design/adminhtml/default/default/template/bronto/api/guide.phtml +46 -5
  146. app/design/adminhtml/default/default/template/bronto/common/suppressed.phtml +13 -0
  147. app/design/adminhtml/default/default/template/bronto/coupon/guide.phtml +73 -0
  148. app/design/adminhtml/default/default/template/bronto/newsletter/guide.phtml +1 -1
  149. app/design/adminhtml/default/default/template/bronto/product/guide.phtml +191 -0
  150. app/design/adminhtml/default/default/template/bronto/product/recommendation/button.phtml +23 -0
  151. app/design/adminhtml/default/default/template/bronto/product/recommendation/default.phtml +50 -0
  152. app/design/adminhtml/default/default/template/bronto/product/recommendation/edit.phtml +58 -0
  153. app/design/adminhtml/default/default/template/bronto/product/recommendation/grid.phtml +12 -0
  154. app/design/adminhtml/default/default/template/bronto/product/recommendation/preview.phtml +110 -0
  155. app/design/adminhtml/default/default/template/bronto/product/recommendation/selected.js.phtml +107 -0
  156. app/design/frontend/base/default/layout/bronto/newsletter.xml +1 -1
  157. app/design/frontend/base/default/layout/bronto/order.xml +9 -0
  158. app/design/frontend/base/default/template/bronto/common/popup.phtml +12 -1
  159. app/design/frontend/base/default/template/bronto/emailcapture/js.phtml +1 -1
  160. app/design/frontend/base/default/template/bronto/newsletter/checkbox.phtml +2 -3
  161. app/design/frontend/base/default/template/bronto/newsletter/js.phtml +14 -8
  162. app/design/frontend/base/default/template/bronto/order/redemption.phtml +12 -0
  163. app/etc/modules/Bronto_Product.xml +12 -0
  164. package.xml +4 -4
  165. shell/bronto/cron.php +12 -0
  166. shell/bronto/fix.php +3 -1
  167. shell/bronto/rewrite.php +167 -0
  168. skin/adminhtml/base/default/bronto/cron.css +2 -2
app/code/community/Bronto/Common/Block/Adminhtml/System/Config/Cron/Queue.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Common_Block_Adminhtml_System_Config_Cron_Queue extends Bronto_Common_Block_Adminhtml_System_Config_Cron
4
+ {
5
+ protected $_jobCode = 'bronto_common_queue';
6
+
7
+ /**
8
+ * @see parent
9
+ */
10
+ protected function _prepareLayout()
11
+ {
12
+ $this->addButton($this->getLayout()->createBlock('bronto_common/adminhtml_widget_queue_button_run'));
13
+ return parent::_prepareLayout();
14
+ }
15
+
16
+ /**
17
+ * @see parent
18
+ */
19
+ public function showCronTable()
20
+ {
21
+ return Mage::helper('bronto_common/api')->queueCanUseMageCron();
22
+ }
23
+ }
app/code/community/Bronto/Common/Block/Adminhtml/System/Config/Guide.php CHANGED
@@ -22,7 +22,9 @@ class Bronto_Common_Block_Adminhtml_System_Config_Guide extends Mage_Adminhtml_B
22
  'bronto_reminder',
23
  'bronto_email',
24
  'bronto_verify',
 
25
  'bronto_popup',
 
26
  'bronto_reviews',
27
  );
28
 
22
  'bronto_reminder',
23
  'bronto_email',
24
  'bronto_verify',
25
+ 'bronto_coupon',
26
  'bronto_popup',
27
+ 'bronto_product',
28
  'bronto_reviews',
29
  );
30
 
app/code/community/Bronto/Common/Block/Adminhtml/System/Config/Suppressed.php CHANGED
@@ -37,8 +37,11 @@ class Bronto_Common_Block_Adminhtml_System_Config_Suppressed
37
  $this->setElement($element);
38
  $html = $this->_getHeaderHtml($element);
39
 
40
- $html .= $this->toHtml();
 
 
41
 
 
42
  $html .= $this->_getFooterHtml($element);
43
 
44
  return $html;
@@ -54,6 +57,16 @@ class Bronto_Common_Block_Adminhtml_System_Config_Suppressed
54
  return '';
55
  }
56
 
 
 
 
 
 
 
 
 
 
 
57
  /**
58
  * The Suppression interface is always collapsed
59
  *
37
  $this->setElement($element);
38
  $html = $this->_getHeaderHtml($element);
39
 
40
+ foreach ($element->getSortedElements() as $elem) {
41
+ $html .= $elem->toHtml();
42
+ }
43
 
44
+ $html .= $this->toHtml();
45
  $html .= $this->_getFooterHtml($element);
46
 
47
  return $html;
57
  return '';
58
  }
59
 
60
+ /**
61
+ * Get URL for reset AJAX call
62
+ *
63
+ * @return string
64
+ */
65
+ public function getResetUrl()
66
+ {
67
+ return '';
68
+ }
69
+
70
  /**
71
  * The Suppression interface is always collapsed
72
  *
app/code/community/Bronto/Common/Block/Adminhtml/System/Config/Suppressed/Reset.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Common_Block_Adminhtml_System_Config_Suppressed_Reset extends Bronto_Common_Block_Adminhtml_Widget_Button_Abstract implements Varien_Data_Form_Element_Renderer_Interface
4
+ {
5
+ /**
6
+ * @see parent
7
+ */
8
+ protected function _setUp()
9
+ {
10
+ $this->setOnClick('resetAllSuppressed(); return false;');
11
+ $this->setClass('delete');
12
+ $this->setStyle('margin-bottom: 10px');
13
+ }
14
+
15
+ /**
16
+ * @see parent
17
+ */
18
+ public function render(Varien_Data_Form_Element_Abstract $element)
19
+ {
20
+ $this->setLabel($element->getLabel());
21
+ return $this->toHtml();
22
+ }
23
+ }
app/code/community/Bronto/Common/Block/Adminhtml/Widget/Queue/Button/Run.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Common_Block_Adminhtml_Widget_Queue_Button_Run extends Mage_Adminhtml_Block_Widget_Button
4
+ {
5
+ /**
6
+ * @see parent
7
+ */
8
+ protected function _construct()
9
+ {
10
+ $this->setLabel('Run Now');
11
+ $this->setOnClick("setLocation('" . $this->getRunUrl() . "'); return false;");
12
+ $this->setClass('bronto-cron-run');
13
+
14
+ if (!Mage::helper('bronto_common/api')->canUseQueue()) {
15
+ $this->setDisabled(true)->setClass('disabled');
16
+ }
17
+ }
18
+
19
+ /**
20
+ * Get the run url for the API send queue
21
+ *
22
+ * @return string
23
+ */
24
+ public function getRunUrl()
25
+ {
26
+ return $this->getUrl('*/debug/send');
27
+ }
28
+ }
app/code/community/Bronto/Common/Block/Popup.php CHANGED
@@ -15,4 +15,15 @@ class Bronto_Common_Block_Popup extends Mage_Core_Block_Template
15
  {
16
  return Mage::helper('bronto_common')->getPopupCode();
17
  }
 
 
 
 
 
 
 
 
 
 
 
18
  }
15
  {
16
  return Mage::helper('bronto_common')->getPopupCode();
17
  }
18
+
19
+ /**
20
+ * Gets the Pop-up submission URL
21
+ *
22
+ * @return string
23
+ */
24
+ public function getPopupSubmitUrl()
25
+ {
26
+ $store = Mage::app()->getStore();
27
+ return Mage::getUrl('btnewsletter/index/submit', array('_secure' => $store->isCurrentlySecure()));
28
+ }
29
  }
app/code/community/Bronto/Common/Helper/Api.php CHANGED
@@ -11,6 +11,15 @@ class Bronto_Common_Helper_Api extends Bronto_Common_Helper_Data
11
  const XML_PATH_FREQUENCY_MIN = 'bronto_api/settings/minutes';
12
  const XML_PATH_ERROR_THRES = 'bronto_api/setting/limit';
13
 
 
 
 
 
 
 
 
 
 
14
  const XML_PATH_SOAP_CLIENT = 'bronto_api/soap_options/soap_client';
15
  const XML_PATH_API_OBSERVER = 'bronto_api/soap_options/observer';
16
  const XML_PATH_API_RETRYER = 'bronto_api/soap_options/retryer';
@@ -33,6 +42,16 @@ class Bronto_Common_Helper_Api extends Bronto_Common_Helper_Data
33
  return $this->__('Bronto API Retry');
34
  }
35
 
 
 
 
 
 
 
 
 
 
 
36
  /**
37
  * Checks if the api retryer is enabled
38
  *
@@ -43,6 +62,42 @@ class Bronto_Common_Helper_Api extends Bronto_Common_Helper_Data
43
  return (bool) $this->getAdminScopedConfig(self::XML_PATH_ENABLED);
44
  }
45
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  /**
47
  * Gets the entries whose attempts are less than this amount
48
  *
11
  const XML_PATH_FREQUENCY_MIN = 'bronto_api/settings/minutes';
12
  const XML_PATH_ERROR_THRES = 'bronto_api/setting/limit';
13
 
14
+
15
+ const XML_PATH_QUEUE_ENABLED = 'bronto_api/queue_settings/enabled';
16
+ const XML_PATH_QUEUE_MAGE_CRON = 'bronto_api/queue_settings/mage_cron';
17
+ const XML_PATH_QUEUE_LIMIT = 'bronto_api/queue_settings/limit';
18
+ const XML_PATH_QUEUE_TIME = 'bronto_api/queue_settings/time';
19
+ const XML_PATH_QUEUE_INTERVAL = 'bronto_api/queue_settings/interval';
20
+ const XML_PATH_QUEUE_FREQUENCY = 'bronto_api/queue_settings/frequency';
21
+ const XML_PATH_QUEUE_FREQUENCY_MIN = 'bronto_api/queue_settings/minutes';
22
+
23
  const XML_PATH_SOAP_CLIENT = 'bronto_api/soap_options/soap_client';
24
  const XML_PATH_API_OBSERVER = 'bronto_api/soap_options/observer';
25
  const XML_PATH_API_RETRYER = 'bronto_api/soap_options/retryer';
42
  return $this->__('Bronto API Retry');
43
  }
44
 
45
+ /**
46
+ * Gets the Canonical name of the Send Queue
47
+ *
48
+ * @return string
49
+ */
50
+ public function getSendName()
51
+ {
52
+ return $this->__('Bronto Send Queue');
53
+ }
54
+
55
  /**
56
  * Checks if the api retryer is enabled
57
  *
62
  return (bool) $this->getAdminScopedConfig(self::XML_PATH_ENABLED);
63
  }
64
 
65
+ /**
66
+ * Checked if the send queue is enabled
67
+ *
68
+ * @param string $scope
69
+ * @param int $scopeId
70
+ * @return bool
71
+ */
72
+ public function canUseQueue($scope = 'default', $scopeId = 0)
73
+ {
74
+ return (bool) $this->getAdminScopedConfig(self::XML_PATH_QUEUE_ENABLED, $scope, $scopeId);
75
+ }
76
+
77
+ /**
78
+ * Check if the cron is magento
79
+ *
80
+ * @param string $scope
81
+ * @param int $scopeId
82
+ * @return bool
83
+ */
84
+ public function queueCanUseMageCron($scope = 'default', $scopeId = 0)
85
+ {
86
+ return (bool) $this->getAdminScopedConfig(self::XML_PATH_QUEUE_MAGE_CRON, $scope, $scopeId);
87
+ }
88
+
89
+ /**
90
+ * Gets the send queue threshold
91
+ *
92
+ * @param string $scope
93
+ * @param int $scopeId
94
+ * @return int
95
+ */
96
+ public function getSendLimit($scope = 'default', $scopeId = 0)
97
+ {
98
+ return (int) $this->getAdminScopedConfig(self::XML_PATH_QUEUE_LIMIT, $scope, $scopeId);
99
+ }
100
+
101
  /**
102
  * Gets the entries whose attempts are less than this amount
103
  *
app/code/community/Bronto/Common/Helper/Contact.php CHANGED
@@ -40,6 +40,61 @@ class Bronto_Common_Helper_Contact extends Bronto_Common_Helper_Data
40
  return $contact;
41
  }
42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  /**
44
  * @param Bronto_Api_Contact_Row $contact
45
  * @param bool $persistOnly
@@ -62,12 +117,58 @@ class Bronto_Common_Helper_Contact extends Bronto_Common_Helper_Data
62
  } catch (Exception $e) {
63
  $this->writeError($e);
64
  }
 
65
  }
66
 
67
- $this->writeVerboseDebug('===== CONTACT SAVE =====', 'bronto_common_api.log');
68
- $this->writeVerboseDebug(var_export($contact->getApi()->getLastRequest(), true), 'bronto_common_api.log');
69
- $this->writeVerboseDebug(var_export($contact->getApi()->getLastResponse(), true), 'bronto_common_api.log');
70
-
71
  return $contact;
72
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  }
40
  return $contact;
41
  }
42
 
43
+ /**
44
+ * A more efficient way to read multiple emails from Bronto
45
+ *
46
+ * @param array $emails
47
+ * @param string $customSource (Optiona)
48
+ * @param int $store (Optional)
49
+ * @param bool $createNonExistent (Optional)
50
+ *
51
+ * @return array Bronto_Api_Contact_Row
52
+ */
53
+ public function getContactsByEmail($emails, $customSource = null, $store = null, $createNonExistent = false)
54
+ {
55
+ if (empty($emails)) {
56
+ return false;
57
+ }
58
+
59
+ $api = $this->getApi(null, 'store', $store);
60
+ $contactObject = $api->getContactObject();
61
+ $filter = array(
62
+ 'type' => 'OR',
63
+ 'email' => array(),
64
+ );
65
+ foreach ($emails as $email) {
66
+ $filter['email'][] = array(
67
+ 'operator' => 'EqualTo',
68
+ 'value' => $email
69
+ );
70
+ }
71
+
72
+ $results = $contactObject->readAll($filter);
73
+ if (count($results) != count($emails)) {
74
+ $contacts = array();
75
+ foreach ($results as $contact) {
76
+ $contacts[$contact->email] = $contact;
77
+ }
78
+
79
+ $newContacts = array();
80
+ foreach ($emails as $email) {
81
+ if (!isset($contacts[$email])) {
82
+ $contact = $contactObject->createRow(array('email' => $email));
83
+ $contact->customSource = $customSource;
84
+ $newContacts[$email] = $contact;
85
+ }
86
+ }
87
+
88
+ if ($createNonExistent) {
89
+ return $contacts + $this->saveContacts($newContacts);
90
+ } else {
91
+ return $contacts + $newContacts;
92
+ }
93
+ } else {
94
+ return $results;
95
+ }
96
+ }
97
+
98
  /**
99
  * @param Bronto_Api_Contact_Row $contact
100
  * @param bool $persistOnly
117
  } catch (Exception $e) {
118
  $this->writeError($e);
119
  }
120
+ $this->_flushApiLogs($contact->getApi());
121
  }
122
 
 
 
 
 
123
  return $contact;
124
  }
125
+
126
+ /**
127
+ * More efficient way add saving multiple contacts
128
+ *
129
+ * @param array Bronto_Api_Contact_Row
130
+ * @return array Bronto_Api_Contact_Row
131
+ */
132
+ public function saveContacts($contacts)
133
+ {
134
+ $contactObject = null;
135
+ $lookupTable = array();
136
+ foreach ($contacts as $index => $contact) {
137
+ $contactObject = $contact->getApiObject();
138
+ $this->saveContact($contact, true);
139
+ $lookupTable[] = $index;
140
+ }
141
+
142
+ if ($contactObject) {
143
+ try {
144
+ $results = $contactObject->flush();
145
+ foreach ($results as $index => $result) {
146
+ $contact = $contacts[$lookupTable[$index]];
147
+ if ($result->hasError()) {
148
+ $this->writeError("Failed to create contact {$contact->email}: ({$result->getErrorCode()}): {$result->getErrorMessage()}");
149
+ $contact->error = $result->getErrorMessage();
150
+ } else {
151
+ $contact->id = $result->id;
152
+ }
153
+ }
154
+ } catch (Exception $e) {
155
+ $this->writeError($e);
156
+ }
157
+ $this->_flushApiLogs($contactObject->getApi());
158
+ }
159
+ return $contacts;
160
+ }
161
+
162
+ /**
163
+ * Writes the contact save logs
164
+ *
165
+ * @param Bronto_Api $api
166
+ * @return void
167
+ */
168
+ protected function _flushApiLogs($api)
169
+ {
170
+ $this->writeVerboseDebug('===== CONTACT SAVE =====', 'bronto_common_api.log');
171
+ $this->writeVerboseDebug(var_export($api->getLastRequest(), true), 'bronto_common_api.log');
172
+ $this->writeVerboseDebug(var_export($api->getLastResponse(), true), 'bronto_common_api.log');
173
+ }
174
  }
app/code/community/Bronto/Common/Helper/Data.php CHANGED
@@ -42,7 +42,13 @@ class Bronto_Common_Helper_Data
42
  /**
43
  * Pop-up Settings
44
  */
45
- const XML_PATH_POPUP_CODE = 'bronto_popup/settings/code';
 
 
 
 
 
 
46
 
47
  /**
48
  * Module Human Readable Name
@@ -104,6 +110,26 @@ class Bronto_Common_Helper_Data
104
  return $this->getAdminScopedConfig(self::XML_PATH_POPUP_CODE);
105
  }
106
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  /**
108
  * Determine if email can be sent through bronto
109
  *
@@ -130,12 +156,16 @@ class Bronto_Common_Helper_Data
130
  */
131
  public function getProductImageUrl($product)
132
  {
133
- return (string)Mage::helper('catalog/image')
134
- ->init($product, $this->getImageType($product->getStoreId()))
135
- ->resize(
136
- $this->getImageWidth($product->getStoreId()),
137
- $this->getImageHeight($product->getStoreId())
138
- );
 
 
 
 
139
  }
140
 
141
  /**
@@ -285,7 +315,7 @@ class Bronto_Common_Helper_Data
285
  } else {
286
  $coreConfig->saveConfig($path, 0, $scope, $scopeId);
287
 
288
- if (!$this->isVersionMatch(Mage::getVersionInfo(), 1, array(4, 5, 9, 10))) {
289
  list($module) = explode('/', $path);
290
 
291
  $coreConfigData->setScope($scope)
@@ -849,19 +879,19 @@ class Bronto_Common_Helper_Data
849
  );
850
 
851
  // Update Scope based on what has been set
852
- if ($scopeParams['store']) {
853
  $store = Mage::app()->getStore($scopeParams['store']);
854
  if ($store->getId()) {
855
  $scopeParams['store_id'] = $store->getId();
856
  }
857
  $scopeParams['scope'] = 'store';
858
- } elseif ($scopeParams['website']) {
859
  $website = Mage::app()->getWebsite($scopeParams['website']);
860
  if ($website->getId()) {
861
  $scopeParams['website_id'] = $website->getId();
862
  }
863
  $scopeParams['scope'] = 'website';
864
- } elseif ($scopeParams['group']) {
865
  $group = Mage::app()->getGroup($scopeParams['group']);
866
  if ($group->getId()) {
867
  $scopeParams['group_id'] = $group->getId();
@@ -1088,13 +1118,19 @@ class Bronto_Common_Helper_Data
1088
  // current Magento version element
1089
  $internalMatch = false;
1090
  foreach ($value as $option) {
 
1091
  $operator = '==';
1092
  $compare = $option;
1093
 
1094
  // If the current compare value is an array,
1095
  // get the operator and value provided
1096
  if (is_array($option)) {
1097
- list ($operator, $compare) = $option;
 
 
 
 
 
1098
  }
1099
 
1100
  if ($index == 'edition') {
@@ -1119,6 +1155,9 @@ class Bronto_Common_Helper_Data
1119
  // Use version_compare to compare the Magento version to the
1120
  // Current compare version using the provided operator
1121
  $internalMatch = version_compare($mValue, $compare, $operator);
 
 
 
1122
  }
1123
 
1124
  if ($internalMatch) {
42
  /**
43
  * Pop-up Settings
44
  */
45
+ const XML_PATH_POPUP_CODE = 'bronto_popup/settings/code';
46
+ const XML_PATH_POPUP_SUBSCRIBE = 'bronto_popup/settings/subscribe';
47
+
48
+ /**
49
+ * Coupon Settings
50
+ */
51
+ const XML_PATH_COUPON_SITE_HASH = 'bronto_coupon/settings/site_hash';
52
 
53
  /**
54
  * Module Human Readable Name
110
  return $this->getAdminScopedConfig(self::XML_PATH_POPUP_CODE);
111
  }
112
 
113
+ /**
114
+ * Can the user be subscribed to magento?
115
+ *
116
+ * @return bool
117
+ */
118
+ public function isSubscribeToMagento()
119
+ {
120
+ return (bool) $this->getAdminScopedConfig(self::XML_PATH_POPUP_SUBSCRIBE);
121
+ }
122
+
123
+ /**
124
+ * Get Site has for the coupon redemption code
125
+ *
126
+ * @return string
127
+ */
128
+ public function getCouponSiteHash()
129
+ {
130
+ return $this->getAdminScopedConfig(self::XML_PATH_COUPON_SITE_HASH);
131
+ }
132
+
133
  /**
134
  * Determine if email can be sent through bronto
135
  *
156
  */
157
  public function getProductImageUrl($product)
158
  {
159
+ try {
160
+ return (string)Mage::helper('catalog/image')
161
+ ->init($product, $this->getImageType($product->getStoreId()))
162
+ ->resize(
163
+ $this->getImageWidth($product->getStoreId()),
164
+ $this->getImageHeight($product->getStoreId())
165
+ );
166
+ } catch (Exception $e) {
167
+ return '';
168
+ }
169
  }
170
 
171
  /**
315
  } else {
316
  $coreConfig->saveConfig($path, 0, $scope, $scopeId);
317
 
318
+ if (!$this->isVersionMatch(Mage::getVersionInfo(), 1, array(4, 5, array('edition' => 'Enterprise', 'major' => 9), 10))) {
319
  list($module) = explode('/', $path);
320
 
321
  $coreConfigData->setScope($scope)
879
  );
880
 
881
  // Update Scope based on what has been set
882
+ if ($scopeParams['store'] !== false) {
883
  $store = Mage::app()->getStore($scopeParams['store']);
884
  if ($store->getId()) {
885
  $scopeParams['store_id'] = $store->getId();
886
  }
887
  $scopeParams['scope'] = 'store';
888
+ } elseif ($scopeParams['website'] !== false) {
889
  $website = Mage::app()->getWebsite($scopeParams['website']);
890
  if ($website->getId()) {
891
  $scopeParams['website_id'] = $website->getId();
892
  }
893
  $scopeParams['scope'] = 'website';
894
+ } elseif ($scopeParams['group'] !== false) {
895
  $group = Mage::app()->getGroup($scopeParams['group']);
896
  if ($group->getId()) {
897
  $scopeParams['group_id'] = $group->getId();
1118
  // current Magento version element
1119
  $internalMatch = false;
1120
  foreach ($value as $option) {
1121
+ $edition = false;
1122
  $operator = '==';
1123
  $compare = $option;
1124
 
1125
  // If the current compare value is an array,
1126
  // get the operator and value provided
1127
  if (is_array($option)) {
1128
+ if (array_key_exists('edition', $option)) {
1129
+ $edition = $option['edition'];
1130
+ $compare = $option['major'];
1131
+ } else {
1132
+ list ($operator, $compare) = $option;
1133
+ }
1134
  }
1135
 
1136
  if ($index == 'edition') {
1155
  // Use version_compare to compare the Magento version to the
1156
  // Current compare version using the provided operator
1157
  $internalMatch = version_compare($mValue, $compare, $operator);
1158
+ if ($edition && $internalMatch) {
1159
+ $internalMatch = ($mageVersion['edition'] == $edition);
1160
+ }
1161
  }
1162
 
1163
  if ($internalMatch) {
app/code/community/Bronto/Common/Helper/Salesrule.php CHANGED
@@ -33,45 +33,7 @@ class Bronto_Common_Helper_Salesrule extends Bronto_Common_Helper_Data
33
  */
34
  public function getRuleOptionsArray()
35
  {
36
- $options = array();
37
-
38
- /** @var Mage_SalesRule_Model_Resource_Rule_Collection $rules */
39
- $rules = Mage::getModel('salesrule/rule')->getCollection();
40
-
41
- // If there are any rules
42
- if ($rules->count()) {
43
- // Cycle Through Rules
44
- foreach ($rules as $rule) {
45
- // If rule is not active, the from date or to date are invalid, or rule doesn't have a coupon just skip this rule
46
- if (
47
- !$rule->getIsActive() ||
48
- (!is_null($rule->getFromDate()) && $rule->getFromDate() > Mage::getModel('core/date')->date('Y-m-d')) ||
49
- (!is_null($rule->getToDate()) && $rule->getToDate() < Mage::getModel('core/date')->date('Y-m-d')) ||
50
- ($rule->getCouponType() == Mage_SalesRule_Model_Rule::COUPON_TYPE_NO_COUPON)
51
- ) {
52
- continue;
53
- }
54
-
55
- // Handle Coupon Label
56
- $couponLabel = '(Coupon: *Auto Generated*)';
57
- if ($couponCode = $rule->getPrimaryCoupon()->getCode()) {
58
- $couponLabel = "(Coupon: {$couponCode})";
59
- }
60
-
61
- // Build Option
62
- $options[] = array(
63
- 'label' => "{$rule->getName()} {$couponLabel}",
64
- 'value' => $rule->getRuleId(),
65
- );
66
- }
67
- }
68
-
69
- // Add -- None Selected -- Option
70
- array_unshift($options, array(
71
- 'label' => '-- None Selected --',
72
- 'value' => ''
73
- ));
74
-
75
- return $options;
76
  }
77
  }
33
  */
34
  public function getRuleOptionsArray()
35
  {
36
+ return Mage::getModel('bronto_common/system_config_source_coupon')
37
+ ->toOptionArray();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  }
39
  }
app/code/community/Bronto/Common/Model/Email/Template.php CHANGED
@@ -75,6 +75,60 @@ class Bronto_Common_Model_Email_Template extends Mage_Core_Model_Email_Template
75
  return $this->_templateFilter;
76
  }
77
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
  /**
79
  * Process email template code
80
  *
@@ -91,10 +145,11 @@ class Bronto_Common_Model_Email_Template extends Mage_Core_Model_Email_Template
91
  $processor->setStoreId($variables['subscriber']->getStoreId());
92
  }
93
 
94
- if ($message = $this->getMessage()) {
95
- $processor->setMessageId($message->id);
96
  }
97
 
 
98
  $processor->setVariables($variables);
99
  $processor->setAvailable($this->getVariablesOptionArray());
100
 
@@ -108,28 +163,81 @@ class Bronto_Common_Model_Email_Template extends Mage_Core_Model_Email_Template
108
  */
109
  public function isMessageValidForSend()
110
  {
111
- /* @var $message Bronto_Api_Message_Row */
112
- $message = $this->getMessage();
113
-
114
- if (!($message instanceOf Bronto_Api_Message_Row)) {
115
- Mage::helper($this->_helper)->writeError(' Invalid Message');
116
 
117
  return false;
118
  }
119
 
120
- if ($message->status != 'active') {
121
- Mage::helper($this->_helper)->writeError(' Message is not active: ' . $message->name);
122
 
123
- return false;
124
- }
 
 
 
 
 
 
 
 
 
125
 
126
- if (!($this->getSenderName() && $this->getSenderEmail())) {
127
- Mage::helper($this->_helper)->writeError(' Message cannot be sent: Sender Name or Email is not set');
 
 
 
128
 
129
- return false;
130
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
 
132
- return true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
  }
134
 
135
  /**
@@ -143,14 +251,20 @@ class Bronto_Common_Model_Email_Template extends Mage_Core_Model_Email_Template
143
  */
144
  public function send($email, $name = null, array $variables = array())
145
  {
 
 
 
 
 
 
146
  // If not set to go through Bronto, fall through to magento sending
147
  if (!Mage::helper($this->_helper)->canSendBronto($this, $variables['store']->getId())) {
148
  return parent::send($email, $name, $variables);
149
  }
150
 
151
  /* @var $message Bronto_Api_Message_Row */
152
- $message = $this->getMessage();
153
  $messageId = $this->getBrontoMessageId();
 
154
 
155
  // If messageId is empty, send through Magento
156
  if (empty($messageId)) {
@@ -175,100 +289,44 @@ class Bronto_Common_Model_Email_Template extends Mage_Core_Model_Email_Template
175
  $variables['email'] = reset($emails);
176
  $variables['name'] = reset($names);
177
 
178
- // Load Bronto Contact(s)
179
- $contacts = array();
180
- foreach ($emails as $key => $email) {
181
- Mage::helper('bronto_common/contact')->writeDebug(' Getting Contact Object for: ' . $email . ' - Store: ' . $variables['store']->getId());
182
- $contacts[$key] = Mage::helper('bronto_common/contact')->getContactByEmail($email, $this->_helper, $variables['store']->getId(), 2);
183
- }
184
-
185
- $deliveryCount = 0;
186
- $deliveryErrors = 0;
187
-
188
- /* @var $contact Bronto_Api_Contact_Row */
189
- foreach ($contacts as $contact) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
190
  try {
191
- // If contact does not have id, create contact, if still no id, log it
192
- if (!$contact->id || empty($contact->id)) {
193
- $contact = Mage::helper('bronto_common/contact')->saveContact($contact);
194
- if (!$contact->id || empty($contact->id)) {
195
- $this->_beforeSend($contact, $message);
196
- $deliveryErrors++;
197
- Mage::helper($this->_helper)->writeDebug(' TEST MODE: Skipping e-mail: ' . $contact->email);
198
- $this->_afterSend(0, "TEST MODE ENABLED: Contact does not exist: " . $contact->email);
199
- continue;
200
- }
201
- }
202
-
203
- // Trigger _beforeSend action for logging
204
- $this->_beforeSend($contact, $message);
205
-
206
- /* @var $deliveryObject Bronto_Api_Delivery */
207
- Mage::helper($this->_helper)->writeDebug(' Getting Delivery Object...');
208
- $client = Mage::helper($this->_helper)
209
- ->getApi(null, 'store', $variables['store']->getId());
210
-
211
- $deliveryObject = Mage::getModel('bronto_common/delivery', array(
212
- 'api' => $client,
213
- 'email_class' => $this->_emailClass()
214
- ));
215
- $deliveryCount++;
216
- Mage::helper($this->_helper)->writeDebug(' Delivery Object Created Successfully');
217
-
218
- Mage::helper($this->_helper)->writeDebug(' Creating Delivery Row...');
219
- /* @var $delivery Bronto_Api_Delivery_Row */
220
- $delivery = $deliveryObject->createRow();
221
- $delivery->start = Mage::getModel('core/date')->date('c');
222
- $delivery->messageId = $message->id;
223
-
224
- $delivery->type = $this->getTemplateSendType() ? $this->getTemplateSendType() : 'transactional';
225
- $delivery->fromEmail = $this->getSenderEmail();
226
- $delivery->fromName = $this->getSenderName();
227
- $delivery->replyEmail = $this->getSenderEmail();
228
- $recipients = array(
229
- array(
230
- 'type' => 'contact',
231
- 'id' => $contact->id,
232
- 'deliveryType' => 'selected'
233
- ),
234
- );
235
- foreach (Mage::getModel('bronto_common/list', $this->_helper)
236
- ->addAdditionalRecipients($variables['store']->getId()) as $exclude) {
237
- $recipients[] = $exclude;
238
- }
239
- $delivery->recipients = $recipients;
240
-
241
- Mage::helper($this->_helper)->writeDebug(' Processing Delivery');
242
- $delivery = $this->getProcessedDelivery($delivery, $variables);
243
- Mage::helper($this->_helper)->writeDebug(' Saving Delivery...');
244
-
245
- $delivery->save();
246
-
247
- if ($delivery->id) {
248
- $this->setLastDeliveryId($delivery->id);
249
- $this->_afterSend(true, null, $delivery);
250
- } else {
251
- $deliveryErrors++;
252
- $this->_afterSend(false, null, $delivery);
253
- }
254
  } catch (Exception $e) {
255
- $errorMessage = $e->getMessage();
256
- if ($e->getCode() === Bronto_Api_Delivery_Exception::MESSAGE_NOT_TRANSACTIONAL_APPROVED) {
257
- // Replace message id with message name
258
- if (preg_match_all("/([a-zA-Z0-9\-]){36}/", $errorMessage, $matches)) { // Grab field id if exists
259
- foreach ($matches[0] as $match) {
260
- $errorMessage = str_replace($match, $message->name, $errorMessage);
261
- }
262
- }
263
- }
264
-
265
- $deliveryErrors++;
266
- Mage::helper($this->_helper)->writeError($errorMessage);
267
- $this->_afterSend(false, $errorMessage, isset($delivery) ? $delivery : null);
268
  }
 
 
269
  }
270
-
271
- return $deliveryErrors == 0;
272
  }
273
 
274
  /**
@@ -295,7 +353,7 @@ class Bronto_Common_Model_Email_Template extends Mage_Core_Model_Email_Template
295
  return parent::sendTransactional($templateId, $sender, $email, $name, $vars, $storeId);
296
  } else {
297
  // If module enabled and template ID is not an instance of the api row, see if we can pull an instance
298
- if (!($templateId instanceOf Bronto_Api_Message_Row)) {
299
  $emailTemplate = Mage::getModel('bronto_email/template')
300
  ->setDesignConfig($this->getDesignConfig()->getData());
301
 
@@ -312,24 +370,8 @@ class Bronto_Common_Model_Email_Template extends Mage_Core_Model_Email_Template
312
  return parent::sendTransactional($templateId, $sender, $email, $name, $vars, $storeId);
313
  }
314
 
315
- // Load Store
316
- $store = Mage::getModel('core/store')->load($storeId);
317
-
318
- // Load Bronto Message
319
- /* @var $messageObject Bronto_Api_Message */
320
- $messageObject = Mage::helper('bronto_common/message')->getApi(null, 'store', $store->getId())->getMessageObject();
321
-
322
- // Load Message
323
- try {
324
- /* @var $message Bronto_Api_Message_Row */
325
- $message = $messageObject->createRow();
326
- $message->id = $emailTemplate->getBrontoMessageId();
327
- $message->read();
328
- } catch (Exception $e) {
329
- Mage::helper($this->_helper)->writeDebug('Falling Back to Magento Sending: Message Not Found.' /* . $e*/);
330
-
331
- return parent::sendTransactional($templateId, $sender, $email, $name, $vars, $storeId);
332
- }
333
 
334
  // Send through main template model
335
  $emailTemplate->sendTransactional(
@@ -343,7 +385,7 @@ class Bronto_Common_Model_Email_Template extends Mage_Core_Model_Email_Template
343
 
344
  return $this->setSentSuccess($emailTemplate->getSentSuccess());
345
  } else {
346
- $message = $templateId;
347
  }
348
  }
349
 
@@ -353,11 +395,6 @@ class Bronto_Common_Model_Email_Template extends Mage_Core_Model_Email_Template
353
  $storeId = $this->getDesignConfig()->getStore();
354
  }
355
 
356
- $this->setMessage($message);
357
- $this->setBrontoMessageId($message->id);
358
- $this->setBrontoMessageName($message->name);
359
- $this->setBrontoMessageApproved(1);
360
-
361
  // If $sender is not array, it is a reference to a config setting, otherwise it should have 'name' and 'email'
362
  if (!is_array($sender)) {
363
  $this->setSenderName(Mage::getStoreConfig('trans_email/ident_' . $sender . '/name', $storeId));
@@ -373,11 +410,8 @@ class Bronto_Common_Model_Email_Template extends Mage_Core_Model_Email_Template
373
  }
374
 
375
  // Check for Sales Rules
376
- if ($this->getSalesRule() && !isset($vars['coupon'])) {
377
  try {
378
- /** @var Mage_SalesRule_Model_Rule $rule */
379
- $rule = Mage::getModel('salesrule/rule')->load($this->getSalesRule());
380
-
381
  /** @var Mage_SalesRule_Model_Coupon $coupon */
382
  $coupon = $rule->acquireCoupon();
383
 
@@ -385,7 +419,7 @@ class Bronto_Common_Model_Email_Template extends Mage_Core_Model_Email_Template
385
  $vars['coupon'] = $coupon;
386
  }
387
  } catch (Exception $e) {
388
- Mage::helper($this->_helper)->writeDebug(' Failed loading Sales Rule with ID: ' . $this->getSalesRule());
389
  }
390
  }
391
 
@@ -443,20 +477,54 @@ class Bronto_Common_Model_Email_Template extends Mage_Core_Model_Email_Template
443
  }
444
 
445
  /**
446
- * @param Bronto_Api_Delivery_Row $delivery
 
 
447
  */
448
- protected function _addAdditionalRecipients($delivery, $storeId)
449
  {
 
450
  }
451
 
452
  /**
453
- * The string model class associating this email template
454
  *
 
 
 
 
 
 
 
 
 
 
 
455
  * @return string
456
  */
457
- protected function _emailClass()
458
  {
459
- return 'bronto_common/email_template';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
460
  }
461
 
462
  /**
75
  return $this->_templateFilter;
76
  }
77
 
78
+ /**
79
+ * Gets the the global recommendation or the one configured for the email
80
+ *
81
+ * @param int $storeId
82
+ * @return Bronto_Product_Model_Recommendation
83
+ */
84
+ protected function _getRecommendation($storeId = null)
85
+ {
86
+ $recommendation = Mage::getModel('bronto_product/recommendation');
87
+ $recommendationId = $this->getProductRecommendation();
88
+ if ($recommendationId) {
89
+ if ($recommendation->load($recommendationId)->hasEntityId()) {
90
+ return $recommendation;
91
+ }
92
+ }
93
+
94
+ if ($this->_helper == 'bronto_email') {
95
+ $recommendationId = Mage::helper('bronto_email')->getDefaultRecommendation('store', $storeId);
96
+ if ($recommendationId) {
97
+ $recommendation->load($recommendationId);
98
+ }
99
+ }
100
+
101
+ return $recommendation;
102
+ }
103
+
104
+ /**
105
+ * Gets the global rule id or the one configured for the email
106
+ *
107
+ * @param int $storeId
108
+ * @return int
109
+ */
110
+ protected function _getSalesRule($storeId = null)
111
+ {
112
+ $rule = Mage::getModel('salesrule/rule');
113
+ $ruleId = $this->getSalesRule();
114
+ if ($ruleId) {
115
+ if ($rule->load($ruleId)->getId()) {
116
+ return $rule;
117
+ }
118
+ }
119
+
120
+ if ($this->_helper == 'bronto_email') {
121
+ $ruleId = Mage::helper('bronto_email')->getDefaultRule('store', $storeId);
122
+ if ($ruleId) {
123
+ if ($rule->load($ruleId)->getId()) {
124
+ return $rule;
125
+ }
126
+ }
127
+ }
128
+
129
+ return null;
130
+ }
131
+
132
  /**
133
  * Process email template code
134
  *
145
  $processor->setStoreId($variables['subscriber']->getStoreId());
146
  }
147
 
148
+ if ($this->getBrontoMessageId()) {
149
+ $processor->setMessageId($this->getBrontoMessageId());
150
  }
151
 
152
+ $processor->setRecommendation($this->_getRecommendation($variables['store']->getId()));
153
  $processor->setVariables($variables);
154
  $processor->setAvailable($this->getVariablesOptionArray());
155
 
163
  */
164
  public function isMessageValidForSend()
165
  {
166
+ if (!($this->getSenderName() && $this->getSenderEmail())) {
167
+ Mage::helper($this->_helper)->writeError(' Message cannot be sent: Sender Name or Email is not set');
 
 
 
168
 
169
  return false;
170
  }
171
 
172
+ return true;
173
+ }
174
 
175
+ /**
176
+ * Sends a Bronto Delivery
177
+ *
178
+ * @param Bronto_Common_Model_Queue $queue
179
+ * @return boolean
180
+ */
181
+ public function sendDeliveryFromQueue($queue)
182
+ {
183
+ $deliveryErrors = 0;
184
+ $message = $queue->getMessage();
185
+ $contacts = $queue->getContacts();
186
 
187
+ $this->setParams($queue->getAdditionalData());
188
+ $this->setMessage($message);
189
+ $this->setBrontoMessageId($message->id);
190
+ $this->setBrontoMessageName($message->name);
191
+ $this->setBrontoMessageApproved(1);
192
 
193
+ foreach ($contacts as $contact) {
194
+ $this->_beforeSend($contact, $message);
195
+ if (!$contact->id) {
196
+ $deliveryErrors++;
197
+ $this->_afterSend(false, "{$contact->email}: {$contact->error}");
198
+ continue;
199
+ }
200
+ try {
201
+ $delivery = $queue->prepareDelivery();
202
+ $delivery->start = $this->_startTime($queue->getStoreId());
203
+ $recipients = array(
204
+ array(
205
+ 'type' => 'contact',
206
+ 'id' => $contact->id,
207
+ 'deliveryType' => 'selected'
208
+ ),
209
+ );
210
+ $list = Mage::getModel('bronto_common/list', $this->_helper);
211
+ $excludes = $list->addAdditionalRecipients($queue->getStoreId());
212
+ foreach ($excludes as $exclude) {
213
+ $recipients[] = $exclude;
214
+ }
215
+ $delivery->recipients = $recipients;
216
+ $delivery->save();
217
 
218
+ if ($delivery->id) {
219
+ $this->setLastDeliveryId($delivery->id);
220
+ $this->_afterSend(true, null, $delivery);
221
+ } else {
222
+ $this->_afterSend(false, null, $delivery);
223
+ }
224
+ } catch (Exception $e) {
225
+ $deliveryErrors++;
226
+ $errorMessage = $e->getMessage();
227
+ if ($e->getCode() === Bronto_Api_Delivery_Exception::MESSAGE_NOT_TRANSACTIONAL_APPROVED) {
228
+ // Replace message id with message name
229
+ if (preg_match_all("/([a-zA-Z0-9\-]){36}/", $errorMessage, $matches)) { // Grab field id if exists
230
+ foreach ($matches[0] as $match) {
231
+ $errorMessage = str_replace($match, $message->name, $errorMessage);
232
+ }
233
+ }
234
+ }
235
+
236
+ Mage::helper($this->_helper)->writeError($errorMessage);
237
+ $this->_afterSend(false, $errorMessage, $delivery);
238
+ }
239
+ }
240
+ return $deliveryErrors == 0;
241
  }
242
 
243
  /**
251
  */
252
  public function send($email, $name = null, array $variables = array())
253
  {
254
+ // In the rare case we got here w/o hitting sendTransactional first...
255
+ if (!isset($variables['store']) || !is_object($variables['store'])) {
256
+ // Get the current store view, as to not break things
257
+ $variables['store'] = Mage::app()->getStore();
258
+ }
259
+
260
  // If not set to go through Bronto, fall through to magento sending
261
  if (!Mage::helper($this->_helper)->canSendBronto($this, $variables['store']->getId())) {
262
  return parent::send($email, $name, $variables);
263
  }
264
 
265
  /* @var $message Bronto_Api_Message_Row */
 
266
  $messageId = $this->getBrontoMessageId();
267
+ $sendType = $this->getTemplateSendType();
268
 
269
  // If messageId is empty, send through Magento
270
  if (empty($messageId)) {
289
  $variables['email'] = reset($emails);
290
  $variables['name'] = reset($names);
291
 
292
+ $apiHelper = Mage::helper('bronto_common/api');
293
+ $api = $apiHelper->getApi(null, 'store', $variables['store']->getId());
294
+
295
+ $delivery = $api->getDeliveryObject()->createRow();
296
+ $delivery = $this->getProcessedDelivery($delivery, $variables);
297
+ $this->_additionalFields($delivery, $variables);
298
+
299
+ $data = array(
300
+ 'emails' => $emails,
301
+ 'params' => $this->_additionalData(),
302
+ 'delivery' => array(
303
+ 'messageId' => $this->getBrontoMessageId(),
304
+ 'type' => $sendType ? $sendType : 'transactional',
305
+ 'fromEmail' => $this->getSenderEmail(),
306
+ 'fromName' => $this->getSenderName(),
307
+ 'replyEmail' => $this->getSenderEmail(),
308
+ 'fields' => $delivery->getFields(),
309
+ )
310
+ );
311
+
312
+ $queue = Mage::getModel('bronto_common/queue')
313
+ ->setStoreId($variables['store']->getId())
314
+ ->setApi($api)
315
+ ->setUnserializedEmailData($data)
316
+ ->setEmailClass($this->_emailClass())
317
+ ->setCreatedAt(Mage::getSingleton('core/date')->gmtDate());
318
+
319
+ if ($this->_queuable() && $apiHelper->canUseQueue('store', $queue->getStoreId())) {
320
  try {
321
+ $queue->save();
322
+ return true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
323
  } catch (Exception $e) {
324
+ $apiHelper->writeError('Failed to save email to queue for store ' . $queue->getStoreId() . ': ' . $e->getMessage());
325
+ return $this->sendDeliveryFromQueue($queue);
 
 
 
 
 
 
 
 
 
 
 
326
  }
327
+ } else {
328
+ return $this->sendDeliveryFromQueue($queue);
329
  }
 
 
330
  }
331
 
332
  /**
353
  return parent::sendTransactional($templateId, $sender, $email, $name, $vars, $storeId);
354
  } else {
355
  // If module enabled and template ID is not an instance of the api row, see if we can pull an instance
356
+ if (!($templateId instanceof Bronto_Api_Message_Row)) {
357
  $emailTemplate = Mage::getModel('bronto_email/template')
358
  ->setDesignConfig($this->getDesignConfig()->getData());
359
 
370
  return parent::sendTransactional($templateId, $sender, $email, $name, $vars, $storeId);
371
  }
372
 
373
+ $message = new Bronto_Api_Message_Row();
374
+ $message->id = $emailTemplate->getBrontoMessageId();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
375
 
376
  // Send through main template model
377
  $emailTemplate->sendTransactional(
385
 
386
  return $this->setSentSuccess($emailTemplate->getSentSuccess());
387
  } else {
388
+ $this->setBrontoMessageId($templateId->id);
389
  }
390
  }
391
 
395
  $storeId = $this->getDesignConfig()->getStore();
396
  }
397
 
 
 
 
 
 
398
  // If $sender is not array, it is a reference to a config setting, otherwise it should have 'name' and 'email'
399
  if (!is_array($sender)) {
400
  $this->setSenderName(Mage::getStoreConfig('trans_email/ident_' . $sender . '/name', $storeId));
410
  }
411
 
412
  // Check for Sales Rules
413
+ if (!isset($vars['coupon']) && $rule = $this->_getSalesRule($storeId)) {
414
  try {
 
 
 
415
  /** @var Mage_SalesRule_Model_Coupon $coupon */
416
  $coupon = $rule->acquireCoupon();
417
 
419
  $vars['coupon'] = $coupon;
420
  }
421
  } catch (Exception $e) {
422
+ Mage::helper($this->_helper)->writeDebug(' Failed loading Sales Rule with ID: ' . $rule->getId());
423
  }
424
  }
425
 
477
  }
478
 
479
  /**
480
+ * The string model class associating this email template
481
+ *
482
+ * @return string
483
  */
484
+ protected function _emailClass()
485
  {
486
+ return 'bronto_common/email_template';
487
  }
488
 
489
  /**
490
+ * Is this a queuable message?
491
  *
492
+ * @return bool
493
+ */
494
+ protected function _queuable()
495
+ {
496
+ return true;
497
+ }
498
+
499
+ /**
500
+ * When should this email be sent out?
501
+ *
502
+ * @param int $storeId
503
  * @return string
504
  */
505
+ protected function _startTime($storeId)
506
  {
507
+ return date('c');
508
+ }
509
+
510
+ /**
511
+ * Ability to set additional fields
512
+ *
513
+ * @param $delivery
514
+ * @param $variables
515
+ */
516
+ protected function _additionalFields($delivery, $variables)
517
+ {
518
+ }
519
+
520
+ /**
521
+ * Ability to add to the serialization data
522
+ *
523
+ * @return array
524
+ */
525
+ protected function _additionalData()
526
+ {
527
+ return array();
528
  }
529
 
530
  /**
app/code/community/Bronto/Common/Model/Email/Template/Filter.php CHANGED
@@ -6,6 +6,11 @@
6
  */
7
  class Bronto_Common_Model_Email_Template_Filter extends Mage_Core_Model_Email_Template_Filter
8
  {
 
 
 
 
 
9
  /**
10
  * @var Bronto_Api_Delivery_Row
11
  */
@@ -31,6 +36,21 @@ class Bronto_Common_Model_Email_Template_Filter extends Mage_Core_Model_Email_Te
31
  */
32
  protected $_currency;
33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  /**
35
  * Assigned template variables
36
  *
@@ -70,6 +90,49 @@ class Bronto_Common_Model_Email_Template_Filter extends Mage_Core_Model_Email_Te
70
  'subscriberConfirmationLink' => 'subConfirmationLink'
71
  );
72
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  /**
74
  * @return array
75
  */
@@ -165,8 +228,8 @@ class Bronto_Common_Model_Email_Template_Filter extends Mage_Core_Model_Email_Te
165
  }
166
 
167
  if (is_object($value)) {
 
168
 
169
- //
170
  // Handle properties that can be get()'ed
171
  foreach ($this->_processedAvailable as $keyValue) {
172
  $method = str_replace($var, '', $keyValue);
@@ -184,74 +247,141 @@ class Bronto_Common_Model_Email_Template_Filter extends Mage_Core_Model_Email_Te
184
  // Coupon
185
  if ($value instanceof Mage_SalesRule_Model_Coupon) {
186
  $this->_filterCoupon($value);
 
187
  }
188
 
189
  // Store
190
  if ($value instanceOf Mage_Core_Model_Store) {
191
  $this->_filterStore($value);
 
192
  }
193
 
194
  // Admin User
195
  if ($value instanceOf Mage_Admin_Model_User) {
196
  $this->_filterAdmin($value);
 
197
  }
198
 
199
  // Subscriber
200
  if ($value instanceOf Mage_Newsletter_Model_Subscriber) {
 
 
 
 
 
201
  $this->_filterSubscriber($value);
 
202
  }
203
 
204
  // Customer
205
  if ($value instanceOf Mage_Customer_Model_Customer) {
 
 
206
  $this->_filterCustomer($value);
 
207
  }
208
 
209
  // Shipment
210
  if ($value instanceOf Mage_Sales_Model_Order_Shipment) {
 
 
 
 
211
  $this->_filterShipment($value);
 
212
  }
213
 
214
  // Invoice
215
  if ($value instanceOf Mage_Sales_Model_Order_Invoice) {
 
 
 
 
216
  $this->_filterInvoice($value);
 
217
  }
218
 
219
  // Order
220
  if ($value instanceOf Mage_Sales_Model_Order) {
 
 
 
 
221
  $this->_filterOrder($value);
 
222
  }
223
 
224
  // Credit memo
225
  if ($value instanceOf Mage_Sales_Model_Order_Creditmemo) {
 
 
 
 
226
  $this->_filterCreditmemo($value);
 
227
  }
228
 
229
  // Quote
230
  if ($value instanceOf Mage_Sales_Model_Quote) {
 
 
 
 
231
  $this->_filterQuote($value);
 
232
  }
233
 
234
  // Wishlist
235
  if ($value instanceOf Mage_Wishlist_Model_Wishlist) {
 
 
 
 
236
  $this->_filterWishlist($value);
 
237
  }
238
 
239
  // Product
240
  if ($value instanceOf Mage_Catalog_Model_Product) {
241
  $this->_filterProduct($value);
 
242
  }
243
 
244
  if ($value instanceof Mage_Sales_Model_Order_Address) {
 
 
 
 
245
  $this->_filterAddress($value);
 
246
  }
247
 
248
- }
249
 
 
250
  }
251
 
 
 
252
  return $this->_delivery;
253
  }
254
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
255
  /**
256
  * Add Coupon Code to Email
257
  *
@@ -331,9 +461,7 @@ class Bronto_Common_Model_Email_Template_Filter extends Mage_Core_Model_Email_Te
331
  protected function _filterSubscriber(Mage_Newsletter_Model_Subscriber $subscriber)
332
  {
333
  if (!in_array('subscriber', $this->_filteredObjects)) {
334
- $customer = Mage::getModel('customer/customer')->load($subscriber->getCustomerId());
335
-
336
- $this->_filterCustomer($customer);
337
  $this->_filteredObjects[] = 'subscriber';
338
  }
339
 
@@ -397,6 +525,9 @@ class Bronto_Common_Model_Email_Template_Filter extends Mage_Core_Model_Email_Te
397
  }
398
  }
399
 
 
 
 
400
  // Order may not be a shippable order
401
  $shipAddress = 'N/A';
402
  $shipDescription = 'N/A';
@@ -418,7 +549,10 @@ class Bronto_Common_Model_Email_Template_Filter extends Mage_Core_Model_Email_Te
418
  $this->setField('orderItems', $this->_filterOrderItems($order));
419
 
420
  // When emailing from the admin, we need to ensure that we're using templates from the frontend
421
- Mage::getDesign()->setArea('frontend');
 
 
 
422
 
423
  $totals = $this->_getTotalsBlock(Mage::getSingleton('core/layout'), $order, 'sales/order_totals', 'order_totals');
424
  $this->setField('orderTotals', $totals->toHtml());
@@ -457,6 +591,9 @@ class Bronto_Common_Model_Email_Template_Filter extends Mage_Core_Model_Email_Te
457
  }
458
  }
459
 
 
 
 
460
  $this->setField('invoiceIncrementId', $invoice->getIncrementId());
461
  $this->setField('invoiceItems', $this->_filterInvoiceItems($invoice));
462
 
@@ -490,6 +627,9 @@ class Bronto_Common_Model_Email_Template_Filter extends Mage_Core_Model_Email_Te
490
  $createdAt = null;
491
  }
492
 
 
 
 
493
  $this->setField('shipmentIncrementId', $shipment->getIncrementId());
494
  $this->setField('shipmentCreatedAt', Mage::helper('core')->formatDate($createdAt, 'long', true)); // TODO: needed?
495
  $this->setField('shipmentItems', $this->_filterShipmentItems($shipment));
@@ -524,6 +664,9 @@ class Bronto_Common_Model_Email_Template_Filter extends Mage_Core_Model_Email_Te
524
  $createdAt = null;
525
  }
526
 
 
 
 
527
  $this->setField('creditmemoIncrementId', $creditmemo->getIncrementId());
528
  $this->setField('creditmemoCreatedAt', Mage::helper('core')->formatDate($createdAt, 'long', true)); // TODO: needed?
529
  $this->setField('creditmemoItems', $this->_filterCreditmemoItems($creditmemo));
@@ -562,6 +705,9 @@ class Bronto_Common_Model_Email_Template_Filter extends Mage_Core_Model_Email_Te
562
  }
563
  }
564
 
 
 
 
565
  $queryParams = $this->getQueryParams();
566
  $queryParams['id'] = urlencode(base64_encode(Mage::helper('core')->encrypt($quote->getId())));
567
  if ($store = $this->getStore()) {
@@ -580,7 +726,10 @@ class Bronto_Common_Model_Email_Template_Filter extends Mage_Core_Model_Email_Te
580
  $items->setQuote($item->getQuote());
581
 
582
  // When emailing from the admin, we need to ensure that we're using templates from the frontend
583
- Mage::getDesign()->setArea('frontend');
 
 
 
584
  $this->setField("cartItems", $items->toHtml());
585
  }
586
 
@@ -607,7 +756,7 @@ class Bronto_Common_Model_Email_Template_Filter extends Mage_Core_Model_Email_Te
607
  $this->setField("productPrice_{$index}", $this->formatPrice($checkout->getPriceInclTax($item)));
608
  $this->setField("productTotal_{$index}", $this->formatPrice($checkout->getSubtotalInclTax($item)));
609
  } else {
610
- $this->setField("productPrice_{$index}", $this->formatPrice($item->getConvertedPrice()));
611
  $this->setField("productTotal_{$index}", $this->formatPrice($item->calcRowTotal()->getRowTotal()));
612
  }
613
 
@@ -642,6 +791,9 @@ class Bronto_Common_Model_Email_Template_Filter extends Mage_Core_Model_Email_Te
642
  }
643
  }
644
 
 
 
 
645
  $queryParams = $this->getQueryParams();
646
  $queryParams['wishlist_id'] = urlencode(base64_encode(Mage::helper('core')->encrypt($wishlist->getId())));
647
  if ($store = $this->getStore()) {
@@ -660,7 +812,10 @@ class Bronto_Common_Model_Email_Template_Filter extends Mage_Core_Model_Email_Te
660
  $items->setWishlist($item->getWishlist());
661
 
662
  // When emailing from the admin, we need to ensure that we're using templates from the frontend
663
- Mage::getDesign()->setArea('frontend');
 
 
 
664
  $this->setField("wishlistItems", $items->toHtml());
665
  }
666
 
@@ -720,7 +875,10 @@ class Bronto_Common_Model_Email_Template_Filter extends Mage_Core_Model_Email_Te
720
  $items->addItemRender('bundle', 'bundle/sales_order_items_renderer', 'bundle/email/order/items/order/default.phtml');
721
 
722
  // When emailing from the admin, we need to ensure that we're using templates from the frontend
723
- Mage::getDesign()->setArea('frontend');
 
 
 
724
 
725
  $totals = $this->_getTotalsBlock($layout, $order, 'sales/order_totals', 'order_totals');
726
  $items->append($totals, 'order_totals');
@@ -762,11 +920,10 @@ class Bronto_Common_Model_Email_Template_Filter extends Mage_Core_Model_Email_Te
762
  // Set Product Detail Fields
763
  $this->setField("productName_{$index}", $item->getName());
764
  $this->setField("productSku_{$index}", $item->getSku());
765
- $this->setField("productPrice_{$index}", $this->formatPrice($item->getConvertedPrice()));
766
  $this->setField("productTotal_{$index}", $this->formatPrice($item->getRowTotal()));
767
  $this->setField("productQty_{$index}", $item->getQtyOrdered() * 1);
768
  $this->setField("productUrl_{$index}", $this->_getOrderItemUrl($item));
769
- $this->setField("productDescription_{$index}", $item->getDescription());
770
 
771
  // Handle Gift Message Details
772
  if ($item->getGiftMessageId() && $_giftMessage = Mage::helper('giftmessage/message')->getGiftMessage($item->getGiftMessageId())) {
@@ -807,7 +964,10 @@ class Bronto_Common_Model_Email_Template_Filter extends Mage_Core_Model_Email_Te
807
  $items->addItemRender('bundle', 'bundle/sales_order_items_renderer', 'bundle/email/order/items/invoice/default.phtml');
808
 
809
  // When emailing from the admin, we need to ensure that we're using templates from the frontend
810
- Mage::getDesign()->setArea('frontend');
 
 
 
811
 
812
  $totals = $this->_getTotalsBlock($layout, $order, 'sales/order_invoice_totals', 'invoice_totals');
813
  $items->append($totals, 'invoice_totals');
@@ -849,11 +1009,10 @@ class Bronto_Common_Model_Email_Template_Filter extends Mage_Core_Model_Email_Te
849
  // Set Product Detail Fields
850
  $this->setField("productName_{$index}", $item->getName());
851
  $this->setField("productSku_{$index}", $item->getSku());
852
- $this->setField("productPrice_{$index}", $this->formatPrice($item->getConvertedPrice()));
853
  $this->setField("productTotal_{$index}", $this->formatPrice($item->getRowTotal()));
854
  $this->setField("productQty_{$index}", $item->getQtyOrdered() * 1);
855
  $this->setField("productUrl_{$index}", $this->_getOrderItemUrl($item));
856
- $this->setField("productDescription_{$index}", $item->getDescription());
857
 
858
  // Handle Gift Message Details
859
  if ($item->getGiftMessageId() && $_giftMessage = Mage::helper('giftmessage/message')->getGiftMessage($item->getGiftMessageId())) {
@@ -894,7 +1053,10 @@ class Bronto_Common_Model_Email_Template_Filter extends Mage_Core_Model_Email_Te
894
  $items->addItemRender('bundle', 'bundle/sales_order_items_renderer', 'bundle/email/order/items/shipment/default.phtml');
895
 
896
  // When emailing from the admin, we need to ensure that we're using templates from the frontend
897
- Mage::getDesign()->setArea('frontend');
 
 
 
898
 
899
  return $items->toHtml();
900
  }
@@ -938,7 +1100,10 @@ class Bronto_Common_Model_Email_Template_Filter extends Mage_Core_Model_Email_Te
938
  $items->addItemRender('bundle', 'bundle/sales_order_items_renderer', 'bundle/email/order/items/creditmemo/default.phtml');
939
 
940
  // When emailing from the admin, we need to ensure that we're using templates from the frontend
941
- Mage::getDesign()->setArea('frontend');
 
 
 
942
 
943
  $totals = $this->_getTotalsBlock($layout, $order, 'sales/order_creditmemo_totals', 'creditmemo_totals');
944
  $items->append($totals, 'creditmemo_totals');
@@ -958,9 +1123,19 @@ class Bronto_Common_Model_Email_Template_Filter extends Mage_Core_Model_Email_Te
958
  */
959
  protected function _getTotalsBlock($layout, $order, $totals_block_type, $totals_block_name)
960
  {
 
 
 
 
 
 
 
 
 
 
961
  $totals = $layout->createBlock($totals_block_type, $totals_block_name);
962
  $totals->setOrder($order);
963
- $totals->setTemplate('sales/order/totals.phtml');
964
  $totals->setLabelProperties('colspan="3" align="right" style="padding:3px 9px"');
965
  $totals->setValueProperties('align="right" style="padding:3px 9px"');
966
 
@@ -988,8 +1163,16 @@ class Bronto_Common_Model_Email_Template_Filter extends Mage_Core_Model_Email_Te
988
 
989
  if ($index !== null) {
990
  try {
 
 
 
 
 
 
 
991
  $imageUrl = Mage::helper('bronto_common')->getProductImageUrl($product);
992
  $this->setField("productImgUrl_{$index}", $imageUrl);
 
993
  } catch (Exception $e) {
994
  Mage::log('Error loading image: ' . $e);
995
  }
@@ -1012,6 +1195,16 @@ class Bronto_Common_Model_Email_Template_Filter extends Mage_Core_Model_Email_Te
1012
  return $item->getRedirectUrl();
1013
  }
1014
 
 
 
 
 
 
 
 
 
 
 
1015
  return $item->getProduct()->getProductUrl();
1016
  }
1017
 
@@ -1278,4 +1471,25 @@ class Bronto_Common_Model_Email_Template_Filter extends Mage_Core_Model_Email_Te
1278
 
1279
  return $this->_currency->formatTxt($price, $options);
1280
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1281
  }
6
  */
7
  class Bronto_Common_Model_Email_Template_Filter extends Mage_Core_Model_Email_Template_Filter
8
  {
9
+ /**
10
+ * @var string
11
+ */
12
+ protected $_eventPrefix = 'bronto_common_email_filter';
13
+
14
  /**
15
  * @var Bronto_Api_Delivery_Row
16
  */
36
  */
37
  protected $_currency;
38
 
39
+ /**
40
+ * @var Mage_Customer_Model_Customer
41
+ */
42
+ protected $_customer;
43
+
44
+ /**
45
+ * @var Bronto_Product_Model_Recommendation
46
+ */
47
+ protected $_recommendation;
48
+
49
+ /**
50
+ * @var Bronto_Product_Model_Collect
51
+ */
52
+ protected $_collector;
53
+
54
  /**
55
  * Assigned template variables
56
  *
90
  'subscriberConfirmationLink' => 'subConfirmationLink'
91
  );
92
 
93
+ /**
94
+ * @return Mage_Customer_Model_Customer
95
+ */
96
+ protected function _getCustomer()
97
+ {
98
+ return $this->_customer;
99
+ }
100
+
101
+ /**
102
+ * @return bool|Bronto_Product_Model_Recommendation
103
+ */
104
+ protected function _getRecommendation()
105
+ {
106
+ return $this->_recommendation;
107
+ }
108
+
109
+ /**
110
+ * @param mixed $items
111
+ * @return Bronto_Product_Model_Collect
112
+ */
113
+ protected function _getRecommendationCollector($items)
114
+ {
115
+ if (is_null($this->_collector)) {
116
+ $this->_collector = Mage::helper('bronto_product')->collector(
117
+ $this->_getRecommendation(),
118
+ $this->getStoreId(),
119
+ $items);
120
+ }
121
+ return $this->_collector;
122
+ }
123
+
124
+ /**
125
+ * Filter using this recommendation
126
+ *
127
+ * @param Bronto_Product_Model_Recommendation $rec
128
+ * @return Bronto_Common_Model_Email_Template_Filter
129
+ */
130
+ public function setRecommendation(Bronto_Product_Model_Recommendation $rec)
131
+ {
132
+ $this->_recommendation = $rec;
133
+ return $this;
134
+ }
135
+
136
  /**
137
  * @return array
138
  */
228
  }
229
 
230
  if (is_object($value)) {
231
+ $eventSuffix = 'unknown';
232
 
 
233
  // Handle properties that can be get()'ed
234
  foreach ($this->_processedAvailable as $keyValue) {
235
  $method = str_replace($var, '', $keyValue);
247
  // Coupon
248
  if ($value instanceof Mage_SalesRule_Model_Coupon) {
249
  $this->_filterCoupon($value);
250
+ $eventSuffix = 'coupon';
251
  }
252
 
253
  // Store
254
  if ($value instanceOf Mage_Core_Model_Store) {
255
  $this->_filterStore($value);
256
+ $eventSuffix = 'store';
257
  }
258
 
259
  // Admin User
260
  if ($value instanceOf Mage_Admin_Model_User) {
261
  $this->_filterAdmin($value);
262
+ $eventSuffix = 'admin';
263
  }
264
 
265
  // Subscriber
266
  if ($value instanceOf Mage_Newsletter_Model_Subscriber) {
267
+ if (!$this->_customer) {
268
+ /** @var Mage_Customer_Model_Customer _customer */
269
+ $this->_customer = Mage::getModel('customer/customer')->load($value->getCustomerId());
270
+ }
271
+
272
  $this->_filterSubscriber($value);
273
+ $eventSuffix = 'subscriber';
274
  }
275
 
276
  // Customer
277
  if ($value instanceOf Mage_Customer_Model_Customer) {
278
+ /** @var Mage_Customer_Model_Customer _customer */
279
+ $this->_customer = $value;
280
  $this->_filterCustomer($value);
281
+ $eventSuffix = 'customer';
282
  }
283
 
284
  // Shipment
285
  if ($value instanceOf Mage_Sales_Model_Order_Shipment) {
286
+ if (!$this->_customer) {
287
+ /** @var Mage_Customer_Model_Customer _customer */
288
+ $this->_customer = Mage::getModel('customer/customer')->load($value->getOrder()->getCustomerId());
289
+ }
290
  $this->_filterShipment($value);
291
+ $eventSuffix = 'shipment';
292
  }
293
 
294
  // Invoice
295
  if ($value instanceOf Mage_Sales_Model_Order_Invoice) {
296
+ if (!$this->_customer) {
297
+ /** @var Mage_Customer_Model_Customer _customer */
298
+ $this->_customer = Mage::getModel('customer/customer')->load($value->getOrder()->getCustomerId());
299
+ }
300
  $this->_filterInvoice($value);
301
+ $eventSuffix = 'invoice';
302
  }
303
 
304
  // Order
305
  if ($value instanceOf Mage_Sales_Model_Order) {
306
+ if (!$this->_customer) {
307
+ /** @var Mage_Customer_Model_Customer _customer */
308
+ $this->_customer = Mage::getModel('customer/customer')->load($value->getCustomerId());
309
+ }
310
  $this->_filterOrder($value);
311
+ $eventSuffix = 'order';
312
  }
313
 
314
  // Credit memo
315
  if ($value instanceOf Mage_Sales_Model_Order_Creditmemo) {
316
+ if (!$this->_customer) {
317
+ /** @var Mage_Customer_Model_Customer _customer */
318
+ $this->_customer = Mage::getModel('customer/customer')->load($value->getOrder()->getCustomerId());
319
+ }
320
  $this->_filterCreditmemo($value);
321
+ $eventSuffix = 'creditmemo';
322
  }
323
 
324
  // Quote
325
  if ($value instanceOf Mage_Sales_Model_Quote) {
326
+ if (!$this->_customer) {
327
+ /** @var Mage_Customer_Model_Customer _customer */
328
+ $this->_customer = $value->getCustomer();
329
+ }
330
  $this->_filterQuote($value);
331
+ $eventSuffix = 'quote';
332
  }
333
 
334
  // Wishlist
335
  if ($value instanceOf Mage_Wishlist_Model_Wishlist) {
336
+ if (!$this->_customer) {
337
+ /** @var Mage_Customer_Model_Customer _customer */
338
+ $this->_customer = Mage::getModel('customer/customer')->load($value->getCustomerId());
339
+ }
340
  $this->_filterWishlist($value);
341
+ $eventSuffix = 'wishlist';
342
  }
343
 
344
  // Product
345
  if ($value instanceOf Mage_Catalog_Model_Product) {
346
  $this->_filterProduct($value);
347
+ $eventSuffix = 'product';
348
  }
349
 
350
  if ($value instanceof Mage_Sales_Model_Order_Address) {
351
+ if (!$this->_customer) {
352
+ /** @var Mage_Customer_Model_Customer _customer */
353
+ $this->_customer = Mage::getModel('customer/customer')->load($value->getOrder()->getCustomerId());
354
+ }
355
  $this->_filterAddress($value);
356
+ $eventSuffix = 'address';
357
  }
358
 
359
+ $this->_firePostFilterEvent($value, $eventSuffix);
360
 
361
+ }
362
  }
363
 
364
+ // Back fill anything if necessary
365
+ $this->_populateRelatedContent();
366
  return $this->_delivery;
367
  }
368
 
369
+ /**
370
+ * Fires an event after filtering a value
371
+ *
372
+ * @param mixed $value
373
+ * @param string $eventSuffix (Optional)
374
+ */
375
+ protected function _firePostFilterEvent($value, $eventSuffix = null)
376
+ {
377
+ if ($eventSuffix) {
378
+ Mage::dispatchEvent("{$this->_eventPrefix}_{$eventSuffix}", array(
379
+ 'filter' => $this,
380
+ $eventSuffix => $value
381
+ ));
382
+ }
383
+ }
384
+
385
  /**
386
  * Add Coupon Code to Email
387
  *
461
  protected function _filterSubscriber(Mage_Newsletter_Model_Subscriber $subscriber)
462
  {
463
  if (!in_array('subscriber', $this->_filteredObjects)) {
464
+ $this->_filterCustomer($this->_getCustomer());
 
 
465
  $this->_filteredObjects[] = 'subscriber';
466
  }
467
 
525
  }
526
  }
527
 
528
+ // Add Related Content
529
+ $this->_populateRelatedContent($order->getAllItems());
530
+
531
  // Order may not be a shippable order
532
  $shipAddress = 'N/A';
533
  $shipDescription = 'N/A';
549
  $this->setField('orderItems', $this->_filterOrderItems($order));
550
 
551
  // When emailing from the admin, we need to ensure that we're using templates from the frontend
552
+ Mage::getDesign()
553
+ ->setPackageName($this->getStore()->getConfig('design/package/name'))
554
+ ->setTheme($this->getStore()->getConfig('design/theme/default'))
555
+ ->setArea('frontend');
556
 
557
  $totals = $this->_getTotalsBlock(Mage::getSingleton('core/layout'), $order, 'sales/order_totals', 'order_totals');
558
  $this->setField('orderTotals', $totals->toHtml());
591
  }
592
  }
593
 
594
+ // Add Related Content
595
+ $this->_populateRelatedContent($invoice->getAllItems());
596
+
597
  $this->setField('invoiceIncrementId', $invoice->getIncrementId());
598
  $this->setField('invoiceItems', $this->_filterInvoiceItems($invoice));
599
 
627
  $createdAt = null;
628
  }
629
 
630
+ // Add Related Content
631
+ $this->_populateRelatedContent($shipment->getAllItems());
632
+
633
  $this->setField('shipmentIncrementId', $shipment->getIncrementId());
634
  $this->setField('shipmentCreatedAt', Mage::helper('core')->formatDate($createdAt, 'long', true)); // TODO: needed?
635
  $this->setField('shipmentItems', $this->_filterShipmentItems($shipment));
664
  $createdAt = null;
665
  }
666
 
667
+ // Add Related Content
668
+ $this->_populateRelatedContent($creditmemo->getAllItems());
669
+
670
  $this->setField('creditmemoIncrementId', $creditmemo->getIncrementId());
671
  $this->setField('creditmemoCreatedAt', Mage::helper('core')->formatDate($createdAt, 'long', true)); // TODO: needed?
672
  $this->setField('creditmemoItems', $this->_filterCreditmemoItems($creditmemo));
705
  }
706
  }
707
 
708
+ // Add Related Content
709
+ $this->_populateRelatedContent($quote->getAllItems());
710
+
711
  $queryParams = $this->getQueryParams();
712
  $queryParams['id'] = urlencode(base64_encode(Mage::helper('core')->encrypt($quote->getId())));
713
  if ($store = $this->getStore()) {
726
  $items->setQuote($item->getQuote());
727
 
728
  // When emailing from the admin, we need to ensure that we're using templates from the frontend
729
+ Mage::getDesign()
730
+ ->setPackageName($this->getStore()->getConfig('design/package/name'))
731
+ ->setTheme($this->getStore()->getConfig('design/theme/default'))
732
+ ->setArea('frontend');
733
  $this->setField("cartItems", $items->toHtml());
734
  }
735
 
756
  $this->setField("productPrice_{$index}", $this->formatPrice($checkout->getPriceInclTax($item)));
757
  $this->setField("productTotal_{$index}", $this->formatPrice($checkout->getSubtotalInclTax($item)));
758
  } else {
759
+ $this->setField("productPrice_{$index}", $this->formatPrice($item->getPrice()));
760
  $this->setField("productTotal_{$index}", $this->formatPrice($item->calcRowTotal()->getRowTotal()));
761
  }
762
 
791
  }
792
  }
793
 
794
+ // Add Related Content
795
+ $this->_populateRelatedContent($wishlist->getItemCollection());
796
+
797
  $queryParams = $this->getQueryParams();
798
  $queryParams['wishlist_id'] = urlencode(base64_encode(Mage::helper('core')->encrypt($wishlist->getId())));
799
  if ($store = $this->getStore()) {
812
  $items->setWishlist($item->getWishlist());
813
 
814
  // When emailing from the admin, we need to ensure that we're using templates from the frontend
815
+ Mage::getDesign()
816
+ ->setPackageName($this->getStore()->getConfig('design/package/name'))
817
+ ->setTheme($this->getStore()->getConfig('design/theme/default'))
818
+ ->setArea('frontend');
819
  $this->setField("wishlistItems", $items->toHtml());
820
  }
821
 
875
  $items->addItemRender('bundle', 'bundle/sales_order_items_renderer', 'bundle/email/order/items/order/default.phtml');
876
 
877
  // When emailing from the admin, we need to ensure that we're using templates from the frontend
878
+ Mage::getDesign()
879
+ ->setPackageName($this->getStore()->getConfig('design/package/name'))
880
+ ->setTheme($this->getStore()->getConfig('design/theme/default'))
881
+ ->setArea('frontend');
882
 
883
  $totals = $this->_getTotalsBlock($layout, $order, 'sales/order_totals', 'order_totals');
884
  $items->append($totals, 'order_totals');
920
  // Set Product Detail Fields
921
  $this->setField("productName_{$index}", $item->getName());
922
  $this->setField("productSku_{$index}", $item->getSku());
923
+ $this->setField("productPrice_{$index}", $this->formatPrice($item->getPrice()));
924
  $this->setField("productTotal_{$index}", $this->formatPrice($item->getRowTotal()));
925
  $this->setField("productQty_{$index}", $item->getQtyOrdered() * 1);
926
  $this->setField("productUrl_{$index}", $this->_getOrderItemUrl($item));
 
927
 
928
  // Handle Gift Message Details
929
  if ($item->getGiftMessageId() && $_giftMessage = Mage::helper('giftmessage/message')->getGiftMessage($item->getGiftMessageId())) {
964
  $items->addItemRender('bundle', 'bundle/sales_order_items_renderer', 'bundle/email/order/items/invoice/default.phtml');
965
 
966
  // When emailing from the admin, we need to ensure that we're using templates from the frontend
967
+ Mage::getDesign()
968
+ ->setPackageName($this->getStore()->getConfig('design/package/name'))
969
+ ->setTheme($this->getStore()->getConfig('design/theme/default'))
970
+ ->setArea('frontend');
971
 
972
  $totals = $this->_getTotalsBlock($layout, $order, 'sales/order_invoice_totals', 'invoice_totals');
973
  $items->append($totals, 'invoice_totals');
1009
  // Set Product Detail Fields
1010
  $this->setField("productName_{$index}", $item->getName());
1011
  $this->setField("productSku_{$index}", $item->getSku());
1012
+ $this->setField("productPrice_{$index}", $this->formatPrice($item->getPrice()));
1013
  $this->setField("productTotal_{$index}", $this->formatPrice($item->getRowTotal()));
1014
  $this->setField("productQty_{$index}", $item->getQtyOrdered() * 1);
1015
  $this->setField("productUrl_{$index}", $this->_getOrderItemUrl($item));
 
1016
 
1017
  // Handle Gift Message Details
1018
  if ($item->getGiftMessageId() && $_giftMessage = Mage::helper('giftmessage/message')->getGiftMessage($item->getGiftMessageId())) {
1053
  $items->addItemRender('bundle', 'bundle/sales_order_items_renderer', 'bundle/email/order/items/shipment/default.phtml');
1054
 
1055
  // When emailing from the admin, we need to ensure that we're using templates from the frontend
1056
+ Mage::getDesign()
1057
+ ->setPackageName($this->getStore()->getConfig('design/package/name'))
1058
+ ->setTheme($this->getStore()->getConfig('design/theme/default'))
1059
+ ->setArea('frontend');
1060
 
1061
  return $items->toHtml();
1062
  }
1100
  $items->addItemRender('bundle', 'bundle/sales_order_items_renderer', 'bundle/email/order/items/creditmemo/default.phtml');
1101
 
1102
  // When emailing from the admin, we need to ensure that we're using templates from the frontend
1103
+ Mage::getDesign()
1104
+ ->setPackageName($this->getStore()->getConfig('design/package/name'))
1105
+ ->setTheme($this->getStore()->getConfig('design/theme/default'))
1106
+ ->setArea('frontend');
1107
 
1108
  $totals = $this->_getTotalsBlock($layout, $order, 'sales/order_creditmemo_totals', 'creditmemo_totals');
1109
  $items->append($totals, 'creditmemo_totals');
1123
  */
1124
  protected function _getTotalsBlock($layout, $order, $totals_block_type, $totals_block_name)
1125
  {
1126
+ // Change this path for order totals
1127
+ $templatePath = 'sales/order/totals.phtml';
1128
+ switch ($totals_block_name) {
1129
+ case 'creditmemo_totals':
1130
+ case 'invoice_totals':
1131
+ // Be sure to use 'invoice_totals' and 'creditmemo_totals',
1132
+ // inplace of 'totals' here
1133
+ $templatePath = str_replace('totals', $totals_block_name, $templatePath);
1134
+ }
1135
+
1136
  $totals = $layout->createBlock($totals_block_type, $totals_block_name);
1137
  $totals->setOrder($order);
1138
+ $totals->setTemplate($templatePath);
1139
  $totals->setLabelProperties('colspan="3" align="right" style="padding:3px 9px"');
1140
  $totals->setValueProperties('align="right" style="padding:3px 9px"');
1141
 
1163
 
1164
  if ($index !== null) {
1165
  try {
1166
+ // Fix for SCP
1167
+ if ($product->getTypeId() == Mage_Catalog_Model_Product_Type::TYPE_SIMPLE) {
1168
+ $parentIds = Mage::getModel('catalog/product_type_configurable')->getParentIdsByChild($product->getId());
1169
+ if (isset($parentIds[0])) {
1170
+ $product = Mage::getModel('catalog/product')->setStoreId($product->getStoreId())->load($parentIds[0]);
1171
+ }
1172
+ }
1173
  $imageUrl = Mage::helper('bronto_common')->getProductImageUrl($product);
1174
  $this->setField("productImgUrl_{$index}", $imageUrl);
1175
+ $this->setField("productDescription_{$index}", $product->getDescription());
1176
  } catch (Exception $e) {
1177
  Mage::log('Error loading image: ' . $e);
1178
  }
1195
  return $item->getRedirectUrl();
1196
  }
1197
 
1198
+ // Fix for SCP
1199
+ $product = $item->getProduct();
1200
+ if ($product->getTypeId() == Mage_Catalog_Model_Product_Type::TYPE_SIMPLE) {
1201
+ $parentIds = Mage::getModel('catalog/product_type_configurable')->getParentIdsByChild($product->getId());
1202
+ if (isset($parentIds[0])) {
1203
+ $parentProduct = Mage::getModel('catalog/product')->setStoreId($item->getStoreId())->load($parentIds[0]);
1204
+ return $parentProduct->getProductUrl();
1205
+ }
1206
+ }
1207
+
1208
  return $item->getProduct()->getProductUrl();
1209
  }
1210
 
1471
 
1472
  return $this->_currency->formatTxt($price, $options);
1473
  }
1474
+
1475
+ /**
1476
+ * Populates the recommendation content
1477
+ *
1478
+ * @param array $products (Optional)
1479
+ */
1480
+ protected function _populateRelatedContent($items = array())
1481
+ {
1482
+ $helper = Mage::helper('bronto_product');
1483
+ $recommendation = $this->_getRecommendation();
1484
+ if ($recommendation && $helper->isEnabled('store', $this->getStoreId())) {
1485
+ $collect = $this->_getRecommendationCollector($items);
1486
+ if ($collect->getRemainingCount() == $recommendation->getNumberOfItems()) {
1487
+ $collect->setRecommendation($recommendation->setCustomer($this->_getCustomer()));
1488
+ $helper->setRelatedFields(
1489
+ $this->_delivery,
1490
+ $collect->collect(),
1491
+ $this->getStoreId());
1492
+ }
1493
+ }
1494
+ }
1495
  }
app/code/community/Bronto/Common/Model/List.php CHANGED
@@ -46,7 +46,7 @@ class Bronto_Common_Model_List
46
  if ($list->hasError()) {
47
  continue;
48
  }
49
- $this->_helper->writeDebug('Excluding list: ' . $list->id);
50
  $recipients[] = array(
51
  'type' => 'list',
52
  'id' => $list->id,
46
  if ($list->hasError()) {
47
  continue;
48
  }
49
+ $this->_helper->writeDebug("Excluding list: {$list->name} ({$list->id})");
50
  $recipients[] = array(
51
  'type' => 'list',
52
  'id' => $list->id,
app/code/community/Bronto/Common/Model/Mysql4/Queue.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Common_Model_Mysql4_Queue extends Mage_Core_Model_Mysql4_Abstract
4
+ {
5
+ /**
6
+ * @see parent
7
+ */
8
+ public function _construct()
9
+ {
10
+ $this->_init('bronto_common/queue', 'queue_id');
11
+ }
12
+
13
+ /**
14
+ * Flags the obtained the items for holding
15
+ *
16
+ * @param array $items
17
+ * @return Bronto_Common_Model_Mysql4_Queue
18
+ */
19
+ public function flagForHolding($ids)
20
+ {
21
+ $resource = $this->_getWriteAdapter();
22
+ $condition = $this->getIdFieldName() . ' IN (' . implode(',', $ids) . ')';
23
+ $update = array('holding' => 1);
24
+ $resource = $resource->update($this->getMainTable(), $update, $condition);
25
+ return $this;
26
+ }
27
+ }
app/code/community/Bronto/Common/Model/Mysql4/Queue/Collection.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Common_Model_Mysql4_Queue_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
4
+ {
5
+ /**
6
+ * @see parent
7
+ */
8
+ public function _construct()
9
+ {
10
+ parent::_construct();
11
+ $this->_init('bronto_common/queue');
12
+ }
13
+
14
+ /**
15
+ * Only gets the entries that aren't flagged for holding
16
+ *
17
+ * @return Bronto_Common_Model_Mysql4_Queue_Collection
18
+ */
19
+ public function getReadyEntries()
20
+ {
21
+ return $this->addFieldToFilter('holding', array('eq' => 0));
22
+ }
23
+
24
+ /**
25
+ * Only gets the entries for the store in question
26
+ *
27
+ * @return Bronto_Common_Model_Mysql4_Queue_Collection
28
+ */
29
+ public function getEntriesForStore($storeId)
30
+ {
31
+ return $this->addFieldToFilter('store_id', array('eq' => $storeId));
32
+ }
33
+
34
+ /**
35
+ * Gets the oldest to pop out the queue
36
+ *
37
+ * @return Bronto_Common_Model_Mysql4_Queue_Collection
38
+ */
39
+ public function orderByOldest()
40
+ {
41
+ return $this->addOrder('created_at', self::SORT_ORDER_ASC);
42
+ }
43
+ }
app/code/community/Bronto/Common/Model/Observer.php CHANGED
@@ -42,7 +42,7 @@ class Bronto_Common_Model_Observer
42
  $sentry->disableModules($scope, $scopeId, true);
43
 
44
  // Unlink all Emails
45
- if (!Mage::helper('bronto_common')->isVersionMatch(Mage::getVersionInfo(), 1, 9)) {
46
  $sentry->unlinkEmails(
47
  Mage::getModel('bronto_email/message')->getCollection(),
48
  $scope,
@@ -152,6 +152,113 @@ class Bronto_Common_Model_Observer
152
  return $results;
153
  }
154
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  /**
156
  * Validates that certain fields are not empty
157
  *
42
  $sentry->disableModules($scope, $scopeId, true);
43
 
44
  // Unlink all Emails
45
+ if (!Mage::helper('bronto_common')->isVersionMatch(Mage::getVersionInfo(), 1, array(array('edition' => 'Enterprise', 'major' => 9)))) {
46
  $sentry->unlinkEmails(
47
  Mage::getModel('bronto_email/message')->getCollection(),
48
  $scope,
152
  return $results;
153
  }
154
 
155
+ /**
156
+ * Cron to process email sending
157
+ *
158
+ * @return array
159
+ */
160
+ public function processSendQueue($cron = null)
161
+ {
162
+ $results = array(
163
+ 'total' => 0,
164
+ 'success' => 0,
165
+ 'error' => 0
166
+ );
167
+ $stores = Mage::app()->getStores(true);
168
+ foreach ($stores as $store) {
169
+ foreach ($this->processSendForStore($store) as $field => $count) {
170
+ $results[$field] += $count;
171
+ }
172
+ }
173
+ return $results;
174
+ }
175
+
176
+ /**
177
+ * Processes the website sends
178
+ *
179
+ * @param int $websiteId
180
+ * @return array
181
+ */
182
+ public function processSendForSite($websiteId)
183
+ {
184
+ $results = array(
185
+ 'total' => 0,
186
+ 'success' => 0,
187
+ 'error' => 0,
188
+ );
189
+ $website = Mage::app()->getWebsite($websiteId);
190
+ foreach ($website->getStores() as $store) {
191
+ foreach ($this->processSendForStore($store) as $field => $count) {
192
+ $results[$field] += $count;
193
+ }
194
+ }
195
+ return $results;
196
+ }
197
+
198
+ /**
199
+ * Processes the send queue for a given scope
200
+ *
201
+ * @return array
202
+ */
203
+ public function processSendForScope()
204
+ {
205
+ $scopeParams = Mage::helper('bronto_common')->getScopeParams();
206
+ if ($scopeParams['store']) {
207
+ return $this->processSendForStore($scopeParams['store_id']);
208
+ } else if ($scopeParams['website']) {
209
+ return $this->processSendForSite($scopeParams['website_id']);
210
+ } else {
211
+ return $this->processSendQueue();
212
+ }
213
+ }
214
+
215
+ /**
216
+ * Processes the send queue for a given store
217
+ *
218
+ * @param int storeId
219
+ * @return array
220
+ */
221
+ public function processSendForStore($storeId)
222
+ {
223
+ $results = array(
224
+ 'total' => 0,
225
+ 'success' => 0,
226
+ 'error' => 0,
227
+ );
228
+ $helper = Mage::helper('bronto_common/api');
229
+ $singleton = Mage::getModel('bronto_common/queue');
230
+ $store = Mage::app()->getStore($storeId);
231
+ if (!$helper->canUseQueue('store', $store->getId())) {
232
+ return $results;
233
+ }
234
+
235
+ $api = $helper->getApi(null, 'store', $store->getId());
236
+ $collection = $singleton->getCollection()
237
+ ->orderByOldest()
238
+ ->getReadyEntries()
239
+ ->getEntriesForStore($store->getId())
240
+ ->setPageSize($helper->getSendLimit('store', $store->getId()))
241
+ ->getItems();
242
+ $singleton->flagForHolding($collection);
243
+
244
+ foreach ($collection as $queue) {
245
+ $results['total']++;
246
+ try {
247
+ if ($queue->setApi($api)->send()) {
248
+ $results['success']++;
249
+ } else {
250
+ $results['error']++;
251
+ }
252
+ } catch (Exception $e) {
253
+ $helper->writeError('Error in delivery for store ' . $store->getId() . ': ' . $e->getMessage());
254
+ $results['error']++;
255
+ }
256
+ // Pop, in either case
257
+ $queue->delete();
258
+ }
259
+ return $results;
260
+ }
261
+
262
  /**
263
  * Validates that certain fields are not empty
264
  *
app/code/community/Bronto/Common/Model/Queue.php ADDED
@@ -0,0 +1,187 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Common_Model_Queue extends Mage_Core_Model_Abstract
4
+ {
5
+ /**
6
+ * @var Bronto_Api
7
+ */
8
+ protected $_api;
9
+
10
+ /**
11
+ * @var Bronto_Api_Delivery_Object
12
+ */
13
+ protected $_deliveryObject;
14
+
15
+ /**
16
+ * @var array Bronto_Api_Contact_Row
17
+ */
18
+ protected $_contacts;
19
+
20
+ /**
21
+ * @var Bronto_Api_Message_Row
22
+ */
23
+ protected $_message;
24
+
25
+ /**
26
+ * @var array
27
+ */
28
+ protected $_unserializedData;
29
+
30
+ /**
31
+ * @see parent
32
+ */
33
+ protected function _construct()
34
+ {
35
+ parent::_construct();
36
+ $this->_init('bronto_common/queue');
37
+ }
38
+
39
+ /**
40
+ * Flags the obtained the items for holding
41
+ *
42
+ * @param array $items
43
+ * @return array
44
+ */
45
+ public function flagForHolding($items)
46
+ {
47
+ $ids = array();
48
+ foreach ($items as $item) {
49
+ $ids[] = $item->getId();
50
+ }
51
+ if (empty($ids)) {
52
+ return array();
53
+ }
54
+ $this->_getResource()->flagForHolding($ids);
55
+ return $ids;
56
+ }
57
+
58
+ /**
59
+ * Sets the Bronto_Api
60
+ *
61
+ * @param Bronto_Api
62
+ * @return Bronto_Common_Model_Queue
63
+ */
64
+ public function setApi($api)
65
+ {
66
+ $this->_api = $api;
67
+ return $this;
68
+ }
69
+
70
+ /**
71
+ * Gets the Bronto_Api for this queue
72
+ *
73
+ * @return Bronto_Api
74
+ */
75
+ protected function _api()
76
+ {
77
+ if (is_null($this->_api)) {
78
+ $this->_api = Mage::helper('bronto_contact')->getApi(null, 'store', $this->getStoreId());
79
+ }
80
+ return $this->_api;
81
+ }
82
+
83
+ /**
84
+ * Gets the delivery object for this delivery
85
+ *
86
+ * @return Bronto_Api_Delivery_Object
87
+ */
88
+ protected function _deliveryObject()
89
+ {
90
+ if (is_null($this->_deliveryObject)) {
91
+ $this->_deliveryObject = Mage::getModel('bronto_common/delivery', array(
92
+ 'api' => $this->_api(),
93
+ 'email_class' => $this->getEmailClass()
94
+ ));
95
+ }
96
+ return $this->_deliveryObject;
97
+ }
98
+
99
+ /**
100
+ * Sets the unserialized data for emails
101
+ *
102
+ * @param array
103
+ * @return Bronto_Common_Model_Queue
104
+ */
105
+ public function setUnserializedEmailData($data)
106
+ {
107
+ return $this->setEmailData(serialize($data));
108
+ }
109
+
110
+ /**
111
+ * Gets the unserialized data for emails
112
+ *
113
+ * @return Varien_Object
114
+ */
115
+ public function getUnserializedEmailData()
116
+ {
117
+ if (is_null($this->_unserializedData)) {
118
+ $this->_unserializedData = unserialize($this->getEmailData());
119
+ }
120
+ return new Varien_Object($this->_unserializedData);
121
+ }
122
+
123
+ /**
124
+ * Gets the contacts to send the delivery
125
+ *
126
+ * @return array Bronto_Api_Contact_Row
127
+ */
128
+ public function getContacts()
129
+ {
130
+ if (is_null($this->_contacts)) {
131
+ $emails = $this->getUnserializedEmailData()->getEmails();
132
+ $contactHelper = Mage::helper('bronto_common/contact');
133
+ $this->_contacts = $contactHelper->getContactsByEmail($emails, null, $this->getStoreId(), true);
134
+ }
135
+ return $this->_contacts;
136
+ }
137
+
138
+ /**
139
+ * Gets the specialized data
140
+ *
141
+ * @return Varien_Object
142
+ */
143
+ public function getAdditionalData()
144
+ {
145
+ return new Varien_Object($this->getUnserializedEmailData()->getParams());
146
+ }
147
+
148
+ /**
149
+ * Gets the Bronto Message associated with this delivery
150
+ *
151
+ * @return Bronto_Api_Message_Row
152
+ */
153
+ public function getMessage()
154
+ {
155
+ if (is_null($this->_message)) {
156
+ $deliveryData = $this->getUnserializedEmailData()->getDelivery();
157
+ $this->_message = Mage::helper('bronto_common/message')->getMessageById($deliveryData['messageId']);
158
+ }
159
+ return $this->_message;
160
+ }
161
+
162
+ /**
163
+ * Creates a Bronto_Api_Delivery_Row from internals
164
+ *
165
+ * @return Bronto_Api_Delivery_Row
166
+ */
167
+ public function prepareDelivery()
168
+ {
169
+ $delivery = $this->_deliveryObject()->createRow();
170
+ $deliveryData = $this->getUnserializedEmailData()->getDelivery();
171
+ foreach ($deliveryData as $field => $value) {
172
+ $delivery->{$field} = $value;
173
+ }
174
+ return $delivery;
175
+ }
176
+
177
+ /**
178
+ * Sends a Bronto Delivery
179
+ *
180
+ * @reutrn bool
181
+ */
182
+ public function send()
183
+ {
184
+ $template = Mage::getModel($this->getEmailClass());
185
+ return $template->sendDeliveryFromQueue($this);
186
+ }
187
+ }
app/code/community/Bronto/Common/Model/Resource/Abstract.php ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ abstract class Bronto_Common_Model_Resource_Abstract extends Mage_Core_Model_Resource_Setup
4
+ {
5
+ protected $_dropStmt = 'DROP TABLE IF EXISTS `{table}`;';
6
+
7
+ /**
8
+ * Return the module namespace for this setup
9
+ *
10
+ * eg: 'bronto_common'
11
+ * @return string
12
+ */
13
+ protected abstract function _module();
14
+
15
+ /**
16
+ * Return the table definitions belonging to this module
17
+ *
18
+ * eg: array('table' => 'CREATE {table} ...')
19
+ * @return array
20
+ */
21
+ protected abstract function _tables();
22
+
23
+ /**
24
+ * Return the update definitions belonging to this module
25
+ *
26
+ * eg: array('1.0.1' => array('table' => array('sql' => 'UPDATE....')))
27
+ * @return array
28
+ */
29
+ protected abstract function _updates();
30
+
31
+ /**
32
+ * Gets the internal table name for $key
33
+ *
34
+ * @param string $key
35
+ * @return string
36
+ */
37
+ protected function _tableName($key)
38
+ {
39
+ return $this->getTable("{$this->_module()}/$key");
40
+ }
41
+
42
+ /**
43
+ * Replaces the {table} name in the statement
44
+ *
45
+ * @param string $key
46
+ * @param string $string
47
+ * @return string
48
+ */
49
+ protected function _replaceName($key, $string)
50
+ {
51
+ return $this->_replaceText('table', $this->_tableName($key), $string);
52
+ }
53
+
54
+ /**
55
+ * Wrapper around str_replace for special replace keys
56
+ *
57
+ * @param string $key
58
+ * @param string $value
59
+ * @param string $original
60
+ * @return string
61
+ */
62
+ protected function _replaceText($key, $value, $original)
63
+ {
64
+ return str_replace('{' . $key . '}', $value, $original);
65
+ }
66
+
67
+ /**
68
+ * Repalce the table and all others
69
+ *
70
+ * @param string $table
71
+ * @param string $string
72
+ * @param array $extra
73
+ * @return string
74
+ */
75
+ protected function _replaceStatement($table, $string, $extra = array()) {
76
+ $statement = $this->_replaceName($table, $string);
77
+ foreach ($extra as $key => $value) {
78
+ $statement = $this->_replaceText($key, $value, $statement);
79
+ }
80
+ return $statement;
81
+ }
82
+
83
+ /**
84
+ * Triggers the callback for a given update
85
+ *
86
+ * @param array $update
87
+ */
88
+ protected function _updateCallback($state, $table, $update)
89
+ {
90
+ if (array_key_exists($state, $update)) {
91
+ $callback = $update[$state];
92
+ if (is_string($callback)) {
93
+ $callback = array($this, $callback);
94
+ }
95
+ if (is_callable($callback)) {
96
+ call_user_func($callback, $table);
97
+ }
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Creates the table with the provided stmt.
103
+ *
104
+ * @param string $table
105
+ * @param array $extra (Optional)
106
+ * @return void
107
+ * @throws RuntimeException is the table does not exist
108
+ */
109
+ public function createTable($table, $extra = array())
110
+ {
111
+ $tables = $this->_tables();
112
+ if (!array_key_exists($table, $this->_tables())) {
113
+ throw new RuntimeException("Table {$table} does not exist.");
114
+ }
115
+ $this->run($this->_replaceStatement($table, $tables[$table], $extra));
116
+ }
117
+
118
+ /**
119
+ * Creates all of the tables
120
+ *
121
+ * @param array $extra (Optional)
122
+ */
123
+ public function createTables($extra = array())
124
+ {
125
+ foreach ($this->_tables() as $table => $statement) {
126
+ $this->dropTable($table);
127
+ $this->createTable($table, $extra);
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Drops all of the tables
133
+ */
134
+ public function dropTables()
135
+ {
136
+ foreach ($this->_tables() as $table => $_) {
137
+ $this->dropTable($table);
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Drops the table with the given key
143
+ *
144
+ * @param string $table
145
+ * @return void
146
+ */
147
+ public function dropTable($table)
148
+ {
149
+ $this->run($this->_replaceName($table, $this->_dropStmt));
150
+ }
151
+
152
+ /**
153
+ * Updates the table with the specific commands
154
+ *
155
+ * @param string $table
156
+ * @param string $version
157
+ * @return void
158
+ */
159
+ public function updateTables($version)
160
+ {
161
+ $updates = $this->_updates();
162
+ if (!array_key_exists($version, $updates)) {
163
+ throw new RuntimeException("Version $version is not defined.");
164
+ }
165
+ // Updates all of the tables in this version
166
+ foreach ($updates[$version] as $table => $update) {
167
+ $extra = !empty($update['extra']) ? $update['extra'] : array();
168
+ try {
169
+ $this->_updateCallback('before', $table, $update);
170
+ if (isset($update['sql'])) {
171
+ $this->run($this->_replaceName($table, $update['sql'], $extra));
172
+ }
173
+ $this->_updateCallback('after', $table, $update);
174
+ } catch (Exception $e) {
175
+ Mage::helper($this->_module())->writeError("Failed to update $table to $version: {$e->getMessage()}");
176
+ }
177
+ }
178
+ }
179
+ }
app/code/community/Bronto/Common/Model/Resource/Setup.php CHANGED
@@ -4,8 +4,82 @@
4
  * @package Bronto\Common
5
  * @copyright 2011-2012 Bronto Software, Inc.
6
  */
7
- class Bronto_Common_Model_Resource_Setup extends Mage_Sales_Model_Mysql4_Setup
8
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  public function handleOld()
10
  {
11
  // Look if Bronto folder exists in local codepool and recursively remove if it is
4
  * @package Bronto\Common
5
  * @copyright 2011-2012 Bronto Software, Inc.
6
  */
7
+ class Bronto_Common_Model_Resource_Setup extends Bronto_Common_Model_Resource_Abstract
8
  {
9
+
10
+ /**
11
+ * @see parent
12
+ * @return string
13
+ */
14
+ protected function _module()
15
+ {
16
+ return 'bronto_common';
17
+ }
18
+
19
+ /**
20
+ * Gets all of the create table definititions at this version
21
+ *
22
+ * @see parent
23
+ * @return array
24
+ */
25
+ protected function _tables()
26
+ {
27
+ return array(
28
+ 'api' => "
29
+ CREATE TABLE `{table}` (
30
+ `token` varchar(36) NOT NULL,
31
+ `session_id` varchar(36) NOT NULL,
32
+ `created_at` datetime NOT NULL,
33
+ PRIMARY KEY (`token`)
34
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Bronto API Session table'",
35
+ 'error' => "
36
+ CREATE TABLE `{table}` (
37
+ `error_id` int(11) NOT NULL AUTO_INCREMENT,
38
+ `email_class` varchar(100) NULL,
39
+ `object` mediumtext NOT NULL DEFAULT '',
40
+ `attempts` smallint(1) NOT NULL,
41
+ `last_attempt` datetime NOT NULL,
42
+ PRIMARY KEY (`error_id`),
43
+ KEY `IDX_BRONTO_ERROR_ATTEMPT` (`attempts`),
44
+ KEY `IDX_BRONTO_ERROR_TIMESTAMP` (`last_attempt`)
45
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Bronto API Error log'",
46
+ 'queue' => "
47
+ CREATE TABLE `{table}` (
48
+ `queue_id` int(11) NOT NULL AUTO_INCREMENT,
49
+ `store_id` int(11) NOT NULL DEFAULT '1',
50
+ `email_class` varchar(100) NOT NULL,
51
+ `email_data` mediumtext NOT NULL DEFAULT '',
52
+ `holding` smallint(1) NOT NULL DEFAULT 0,
53
+ `created_at` datetime NOT NULL,
54
+ PRIMARY KEY (`queue_id`),
55
+ KEY `IDX_BRONTO_SEND_QUEUE_STORE` (`store_id`),
56
+ KEY `IDX_BRONTO_SEND_QUEUE_HOLDING` (`holding`),
57
+ KEY `IDX_BRONTO_SEND_QUEUE_TIMESTAMP` (`created_at`)
58
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Bronto API Send queue'"
59
+ );
60
+ }
61
+
62
+ /**
63
+ * Updates the appropriate tables
64
+ *
65
+ * @see parent
66
+ * @return array
67
+ */
68
+ protected function _updates()
69
+ {
70
+ return array(
71
+ '2.3.0' => array(
72
+ 'error' => array(
73
+ 'sql' => 'ALTER TABLE {table} MODIFY COLUMN `object` mediumtext'
74
+ ),
75
+ 'queue' => array(
76
+ 'before' => 'dropTable',
77
+ 'after' => 'createTable',
78
+ )
79
+ )
80
+ );
81
+ }
82
+
83
  public function handleOld()
84
  {
85
  // Look if Bronto folder exists in local codepool and recursively remove if it is
app/code/community/Bronto/Common/Model/System/Config/Backend/Cron/Queue.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Common_Model_System_Config_Backend_Cron_Queue extends Bronto_Common_Model_System_Config_Backend_Cron
4
+ {
5
+ protected $_cron_string_path = 'crontab/jobs/bronto_common_queue/schedule/cron_expr';
6
+ protected $_cron_model_path = 'crontab/jobs/bronto_common_queue/run/model';
7
+ }
app/code/community/Bronto/Common/Model/System/Config/Backend/Token.php CHANGED
@@ -85,7 +85,7 @@ class Bronto_Common_Model_System_Config_Backend_Token extends Mage_Core_Model_Co
85
  $sentry = Mage::getModel('bronto_common/keysentry');
86
  $sentry->disableModules($this->getScope(), $this->getScopeId(), $includeCommon);
87
 
88
- if (!Mage::helper('bronto_common')->isVersionMatch(Mage::getVersionInfo(), 1, 9)) {
89
  $sentry->unlinkEmails(
90
  Mage::getModel('bronto_email/message')->getCollection(),
91
  $this->getScope(),
85
  $sentry = Mage::getModel('bronto_common/keysentry');
86
  $sentry->disableModules($this->getScope(), $this->getScopeId(), $includeCommon);
87
 
88
+ if (!Mage::helper('bronto_common')->isVersionMatch(Mage::getVersionInfo(), 1, array(array('edition' => 'Enterprise', 'major' => 9)))) {
89
  $sentry->unlinkEmails(
90
  Mage::getModel('bronto_email/message')->getCollection(),
91
  $this->getScope(),
app/code/community/Bronto/Common/Model/System/Config/Source/Coupon.php ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Common_Model_System_Config_Source_Coupon
4
+ {
5
+ private $_options;
6
+
7
+ /**
8
+ * Gathers all of the sales rules on the system
9
+ *
10
+ * @return array
11
+ */
12
+ protected function _fillOptions($default = false)
13
+ {
14
+ $options = array();
15
+ /** @var Mage_SalesRule_Model_Resource_Rule_Collection $rules */
16
+ $rules = Mage::getModel('salesrule/rule')->getCollection();
17
+
18
+ // If there are any rules
19
+ if ($rules->count()) {
20
+ // Cycle Through Rules
21
+ foreach ($rules as $rule) {
22
+ // If rule is not active, the from date or to date are invalid, or rule doesn't have a coupon just skip this rule
23
+ if (
24
+ !$rule->getIsActive() ||
25
+ (!is_null($rule->getFromDate()) && $rule->getFromDate() > Mage::getModel('core/date')->date('Y-m-d')) ||
26
+ (!is_null($rule->getToDate()) && $rule->getToDate() < Mage::getModel('core/date')->date('Y-m-d')) ||
27
+ ($rule->getCouponType() == Mage_SalesRule_Model_Rule::COUPON_TYPE_NO_COUPON) ||
28
+ ($rule->getCouponType() == Mage_SalesRule_Model_Rule::COUPON_TYPE_SPECIFIC && $rule->getUseAutoGeneration())
29
+ ) {
30
+ continue;
31
+ }
32
+
33
+ // Handle Coupon Label
34
+ $couponLabel = '(Coupon: *Auto Generated*)';
35
+ if ($couponCode = $rule->getPrimaryCoupon()->getCode()) {
36
+ $couponLabel = "(Coupon: {$couponCode})";
37
+ }
38
+
39
+ // Build Option
40
+ $options[] = array(
41
+ 'label' => "{$rule->getName()} {$couponLabel}",
42
+ 'value' => $rule->getRuleId(),
43
+ );
44
+ }
45
+ }
46
+
47
+ $noneSelected = '-- None Selected --';
48
+ if ($default) {
49
+ $noneSelected = '-- Use Default --';
50
+ }
51
+
52
+ // Add -- None Selected -- Option
53
+ array_unshift($options, array(
54
+ 'label' => Mage::helper('bronto_common')->__($noneSelected),
55
+ 'value' => ''
56
+ ));
57
+
58
+ return $options;
59
+ }
60
+
61
+ /**
62
+ * Retrieve option array of sales rules
63
+ *
64
+ * @return array
65
+ */
66
+ public function toOptionArray($noneSelected = false)
67
+ {
68
+ if (empty($this->_options)) {
69
+ $this->_options = $this->_fillOptions($noneSelected);
70
+ }
71
+ return $this->_options;
72
+ }
73
+ }
app/code/community/Bronto/Common/Model/System/Config/Source/Limit.php CHANGED
@@ -12,6 +12,8 @@ class Bronto_Common_Model_System_Config_Source_Limit
12
  public function toOptionArray()
13
  {
14
  return array(
 
 
15
  50 => 50,
16
  100 => 100,
17
  250 => 250,
12
  public function toOptionArray()
13
  {
14
  return array(
15
+ 10 => 10,
16
+ 25 => 25,
17
  50 => 50,
18
  100 => 100,
19
  250 => 250,
app/code/community/Bronto/Common/Model/System/Config/Source/Related.php ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Common_Model_System_Config_Source_Related
4
+ {
5
+
6
+ /**
7
+ * @var array
8
+ */
9
+ protected $_options;
10
+
11
+ /**
12
+ * Related Product Sources key => value pairs
13
+ *
14
+ * @param null $isMultiselect
15
+ *
16
+ * @return array
17
+ */
18
+ public function toOptionArray($isMultiselect = null)
19
+ {
20
+ if (!is_null($this->_options)) {
21
+ return $this->_options;
22
+ }
23
+
24
+ $helper = Mage::helper('bronto_common');
25
+
26
+ $productSources = array(
27
+ array('value' => 'related', 'label' => $helper->__('Related Products')),
28
+ array('value' => 'upsell', 'label' => $helper->__('Up-sells')),
29
+ array('value' => 'crosssell', 'label' => $helper->__('Cross-sells')),
30
+ );
31
+
32
+ $globalSources = array(
33
+ array('value' => 'bestseller', 'label' => $helper->__('Bestsellers')),
34
+ array('value' => 'mostviewed', 'label' => $helper->__('Most Viewed')),
35
+ );
36
+
37
+ $customerSources = array(
38
+ array('value' => 'recentlyviewed', 'label' => $helper->__('Recently Viewed')),
39
+ );
40
+
41
+ $this->_options = array(
42
+ array('label' => $helper->__('Product Specific Sources'), 'value' => $productSources),
43
+ array('label' => $helper->__('Global Sources'), 'value' => $globalSources),
44
+ array('label' => $helper->__('Customer Specific Sources'), 'value' => $customerSources),
45
+ );
46
+
47
+ if (!$isMultiselect) {
48
+ array_unshift($this->_options, array('value' => '', 'label' => $helper->__('--Please Select--')));
49
+ }
50
+
51
+ return $this->_options;
52
+ }
53
+ }
app/code/community/Bronto/Common/controllers/Adminhtml/DebugController.php CHANGED
@@ -52,6 +52,19 @@ class Bronto_Common_Adminhtml_DebugController extends Mage_Adminhtml_Controller_
52
  ->setBody($json);
53
  }
54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  /**
56
  * Sends an archive to the browser
57
  */
52
  ->setBody($json);
53
  }
54
 
55
+ /**
56
+ * Runs the API send queue
57
+ */
58
+ public function sendAction()
59
+ {
60
+ $helper = Mage::helper('bronto_common/api');
61
+ $result = Mage::getModel('bronto_common/observer')->processSendForScope();
62
+ $this->_getSession()->addSuccess(sprintf("Processed %d Deliveries (%d Error / %d Success)", $result['total'], $result['error'], $result['success']));
63
+ $returnParams = array('section' => 'bronto_api');
64
+ $returnParams = array_merge($returnParams, $helper->getScopeParams());
65
+ $this->_redirect('*/system_config/edit', $returnParams);
66
+ }
67
+
68
  /**
69
  * Sends an archive to the browser
70
  */
app/code/community/Bronto/Common/etc/adminhtml.xml CHANGED
@@ -16,6 +16,10 @@
16
  <title>Bronto Popup Section</title>
17
  <sort_order>9994</sort_order>
18
  </bronto_popup>
 
 
 
 
19
  <bronto_api module="bronto_common">
20
  <title>Bronto API Section</title>
21
  <sort_order>9995</sort_order>
16
  <title>Bronto Popup Section</title>
17
  <sort_order>9994</sort_order>
18
  </bronto_popup>
19
+ <bronto_coupon module="bronto_common">
20
+ <title>Bronto Coupon Section</title>
21
+ <sort_order>9996</sort_order>
22
+ </bronto_coupon>
23
  <bronto_api module="bronto_common">
24
  <title>Bronto API Section</title>
25
  <sort_order>9995</sort_order>
app/code/community/Bronto/Common/etc/config.xml CHANGED
@@ -2,7 +2,7 @@
2
  <config>
3
  <modules>
4
  <Bronto_Common>
5
- <version>2.2.2</version>
6
  </Bronto_Common>
7
  </modules>
8
  <global>
@@ -30,6 +30,9 @@
30
  <error>
31
  <table>bronto_common_api_errors</table>
32
  </error>
 
 
 
33
  </entities>
34
  </bronto_common_mysql4>
35
  </models>
@@ -134,6 +137,11 @@
134
  <using_solution_partner>1</using_solution_partner>
135
  </support>
136
  </bronto>
 
 
 
 
 
137
  <bronto_api>
138
  <settings>
139
  <enabled>0</enabled>
@@ -144,6 +152,14 @@
144
  <limit>50</limit>
145
  <threshold>5</threshold>
146
  </settings>
 
 
 
 
 
 
 
 
147
  <soap_options>
148
  <soap_client>Bronto_SoapClient</soap_client>
149
  <observer>Bronto_Common_Model_Api</observer>
@@ -164,6 +180,11 @@
164
  <model>bronto_common/observer::processApiErrors</model>
165
  </run>
166
  </bronto_common_errors>
 
 
 
 
 
167
  <bronto_common_delete_archives>
168
  <schedule>
169
  <cron_expr>0 0 * * *</cron_expr>
2
  <config>
3
  <modules>
4
  <Bronto_Common>
5
+ <version>2.3.0</version>
6
  </Bronto_Common>
7
  </modules>
8
  <global>
30
  <error>
31
  <table>bronto_common_api_errors</table>
32
  </error>
33
+ <queue>
34
+ <table>bronto_common_api_send_queue</table>
35
+ </queue>
36
  </entities>
37
  </bronto_common_mysql4>
38
  </models>
137
  <using_solution_partner>1</using_solution_partner>
138
  </support>
139
  </bronto>
140
+ <bronto_popup>
141
+ <settings>
142
+ <subscribe>0</subscribe>
143
+ </settings>
144
+ </bronto_popup>
145
  <bronto_api>
146
  <settings>
147
  <enabled>0</enabled>
152
  <limit>50</limit>
153
  <threshold>5</threshold>
154
  </settings>
155
+ <queue_settings>
156
+ <enabled>0</enabled>
157
+ <mage_cron>1</mage_cron>
158
+ <frequency>I</frequency>
159
+ <interval>5</interval>
160
+ <minutes>0</minutes>
161
+ <limit>50</limit>
162
+ </queue_settings>
163
  <soap_options>
164
  <soap_client>Bronto_SoapClient</soap_client>
165
  <observer>Bronto_Common_Model_Api</observer>
180
  <model>bronto_common/observer::processApiErrors</model>
181
  </run>
182
  </bronto_common_errors>
183
+ <bronto_common_queue>
184
+ <run>
185
+ <model>bronto_common/observer::processSendQueue</model>
186
+ </run>
187
+ </bronto_common_queue>
188
  <bronto_common_delete_archives>
189
  <schedule>
190
  <cron_expr>0 0 * * *</cron_expr>
app/code/community/Bronto/Common/etc/system.xml CHANGED
@@ -54,10 +54,131 @@
54
  </roundtrip_status>
55
  </fields>
56
  </apitoken>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  <settings>
58
  <label>API Retry Settings</label>
59
  <frontend_type>text</frontend_type>
60
- <sort_order>2</sort_order>
61
  <show_in_default>1</show_in_default>
62
  <show_in_website>0</show_in_website>
63
  <show_in_store>0</show_in_store>
@@ -175,7 +296,7 @@
175
  <cron_list>
176
  <frontend_type>text</frontend_type>
177
  <frontend_model>bronto_common/adminhtml_system_config_cron_error</frontend_model>
178
- <sort_order>3</sort_order>
179
  <show_in_default>1</show_in_default>
180
  <show_in_website>0</show_in_website>
181
  <show_in_store>0</show_in_store>
@@ -183,7 +304,7 @@
183
  <soap_options>
184
  <label>SOAP Options</label>
185
  <frontend_type>text</frontend_type>
186
- <sort_order>5</sort_order>
187
  <show_in_default>1</show_in_default>
188
  <show_in_website>0</show_in_website>
189
  <show_in_store>0</show_in_store>
@@ -297,11 +418,57 @@
297
  </soap_options>
298
  </groups>
299
  </bronto_api>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
300
  <bronto_popup module="bronto_common">
301
  <label>Pop-up Manager</label>
302
  <tab>bronto</tab>
303
  <frontend_type>text</frontend_type>
304
- <sort_order>899</sort_order>
305
  <show_in_default>1</show_in_default>
306
  <show_in_website>1</show_in_website>
307
  <show_in_store>1</show_in_store>
@@ -324,15 +491,11 @@
324
  <expanded>1</expanded>
325
  <comment><![CDATA[The Bronto Pop-up Manager gives you more control
326
  and flexibility to manage pop-up sign-ups throughout their
327
- lifecycle.<br/>If interested, please contact your Account
328
- Manager to learn more about this offering.<br/><br/>
329
- <h2>Pop-up Manager Highlights</h2><ul>
330
- <li style="padding-left: 60px"><strong>&bull;&nbsp;&nbsp;Simple, fast installation</strong> - Paste the single line of JavaScript provided by the Pop-up Manager below, and the rest is magic.</li>
331
- <li style="padding-left: 60px"><strong>&bull;&nbsp;&nbsp;Visual editor</strong> - Create a pop-up sign-up in minutes and make changes to any visual element on the fly.</li>
332
- <li style="padding-left: 60px"><strong>&bull;&nbsp;&nbsp;Customizable design</strong> - Store and manage multiple versions of pop-up sign-ups.</li>
333
- <li style="padding-left: 60px"><strong>&bull;&nbsp;&nbsp;A/B testing</strong> - Test two different versions of a pop-up to determine which performs better.</li>
334
- <li style="padding-left: 60px"><strong>&bull;&nbsp;&nbsp;Bronto-hosted</strong> - Fast and reliable hosting with Bronto's content distribution network.</li>
335
- </ul><br /><br/>]]></comment>
336
  <fields>
337
  <code>
338
  <label>Pop-up Manager Script</label>
@@ -342,6 +505,16 @@
342
  <show_in_website>1</show_in_website>
343
  <show_in_store>1</show_in_store>
344
  </code>
 
 
 
 
 
 
 
 
 
 
345
  </fields>
346
  </settings>
347
  </groups>
54
  </roundtrip_status>
55
  </fields>
56
  </apitoken>
57
+ <queue_settings>
58
+ <label>API Send Queue Settings</label>
59
+ <frontend_type>text</frontend_type>
60
+ <sort_order>2</sort_order>
61
+ <show_in_default>1</show_in_default>
62
+ <show_in_website>1</show_in_website>
63
+ <show_in_store>1</show_in_store>
64
+ <expanded>1</expanded>
65
+ <fields>
66
+ <enabled>
67
+ <label>Enable API Send Queuing</label>
68
+ <frontend_type>select</frontend_type>
69
+ <backend_model>bronto_common/system_config_backend_enable</backend_model>
70
+ <source_model>adminhtml/system_config_source_yesno</source_model>
71
+ <sort_order>0</sort_order>
72
+ <show_in_default>1</show_in_default>
73
+ <show_in_website>1</show_in_website>
74
+ <show_in_store>1</show_in_store>
75
+ <comment><![CDATA[With send queuing enabled,
76
+ <em>all</em>
77
+ transactional emails will be placed in a queue,
78
+ and must be flushed. While this is a more performant
79
+ method, real-time sending is essentially disabled.
80
+ It is <em>highly</em>
81
+ recommended to flush this queue using the system
82
+ cron, or the lowest available interval Magento cron.]]></comment>
83
+ </enabled>
84
+ <mage_cron>
85
+ <label>Use Magento Cron</label>
86
+ <depends>
87
+ <enabled>1</enabled>
88
+ </depends>
89
+ <frontend_type>select</frontend_type>
90
+ <frontend_model>bronto_common/adminhtml_system_config_form_field</frontend_model>
91
+ <source_model>adminhtml/system_config_source_yesno</source_model>
92
+ <backend_model>bronto_common/system_config_backend_cron_queue</backend_model>
93
+ <sort_order>2</sort_order>
94
+ <show_in_default>1</show_in_default>
95
+ <show_in_website>1</show_in_website>
96
+ <show_in_store>1</show_in_store>
97
+ <comment>
98
+ <![CDATA[Setting to <em>No</em> will prevent the Magento Cron from triggering the import process for this module.<br />For more details, check the <em>Cron Settings</em> section in the <strong>Bronto &raquo; Advanced</strong> tab.]]></comment>
99
+ </mage_cron>
100
+ <frequency>
101
+ <label>Frequency</label>
102
+ <depends>
103
+ <enabled>1</enabled>
104
+ <mage_cron>1</mage_cron>
105
+ </depends>
106
+ <frontend_type>select</frontend_type>
107
+ <source_model>bronto_common/system_config_source_cron_frequency</source_model>
108
+ <backend_model>bronto_common/system_config_backend_cron_error</backend_model>
109
+ <sort_order>3</sort_order>
110
+ <show_in_default>1</show_in_default>
111
+ <show_in_website>1</show_in_website>
112
+ <show_in_store>1</show_in_store>
113
+ </frequency>
114
+ <interval>
115
+ <label>Interval</label>
116
+ <depends>
117
+ <enabled>1</enabled>
118
+ <frequency>I</frequency>
119
+ <mage_cron>1</mage_cron>
120
+ </depends>
121
+ <frontend_type>select</frontend_type>
122
+ <source_model>bronto_common/system_config_source_cron_minutes</source_model>
123
+ <sort_order>4</sort_order>
124
+ <show_in_default>1</show_in_default>
125
+ <show_in_website>1</show_in_website>
126
+ <show_in_store>1</show_in_store>
127
+ <comment>Set this value larger than your cron.php launch period.</comment>
128
+ </interval>
129
+ <minutes>
130
+ <label>Minute of the Hour</label>
131
+ <depends>
132
+ <frequency>H</frequency>
133
+ <mage_cron>1</mage_cron>
134
+ <enabled>1</enabled>
135
+ </depends>
136
+ <frontend_type>text</frontend_type>
137
+ <sort_order>40</sort_order>
138
+ <show_in_default>1</show_in_default>
139
+ <show_in_website>1</show_in_website>
140
+ <show_in_store>1</show_in_store>
141
+ <comment>Valid range: 0-59 (default 0).</comment>
142
+ </minutes>
143
+ <time>
144
+ <label>Start Time</label>
145
+ <depends>
146
+ <enabled>1</enabled>
147
+ <mage_cron>1</mage_cron>
148
+ </depends>
149
+ <frontend_type>time</frontend_type>
150
+ <sort_order>5</sort_order>
151
+ <show_in_default>1</show_in_default>
152
+ <show_in_website>1</show_in_website>
153
+ <show_in_store>1</show_in_store>
154
+ </time>
155
+ <limit>
156
+ <label>Limit</label>
157
+ <depends>
158
+ <enabled>1</enabled>
159
+ </depends>
160
+ <frontend_type>select</frontend_type>
161
+ <source_model>bronto_common/system_config_source_limit</source_model>
162
+ <sort_order>6</sort_order>
163
+ <show_in_default>1</show_in_default>
164
+ <show_in_website>1</show_in_website>
165
+ <show_in_store>1</show_in_store>
166
+ <comment>Total API deliveries to process every run.</comment>
167
+ </limit>
168
+ </fields>
169
+ </queue_settings>
170
+ <queue_cron_list>
171
+ <frontend_type>text</frontend_type>
172
+ <frontend_model>bronto_common/adminhtml_system_config_cron_queue</frontend_model>
173
+ <sort_order>3</sort_order>
174
+ <show_in_default>1</show_in_default>
175
+ <show_in_website>0</show_in_website>
176
+ <show_in_store>0</show_in_store>
177
+ </queue_cron_list>
178
  <settings>
179
  <label>API Retry Settings</label>
180
  <frontend_type>text</frontend_type>
181
+ <sort_order>4</sort_order>
182
  <show_in_default>1</show_in_default>
183
  <show_in_website>0</show_in_website>
184
  <show_in_store>0</show_in_store>
296
  <cron_list>
297
  <frontend_type>text</frontend_type>
298
  <frontend_model>bronto_common/adminhtml_system_config_cron_error</frontend_model>
299
+ <sort_order>5</sort_order>
300
  <show_in_default>1</show_in_default>
301
  <show_in_website>0</show_in_website>
302
  <show_in_store>0</show_in_store>
304
  <soap_options>
305
  <label>SOAP Options</label>
306
  <frontend_type>text</frontend_type>
307
+ <sort_order>6</sort_order>
308
  <show_in_default>1</show_in_default>
309
  <show_in_website>0</show_in_website>
310
  <show_in_store>0</show_in_store>
418
  </soap_options>
419
  </groups>
420
  </bronto_api>
421
+ <bronto_coupon module="bronto_common">
422
+ <label>Coupon Manager</label>
423
+ <tab>bronto</tab>
424
+ <frontend_type>text</frontend_type>
425
+ <sort_order>899</sort_order>
426
+ <show_in_default>1</show_in_default>
427
+ <show_in_website>1</show_in_website>
428
+ <show_in_store>1</show_in_store>
429
+ <groups>
430
+ <about>
431
+ <frontend_type>text</frontend_type>
432
+ <frontend_model>bronto_common/adminhtml_system_config_about</frontend_model>
433
+ <sort_order>0</sort_order>
434
+ <show_in_default>1</show_in_default>
435
+ <show_in_website>1</show_in_website>
436
+ <show_in_store>1</show_in_store>
437
+ </about>
438
+ <settings>
439
+ <label>Settings</label>
440
+ <frontend_type>text</frontend_type>
441
+ <sort_order>10</sort_order>
442
+ <show_in_default>1</show_in_default>
443
+ <show_in_website>1</show_in_website>
444
+ <show_in_store>1</show_in_store>
445
+ <expanded>1</expanded>
446
+ <comment><![CDATA[The Bronto Coupon Manager gives you more control
447
+ and flexibility to coupons and redemption throughout their
448
+ lifecycle.<br/>If interested, please request info on the
449
+ App site: <a
450
+ href="https://appcenter.bronto.com/apps/coupon-manager">Coupon
451
+ Manager</a>
452
+ <br /><br/>]]></comment>
453
+ <fields>
454
+ <site_hash>
455
+ <label>Coupon Manager Account ID</label>
456
+ <frontend_type>text</frontend_type>
457
+ <comment>Found in the settings dialog of the Coupon Manager.</comment>
458
+ <sort_order>0</sort_order>
459
+ <show_in_default>1</show_in_default>
460
+ <show_in_website>1</show_in_website>
461
+ <show_in_store>1</show_in_store>
462
+ </site_hash>
463
+ </fields>
464
+ </settings>
465
+ </groups>
466
+ </bronto_coupon>
467
  <bronto_popup module="bronto_common">
468
  <label>Pop-up Manager</label>
469
  <tab>bronto</tab>
470
  <frontend_type>text</frontend_type>
471
+ <sort_order>898</sort_order>
472
  <show_in_default>1</show_in_default>
473
  <show_in_website>1</show_in_website>
474
  <show_in_store>1</show_in_store>
491
  <expanded>1</expanded>
492
  <comment><![CDATA[The Bronto Pop-up Manager gives you more control
493
  and flexibility to manage pop-up sign-ups throughout their
494
+ lifecycle.<br/>If interested, please request info on the
495
+ App site: <a
496
+ href="https://appcenter.bronto.com/apps/pop-up-manager">Pop-Up
497
+ Manager</a>
498
+ <br /><br/>]]></comment>
 
 
 
 
499
  <fields>
500
  <code>
501
  <label>Pop-up Manager Script</label>
505
  <show_in_website>1</show_in_website>
506
  <show_in_store>1</show_in_store>
507
  </code>
508
+ <subscribe>
509
+ <label>Subscribe to Magento</label>
510
+ <frontend_type>select</frontend_type>
511
+ <source_model>adminhtml/system_config_source_yesno</source_model>
512
+ <comment><![CDATA[If <em>Yes</em>, the customer subscribing to the Pop-Up will be subscribed to the Magento newsletter for the store view.]]></comment>
513
+ <sort_order>1</sort_order>
514
+ <show_in_default>1</show_in_default>
515
+ <show_in_website>1</show_in_website>
516
+ <show_in_store>1</show_in_store>
517
+ </subscribe>
518
  </fields>
519
  </settings>
520
  </groups>
app/code/community/Bronto/Common/sql/bronto_common_setup/mysql4-install-2.3.0.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ $installer = $this;
4
+
5
+ $installer->startSetup();
6
+
7
+ try {
8
+ $installer->createTables();
9
+ } catch (Exception $e) {
10
+ Mage::helper('bronto_common')->writeError($e->getMessage());
11
+ }
12
+
13
+ $installer->endSetup();
app/code/community/Bronto/Common/sql/bronto_common_setup/mysql4-upgrade-2.2.2-2.3.0.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ $installer = $this;
4
+
5
+ $installer->startSetup();
6
+ $installer->updateTables('2.3.0');
7
+ $installer->endSetup();
app/code/community/Bronto/Customer/Block/Adminhtml/System/Config/Cron.php CHANGED
@@ -16,6 +16,7 @@ class Bronto_Customer_Block_Adminhtml_System_Config_Cron extends Bronto_Common_B
16
  {
17
  $this->addButton($this->getLayout()->createBlock('bronto_customer/adminhtml_widget_button_sync'));
18
  $this->addButton($this->getLayout()->createBlock('bronto_customer/adminhtml_widget_button_reset'));
 
19
  $this->addButton($this->getLayout()->createBlock('bronto_customer/adminhtml_widget_button_run'));
20
 
21
  return parent::_prepareLayout();
16
  {
17
  $this->addButton($this->getLayout()->createBlock('bronto_customer/adminhtml_widget_button_sync'));
18
  $this->addButton($this->getLayout()->createBlock('bronto_customer/adminhtml_widget_button_reset'));
19
+ $this->addButton($this->getLayout()->createBlock('bronto_customer/adminhtml_widget_button_mark'));
20
  $this->addButton($this->getLayout()->createBlock('bronto_customer/adminhtml_widget_button_run'));
21
 
22
  return parent::_prepareLayout();
app/code/community/Bronto/Customer/Block/Adminhtml/System/Config/Suppressed.php CHANGED
@@ -16,4 +16,12 @@ class Bronto_Customer_Block_Adminhtml_System_Config_Suppressed
16
  {
17
  return Mage::helper('bronto_common')->getScopeUrl('adminhtml/customer/suppression');
18
  }
19
- }
 
 
 
 
 
 
 
 
16
  {
17
  return Mage::helper('bronto_common')->getScopeUrl('adminhtml/customer/suppression');
18
  }
19
+
20
+ /**
21
+ * @see parent
22
+ */
23
+ public function getResetUrl()
24
+ {
25
+ return Mage::helper('bronto_common')->getScopeUrl('adminhtml/customer/reset');
26
+ }
27
+ }
app/code/community/Bronto/Customer/Block/Adminhtml/Widget/Button/Mark.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Customer_Block_Adminhtml_Widget_Button_Mark extends Mage_Adminhtml_Block_Widget_Button
4
+ {
5
+ /**
6
+ * @see parent
7
+ */
8
+ protected function _construct()
9
+ {
10
+ $this->setLabel('Mark All Imported');
11
+ $this->setOnClick("deleteConfirm('This will mark all customers as imported and will not send the information to Bronto.\\n\\nAre you sure you want to do this?', '" . Mage::helper('bronto_customer')->getScopeUrl('*/customer/mark') . "'); return false;");
12
+ $this->setClass('bronto-cron-mark');
13
+
14
+ if (!Mage::helper('bronto_customer')->isModuleActive() || (!Mage::helper('bronto_common')->isDebugEnabled())) {
15
+ $this->setDisabled(true)->setClass('disabled');
16
+ }
17
+ }
18
+ }
app/code/community/Bronto/Customer/Model/Observer.php CHANGED
@@ -125,14 +125,14 @@ class Bronto_Customer_Model_Observer extends Mage_Core_Model_Abstract
125
 
126
  // Final flush (for any we miss)
127
  if (!empty($customerCache)) {
128
- $results = $this->_flushCustomers($contactObject, $customerCache, $result);
129
  }
130
 
131
- Mage::helper('bronto_customer')->writeDebug(' Success: ' . $results['success']);
132
- Mage::helper('bronto_customer')->writeDebug(' Error: ' . $results['error']);
133
- Mage::helper('bronto_customer')->writeDebug(' Total: ' . $results['total']);
134
 
135
- return $results;
136
  }
137
 
138
  /**
@@ -273,6 +273,7 @@ class Bronto_Customer_Model_Observer extends Mage_Core_Model_Abstract
273
 
274
  $_attributeType = $attribute->getFrontendInput();
275
  $_attributeCode = $attribute->getAttributeCode();
 
276
 
277
  // Pick up Website/Store/Group Values
278
  switch ($_attributeCode) {
@@ -300,6 +301,10 @@ class Bronto_Customer_Model_Observer extends Mage_Core_Model_Abstract
300
  break;
301
  }
302
 
 
 
 
 
303
  // Format Attribute Values
304
  switch ($_attributeType) {
305
  case 'select':
@@ -321,22 +326,30 @@ class Bronto_Customer_Model_Observer extends Mage_Core_Model_Abstract
321
 
322
  return implode(', ', $values);
323
  break;
324
- case 'date':
325
- $dates = explode(' ', $value);
326
- $date = $dates[0];
327
-
328
- if (!preg_match('/^[\d]{4}-[\d]{2}-[\d]{2}$/', $date)) {
329
- return '';
330
- } else {
331
- return implode('T', $dates) . Mage::getSingleton('core/date')->date('P');
332
- }
333
- break;
334
  default:
335
  return $value;
336
  break;
337
  }
338
  }
339
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
340
  /**
341
  * @param Bronto_Api_Contact $customerObject
342
  * @param array $customerCache
125
 
126
  // Final flush (for any we miss)
127
  if (!empty($customerCache)) {
128
+ $result = $this->_flushCustomers($contactObject, $customerCache, $result);
129
  }
130
 
131
+ Mage::helper('bronto_customer')->writeDebug(' Success: ' . $result['success']);
132
+ Mage::helper('bronto_customer')->writeDebug(' Error: ' . $result['error']);
133
+ Mage::helper('bronto_customer')->writeDebug(' Total: ' . $result['total']);
134
 
135
+ return $result;
136
  }
137
 
138
  /**
273
 
274
  $_attributeType = $attribute->getFrontendInput();
275
  $_attributeCode = $attribute->getAttributeCode();
276
+ $_attributeBack = $attribute->getBackendType();
277
 
278
  // Pick up Website/Store/Group Values
279
  switch ($_attributeCode) {
301
  break;
302
  }
303
 
304
+ if ($_attributeBack == 'datetime' || $_attributeType == 'date') {
305
+ $value = $this->_formatDateValue($value);
306
+ }
307
+
308
  // Format Attribute Values
309
  switch ($_attributeType) {
310
  case 'select':
326
 
327
  return implode(', ', $values);
328
  break;
 
 
 
 
 
 
 
 
 
 
329
  default:
330
  return $value;
331
  break;
332
  }
333
  }
334
 
335
+ /**
336
+ * Format the value into a Bronto acceptable date
337
+ *
338
+ * @param string $value
339
+ * @return string
340
+ */
341
+ protected function _formatDateValue($value)
342
+ {
343
+ $dates = explode(' ', $value);
344
+ $date = $dates[0];
345
+
346
+ if (!preg_match('/^[\d]{4}-[\d]{2}-[\d]{2}$/', $date)) {
347
+ return '';
348
+ } else {
349
+ return implode('T', $dates) . Mage::getSingleton('core/date')->date('P');
350
+ }
351
+ }
352
+
353
  /**
354
  * @param Bronto_Api_Contact $customerObject
355
  * @param array $customerCache
app/code/community/Bronto/Customer/controllers/Adminhtml/CustomerController.php CHANGED
@@ -51,6 +51,34 @@ class Bronto_Customer_Adminhtml_CustomerController extends Mage_Adminhtml_Contro
51
  $this->_redirect('*/system_config/edit', $returnParams);
52
  }
53
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  /**
55
  * Reset all Customers
56
  */
@@ -62,6 +90,7 @@ class Bronto_Customer_Adminhtml_CustomerController extends Mage_Adminhtml_Contro
62
  $adapter = $resource->getWriteAdapter();
63
 
64
  $queue_id = $this->getRequest()->getParam('queue_id', false);
 
65
 
66
  $where = array();
67
  if ($storeIds) {
@@ -72,6 +101,10 @@ class Bronto_Customer_Adminhtml_CustomerController extends Mage_Adminhtml_Contro
72
  $where['queue_id = ?'] = $queue_id;
73
  }
74
 
 
 
 
 
75
  try {
76
  $adapter->update(
77
  $resource->getTable('bronto_customer/queue'),
51
  $this->_redirect('*/system_config/edit', $returnParams);
52
  }
53
 
54
+ /**
55
+ * Marks all Customers as imported
56
+ */
57
+ public function markAction()
58
+ {
59
+ $helper = Mage::helper('bronto_customer');
60
+ $resource = Mage::getResourceModel('bronto_customer/queue');
61
+ $adapter = $resource->getWriteAdapter();
62
+
63
+ try {
64
+ $date = Mage::getSingleton('core/date')->gmtDate();
65
+ $adapter->update(
66
+ $resource->getTable('bronto_customer/queue'),
67
+ array('bronto_imported' => $date),
68
+ array(
69
+ 'bronto_imported IS NULL' => '',
70
+ 'bronto_suppressed IS NULL' => ''
71
+ ));
72
+ } catch (Exception $e) {
73
+ $helper->writeError($e);
74
+ $this->_getSession()->addError('Mark All failed: ' . $e->getMessage());
75
+ }
76
+
77
+ $returnParams = array('section' => 'bronto_customer');
78
+ $returnParams = array_merge($returnParams, $helper->getScopeParams());
79
+ $this->_redirect('*/system_config/edit', $returnParams);
80
+ }
81
+
82
  /**
83
  * Reset all Customers
84
  */
90
  $adapter = $resource->getWriteAdapter();
91
 
92
  $queue_id = $this->getRequest()->getParam('queue_id', false);
93
+ $suppressed = $this->getRequest()->getParam('suppressed', false);
94
 
95
  $where = array();
96
  if ($storeIds) {
101
  $where['queue_id = ?'] = $queue_id;
102
  }
103
 
104
+ if ($suppressed) {
105
+ $where['bronto_suppressed IS NOT NULL'] = '';
106
+ }
107
+
108
  try {
109
  $adapter->update(
110
  $resource->getTable('bronto_customer/queue'),
app/code/community/Bronto/Customer/etc/system.xml CHANGED
@@ -152,6 +152,17 @@
152
  <show_in_website>1</show_in_website>
153
  <show_in_store>1</show_in_store>
154
  <expanded>0</expanded>
 
 
 
 
 
 
 
 
 
 
 
155
  </suppressed>
156
  <attributes>
157
  <label>Customer Attributes</label>
152
  <show_in_website>1</show_in_website>
153
  <show_in_store>1</show_in_store>
154
  <expanded>0</expanded>
155
+ <fields>
156
+ <reset>
157
+ <label>Reset All Suppressed Customers</label>
158
+ <frontend_type>text</frontend_type>
159
+ <frontend_model>bronto_common/adminhtml_system_config_suppressed_reset</frontend_model>
160
+ <sort_order>0</sort_order>
161
+ <show_in_default>1</show_in_default>
162
+ <show_in_website>1</show_in_website>
163
+ <show_in_store>1</show_in_store>
164
+ </reset>
165
+ </fields>
166
  </suppressed>
167
  <attributes>
168
  <label>Customer Attributes</label>
app/code/community/Bronto/Email/Block/Adminhtml/System/Email/Import/Grid.php CHANGED
@@ -7,6 +7,16 @@
7
  class Bronto_Email_Block_Adminhtml_System_Email_Import_Grid extends Mage_Adminhtml_Block_System_Email_Template_Grid
8
  {
9
 
 
 
 
 
 
 
 
 
 
 
10
  protected function _prepareCollection()
11
  {
12
  /* @var $collection Bronto_Email_Model_Mysql4_Template_Collection */
@@ -16,7 +26,7 @@ class Bronto_Email_Block_Adminhtml_System_Email_Import_Grid extends Mage_Adminht
16
  $brontoTable = Mage::getSingleton('core/resource')->getTableName('bronto_email/message');
17
 
18
  // Apply conditional logic to handle 1.9 overriding collection _construct
19
- if (Mage::helper('bronto_common')->isVersionMatch(Mage::getVersionInfo(), 1, array(4, 5, 9, 10))) {
20
  $collection->getSelect()->joinLeft(
21
  $brontoTable,
22
  "`{$templateTable}`.`template_id` = `{$brontoTable}`.`core_template_id`"
@@ -60,13 +70,13 @@ class Bronto_Email_Block_Adminhtml_System_Email_Import_Grid extends Mage_Adminht
60
  $this->setMassactionIdField('template_id');
61
  $this->getMassactionBlock()->setFormFieldName('template_id');
62
 
63
- $stores = Mage::app()->getStores();
64
  if (is_array($stores) && count($stores) >= 1) {
65
  foreach ($stores as $store) {
66
  if (Mage::helper('bronto_email')->isEnabled('store', $store->getId())) {
67
  $this->getMassactionBlock()->addItem('import|' . $store->getCode(), array(
68
  'url' => $this->getUrl('*/*/massImport', array('template_id' => '', 'store_id' => $store->getId())),
69
- 'label' => Mage::helper('bronto_email')->__('Import For Store: ' . $store->getName()),
70
  'confirm' => Mage::helper('bronto_email')->__('Are you sure? This will import the selected template(s) to Bronto for the specified store.'),
71
  ));
72
  }
7
  class Bronto_Email_Block_Adminhtml_System_Email_Import_Grid extends Mage_Adminhtml_Block_System_Email_Template_Grid
8
  {
9
 
10
+ /**
11
+ * Turn off AJAX for this grid, as it kicks back to the Dashboard
12
+ * @see parent
13
+ */
14
+ protected function _construct()
15
+ {
16
+ parent::_construct();
17
+ $this->setUseAjax(false);
18
+ }
19
+
20
  protected function _prepareCollection()
21
  {
22
  /* @var $collection Bronto_Email_Model_Mysql4_Template_Collection */
26
  $brontoTable = Mage::getSingleton('core/resource')->getTableName('bronto_email/message');
27
 
28
  // Apply conditional logic to handle 1.9 overriding collection _construct
29
+ if (Mage::helper('bronto_common')->isVersionMatch(Mage::getVersionInfo(), 1, array(4, 5, array('edition' => 'Enterprise', 'major' => 9), 10))) {
30
  $collection->getSelect()->joinLeft(
31
  $brontoTable,
32
  "`{$templateTable}`.`template_id` = `{$brontoTable}`.`core_template_id`"
70
  $this->setMassactionIdField('template_id');
71
  $this->getMassactionBlock()->setFormFieldName('template_id');
72
 
73
+ $stores = Mage::app()->getStores(true);
74
  if (is_array($stores) && count($stores) >= 1) {
75
  foreach ($stores as $store) {
76
  if (Mage::helper('bronto_email')->isEnabled('store', $store->getId())) {
77
  $this->getMassactionBlock()->addItem('import|' . $store->getCode(), array(
78
  'url' => $this->getUrl('*/*/massImport', array('template_id' => '', 'store_id' => $store->getId())),
79
+ 'label' => Mage::helper('bronto_email')->__('Import For Store: ' . (!$store->getId() ? 'Default' : $store->getName())),
80
  'confirm' => Mage::helper('bronto_email')->__('Are you sure? This will import the selected template(s) to Bronto for the specified store.'),
81
  ));
82
  }
app/code/community/Bronto/Email/Block/Adminhtml/System/Email/Import/Grid/Renderer/Action.php CHANGED
@@ -43,13 +43,13 @@ class Bronto_Email_Block_Adminhtml_System_Email_Import_Grid_Renderer_Action exte
43
  'caption' => $this->__('Edit'),
44
  );
45
 
46
- $stores = Mage::app()->getStores();
47
  if (is_array($stores) && count($stores) >= 1) {
48
  foreach ($stores as $store) {
49
  if (Mage::helper('bronto_email')->isEnabled('store', $store->getId())) {
50
  $actions[] = array(
51
  'url' => $this->getUrl('*/*/massImport', array('template_id' => $row->getId(), 'store_id' => $store->getId())),
52
- 'caption' => $this->__('Import For Store: ' . $store->getName()),
53
  'confirm' => Mage::helper('bronto_email')->__('Are you sure you want to import the selected template?'),
54
  );
55
  }
43
  'caption' => $this->__('Edit'),
44
  );
45
 
46
+ $stores = Mage::app()->getStores(true);
47
  if (is_array($stores) && count($stores) >= 1) {
48
  foreach ($stores as $store) {
49
  if (Mage::helper('bronto_email')->isEnabled('store', $store->getId())) {
50
  $actions[] = array(
51
  'url' => $this->getUrl('*/*/massImport', array('template_id' => $row->getId(), 'store_id' => $store->getId())),
52
+ 'caption' => $this->__('Import For Store: ' . (!$store->getId() ? 'Default' : $store->getName())),
53
  'confirm' => Mage::helper('bronto_email')->__('Are you sure you want to import the selected template?'),
54
  );
55
  }
app/code/community/Bronto/Email/Block/Adminhtml/System/Email/Template/Edit/Form.php CHANGED
@@ -95,7 +95,7 @@ class Bronto_Email_Block_Adminhtml_System_Email_Template_Edit_Form extends Mage_
95
  'title' => Mage::helper('adminhtml')->__('Store View'),
96
  'onchange' => "updateMessages();",
97
  'required' => true,
98
- 'values' => $this->_getActiveStoreValuesForForm(false, false),
99
  ));
100
  } else {
101
  $fieldset->addField('store_id', 'hidden', array(
@@ -126,9 +126,11 @@ class Bronto_Email_Block_Adminhtml_System_Email_Template_Edit_Form extends Mage_
126
  // Disable Some
127
  $('bronto_message_id').disable();
128
  $('sales_rule').disable();
 
129
  $('orig_template_text').disable();
130
  $('container_bronto_message_id').hide();
131
  $('container_sales_rule').hide();
 
132
  $('container_orig_template_text').hide();
133
 
134
  // Enable Others
@@ -146,9 +148,11 @@ class Bronto_Email_Block_Adminhtml_System_Email_Template_Edit_Form extends Mage_
146
  // Enable Some
147
  $('bronto_message_id').enable();
148
  $('sales_rule').enable();
 
149
  $('orig_template_text').enable();
150
  $('container_bronto_message_id').show();
151
  $('container_sales_rule').show();
 
152
  $('container_orig_template_text').show();
153
 
154
  // Disable Others
@@ -205,6 +209,7 @@ class Bronto_Email_Block_Adminhtml_System_Email_Template_Edit_Form extends Mage_
205
  // Add hidden fields to hold backups of the necessary values
206
  $fieldset->addField('bronto_message_id_hidden', 'hidden', array('name' => 'bronto_message_id_hidden'));
207
  $fieldset->addField('sales_rule_hidden', 'hidden', array('name' => 'sales_rule_hidden'));
 
208
  $fieldset->addField('template_subject_hidden', 'hidden', array('name' => 'template_subject_hidden'));
209
  $fieldset->addField('template_text_hidden', 'hidden', array('name' => 'template_text_hidden'));
210
  $fieldset->addField('template_styles_hidden', 'hidden', array('name' => 'template_styles_hidden'));
@@ -235,10 +240,22 @@ class Bronto_Email_Block_Adminhtml_System_Email_Template_Edit_Form extends Mage_
235
  'note' => $this->__('Use API tag <em>%%%%#couponCode%%%%</em> within your message in Bronto. You are responsible for ensuring the shopping cart price rule is active and valid, or else it may appear blank.'),
236
  'container_id' => 'container_sales_rule',
237
  'onchange' => "syncHiddenValue(this);",
238
- 'values' => Mage::helper('bronto_common/salesrule')->getRuleOptionsArray(),
239
  'required' => false,
240
  ));
241
 
 
 
 
 
 
 
 
 
 
 
 
 
242
  // Display Variables that are available for the original template
243
  $fieldset->addField('template_variables_key', 'label', array(
244
  'container_id' => 'template_variables_key_row',
@@ -304,6 +321,12 @@ class Bronto_Email_Block_Adminhtml_System_Email_Template_Edit_Form extends Mage_
304
  }
305
 
306
  if ($templateId) {
 
 
 
 
 
 
307
  $form->addValues($this->getEmailTemplate()->getData());
308
  $form->addValues(array(
309
  'template_variables' => Zend_Json::encode($this->getEmailTemplate()->getVariablesOptionArray(true)),
@@ -313,6 +336,7 @@ class Bronto_Email_Block_Adminhtml_System_Email_Template_Edit_Form extends Mage_
313
  'template_subject_hidden' => $this->getEmailTemplate()->getTemplateSubject(),
314
  'template_text_hidden' => $this->getEmailTemplate()->getTemplateText(),
315
  'template_styles_hidden' => $this->getEmailTemplate()->getTemplateStyles(),
 
316
  ));
317
  }
318
 
95
  'title' => Mage::helper('adminhtml')->__('Store View'),
96
  'onchange' => "updateMessages();",
97
  'required' => true,
98
+ 'values' => $this->_getActiveStoreValuesForForm(true, true),
99
  ));
100
  } else {
101
  $fieldset->addField('store_id', 'hidden', array(
126
  // Disable Some
127
  $('bronto_message_id').disable();
128
  $('sales_rule').disable();
129
+ $('product_recommendation').disable();
130
  $('orig_template_text').disable();
131
  $('container_bronto_message_id').hide();
132
  $('container_sales_rule').hide();
133
+ $('container_product_recommendation').hide();
134
  $('container_orig_template_text').hide();
135
 
136
  // Enable Others
148
  // Enable Some
149
  $('bronto_message_id').enable();
150
  $('sales_rule').enable();
151
+ $('product_recommendation').enable();
152
  $('orig_template_text').enable();
153
  $('container_bronto_message_id').show();
154
  $('container_sales_rule').show();
155
+ $('container_product_recommendation').show();
156
  $('container_orig_template_text').show();
157
 
158
  // Disable Others
209
  // Add hidden fields to hold backups of the necessary values
210
  $fieldset->addField('bronto_message_id_hidden', 'hidden', array('name' => 'bronto_message_id_hidden'));
211
  $fieldset->addField('sales_rule_hidden', 'hidden', array('name' => 'sales_rule_hidden'));
212
+ $fieldset->addField('product_recommendation_hidden', 'hidden', array('name' => 'product_recommendation_hidden'));
213
  $fieldset->addField('template_subject_hidden', 'hidden', array('name' => 'template_subject_hidden'));
214
  $fieldset->addField('template_text_hidden', 'hidden', array('name' => 'template_text_hidden'));
215
  $fieldset->addField('template_styles_hidden', 'hidden', array('name' => 'template_styles_hidden'));
240
  'note' => $this->__('Use API tag <em>%%%%#couponCode%%%%</em> within your message in Bronto. You are responsible for ensuring the shopping cart price rule is active and valid, or else it may appear blank.'),
241
  'container_id' => 'container_sales_rule',
242
  'onchange' => "syncHiddenValue(this);",
243
+ 'values' => Mage::getModel('bronto_common/system_config_source_coupon')->toOptionArray(true),
244
  'required' => false,
245
  ));
246
 
247
+ if (Mage::helper('bronto_product')->isEnabledForAny()) {
248
+ $fieldset->addField('product_recommendation', 'select', array(
249
+ 'name' => 'product_recommendation',
250
+ 'container_id' => 'container_product_recommendation',
251
+ 'onchange' => "syncHiddenValue(this);",
252
+ 'label' => Mage::helper('adminhtml')->__('Product Recommendations'),
253
+ 'required' => false,
254
+ 'values' => Mage::getModel('bronto_product/recommendation')->toOptionArray(true),
255
+ 'note' => $this->__('Inject related product content into this message. Recommendations are created in <strong>Promotions</strong> &raquo; <strong>Bronto Product Recommendations')
256
+ ));
257
+ }
258
+
259
  // Display Variables that are available for the original template
260
  $fieldset->addField('template_variables_key', 'label', array(
261
  'container_id' => 'template_variables_key_row',
321
  }
322
 
323
  if ($templateId) {
324
+ if ($this->getEmailTemplate()->getUseDefaultSalesRule()) {
325
+ $this->getEmailTemplate()->setSalesRule('default');
326
+ }
327
+ if ($this->getEmailTemplate()->getUseDefaultRec()) {
328
+ $this->getEmailTemplate()->setProductRecommendation('default');
329
+ }
330
  $form->addValues($this->getEmailTemplate()->getData());
331
  $form->addValues(array(
332
  'template_variables' => Zend_Json::encode($this->getEmailTemplate()->getVariablesOptionArray(true)),
336
  'template_subject_hidden' => $this->getEmailTemplate()->getTemplateSubject(),
337
  'template_text_hidden' => $this->getEmailTemplate()->getTemplateText(),
338
  'template_styles_hidden' => $this->getEmailTemplate()->getTemplateStyles(),
339
+ 'product_recommendation_hidden' => $this->getEmailTemplate()->getProductRecommendation(),
340
  ));
341
  }
342
 
app/code/community/Bronto/Email/Block/Adminhtml/System/Email/Template/Grid.php CHANGED
@@ -9,8 +9,8 @@ class Bronto_Email_Block_Adminhtml_System_Email_Template_Grid extends Mage_Admin
9
  protected function _construct()
10
  {
11
  parent::_construct();
12
-
13
  $this->setId('systemBrontoEmailTemplateGrid');
 
14
  }
15
 
16
  protected function _prepareCollection()
@@ -22,7 +22,7 @@ class Bronto_Email_Block_Adminhtml_System_Email_Template_Grid extends Mage_Admin
22
  $brontoTable = Mage::getSingleton('core/resource')->getTableName('bronto_email/message');
23
 
24
  // Apply conditional logic to handle 1.9 overriding collection _construct
25
- if (Mage::helper('bronto_common')->isVersionMatch(Mage::getVersionInfo(), 1, array(4, 5, 9, 10))) {
26
  $collection->getSelect()->joinLeft(
27
  $brontoTable,
28
  "`{$templateTable}`.`template_id` = `{$brontoTable}`.`core_template_id`"
@@ -88,25 +88,16 @@ class Bronto_Email_Block_Adminhtml_System_Email_Template_Grid extends Mage_Admin
88
  )
89
  );
90
 
91
- $storeCodes = array();
92
- foreach (Mage::app()->getStores() as $id => $store) {
93
- $storeName = $store->getName();
94
- if (!Mage::helper('bronto_email')->isEnabled('store', $store->getId())) {
95
- $storeName .= ' (Disabled)';
96
- }
97
- $storeCodes[$id] = $storeName;
 
98
  }
99
 
100
- $this->addColumn(
101
- 'store', array(
102
- 'header' => Mage::helper('adminhtml')->__('Store'),
103
- 'index' => 'store_id',
104
- 'type' => 'options',
105
- 'options' => $storeCodes,
106
- 'renderer' => 'bronto_email/adminhtml_system_email_template_grid_renderer_storename',
107
- )
108
- );
109
-
110
  $this->addColumn(
111
  'template_send_type',
112
  array(
9
  protected function _construct()
10
  {
11
  parent::_construct();
 
12
  $this->setId('systemBrontoEmailTemplateGrid');
13
+ $this->setUseAjax(false);
14
  }
15
 
16
  protected function _prepareCollection()
22
  $brontoTable = Mage::getSingleton('core/resource')->getTableName('bronto_email/message');
23
 
24
  // Apply conditional logic to handle 1.9 overriding collection _construct
25
+ if (Mage::helper('bronto_common')->isVersionMatch(Mage::getVersionInfo(), 1, array(4, 5, array('edition' => 'Enterprise', 'major' => 9), 10))) {
26
  $collection->getSelect()->joinLeft(
27
  $brontoTable,
28
  "`{$templateTable}`.`template_id` = `{$brontoTable}`.`core_template_id`"
88
  )
89
  );
90
 
91
+ if (!Mage::app()->isSingleStoreMode()) {
92
+ $this->addColumn('store_id', array(
93
+ 'header' => Mage::helper('adminhtml')->__('Store View'),
94
+ 'type' => 'store',
95
+ 'index' => 'store_id',
96
+ 'sortable' => true,
97
+ 'store_view' => true
98
+ ));
99
  }
100
 
 
 
 
 
 
 
 
 
 
 
101
  $this->addColumn(
102
  'template_send_type',
103
  array(
app/code/community/Bronto/Email/Helper/Data.php CHANGED
@@ -12,6 +12,8 @@ class Bronto_Email_Helper_Data
12
  const XML_PATH_USE_BRONTO = 'bronto_email/settings/use_bronto';
13
  const XML_PATH_LOG_ENABLED = 'bronto_email/settings/log_enabled';
14
  const XML_PATH_LOG_FIELDS_ENABLED = 'bronto_email/settings/log_fields_enabled';
 
 
15
 
16
  /**
17
  * Xml path to email template nodes
@@ -110,6 +112,30 @@ class Bronto_Email_Helper_Data
110
  return $message;
111
  }
112
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  /**
114
  * Get Config setting for sending through bronto
115
  *
@@ -201,7 +227,7 @@ class Bronto_Email_Helper_Data
201
  $emails = array();
202
  $templates = Mage::getModel('bronto_email/template')->getCollection();
203
 
204
- if ($this->isVersionMatch(Mage::getVersionInfo(), 1, array(4, 5, 9, 10))) {
205
  $templateTable = Mage::getSingleton('core/resource')->getTableName('bronto_email/template');
206
  $brontoTable = Mage::getSingleton('core/resource')->getTableName('bronto_email/message');
207
  $templates->getSelect()->joinLeft(
12
  const XML_PATH_USE_BRONTO = 'bronto_email/settings/use_bronto';
13
  const XML_PATH_LOG_ENABLED = 'bronto_email/settings/log_enabled';
14
  const XML_PATH_LOG_FIELDS_ENABLED = 'bronto_email/settings/log_fields_enabled';
15
+ const XML_PATH_DEFAULT_COUPON = 'bronto_email/settings/default_coupon';
16
+ const XML_PATH_DEFAULT_REC = 'bronto_email/settings/default_recommendation';
17
 
18
  /**
19
  * Xml path to email template nodes
112
  return $message;
113
  }
114
 
115
+ /**
116
+ * Gets the default rule id
117
+ *
118
+ * @param string $scope
119
+ * @param int $scopeId
120
+ * @return string
121
+ */
122
+ public function getDefaultRule($scope = 'default', $scopeId = 0)
123
+ {
124
+ return $this->getAdminScopedConfig(self::XML_PATH_DEFAULT_COUPON, $scope, $scopeId);
125
+ }
126
+
127
+ /**
128
+ * Gets the default product recommendation
129
+ *
130
+ * @param string $scope
131
+ * @param int $scopeId
132
+ * @return string
133
+ */
134
+ public function getDefaultRecommendation($scope = 'default', $scopeId = 0)
135
+ {
136
+ return $this->getAdminScopedConfig(self::XML_PATH_DEFAULT_REC, $scope, $scopeId);
137
+ }
138
+
139
  /**
140
  * Get Config setting for sending through bronto
141
  *
227
  $emails = array();
228
  $templates = Mage::getModel('bronto_email/template')->getCollection();
229
 
230
+ if ($this->isVersionMatch(Mage::getVersionInfo(), 1, array(4, 5, array('edition' => 'Enterprise', 'major' => 9), 10))) {
231
  $templateTable = Mage::getSingleton('core/resource')->getTableName('bronto_email/template');
232
  $brontoTable = Mage::getSingleton('core/resource')->getTableName('bronto_email/message');
233
  $templates->getSelect()->joinLeft(
app/code/community/Bronto/Email/Model/Mysql4/Template/Collection.php CHANGED
@@ -13,7 +13,7 @@ class Bronto_Email_Model_Mysql4_Template_Collection extends Mage_Core_Model_Mysq
13
  parent::_construct();
14
  $this->_templateTable = $this->getResource()->getTable('bronto_email/template');
15
  $this->_brontoTable = $this->getResource()->getTable('bronto_email/message');
16
- if (Mage::helper('bronto_common')->isVersionMatch(Mage::getVersionInfo(), 1, array(4, 9))) {
17
  $this->_select->joinLeft(
18
  array($this->_brontoTable),
19
  "`{$this->_templateTable}`.`template_id` = `{$this->_brontoTable}`.`core_template_id`"
@@ -21,6 +21,19 @@ class Bronto_Email_Model_Mysql4_Template_Collection extends Mage_Core_Model_Mysq
21
  }
22
  }
23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  /**
25
  * Init collection select
26
  *
13
  parent::_construct();
14
  $this->_templateTable = $this->getResource()->getTable('bronto_email/template');
15
  $this->_brontoTable = $this->getResource()->getTable('bronto_email/message');
16
+ if (Mage::helper('bronto_common')->isVersionMatch(Mage::getVersionInfo(), 1, array(4, array('edition' => 'Enterprise', 'major' => 9)))) {
17
  $this->_select->joinLeft(
18
  array($this->_brontoTable),
19
  "`{$this->_templateTable}`.`template_id` = `{$this->_brontoTable}`.`core_template_id`"
21
  }
22
  }
23
 
24
+ /**
25
+ * Adds the store filtering based on All Store views or a specific one
26
+ *
27
+ * @param int $storeId
28
+ * @return Bronto_Email_Model_Mysql4_Template_Collection
29
+ */
30
+ public function addStoreViewFilter($storeId)
31
+ {
32
+ return $this->addFieldToFilter('store_id', array(
33
+ 'in' => array('0', $storeId))
34
+ );
35
+ }
36
+
37
  /**
38
  * Init collection select
39
  *
app/code/community/Bronto/Email/Model/Observer.php CHANGED
@@ -35,6 +35,34 @@ class Bronto_Email_Model_Observer
35
  Mage::getSingleton('adminhtml/session')->addNotice(Mage::helper('bronto_email')->__(Mage::helper('bronto_email')->getModuleEnabledText()));
36
  }
37
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  /**
39
  * Grab Config Data Object before save and handle the 'Create New...' value for
40
  * fields that were generated dynamically
35
  Mage::getSingleton('adminhtml/session')->addNotice(Mage::helper('bronto_email')->__(Mage::helper('bronto_email')->getModuleEnabledText()));
36
  }
37
 
38
+ /**
39
+ * Observes the module becoming enabled and moves custom templates to the
40
+ * bronto email table
41
+ *
42
+ * @param Varien_Event_Observer $observer
43
+ */
44
+ public function moveOldTemplates(Varien_Event_Observer $observer)
45
+ {
46
+ $helper = Mage::helper('bronto_email');
47
+ $settings = $helper->getTemplatePaths();
48
+ $scopeParams = $helper->getScopeParams();
49
+ foreach ($settings as $setting) {
50
+ $data = $helper->getAdminScopedConfig($setting);
51
+ if (str_replace('/', '_', $setting) == $data) {
52
+ continue;
53
+ }
54
+ $model = Mage::getModel('bronto_email/message')->load($data);
55
+ if (!$model->getId()) {
56
+ try {
57
+ Mage::getModel('bronto_email/template_import')
58
+ ->importTemplate($data, $scopeParams['store_id'], true);
59
+ } catch (Exception $e) {
60
+ $helper->writeError("Failed to import message {$e->getMessage()}");
61
+ }
62
+ }
63
+ }
64
+ }
65
+
66
  /**
67
  * Grab Config Data Object before save and handle the 'Create New...' value for
68
  * fields that were generated dynamically
app/code/community/Bronto/Email/Model/Resource/Setup.php CHANGED
@@ -1,7 +1,74 @@
1
  <?php
2
 
3
- class Bronto_Email_Model_Resource_Setup extends Mage_Core_Model_Resource_Setup
4
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  /**
6
  * Sets the Bronto sending for all available scopes if the module is enabled
7
  *
1
  <?php
2
 
3
+ class Bronto_Email_Model_Resource_Setup extends Bronto_Common_Model_Resource_Abstract
4
  {
5
+
6
+ /**
7
+ * @see parent
8
+ */
9
+ protected function _module()
10
+ {
11
+ return 'bronto_email';
12
+ }
13
+
14
+ /**
15
+ * @see parent
16
+ */
17
+ protected function _tables()
18
+ {
19
+ return array(
20
+ 'message' => "
21
+ CREATE TABLE `{table}` (
22
+ `core_template_id` int(10) unsigned NOT NULL COMMENT 'Magento Template ID',
23
+ `template_send_type` varchar(255) NOT NULL DEFAULT 'magento' COMMENT 'Type of message to send as',
24
+ `orig_template_text` text COMMENT 'Original Template Text',
25
+ `bronto_message_id` varchar(36) DEFAULT NULL COMMENT 'Bronto Message ID',
26
+ `bronto_message_name` varchar(255) DEFAULT NULL COMMENT 'Bronto Message Name',
27
+ `bronto_message_approved` smallint(5) unsigned NOT NULL DEFAULT '1' COMMENT 'Bronto Message Transactional Approval Status',
28
+ `store_id` int(11) NOT NULL DEFAULT '1' COMMENT 'Store ID for Template',
29
+ `sales_rule` int(10) NULL COMMENT 'Sales Rule for Coupon Codes',
30
+ `product_recommendation` int(11) unsigned DEFAULT NULL COMMENT 'Product Recommendations',
31
+ PRIMARY KEY (`core_template_id`),
32
+ KEY `IDX_BRONTO_STORE_ID` (`store_id`),
33
+ CONSTRAINT `FK_BRONTO_EMAIL_TEMPLATE_ID_CORE_EMAIL_TEMPLATE_ID` FOREIGN KEY (`core_template_id`)
34
+ REFERENCES `{$this->getTable('core/email_template')}` (`template_id`) ON DELETE CASCADE ON UPDATE CASCADE
35
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Bronto Email Template Attributes'
36
+ ",
37
+ 'log' => "
38
+ CREATE TABLE `{table}` (
39
+ `log_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Log ID',
40
+ `customer_id` int(10) unsigned DEFAULT NULL COMMENT 'Customer ID',
41
+ `customer_email` varchar(255) DEFAULT NULL COMMENT 'Customer Email Address',
42
+ `contact_id` varchar(36) DEFAULT NULL COMMENT 'Bronto Contact ID',
43
+ `message_id` varchar(36) NOT NULL COMMENT 'Bronto Message ID',
44
+ `message_name` varchar(64) DEFAULT NULL COMMENT 'Bronto Message Name',
45
+ `delivery_id` varchar(36) DEFAULT NULL COMMENT 'Bronto Delivery ID',
46
+ `sent_at` datetime DEFAULT NULL COMMENT 'Date Message Sent',
47
+ `success` smallint(5) unsigned NOT NULL DEFAULT '0' COMMENT 'Message Send Success',
48
+ `error` varchar(255) DEFAULT NULL COMMENT 'Error Message',
49
+ `fields` text COMMENT 'Fields',
50
+ PRIMARY KEY (`log_id`),
51
+ KEY `IDX_BRONTO_EMAIL_LOG_CUSTOMER_EMAIL` (`customer_email`),
52
+ KEY `IDX_BRONTO_EMAIL_LOG_SENT_AT` (`sent_at`)
53
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Bronto Email Delivery Logs'
54
+ ");
55
+ }
56
+
57
+ /**
58
+ * @see parent
59
+ */
60
+ protected function _updates()
61
+ {
62
+ return array(
63
+ '1.2.0' => array(
64
+ 'message' => array(
65
+ 'sql' =>
66
+ "ALTER TABLE {table} ADD COLUMN `product_recommendation` int(11) unsigned DEFAULT NULL AFTER `sales_rule`;"
67
+ )
68
+ )
69
+ );
70
+ }
71
+
72
  /**
73
  * Sets the Bronto sending for all available scopes if the module is enabled
74
  *
app/code/community/Bronto/Email/Model/System/Config/Source/Email/Template.php CHANGED
@@ -20,7 +20,7 @@ class Bronto_Email_Model_System_Config_Source_Email_Template extends Mage_Adminh
20
  $collection = Mage::getModel('bronto_email/template')->getCollection();
21
 
22
  // Apply conditional logic to handle 1.9 overriding collection _construct
23
- if (Mage::helper('bronto_common')->isVersionMatch(Mage::getVersionInfo(), 1, array(4, 5, 9, 10))) {
24
  $collection->getSelect()->joinLeft(
25
  $brontoTable,
26
  "`{$templateTable}`.`template_id` = `{$brontoTable}`.`core_template_id`"
@@ -36,7 +36,7 @@ class Bronto_Email_Model_System_Config_Source_Email_Template extends Mage_Adminh
36
  $store = Mage::app()->getStore($storeCode);
37
  $storeId = $store->getId();
38
 
39
- $collection->addFieldToFilter('store_id', $storeId);
40
  }
41
  }
42
 
20
  $collection = Mage::getModel('bronto_email/template')->getCollection();
21
 
22
  // Apply conditional logic to handle 1.9 overriding collection _construct
23
+ if (Mage::helper('bronto_common')->isVersionMatch(Mage::getVersionInfo(), 1, array(4, 5, array('edition' => 'Enterprise', 'major' => 9), 10))) {
24
  $collection->getSelect()->joinLeft(
25
  $brontoTable,
26
  "`{$templateTable}`.`template_id` = `{$brontoTable}`.`core_template_id`"
36
  $store = Mage::app()->getStore($storeCode);
37
  $storeId = $store->getId();
38
 
39
+ $collection->addStoreViewFilter($storeId);
40
  }
41
  }
42
 
app/code/community/Bronto/Email/Model/Template/Import.php CHANGED
@@ -15,17 +15,18 @@ class Bronto_Email_Model_Template_Import extends Bronto_Email_Model_Template
15
  *
16
  * @param int $templateId
17
  * @param mixed $storeId
 
18
  *
19
  * @return string
20
  * @throws Exception
21
  */
22
- public function importTemplate($templateId, $storeId = false)
23
  {
24
  /** @var $template Bronto_Email_Model_Template_Import */
25
  $template = $this->load($templateId);
26
 
27
  try {
28
- return $this->processMessage($template, $storeId);
29
  } catch (Exception $e) {
30
  throw new Exception($e->getMessage());
31
  }
@@ -39,7 +40,7 @@ class Bronto_Email_Model_Template_Import extends Bronto_Email_Model_Template
39
  *
40
  * @return bool
41
  */
42
- protected function processMessage(Bronto_Email_Model_Template $template, $storeId = false)
43
  {
44
  $data = $template->getData();
45
  $emt = Mage::getModel('bronto_common/email_template_templatefilter');
@@ -54,7 +55,7 @@ class Bronto_Email_Model_Template_Import extends Bronto_Email_Model_Template
54
  }
55
 
56
  // If module is not enabled for this store, don't proceed
57
- if (!Mage::helper('bronto_email')->isEnabled('store', $store->getId())) {
58
  return false;
59
  }
60
 
15
  *
16
  * @param int $templateId
17
  * @param mixed $storeId
18
+ * @param bool $force
19
  *
20
  * @return string
21
  * @throws Exception
22
  */
23
+ public function importTemplate($templateId, $storeId = false, $force = false)
24
  {
25
  /** @var $template Bronto_Email_Model_Template_Import */
26
  $template = $this->load($templateId);
27
 
28
  try {
29
+ return $this->processMessage($template, $storeId, $force);
30
  } catch (Exception $e) {
31
  throw new Exception($e->getMessage());
32
  }
40
  *
41
  * @return bool
42
  */
43
+ protected function processMessage(Bronto_Email_Model_Template $template, $storeId = false, $force = false)
44
  {
45
  $data = $template->getData();
46
  $emt = Mage::getModel('bronto_common/email_template_templatefilter');
55
  }
56
 
57
  // If module is not enabled for this store, don't proceed
58
+ if (!$force && !Mage::helper('bronto_email')->isEnabled('store', $store->getId())) {
59
  return false;
60
  }
61
 
app/code/community/Bronto/Email/Model/Template/Mailer.php CHANGED
@@ -29,28 +29,8 @@ class Bronto_Email_Model_Template_Mailer
29
  return parent::send();
30
  }
31
 
32
- // Load Bronto Message
33
- $store = Mage::getModel('core/store')->load($this->getStoreId());
34
-
35
- // Load Bronto Message
36
- /* @var $messageObject Bronto_Api_Message */
37
- $messageObject = Mage::helper('bronto_email/message')->getApi(
38
- null,
39
- 'store',
40
- $store->getId()
41
- )->getMessageObject();
42
-
43
- // Load Message
44
- try {
45
- /* @var $message Bronto_Api_Message_Row */
46
- $message = $messageObject->createRow();
47
- $message->id = $emailTemplate->getBrontoMessageId();
48
- $message->read();
49
- } catch (Exception $e) {
50
- Mage::helper('bronto_email')->writeDebug('Falling Back to Magento Sending: ' . $e);
51
-
52
- return parent::send();
53
- }
54
 
55
  // Send all emails from corresponding list
56
  while (!empty($this->_emailInfos)) {
29
  return parent::send();
30
  }
31
 
32
+ $message = new Bronto_Api_Message_Row();
33
+ $message->id = $emailTemplate->getBrontoMessageId();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
 
35
  // Send all emails from corresponding list
36
  while (!empty($this->_emailInfos)) {
app/code/community/Bronto/Email/controllers/Adminhtml/System/Email/TemplateController.php CHANGED
@@ -251,9 +251,15 @@ class Bronto_Email_Adminhtml_System_Email_TemplateController extends Mage_Adminh
251
  ->setOrigTemplateText($origTemplateText);
252
  }
253
 
254
- $brontoTemplate
255
- ->setTemplateSendType($sendType)
256
- ->setSalesRule($request->getParam('sales_rule', null));
 
 
 
 
 
 
257
 
258
  // If Template doesn't exist or added_at is not set, set it
259
  if (!$template->getId() || !$template->getAddedAt()) {
251
  ->setOrigTemplateText($origTemplateText);
252
  }
253
 
254
+ // Only set if the module is enabled, essentially
255
+ if ($request->has('product_recommendation')) {
256
+ $rec = $request->getParam('product_recommendation', null);
257
+ $brontoTemplate->setProductRecommendation($rec);
258
+ }
259
+
260
+ $salesRule = $request->getParam('sales_rule', null);
261
+ $brontoTemplate->setSalesRule($salesRule);
262
+ $brontoTemplate->setTemplateSendType($sendType);
263
 
264
  // If Template doesn't exist or added_at is not set, set it
265
  if (!$template->getId() || !$template->getAddedAt()) {
app/code/community/Bronto/Email/etc/config.xml CHANGED
@@ -2,7 +2,7 @@
2
  <config>
3
  <modules>
4
  <Bronto_Email>
5
- <version>1.1.9</version>
6
  </Bronto_Email>
7
  </modules>
8
  <global>
@@ -96,6 +96,11 @@
96
  <class>bronto_email/observer</class>
97
  <method>watchEnableAction</method>
98
  </bronto_email_enable>
 
 
 
 
 
99
  </observers>
100
  </bronto_email_enable>
101
  <controller_action_predispatch>
2
  <config>
3
  <modules>
4
  <Bronto_Email>
5
+ <version>1.2.0</version>
6
  </Bronto_Email>
7
  </modules>
8
  <global>
96
  <class>bronto_email/observer</class>
97
  <method>watchEnableAction</method>
98
  </bronto_email_enable>
99
+ <bronto_move_templates>
100
+ <type>singleton</type>
101
+ <class>bronto_email/observer</class>
102
+ <method>moveOldTemplates</method>
103
+ </bronto_move_templates>
104
  </observers>
105
  </bronto_email_enable>
106
  <controller_action_predispatch>
app/code/community/Bronto/Email/etc/system.xml CHANGED
@@ -76,6 +76,32 @@
76
  <show_in_website>1</show_in_website>
77
  <show_in_store>1</show_in_store>
78
  </log_fields_enabled>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  </fields>
80
  </settings>
81
  <templates translate="label">
76
  <show_in_website>1</show_in_website>
77
  <show_in_store>1</show_in_store>
78
  </log_fields_enabled>
79
+ <default_coupon>
80
+ <label>Default Price Rule Coupon Code</label>
81
+ <depends>
82
+ <enabled>1</enabled>
83
+ </depends>
84
+ <frontend_type>select</frontend_type>
85
+ <source_model>bronto_common/system_config_source_coupon</source_model>
86
+ <sort_order>12</sort_order>
87
+ <show_in_default>1</show_in_default>
88
+ <show_in_website>1</show_in_website>
89
+ <show_in_store>1</show_in_store>
90
+ <comment><![CDATA[Use API tag <em>%%%%#couponCode%%%%</em> within your message in Bronto. You are responsible for ensuring the Shopping Cart Price Rule is active and valid, or else it may appear blank.]]></comment>
91
+ </default_coupon>
92
+ <default_recommendation>
93
+ <label>Default Product Recommendation</label>
94
+ <depends>
95
+ <enabled>1</enabled>
96
+ </depends>
97
+ <frontend_type>select</frontend_type>
98
+ <source_model>bronto_product/recommendation</source_model>
99
+ <sort_order>13</sort_order>
100
+ <show_in_default>1</show_in_default>
101
+ <show_in_website>1</show_in_website>
102
+ <show_in_store>1</show_in_store>
103
+ <comment><![CDATA[Inject related product content in the message. Recommendations are created in <strong>Promotions</strong> &raquo; <strong>Bronto Product Recommendations]]></comment>
104
+ </default_recommendation>
105
  </fields>
106
  </settings>
107
  <templates translate="label">
app/code/community/Bronto/Email/sql/bronto_email_setup/mysql4-install-1.2.0.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ $installer = $this;
4
+
5
+ $installer->startSetup();
6
+
7
+ try {
8
+ $installer->createTables();
9
+ } catch (Exception $e) {
10
+ Mage::helper('bronto_email')->writeError($e->getMessage());
11
+ }
12
+
13
+ $installer->endSetup();
app/code/community/Bronto/Email/sql/bronto_email_setup/mysql4-upgrade-1.1.9-1.2.0.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ $installer = $this;
4
+
5
+ $installer->startSetup();
6
+ $installer->updateTables('1.2.0');
7
+ $installer->endSetup();
app/code/community/Bronto/Emailcapture/Block/Emailcapture.php CHANGED
@@ -13,7 +13,8 @@ class Bronto_Emailcapture_Block_Emailcapture extends Mage_Core_Block_Template
13
  */
14
  public function getTargetUrl()
15
  {
16
- return Mage::getUrl('emailcapture/index/capture', array('_secure' => true));
 
17
  }
18
 
19
  /**
13
  */
14
  public function getTargetUrl()
15
  {
16
+ $store = Mage::app()->getStore();
17
+ return Mage::getUrl('emailcapture/index/capture', array('_secure' => $store->isCurrentlySecure()));
18
  }
19
 
20
  /**
app/code/community/Bronto/Newsletter/Block/Adminhtml/System/Config/Cron.php CHANGED
@@ -16,6 +16,7 @@ class Bronto_Newsletter_Block_Adminhtml_System_Config_Cron extends Bronto_Common
16
  {
17
  $this->addButton($this->getLayout()->createBlock('bronto_newsletter/adminhtml_widget_button_sync'));
18
  $this->addButton($this->getLayout()->createBlock('bronto_newsletter/adminhtml_widget_button_reset'));
 
19
  $this->addButton($this->getLayout()->createBlock('bronto_newsletter/adminhtml_widget_button_run'));
20
 
21
  return parent::_prepareLayout();
16
  {
17
  $this->addButton($this->getLayout()->createBlock('bronto_newsletter/adminhtml_widget_button_sync'));
18
  $this->addButton($this->getLayout()->createBlock('bronto_newsletter/adminhtml_widget_button_reset'));
19
+ $this->addButton($this->getLayout()->createBlock('bronto_newsletter/adminhtml_widget_button_mark'));
20
  $this->addButton($this->getLayout()->createBlock('bronto_newsletter/adminhtml_widget_button_run'));
21
 
22
  return parent::_prepareLayout();
app/code/community/Bronto/Newsletter/Block/Adminhtml/System/Config/Suppressed.php CHANGED
@@ -16,4 +16,12 @@ class Bronto_Newsletter_Block_Adminhtml_System_Config_Suppressed
16
  {
17
  return Mage::helper('bronto_common')->getScopeUrl('adminhtml/newsletter/suppression');
18
  }
19
- }
 
 
 
 
 
 
 
 
16
  {
17
  return Mage::helper('bronto_common')->getScopeUrl('adminhtml/newsletter/suppression');
18
  }
19
+
20
+ /**
21
+ * @see parent
22
+ */
23
+ public function getResetUrl()
24
+ {
25
+ return Mage::helper('bronto_common')->getScopeUrl('adminhtml/newsletter/reset');
26
+ }
27
+ }
app/code/community/Bronto/Newsletter/Block/Adminhtml/Widget/Button/Mark.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Newsletter_Block_Adminhtml_Widget_Button_Mark extends Mage_Adminhtml_Block_Widget_Button
4
+ {
5
+ /**
6
+ * @see parent
7
+ */
8
+ protected function _construct()
9
+ {
10
+ $this->setLabel('Mark All Imported');
11
+ $this->setOnClick("deleteConfirm('This will mark all subscribers as imported and will not send the information to Bronto.\\n\\nAre you sure you want to do this?', '" . Mage::helper('bronto_customer')->getScopeUrl('*/newsletter/mark') . "'); return false;");
12
+ $this->setClass('bronto-cron-mark');
13
+
14
+ if (!Mage::helper('bronto_newsletter')->isModuleActive() || (!Mage::helper('bronto_common')->isDebugEnabled())) {
15
+ $this->setDisabled(true)->setClass('disabled');
16
+ }
17
+ }
18
+ }
app/code/community/Bronto/Newsletter/Block/Checkout/Onepage/Newsletter.php CHANGED
@@ -26,6 +26,22 @@ class Bronto_Newsletter_Block_Checkout_Onepage_Newsletter extends Mage_Checkout_
26
  return Mage::helper('bronto_newsletter')->isEnabled();
27
  }
28
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  /**
30
  * @return bool
31
  */
@@ -83,7 +99,8 @@ class Bronto_Newsletter_Block_Checkout_Onepage_Newsletter extends Mage_Checkout_
83
  */
84
  public function getRequestUrl()
85
  {
86
- return Mage::getSingleton('core/url')->getUrl('btnewsletter/index/checkbox', array('_secure' => true));
 
87
  }
88
 
89
  /**
@@ -93,7 +110,8 @@ class Bronto_Newsletter_Block_Checkout_Onepage_Newsletter extends Mage_Checkout_
93
  */
94
  public function getSubscribeUrl()
95
  {
96
- return Mage::getSingleton('core/url')->getUrl('btnewsletter/index/subscribe', array('_secure' => true));
 
97
  }
98
 
99
  /**
26
  return Mage::helper('bronto_newsletter')->isEnabled();
27
  }
28
 
29
+ /**
30
+ * @return string
31
+ */
32
+ public function getCssSelector()
33
+ {
34
+ return Mage::helper('bronto_newsletter')->getCssSelector();
35
+ }
36
+
37
+ /**
38
+ * @return string
39
+ */
40
+ public function getCheckboxStyle()
41
+ {
42
+ return Mage::helper('bronto_newsletter')->getCheckboxStyle();
43
+ }
44
+
45
  /**
46
  * @return bool
47
  */
99
  */
100
  public function getRequestUrl()
101
  {
102
+ $store = Mage::app()->getStore();
103
+ return Mage::getSingleton('core/url')->getUrl('btnewsletter/index/checkbox', array('_secure' => $store->isCurrentlySecure()));
104
  }
105
 
106
  /**
110
  */
111
  public function getSubscribeUrl()
112
  {
113
+ $store = Mage::app()->getStore();
114
+ return Mage::getSingleton('core/url')->getUrl('btnewsletter/index/subscribe', array('_secure' => $store->isCurrentlySecure()));
115
  }
116
 
117
  /**
app/code/community/Bronto/Newsletter/Helper/Data.php CHANGED
@@ -16,6 +16,8 @@ class Bronto_Newsletter_Helper_Data extends Bronto_Common_Helper_Data
16
  const XML_PATH_SHOW_REGISTRAR = 'bronto_newsletter/checkout/show_to_registrars';
17
  const XML_PATH_SHOW_SUBSCRIBED = 'bronto_newsletter/checkout/show_if_subscribed';
18
  const XML_PATH_LABEL_TEXT = 'bronto_newsletter/checkout/label_text';
 
 
19
  const XML_PATH_INSTALL_DATE = 'bronto_newsletter/settings/install_date';
20
  const XML_PATH_UPGRADE_DATE = 'bronto_newsletter/settings/upgrade_date';
21
 
@@ -85,6 +87,30 @@ class Bronto_Newsletter_Helper_Data extends Bronto_Common_Helper_Data
85
  return $this->_disableModule(self::XML_PATH_ENABLED, $scope, $scopeId, $deleteConfig);
86
  }
87
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  /**
89
  * @return int
90
  */
16
  const XML_PATH_SHOW_REGISTRAR = 'bronto_newsletter/checkout/show_to_registrars';
17
  const XML_PATH_SHOW_SUBSCRIBED = 'bronto_newsletter/checkout/show_if_subscribed';
18
  const XML_PATH_LABEL_TEXT = 'bronto_newsletter/checkout/label_text';
19
+ const XML_PATH_CHECKBOX_CSS = 'bronto_newsletter/checkout/css_selector';
20
+ const XML_PATH_CHECKBOX_STYLE = 'bronto_newsletter/checkout/checkbox_style';
21
  const XML_PATH_INSTALL_DATE = 'bronto_newsletter/settings/install_date';
22
  const XML_PATH_UPGRADE_DATE = 'bronto_newsletter/settings/upgrade_date';
23
 
87
  return $this->_disableModule(self::XML_PATH_ENABLED, $scope, $scopeId, $deleteConfig);
88
  }
89
 
90
+ /**
91
+ * Gets the CSS selector for the checkbox
92
+ *
93
+ * @param string $scope
94
+ * @param int $scopeId
95
+ * @return string
96
+ */
97
+ public function getCssSelector($scope = 'default', $scopeId = 0)
98
+ {
99
+ return $this->getAdminScopedConfig(self::XML_PATH_CHECKBOX_CSS, $scope, $scopeId);
100
+ }
101
+
102
+ /**
103
+ * Gets the Checkbox styles
104
+ *
105
+ * @param string $scope
106
+ * @param int $scopeId
107
+ * @return string
108
+ */
109
+ public function getCheckboxStyle($scope = 'default', $scopeId = 0)
110
+ {
111
+ return $this->getAdminScopedConfig(self::XML_PATH_CHECKBOX_STYLE, $scope, $scopeId);
112
+ }
113
+
114
  /**
115
  * @return int
116
  */
app/code/community/Bronto/Newsletter/Model/Observer.php CHANGED
@@ -38,6 +38,15 @@ class Bronto_Newsletter_Model_Observer
38
  }
39
  }
40
 
 
 
 
 
 
 
 
 
 
41
  /**
42
  * Get Bronto Contact Row via Email address
43
  *
@@ -96,7 +105,7 @@ class Bronto_Newsletter_Model_Observer
96
  /* @var $subscriber Mage_Newsletter_Model_Subscriber */
97
  $subscriber = Mage::getModel('newsletter/subscriber')->loadByEmail($email);
98
  if (!$subscriber->hasSubscriberEmail() && $isSubscribed == Bronto_Api_Contact::STATUS_TRANSACTIONAL) {
99
- $this->_helper->writeError('Unable to create subscriber object');
100
 
101
  return false;
102
  }
@@ -199,7 +208,7 @@ class Bronto_Newsletter_Model_Observer
199
  }
200
 
201
  // Send to queue
202
- $this->_saveToQueue($subscriber, Mage::app()->getStore()->getId());
203
  } catch (Exception $e) {
204
  $this->_helper->writeError($e);
205
  }
@@ -234,11 +243,15 @@ class Bronto_Newsletter_Model_Observer
234
 
235
  // If ContactQueue status doesn't match subscriber status, replace it
236
  if ($status != $contactQueue->getStatus()) {
 
 
 
 
 
237
  $contactQueue->setSubscriberEmail($subscriber->getEmail())
238
  ->setStatus($status)
239
  ->setMessagePreference('html')
240
  ->setSource('api')
241
- ->setImported(0)
242
  ->setUpdatedAt(Mage::getSingleton('core/date')->gmtDate())
243
  ->save();
244
  }
@@ -379,8 +392,10 @@ class Bronto_Newsletter_Model_Observer
379
 
380
  $result['success']++;
381
  } catch (Exception $e) {
382
- // 315 means contact on suppression list, so suppress
383
- if (315 == $e->getCode()) {
 
 
384
  $subscriber->setBrontoSuppressed($e->getMessage());
385
  }
386
 
38
  }
39
  }
40
 
41
+ /**
42
+ * Observes module becoming enabled and displays message warning user to configure settings
43
+ * @param Varien_Event_Observer $observer
44
+ */
45
+ public function watchEnableAction(Varien_Event_Observer $observer)
46
+ {
47
+ Mage::getSingleton('adminhtml/session')->addNotice(Mage::helper('bronto_newsletter')->__(Mage::helper('bronto_newsletter')->getModuleEnabledText()));
48
+ }
49
+
50
  /**
51
  * Get Bronto Contact Row via Email address
52
  *
105
  /* @var $subscriber Mage_Newsletter_Model_Subscriber */
106
  $subscriber = Mage::getModel('newsletter/subscriber')->loadByEmail($email);
107
  if (!$subscriber->hasSubscriberEmail() && $isSubscribed == Bronto_Api_Contact::STATUS_TRANSACTIONAL) {
108
+ $this->_helper->writeDebug('Unable to create subscriber object');
109
 
110
  return false;
111
  }
208
  }
209
 
210
  // Send to queue
211
+ $this->_saveToQueue($subscriber, $subscriber->getStoreId());
212
  } catch (Exception $e) {
213
  $this->_helper->writeError($e);
214
  }
243
 
244
  // If ContactQueue status doesn't match subscriber status, replace it
245
  if ($status != $contactQueue->getStatus()) {
246
+ if ($subscriber->getSubscribeSource() == 'popup') {
247
+ $contactQueue->setImported(2);
248
+ } else {
249
+ $contactQueue->setImported(0);
250
+ }
251
  $contactQueue->setSubscriberEmail($subscriber->getEmail())
252
  ->setStatus($status)
253
  ->setMessagePreference('html')
254
  ->setSource('api')
 
255
  ->setUpdatedAt(Mage::getSingleton('core/date')->gmtDate())
256
  ->save();
257
  }
392
 
393
  $result['success']++;
394
  } catch (Exception $e) {
395
+ // 303 = invalid email address
396
+ // 315 = on suppression list
397
+ // 317 = email over 100 characters in length
398
+ if (in_array($e->getCode(), array(303, 315, 317))) {
399
  $subscriber->setBrontoSuppressed($e->getMessage());
400
  }
401
 
app/code/community/Bronto/Newsletter/controllers/Adminhtml/NewsletterController.php CHANGED
@@ -61,27 +61,26 @@ class Bronto_Newsletter_Adminhtml_NewsletterController extends Mage_Adminhtml_Co
61
  $adapter = $resource->getWriteAdapter();
62
 
63
  $queue_id = $this->getRequest()->getParam('queue_id', false);
 
64
 
65
  try {
 
 
66
  if ($queue_id) {
67
- $adapter->update(
68
- $resource->getTable('bronto_newsletter/queue'),
69
- array(
70
- 'imported' => null,
71
- 'bronto_suppressed' => null,
72
- ),
73
- array('queue_id = ?' => $queue_id)
74
- );
75
  } else {
76
- $adapter->update(
77
- $resource->getTable('bronto_newsletter/queue'),
78
- array(
79
- 'imported' => 2,
80
- 'bronto_suppressed' => null,
81
- ),
82
- array('imported' => 1)
83
- );
84
  }
 
 
 
 
 
85
  } catch (Exception $e) {
86
  $helper->writeError($e);
87
  $this->_getSession()->addError('Reset failed: ' . $e->getMessage());
@@ -92,6 +91,30 @@ class Bronto_Newsletter_Adminhtml_NewsletterController extends Mage_Adminhtml_Co
92
  $this->_redirect('*/system_config/edit', $returnParams);
93
  }
94
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  /**
96
  * Pull Subscribers from Subscribers Table if not in queue
97
  */
61
  $adapter = $resource->getWriteAdapter();
62
 
63
  $queue_id = $this->getRequest()->getParam('queue_id', false);
64
+ $suppressed = $this->getRequest()->getParam('suppressed', false);
65
 
66
  try {
67
+ $update = array('bronto_suppressed' => null);
68
+ $where = array();
69
  if ($queue_id) {
70
+ $update['imported'] = null;
71
+ $where['queue_id = ?'] = $queue_id;
72
+ } else if ($suppressed) {
73
+ $update['imported'] = null;
74
+ $where['bronto_suppressed IS NOT NULL'] = '';
 
 
 
75
  } else {
76
+ $update['imported'] = 2;
77
+ $where['imported'] = 1;
 
 
 
 
 
 
78
  }
79
+ $adapter->update(
80
+ $resource->getTable('bronto_newsletter/queue'),
81
+ $update,
82
+ $where
83
+ );
84
  } catch (Exception $e) {
85
  $helper->writeError($e);
86
  $this->_getSession()->addError('Reset failed: ' . $e->getMessage());
91
  $this->_redirect('*/system_config/edit', $returnParams);
92
  }
93
 
94
+ /**
95
+ * Marks all Subscribers as imported
96
+ */
97
+ public function markAction()
98
+ {
99
+ $helper = Mage::helper('bronto_newsletter');
100
+ $resource = Mage::getResourceModel('bronto_newsletter/queue');
101
+ $adapter = $resource->getWriteAdapter();
102
+
103
+ try {
104
+ $adapter->update(
105
+ $resource->getTable('bronto_newsletter/queue'),
106
+ array('imported' => 1),
107
+ array('bronto_suppressed IS NULL' => ''));
108
+ } catch (Exception $e) {
109
+ $helper->writeError($e);
110
+ $this->_getSession()->addError('Mark All failed: ' . $e->getMessage());
111
+ }
112
+
113
+ $returnParams = array('section' => 'bronto_newsletter');
114
+ $returnParams = array_merge($returnParams, $helper->getScopeParams());
115
+ $this->_redirect('*/system_config/edit', $returnParams);
116
+ }
117
+
118
  /**
119
  * Pull Subscribers from Subscribers Table if not in queue
120
  */
app/code/community/Bronto/Newsletter/controllers/IndexController.php CHANGED
@@ -6,6 +6,27 @@
6
  */
7
  class Bronto_Newsletter_IndexController extends Mage_Core_Controller_Front_Action
8
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  /**
10
  * Retrieve Checkbox HTML
11
  */
@@ -68,4 +89,4 @@ class Bronto_Newsletter_IndexController extends Mage_Core_Controller_Front_Actio
68
  // Return subscription status
69
  $this->getResponse()->setBody($oldStatus . '=>' . $status);
70
  }
71
- }
6
  */
7
  class Bronto_Newsletter_IndexController extends Mage_Core_Controller_Front_Action
8
  {
9
+ /**
10
+ * Endpoint for integrated popup submissions
11
+ */
12
+ public function SubmitAction()
13
+ {
14
+ $email = $this->getRequest()->getParam('emailAddress');
15
+ try {
16
+ if (Mage::helper('bronto_common')->isSubscribeToMagento()) {
17
+ // Note: this will send email confirmation or success, depending
18
+ $subscriber = Mage::getModel('newsletter/subscriber')
19
+ ->loadByEmail($email)
20
+ ->setSubscribeSource('popup')
21
+ ->subscribe($email);
22
+ }
23
+ $this->getResponse()->setBody('success');
24
+ } catch (Exception $e) {
25
+ Mage::helper('bronto_newsletter')->writeError($e);
26
+ $this->getResponse()->setBody($e->getMessage());
27
+ }
28
+ }
29
+
30
  /**
31
  * Retrieve Checkbox HTML
32
  */
89
  // Return subscription status
90
  $this->getResponse()->setBody($oldStatus . '=>' . $status);
91
  }
92
+ }
app/code/community/Bronto/Newsletter/etc/config.xml CHANGED
@@ -109,6 +109,16 @@
109
  <label_text>Sign up for our newsletter</label_text>
110
  <use_custom_template>0</use_custom_template>
111
  <billing_template>checkout/onepage/billing.phtml</billing_template>
 
 
 
 
 
 
 
 
 
 
112
  </checkout>
113
  <contacts>
114
  <update_status>1</update_status>
109
  <label_text>Sign up for our newsletter</label_text>
110
  <use_custom_template>0</use_custom_template>
111
  <billing_template>checkout/onepage/billing.phtml</billing_template>
112
+ <css_selector>#billing_address</css_selector>
113
+ <checkbox_style><![CDATA[
114
+ .col1-layout .billing_is_subscribed_box {
115
+ margin-left: 240px !important;
116
+ float:left;
117
+ width:auto;
118
+ margin: 2px 8px 0 0; }
119
+ .col1-layout #billing_subscribed_label {
120
+ width: auto;
121
+ text-align: left; }]]></checkbox_style>
122
  </checkout>
123
  <contacts>
124
  <update_status>1</update_status>
app/code/community/Bronto/Newsletter/etc/system.xml CHANGED
@@ -197,6 +197,35 @@
197
  <show_in_website>1</show_in_website>
198
  <show_in_store>1</show_in_store>
199
  </label_text>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
  </fields>
201
  </checkout>
202
  <contacts>
@@ -264,6 +293,17 @@
264
  <show_in_website>1</show_in_website>
265
  <show_in_store>1</show_in_store>
266
  <expanded>0</expanded>
 
 
 
 
 
 
 
 
 
 
 
267
  </suppressed>
268
  </groups>
269
  </bronto_newsletter>
197
  <show_in_website>1</show_in_website>
198
  <show_in_store>1</show_in_store>
199
  </label_text>
200
+ <css_selector>
201
+ <label>Checkbox CSS Selector</label>
202
+ <frontend_type>text</frontend_type>
203
+ <sort_order>20</sort_order>
204
+ <show_in_default>1</show_in_default>
205
+ <show_in_website>1</show_in_website>
206
+ <show_in_store>1</show_in_store>
207
+ <comment><![CDATA[CSS Selector to place the newly
208
+ added subscriber checkbox on the checkout
209
+ page.<br/>Default:
210
+ <code>#billing_address</code>]]></comment>
211
+ </css_selector>
212
+ <checkbox_style>
213
+ <label>Checkbox CSS Style</label>
214
+ <frontend_type>textarea</frontend_type>
215
+ <sort_order>25</sort_order>
216
+ <show_in_default>1</show_in_default>
217
+ <show_in_website>1</show_in_website>
218
+ <show_in_store>1</show_in_store>
219
+ <comment><![CDATA[Dynamic styling for the newly
220
+ checkbox.<br/>Default: <pre>.col1-layout .billing_is_subscribed_box {
221
+ margin-left: 240px !important;
222
+ float:left;
223
+ width:auto;
224
+ margin: 2px 8px 0 0; }
225
+ .col1-layout #billing_subscribed_label {
226
+ width: auto;
227
+ text-align: left; }</pre>]]></comment>
228
+ </checkbox_style>
229
  </fields>
230
  </checkout>
231
  <contacts>
293
  <show_in_website>1</show_in_website>
294
  <show_in_store>1</show_in_store>
295
  <expanded>0</expanded>
296
+ <fields>
297
+ <reset>
298
+ <label>Reset All Suppressed Subscribers</label>
299
+ <frontend_type>text</frontend_type>
300
+ <frontend_model>bronto_common/adminhtml_system_config_suppressed_reset</frontend_model>
301
+ <sort_order>0</sort_order>
302
+ <show_in_default>1</show_in_default>
303
+ <show_in_website>1</show_in_website>
304
+ <show_in_store>1</show_in_store>
305
+ </reset>
306
+ </fields>
307
  </suppressed>
308
  </groups>
309
  </bronto_newsletter>
app/code/community/Bronto/Order/Block/Adminhtml/System/Config/Cron.php CHANGED
@@ -23,6 +23,7 @@ class Bronto_Order_Block_Adminhtml_System_Config_Cron extends Bronto_Common_Bloc
23
  {
24
  $this->addButton($this->getLayout()->createBlock('bronto_order/adminhtml_widget_button_sync'));
25
  $this->addButton($this->getLayout()->createBlock('bronto_order/adminhtml_widget_button_reset'));
 
26
  $this->addButton($this->getLayout()->createBlock('bronto_order/adminhtml_widget_button_run'));
27
 
28
  return parent::_prepareLayout();
23
  {
24
  $this->addButton($this->getLayout()->createBlock('bronto_order/adminhtml_widget_button_sync'));
25
  $this->addButton($this->getLayout()->createBlock('bronto_order/adminhtml_widget_button_reset'));
26
+ $this->addButton($this->getLayout()->createBlock('bronto_order/adminhtml_widget_button_mark'));
27
  $this->addButton($this->getLayout()->createBlock('bronto_order/adminhtml_widget_button_run'));
28
 
29
  return parent::_prepareLayout();
app/code/community/Bronto/Order/Block/Adminhtml/System/Config/Suppressed.php CHANGED
@@ -16,4 +16,12 @@ class Bronto_Order_Block_Adminhtml_System_Config_Suppressed
16
  {
17
  return Mage::helper('bronto_common')->getScopeUrl('adminhtml/order/suppression');
18
  }
19
- }
 
 
 
 
 
 
 
 
16
  {
17
  return Mage::helper('bronto_common')->getScopeUrl('adminhtml/order/suppression');
18
  }
19
+
20
+ /**
21
+ * @see parent
22
+ */
23
+ public function getResetUrl()
24
+ {
25
+ return Mage::helper('bronto_common')->getScopeUrl('adminhtml/order/reset');
26
+ }
27
+ }
app/code/community/Bronto/Order/Block/Adminhtml/Widget/Button/Mark.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Order_Block_Adminhtml_Widget_Button_Mark extends Mage_Adminhtml_Block_Widget_Button
4
+ {
5
+ /**
6
+ * @see parent
7
+ */
8
+ protected function _construct()
9
+ {
10
+ $this->setLabel('Mark All Imported');
11
+ $this->setOnClick("deleteConfirm('This will mark all orders as imported and will not send the information to Bronto.\\n\\nAre you sure you want to do this?', '" . Mage::helper('bronto_customer')->getScopeUrl('*/order/mark') . "'); return false;");
12
+ $this->setClass('bronto-cron-mark');
13
+
14
+ if (!Mage::helper('bronto_newsletter')->isModuleActive() || (!Mage::helper('bronto_common')->isDebugEnabled())) {
15
+ $this->setDisabled(true)->setClass('disabled');
16
+ }
17
+ }
18
+ }
app/code/community/Bronto/Order/Block/Redemption.php ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Order_Block_Redemption extends Mage_Core_Block_Template
4
+ {
5
+ /**
6
+ * Gets the siteKey for the coupon redemption
7
+ *
8
+ * @return string
9
+ */
10
+ public function getRedemptionSiteHash()
11
+ {
12
+ return Mage::helper('bronto_common')->getCouponSiteHash();
13
+ }
14
+
15
+ /**
16
+ * Override for populating the template variables
17
+ *
18
+ * @see parent
19
+ */
20
+ protected function _beforeToHtml()
21
+ {
22
+ $this->_prepareCouponVariables();
23
+ }
24
+
25
+ /**
26
+ * Prepares the coupon variables for the template
27
+ *
28
+ * @return void
29
+ */
30
+ protected function _prepareCouponVariables()
31
+ {
32
+ $orderId = Mage::getSingleton('checkout/session')->getLastOrderId();
33
+ if ($orderId) {
34
+ $order = Mage::getModel('sales/order')->load($orderId);
35
+ if ($order->getId()) {
36
+ $this->setData(array(
37
+ 'email_address' => $order->getCustomerEmail(),
38
+ 'coupon_used' => $order->getCouponCode(),
39
+ 'order_increment_id' => $order->getIncrementId(),
40
+ 'order_subtotal' => $order->getSubtotal(),
41
+ 'discount_amount' => $order->getDiscountAmount(),
42
+ 'order' => $order,
43
+ ));
44
+ }
45
+ }
46
+ }
47
+ }
app/code/community/Bronto/Order/Helper/Data.php CHANGED
@@ -12,6 +12,7 @@ class Bronto_Order_Helper_Data extends Bronto_Common_Helper_Data implements Bron
12
  const XML_PATH_SYNC_LIMIT = 'bronto_order/settings/sync_limit';
13
  const XML_PATH_INSTALL_DATE = 'bronto_order/settings/install_date';
14
  const XML_PATH_UPGRADE_DATE = 'bronto_order/settings/upgrade_date';
 
15
 
16
  const XML_PATH_PRICE = 'bronto_order/import/price';
17
  const XML_PATH_DESCRIPTION = 'bronto_order/import/description';
@@ -142,6 +143,13 @@ class Bronto_Order_Helper_Data extends Bronto_Common_Helper_Data implements Bron
142
  return (bool)$this->getAdminScopedConfig(self::XML_PATH_INCL_DISCOUNT, $scope, $scopeId);
143
  }
144
 
 
 
 
 
 
 
 
145
  /**
146
  * Gets the tid hash for the managed tid
147
  *
12
  const XML_PATH_SYNC_LIMIT = 'bronto_order/settings/sync_limit';
13
  const XML_PATH_INSTALL_DATE = 'bronto_order/settings/install_date';
14
  const XML_PATH_UPGRADE_DATE = 'bronto_order/settings/upgrade_date';
15
+ const XML_PATH_BULK_LIMIT = 'bronto_order/settings/bulk_limit';
16
 
17
  const XML_PATH_PRICE = 'bronto_order/import/price';
18
  const XML_PATH_DESCRIPTION = 'bronto_order/import/description';
143
  return (bool)$this->getAdminScopedConfig(self::XML_PATH_INCL_DISCOUNT, $scope, $scopeId);
144
  }
145
 
146
+ /**
147
+ * @return int
148
+ */
149
+ public function getBulkLimit($scope = 'default', $scopeId = 0) {
150
+ return (int)$this->getAdminScopedConfig(self::XML_PATH_BULK_LIMIT, $scope, $scopeId);
151
+ }
152
+
153
  /**
154
  * Gets the tid hash for the managed tid
155
  *
app/code/community/Bronto/Order/Model/Observer.php CHANGED
@@ -111,6 +111,7 @@ class Bronto_Order_Model_Observer
111
  $basePrefix = $this->_helper->getPriceAttribute('store', $store->getId());
112
  $inclTaxes = $this->_helper->isTaxIncluded('store', $store->getId());
113
  $inclDiscounts = $this->_helper->isDiscountIncluded('store', $store->getId());
 
114
  $orderCache = array();
115
 
116
  // Cycle through each order queue row
@@ -227,22 +228,34 @@ class Bronto_Order_Model_Observer
227
  /* @var $product Mage_Catalog_Model_Product */
228
  $product = Mage::getModel('catalog/product')->setStoreId($storeId)->load($item->getProductId());
229
 
 
 
 
 
 
 
 
230
  // If the product type is simple and the description
231
  // is empty, then attempt to find a parent product
232
  // to backfill the description.
233
  if ($product->getTypeId() == Mage_Catalog_Model_Product_Type::TYPE_SIMPLE && !$product->getData($descriptionAttr)) {
234
- $parentIds = Mage::getModel('catalog/product_type_configurable')->getParentIdsByChild($product->getId());
235
- if (isset($parentIds[0])) {
236
- $parentProduct = Mage::getModel('catalog/product')->setStoreId($storeId)->load($parentIds[0]);
237
- $product->setData($descriptionAttr, $parentProduct->getData($descriptionAttr));
238
- }
239
  }
240
 
241
- // If there is a parent product, use that to get category ids
242
- if ($parent) {
243
- $categoryIds = $parent->getCategoryIds();
244
- } else {
245
- $categoryIds = $product->getCategoryIds();
 
 
 
 
 
246
  }
247
 
248
  // Cycle through category ids to pull category details
@@ -285,7 +298,7 @@ class Bronto_Order_Model_Observer
285
  // $orderRow->save();
286
 
287
  // Flush every 10 orders
288
- if ($result['total'] % 100 === 0) {
289
  $result = $this->_flushOrders($orderObject, $orderCache, $result);
290
  $orderCache = array();
291
  }
@@ -304,15 +317,15 @@ class Bronto_Order_Model_Observer
304
 
305
  // Final flush (for any we miss)
306
  if (!empty($orderCache)) {
307
- $results = $this->_flushOrders($orderObject, $orderCache, $result);
308
  }
309
 
310
  // Log results
311
- $this->_helper->writeDebug(' Success: ' . $results['success']);
312
- $this->_helper->writeDebug(' Error: ' . $results['error']);
313
- $this->_helper->writeDebug(' Total: ' . $results['total']);
314
 
315
- return $results;
316
  }
317
 
318
  /**
111
  $basePrefix = $this->_helper->getPriceAttribute('store', $store->getId());
112
  $inclTaxes = $this->_helper->isTaxIncluded('store', $store->getId());
113
  $inclDiscounts = $this->_helper->isDiscountIncluded('store', $store->getId());
114
+ $uploadMax = $this->_helper->getBulkLimit('store', $store->getId());
115
  $orderCache = array();
116
 
117
  // Cycle through each order queue row
228
  /* @var $product Mage_Catalog_Model_Product */
229
  $product = Mage::getModel('catalog/product')->setStoreId($storeId)->load($item->getProductId());
230
 
231
+ // If there is a parent product, use that to get category ids
232
+ if ($parent) {
233
+ $categoryIds = $parent->getCategoryIds();
234
+ } else {
235
+ $categoryIds = $product->getCategoryIds();
236
+ }
237
+
238
  // If the product type is simple and the description
239
  // is empty, then attempt to find a parent product
240
  // to backfill the description.
241
  if ($product->getTypeId() == Mage_Catalog_Model_Product_Type::TYPE_SIMPLE && !$product->getData($descriptionAttr)) {
242
+ $parentIds = Mage::getModel('catalog/product_type_configurable')->getParentIdsByChild($product->getId());
243
+ if (isset($parentIds[0])) {
244
+ $parentProduct = Mage::getModel('catalog/product')->setStoreId($storeId)->load($parentIds[0]);
245
+ $product->setData($descriptionAttr, $parentProduct->getData($descriptionAttr));
246
+ }
247
  }
248
 
249
+ if (empty($categoryIds)) {
250
+ if (empty($parentProduct)) {
251
+ $parentIds = Mage::getModel('catalog/product_type_configurable')->getParentIdsByChild($product->getId());
252
+ if (isset($parentIds[0])) {
253
+ $parentProduct = Mage::getModel('catalog/product')->setStoreId($storeId)->load($parentIds[0]);
254
+ }
255
+ }
256
+ if ($parentProduct) {
257
+ $categoryIds = $parentProduct->getCategoryIds();
258
+ }
259
  }
260
 
261
  // Cycle through category ids to pull category details
298
  // $orderRow->save();
299
 
300
  // Flush every 10 orders
301
+ if ($result['total'] % $uploadMax === 0) {
302
  $result = $this->_flushOrders($orderObject, $orderCache, $result);
303
  $orderCache = array();
304
  }
317
 
318
  // Final flush (for any we miss)
319
  if (!empty($orderCache)) {
320
+ $result = $this->_flushOrders($orderObject, $orderCache, $result);
321
  }
322
 
323
  // Log results
324
+ $this->_helper->writeDebug(' Success: ' . $result['success']);
325
+ $this->_helper->writeDebug(' Error: ' . $result['error']);
326
+ $this->_helper->writeDebug(' Total: ' . $result['total']);
327
 
328
+ return $result;
329
  }
330
 
331
  /**
app/code/community/Bronto/Order/Model/System/Config/Source/Bulk.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Order_Model_System_Config_Source_Bulk
4
+ {
5
+ /**
6
+ * @return array
7
+ */
8
+ public function toOptionArray()
9
+ {
10
+ return array(
11
+ 5 => 5,
12
+ 10 => 10,
13
+ 25 => 25,
14
+ 50 => 50,
15
+ 100 => 100,
16
+ );
17
+ }
18
+ }
app/code/community/Bronto/Order/controllers/Adminhtml/OrderController.php CHANGED
@@ -62,6 +62,7 @@ class Bronto_Order_Adminhtml_OrderController extends Mage_Adminhtml_Controller_A
62
  $adapter = $resource->getWriteAdapter();
63
 
64
  $queue_id = $this->getRequest()->getParam('queue_id', false);
 
65
 
66
  $where = array();
67
  if ($storeIds) {
@@ -72,6 +73,10 @@ class Bronto_Order_Adminhtml_OrderController extends Mage_Adminhtml_Controller_A
72
  $where['queue_id = ?'] = $queue_id;
73
  }
74
 
 
 
 
 
75
  try {
76
  $adapter->update(
77
  $resource->getTable('bronto_order/queue'), array(
@@ -89,6 +94,38 @@ class Bronto_Order_Adminhtml_OrderController extends Mage_Adminhtml_Controller_A
89
  $this->_redirect('*/system_config/edit', $returnParams);
90
  }
91
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  /**
93
  * Pull Orders from Order Table if not in queue
94
  */
62
  $adapter = $resource->getWriteAdapter();
63
 
64
  $queue_id = $this->getRequest()->getParam('queue_id', false);
65
+ $suppressed = $this->getRequest()->getParam('suppressed', false);
66
 
67
  $where = array();
68
  if ($storeIds) {
73
  $where['queue_id = ?'] = $queue_id;
74
  }
75
 
76
+ if ($suppressed) {
77
+ $where['bronto_suppressed IS NOT NULL'] = '';
78
+ }
79
+
80
  try {
81
  $adapter->update(
82
  $resource->getTable('bronto_order/queue'), array(
94
  $this->_redirect('*/system_config/edit', $returnParams);
95
  }
96
 
97
+ /**
98
+ * Mark all Orders as imported
99
+ */
100
+ public function markAction()
101
+ {
102
+ $helper = Mage::helper('bronto_order');
103
+ $storeIds = $helper->getStoreIds();
104
+ $resource = Mage::getResourceModel('bronto_order/queue');
105
+ $adapter = $resource->getWriteAdapter();
106
+
107
+ if ($storeIds) {
108
+ $where = array('store_id IN (?)' => $storeIds);
109
+ }
110
+ $where['bronto_suppressed IS NULL'] = '';
111
+
112
+ try {
113
+ $date = Mage::getSingleton('core/date')->gmtDate();
114
+ $adapter->update(
115
+ $resource->getTable('bronto_order/queue'),
116
+ array('bronto_imported' => $date),
117
+ $where
118
+ );
119
+ } catch (Exception $e) {
120
+ $helper->writeError($e);
121
+ $this->_getSession()->addError('Mark failed: ' . $e->getMessage());
122
+ }
123
+
124
+ $returnParams = array('section' => 'bronto_order');
125
+ $returnParams = array_merge($returnParams, $helper->getScopeParams());
126
+ $this->_redirect('*/system_config/edit', $returnParams);
127
+ }
128
+
129
  /**
130
  * Pull Orders from Order Table if not in queue
131
  */
app/code/community/Bronto/Order/etc/config.xml CHANGED
@@ -130,6 +130,7 @@
130
  <minutes>0</minutes>
131
  <limit>250</limit>
132
  <sync_limit>1000</sync_limit>
 
133
  </settings>
134
  <import>
135
  <description>short_description</description>
130
  <minutes>0</minutes>
131
  <limit>250</limit>
132
  <sync_limit>1000</sync_limit>
133
+ <bulk_limit>100</bulk_limit>
134
  </settings>
135
  <import>
136
  <description>short_description</description>
app/code/community/Bronto/Order/etc/system.xml CHANGED
@@ -132,6 +132,19 @@
132
  <show_in_store>1</show_in_store>
133
  <comment>Total Orders to sync to queue at a time.</comment>
134
  </sync_limit>
 
 
 
 
 
 
 
 
 
 
 
 
 
135
  </fields>
136
  </settings>
137
  <import>
@@ -167,7 +180,7 @@
167
  <comment><![CDATA[If <em>Yes</em>, the imported unit price
168
  will include discounts, adhering to configured tax
169
  rules (&quot;Sales&quot; &gt; &quot;Tax&quot; &gt;
170
- &quot;Calucation Settings&quot;).]]></comment>
171
  </incl_discount>
172
  <incl_tax>
173
  <label>Include Taxes</label>
@@ -178,7 +191,7 @@
178
  <show_in_website>1</show_in_website>
179
  <show_in_store>1</show_in_store>
180
  <comment><![CDATA[If <em>Yes</em>, the imported price will include taxes, adhering to the configured tax rules (&quot;Sales&quot; &gt; &quot;Tax&quot; &gt;
181
- &quot;Calucation Settings&quot;).]]></comment>
182
  </incl_tax>
183
  <description>
184
  <label>Product Description</label>
@@ -209,6 +222,17 @@
209
  <show_in_website>1</show_in_website>
210
  <show_in_store>1</show_in_store>
211
  <expanded>0</expanded>
 
 
 
 
 
 
 
 
 
 
 
212
  </suppressed>
213
  </groups>
214
  </bronto_order>
132
  <show_in_store>1</show_in_store>
133
  <comment>Total Orders to sync to queue at a time.</comment>
134
  </sync_limit>
135
+ <bulk_limit>
136
+ <label>API Bulk Limit</label>
137
+ <depends>
138
+ <enabled>1</enabled>
139
+ </depends>
140
+ <frontend_type>select</frontend_type>
141
+ <source_model>bronto_order/system_config_source_bulk</source_model>
142
+ <sort_order>70</sort_order>
143
+ <show_in_default>1</show_in_default>
144
+ <show_in_website>1</show_in_website>
145
+ <show_in_store>1</show_in_store>
146
+ <comment>Number of orders to send to Bronto at a time.</comment>
147
+ </bulk_limit>
148
  </fields>
149
  </settings>
150
  <import>
180
  <comment><![CDATA[If <em>Yes</em>, the imported unit price
181
  will include discounts, adhering to configured tax
182
  rules (&quot;Sales&quot; &gt; &quot;Tax&quot; &gt;
183
+ &quot;Calculation Settings&quot;).]]></comment>
184
  </incl_discount>
185
  <incl_tax>
186
  <label>Include Taxes</label>
191
  <show_in_website>1</show_in_website>
192
  <show_in_store>1</show_in_store>
193
  <comment><![CDATA[If <em>Yes</em>, the imported price will include taxes, adhering to the configured tax rules (&quot;Sales&quot; &gt; &quot;Tax&quot; &gt;
194
+ &quot;Calculation Settings&quot;).]]></comment>
195
  </incl_tax>
196
  <description>
197
  <label>Product Description</label>
222
  <show_in_website>1</show_in_website>
223
  <show_in_store>1</show_in_store>
224
  <expanded>0</expanded>
225
+ <fields>
226
+ <reset>
227
+ <label>Reset All Suppressed Orders</label>
228
+ <frontend_type>text</frontend_type>
229
+ <frontend_model>bronto_common/adminhtml_system_config_suppressed_reset</frontend_model>
230
+ <sort_order>0</sort_order>
231
+ <show_in_default>1</show_in_default>
232
+ <show_in_website>1</show_in_website>
233
+ <show_in_store>1</show_in_store>
234
+ </reset>
235
+ </fields>
236
  </suppressed>
237
  </groups>
238
  </bronto_order>
app/code/community/Bronto/Product/Block/Adminhtml/System/Config/About.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Block_Adminhtml_System_Config_About extends Bronto_Common_Block_Adminhtml_System_Config_About
4
+ {
5
+
6
+ /**
7
+ * @var string
8
+ */
9
+ protected $_module = 'bronto_product';
10
+
11
+ /**
12
+ * @var string
13
+ */
14
+ protected $_name = 'Bronto Product Recommendations for Magento';
15
+ }
app/code/community/Bronto/Product/Block/Adminhtml/System/Config/Cron.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Block_Adminhtml_System_Config_Cron extends Bronto_Common_Block_Adminhtml_System_Config_Cron
4
+ {
5
+ protected $_jobCode = 'bronto_product_parse_tag';
6
+
7
+ /**
8
+ * @see parent
9
+ */
10
+ protected function _prepareLayout()
11
+ {
12
+ $this->addButton($this->getLayout()->createBlock('bronto_product/adminhtml_widget_button_run'));
13
+ return parent::_prepareLayout();
14
+ }
15
+
16
+ /**
17
+ * Determine if the cron table should show
18
+ *
19
+ * @return bool
20
+ */
21
+ public function showCronTable()
22
+ {
23
+ return Mage::helper('bronto_product')->canUseMageCron();
24
+ }
25
+ }
app/code/community/Bronto/Product/Block/Adminhtml/System/Config/Information.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Block_Adminhtml_System_Config_Information extends Mage_Adminhtml_Block_System_Config_Form_Fieldset
4
+ {
5
+ /**
6
+ * Returns the description for the module in a read-only html block
7
+ *
8
+ * @param Varien_Data_Form_Element_Abstract $element
9
+ * @return string
10
+ */
11
+ public function render(Varien_Data_Form_Element_Abstract $element)
12
+ {
13
+ $url = Mage::helper('adminhtml')->getUrl('*/recommendations');
14
+ $element->setComment(str_replace('{url}', $url, $element->getComment()));
15
+ return parent::render($element);
16
+ }
17
+ }
app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation.php ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Block_Adminhtml_System_Recommendation extends Mage_Adminhtml_Block_Widget_Grid_Container
4
+ {
5
+ protected $_blockGroup = 'bronto_product';
6
+ protected $_controller = 'adminhtml_system_recommendation';
7
+ protected $_addButtonLabel = 'Add New Recommendation';
8
+
9
+ /**
10
+ * Override for previewing the recommendation with API tags and emails
11
+ *
12
+ * @see parent
13
+ */
14
+ public function __construct()
15
+ {
16
+ $this->addButton('preview_button', array(
17
+ 'label' => $this->__('Preview Recommendation'),
18
+ 'onclick' => "setLocation('{$this->getPreviewUrl()}')",
19
+ 'class' => 'go',
20
+ ));
21
+ $this->addButton('add_tag_button', array(
22
+ 'label' => $this->__('Add Content Tag Recommendation'),
23
+ 'onclick' => "setLocation('{$this->getNewContentTagUrl()}')",
24
+ 'class' => 'add tag-add',
25
+ ));
26
+ parent::__construct();
27
+ $this->setTemplate('bronto/product/recommendation/grid.phtml');
28
+ }
29
+
30
+ /**
31
+ * Adding this link to route back to config page
32
+ *
33
+ * @return string
34
+ */
35
+ public function getConfigLink()
36
+ {
37
+ $url = Mage::helper('bronto_product')->getScopeUrl('*/system_config/edit', array('section' => 'bronto_product'));
38
+ return '<strong>System &rsaquo; Configuration &raquo; Bronto &rsaquo; <a href="' . $url . '">Product Recommendations</a></strong>';
39
+ }
40
+
41
+ /**
42
+ * Override for the actual header used
43
+ *
44
+ * @return string
45
+ */
46
+ public function getHeaderText()
47
+ {
48
+ return Mage::helper($this->_blockGroup)
49
+ ->__('Bronto Product Recommendations');
50
+ }
51
+
52
+ /**
53
+ * Override for the icon in the header
54
+ *
55
+ * @return string
56
+ */
57
+ public function getHeaderCssClass()
58
+ {
59
+ return 'icon-head head-products';
60
+ }
61
+
62
+ /**
63
+ * Returns the preview url
64
+ *
65
+ * @return string
66
+ */
67
+ public function getPreviewUrl()
68
+ {
69
+ return $this->getUrl('*/*/preview', array('ret' => 'index', '_current' => true));
70
+ }
71
+
72
+ /**
73
+ * Returns the content tag URL
74
+ *
75
+ * @return string
76
+ */
77
+ public function getNewContentTagUrl()
78
+ {
79
+ return $this->getUrl('*/*/new', array('ret' => 'index', 'type' => 'content_tag', '_current' => true));
80
+ }
81
+ }
app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Default.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Block_Adminhtml_System_Recommendation_Default extends Mage_Adminhtml_Block_Template
4
+ {
5
+ const DEFAULT_TEMPLATE = 'bronto/product/recommendation/default.phtml';
6
+
7
+ /**
8
+ * @see parent
9
+ */
10
+ protected function _construct()
11
+ {
12
+ $this->setTemplate(self::DEFAULT_TEMPLATE);
13
+ }
14
+ }
app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Edit.php ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Block_Adminhtml_System_Recommendation_Edit extends Mage_Adminhtml_Block_Widget_Form_Container
4
+ {
5
+ /**
6
+ * Overrride for buttons on the form
7
+ * @see parent
8
+ */
9
+ public function __construct()
10
+ {
11
+ $this->_controller = 'recommendations';
12
+ $this->_blockGroup = 'bronto_product';
13
+ parent::__construct();
14
+
15
+ $this->addButton('save_and_edit_button', array(
16
+ 'label' => $this->__('Save and Continue Edit'),
17
+ 'onclick' => "editForm.submit('" . $this->getSaveAndEditUrl() . "')",
18
+ 'class' => 'save'
19
+ ), 1);
20
+
21
+ if ($this->getRequest()->getParam('id')) {
22
+ $this->addButton('preview_button', array(
23
+ 'label' => $this->__('Preview Recommendation'),
24
+ 'onclick' => "setLocation('{$this->getPreviewUrl()}')",
25
+ 'class' => 'go'
26
+ ));
27
+ }
28
+
29
+ // TODO: use this if we're going to be doing something crazy
30
+ $this->setTemplate('bronto/product/recommendation/edit.phtml');
31
+ }
32
+
33
+ /**
34
+ * Override for the form header
35
+ *
36
+ * @see parent
37
+ * @return string
38
+ */
39
+ public function getHeaderText()
40
+ {
41
+ $rec = Mage::registry('current_product_recommendation');
42
+ if ($rec->hasEntityId()) {
43
+ return $this->__("Edit Recommendation '%s'", $rec->getName());
44
+ } else {
45
+ return $this->__("New Recommendation");
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Override for the icon used in the header
51
+ *
52
+ * @see parent
53
+ * @return string
54
+ */
55
+ public function getHeaderCssClass()
56
+ {
57
+ return 'icon-head head-products';
58
+ }
59
+
60
+ /**
61
+ * Override to get the rigt form for the container
62
+ *
63
+ * @see parent
64
+ */
65
+ protected function _prepareLayout()
66
+ {
67
+ return $this
68
+ ->setChild('form', $this->getLayout()->createBlock("{$this->_blockGroup}/adminhtml_system_recommendation_{$this->_mode}_form"))
69
+ ->setChild('selected_products', $this->getLayout()->createBlock("{$this->_blockGroup}/adminhtml_system_recommendation_selected_js"));
70
+ }
71
+
72
+ /**
73
+ * Gets the the delete url
74
+ *
75
+ * @return string
76
+ */
77
+ public function getDeleteUrl()
78
+ {
79
+ return $this->getUrl('*/*/delete', array('id' => $this->getRequest()->getParam('id')));
80
+ }
81
+
82
+ /**
83
+ * Gets the save url
84
+ *
85
+ * @return string
86
+ */
87
+ public function getSaveUrl()
88
+ {
89
+ return $this->getUrl('*/*/save', array('_current' => true));
90
+ }
91
+
92
+ /**
93
+ * Gets the AJAX validation url
94
+ *
95
+ * @return string
96
+ */
97
+ public function getValidationUrl()
98
+ {
99
+ return $this->getUrl('*/*/validate', array('_current' => true));
100
+ }
101
+
102
+ /**
103
+ * Provides the selected products js
104
+ *
105
+ * @return string
106
+ */
107
+ public function getSelectedProductsJs()
108
+ {
109
+ return $this->getChild('selected_products')->toHtml();
110
+ }
111
+
112
+ /**
113
+ * Gets the save and continue edit url
114
+ *
115
+ * @return string
116
+ */
117
+ public function getSaveAndEditUrl()
118
+ {
119
+ return $this->getUrl("*/*/save", array('_current' => true, 'continue' => true));
120
+ }
121
+
122
+ /**
123
+ * URL to post the content tag content for preview
124
+ *
125
+ * @return string
126
+ */
127
+ public function getPreviewContentUrl()
128
+ {
129
+ return $this->getUrl('*/*/content', array('_current' => true));
130
+ }
131
+
132
+ /**
133
+ * Provides the preview url for an editing recommendation
134
+ *
135
+ * @return string
136
+ */
137
+ public function getPreviewUrl()
138
+ {
139
+ return $this->getUrl('*/*/preview', array('entity_id' => $this->getRequest()->getParam('id'), 'ret' => 'edit'));
140
+ }
141
+ }
app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Edit/Button.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Block_Adminhtml_System_Recommendation_Edit_Button extends Mage_Adminhtml_Block_Template implements Varien_Data_Form_Element_Renderer_Interface
4
+ {
5
+ protected $_element;
6
+ protected $_displayLabel = true;
7
+
8
+ /**
9
+ * @see parent
10
+ */
11
+ protected function _construct()
12
+ {
13
+ $this->setTemplate('bronto/product/recommendation/button.phtml');
14
+ }
15
+
16
+ /**
17
+ * Sets whether or not the content should be displayed in label
18
+ *
19
+ * @param bool $display
20
+ * @return Bronto_Product_Block_Adminhtml_System_Recommendation_Edit_Button
21
+ */
22
+ public function setDisplayInLabel($display)
23
+ {
24
+ $this->_displayLabel = $display;
25
+ return $this;
26
+ }
27
+
28
+ /**
29
+ * Should this button display in a label
30
+ *
31
+ * @return bool
32
+ */
33
+ public function isDisplayInLabel()
34
+ {
35
+ return $this->_displayLabel;
36
+ }
37
+
38
+ /**
39
+ * Gets the wrapped element
40
+ *
41
+ * @return Varien_Data_Form_Element_Abstract
42
+ */
43
+ public function getElement()
44
+ {
45
+ return $this->_element;
46
+ }
47
+
48
+ /**
49
+ * @see parent
50
+ * @param Varien_Data_Form_Element_Abstract $element
51
+ * @return string
52
+ */
53
+ public function render(Varien_Data_Form_Element_Abstract $element)
54
+ {
55
+ $this->_element = $element;
56
+ return $this->toHtml();
57
+ }
58
+ }
app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Edit/Form.php ADDED
@@ -0,0 +1,266 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Block_Adminhtml_System_Recommendation_Edit_Form extends Mage_Adminhtml_Block_Widget_Form
4
+ {
5
+ private $_buttonRenderer;
6
+
7
+ /**
8
+ * Creates a select button used for choosing products manually
9
+ *
10
+ * @param string $field
11
+ * @return Mage_Adminhtml_Block_Widget_Button
12
+ */
13
+ protected function _selectButton($field)
14
+ {
15
+ return $this->getLayout()->createBlock('adminhtml/widget_button')
16
+ ->setData(array(
17
+ 'label' => $this->__('Select Products'),
18
+ 'onclick' => "selectProducts('{$field}', true);",
19
+ 'class' => 'go'
20
+ ));
21
+ }
22
+
23
+ /**
24
+ * Gets the internal button renderer
25
+ */
26
+ protected function _getButtonRenderer($new = false)
27
+ {
28
+ if ($new) {
29
+ return $this->getLayout()->createBlock('bronto_product/adminhtml_system_recommendation_edit_button');
30
+ }
31
+ if (is_null($this->_buttonRenderer)) {
32
+ $this->_buttonRenderer = $this->getLayout()->createBlock('bronto_product/adminhtml_system_recommendation_edit_button');
33
+ }
34
+ return $this->_buttonRenderer;
35
+ }
36
+
37
+ /**
38
+ * Building the form details
39
+ *
40
+ * @see parent
41
+ */
42
+ protected function _prepareForm()
43
+ {
44
+ $model = Mage::registry('product_recommendation');
45
+ $sources = Mage::getModel('bronto_product/system_config_source_recommendation')->toOptionArray();
46
+ $fallbackSources = Mage::getModel('bronto_product/system_config_source_recommendation')->toOptionArray(null, true);
47
+ $dependence = $this->getLayout()->createBlock('adminhtml/widget_form_element_dependence');
48
+
49
+ if ($model->isContentTag()) {
50
+ unset($sources[3], $sources[1]);
51
+ $fallbackSources = $sources;
52
+ if (!$model->hasEntityId()) {
53
+ $model->setTagContent($this->getLayout()->createBlock('bronto_product/adminhtml_system_recommendation_default')->toHtml());
54
+ }
55
+ }
56
+
57
+ $form = new Varien_Data_Form(array(
58
+ 'id' => 'edit_form',
59
+ 'action' => $this->getUrl('*/*/save', array('id' => $this->getRequest()->getParam('id'))),
60
+ 'method' => 'post'
61
+ ));
62
+
63
+ $fieldset = $form->addFieldset('base_fieldset', array(
64
+ 'legend' => $this->__('Recommendation Information')
65
+ ));
66
+
67
+ if ($model->hasEntityId()) {
68
+ $fieldset->addField('entity_id', 'hidden', array(
69
+ 'name' => 'entity_id'
70
+ ));
71
+ }
72
+
73
+ $fieldset->addField('content_type', 'hidden', array(
74
+ 'name' => 'content_type',
75
+ 'value' => $model->getType()
76
+ ));
77
+
78
+ $fieldset->addField('name', 'text', array(
79
+ 'name' => 'name',
80
+ 'required' => true,
81
+ 'label' => $this->__('Name'),
82
+ 'title' => $this->__('Name'),
83
+ ));
84
+
85
+ $fieldset->addField('number_of_items', 'text', array(
86
+ 'name' => 'number_of_items',
87
+ 'required' => true,
88
+ 'value' => '5',
89
+ 'class' => 'validate-digits validate-digits-range digits-range-0-10',
90
+ 'label' => $this->__('Number of Items'),
91
+ 'title' => $this->__('Number of Items'),
92
+ ));
93
+
94
+ if (!Mage::app()->isSingleStoreMode() && $model->isContentTag()) {
95
+ $fieldset->addField('store_id', 'select', array(
96
+ 'name' => 'store_id',
97
+ 'label' => Mage::helper('adminhtml')->__('Store View'),
98
+ 'required' => true,
99
+ 'values' => Mage::getSingleton('adminhtml/system_store')->getStoreValuesForForm(false, false)
100
+ ));
101
+ } else if ($model->isContentTag()) {
102
+ $fieldset->addField('store_id', 'hidden', array(
103
+ 'name' => 'store_id',
104
+ 'value' => Mage::app()->getStore(true)->getId(),
105
+ ));
106
+ }
107
+
108
+ $primarySource = $fieldset->addField('primary_source', 'select', array(
109
+ 'name' => 'primary_source',
110
+ 'required' => true,
111
+ 'label' => $this->__('Primary Source'),
112
+ 'title' => $this->__('Primary Source'),
113
+ 'values' => $sources
114
+ ));
115
+
116
+ $manualPri = $fieldset->addField('manual_primary_source', 'text', array(
117
+ 'name' => 'manual_primary_source',
118
+ 'label' => $this->_selectButton('manual_primary_source')->toHtml(),
119
+ 'title' => $this->__('Custom Products'),
120
+ ));
121
+ $manualPri->setRenderer($this->_getButtonRenderer());
122
+
123
+ $manualPriHide = $fieldset->addField('primary_source_hidden', 'hidden', array(
124
+ 'name' => 'primary_source_hidden'
125
+ ));
126
+
127
+ $secondSource = $fieldset->addField('secondary_source', 'select', array(
128
+ 'name' => 'secondary_source',
129
+ 'label' => $this->__('Secondary Source'),
130
+ 'title' => $this->__('Secondary Source'),
131
+ 'values' => $sources
132
+ ));
133
+
134
+ $manualSec = $fieldset->addField('manual_secondary_source', 'text', array(
135
+ 'name' => 'manual_secondary_source',
136
+ 'label' => $this->_selectButton('manual_secondary_source')->toHtml(),
137
+ 'title' => $this->__('Custom Products'),
138
+ ));
139
+ $manualSec->setRenderer($this->_getButtonRenderer());
140
+
141
+ $manualSecHide = $fieldset->addField('secondary_source_hidden', 'hidden', array(
142
+ 'name' => 'secondary_source_hidden'
143
+ ));
144
+
145
+ $fallbackSource = $fieldset->addField('fallback_source', 'select', array(
146
+ 'name' => 'fallback_source',
147
+ 'label' => $this->__('Fallback Source'),
148
+ 'title' => $this->__('Fallback Source'),
149
+ 'values' => $fallbackSources
150
+ ));
151
+
152
+ $manualFal = $fieldset->addField('manual_fallback_source', 'text', array(
153
+ 'name' => 'manual_fallback_source',
154
+ 'label' => $this->_selectButton('manual_fallback_source')->toHtml(),
155
+ 'title' => $this->__('Custom Products'),
156
+ ));
157
+ $manualFal->setRenderer($this->_getButtonRenderer());
158
+
159
+ $manualFalHide = $fieldset->addField('fallback_source_hidden', 'hidden', array(
160
+ 'name' => 'fallback_source_hidden'
161
+ ));
162
+
163
+ if ($model->isContentTag()) {
164
+ $this->_prepareContentTagBasedForm($fieldset);
165
+ }
166
+
167
+ $dependence
168
+ ->addFieldMap($primarySource->getHtmlId(), $primarySource->getName())
169
+ ->addFieldMap($manualPri->getHtmlId(), $manualPri->getName())
170
+ ->addFieldMap($secondSource->getHtmlId(), $secondSource->getName())
171
+ ->addFieldMap($manualSec->getHtmlId(), $manualSec->getName())
172
+ ->addFieldMap($fallbackSource->getHtmlId(), $fallbackSource->getName())
173
+ ->addFieldMap($manualFal->getHtmlId(), $manualFal->getName())
174
+ ->addFieldDependence(
175
+ $manualPri->getName(),
176
+ $primarySource->getName(),
177
+ 'custom'
178
+ )
179
+ ->addFieldDependence(
180
+ $manualSec->getName(),
181
+ $secondSource->getName(),
182
+ 'custom'
183
+ )
184
+ ->addFieldDependence(
185
+ $manualFal->getName(),
186
+ $fallbackSource->getName(),
187
+ 'custom'
188
+ );
189
+
190
+ $form->setValues($model->getData());
191
+ $form->setUseContainer(true);
192
+ $this->setForm($form);
193
+
194
+ $this->setChild('form_after', $dependence);
195
+ return parent::_prepareForm();
196
+ }
197
+
198
+ /**
199
+ * Prepares the WYSIWYG editor
200
+ *
201
+ * @param $fieldset
202
+ * @return void
203
+ */
204
+ protected function _prepareContentTagBasedForm($fieldset)
205
+ {
206
+ $variables = $fieldset->addField('variables', 'label', array(
207
+ 'label' => Mage::helper('adminhtml')->__('API Reference'),
208
+ 'after_element_html' => '
209
+ <p>Loop tags are to be used inside <code>{dynamic_code}{loop}{/loop}{/dynamic_code}</code>.</p>
210
+ <table id="api_info" style="width: 300px;">
211
+ <thead>
212
+ <tr style="border-bottom: 1px solid #d6d6d6;">
213
+ <th>Loop Tag Description</th>
214
+ <th>Loop Tag</th>
215
+ </tr>
216
+ </thead>
217
+ <tbody>
218
+ <tr>
219
+ <td>Related Product\'s name</td>
220
+ <td>relatedName_#</td>
221
+ </tr>
222
+ <tr>
223
+ <td>Related Product\'s description &nbsp;</td>
224
+ <td>relatedDescription_#</td>
225
+ </tr>
226
+ <tr>
227
+ <td>Related Product\'s sku</td>
228
+ <td>relatedSku_#</td>
229
+ </tr>
230
+ <tr>
231
+ <td>Related Product\'s price</td>
232
+ <td>relatedPrice_#</td>
233
+ </tr>
234
+ <tr>
235
+ <td>Related Product\'s URL</td>
236
+ <td>relatedUrl_#</td>
237
+ </tr>
238
+ <tr>
239
+ <td>Related Product\'s image</td>
240
+ <td>relatedImgUrl_#</td>
241
+ </tr>
242
+ </tbody>
243
+ </table>
244
+ '
245
+ ));
246
+
247
+ $content = $fieldset->addField('tag_content', 'textarea', array(
248
+ 'label' => $this->__('Content Template'),
249
+ 'name' => 'tag_content',
250
+ 'required' => true,
251
+ 'style' => 'height:25em;width:600px',
252
+ ));
253
+
254
+ $previewButton = $fieldset->addField('preview_button', 'text', array(
255
+ 'label' => '&nbsp;',
256
+ 'container_id' => 'preview_button',
257
+ 'note' => $this->__('Content Template will be processed, along with the loop tags associated with the related products.'),
258
+ 'button' => $this->getLayout()->createBlock('adminhtml/widget_button')
259
+ ->setData(array(
260
+ 'class' => 'go',
261
+ 'label' => $this->__('Preview Content')
262
+ ))
263
+ ));
264
+ $previewButton->setRenderer($this->_getButtonRenderer(true)->setDisplayInLabel(false));
265
+ }
266
+ }
app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Grid.php ADDED
@@ -0,0 +1,170 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Block_Adminhtml_System_Recommendation_Grid extends Mage_Adminhtml_Block_Widget_Grid
4
+ {
5
+ /**
6
+ * Override paretn constructor for some grid specific things
7
+ *
8
+ * @param array $attributes (Optional)
9
+ * @see parent
10
+ */
11
+ public function __construct($attributes = array())
12
+ {
13
+ parent::__construct($attributes);
14
+ $this->setId('recommendationGrid');
15
+ $this->setIdFieldName('entity_id');
16
+ $this->setDefaultSort('entity_id');
17
+ $this->setDefaultDir('DESC');
18
+ $this->setSaveParametersInSession(true);
19
+ }
20
+
21
+ /**
22
+ * Prepares the data collection
23
+ *
24
+ * @return Bronto_Product_Block_Adminhtml_System_Recommendation_Grid
25
+ */
26
+ protected function _prepareCollection()
27
+ {
28
+ $collection = Mage::getModel('bronto_product/recommendation')->getCollection();
29
+ $this->setCollection($collection);
30
+
31
+ return parent::_prepareCollection();
32
+ }
33
+
34
+ /**
35
+ * Prepares the mass action block
36
+ *
37
+ * @return Bronto_Product_Block_Adminhtml_System_Recommendation_Grid
38
+ */
39
+ protected function _prepareMassaction()
40
+ {
41
+ $this->setMassactionIdField('entity_id');
42
+ $this->getMassactionBlock()->setFormFieldName('id');
43
+
44
+ $this->getMassactionBlock()->addItem('copy', array(
45
+ 'label' => $this->__('Copy'),
46
+ 'confirm' => $this->__('Are you sure?'),
47
+ 'url' => $this->getUrl('*/*/copy')
48
+ ));
49
+
50
+ $this->getMassactionBlock()->addItem('delete', array(
51
+ 'label' => $this->__('Delete'),
52
+ 'confirm' => $this->__('Are you sure?'),
53
+ 'url' => $this->getUrl('*/*/delete')
54
+ ));
55
+ return $this;
56
+ }
57
+
58
+ /**
59
+ * Gathers the sources from the dropdown sources
60
+ *
61
+ * @return array
62
+ */
63
+ protected function _getSources($fallback = false)
64
+ {
65
+ $sources = array();
66
+ $model = Mage::getModel('bronto_product/system_config_source_recommendation');
67
+ foreach ($model->toOptionArray(true) as $index => $optgroup) {
68
+ if ($index === 0 && $fallback) {
69
+ continue;
70
+ }
71
+ foreach ($optgroup['value'] as $option) {
72
+ $sources[$option['value']] = $option['label'];
73
+ }
74
+ }
75
+ return $sources;
76
+ }
77
+
78
+ /**
79
+ * Prepares the columns of the grid
80
+ *
81
+ * @see parent
82
+ */
83
+ protected function _prepareColumns()
84
+ {
85
+ $helper = Mage::helper('bronto_product');
86
+ $sources = $this->_getSources();
87
+
88
+ $this->addColumn('entity_id', array(
89
+ 'header' => $helper->__('ID'),
90
+ 'align' => 'left',
91
+ 'index' => 'entity_id',
92
+ 'type' => 'number',
93
+ 'filter' => false
94
+ ));
95
+
96
+ $this->addColumn('name', array(
97
+ 'header' => $helper->__('Name'),
98
+ 'index' => 'name',
99
+ ));
100
+
101
+ $this->addColumn('number_of_items', array(
102
+ 'header' => $helper->__('# of Items'),
103
+ 'index' => 'number_of_items',
104
+ 'type' => 'number',
105
+ 'filter' => false,
106
+ 'sortable' => false
107
+ ));
108
+
109
+ $this->addColumn('content_type', array(
110
+ 'header' => $helper->__('Content Type'),
111
+ 'index' => 'content_type',
112
+ 'type' => 'options',
113
+ 'options' => Mage::getModel('bronto_product/content')->toOptionArray(),
114
+ ));
115
+
116
+ $this->addColumn('primary_source', array(
117
+ 'header' => $helper->__('Primary Source'),
118
+ 'index' => 'primary_source',
119
+ 'type' => 'options',
120
+ 'options' => $sources,
121
+ ));
122
+
123
+ $this->addColumn('secondary_source', array(
124
+ 'header' => $helper->__('Secondary Source'),
125
+ 'index' => 'secondary_source',
126
+ 'type' => 'options',
127
+ 'options' => $sources,
128
+ ));
129
+
130
+ $this->addColumn('fallback_source', array(
131
+ 'header' => $helper->__('Fallback Source'),
132
+ 'index' => 'fallback_source',
133
+ 'type' => 'options',
134
+ 'options' => $this->_getSources(true),
135
+ ));
136
+
137
+ if (!Mage::app()->isSingleStoreMode()) {
138
+ $this->addColumn('store_id', array(
139
+ 'header' => $helper->__('Store View'),
140
+ 'type' => 'store',
141
+ 'skipAllStoresLabel' => true,
142
+ 'index' => 'store_id',
143
+ 'sortable' => false,
144
+ 'store_view' => true,
145
+ ));
146
+ }
147
+
148
+ $this->addColumn('action', array(
149
+ 'header' => $helper->__('Action'),
150
+ 'index' => 'entity_id',
151
+ 'sortable' => false,
152
+ 'filter' => false,
153
+ 'width' => '130px',
154
+ 'renderer' => 'bronto_product/adminhtml_system_recommendation_grid_renderer_action'
155
+ ));
156
+
157
+ return $this;
158
+ }
159
+
160
+ /**
161
+ * Gets the edit url for a given recommendation
162
+ *
163
+ * @param $row
164
+ * @return string
165
+ */
166
+ public function getRowUrl($row)
167
+ {
168
+ return $this->getUrl('*/*/edit', array('id' => $row->getId()));
169
+ }
170
+ }
app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Grid/Renderer/Action.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Block_Adminhtml_System_Recommendation_Grid_Renderer_Action extends Mage_Adminhtml_Block_Widget_Grid_Column_Renderer_Action
4
+ {
5
+ /**
6
+ * Override for immediate action on a recommendation
7
+ *
8
+ * @param Varien_Object $row
9
+ * @return string
10
+ */
11
+ public function render(Varien_Object $row)
12
+ {
13
+ $actions = array();
14
+ $actions[] = array(
15
+ 'url' => $this->getUrl('*/*/edit', array('id' => $row->getId())),
16
+ 'caption' => $this->__('Edit'),
17
+ );
18
+ $actions[] = array(
19
+ 'url' => $this->getUrl('*/*/copy', array('id' => $row->getId())),
20
+ 'caption' => $this->__('Copy'),
21
+ 'confirm' => $this->__('Are you sure you want to copy the selected recommendation?'),
22
+ );
23
+ $actions[] = array(
24
+ 'url' => $this->getUrl('*/*/delete', array('id' => $row->getId())),
25
+ 'caption' => $this->__('Delete'),
26
+ 'confirm' => $this->__('Are you sure you want to delete the selected recommendation?'),
27
+ );
28
+ $actions[] = array(
29
+ 'url' => $this->getUrl('*/*/preview', array('entity_id' => $row->getId(), 'ret' => 'index')),
30
+ 'caption' => $this->__('Preview'),
31
+ );
32
+ $this->getColumn()->setActions($actions);
33
+ return parent::render($row);
34
+ }
35
+ }
app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Grid/Renderer/Description.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Block_Adminhtml_System_Recommendation_Grid_Renderer_Description extends Mage_Adminhtml_Block_Widget_Grid_Column_Renderer_Abstract
4
+ {
5
+ /**
6
+ * Properly truncates the description
7
+ *
8
+ * @param Varien_Object $row
9
+ * @return string
10
+ */
11
+ public function render(Varien_Object $row)
12
+ {
13
+ $storeId = $this->getRequest()->getParam('store', 0);
14
+ $helper = Mage::helper('bronto_product');
15
+ $limit = $helper->getCharLimit('store', $storeId);
16
+ $attr = $helper->getDescriptionAttr('store', $storeId);
17
+ return $helper->truncateText($row->getData($attr), $limit);
18
+ }
19
+ }
app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Grid/Renderer/Image.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Block_Adminhtml_System_Recommendation_Grid_Renderer_Image extends Mage_Adminhtml_Block_Widget_Grid_Column_Renderer_Abstract
4
+ {
5
+ /**
6
+ * Returns the image as it would appear in the email
7
+ *
8
+ * @param Varien_Object $row
9
+ * @return string
10
+ */
11
+ public function render(Varien_Object $row)
12
+ {
13
+ $product = Mage::getModel('catalog/product')->load($row->getId());
14
+ $imageUrl = Mage::helper('bronto_common')->getProductImageUrl($product);
15
+ return '<img src="' . $imageUrl . '" alt="' . (empty($imageUrl) ? 'Not Found' : $imageUrl) . '" />';
16
+ }
17
+ }
app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Grid/Renderer/Price.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Block_Adminhtml_System_Recommendation_Grid_Renderer_Price extends Mage_Adminhtml_Block_Widget_Grid_Column_Renderer_Abstract
4
+ {
5
+ /**
6
+ * Properly render the price
7
+ *
8
+ * @param Varien_Object $row
9
+ * @return string
10
+ */
11
+ public function render(Varien_Object $row)
12
+ {
13
+ $storeId = $this->getRequest()->getParam('store', 0);
14
+ list($base, $currency, $options) = Mage::helper('bronto_product')->currencyAndOptions($storeId);
15
+ $price = $row->getPrice();
16
+ if ($base != $currency) {
17
+ $price = $base->convert($price, $currency, $options);
18
+ }
19
+ return $currency->formatTxt($price, $options);
20
+ }
21
+ }
app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Grid/Renderer/Url.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Block_Adminhtml_System_Recommendation_Grid_Renderer_Url extends Mage_Adminhtml_Block_Widget_Grid_Column_Renderer_Abstract
4
+ {
5
+
6
+ /**
7
+ * Returns the url as a clickable link to the product
8
+ *
9
+ * @param Varien_Object $row
10
+ * @return string
11
+ */
12
+ public function render(Varien_Object $row)
13
+ {
14
+ $storeId = $this->getRequest()->getParam('store', 0);
15
+ $url = Mage::helper('bronto_common/product')->getProductAttribute($row->getId(), 'url', $storeId);
16
+ return '<a href="' . $url . '">' . $url . '</a>';
17
+ }
18
+ }
app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Message/Form.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Block_Adminhtml_System_Recommendation_Message_Form extends Mage_Adminhtml_Block_Widget_Form
4
+ {
5
+
6
+ /**
7
+ * Prepares the message form
8
+ * @see parent
9
+ */
10
+ protected function _prepareForm()
11
+ {
12
+ $form = new Varien_Data_Form('message_form', array(
13
+ 'id' => 'message_form',
14
+ ));
15
+
16
+ $fieldset = $form->addFieldset('message_fieldset', array(
17
+ 'comment' => $this->__('If a message is selected, a test delivery will be made to the email entered. This means that if a contact does not exist with the supplied email, it will be created. The same rules apply to test deliveries as they do marketing messages, so the contact must either be onboarding or active in order to receive the message.')
18
+ ));
19
+
20
+ $fieldset->addField('message_id', 'select', array(
21
+ 'name' => 'message_id',
22
+ 'label' => $this->__('Bronto Message'),
23
+ 'values' => Mage::helper('bronto_common/message')->getMessagesOptionsArray($this->getRequest()->getParam('store', null))
24
+ ));
25
+
26
+ $fieldset->addField('email_address', 'text', array(
27
+ 'name' => 'email_address',
28
+ 'label' => $this->__('Email Address'),
29
+ ));
30
+
31
+ $form->setValues(array(
32
+ 'email_address' => Mage::getSingleton('admin/session')->getUser()->getEmail()));
33
+ $this->setForm($form);
34
+ return parent::_prepareForm();
35
+ }
36
+ }
app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Preview.php ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Block_Adminhtml_System_Recommendation_Preview extends Mage_Adminhtml_Block_Widget_Form_Container
4
+ {
5
+ /**
6
+ * Override for buttons on the form
7
+ * @see parent
8
+ */
9
+ public function __construct()
10
+ {
11
+ $this->_controller = 'recommendations';
12
+ $this->_blockGroup = 'bronto_product';
13
+ parent::__construct();
14
+ $this->removeButton('save');
15
+ $this->removeButton('reset');
16
+ $this->removeButton('delete');
17
+
18
+ $this->setTemplate('bronto/product/recommendation/preview.phtml');
19
+ }
20
+
21
+ /**
22
+ * Override for the preview functionality
23
+ *
24
+ * @return string
25
+ */
26
+ public function getHeaderText()
27
+ {
28
+ return $this->__('Preview Recommendation');
29
+ }
30
+
31
+ /**
32
+ * Override for the preview functionality
33
+ *
34
+ * @return string
35
+ */
36
+ public function getHeaderCssClass()
37
+ {
38
+ return 'icon-head head-products';
39
+ }
40
+
41
+ /**
42
+ * Override for the preview form
43
+ *
44
+ * @see parent
45
+ */
46
+ public function _prepareLayout()
47
+ {
48
+ $storeSwitcher = $this->getLayout()->createBlock("adminhtml/store_switcher")
49
+ ->setUseConfirm(false)
50
+ ->setSwitchUrl($this->getUrl('*/*/*', array('store' => null, '_current' => true)));
51
+ $storeSwitcher->hasDefaultOption(false);
52
+ return $this
53
+ ->setChild('form', $this->getLayout()->createBlock("{$this->_blockGroup}/adminhtml_system_recommendation_preview_form"))
54
+ ->setChild('selected_products', $this->getLayout()->createBlock("{$this->_blockGroup}/adminhtml_system_recommendation_selected_js"))
55
+ ->setChild('store_switcher', $storeSwitcher);
56
+ }
57
+
58
+ /**
59
+ * The store switcher to change the pulled messages
60
+ *
61
+ * @return string
62
+ */
63
+ public function getStoreSwitcherHtml()
64
+ {
65
+ return $this->getChild('store_switcher')->toHtml();
66
+ }
67
+
68
+ /**
69
+ * Is the Magento installation single store only?
70
+ *
71
+ * @return bool
72
+ */
73
+ public function isSingleStoreMode()
74
+ {
75
+ return Mage::app()->isSingleStoreMode();
76
+ }
77
+
78
+ /**
79
+ * Provides the selected products js
80
+ * @return string
81
+ */
82
+ public function getSelectedProductsJs()
83
+ {
84
+ return $this->getChild('selected_products')->toHtml();
85
+ }
86
+
87
+ /**
88
+ * Gets the AJAX url for updating the recommended content
89
+ * @return string
90
+ */
91
+ public function getUpdatePreviewUrl()
92
+ {
93
+ return $this->getUrl('*/*/previewGrid', array('store' => $this->getRequest()->getParam('store', 1)));
94
+ }
95
+
96
+ /**
97
+ * Gets the AJAX url for Bronto message to send to a test contact
98
+ * @return string
99
+ */
100
+ public function getMessageDialogUrl()
101
+ {
102
+ return $this->getUrl('*/*/messages', array('store' => $this->getRequest()->getParam('store', 1)));
103
+ }
104
+
105
+ /**
106
+ * Gets the AJAX url for sending the Bronto message to the test contact
107
+ * @return string
108
+ */
109
+ public function getSendMessageUrl()
110
+ {
111
+ return $this->getUrl('*/*/sendMessage', array('store' => $this->getRequest()->getParam('store', 1)));
112
+ }
113
+
114
+ /**
115
+ * Gets the correct url for going backward
116
+ * @return string
117
+ */
118
+ public function getBackUrl()
119
+ {
120
+ $params = array();
121
+ if ($this->getRequest()->getParam('entity_id')) {
122
+ $params['id'] = $this->getRequest()->getParam('entity_id');
123
+ }
124
+ return $this->getUrl('*/*/' . $this->getRequest()->getParam('ret', 'index'), $params);
125
+ }
126
+ }
app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Preview/Form.php ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Block_Adminhtml_System_Recommendation_Preview_Form extends Mage_Adminhtml_Block_Widget_Form
4
+ {
5
+
6
+ /**
7
+ * Creates the widget containing the dialog popup
8
+ *
9
+ * @param string $field
10
+ * @param string $label
11
+ * @return Mage_Adminhtml_Block_Widget_Button
12
+ */
13
+ protected function _selectButton($field, $label)
14
+ {
15
+ return $this->getLayout()->createBlock('adminhtml/widget_button')
16
+ ->setData(array(
17
+ 'label' => $this->__($label),
18
+ 'onclick' => "selectProducts('{$field}', false);",
19
+ 'class' => 'go'
20
+ ));
21
+ }
22
+
23
+ /**
24
+ * Prepares the top level preview form
25
+ *
26
+ * @see parent
27
+ */
28
+ protected function _prepareForm()
29
+ {
30
+ $model = Mage::registry('product_recommendation');
31
+ $buttonRenderer = $this->getLayout()->createBlock('bronto_product/adminhtml_system_recommendation_edit_button');
32
+
33
+ $form = new Varien_Data_Form(array(
34
+ 'id' => 'preview_form',
35
+ 'method' => 'post'
36
+ ));
37
+
38
+ $fieldset = $form->addFieldset('base_fieldset', array(
39
+ 'legend' => $this->__('Preview Information')
40
+ ));
41
+
42
+ $fieldset->addField('entity_id', 'select', array(
43
+ 'name' => 'entity_id',
44
+ 'required' => true,
45
+ 'onchange' => "updateRecommendations()",
46
+ 'label' => $this->__('Recommendations'),
47
+ 'values' => Mage::getModel('bronto_product/recommendation')->toOptionArray()
48
+ ));
49
+
50
+ $optional = $fieldset->addField('product_ids', 'text', array(
51
+ 'name' => 'product_ids',
52
+ 'onchange' => "updateRecommendations()",
53
+ 'label' => $this->_selectButton('product_ids', 'Optional Products')->toHtml(),
54
+ 'title' => $this->__('Optional Products')
55
+ ));
56
+ $optional->setRenderer($buttonRenderer);
57
+
58
+ $correctClass = $model->hasEntityId() ? 'go' : 'disabled';
59
+ $sendMessage = $fieldset->addField('send_message_button', 'label', array(
60
+ 'label' => $this->getLayout()->createBlock('adminhtml/widget_button')
61
+ ->setData(array(
62
+ 'label' => $this->__('Send Test Email'),
63
+ 'class' => $correctClass,
64
+ 'onclick' => "messagePicker()",
65
+ 'disabled' => $correctClass == 'disabled'
66
+ ))
67
+ ->toHtml()
68
+ ));
69
+ $sendMessage->setRenderer($buttonRenderer);
70
+
71
+ $subfieldset = $fieldset->addFieldset('product_preview', array(
72
+ 'legend' => $this->__('Recommended Products'),
73
+ ));
74
+
75
+ $grid = new Bronto_Product_Block_Adminhtml_System_Recommendation_Preview_GridElement($this->getLayout()->createBlock('bronto_product/adminhtml_system_recommendation_preview_grid'));
76
+ $subfieldset->addElement($grid);
77
+
78
+ $form->setValues($model->getData());
79
+ $form->setUseContainer(true);
80
+ $this->setForm($form);
81
+ return parent::_prepareForm();
82
+ }
83
+ }
app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Preview/Grid.php ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Block_Adminhtml_System_Recommendation_Preview_Grid extends Mage_Adminhtml_Block_Widget_Grid
4
+ {
5
+ /**
6
+ * @see parent
7
+ */
8
+ public function __construct($attributes = array())
9
+ {
10
+ parent::__construct($attributes);
11
+ $this->setId('previewProductsGrid');
12
+ $this->setIdFieldName('entity_id');
13
+ $this->setFilterVisibility(false);
14
+ }
15
+
16
+ /**
17
+ * Use the store in the params
18
+ *
19
+ * @return Mage_Core_Model_Store
20
+ */
21
+ protected function _getStore()
22
+ {
23
+ $storeId = $this->getRequest()->getParam('store', 1);
24
+ return Mage::app()->getStore($storeId);
25
+ }
26
+
27
+ /**
28
+ * Prepares the product collection
29
+ * @see parent
30
+ */
31
+ protected function _prepareCollection()
32
+ {
33
+ $store = $this->_getStore();
34
+ $productIds = $this->getRelatedProductIds();
35
+ $collection = Mage::getModel('catalog/product')->getCollection()
36
+ ->addAttributeToSelect('sku')
37
+ ->addAttributeToSelect('name')
38
+ ->addAttributeToSelect(Mage::helper('bronto_product')->getDescriptionAttr('store', $store->getId()))
39
+ ->joinField('qty',
40
+ 'cataloginventory/stock_item',
41
+ 'qty',
42
+ 'product_id=entity_id',
43
+ '{{table}}.stock_id=1',
44
+ 'left');
45
+ if (!empty($productIds)) {
46
+ $collection->addFieldToFilter('entity_id', array('in' => $productIds));
47
+ } else {
48
+ $collection->addFieldToFilter('entity_id', array('eq' => 0));
49
+ }
50
+ if ($store->getId()) {
51
+ $collection->addStoreFilter($store);
52
+ $collection->joinAttribute('custom_name', 'catalog_product/name', 'entity_id', null, 'inner', $store->getId());
53
+ $collection->joinAttribute('status', 'catalog_product/status', 'entity_id', null, 'inner', $store->getId());
54
+ $collection->joinAttribute('visibility', 'catalog_product/visibility', 'entity_id', null, 'inner', $store->getId());
55
+ $collection->joinAttribute('price', 'catalog_product/price', 'entity_id', null, 'left', $store->getId());
56
+ } else {
57
+ $collection->addAttributeToSelect('price');
58
+ }
59
+
60
+ $this->setCollection($collection);
61
+ parent::_prepareCollection();
62
+ return $this;
63
+ }
64
+
65
+ /**
66
+ * Prepares the grid to match the api data
67
+ * @see parent
68
+ */
69
+ protected function _prepareColumns()
70
+ {
71
+ $store = $this->_getStore();
72
+
73
+ $this->addColumn('name',
74
+ array(
75
+ 'header'=> Mage::helper('catalog')->__('Name'),
76
+ 'index' => 'name',
77
+ 'filter' => false,
78
+ 'sortable' => false
79
+ ));
80
+
81
+ $this->addColumn('sku',
82
+ array(
83
+ 'header'=> Mage::helper('catalog')->__('SKU'),
84
+ 'width' => 80,
85
+ 'index' => 'sku',
86
+ 'filter' => false,
87
+ 'sortable' => false
88
+ ));
89
+
90
+ $this->addColumn('price',
91
+ array(
92
+ 'header' => Mage::helper('catalog')->__('Price'),
93
+ 'type' => 'currency',
94
+ 'filter' => false,
95
+ 'sortable' => false,
96
+ 'index' => 'price',
97
+ 'renderer' => 'bronto_product/adminhtml_system_recommendation_grid_renderer_price',
98
+ ));
99
+
100
+ $this->addColumn('description',
101
+ array(
102
+ 'header' => Mage::helper('catalog')->__('Description'),
103
+ 'width' => '200px',
104
+ 'filter' => false,
105
+ 'sortable' => false,
106
+ 'renderer' => 'bronto_product/adminhtml_system_recommendation_grid_renderer_description'
107
+ ));
108
+
109
+ $this->addColumn('url',
110
+ array(
111
+ 'header' => Mage::helper('catalog')->__('URL'),
112
+ 'sortable' => false,
113
+ 'filter' => false,
114
+ 'renderer' => 'bronto_product/adminhtml_system_recommendation_grid_renderer_url'
115
+ ));
116
+
117
+ $this->addColumn('image_url',
118
+ array(
119
+ 'header' => Mage::helper('catalog')->__('Image'),
120
+ 'sortable' => false,
121
+ 'filter' => false,
122
+ 'renderer' => 'bronto_product/adminhtml_system_recommendation_grid_renderer_image'
123
+ ));
124
+
125
+ return $this;
126
+ }
127
+
128
+ /**
129
+ * Gets the related product ids to filter upon
130
+ * @return array
131
+ */
132
+ public function getRelatedProductIds()
133
+ {
134
+ return Mage::helper('bronto_product')->collectRecommendations(
135
+ $this->getSelectedRecommendation(),
136
+ $this->_getStore()->getId(),
137
+ $this->getOptionalProducts());
138
+ }
139
+
140
+ /**
141
+ * Gets the underlying recommendation or a blank one
142
+ * @return Bronto_Product_Model_Recommendation
143
+ */
144
+ public function getSelectedRecommendation()
145
+ {
146
+ $model = Mage::getModel('bronto_product/recommendation');
147
+ $model->load($this->getRequest()->getParam('entity_id'));
148
+ return $model;
149
+ }
150
+
151
+ /**
152
+ * Gets the optionally selected products representing the cart or order
153
+ * @return array
154
+ */
155
+ public function getOptionalProducts()
156
+ {
157
+ $productIds = $this->getRequest()->getPost('product_ids', array());
158
+ $products = array();
159
+ foreach ($productIds as $productId) {
160
+ $products[] = Mage::getModel('catalog/product')->load($productId);
161
+ }
162
+ return $products;
163
+ }
164
+ }
app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Preview/GridElement.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Block_Adminhtml_System_Recommendation_Preview_GridElement extends Varien_Data_Form_Element_Abstract
4
+ {
5
+ private $_block;
6
+
7
+ /**
8
+ * Wraps the block to return the html
9
+ * @param Mage_Adminhtml_Block_Abstract
10
+ */
11
+ public function __construct($block)
12
+ {
13
+ $this->_block = $block;
14
+ }
15
+
16
+ /**
17
+ * Returns the html of the wrapped block
18
+ * @return string
19
+ */
20
+ public function toHtml()
21
+ {
22
+ return $this->_block->toHtml();
23
+ }
24
+ }
app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Selected/Grid.php ADDED
@@ -0,0 +1,223 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Block_Adminhtml_System_Recommendation_Selected_Grid extends Mage_Adminhtml_Block_Widget_Grid
4
+ {
5
+ /**
6
+ * @see parent
7
+ */
8
+ public function __construct($attributes = array())
9
+ {
10
+ parent::__construct($attributes);
11
+ $this->setId('selectedProductsGrid');
12
+ $this->setIdFieldName('entity_id');
13
+ $this->setDefaultSort('entity_id');
14
+ $this->setUseAjax(true);
15
+ if ($this->_getSelectedProducts()) {
16
+ $this->setDefaultFilter(array('in_products' => 1));
17
+ }
18
+ }
19
+
20
+ /**
21
+ * Initial column filter for pre-existing products
22
+ *
23
+ * @param mixed $column
24
+ * @return Bronto_Product_Block_Adminhtml_System_Recommendation_Selected_Grid
25
+ */
26
+ protected function _addColumnFilterToCollection($column)
27
+ {
28
+ // Set custom filter for in product flag
29
+ if ($column->getId() == 'in_products') {
30
+ $productIds = $this->_getSelectedProducts();
31
+ if (empty($productIds)) {
32
+ $productIds = 0;
33
+ }
34
+ if ($column->getFilter()->getValue()) {
35
+ $this->getCollection()->addFieldToFilter('entity_id', array('in'=>$productIds));
36
+ } else {
37
+ if($productIds) {
38
+ $this->getCollection()->addFieldToFilter('entity_id', array('nin'=>$productIds));
39
+ }
40
+ }
41
+ } else {
42
+ parent::_addColumnFilterToCollection($column);
43
+ }
44
+ return $this;
45
+ }
46
+
47
+ /**
48
+ * Use the store in the params
49
+ *
50
+ * @return Mage_Core_Model_Store
51
+ */
52
+ protected function _getStore()
53
+ {
54
+ $storeId = $this->getRequest()->getParam('store', 0);
55
+ return Mage::app()->getStore($storeId);
56
+ }
57
+
58
+ /**
59
+ * Product collection for the products
60
+ *
61
+ * @see parent
62
+ */
63
+ protected function _prepareCollection()
64
+ {
65
+ $store = $this->_getStore();
66
+ $collection = Mage::getModel('catalog/product')->getCollection()
67
+ ->addAttributeToSelect('sku')
68
+ ->addAttributeToSelect('name')
69
+ ->addAttributeToSelect('attribute_set_id')
70
+ ->addAttributeToSelect('type_id')
71
+ //->addAttributeToFilter('status', array(''))
72
+ ->joinField('qty',
73
+ 'cataloginventory/stock_item',
74
+ 'qty',
75
+ 'product_id=entity_id',
76
+ '{{table}}.stock_id=1',
77
+ 'left');
78
+
79
+ if ($store->getId()) {
80
+ $collection->addStoreFilter($store);
81
+ $collection->joinAttribute('custom_name', 'catalog_product/name', 'entity_id', null, 'inner', $store->getId());
82
+ $collection->joinAttribute('status', 'catalog_product/status', 'entity_id', null, 'inner', $store->getId());
83
+ $collection->joinAttribute('visibility', 'catalog_product/visibility', 'entity_id', null, 'inner', $store->getId());
84
+ $collection->joinAttribute('price', 'catalog_product/price', 'entity_id', null, 'left', $store->getId());
85
+ } else {
86
+ $collection->addAttributeToSelect('price');
87
+ $collection->addAttributeToSelect('status');
88
+ $collection->addAttributeToSelect('visibility');
89
+ }
90
+
91
+ $this->setCollection($collection);
92
+
93
+ parent::_prepareCollection();
94
+ $this->getCollection()->addWebsiteNamesToResult();
95
+ return $this;
96
+ }
97
+
98
+ /**
99
+ * Prepares the columns used in the product grid
100
+ *
101
+ * @see parent
102
+ */
103
+ protected function _prepareColumns()
104
+ {
105
+ $this->addColumn('in_products', array(
106
+ 'header_css_class' => 'a-center',
107
+ 'type' => 'checkbox',
108
+ 'field_name' => 'in_products',
109
+ 'values' => $this->_getSelectedProducts(),
110
+ 'align' => 'center',
111
+ 'index' => 'entity_id'
112
+ ));
113
+
114
+ $this->addColumn('entity_id',
115
+ array(
116
+ 'header'=> Mage::helper('catalog')->__('ID'),
117
+ 'width' => 50,
118
+ 'sortable' => true,
119
+ 'type' => 'number',
120
+ 'index' => 'entity_id',
121
+ ));
122
+ $this->addColumn('name',
123
+ array(
124
+ 'header'=> Mage::helper('catalog')->__('Name'),
125
+ 'index' => 'name',
126
+ ));
127
+
128
+ $store = $this->_getStore();
129
+ if ($store->getId()) {
130
+ $this->addColumn('custom_name',
131
+ array(
132
+ 'header'=> Mage::helper('catalog')->__('Name in %s', $store->getName()),
133
+ 'index' => 'custom_name',
134
+ ));
135
+ }
136
+
137
+ $this->addColumn('type',
138
+ array(
139
+ 'header' => Mage::helper('catalog')->__('Type'),
140
+ 'width' => 100,
141
+ 'index' => 'type_id',
142
+ 'type' => 'options',
143
+ 'options' => Mage::getSingleton('catalog/product_type')->getOptionArray(),
144
+ ));
145
+
146
+ $sets = Mage::getResourceModel('eav/entity_attribute_set_collection')
147
+ ->setEntityTypeFilter(Mage::getModel('catalog/product')->getResource()->getTypeId())
148
+ ->load()
149
+ ->toOptionHash();
150
+
151
+ $this->addColumn('set_name',
152
+ array(
153
+ 'header' => Mage::helper('catalog')->__('Attrib. Set Name'),
154
+ 'width' => 100,
155
+ 'index' => 'attribute_set_id',
156
+ 'type' => 'options',
157
+ 'options' => $sets,
158
+ ));
159
+
160
+ $this->addColumn('sku',
161
+ array(
162
+ 'header'=> Mage::helper('catalog')->__('SKU'),
163
+ 'width' => 80,
164
+ 'index' => 'sku',
165
+ ));
166
+
167
+ $store = $this->_getStore();
168
+ $this->addColumn('price',
169
+ array(
170
+ 'header' => Mage::helper('catalog')->__('Price'),
171
+ 'type' => 'price',
172
+ 'currency_code' => $store->getBaseCurrency()->getCode(),
173
+ 'index' => 'price',
174
+ ));
175
+
176
+ $this->addColumn('visibility',
177
+ array(
178
+ 'header' => Mage::helper('catalog')->__('Visibility'),
179
+ 'width' => 100,
180
+ 'index' => 'visibility',
181
+ 'type' => 'options',
182
+ 'options' => Mage::getModel('catalog/product_visibility')->getOptionArray(),
183
+ ));
184
+
185
+ $this->addColumn('status',
186
+ array(
187
+ 'header' => Mage::helper('catalog')->__('Status'),
188
+ 'width' => 70,
189
+ 'index' => 'status',
190
+ 'type' => 'options',
191
+ 'options' => Mage::getSingleton('catalog/product_status')->getOptionArray(),
192
+ ));
193
+
194
+ return parent::_prepareColumns();
195
+ }
196
+
197
+ /**
198
+ * Gets the selected products from the request or model
199
+ *
200
+ * @return array
201
+ */
202
+ protected function _getSelectedProducts()
203
+ {
204
+ $products = $this->getRequest()->getParam('products', null);
205
+ Mage::helper('bronto_common')->writeDebug(var_export($products, true));
206
+ if (!is_array($products)) {
207
+ $products = $this->getRelatedProductIds();
208
+ }
209
+ return $products;
210
+ }
211
+
212
+ /**
213
+ * Gets the related products from the source of the model
214
+ *
215
+ * @return array
216
+ */
217
+ public function getRelatedProductIds()
218
+ {
219
+ $source = $this->getRequest()->getParam('source', 'primary');
220
+ $product = Mage::registry('current_product_recommendation');
221
+ return $product->getCustomProductIds($source);
222
+ }
223
+ }
app/code/community/Bronto/Product/Block/Adminhtml/System/Recommendation/Selected/Js.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Block_Adminhtml_System_Recommendation_Selected_Js extends Mage_Adminhtml_Block_Abstract
4
+ {
5
+ /**
6
+ * Override for template path
7
+ */
8
+ public function __construct()
9
+ {
10
+ parent::__construct();
11
+ $this->setTemplate('bronto/product/recommendation/selected.js.phtml');
12
+ }
13
+
14
+ /**
15
+ * Url for the ajax picker
16
+ *
17
+ * @return string
18
+ */
19
+ public function getSelectAjaxUrl()
20
+ {
21
+ return $this->getUrl('*/*/selected', array('_current' => true));
22
+ }
23
+ }
app/code/community/Bronto/Product/Block/Adminhtml/Widget/Button/Run.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Block_Adminhtml_Widget_Button_Run extends Mage_Adminhtml_Block_Widget_Button
4
+ {
5
+ /**
6
+ * @see parent
7
+ */
8
+ protected function _construct()
9
+ {
10
+ $this->setLabel('Run Now');
11
+ $this->setOnClick("setLocation('" . $this->getRunUrl() . "'); return false;");
12
+ $this->setClass('bronto-cron-run');
13
+
14
+ if (!Mage::helper('bronto_product')->isModuleActive()) {
15
+ $this->setDisabled(true)->setClass('disabled');
16
+ }
17
+ }
18
+
19
+ /**
20
+ * Gets the run url for product recommendation
21
+ *
22
+ * @return string
23
+ */
24
+ public function getRunUrl()
25
+ {
26
+ return $this->getUrl('*/recommendations/run');
27
+ }
28
+ }
app/code/community/Bronto/Product/Helper/Data.php ADDED
@@ -0,0 +1,348 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Helper_Data extends Bronto_Common_Helper_Data
4
+ {
5
+ const XML_PATH_ENABLED = 'bronto_product/settings/enabled';
6
+ const XML_PATH_MAGE_CRON = 'bronto_product/settings/mage_cron';
7
+ const XML_PATH_DESCRIPTION = 'bronto_product/settings/description';
8
+ const XML_PATH_CHAR_LIMIT = 'bronto_product/settings/char_limit';
9
+
10
+ /**
11
+ * Checks if the module is enabled
12
+ *
13
+ * @param string $default
14
+ * @param int $scopeId
15
+ * @return bool
16
+ */
17
+ public function isEnabled($scope = 'default', $scopeId = 0)
18
+ {
19
+ return (bool)$this->getAdminScopedConfig(self::XML_PATH_ENABLED, $scope, $scopeId);
20
+ }
21
+
22
+ /**
23
+ * Checks if the module has Magento cron enabled
24
+ *
25
+ * @param string $scope
26
+ * @param int $scopeId
27
+ * @return bool
28
+ */
29
+ public function canUseMageCron($scope = 'default', $scopeId = 0)
30
+ {
31
+ return (bool)$this->getAdminScopedConfig(self::XML_PATH_MAGE_CRON, $scope, $scopeId);
32
+ }
33
+
34
+ /**
35
+ * Gets the character truncation limit for the description attr
36
+ *
37
+ * @param string $scope
38
+ * @param int $scopeId
39
+ * @return int
40
+ */
41
+ public function getCharLimit($scope = 'default', $scopeId = 0)
42
+ {
43
+ return (int)$this->getAdminScopedConfig(self::XML_PATH_CHAR_LIMIT, $scope, $scopeId);
44
+ }
45
+
46
+ /**
47
+ * Gets the description attribute for the product description
48
+ *
49
+ * @param string $scope
50
+ * @param int $scopeId
51
+ * @return string
52
+ */
53
+ public function getDescriptionAttr($scope = 'default', $scopeId = 0)
54
+ {
55
+ return $this->getAdminScopedConfig(self::XML_PATH_DESCRIPTION, $scope, $scopeId);
56
+ }
57
+
58
+ /**
59
+ * Checks if the module is enabled for any store
60
+ *
61
+ * @return bool
62
+ */
63
+ public function isEnabledForAny()
64
+ {
65
+ $stores = Mage::app()->getStores();
66
+ if (is_array($stores) && count($stores) >= 1) {
67
+ foreach ($stores as $store) {
68
+ if ($this->isEnabled('store', $store->getId())) {
69
+ return true;
70
+ }
71
+ }
72
+ }
73
+ return false;
74
+ }
75
+
76
+ /**
77
+ * Gets the friendly name for this module
78
+ *
79
+ * @return string
80
+ */
81
+ public function getName()
82
+ {
83
+ return 'Bronto Product Recommendations';
84
+ }
85
+
86
+ /**
87
+ * Collects all products that are in some way 'recommended' based
88
+ * on the defined recommendation.
89
+ *
90
+ * @param Bronto_Product_Model_Recommendation $recommendation
91
+ * @param int $storeId
92
+ * @param mixed $originalItems
93
+ * @return array
94
+ */
95
+ public function collectRecommendations(Bronto_Product_Model_Recommendation $recommendation, $storeId = null, $originalItems = array())
96
+ {
97
+ // Don't operate on an invalid recommendation
98
+ if (!$recommendation) {
99
+ return array();
100
+ }
101
+ return $this->collector($recommendation, $storeId, $originalItems)->collect();
102
+ }
103
+
104
+ /**
105
+ * Builds a recommendation collector based on the parameters
106
+ *
107
+ * @param Bronto_Product_Model_Recommendation $recommendation
108
+ * @param int $storeId
109
+ * @param mixed $originalItems
110
+ * @return Bronto_Product_Model_Collect
111
+ */
112
+ public function collector(Bronto_Product_Model_Recommendation $recommendation, $storeId = null, $originalItems = array())
113
+ {
114
+ return Mage::getModel('bronto_product/collect')
115
+ ->setRecommendation($recommendation)
116
+ ->setOriginalHash($this->itemsToProductHash($originalItems))
117
+ ->setStoreId($storeId);
118
+ }
119
+
120
+ /**
121
+ * Creates a Product Hash table from an item collection or a product array
122
+ *
123
+ * @param mixed $items
124
+ * @return array
125
+ */
126
+ public function itemsToProductHash($items)
127
+ {
128
+ $hash = array();
129
+ foreach ($items as $item) {
130
+ if (is_numeric($item)) {
131
+ $item = Mage::getModel('catalog/product')->load($item);
132
+ }
133
+ if ($item->getParentItem()) {
134
+ continue;
135
+ }
136
+ if (!$item instanceof Mage_Catalog_Model_Product) {
137
+ if (array_key_exists($item->getProductId(), $hash)) {
138
+ continue;
139
+ }
140
+ $product = $item->getProduct();
141
+ if (!$product) {
142
+ $product = Mage::getModel('catalog/product')->load($item->getProductId());
143
+ }
144
+ } else {
145
+ $product = $item;
146
+ }
147
+ $hash[$product->getId()] = $product;
148
+ }
149
+ return $hash;
150
+ }
151
+
152
+ /**
153
+ * Gathers the currency setting and options for the store in question
154
+ *
155
+ * @param int $storeId (Optional)
156
+ * @return Tuple array($baseCurrency, $currency, $options)
157
+ */
158
+ public function currencyAndOptions($storeId = null)
159
+ {
160
+ $store = Mage::app()->getStore($storeId);
161
+ $baseCurrencyCode = Mage::app()->getStore()->getBaseCurrencyCode();
162
+ $currencyCode = $store->getDefaultCurrencyCode();
163
+ $baseCurrency = Mage::getModel('directory/currency')->load($baseCurrencyCode);
164
+ $currency = Mage::getModel('directory/currency')->load($currencyCode);
165
+ $options = array(
166
+ 'precision' => 2,
167
+ 'display' => Zend_Currency::NO_SYMBOL,
168
+ );
169
+ if ($this->useCurrencySymbol($storeId)) {
170
+ unset($options['display']);
171
+ }
172
+ return array($baseCurrency, $currency, $options);
173
+ }
174
+
175
+ /**
176
+ * Convenience method for collecting related products and
177
+ * setting bronto delivery fields for a given cart
178
+ *
179
+ * @param Bronto_Product_Model_Recommendation $recommendation
180
+ * @param mixed $items
181
+ * @param Bronto_Api_Delivery_Row $delivery
182
+ * @param int $storeId
183
+ * @return void
184
+ */
185
+ public function collectAndSetFields($recommendation, $items, $delivery, $storeId)
186
+ {
187
+ $this->setRelatedFields(
188
+ $delivery,
189
+ $this->collectRecommendations($recommendation, $storeId, $items),
190
+ $storeId);
191
+ }
192
+
193
+ /**
194
+ * Utility for truncating string to a certain limit, split by words
195
+ *
196
+ * @param string $string
197
+ * @param int $limit
198
+ * @return string
199
+ */
200
+ public function truncateText($string, $limit)
201
+ {
202
+ if (strlen($string) > $limit) {
203
+ $words = preg_split('/\s+/', $string);
204
+ $ret = '';
205
+ $size = 0;
206
+ foreach ($words as $word) {
207
+ $wordlen = strlen($word) + 1;
208
+ if (($wordlen + $size) > $limit - 3) {
209
+ break;
210
+ }
211
+ $ret .= "$word ";
212
+ $size += $wordlen;
213
+ }
214
+ return $ret . '...';
215
+ }
216
+ return $string;
217
+ }
218
+
219
+ /**
220
+ * Creates the fields to process by products and store
221
+ *
222
+ * @param array $productIds
223
+ * @param int $storeId (Optional)
224
+ * @return array
225
+ */
226
+ public function relatedFields($productIds, $storeId = null)
227
+ {
228
+ $fieldsByIndex = array();
229
+ list($base, $currency, $options) = $this->currencyAndOptions($storeId);
230
+ $attr = $this->getDescriptionAttr('store', $storeId);
231
+ $limit = $this->getCharLimit('store', $storeId);
232
+ foreach ($productIds as $key => $productId) {
233
+ $index = $key + 1;
234
+
235
+ /** @var Mage_Catalog_Model_Product $relatedProduct */
236
+ $relatedProduct = Mage::getModel('catalog/product')
237
+ ->setStore($storeId)
238
+ ->load($productId);
239
+
240
+ $price = $relatedProduct->getPrice();
241
+ // Only convert the price if the current price is different from the display
242
+ if ($base != $currency) {
243
+ $price = $base->convert($price, $currency);
244
+ }
245
+ $imageUrl = $this->getProductImageUrl($relatedProduct);
246
+ $fields = array(
247
+ array(
248
+ "name" => "relatedName_{$index}",
249
+ "content" => $relatedProduct->getName(),
250
+ "type" => "html"
251
+ ),
252
+ array(
253
+ "name" => "relatedPrice_{$index}",
254
+ "content" => $currency->formatTxt($price, $options),
255
+ "type" => 'html',
256
+ ),
257
+ array(
258
+ "name" => "relatedDescription_{$index}",
259
+ "content" => $this->truncateText($relatedProduct->getData($attr), $limit),
260
+ "type" => 'html',
261
+ ),
262
+ array(
263
+ "name" => "relatedSku_{$index}",
264
+ "content" => $relatedProduct->getSku(),
265
+ 'type' => 'html',
266
+ ),
267
+ array(
268
+ "name" => "relatedUrl_{$index}",
269
+ "content" => Mage::helper('bronto_common/product')->getProductAttribute($relatedProduct, 'url', $storeId),
270
+ "type" => 'html',
271
+ ),
272
+ array(
273
+ "name" => "relatedImgUrl_{$index}",
274
+ "content" => $imageUrl,
275
+ 'type' => 'html'
276
+ )
277
+ );
278
+ $fieldsByIndex[] = $fields;
279
+ }
280
+ return $fieldsByIndex;
281
+ }
282
+
283
+ /**
284
+ * Sets an array of products, representing related products
285
+ * in a delivery as relatedXxx_# API fields
286
+ *
287
+ * @param Bronto_Api_Delivery_Row $delivery
288
+ * @param array $productIds
289
+ * @param int $storeId
290
+ * @return void
291
+ */
292
+ public function setRelatedFields($delivery, $productIds, $storeId = null)
293
+ {
294
+ $currentData = $delivery->getData();
295
+ if (empty($currentData['fields'])) {
296
+ $currentData['fields'] = array();
297
+ }
298
+ foreach ($this->relatedFields($productIds, $storeId) as $fields) {
299
+ $currentData['fields'] = array_merge($currentData['fields'], $fields);
300
+ }
301
+ // By passing the setField call on the API is far more efficient
302
+ $delivery->setData($currentData);
303
+ }
304
+
305
+ /**
306
+ * Process tag content dynamic data
307
+ *
308
+ * @param Bronto_Product_Model_Recommendation $rec
309
+ * @param int $storeId
310
+ * @return array
311
+ */
312
+ public function processTagContent($rec, $storeId = null)
313
+ {
314
+ $productIds = $this->collectRecommendations($rec, $storeId);
315
+ $fields = $this->relatedFields($productIds, $storeId);
316
+ return $rec->processContent($fields);
317
+ }
318
+
319
+ /**
320
+ * Gets an API Content Tag for the product rec
321
+ *
322
+ * @param Bronto_Api_Content_Tag
323
+ * @param Bronto_Product_Model_Recommendation
324
+ * @return Bronto_Api_Content_Tag_Row
325
+ */
326
+ public function getContentTagForRecommendation($tagObject, $rec)
327
+ {
328
+ $filter = array(
329
+ 'type' => 'OR',
330
+ 'name' => array(
331
+ 'value' => $rec->getName(),
332
+ 'operator' => 'EqualTo',
333
+ )
334
+ );
335
+ if ($rec->hasTagId()) {
336
+ $filter['id'] = array($rec->getTagId());
337
+ }
338
+ $tags = $tagObject->readAll($filter, false);
339
+ $tag = $tags->current();
340
+ if (count($tags) > 1) {
341
+ Mage::throwException("Unable to find unique tag for {$rec->getName()}.");
342
+ } else if (!$tag) {
343
+ $tag = $tagObject->createRow();
344
+ $tag->name = $rec->getName();
345
+ }
346
+ return $tag;
347
+ }
348
+ }
app/code/community/Bronto/Product/Model/Collect.php ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Model_Collect extends Bronto_Product_Model_Collect_Abstract
4
+ {
5
+ private $_currentCount = 0;
6
+
7
+ /**
8
+ * Creates a method using the given source
9
+ *
10
+ * @param string $source
11
+ * @return Bronto_Product_Model_Collect_Abstract
12
+ */
13
+ protected function _method($source)
14
+ {
15
+ return Mage::getModel("bronto_product/collect_$source");
16
+ }
17
+
18
+ /**
19
+ * Invokes the source method for filling the product info
20
+ *
21
+ * @param string $target
22
+ * @param string $source
23
+ * @param $product (Optional)
24
+ * @return void
25
+ */
26
+ protected function _invokeSource($target, $source, $product = null)
27
+ {
28
+ if (!empty($source)) {
29
+ $method = $this->_method($source);
30
+ if ($method) {
31
+ Mage::helper('bronto_product')->writeDebug("Invoking {$source} on collection of {$this->_recommendation->getName()} on store {$this->getStoreId()}");
32
+ $productIds = $method
33
+ ->setStoreId($this->getStoreId())
34
+ ->setRecommendation($this->_recommendation)
35
+ ->setOriginalHash($this->_hash + $this->_products)
36
+ ->setProduct($product)
37
+ ->setSource($target)
38
+ ->setRemainingCount($this->getRemainingCount())
39
+ ->collect();
40
+
41
+ $this->_fillProducts($productIds);
42
+ }
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Performs the scan for associated products
48
+ *
49
+ * @return array
50
+ */
51
+ public function collect()
52
+ {
53
+ if (is_null($this->_recommendation)) {
54
+ Mage::throwException('Product Recommendation is required for collecting recommended products');
55
+ }
56
+
57
+ foreach ($this->_recommendation->getSources() as $source => $method) {
58
+ if ($this->_recommendation->isProductRelated($source)) {
59
+ if (is_null($this->_hash)) {
60
+ Mage::helper('bronto_product')->writeInfo('originalHash cannot be null for a product related source. Skipping');
61
+ continue;
62
+ }
63
+ foreach ($this->_hash as $productId => $product) {
64
+ if ($this->isReachedMax()) {
65
+ break;
66
+ }
67
+ $this->_invokeSource($source, $method, $product);
68
+ }
69
+ } else {
70
+ $this->_invokeSource($source, $method);
71
+ }
72
+ }
73
+ return array_keys($this->_products);
74
+ }
75
+ }
app/code/community/Bronto/Product/Model/Collect/Abstract.php ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ abstract class Bronto_Product_Model_Collect_Abstract {
4
+ protected $_products = array();
5
+ protected $_hash;
6
+ protected $_storeId;
7
+ protected $_recommendation;
8
+ protected $_remainingCount;
9
+
10
+ protected $_source;
11
+ protected $_product = null;
12
+
13
+ /**
14
+ * Implementors override this specialized collection method
15
+ *
16
+ * @return array
17
+ */
18
+ public abstract function collect();
19
+
20
+ /**
21
+ * Tells the factory that an associated product is required
22
+ *
23
+ * @return bool
24
+ */
25
+ public function isProductRelated()
26
+ {
27
+ return false;
28
+ }
29
+
30
+ /**
31
+ * Tells the factory that an associated source is required
32
+ *
33
+ * @return bool
34
+ */
35
+ public function isSourceRequired()
36
+ {
37
+ return false;
38
+ }
39
+
40
+ /**
41
+ * Returns the computed recommendations for this collector
42
+ *
43
+ * @return array
44
+ */
45
+ public function getProducts()
46
+ {
47
+ if (!$this->isReachedMax()) {
48
+ return $this->collect();
49
+ }
50
+ return array_keys($this->_products);
51
+ }
52
+
53
+ /**
54
+ * Determines if this collector has filled up
55
+ *
56
+ * @return bool
57
+ */
58
+ public function isReachedMax()
59
+ {
60
+ return $this->getRemainingCount() <= 0;
61
+ }
62
+
63
+ /**
64
+ * Sets the Product recommendation to gather related products
65
+ *
66
+ * @param Bronto_Product_Model_Recommendation $rec
67
+ * @return Bronto_Product_Model_Collect_Abstract
68
+ */
69
+ public function setRecommendation(Bronto_Product_Model_Recommendation $rec)
70
+ {
71
+ $this->_recommendation = $rec;
72
+ return $this;
73
+ }
74
+
75
+ /**
76
+ * Sets the original hash to be used to dedupe the collection
77
+ *
78
+ * @param array $originalHash
79
+ * @return Bronto_Product_Model_Collect_Abstract
80
+ */
81
+ public function setOriginalHash($originalHash)
82
+ {
83
+ $this->_hash = $originalHash;
84
+ return $this;
85
+ }
86
+
87
+ /**
88
+ * Sets the store Id for processing
89
+ *
90
+ * @param mixed $storeId
91
+ * @return Bronto_Product_Model_Collect_Abstract
92
+ */
93
+ public function setStoreId($storeId)
94
+ {
95
+ $this->_storeId = $storeId;
96
+ return $this;
97
+ }
98
+
99
+ /**
100
+ * Gets the current number of recommendations
101
+ *
102
+ * @return int
103
+ */
104
+ public function getRemainingCount()
105
+ {
106
+ if (is_null($this->_remainingCount)) {
107
+ $this->_remainingCount = $this->_recommendation->getNumberOfItems();
108
+ }
109
+ return $this->_remainingCount;
110
+ }
111
+
112
+ /**
113
+ * Adjusts the remaining count
114
+ *
115
+ * @param int $remainingCount
116
+ * @return Bronto_Product_Model_Collect_Abstract
117
+ */
118
+ public function setRemainingCount($remainingCount)
119
+ {
120
+ $this->_remainingCount = $remainingCount;
121
+ return $this;
122
+ }
123
+
124
+ /**
125
+ * Sets the product for a related product collector
126
+ *
127
+ * @param Mage_Catalog_Model_Product $product
128
+ * @return Bronto_Product_Model_Collect_Abstract
129
+ */
130
+ public function setProduct($product = null)
131
+ {
132
+ $this->_product = $product;
133
+ return $this;
134
+ }
135
+
136
+ /**
137
+ * Sets the source for a source required collector
138
+ *
139
+ * @param string $source
140
+ * @return Bronto_Product_Model_Collect_Abstract
141
+ */
142
+ public function setSource($source)
143
+ {
144
+ $this->_source = $source;
145
+ return $this;
146
+ }
147
+
148
+ /**
149
+ * Gets the store id
150
+ *
151
+ * @return int
152
+ */
153
+ public function getStoreId()
154
+ {
155
+ return $this->_storeId;
156
+ }
157
+
158
+ /**
159
+ * Fills the products from the collection, only returning those added
160
+ *
161
+ * @param mixed $productsOrIds
162
+ * @return array
163
+ */
164
+ protected function _fillProducts($productsOrIds)
165
+ {
166
+ $products = array();
167
+ foreach ($productsOrIds as $productOrId) {
168
+ if ($this->isReachedMax()) {
169
+ break;
170
+ }
171
+ if ($productOrId instanceof Mage_Catalog_Model_Product) {
172
+ $productId = $productOrId->getId();
173
+ } else if ($productOrId instanceof Mage_Reports_Model_Event) {
174
+ $productId = $productOrId->getObjectId();
175
+ } else {
176
+ $productId = $productOrId;
177
+ }
178
+ if (!$this->_isValidProduct($productId)) {
179
+ continue;
180
+ }
181
+ $this->_products[$productId] = 1;
182
+ $this->_remainingCount--;
183
+ $products[] = $productId;
184
+ }
185
+ return $products;
186
+ }
187
+
188
+ /**
189
+ * Tests if this product can be added to the pool
190
+ *
191
+ * @param string $productId
192
+ * @return bool
193
+ */
194
+ protected function _isValidProduct($productId)
195
+ {
196
+ if (array_key_exists($productId, $this->_hash)) {
197
+ return false;
198
+ }
199
+ if (array_key_exists($productId, $this->_products)) {
200
+ return false;
201
+ }
202
+ return true;
203
+ }
204
+ }
app/code/community/Bronto/Product/Model/Collect/Bestseller.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Model_Collect_Bestseller extends Bronto_Product_Model_Collect_Abstract
4
+ {
5
+ /**
6
+ * @see parent
7
+ */
8
+ public function collect()
9
+ {
10
+ $bestSellers = Mage::getResourceModel('reports/product_collection')
11
+ ->addOrderedQty()
12
+ ->setStoreId($this->getStoreId())
13
+ ->addStoreFilter($this->getStoreId())
14
+ ->setOrder('ordered_qty', 'desc')
15
+ ->addIdFilter(array_keys($this->_hash), true)
16
+ ->setPageSize($this->getRemainingCount());
17
+
18
+ Mage::getSingleton('catalog/product_status')->addVisibleFilterToCollection($bestSellers);
19
+ Mage::getSingleton('catalog/product_visibility')->addVisibleInCatalogFilterToCollection($bestSellers);
20
+ Mage::getModel('cataloginventory/stock')->addInStockFilterToCollection($bestSellers);
21
+
22
+ return $this->_fillProducts($bestSellers);
23
+ }
24
+ }
app/code/community/Bronto/Product/Model/Collect/Crosssell.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Model_Collect_Crosssell extends Bronto_Product_Model_Collect_Abstract
4
+ {
5
+ /**
6
+ * @see parent
7
+ */
8
+ public function isProductRelated()
9
+ {
10
+ return true;
11
+ }
12
+
13
+ /**
14
+ * @see parent
15
+ */
16
+ public function collect()
17
+ {
18
+ $cross = $this->_product->getCrossSellProductCollection();
19
+ Mage::getModel('cataloginventory/stock')->addInStockFilterToCollection($cross);
20
+ return $this->_fillProducts($cross);
21
+ }
22
+ }
app/code/community/Bronto/Product/Model/Collect/Custom.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Model_Collect_Custom extends Bronto_Product_Model_Collect_Abstract
4
+ {
5
+ /**
6
+ * @see parent
7
+ */
8
+ public function collect()
9
+ {
10
+ $productIds = $this->_recommendation->getCustomProductIds($this->_source);
11
+ if (empty($productIds)) {
12
+ return array();
13
+ }
14
+ $custom = Mage::getModel('catalog/product')->getCollection()
15
+ ->addFieldToFilter('entity_id', array('id' => $productIds));
16
+ Mage::getModel('cataloginventory/stock')->addInStockFilterToCollection($custom);
17
+ return $this->_fillProducts($custom);
18
+ }
19
+ }
app/code/community/Bronto/Product/Model/Collect/Mostviewed.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Model_Collect_Mostviewed extends Bronto_Product_Model_Collect_Abstract
4
+ {
5
+ const DAYS_THRESHOLD = '30';
6
+
7
+ /**
8
+ * @see parent
9
+ */
10
+ public function collect()
11
+ {
12
+ $mostViewed = Mage::getResourceModel('reports/product_viewed_collection')
13
+ ->addStoreFilter($this->getStoreId())
14
+ ->setPageSize($this->getRemainingCount())
15
+ ->addViewsCount(date('Y-m-d', strtotime('-' . self::DAYS_THRESHOLD . ' days')), date('Y-m-d'));
16
+
17
+ // Add Status and visibility filters
18
+ Mage::getSingleton('catalog/product_status')->addVisibleFilterToCollection($mostViewed);
19
+ Mage::getSingleton('catalog/product_visibility')->addVisibleInCatalogFilterToCollection($mostViewed);
20
+ Mage::getModel('cataloginventory/stock')->addInStockFilterToCollection($mostViewed);
21
+ return $this->_fillProducts($mostViewed);
22
+ }
23
+ }
app/code/community/Bronto/Product/Model/Collect/New.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Model_Collect_New extends Bronto_Product_Model_Collect_Abstract
4
+ {
5
+ /**
6
+ * @see parent
7
+ */
8
+ public function collect()
9
+ {
10
+ $todayDate = Mage::app()->getLocale()->date()->toString(Varien_Date::DATETIME_INTERNAL_FORMAT);
11
+ $newProducts = Mage::getResourceModel('catalog/product_collection')
12
+ ->addStoreFilter($this->getStoreId())
13
+ ->addAttributeToFilter('news_from_date', array('or'=> array(
14
+ 0 => array('date' => true, 'to' => $todayDate),
15
+ 1 => array('is' => new Zend_Db_Expr('null')))
16
+ ), 'left')
17
+ ->addAttributeToFilter('news_to_date', array('or'=> array(
18
+ 0 => array('date' => true, 'from' => $todayDate),
19
+ 1 => array('is' => new Zend_Db_Expr('null')))
20
+ ), 'left')
21
+ ->addAttributeToFilter(
22
+ array(
23
+ array('attribute' => 'news_from_date', 'is'=>new Zend_Db_Expr('not null')),
24
+ array('attribute' => 'news_to_date', 'is'=>new Zend_Db_Expr('not null'))
25
+ )
26
+ )
27
+ ->addAttributeToSort('news_from_date', 'desc')
28
+ ->setPageSize($this->getRemainingCount());
29
+
30
+ Mage::getSingleton('catalog/product_status')->addVisibleFilterToCollection($newProducts);
31
+ Mage::getSingleton('catalog/product_visibility')->addVisibleInCatalogFilterToCollection($newProducts);
32
+ Mage::getModel('cataloginventory/stock')->addInStockFilterToCollection($newProducts);
33
+ return $this->_fillProducts($newProducts);
34
+ }
35
+ }
app/code/community/Bronto/Product/Model/Collect/Recentlyviewed.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Model_Collect_Recentlyviewed extends Bronto_Product_Model_Collect_Abstract
4
+ {
5
+ /**
6
+ * @see parent
7
+ */
8
+ public function collect()
9
+ {
10
+ // It's possible that we don't have a customer
11
+ $customer = $this->_recommendation->getCustomer();
12
+ if (!$customer) {
13
+ return array();
14
+ }
15
+ return $this->_fillProducts(Mage::getModel('reports/event')
16
+ ->getCollection()
17
+ ->addStoreFilter(array($this->getStoreId()))
18
+ ->addRecentlyFiler(Mage_Reports_Model_Event::EVENT_PRODUCT_VIEW, $customer->getId())
19
+ ->addOrder('logged_at', 'desc')
20
+ ->setPageSize($this->getRemainingCount()));
21
+ }
22
+ }
app/code/community/Bronto/Product/Model/Collect/Related.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Model_Collect_Related extends Bronto_Product_Model_Collect_Abstract
4
+ {
5
+ /**
6
+ * @see parent
7
+ */
8
+ public function isProductRelated()
9
+ {
10
+ return true;
11
+ }
12
+
13
+ /**
14
+ * @see parent
15
+ */
16
+ public function collect()
17
+ {
18
+ $related = $this->_product->getRelatedProductCollection();
19
+ Mage::getModel('cataloginventory/stock')->addInStockFilterToCollection($related);
20
+ return $this->_fillProducts($related);
21
+ }
22
+ }
app/code/community/Bronto/Product/Model/Collect/Upsell.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Model_Collect_Upsell extends Bronto_Product_Model_Collect_Abstract
4
+ {
5
+ /**
6
+ * @see parent
7
+ */
8
+ public function isProductRelated()
9
+ {
10
+ return true;
11
+ }
12
+
13
+ /**
14
+ * @see parent
15
+ */
16
+ public function collect()
17
+ {
18
+ $upsell = $this->_product->getUpSellProductCollection();
19
+ Mage::getModel('cataloginventory/stock')->addInStockFilterToCollection($related);
20
+ return $this->_fillProducts($upsell);
21
+ }
22
+ }
app/code/community/Bronto/Product/Model/Content.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Model_Content
4
+ {
5
+ protected $_options;
6
+
7
+ /**
8
+ * Gets the sources for the content types
9
+ *
10
+ * @return array
11
+ */
12
+ public function toOptionArray()
13
+ {
14
+ if (!is_null($this->_options)) {
15
+ return $this->_options;
16
+ }
17
+
18
+ $helper = Mage::helper('bronto_product');
19
+ $this->_options = array(
20
+ 'api' => $helper->__('Email Based'),
21
+ 'content_tag' => $helper->__('Content Tag'),
22
+ );
23
+ return $this->_options;
24
+ }
25
+ }
app/code/community/Bronto/Product/Model/Filter.php ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Model_Filter
4
+ {
5
+ protected $_content = '';
6
+ protected $_fields = array();
7
+
8
+ /**
9
+ * Set the original content
10
+ *
11
+ * @param string $content
12
+ * @return Bronto_Product_Model_Filter
13
+ */
14
+ public function setContent($content)
15
+ {
16
+ $this->_content = $content;
17
+ return $this;
18
+ }
19
+
20
+ /**
21
+ * Set the related fields for this filter
22
+ *
23
+ * @param array $fields
24
+ * @return Bronto_Product_Model_Filter
25
+ */
26
+ public function setFields($fields)
27
+ {
28
+ $this->_fields = $fields;
29
+ return $this;
30
+ }
31
+
32
+ /**
33
+ * Process the related api tags for this content
34
+ *
35
+ * @return string
36
+ */
37
+ public function process()
38
+ {
39
+ list($content, $blocks) = $this->gatherDynamicBlocks($this->_content);
40
+ foreach ($blocks as $key => $block) {
41
+ $content = str_replace($key, $this->processBlock($block), $content);
42
+ }
43
+ return $content;
44
+ }
45
+
46
+ /**
47
+ * Splits the given content into blocks
48
+ *
49
+ * @param string $content
50
+ * @return tuple (string, array)
51
+ */
52
+ protected function gatherDynamicBlocks($content)
53
+ {
54
+ $blocks = array();
55
+ $pattern = '|\{dynamic_code\}\s*\{[^/]+\}\s*(.+?)\{/.+?\}\s*\{/dynamic_code\}|s';
56
+ if (preg_match_all($pattern, $content, $matches)) {
57
+ $blockIndex = 0;
58
+ foreach ($matches[0] as $match) {
59
+ $content = str_replace($match, "block_{$blockIndex}_", $content);
60
+ $blockIndex++;
61
+ }
62
+ $blockIndex = 0;
63
+ foreach ($matches[1] as $match) {
64
+ $blocks["block_{$blockIndex}_"] = $match;
65
+ $blockIndex++;
66
+ }
67
+ }
68
+ return array($content, $blocks);
69
+ }
70
+
71
+ /**
72
+ * Transforms the dynamic block with the related content
73
+ *
74
+ * @param string $block
75
+ * @return string
76
+ */
77
+ protected function processBlock($block)
78
+ {
79
+ $content = '';
80
+ foreach ($this->_fields as $key => $fields) {
81
+ $index = $key + 1;
82
+ $currentBlock = $block;
83
+ foreach ($fields as $field) {
84
+ list($name, $num) = explode('_', $field['name']);
85
+ $currentBlock = preg_replace("/%%#{$name}_#%%/", $field['content'], $currentBlock);
86
+ }
87
+ $content .= $currentBlock;
88
+ }
89
+ if (empty($content)) {
90
+ $content = $block;
91
+ }
92
+ // Close the loop
93
+ $content = preg_replace("/%%#.+?_#%%/", '', $content);
94
+ return $content;
95
+ }
96
+ }
app/code/community/Bronto/Product/Model/Mysql4/Recommendation.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Model_Mysql4_Recommendation extends Mage_Core_Model_Mysql4_Abstract
4
+ {
5
+ /**
6
+ * @see parent
7
+ */
8
+ public function _construct()
9
+ {
10
+ $this->_init('bronto_product/recommendation', 'entity_id');
11
+ }
12
+ }
app/code/community/Bronto/Product/Model/Mysql4/Recommendation/Collection.php ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Model_Mysql4_Recommendation_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
4
+ {
5
+ /**
6
+ * @see parent
7
+ */
8
+ public function _construct()
9
+ {
10
+ parent::_construct();
11
+ $this->_init('bronto_product/recommendation');
12
+ }
13
+
14
+ /**
15
+ * Filters recommendations that can be sent in emails
16
+ *
17
+ * @return Bronto_Product_Model_Mysql4_Recommendation_Collection
18
+ */
19
+ public function onlyEmailBased()
20
+ {
21
+ return $this->addFieldToFilter('content_type', array('eq' => 'api'));
22
+ }
23
+
24
+ /**
25
+ * Filters recommendations that can be used to update content tags
26
+ *
27
+ * @return Bronto_Product_Model_Mysql4_Recommendation_Collection
28
+ */
29
+ public function onlyContentTagBased()
30
+ {
31
+ return $this->addFieldToFilter('content_type', array('eq' => 'content_tag'));
32
+ }
33
+
34
+ /**
35
+ * Filters recommendations that can be used for this store only
36
+ *
37
+ * @param int $storeId
38
+ * @return Bronto_Product_Model_Mysql4_Recommendation_Collection
39
+ */
40
+ public function addStoreToFilter($storeId = 1)
41
+ {
42
+ return $this->addFieldToFilter('store_id', array('eq' => $storeId));
43
+ }
44
+
45
+ /**
46
+ * Filters a store on a particular scope with the admin scope included
47
+ *
48
+ * @param int $storeId
49
+ * @return Bronto_Product_Model_Mysql4_Recommendation_Collection
50
+ */
51
+ public function addAnyStoreFilter($storeId)
52
+ {
53
+ if ($storeId != 0) {
54
+ return $this->addFieldToFilter('store_id', array('in' => array(0, $storeId)));
55
+ }
56
+ return $this;
57
+ }
58
+
59
+ /**
60
+ * Filters the recommendations by a given name
61
+ *
62
+ * @param string $name
63
+ * @return Bronto_Product_Model_Mysql4_Recommendation_Collection
64
+ */
65
+ public function addNameToFilter($name)
66
+ {
67
+ return $this->addFieldToFilter('name', array('eq' => $name));
68
+ }
69
+
70
+ /**
71
+ * Filters the recommendations by ending with a certain name
72
+ *
73
+ * @param string $name
74
+ * @return Bronto_Product_Model_Mysql4_Recommendation_Collection
75
+ */
76
+ public function nameEndsWith($name)
77
+ {
78
+ return $this->addFieldToFilter('name', array('like' => "%$name"));
79
+ }
80
+
81
+ /**
82
+ * Orders the recommendations by name, in specified direction
83
+ *
84
+ * @param string $dir
85
+ * @return Bronto_Product_Model_Mysql4_Recommendation_Collection
86
+ */
87
+ public function orderAlphebetically($dir = 'asc')
88
+ {
89
+ return $this->addOrder('name', $dir);
90
+ }
91
+ }
app/code/community/Bronto/Product/Model/Observer.php ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Model_Observer
4
+ {
5
+ /**
6
+ * Cron job to process all content tags for the product recommendations
7
+ */
8
+ public function processContentTags()
9
+ {
10
+ $results = array(
11
+ 'total' => 0,
12
+ 'success' => 0,
13
+ 'error' => 0
14
+ );
15
+ $stores = Mage::app()->getStores(true);
16
+ foreach ($stores as $store) {
17
+ $storeResults = $this->processContentTagsForStore($store);
18
+ $results['total'] += $storeResults['total'];
19
+ $results['success'] += $storeResults['success'];
20
+ $results['error'] += $storeResults['error'];
21
+ }
22
+ return $results;
23
+ }
24
+
25
+ /**
26
+ * Process the content tags for a given scope
27
+ *
28
+ * @return array
29
+ */
30
+ public function processContentTagsForScope()
31
+ {
32
+ $scopeParams = Mage::helper('bronto_product')->getScopeParams();
33
+ if ($scopeParams['store']) {
34
+ return $this->processContentTagsForStore($scopeParams['store_id']);
35
+ } else if ($scopeParams['website']) {
36
+ return $this->processContentTagsForSite($scopeParams['website_id']);
37
+ } else {
38
+ return $this->processContentTags();
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Process the content tags for a given website
44
+ *
45
+ * @param int $websiteId
46
+ * @return array
47
+ */
48
+ public function processContentTagsForSite($websiteId)
49
+ {
50
+ $results = array(
51
+ 'total' => 0,
52
+ 'success' => 0,
53
+ 'error' => 0,
54
+ );
55
+
56
+ $website = Mage::app()->getWebsite($websiteId);
57
+ foreach ($website->getStores() as $store) {
58
+ foreach ($this->processContentTagsForStore($store) as $k => $v) {
59
+ $results[$k] += $v;
60
+ }
61
+ }
62
+ return $results;
63
+ }
64
+
65
+ /**
66
+ * Process content tags for a single store view
67
+ *
68
+ * @param mixed $storeOrId
69
+ * @return array
70
+ */
71
+ public function processContentTagsForStore($storeOrId)
72
+ {
73
+ $results = array(
74
+ 'total' => 0,
75
+ 'success' => 0,
76
+ 'error' => 0,
77
+ );
78
+
79
+ $helper = Mage::helper('bronto_product');
80
+ $store = $storeOrId;
81
+ if (is_numeric($storeOrId)) {
82
+ $store = Mage::app()->getStore($storeOrId);
83
+ }
84
+
85
+ $recTags = Mage::getModel('bronto_product/recommendation')
86
+ ->getCollection()
87
+ ->onlyContentTagBased()
88
+ ->addStoreToFilter($store->getId());
89
+
90
+ // Cron or no cron... it must be enabled
91
+ if (!$helper->isEnabled('store', $store->getId())) {
92
+ continue;
93
+ }
94
+
95
+ $api = $helper->getApi(null, 'store', $store->getId());
96
+ $tagObject = $api->getContentTagObject();
97
+ foreach ($recTags as $recTag) {
98
+ $results['total']++;
99
+ try {
100
+ $tag = $helper->getContentTagForRecommendation($tagObject, $recTag);
101
+ $tag->value = $helper->processTagContent($recTag, $store->getId());
102
+ $tag->save();
103
+ $recTag
104
+ ->setTagId($tag->id)
105
+ ->save();
106
+ $results['success']++;
107
+ } catch (Exception $e) {
108
+ $message = $e->getMessage();
109
+ if ($e->getCode() == 1604) {
110
+ $message = 'Message content appears to be formatted incorrectly. Make sure the API tags are surrounded by {dynamic_code}{loop} blocks.';
111
+ }
112
+ $helper->writeError("Unable to save content tag for {$recTag->getName()} in store {$store->getId()}: {$message}");
113
+ $results['error']++;
114
+ }
115
+ }
116
+
117
+ return $results;
118
+ }
119
+ }
app/code/community/Bronto/Product/Model/Recommendation.php ADDED
@@ -0,0 +1,225 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Model_Recommendation extends Mage_Core_Model_Abstract
4
+ {
5
+ const SOURCE_RELATED_PRODUCT = 'related';
6
+ const SOURCE_UPSELL_PRODUCT = 'upsell';
7
+ const SOURCE_CROSSSELL_PRODUCT = 'crosssell';
8
+ const SOURCE_BESTSELLER = 'bestseller';
9
+ const SOURCE_MOST_VIEWED = 'mostviewed';
10
+ const SOURCE_RECENTLY_VIEWED = 'recentlyviewed';
11
+ const SOURCE_CUSTOM = 'custom';
12
+ const SOURCE_NEW_PRODUCT = 'new';
13
+
14
+ const SOURCE_PRIMARY = 'primary';
15
+ const SOURCE_SECONDARY = 'secondary';
16
+ const SOURCE_FALLBACK = 'fallback';
17
+
18
+ const TYPE_API = 'api';
19
+ const TYPE_CONTENT_TAG = 'content_tag';
20
+
21
+ /**
22
+ * Local caches of the product ids in the targetted sources
23
+ * @var array
24
+ */
25
+ private $_customSources;
26
+ private $_sources;
27
+ private $_customer;
28
+
29
+ /**
30
+ * @see parent
31
+ */
32
+ protected function _construct()
33
+ {
34
+ parent::_construct();
35
+ $this->_init('bronto_product/recommendation');
36
+ }
37
+
38
+ /**
39
+ * Is this a content tag type of recommendation?
40
+ *
41
+ * @return bool
42
+ */
43
+ public function isContentTag()
44
+ {
45
+ return $this->getContentType() == self::TYPE_CONTENT_TAG;
46
+ }
47
+
48
+ /**
49
+ * Is this content dynamic?
50
+ *
51
+ * @return bool
52
+ */
53
+ public function isDynamicContent()
54
+ {
55
+ return $this->isContentTag() &&
56
+ preg_match('/\{\s*dynamic_code\s*\}/', $this->getTagContent());
57
+ }
58
+
59
+ /**
60
+ * Geta an array of Product Ids defined by the user
61
+ *
62
+ * @param string $source
63
+ * @return array
64
+ */
65
+ public function getCustomProductIds($source)
66
+ {
67
+ if (is_null($this->_customSources)) {
68
+ foreach ($this->getSources() as $key => $value) {
69
+ $ids = $this->getData("manual_{$key}_source");
70
+ if (empty($ids)) {
71
+ $ids = array();
72
+ } else {
73
+ $ids = preg_split('/\s*,\s*/', $ids);
74
+ }
75
+ $this->_customSources[$key] = $ids;
76
+ }
77
+ }
78
+ return $this->_customSources[$source];
79
+ }
80
+
81
+ /**
82
+ * Sets a customer for this recommendation; Required for
83
+ * Recently viewed
84
+ *
85
+ * @param Mage_Customer_Model_Customer $customer
86
+ * @return Bronto_Product_Model_Recommendation
87
+ */
88
+ public function setCustomer(Mage_Customer_Model_Customer $customer)
89
+ {
90
+ $this->_customer = $customer;
91
+ return $this;
92
+ }
93
+
94
+ /**
95
+ * Gets the associated customer for the recommendation
96
+ *
97
+ * @return Mage_Customer_Model_Customer
98
+ */
99
+ public function getCustomer()
100
+ {
101
+ return $this->_customer;
102
+ }
103
+
104
+ /**
105
+ * Tests whether this recommendation requires a customer id
106
+ *
107
+ * @param string $source (Optional)
108
+ * @return bool
109
+ */
110
+ public function isCustomerRequired($source = null)
111
+ {
112
+ if ($source) {
113
+ return $this->getData("{$source}_source") == self::SOURCE_RECENTLY_VIEWED;
114
+ } else {
115
+ foreach ($this->getSources() as $value) {
116
+ if ($value == self::SOURCE_RECENTLY_VIEWED) {
117
+ return true;
118
+ }
119
+ }
120
+ return false;
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Given delivery fields, process this content tag content
126
+ *
127
+ * @param array $fields
128
+ * @return string
129
+ */
130
+ public function processContent($fields)
131
+ {
132
+ if ($this->isDynamicContent()) {
133
+ return Mage::getModel('bronto_product/filter')
134
+ ->setContent($this->getTagContent())
135
+ ->setFields($fields)
136
+ ->process();
137
+ }
138
+ return $this->getTagContent();
139
+ }
140
+
141
+ /**
142
+ * Tests this recommendation require a specific product
143
+ *
144
+ * @param string $source (Optional)
145
+ * @return bool
146
+ */
147
+ public function isProductRelated($source = null)
148
+ {
149
+ $productRelated = array(
150
+ self::SOURCE_RELATED_PRODUCT,
151
+ self::SOURCE_UPSELL_PRODUCT,
152
+ self::SOURCE_CROSSSELL_PRODUCT);
153
+ if ($source) {
154
+ return in_array($this->getData("{$source}_source"), $productRelated);
155
+ } else {
156
+ foreach ($this->getSources() as $value) {
157
+ if (in_array($value, $productRelated)) {
158
+ return true;
159
+ }
160
+ }
161
+ return false;
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Gets the defined sources for this recommendation
167
+ *
168
+ * @return array
169
+ */
170
+ public function getSources()
171
+ {
172
+ if (is_null($this->_sources)) {
173
+ $this->_sources = array();
174
+ foreach ($this->getData() as $key => $value) {
175
+ if (preg_match('/^([^manual_].+)_source$/', $key, $matches)) {
176
+ $this->_sources[$matches[1]] = $value;
177
+ }
178
+ }
179
+ }
180
+ return $this->_sources;
181
+ }
182
+
183
+ /**
184
+ * Performs a copy of the model without an id
185
+ *
186
+ * @return Bronto_Product_Model_Recommendation
187
+ */
188
+ public function softCopy()
189
+ {
190
+ $data = $this->getData();
191
+ // Pop all static references
192
+ unset($data['entity_id'], $data['tag_id']);
193
+ $originalName = preg_replace('/Copy\s*\d* of /', '', $this->getName());
194
+ $count = $this->getCollection()
195
+ ->nameEndsWith($originalName)
196
+ ->count();
197
+ $data['name'] = sprintf("Copy %d of %s", $count, $originalName);
198
+ return Mage::getModel('bronto_product/recommendation')->setData($data);
199
+ }
200
+
201
+ /**
202
+ * The list of saved options as a menu
203
+ *
204
+ * @return array
205
+ */
206
+ public function toOptionArray($default = false)
207
+ {
208
+ $noneSelected = $default ? 'Use Default' : 'None Selected';
209
+ $helper = Mage::helper('bronto_product');
210
+ $options = array();
211
+
212
+ $recommendations = $this->getCollection()->orderAlphebetically();
213
+ foreach ($recommendations as $rec) {
214
+ $options[] = array(
215
+ 'label' => $rec->getName(),
216
+ 'value' => $rec->getId());
217
+ }
218
+
219
+ array_unshift($options, array(
220
+ 'label' => $helper->__('-- ' . $noneSelected . ' --'),
221
+ 'value' => ''
222
+ ));
223
+ return $options;
224
+ }
225
+ }
app/code/community/Bronto/Product/Model/Resource/Setup.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Model_Resource_Setup extends Bronto_Common_Model_Resource_Abstract
4
+ {
5
+ /**
6
+ * @see parent
7
+ */
8
+ protected function _module()
9
+ {
10
+ return 'bronto_product';
11
+ }
12
+
13
+ /**
14
+ * @see parent
15
+ */
16
+ protected function _tables()
17
+ {
18
+ return array(
19
+ 'recommendation' => "
20
+ CREATE TABLE `{table}` (
21
+ `entity_id` int(11) NOT NULL AUTO_INCREMENT,
22
+ `name` varchar(255) NOT NULL,
23
+ `content_type` varchar(30) NOT NULL DEFAULT 'api',
24
+ `tag_id` varchar(50) NULL,
25
+ `store_id` int(11) NOT NULL DEFAULT '1' COMMENT 'Store ID for Recommendation',
26
+ `tag_content` text NULL,
27
+ `number_of_items` smallint(2) NOT NULL DEFAULT 5,
28
+ `primary_source` varchar(20) NOT NULL DEFAULT 'related',
29
+ `secondary_source` varchar(20) NOT NULL DEFAULT 'bestseller',
30
+ `fallback_source` varchar(20) NOT NULL DEFAULT '',
31
+ `manual_primary_source` varchar(255) NULL,
32
+ `manual_secondary_source` varchar(255) NULL,
33
+ `manual_fallback_source` varchar(255) NULL,
34
+ PRIMARY KEY (`entity_id`),
35
+ KEY `IDX_BRONTO_PRODUCT_NAME` (`name`),
36
+ KEY `IDX_BRONTO_PRODUCT_STOREID` (`store_id`),
37
+ KEY `IDX_BRONTO_PRODUCT_TYPE` (`content_type`),
38
+ KEY `IDX_BRONTO_PRODUCT_PRIMARY` (`primary_source`),
39
+ KEY `IDX_BRONTO_PRODUCT_SECONDARY` (`secondary_source`),
40
+ KEY `IDX_BRONTO_PRODUCT_FALLBACK` (`fallback_source`)
41
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Bronto Product Recommentation table';"
42
+ );
43
+ }
44
+
45
+ /**
46
+ * @see parent
47
+ */
48
+ protected function _updates()
49
+ {
50
+ return array();
51
+ }
52
+ }
app/code/community/Bronto/Product/Model/System/Config/Cron.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Model_System_Config_Cron extends Bronto_Common_Model_System_Config_Backend_Cron
4
+ {
5
+ protected $_cron_string_path = 'crontab/jobs/bronto_product_parse_tag/schedule/cron_expr';
6
+ protected $_cron_model_path = 'crontab/jobs/bronto_product_parse_tag/run/model';
7
+ }
app/code/community/Bronto/Product/Model/System/Config/Source/Recommendation.php ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Model_System_Config_Source_Recommendation
4
+ {
5
+
6
+ /**
7
+ * @var array
8
+ */
9
+ protected $_options;
10
+
11
+ /**
12
+ * Related Product Sources key => value pairs
13
+ *
14
+ * @param null $isMultiselect
15
+ *
16
+ * @return array
17
+ */
18
+ public function toOptionArray($isMultiselect = null, $fallback = false)
19
+ {
20
+ if (!is_null($this->_options)) {
21
+ return $this->_options;
22
+ }
23
+
24
+ $helper = Mage::helper('bronto_common');
25
+
26
+ $productSources = array(
27
+ array('value' => 'related', 'label' => $helper->__('Related Products')),
28
+ array('value' => 'upsell', 'label' => $helper->__('Up-sells')),
29
+ array('value' => 'crosssell', 'label' => $helper->__('Cross-sells')),
30
+ );
31
+
32
+ $globalSources = array(
33
+ array('value' => 'new', 'label' => $helper->__('New Products')),
34
+ array('value' => 'bestseller', 'label' => $helper->__('Bestsellers')),
35
+ array('value' => 'mostviewed', 'label' => $helper->__('Most Viewed by last 30 days')),
36
+ );
37
+
38
+ $customerSources = array(
39
+ array('value' => 'recentlyviewed', 'label' => $helper->__('Recently Viewed')),
40
+ );
41
+
42
+ $customSources = array(
43
+ array('value' => 'custom', 'label' => $helper->__('Custom Products'))
44
+ );
45
+
46
+ $this->_options = array();
47
+ if (!$fallback) {
48
+ $this->_options[] = array('label' => $helper->__('Product Sources'), 'value' => $productSources);
49
+ }
50
+
51
+ $this->_options[] = array('label' => $helper->__('Global Sources'), 'value' => $globalSources);
52
+ $this->_options[] = array('label' => $helper->__('Customer Sources'), 'value' => $customerSources);
53
+ $this->_options[] = array('label' => $helper->__('Manual Entry'), 'value' => $customSources);
54
+
55
+ if (!$isMultiselect) {
56
+ array_unshift($this->_options, array('value' => '', 'label' => $helper->__('-- None Selected --')));
57
+ }
58
+
59
+ return $this->_options;
60
+ }
61
+ }
app/code/community/Bronto/Product/controllers/Adminhtml/RecommendationsController.php ADDED
@@ -0,0 +1,490 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Product_Adminhtml_RecommendationsController extends Mage_Adminhtml_Controller_Action
4
+ {
5
+ protected $_header = 'Product Recommendations';
6
+ protected $_module = 'bronto_product';
7
+ protected $_helper;
8
+
9
+ /**
10
+ * Gets the product helper related to this module
11
+ *
12
+ * @return Bronto_Product_Helper_Data
13
+ */
14
+ public function getHelper()
15
+ {
16
+ if (!$this->_helper) {
17
+ $this->_helper = Mage::helper($this->_module);
18
+ }
19
+ return $this->_helper;
20
+ }
21
+
22
+ /**
23
+ * Gets the block for the grid for certain things
24
+ *
25
+ * @return Mage_Adminhtml_Block_Abstract
26
+ */
27
+ public function getBlock($key)
28
+ {
29
+ return $this->getLayout()
30
+ ->createBlock("{$this->_module}/adminhtml_system_{$key}", $key);
31
+ }
32
+
33
+ /**
34
+ * Initialize module page
35
+ *
36
+ * @return Bronto_Product_Adminhtml_RecommendationsController
37
+ */
38
+ protected function _initAction()
39
+ {
40
+ $this->loadLayout()
41
+ ->_setActiveMenu('promo/bronto_product')
42
+ ->_addBreadcrumb(
43
+ $this->getHelper()->__($this->_header),
44
+ $this->getHelper()->__($this->_header)
45
+ );
46
+ return $this;
47
+ }
48
+
49
+ /**
50
+ * Initialize the modal headers for products and message sending
51
+ *
52
+ * @return Bronto_Product_Adminhtml_RecommendationsController
53
+ */
54
+ protected function _modalStyles()
55
+ {
56
+ $head = $this->getLayout()->getBlock('head');
57
+ $head->addItem('js_css', 'prototype/windows/themes/default.css');
58
+ $enabled = Mage::getSingleton('cms/wysiwyg_config')->isEnabled();
59
+ if (Mage::helper('bronto_common')->isVersionMatch(Mage::getVersionInfo(), '1', array('6', array('edition' => 'Enterprise', 'major' => '9'), '10', '11'))) {
60
+ $head->addItem('js_css', 'prototype/windows/themes/magento.css');
61
+ if ($enabled) {
62
+ $head->addItem('js_css', 'mage/adminhtml/wysiwyg/tiny_mce/setup.js');
63
+ }
64
+ } else {
65
+ $head->addCss('lib/prototype/windows/themes/magento.css');
66
+ if ($enabled) {
67
+ $head->addJs('mage/adminhtml/wysiwyg/tiny_mce/setup.js');
68
+ }
69
+ }
70
+ if ($enabled) {
71
+ $head->setCanLoadTinyMce(true);
72
+ }
73
+ return $this;
74
+ }
75
+
76
+ /**
77
+ * Instantiates and loads the given product recommendation
78
+ *
79
+ * @param string $idField
80
+ * @return Bronto_Product_Model_Recommendation
81
+ */
82
+ protected function _initRecommendation($idField = 'entity_id')
83
+ {
84
+ $this
85
+ ->_title($this->__('Promotions'))
86
+ ->_title($this->__($this->_header));
87
+
88
+ $id = (int)$this->getRequest()->getParam($idField);
89
+ $type = $this->getRequest()->getParam('type', Bronto_Product_Model_Recommendation::TYPE_API);
90
+
91
+ $model = Mage::getModel('bronto_product/recommendation')
92
+ ->setNumberOfItems(5)
93
+ ->setContentType($type)
94
+ ->load($id);
95
+
96
+ if (!Mage::registry('product_recommendation')) {
97
+ Mage::register('product_recommendation', $model);
98
+ }
99
+
100
+ if (!Mage::registry('current_product_recommendation')) {
101
+ Mage::register('current_product_recommendation', $model);
102
+ }
103
+
104
+ return $model;
105
+ }
106
+
107
+ /**
108
+ * Main grid for all product recommendations defined by the user
109
+ *
110
+ * @return Bronto_Product_Adminhtml_RecommendationsController
111
+ */
112
+ public function indexAction()
113
+ {
114
+ $this
115
+ ->_title($this->__('Promotions'))
116
+ ->_title($this->__($this->_header));
117
+ if (!$this->getHelper()->isEnabledForAny()) {
118
+ $url = $this->getUrl('*/system_config/edit', array('section' => $this->_module));
119
+ $link = '<a href="' . $url . '">' . $this->getHelper()->__('Product Recommendations') . '</a>';
120
+ Mage::getSingleton('adminhtml/session')->addNotice(
121
+ $this->getHelper()->__('This module is currently disabled. Please see System &rsaquo; Configuration &raquo; Bronto &rsaquo; ') . $link . $this->getHelper()->__(' to enable.'));
122
+ }
123
+ $this->_initAction()->_addContent($this->getBlock('recommendation'));
124
+ $this->renderLayout();
125
+ return $this;
126
+ }
127
+
128
+ /**
129
+ * Validates the model, by either setting the required fields
130
+ * or throwing exceptions
131
+ *
132
+ * @return Bronto_Product_Model_Recommendation
133
+ */
134
+ protected function _validateRecommendation($model)
135
+ {
136
+ $name = $this->getRequest()->getParam('name', null);
137
+ $content = $this->getRequest()->getParam('tag_content', null);
138
+ $storeId = $this->getRequest()->getParam('store_id', '0');
139
+ $numberOfItems = $this->getRequest()->getParam('number_of_items');
140
+ $primarySource = $this->getRequest()->getParam('primary_source');
141
+
142
+ if (empty($name)) {
143
+ throw new RuntimeException('Name cannot be empty.');
144
+ }
145
+
146
+ if (!is_numeric($numberOfItems)) {
147
+ throw new RuntimeException("Number of Items must be a number.");
148
+ }
149
+
150
+ if (empty($primarySource)) {
151
+ throw new RuntimeException("Primary Source cannot be empty.");
152
+ }
153
+
154
+ if ($model->isContentTag()) {
155
+ if (empty($content)) {
156
+ throw new RuntimeException("Content Template cannot be empty.");
157
+ }
158
+
159
+ if (is_null($storeId)) {
160
+ throw new RuntimeException("Store View cannot be empty.");
161
+ }
162
+
163
+ $other = current($model->getCollection()
164
+ ->addNameToFilter($name)
165
+ ->addAnyStoreFilter($storeId)
166
+ ->onlyContentTagBased()
167
+ ->getItems());
168
+
169
+ if ($other && $other->getId() != $model->getId()) {
170
+ throw new RuntimeException("Another content tag recommendation already exists with name $name for this store view.");
171
+ }
172
+ }
173
+
174
+ return $model
175
+ ->setName($name)
176
+ ->setNumberOfItems((int) $numberOfItems)
177
+ ->setTagContent($content)
178
+ ->setStoreId($storeId)
179
+ ->setPrimarySource($primarySource);
180
+ }
181
+
182
+ /**
183
+ * Validates the recommendation via an AJAX call
184
+ */
185
+ public function validateAction()
186
+ {
187
+ $json = array();
188
+ try {
189
+ $this->_validateRecommendation($this->_initRecommendation());
190
+ } catch (Exception $e) {
191
+ $json['message'] = $e->getMessage();
192
+ }
193
+
194
+ if (isset($json['message'])) {
195
+ $json['error'] = true;
196
+ $json['message'] = Mage::getBlockSingleton('core/messages')
197
+ ->addError($json['message'])
198
+ ->getGroupedHtml();
199
+ }
200
+ $this->getResponse()
201
+ ->setHeader('Content-Type', 'application/json')
202
+ ->setBody(Mage::helper('core')->jsonEncode($json));
203
+ }
204
+
205
+ /**
206
+ * Forwards calls to the new action
207
+ */
208
+ public function editAction()
209
+ {
210
+ $this->_forward('new');
211
+ }
212
+
213
+ /**
214
+ * Renders the form for product receommendations
215
+ */
216
+ public function newAction()
217
+ {
218
+ $this->_initAction()->_modalStyles();
219
+
220
+ $rec = $this->_initRecommendation('id');
221
+ if ($this->getRequest()->getParam('id')) {
222
+ $this->_addBreadcrumb(
223
+ $this->__('Edit Recommendation'),
224
+ $this->__('Edit Product Recommendation'));
225
+ } else {
226
+ $this->_addBreadcrumb(
227
+ $this->__('New Recommendation'),
228
+ $this->__('New Product Recommendation'));
229
+ }
230
+ $this->_title($rec->hasEntityId() ? $rec->getName() : $this->__('New Recommendation'));
231
+ $this->_addContent($this->getBlock('recommendation_edit')->setEditMode($rec->hasEntityId()));
232
+ $this->renderLayout();
233
+ }
234
+
235
+ /**
236
+ * Deletes one or more recommendations
237
+ */
238
+ public function deleteAction()
239
+ {
240
+ $recIds = $this->getRequest()->getParam('id', array());
241
+ $deleted = 0;
242
+ if (is_numeric($recIds)) {
243
+ $recIds = array($recIds);
244
+ }
245
+
246
+ $session = Mage::getSingleton('adminhtml/session');
247
+ if (count($recIds) > 0) {
248
+ foreach ($recIds as $recId) {
249
+ $rec = Mage::getModel('bronto_product/recommendation')->load($recId);
250
+ if ($rec->hasEntityId()) {
251
+ try {
252
+ $rec->delete();
253
+ $deleted++;
254
+ } catch (Exception $e) {
255
+ $session->addError($e->getMessage());
256
+ }
257
+ }
258
+ }
259
+ $session->addSuccess($this->__('Total of %d product recommendation(s) have been successfully deleted.', $deleted));
260
+ } else {
261
+ $session->addError($this->__('Please select recommendation(s).'));
262
+ }
263
+ $this->_redirect("*/*");
264
+ }
265
+
266
+ /**
267
+ * Copies one or more recommendations
268
+ */
269
+ public function copyAction()
270
+ {
271
+ $recIds = $this->getRequest()->getParam('id', array());
272
+ $copied = 0;
273
+ if (is_numeric($recIds)) {
274
+ $recIds = array($recIds);
275
+ }
276
+
277
+ $session = Mage::getSingleton('adminhtml/session');
278
+ if (count($recIds) > 0) {
279
+ foreach ($recIds as $recId) {
280
+ $rec = Mage::getModel('bronto_product/recommendation')->load($recId);
281
+ if ($rec->hasEntityId()) {
282
+ try {
283
+ $rec->softCopy()->save();
284
+ $copied++;
285
+ } catch (Exception $e) {
286
+ $session->addError($e->getMessage());
287
+ }
288
+ }
289
+ }
290
+ $session->addSuccess($this->__('Total of %d product recommendation(s) have been successfully copied.', $copied));
291
+ } else {
292
+ $session->addError($this->__('Please select recommendation(s).'));
293
+ }
294
+ $this->_redirect('*/*');
295
+ }
296
+
297
+ /**
298
+ * Save or update a recommendation
299
+ */
300
+ public function saveAction()
301
+ {
302
+ $recommendation = $this->_initRecommendation();
303
+ $session = Mage::getSingleton('adminhtml/session');
304
+
305
+ if (!$recommendation->hasEntityId() && $this->getRequest()->getParam('id')) {
306
+ $session->addError($this->__('This Product Recommendation no longer exists.'));
307
+ return $this->_redirect('*/*/');
308
+ }
309
+
310
+ try {
311
+ $secondSource = $this->getRequest()->getParam('secondary_source');
312
+ $fallbackSource = $this->getRequest()->getParam('fallback_source');
313
+ $manualPri = $this->getRequest()->getParam('manual_primary_source');
314
+ $manualSec = $this->getRequest()->getParam('manual_secondary_source');
315
+ $manualFal = $this->getRequest()->getParam('manual_fallback_source');
316
+
317
+ $this
318
+ ->_validateRecommendation($recommendation)
319
+ ->setSecondarySource($secondSource)
320
+ ->setFallbackSource($fallbackSource)
321
+ ->setManualPrimarySource($manualPri)
322
+ ->setManualSecondarySource($manualSec)
323
+ ->setManualFallbackSource($manualFal)
324
+ ->save();
325
+
326
+ $session->addSuccess($this->__('The Product Recommendation has been saved.'));
327
+
328
+ if ($this->getRequest()->getParam('continue')) {
329
+ return $this->_redirect('*/*/edit', array('id' => $recommendation->getId()));
330
+ } else {
331
+ return $this->_redirect('*/*/');
332
+ }
333
+ } catch (Exception $e) {
334
+ $session->setData('product_recommendation_data', $this->getRequest()->getParams());
335
+ $session->addError($e->getMessage());
336
+ return $this->_forward('new');
337
+ }
338
+
339
+ return $this;
340
+ }
341
+
342
+ /**
343
+ * Display the preview form
344
+ */
345
+ public function previewAction()
346
+ {
347
+ $recommendation = $this
348
+ ->_initAction()
349
+ ->_modalStyles()
350
+ ->_initRecommendation('entity_id');
351
+
352
+ $this->_addBreadcrumb(
353
+ $this->_title($this->__('Preview Recommendation')),
354
+ $this->_title($this->__('Preview Product Recommendations')));
355
+ $this->_addContent($this->getBlock('recommendation_preview')->setEditMode($recommendation->hasEntityId()));
356
+ $this->renderLayout();
357
+ }
358
+
359
+ /**
360
+ * Display the grid for products
361
+ */
362
+ public function selectedAction()
363
+ {
364
+ $this->_initRecommendation('id');
365
+ $this->getResponse()->setBody(
366
+ '<div style="height: 360px; overflow: auto">' .
367
+ $this->getBlock('recommendation_selected_grid')->toHtml() .
368
+ '</div>'
369
+ );
370
+ }
371
+
372
+ /**
373
+ * Fills the message form depending on the store view
374
+ */
375
+ public function messagesAction()
376
+ {
377
+ $this->loadLayout();
378
+ $this->getResponse()->setBody($this->getBlock('recommendation_message_form')->toHtml());
379
+ }
380
+
381
+ /**
382
+ * Sends the test email to the test contact
383
+ */
384
+ public function sendMessageAction()
385
+ {
386
+ $json = array();
387
+ try {
388
+ $grid = $this->getBlock('recommendation_preview_grid');
389
+ $emailAddress = $this->getRequest()->getPost('email_address');
390
+ $messageId = $this->getRequest()->getPost('message_id');
391
+ $storeId = $this->getRequest()->getParam('store', 0);
392
+
393
+ $json['missingParentRequirement'] = false;
394
+ if (!$grid->getSelectedRecommendation()->hasEntityId()) {
395
+ $json['missingParentRequirement'] = true;
396
+ throw new RuntimeException('Please select a product recommendation.');
397
+ }
398
+
399
+ if (empty($emailAddress) || !Zend_Validate::is($emailAddress, 'EmailAddress')) {
400
+ throw new RuntimeException('Email address is not valid.');
401
+ }
402
+
403
+ if (empty($messageId)) {
404
+ throw new RuntimeException('Please select a message ID.');
405
+ }
406
+
407
+ $contact = Mage::helper('bronto_common/contact')->getContactByEmail($emailAddress, 'Magento Test Delivery', $storeId);
408
+ if (empty($contact->id)) {
409
+ $contact->status = Bronto_Api_Contact::STATUS_ONBOARDING;
410
+ $contact->save();
411
+ }
412
+
413
+ $api = Mage::helper('bronto_common')->getApi(null, 'store', $storeId);
414
+ $deliveryObject = $api->getDeliveryObject();
415
+ $delivery = $deliveryObject->createRow();
416
+ $delivery->messageId = $messageId;
417
+ $delivery->fromEmail = $emailAddress;
418
+ $delivery->fromName = 'Product Recommendation';
419
+ $delivery->replyEmail = $emailAddress;
420
+ $delivery->type = 'test';
421
+ $delivery->start = date('c');
422
+ $delivery->recipients = array(
423
+ array(
424
+ 'type' => 'contact',
425
+ 'id' => $contact->id,
426
+ 'deliveryType' => 'selected'
427
+ ));
428
+
429
+ Mage::helper('bronto_product')->collectAndSetFields(
430
+ $grid->getSelectedRecommendation(),
431
+ $grid->getOptionalProducts(),
432
+ $delivery,
433
+ $this->getRequest()->getParam('store', 0));
434
+ $deliveryObject->add($delivery);
435
+ $json['success'] = true;
436
+ $json['message'] = Mage::getBlockSingleton('core/messages')
437
+ ->addSuccess($this->__('Test message successfully send to ' . $emailAddress . '.'))
438
+ ->getGroupedHtml();
439
+ } catch (Exception $e) {
440
+ $json['success'] = false;
441
+ $json['message'] = $json['missingParentRequirement'] ?
442
+ Mage::getBlockSingleton('core/messages')
443
+ ->addError($e->getMessage())
444
+ ->getGroupedHtml() :
445
+ $e->getMessage();
446
+ }
447
+
448
+ $this->getResponse()
449
+ ->setHeader('Content-Type', 'application/json')
450
+ ->setBody(Mage::helper('core')->jsonEncode($json));
451
+ }
452
+
453
+ /**
454
+ * Ajax response for the preview info
455
+ */
456
+ public function previewGridAction()
457
+ {
458
+ $this->loadLayout();
459
+ $this->getResponse()->setBody($this->getBlock('recommendation_preview_grid')->toHtml());
460
+ }
461
+
462
+ /**
463
+ * Handle AJAX post of tag info
464
+ */
465
+ public function contentAction()
466
+ {
467
+ $model = Mage::getModel('bronto_product/recommendation')->setData($this->getRequest()->getParams());
468
+ if (!$model->isDynamicContent()) {
469
+ $html = Mage::getBlockSingleton('core/messages')
470
+ ->addError('Content does not appear to be formatted correctly.')
471
+ ->getGroupedHtml();
472
+ } else {
473
+ $html = $this->getHelper()->processTagContent($model, $model->getStoreId());
474
+ }
475
+ $this->getResponse()->setBody($html);
476
+ }
477
+
478
+ /**
479
+ * Triggers a cron run for the product recs
480
+ */
481
+ public function runAction()
482
+ {
483
+ $helper = Mage::helper('bronto_product');
484
+ $result = Mage::getModel('bronto_product/observer')->processContentTagsForScope();
485
+ $this->_getSession()->addSuccess(sprintf("Processed %d Content Tags (%d Error / %d Success)", $result['total'], $result['error'], $result['success']));
486
+ $returnParams = array('section' => 'bronto_product');
487
+ $returnParams = array_merge($returnParams, $helper->getScopeParams());
488
+ $this->_redirect('*/system_config/edit', $returnParams);
489
+ }
490
+ }
app/code/community/Bronto/Product/etc/adminhtml.xml ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <acl>
4
+ <resources>
5
+ <admin>
6
+ <children>
7
+ <promo>
8
+ <children>
9
+ <bronto_product translate="title" module="bronto_product">
10
+ <title>Bronto Product Recommendations</title>
11
+ <sort_order>30</sort_order>
12
+ </bronto_product>
13
+ </children>
14
+ </promo>
15
+ <system>
16
+ <children>
17
+ <config>
18
+ <children>
19
+ <bronto_product module="bronto_product">
20
+ <title>Bronto Product Recommendations Section</title>
21
+ <sort_order>9999</sort_order>
22
+ </bronto_product>
23
+ </children>
24
+ </config>
25
+ </children>
26
+ </system>
27
+ </children>
28
+ </admin>
29
+ </resources>
30
+ </acl>
31
+ <menu>
32
+ <promo>
33
+ <children>
34
+ <bronto_product translate="title" module="bronto_product">
35
+ <title>Bronto Product Recommendations</title>
36
+ <action>adminhtml/recommendations</action>
37
+ <sort_order>30</sort_order>
38
+ <depends>
39
+ <module>Bronto_Product</module>
40
+ </depends>
41
+ <resource>promo/bronto_product</resource>
42
+ </bronto_product>
43
+ </children>
44
+ </promo>
45
+ </menu>
46
+ </config>
app/code/community/Bronto/Product/etc/config.xml ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Bronto_Product>
5
+ <version>1.0.0</version>
6
+ </Bronto_Product>
7
+ </modules>
8
+ <global>
9
+ <blocks>
10
+ <bronto_product>
11
+ <class>Bronto_Product_Block</class>
12
+ </bronto_product>
13
+ </blocks>
14
+ <helpers>
15
+ <bronto_product>
16
+ <class>Bronto_Product_Helper</class>
17
+ </bronto_product>
18
+ </helpers>
19
+ <models>
20
+ <bronto_product>
21
+ <class>Bronto_Product_Model</class>
22
+ <resourceModel>bronto_product_mysql4</resourceModel>
23
+ </bronto_product>
24
+ <bronto_product_mysql4>
25
+ <class>Bronto_Product_Model_Mysql4</class>
26
+ <entities>
27
+ <recommendation>
28
+ <table>bronto_product_recommendation</table>
29
+ </recommendation>
30
+ </entities>
31
+ </bronto_product_mysql4>
32
+ </models>
33
+ <resources>
34
+ <bronto_product_setup>
35
+ <setup>
36
+ <module>Bronto_Product</module>
37
+ <class>Bronto_Product_Model_Resource_Setup</class>
38
+ </setup>
39
+ <connection>
40
+ <use>core_setup</use>
41
+ </connection>
42
+ </bronto_product_setup>
43
+ </resources>
44
+ </global>
45
+ <admin>
46
+ <routers>
47
+ <adminhtml>
48
+ <args>
49
+ <modules>
50
+ <bronto_product before="Mage_Adminhtml">Bronto_Product_Adminhtml</bronto_product>
51
+ </modules>
52
+ </args>
53
+ </adminhtml>
54
+ </routers>
55
+ </admin>
56
+ <default>
57
+ <bronto_product>
58
+ <settings>
59
+ <enabled>0</enabled>
60
+ <mage_cron>1</mage_cron>
61
+ <frequency>D</frequency>
62
+ <interval>15</interval>
63
+ <minutes>0</minutes>
64
+ <description>short_description</description>
65
+ <char_limit>100</char_limit>
66
+ </settings>
67
+ </bronto_product>
68
+ </default>
69
+ <crontab>
70
+ <jobs>
71
+ <bronto_product_parse_tag>
72
+ <run>
73
+ <model>bronto_product/observer::processContentTags</model>
74
+ </run>
75
+ </bronto_product_parse_tag>
76
+ </jobs>
77
+ </crontab>
78
+ <phpunit>
79
+ <suite>
80
+ <modules>
81
+ <Bronto_Product/>
82
+ </modules>
83
+ </suite>
84
+ </phpunit>
85
+ </config>
app/code/community/Bronto/Product/etc/system.xml ADDED
@@ -0,0 +1,199 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <sections>
4
+ <bronto_product module="bronto_product">
5
+ <label><![CDATA[<div id="bronto_product_icon_block">Product Recommendations</div>]]></label>
6
+ <tab>bronto</tab>
7
+ <frontend_type>text</frontend_type>
8
+ <sort_order>896</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
+ <groups>
13
+ <about>
14
+ <frontend_type>text</frontend_type>
15
+ <frontend_model>bronto_product/adminhtml_system_config_about</frontend_model>
16
+ <sort_order>0</sort_order>
17
+ <show_in_default>1</show_in_default>
18
+ <show_in_website>1</show_in_website>
19
+ <show_in_store>1</show_in_store>
20
+ </about>
21
+ <settings>
22
+ <label>Settings</label>
23
+ <frontend_type>text</frontend_type>
24
+ <frontend_model>bronto_product/adminhtml_system_config_information</frontend_model>
25
+ <sort_order>20</sort_order>
26
+ <show_in_default>1</show_in_default>
27
+ <show_in_website>1</show_in_website>
28
+ <show_in_store>1</show_in_store>
29
+ <expanded>1</expanded>
30
+ <comment><![CDATA[Module configuration is located at:
31
+ <strong>Promotions</strong> &rsaquo; <a
32
+ href="{url}">Bronto Product
33
+ Recommendations</a></strong><br/>
34
+ <div class="bronto-with-help">
35
+ <strong>Recommended products adds new API tags to
36
+ configured messages.</strong>
37
+ <div class="bronto-help bronto-vertical-align">
38
+ <div class="bronto-help-window" style="width: 300px">
39
+ <table id="api_info" style="width: 300px; border: 1px solid #d6d6d6;">
40
+ <thead>
41
+ <tr style="border-bottom: 1px solid #d6d6d6;">
42
+ <th>Loop Tag Description</th>
43
+ <th>Loop Tag</th>
44
+ </tr>
45
+ </thead>
46
+ <tbody>
47
+ <tr>
48
+ <td>Related Product's name</td>
49
+ <td>relatedName_#</td>
50
+ </tr>
51
+ <tr>
52
+ <td>Related Product's description &nbsp;</td>
53
+ <td>relatedDescription_#</td>
54
+ </tr>
55
+ <tr>
56
+ <td>Related Product's sku</td>
57
+ <td>relatedSku_#</td>
58
+ </tr>
59
+ <tr>
60
+ <td>Related Product's price</td>
61
+ <td>relatedPrice_#</td>
62
+ </tr>
63
+ <tr>
64
+ <td>Related Product's URL</td>
65
+ <td>relatedUrl_#</td>
66
+ </tr>
67
+ <tr>
68
+ <td>Related Product's image</td>
69
+ <td>relatedImgUrl_#</td>
70
+ </tr>
71
+ </tbody>
72
+ </table>
73
+ </div>
74
+ </div>
75
+ </div>
76
+ ]]></comment>
77
+ <fields>
78
+ <enabled>
79
+ <label>Enable Recommendations</label>
80
+ <frontend_type>select</frontend_type>
81
+ <backend_model>bronto_common/system_config_backend_enable</backend_model>
82
+ <source_model>adminhtml/system_config_source_yesno</source_model>
83
+ <sort_order>10</sort_order>
84
+ <show_in_default>1</show_in_default>
85
+ <show_in_website>1</show_in_website>
86
+ <show_in_store>1</show_in_store>
87
+ </enabled>
88
+ <mage_cron>
89
+ <label>Use Magento Cron</label>
90
+ <depends>
91
+ <enabled>1</enabled>
92
+ </depends>
93
+ <frontend_type>select</frontend_type>
94
+ <frontend_model>bronto_common/adminhtml_system_config_form_field</frontend_model>
95
+ <source_model>adminhtml/system_config_source_yesno</source_model>
96
+ <sort_order>20</sort_order>
97
+ <show_in_default>1</show_in_default>
98
+ <show_in_website>0</show_in_website>
99
+ <show_in_store>0</show_in_store>
100
+ <comment>
101
+ <![CDATA[Setting to <em>No</em> will prevent the Magento Cron from triggering the import process for this module.<br />For more details, check the <em>Cron Settings</em> section in the <strong>Bronto &raquo; Advanced</strong> tab.]]></comment>
102
+ </mage_cron>
103
+ <frequency translate="label">
104
+ <label>Frequency</label>
105
+ <depends>
106
+ <enabled>1</enabled>
107
+ <mage_cron>1</mage_cron>
108
+ </depends>
109
+ <frontend_type>select</frontend_type>
110
+ <source_model>bronto_common/system_config_source_cron_frequency</source_model>
111
+ <backend_model>bronto_product/system_config_cron</backend_model>
112
+ <sort_order>40</sort_order>
113
+ <show_in_default>1</show_in_default>
114
+ <show_in_website>0</show_in_website>
115
+ <show_in_store>0</show_in_store>
116
+ </frequency>
117
+ <interval translate="label">
118
+ <label>Interval</label>
119
+ <depends>
120
+ <enabled>1</enabled>
121
+ <mage_cron>1</mage_cron>
122
+ <frequency>I</frequency>
123
+ </depends>
124
+ <frontend_type>select</frontend_type>
125
+ <source_model>bronto_common/system_config_source_cron_minutes</source_model>
126
+ <sort_order>50</sort_order>
127
+ <show_in_default>1</show_in_default>
128
+ <show_in_website>0</show_in_website>
129
+ <show_in_store>0</show_in_store>
130
+ <comment>Set this value larger than your cron.php launch period.</comment>
131
+ </interval>
132
+ <minutes translate="label">
133
+ <label>Minute of the Hour</label>
134
+ <depends>
135
+ <enabled>1</enabled>
136
+ <frequency>H</frequency>
137
+ </depends>
138
+ <frontend_type>text</frontend_type>
139
+ <sort_order>60</sort_order>
140
+ <show_in_default>1</show_in_default>
141
+ <show_in_website>0</show_in_website>
142
+ <show_in_store>0</show_in_store>
143
+ <comment>Valid range: 0-59 (default 0).</comment>
144
+ </minutes>
145
+ <time translate="label">
146
+ <label>Start Time</label>
147
+ <depends>
148
+ <enabled>1</enabled>
149
+ <mage_cron>1</mage_cron>
150
+ </depends>
151
+ <frontend_type>time</frontend_type>
152
+ <sort_order>70</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
+ </time>
157
+ <description>
158
+ <label>Product Description Attribute</label>
159
+ <depends>
160
+ <enabled>1</enabled>
161
+ </depends>
162
+ <frontend_type>select</frontend_type>
163
+ <source_model>bronto_order/system_config_source_description</source_model>
164
+ <sort_order>80</sort_order>
165
+ <show_in_default>1</show_in_default>
166
+ <show_in_website>1</show_in_website>
167
+ <show_in_store>1</show_in_store>
168
+ <comment><![CDATA[Product attribute used for the
169
+ <em>%%%%#relatedDescription_#%%%%</em>
170
+ tag.]]></comment>
171
+ </description>
172
+ <char_limit>
173
+ <label>Truncate Description Characters</label>
174
+ <depends>
175
+ <enabled>1</enabled>
176
+ </depends>
177
+ <frontend_type>text</frontend_type>
178
+ <sort_order>90</sort_order>
179
+ <show_in_default>1</show_in_default>
180
+ <show_in_website>1</show_in_website>
181
+ <show_in_store>1</show_in_store>
182
+ <comment>If the selected product description attribute is greater than
183
+ this amount, the content will be
184
+ truncated.</comment>
185
+ </char_limit>
186
+ </fields>
187
+ </settings>
188
+ <cron_list>
189
+ <frontend_type>text</frontend_type>
190
+ <frontend_model>bronto_product/adminhtml_system_config_cron</frontend_model>
191
+ <sort_order>30</sort_order>
192
+ <show_in_default>1</show_in_default>
193
+ <show_in_website>1</show_in_website>
194
+ <show_in_store>1</show_in_store>
195
+ </cron_list>
196
+ </groups>
197
+ </bronto_product>
198
+ </sections>
199
+ </config>
app/code/community/Bronto/Product/sql/bronto_product_setup/mysql4-install-1.0.0.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ $installer = $this;
4
+
5
+ $installer->startSetup();
6
+
7
+ try {
8
+ $installer->dropTable('recommendation');
9
+ $installer->createTable('recommendation');
10
+ } catch (Exception $e) {
11
+ Mage::helper('bronto_product')->writeError('Failed to create Product Recommentation table: ' . $e->getMessage());
12
+ }
13
+
14
+ $installer->endSetup();
app/code/community/Bronto/Reminder/Block/Adminhtml/Reminder/Edit/Tab/Customers.php CHANGED
@@ -56,6 +56,15 @@ class Bronto_Reminder_Block_Adminhtml_Reminder_Edit_Tab_Customers extends Mage_A
56
  'renderer' => 'bronto_reminder/adminhtml_widget_grid_column_renderer_email'
57
  ));
58
 
 
 
 
 
 
 
 
 
 
59
  $this->addColumn('grid_associated_at', array(
60
  'header' => Mage::helper('bronto_reminder')->__('Matched At'),
61
  'align' => 'left',
56
  'renderer' => 'bronto_reminder/adminhtml_widget_grid_column_renderer_email'
57
  ));
58
 
59
+ $this->addColumn('grid_store', array(
60
+ 'header' => Mage::helper('bronto_reminder')->__('Store View'),
61
+ 'type' => 'store',
62
+ 'skipAllStoresLabel' => true,
63
+ 'index' => 'store_id',
64
+ 'sortable' => false,
65
+ 'store_view' => true,
66
+ ));
67
+
68
  $this->addColumn('grid_associated_at', array(
69
  'header' => Mage::helper('bronto_reminder')->__('Matched At'),
70
  'align' => 'left',
app/code/community/Bronto/Reminder/Block/Adminhtml/Reminder/Edit/Tab/General.php CHANGED
@@ -41,6 +41,16 @@ class Bronto_Reminder_Block_Adminhtml_Reminder_Edit_Tab_General extends Mage_Adm
41
  'values' => Mage::helper('bronto_common/salesrule')->getRuleOptionsArray(),
42
  ));
43
 
 
 
 
 
 
 
 
 
 
 
44
  if (!Mage::app()->isSingleStoreMode()) {
45
  $fieldset->addField('website_ids', 'multiselect', array(
46
  'name' => 'website_ids',
41
  'values' => Mage::helper('bronto_common/salesrule')->getRuleOptionsArray(),
42
  ));
43
 
44
+ if (Mage::helper('bronto_product')->isEnabledForAny()) {
45
+ $fieldset->addField("product_recommendation_id", 'select', array(
46
+ 'name' => "product_recommendation_id",
47
+ 'required' => false,
48
+ 'label' => $this->__('Product Recommendations'),
49
+ 'values' => Mage::getModel('bronto_product/recommendation')->toOptionArray('None Selected'),
50
+ 'note' => $this->__('Inject related product content into this message. Recommendations are created in <strong>Promotions</strong> &raquo; <strong>Bronto Product Recommendations')
51
+ ));
52
+ }
53
+
54
  if (!Mage::app()->isSingleStoreMode()) {
55
  $fieldset->addField('website_ids', 'multiselect', array(
56
  'name' => 'website_ids',
app/code/community/Bronto/Reminder/Model/Email/Message.php CHANGED
@@ -24,6 +24,14 @@ class Bronto_Reminder_Model_Email_Message extends Bronto_Common_Model_Email_Temp
24
  return 'bronto_reminder/email_message';
25
  }
26
 
 
 
 
 
 
 
 
 
27
  /**
28
  * Log about the functionality of sending the email before it goes out
29
  *
24
  return 'bronto_reminder/email_message';
25
  }
26
 
27
+ /**
28
+ * @see parent
29
+ */
30
+ protected function _queuable()
31
+ {
32
+ return false;
33
+ }
34
+
35
  /**
36
  * Log about the functionality of sending the email before it goes out
37
  *
app/code/community/Bronto/Reminder/Model/Mysql4/Rule.php CHANGED
@@ -484,6 +484,7 @@ class Bronto_Reminder_Model_Mysql4_Rule
484
 
485
  $dataToInsert[] = array(
486
  'rule_id' => $ruleId,
 
487
  'coupon_id' => $couponId,
488
  'unique_id' => $row['unique_id'],
489
  'store_id' => $row['store_id'],
@@ -535,10 +536,11 @@ class Bronto_Reminder_Model_Mysql4_Rule
535
  *
536
  * @param int|null $limit
537
  * @param int|null $ruleId
 
538
  *
539
  * @return array
540
  */
541
- public function getCustomersForNotification($limit = null, $ruleId = null)
542
  {
543
  $couponTable = $this->getTable('bronto_reminder/coupon');
544
  $ruleTable = $this->getTable('bronto_reminder/rule');
@@ -549,6 +551,7 @@ class Bronto_Reminder_Model_Mysql4_Rule
549
  array(
550
  'rule_id',
551
  'coupon_id',
 
552
  'unique_id',
553
  'store_id',
554
  'customer_id',
@@ -558,6 +561,10 @@ class Bronto_Reminder_Model_Mysql4_Rule
558
  )
559
  );
560
 
 
 
 
 
561
  $select->join(
562
  array('r' => $ruleTable),
563
  'c.rule_id = r.rule_id AND r.is_active = 1',
484
 
485
  $dataToInsert[] = array(
486
  'rule_id' => $ruleId,
487
+ 'product_recommendation_id' => $rule->getProductRecommendationId(),
488
  'coupon_id' => $couponId,
489
  'unique_id' => $row['unique_id'],
490
  'store_id' => $row['store_id'],
536
  *
537
  * @param int|null $limit
538
  * @param int|null $ruleId
539
+ * @param int|null $threshold
540
  *
541
  * @return array
542
  */
543
+ public function getCustomersForNotification($limit = null, $ruleId = null, $threshold = null)
544
  {
545
  $couponTable = $this->getTable('bronto_reminder/coupon');
546
  $ruleTable = $this->getTable('bronto_reminder/rule');
551
  array(
552
  'rule_id',
553
  'coupon_id',
554
+ 'product_recommendation_id',
555
  'unique_id',
556
  'store_id',
557
  'customer_id',
561
  )
562
  );
563
 
564
+ if ($threshold) {
565
+ $select->where('c.emails_failed IS NULL OR c.emails_failed < ? ', $threshold);
566
+ }
567
+
568
  $select->join(
569
  array('r' => $ruleTable),
570
  'c.rule_id = r.rule_id AND r.is_active = 1',
app/code/community/Bronto/Reminder/Model/Resource/Setup.php ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Reminder_Model_Resource_Setup extends Bronto_Common_Model_Resource_Abstract
4
+ {
5
+ /**
6
+ * @see parent
7
+ */
8
+ protected function _module()
9
+ {
10
+ return 'bronto_reminder';
11
+ }
12
+
13
+ /**
14
+ * @see parent
15
+ */
16
+ protected function _tables()
17
+ {
18
+ return array(
19
+ 'rule' => "
20
+ CREATE TABLE `{table}` (
21
+ `rule_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
22
+ `name` varchar(255) NOT NULL DEFAULT '',
23
+ `description` text NOT NULL,
24
+ `conditions_serialized` mediumtext NOT NULL,
25
+ `condition_sql` mediumtext,
26
+ `is_active` tinyint(1) unsigned NOT NULL DEFAULT '0',
27
+ `salesrule_id` int(10) unsigned DEFAULT NULL,
28
+ `product_recommendation_id` int(11) unsigned DEFAULT NULL,
29
+ `schedule` varchar(255) NOT NULL DEFAULT '',
30
+ `default_label` varchar(255) NOT NULL DEFAULT '',
31
+ `default_description` text NOT NULL,
32
+ `active_from` datetime DEFAULT NULL,
33
+ `active_to` datetime DEFAULT NULL,
34
+ `send_to` enum('user', 'guest', 'both') DEFAULT 'both',
35
+ `send_limit` int(10) DEFAULT 1,
36
+ PRIMARY KEY (`rule_id`),
37
+ KEY `IDX_BRONTO_REMINDER_SALESRULE` (`salesrule_id`),
38
+ CONSTRAINT `FK_BRONTO_REMINDER_SALESRULE` FOREIGN KEY (`salesrule_id`)
39
+ REFERENCES `{$this->getTable('salesrule')}` (`rule_id`) ON DELETE SET NULL ON UPDATE CASCADE
40
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8;",
41
+ 'website' => "
42
+ CREATE TABLE `{table}` (
43
+ `rule_id` int(10) unsigned NOT NULL,
44
+ `website_id` smallint(5) unsigned NOT NULL,
45
+ PRIMARY KEY (`rule_id`,`website_id`),
46
+ KEY `IDX_BRONTO_REMINDER_WEBSITE` (`website_id`),
47
+ CONSTRAINT `FK_BRONTO_REMINDER_RULE` FOREIGN KEY (`rule_id`)
48
+ REFERENCES `{$this->getTable('bronto_reminder/rule')}` (`rule_id`) ON DELETE CASCADE ON UPDATE CASCADE
49
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8;",
50
+ 'message' => "
51
+ CREATE TABLE `{table}` (
52
+ `rule_id` int(10) unsigned NOT NULL,
53
+ `store_id` smallint(5) NOT NULL,
54
+ `message_id` varchar(255) NOT NULL DEFAULT '',
55
+ `send_type` varchar(20) NOT NULL DEFAULT 'transactional',
56
+ `label` varchar(255) DEFAULT NULL,
57
+ `description` text,
58
+ PRIMARY KEY (`rule_id`,`store_id`),
59
+ KEY `IDX_BRONTO_REMINDER_MESSAGE_RULE` (`rule_id`),
60
+ KEY `IDX_BRONTO_REMINDER_MESSAGE` (`message_id`),
61
+ CONSTRAINT `FK_BRONTO_REMINDER_MESSAGE_RULE` FOREIGN KEY (`rule_id`)
62
+ REFERENCES `{$this->getTable('bronto_reminder/rule')}` (`rule_id`) ON DELETE CASCADE ON UPDATE CASCADE
63
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8;",
64
+ 'coupon' => "
65
+ CREATE TABLE `{table}` (
66
+ `rule_id` int(10) unsigned NOT NULL,
67
+ `coupon_id` int(10) unsigned DEFAULT NULL,
68
+ `product_recommendation_id` int(11) unsigned DEFAULT NULL,
69
+ `unique_id` varchar(255) NOT NULL,
70
+ `store_id` int(10) unsigned NOT NULL,
71
+ `customer_id` int(10) unsigned NOT NULL,
72
+ `customer_email` varchar(255) CHARACTER SET utf8 NOT NULL,
73
+ `quote_id` int(10) unsigned NOT NULL DEFAULT '0',
74
+ `wishlist_id` int(10) unsigned NOT NULL DEFAULT '0',
75
+ `associated_at` datetime NOT NULL,
76
+ `emails_failed` smallint(5) unsigned NOT NULL DEFAULT '0',
77
+ `is_active` tinyint(1) unsigned NOT NULL DEFAULT '1',
78
+ PRIMARY KEY (`rule_id`,`unique_id`,`store_id`,`customer_email`),
79
+ KEY `IDX_BRONTO_REMINDER_RULE_COUPON` (`rule_id`),
80
+ CONSTRAINT `FK_BRONTO_REMINDER_RULE_COUPON` FOREIGN KEY (`rule_id`)
81
+ REFERENCES `{$this->getTable('bronto_reminder/rule')}` (`rule_id`) ON DELETE CASCADE ON UPDATE CASCADE
82
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8;",
83
+ 'log' => "
84
+ CREATE TABLE `{table}` (
85
+ `log_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
86
+ `rule_id` int(10) unsigned NOT NULL,
87
+ `unique_id` varchar(255) NOT NULL,
88
+ `sent_at` datetime NOT NULL,
89
+ `bronto_delivery_id` varchar(255) DEFAULT NULL,
90
+ `bronto_message_id` varchar(255) DEFAULT NULL,
91
+ PRIMARY KEY (`log_id`),
92
+ KEY `IDX_BRONTO_REMINDER_LOG_RULE` (`rule_id`),
93
+ CONSTRAINT `FK_BRONTO_REMINDER_LOG_RULE` FOREIGN KEY (`rule_id`)
94
+ REFERENCES `{$this->getTable('bronto_reminder/rule')}` (`rule_id`) ON DELETE CASCADE ON UPDATE CASCADE
95
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8;",
96
+ 'delivery' => "
97
+ CREATE TABLE `{table}` (
98
+ `log_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Log ID',
99
+ `customer_id` int(10) unsigned DEFAULT NULL COMMENT 'Customer ID',
100
+ `customer_email` varchar(255) DEFAULT NULL COMMENT 'Customer Email Address',
101
+ `contact_id` varchar(36) DEFAULT NULL COMMENT 'Bronto Contact ID',
102
+ `message_id` varchar(36) NOT NULL COMMENT 'Bronto Message ID',
103
+ `message_name` varchar(64) DEFAULT NULL COMMENT 'Bronto Message Name',
104
+ `delivery_id` varchar(36) DEFAULT NULL COMMENT 'Bronto Delivery ID',
105
+ `sent_at` datetime DEFAULT NULL COMMENT 'Date Message Sent',
106
+ `success` smallint(5) unsigned NOT NULL DEFAULT '0' COMMENT 'Message Send Success',
107
+ `error` varchar(255) DEFAULT NULL COMMENT 'Error Message',
108
+ `fields` text COMMENT 'Fields',
109
+ PRIMARY KEY (`log_id`),
110
+ KEY `IDX_BRONTO_REMINDER_LOG_CUSTOMER_EMAIL` (`customer_email`),
111
+ KEY `IDX_BRONTO_REMINDER_LOG_SENT_AT` (`sent_at`)
112
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Bronto Reminder Delivery Logs';
113
+ "
114
+ );
115
+ }
116
+
117
+ /**
118
+ * @see parent
119
+ */
120
+ protected function _updates()
121
+ {
122
+ return array(
123
+ '1.4.17' => array(
124
+ 'rule' => array(
125
+ 'sql' => 'ALTER TABLE {table} ADD COLUMN `product_recommendation_id` int(11) unsigned DEFAULT NULL AFTER `salesrule_id`;'
126
+ ),
127
+ 'coupon' => array(
128
+ 'sql' => 'ALTER TABLE {table} ADD COLUMN `product_recommendation_id` int(11) unsigned DEFAULT NULL AFTER `coupon_id`;'
129
+ )
130
+ )
131
+ );
132
+ }
133
+ }
app/code/community/Bronto/Reminder/Model/Rule.php CHANGED
@@ -34,7 +34,7 @@ class Bronto_Reminder_Model_Rule
34
  if (Mage::helper('bronto_verify')->isVersionMatch(
35
  Mage::getVersionInfo(),
36
  1,
37
- array(array('<=', 6), 9, 10, 11)
38
  )
39
  ) {
40
  $conditionsArr = unserialize($this->getConditionsSerialized());
@@ -67,6 +67,9 @@ class Bronto_Reminder_Model_Rule
67
  if (!$this->getSalesruleId()) {
68
  $this->setSalesruleId(null);
69
  }
 
 
 
70
  parent::_beforeSave();
71
  }
72
 
@@ -108,13 +111,14 @@ class Bronto_Reminder_Model_Rule
108
  * Get array of Registered User abandons and then Guest abandons
109
  *
110
  * @param int $limit
 
111
  *
112
  * @return array
113
  */
114
- protected function _getRecipients($limit)
115
  {
116
  // Pull in array of customers who abandoned their cart
117
- return (array)$this->_getResource()->getCustomersForNotification($limit, $this->getRuleId());
118
  }
119
 
120
  /**
@@ -169,9 +173,10 @@ class Bronto_Reminder_Model_Rule
169
  }
170
 
171
  /* @var $mail Bronto_Reminder_Model_Email_Message */
172
- $mail = Mage::getModel('bronto_reminder/email_message');
173
- $limit = Mage::helper('bronto_reminder')->getOneRunLimit();
174
- $identity = Mage::helper('bronto_reminder')->getEmailIdentity();
 
175
 
176
  $this->_matchCustomers();
177
 
@@ -180,7 +185,7 @@ class Bronto_Reminder_Model_Rule
180
  }
181
 
182
  // Get Array of Recipients
183
- $recipients = $this->_getRecipients($limit);
184
 
185
  $total = 0;
186
  $success = 0;
@@ -196,7 +201,7 @@ class Bronto_Reminder_Model_Rule
196
  $store = Mage::getModel('core/store')->load($recipient['store_id']);
197
 
198
  // If Sending not allowed for this store
199
- if (!Mage::helper('bronto_reminder')->isAllowSend($store)) {
200
  $error++;
201
  continue;
202
  }
@@ -267,6 +272,8 @@ class Bronto_Reminder_Model_Rule
267
  $store->getWebsiteId()
268
  );
269
  $mail->setTemplateSendType($messageData['send_type']);
 
 
270
  $mail->sendTransactional(
271
  $message,
272
  $identity,
34
  if (Mage::helper('bronto_verify')->isVersionMatch(
35
  Mage::getVersionInfo(),
36
  1,
37
+ array(array('<=', 6), array('edition' => 'Enterprise', 'major' => 9), 10, 11)
38
  )
39
  ) {
40
  $conditionsArr = unserialize($this->getConditionsSerialized());
67
  if (!$this->getSalesruleId()) {
68
  $this->setSalesruleId(null);
69
  }
70
+ if (!$this->getProductRecommendationId()) {
71
+ $this->setProductRecommendationId(null);
72
+ }
73
  parent::_beforeSave();
74
  }
75
 
111
  * Get array of Registered User abandons and then Guest abandons
112
  *
113
  * @param int $limit
114
+ * @param int $threshold (Optional)
115
  *
116
  * @return array
117
  */
118
+ protected function _getRecipients($limit, $threshold = null)
119
  {
120
  // Pull in array of customers who abandoned their cart
121
+ return (array)$this->_getResource()->getCustomersForNotification($limit, $this->getRuleId(), $threshold);
122
  }
123
 
124
  /**
173
  }
174
 
175
  /* @var $mail Bronto_Reminder_Model_Email_Message */
176
+ $mail = Mage::getModel('bronto_reminder/email_message');
177
+ $limit = Mage::helper('bronto_reminder')->getOneRunLimit();
178
+ $identity = Mage::helper('bronto_reminder')->getEmailIdentity();
179
+ $threshold = Mage::helper('bronto_reminder')->getSendFailureThreshold();
180
 
181
  $this->_matchCustomers();
182
 
185
  }
186
 
187
  // Get Array of Recipients
188
+ $recipients = $this->_getRecipients($limit, $threshold);
189
 
190
  $total = 0;
191
  $success = 0;
201
  $store = Mage::getModel('core/store')->load($recipient['store_id']);
202
 
203
  // If Sending not allowed for this store
204
+ if (!Mage::helper('bronto_reminder')->isAllowSend('store', $store->getId())) {
205
  $error++;
206
  continue;
207
  }
272
  $store->getWebsiteId()
273
  );
274
  $mail->setTemplateSendType($messageData['send_type']);
275
+ $mail->setSalesRule($recipient['coupon_id']);
276
+ $mail->setProductRecommendation($recipient['product_recommendation_id']);
277
  $mail->sendTransactional(
278
  $message,
279
  $identity,
app/code/community/Bronto/Reminder/controllers/LoadController.php CHANGED
@@ -35,6 +35,9 @@ class Bronto_Reminder_LoadController extends Mage_Core_Controller_Front_Action
35
  $redirectUrl = Mage::app()->getStore()->getUrl('checkout/cart');
36
  } else if ($wishlist = $this->_handleWishlist($wishlistId, $storeId)) {
37
  $redirectUrl = Mage::app()->getStore()->getUrl('wishlist');
 
 
 
38
  }
39
 
40
  // Get Customer ID from Quote/Wishlist
35
  $redirectUrl = Mage::app()->getStore()->getUrl('checkout/cart');
36
  } else if ($wishlist = $this->_handleWishlist($wishlistId, $storeId)) {
37
  $redirectUrl = Mage::app()->getStore()->getUrl('wishlist');
38
+ } else {
39
+ $this->_redirectUrl(Mage::app()->getStore()->getUrl('checkout/cart'));
40
+ return;
41
  }
42
 
43
  // Get Customer ID from Quote/Wishlist
app/code/community/Bronto/Reminder/etc/config.xml CHANGED
@@ -2,7 +2,7 @@
2
  <config>
3
  <modules>
4
  <Bronto_Reminder>
5
- <version>1.4.16</version>
6
  </Bronto_Reminder>
7
  </modules>
8
  <global>
@@ -52,8 +52,19 @@
52
  <bronto_reminder_setup>
53
  <setup>
54
  <module>Bronto_Reminder</module>
 
55
  </setup>
56
  </bronto_reminder_setup>
 
 
 
 
 
 
 
 
 
 
57
  </resources>
58
  <events>
59
  <salesrule_rule_get_coupon_types>
2
  <config>
3
  <modules>
4
  <Bronto_Reminder>
5
+ <version>1.4.17</version>
6
  </Bronto_Reminder>
7
  </modules>
8
  <global>
52
  <bronto_reminder_setup>
53
  <setup>
54
  <module>Bronto_Reminder</module>
55
+ <class>Bronto_Reminder_Model_Resource_Setup</class>
56
  </setup>
57
  </bronto_reminder_setup>
58
+ <bronto_reminder_write>
59
+ <connection>
60
+ <use>core_write</use>
61
+ </connection>
62
+ </bronto_reminder_write>
63
+ <bronto_reminder_read>
64
+ <connection>
65
+ <use>core_read</use>
66
+ </connection>
67
+ </bronto_reminder_read>
68
  </resources>
69
  <events>
70
  <salesrule_rule_get_coupon_types>
app/code/community/Bronto/Reminder/sql/bronto_reminder_setup/mysql4-install-1.4.17.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ $installer = $this;
4
+
5
+ $installer->startSetup();
6
+
7
+ try {
8
+ $installer->createTables();
9
+ } catch (Exception $e) {
10
+ Mage::helper('bronto_reminder')->writeError('Failed to create tables: ' . $e->getMessage());
11
+ }
12
+
13
+ $installer->endSetup();
app/code/community/Bronto/Reminder/sql/bronto_reminder_setup/mysql4-upgrade-1.4.16-1.4.17.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ $installer = $this;
4
+
5
+ $installer->startSetup();
6
+ $installer->updateTables('1.4.17');
7
+ $installer->endSetup();
app/code/community/Bronto/Reviews/Helper/Data.php CHANGED
@@ -8,15 +8,17 @@ class Bronto_Reviews_Helper_Data
8
  extends Bronto_Common_Helper_Data
9
  implements Bronto_Common_Helper_DataInterface
10
  {
11
- const XML_PATH_ENABLED = 'bronto_reviews/settings/enabled';
12
- const XML_PATH_STATUS = 'bronto_reviews/settings/status';
13
- const XML_PATH_CANCEL_STATUS = 'bronto_reviews/settings/cancel_status';
14
- const XML_PATH_URL_SUFFIX = 'bronto_reviews/settings/url_suffix';
15
- const XML_PATH_PERIOD = 'bronto_reviews/settings/period';
16
- const XML_PATH_MESSAGE = 'bronto_reviews/settings/message';
17
- const XML_PATH_SENDER_EMAIL = 'bronto_reviews/settings/sender_email';
18
- const XML_PATH_SENDER_NAME = 'bronto_reviews/settings/sender_name';
19
- const XML_PATH_REPLY_TO = 'bronto_reviews/settings/reply_to';
 
 
20
 
21
  /**
22
  * Gets the canonical name for the Bronto Review module
@@ -69,6 +71,30 @@ class Bronto_Reviews_Helper_Data
69
  return $this->getAdminScopedConfig(self::XML_PATH_STATUS, $scope, $scopeId);
70
  }
71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  /**
73
  * Get Order Status at which to cancel Review Request Emails
74
  *
8
  extends Bronto_Common_Helper_Data
9
  implements Bronto_Common_Helper_DataInterface
10
  {
11
+ const XML_PATH_ENABLED = 'bronto_reviews/settings/enabled';
12
+ const XML_PATH_STATUS = 'bronto_reviews/settings/status';
13
+ const XML_PATH_CANCEL_STATUS = 'bronto_reviews/settings/cancel_status';
14
+ const XML_PATH_URL_SUFFIX = 'bronto_reviews/settings/url_suffix';
15
+ const XML_PATH_PERIOD = 'bronto_reviews/settings/period';
16
+ const XML_PATH_MESSAGE = 'bronto_reviews/settings/message';
17
+ const XML_PATH_SENDER_EMAIL = 'bronto_reviews/settings/sender_email';
18
+ const XML_PATH_SENDER_NAME = 'bronto_reviews/settings/sender_name';
19
+ const XML_PATH_REPLY_TO = 'bronto_reviews/settings/reply_to';
20
+ const XML_PATH_DEFAULT_COUPON = 'bronto_reviews/settings/default_coupon';
21
+ const XML_PATH_DEFAULT_REC = 'bronto_reviews/settings/default_recommendation';
22
 
23
  /**
24
  * Gets the canonical name for the Bronto Review module
71
  return $this->getAdminScopedConfig(self::XML_PATH_STATUS, $scope, $scopeId);
72
  }
73
 
74
+ /**
75
+ * Gets the coupon code selected for this review
76
+ *
77
+ * @param string $scope
78
+ * @param int $scopeId
79
+ * @return string
80
+ */
81
+ public function getDefaultRule($scope = 'default', $scopeId = 0)
82
+ {
83
+ return $this->getAdminScopedConfig(self::XML_PATH_DEFAULT_COUPON, $scope, $scopeId);
84
+ }
85
+
86
+ /**
87
+ * Gets the product recommendation selected for this review
88
+ *
89
+ * @param string $scope
90
+ * @param int $scopeId
91
+ * @return string
92
+ */
93
+ public function getDefaultRecommendation($scope = 'default', $scopeId)
94
+ {
95
+ return $this->getAdminScopedConfig(self::XML_PATH_DEFAULT_REC, $scope, $scopeId);
96
+ }
97
+
98
  /**
99
  * Get Order Status at which to cancel Review Request Emails
100
  *
app/code/community/Bronto/Reviews/Model/Message.php ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Reviews_Model_Message extends Bronto_Common_Model_Email_Template
4
+ {
5
+ protected $_helper = 'bronto_reviews';
6
+
7
+ protected $_apiLogFile = 'bronto_reviews_api.log';
8
+
9
+ /**
10
+ * @see parent
11
+ */
12
+ protected function _emailClass()
13
+ {
14
+ return 'bronto_reviews/message';
15
+ }
16
+
17
+ /**
18
+ * @see parent
19
+ */
20
+ protected function _startTime($storeId)
21
+ {
22
+ $helper = Mage::helper($this->_helper);
23
+ $sendPeriod = $helper->getReviewSendPeriod('store', $storeId);
24
+ return date('c', strtotime('+' . abs($sendPeriod) . ' days'));
25
+ }
26
+
27
+ /**
28
+ * @see parent
29
+ */
30
+ protected function _additionalFields($delivery, $variables)
31
+ {
32
+ $order = $variables['order'];
33
+ $storeId = $order->getStoreId();
34
+ $helper = Mage::helper('bronto_common/product');
35
+ $reviewHelper = Mage::helper('bronto_reviews');
36
+ $urlSuffix = ltrim($reviewHelper->getProductUrlSuffix('store', $storeId), '/');
37
+
38
+ $index = 1;
39
+ foreach ($order->getAllItems() as $item) {
40
+ if (!$item->getParentItem()) {
41
+ $product = Mage::getModel('catalog/product')
42
+ ->setStoreId($storeId)
43
+ ->load($item->getProductId());
44
+
45
+ $productUrl = $helper->getProductAttribute($product, 'url', $storeId) . $urlSuffix;
46
+ $reviewUrl = $reviewHelper->getReviewsUrl($product, $storeId) . $urlSuffix;
47
+
48
+ $delivery->setField('reviewUrl_' . $index, $reviewUrl, 'html');
49
+ $delivery->setField('productUrl_' . $index, $productUrl, 'html');
50
+ $index++;
51
+ }
52
+ }
53
+ }
54
+
55
+ /**
56
+ * @see parent
57
+ */
58
+ protected function _additionalData()
59
+ {
60
+ return array('order_id' => $this->getOrderId());
61
+ }
62
+
63
+ /**
64
+ * @see parent
65
+ */
66
+ protected function _afterSend($success, $error = null, Bronto_Api_Delivery_Row $delivery = null)
67
+ {
68
+ $helper = Mage::helper($this->_helper);
69
+ if (!is_null($delivery)) {
70
+ if ($success) {
71
+ $review = Mage::getModel('bronto_reviews/queue')
72
+ ->load($this->getParams()->getOrderId())
73
+ ->setDeliveryId($delivery->id);
74
+ if (!is_null($review->getDeliveryId())) {
75
+ $review->save();
76
+ }
77
+ }
78
+ $status = $success ? 'Successful' : 'Failed';
79
+
80
+ $helper->writeVerboseDebug("===== $status Reviews Delivery =====", $this->_apiLogFile);
81
+ $helper->writeVerboseDebug(var_export($delivery->getApi()->getLastRequest(), true), $this->_apiLogFile);
82
+ $helper->writeVerboseDebug(var_export($delivery->getApi()->getLastResponse(), true), $this->_apiLogFile);
83
+ }
84
+ }
85
+ }
app/code/community/Bronto/Reviews/Model/Observer.php CHANGED
@@ -38,34 +38,6 @@ class Bronto_Reviews_Model_Observer
38
  return $this;
39
  }
40
 
41
- /**
42
- * Get Contact Row Object to use
43
- *
44
- * @return Bronto_Api_Contact_Row
45
- */
46
- public function getContact()
47
- {
48
- if (!$this->_contact) {
49
- // Retrieve Store's configured API Token
50
- $token = $this->_helper->getApiToken('store', $this->getOrder()->getStoreId());
51
-
52
- /** @var Bronto_Common_Model_Api $api */
53
- $api = $this->_helper->getApi($token, 'store', $this->getOrder()->getStoreId());
54
-
55
- /** @var Bronto_Api_Contact $contactObject */
56
- $contactObject = $api->getContactObject();
57
-
58
- /** @var Bronto_Api_Contact_Row $brontoContact */
59
- $brontoContact = $contactObject->createRow(array());
60
- $brontoContact->email = $this->getOrder()->getCustomerEmail();
61
- $brontoContact->save();
62
-
63
- $this->setContact($brontoContact);
64
- }
65
-
66
- return $this->_contact;
67
- }
68
-
69
  /**
70
  * Set Order to use
71
  *
@@ -259,7 +231,11 @@ class Bronto_Reviews_Model_Observer
259
  $delivery = $this->getDeliveryObject();
260
  $result = $delivery->update(array('id' => $deliveryId, 'status' => 'skipped'));
261
  if ($result->hasErrors()) {
262
- $error = implode('<br />', $result->getErrors());
 
 
 
 
263
 
264
  Mage::throwException($error);
265
  }
@@ -268,159 +244,46 @@ class Bronto_Reviews_Model_Observer
268
  }
269
  }
270
 
271
- protected function _setIneligibleRecipients($delivery, $storeId)
272
- {
273
- $helper = Mage::helper('bronto_reviews');
274
- $listIds = $helper->getExclusionLists('store', $storeId);
275
- if ($listIds) {
276
- $listObject = $delivery->getApi()->getListObject();
277
- try {
278
- $lists = $listObject->read(array('id' => $listIds));
279
- foreach ($lists as $list) {
280
- if ($list->hasError()) {
281
- continue;
282
- }
283
- $delivery->recipients[] = array(
284
- 'type' => 'list',
285
- 'id' => $list->id,
286
- 'deliveryType' => 'ineligible'
287
- );
288
- }
289
- } catch (Exception $e) {
290
- $helper->writeError('Failed to exlude lists: ' . $e->getMessage());
291
- }
292
- }
293
- }
294
-
295
  /**
296
  * Create Delivery With Order Details
297
  */
298
  protected function _makeDelivery()
299
  {
 
300
  try {
301
- // Get Delivery Object
302
- $this->_helper->writeDebug(' Creating Delivery Row');
303
 
304
- /** @var $deliveryRow Bronto_Api_Delivery_Row */
305
- $deliveryRow = $this->getDeliveryRow();
306
-
307
- // Get Order Object
308
- /** @var $order Mage_Sales_Model_Order */
309
  $order = $this->getOrder();
310
-
311
- // Get Contact Object
312
- $this->_helper->writeDebug(' Creating Contact Object for email: ' . $order->getCustomerEmail());
313
- /** @var $contact Bronto_Api_Contact_Row */
314
- $contact = $this->getContact();
315
-
316
- // Create Recipient
317
- $deliveryRecipientObject = array(
318
- 'type' => 'contact',
319
- 'id' => $contact->id
320
  );
321
- $exclusionRecipients = Mage::getModel('bronto_common/list', 'bronto_reviews')
322
- ->addAdditionalRecipients($order->getStoreId());
323
- array_unshift($exclusionRecipients, $deliveryRecipientObject);
324
-
325
- // Create Send Time
326
- $sendTime = date('c', strtotime('+' . abs($this->_helper->getReviewSendPeriod('store', $order->getStoreId())) . ' days'));
327
- $this->_helper->writeDebug(' Delivery being set for ' . $sendTime);
328
-
329
- // Create Delivery Row
330
- $deliveryRow->start = $sendTime;
331
- $deliveryRow->messageId = $this->_helper->getReviewSendMessage('store', $order->getStoreId());
332
- $deliveryRow->type = 'marketing';
333
- $deliveryRow->fromEmail = $this->_helper->getReviewSenderEmail('store', $order->getStoreId());
334
- $deliveryRow->fromName = $this->_helper->getReviewSenderName('store', $order->getStoreId());
335
- $deliveryRow->replyEmail = $this->_helper->getReviewReplyTo('store', $order->getStoreId());
336
- $deliveryRow->recipients = $exclusionRecipients;
337
- $deliveryRow->fields = $this->_buildFields();
338
-
339
- // Save Delivery
340
- $this->_helper->writeDebug(' Saving Delivery Row');
341
- $deliveryRow->save();
342
-
343
- // Verbose Logging
344
- $this->_helper->writeVerboseDebug('===== FLUSH =====', 'bronto_reviews_api.log');
345
- $this->_helper->writeVerboseDebug(var_export($this->getDeliveryObject()->getApi()->getLastRequest(), true), 'bronto_reviews_api.log');
346
- $this->_helper->writeVerboseDebug(var_export($this->getDeliveryObject()->getApi()->getLastResponse(), true), 'bronto_reviews_api.log');
347
-
348
- if ($deliveryRow->hasError()) {
349
- Mage::throwException($deliveryRow->getErrorCode() . ' ' . $deliveryRow->getErrorMessage());
350
  } else {
351
- $this->setDeliveryId($deliveryRow->id);
352
- $this->_helper->writeLog("Review Request sent to {$order->getCustomerEmail()}. Delivery ID: {$deliveryRow->id}");
353
  }
354
  } catch (Exception $e) {
355
- $this->_helper->writeError('Bronto Failed creating apiObject:' . $e->getMessage());
356
- }
357
- }
358
-
359
- /**
360
- * Get array of fields for delivery
361
- *
362
- * @return array
363
- */
364
- protected function _buildFields()
365
- {
366
- /** @var $order Mage_Sales_Model_Order */
367
- $order = $this->getOrder();
368
-
369
- // Build Fields
370
- $fields = array(
371
- array('name' => 'orderCustomerName', 'type' => 'html', 'content' => $order->getCustomerName()),
372
- array('name' => 'orderIncrementId', 'type' => 'html', 'content' => $order->getIncrementId()),
373
- array('name' => 'orderCreatedAt', 'type' => 'html', 'content' => $order->getCreatedAt()),
374
- );
375
-
376
- // Cycle through order items and create fields
377
- $productInc = 1;
378
- foreach ($order->getAllVisibleItems() as $item) {
379
- // Get Store ID from Order
380
- $storeId = $order->getStoreId();
381
-
382
- /** @var Mage_Catalog_Model_Product $product */
383
- $product = Mage::getModel('catalog/product')->setStoreId($storeId)->load($item->getProductId());
384
-
385
- // Build Product URL with Suffix Config
386
- $productUrl = Mage::helper('bronto_order')->getItemUrl($item, $product, $storeId);
387
- $productUrl .= ltrim($this->_helper->getProductUrlSuffix('store', $storeId), '/');
388
-
389
- $reviewUrl = $this->_helper->getReviewsUrl($product, $storeId);
390
- $reviewUrl .= ltrim($this->_helper->getProductUrlSuffix('store', $storeId), '/');
391
-
392
- // Add Reviews Url
393
- $fields[] = array(
394
- 'name' => 'reviewUrl_' . $productInc,
395
- 'type' => 'html',
396
- 'content' => $reviewUrl
397
- );
398
-
399
- // Add Product Name Field
400
- $fields[] = array(
401
- 'name' => 'productName_' . $productInc,
402
- 'type' => 'html',
403
- 'content' => $item->getName()
404
- );
405
-
406
- // Add Product Image Field
407
- $fields[] = array(
408
- 'name' => 'productImgUrl_' . $productInc,
409
- 'type' => 'html',
410
- 'content' => Mage::helper('bronto_order')->getItemImg($item, $product, $storeId)
411
- );
412
-
413
- // Add Product URL Field
414
- $fields[] = array(
415
- 'name' => 'productUrl_' . $productInc,
416
- 'type' => 'html',
417
- 'content' => $productUrl
418
- );
419
-
420
- // Increment Count
421
- $productInc++;
422
  }
423
-
424
- return $fields;
425
  }
426
  }
38
  return $this;
39
  }
40
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  /**
42
  * Set Order to use
43
  *
231
  $delivery = $this->getDeliveryObject();
232
  $result = $delivery->update(array('id' => $deliveryId, 'status' => 'skipped'));
233
  if ($result->hasErrors()) {
234
+ $errors = array();
235
+ foreach ($result->getErrors() as $soapFault) {
236
+ $errors[] = $soapFault['code'] . ": " . $soapFault['message'];
237
+ }
238
+ $error = implode('<br />', $errors);
239
 
240
  Mage::throwException($error);
241
  }
244
  }
245
  }
246
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
247
  /**
248
  * Create Delivery With Order Details
249
  */
250
  protected function _makeDelivery()
251
  {
252
+ $helper = $this->_helper;
253
  try {
 
 
254
 
 
 
 
 
 
255
  $order = $this->getOrder();
256
+ $storeId = $order->getStoreId();
257
+ $sender = array(
258
+ 'name' => $helper->getReviewSenderName('store', $storeId),
259
+ 'email' => $helper->getReviewSenderEmail('store', $storeId)
 
 
 
 
 
 
260
  );
261
+
262
+ $message = new Bronto_Api_Message_Row();
263
+ $message->id = $helper->getReviewSendMessage('store', $storeId);
264
+
265
+ $helper->writeDebug(' Creating review delivery...');
266
+ $message = Mage::getModel('bronto_reviews/message')
267
+ ->setDesignConfig(array('area' => 'frontend', 'store' => $storeId))
268
+ ->setSalesRule($helper->getDefaultRule('store', $storeId))
269
+ ->setProductRecommendation($helper->getDefaultRecommendation('store', $storeId))
270
+ ->setTemplateSendType('marketing')
271
+ ->setOrderId($order->getId())
272
+ ->sendTransactional(
273
+ $message,
274
+ $sender,
275
+ array($order->getCustomerEmail()),
276
+ array($order->getCustomerName()),
277
+ array('order' => $order),
278
+ $storeId
279
+ );
280
+ if ($message->getSentSuccess()) {
281
+ $helper->writeDebug(' Successfully created delivery.');
 
 
 
 
 
 
 
 
282
  } else {
283
+ $helper->writeError(' Failed to sent the message.');
 
284
  }
285
  } catch (Exception $e) {
286
+ $helper->writeError('Bronto Failed creating apiObject:' . $e->getMessage());
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
287
  }
 
 
288
  }
289
  }
app/code/community/Bronto/Reviews/Model/Queue.php CHANGED
@@ -12,15 +12,14 @@ class Bronto_Reviews_Model_Queue extends Mage_Core_Model_Abstract
12
  parent::_construct();
13
  $this->_init('bronto_reviews/queue');
14
  }
15
-
16
- public function load($id = false, $column = false)
17
  {
18
  parent::load($id, 'order_id');
19
-
20
  if (!$this->getId()) {
21
  $this->setId($id);
22
  }
23
-
24
  return $this;
25
  }
26
- }
12
  parent::_construct();
13
  $this->_init('bronto_reviews/queue');
14
  }
15
+
16
+ public function load($id, $column = null)
17
  {
18
  parent::load($id, 'order_id');
 
19
  if (!$this->getId()) {
20
  $this->setId($id);
21
  }
22
+
23
  return $this;
24
  }
25
+ }
app/code/community/Bronto/Reviews/Model/System/Config/Source/Orderstatus.php CHANGED
@@ -11,13 +11,23 @@ class Bronto_Reviews_Model_System_Config_Source_Orderstatus
11
  */
12
  public function toOptionArray()
13
  {
14
- $status = Mage::getModel('sales/order_status')->getCollection();
15
  $statArray = array();
16
- foreach ($status as $stat) {
17
- $statArray[] = array(
18
- 'value' => $stat->getStatus(),
19
- 'label' => $stat->getLabel()
20
- );
 
 
 
 
 
 
 
 
 
 
 
21
  }
22
  return $statArray;
23
 
@@ -50,4 +60,4 @@ class Bronto_Reviews_Model_System_Config_Source_Orderstatus
50
  }
51
  return $statArray;
52
  }
53
- }
11
  */
12
  public function toOptionArray()
13
  {
 
14
  $statArray = array();
15
+ if (Mage::helper('bronto_common')->isVersionMatch(Mage::getVersionInfo(), 1, array(array('edition' => 'Enterprise', 'major' => 9)))) {
16
+ $status = Mage::getModel('sales/order_config')->getStatuses();
17
+ foreach ($status as $value => $label) {
18
+ $statArray[] = array(
19
+ 'value' => $value,
20
+ 'label' => $label
21
+ );
22
+ }
23
+ } else {
24
+ $status = Mage::getModel('sales/order_status')->getCollection();
25
+ foreach ($status as $stat) {
26
+ $statArray[] = array(
27
+ 'value' => $stat->getStatus(),
28
+ 'label' => $stat->getLabel()
29
+ );
30
+ }
31
  }
32
  return $statArray;
33
 
60
  }
61
  return $statArray;
62
  }
63
+ }
app/code/community/Bronto/Reviews/etc/system.xml CHANGED
@@ -87,12 +87,38 @@
87
  <show_in_store>1</show_in_store>
88
  <validate>validate-select required-entry</validate>
89
  </message>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  <url_suffix>
91
  <label>URL Suffix</label>
92
  <depends><enabled>1</enabled></depends>
93
  <frontend_type>text</frontend_type>
94
  <comment><![CDATA[This suffix will be added to both the Product URL and the Review URL.<br />Default: &quot;<code>#review-form</code>&quot;]]></comment>
95
- <sort_order>31</sort_order>
96
  <show_in_default>1</show_in_default>
97
  <show_in_website>1</show_in_website>
98
  <show_in_store>1</show_in_store>
87
  <show_in_store>1</show_in_store>
88
  <validate>validate-select required-entry</validate>
89
  </message>
90
+ <default_coupon>
91
+ <label>Shopping Cart Price Rule</label>
92
+ <depends>
93
+ <enabled>1</enabled>
94
+ </depends>
95
+ <frontend_type>select</frontend_type>
96
+ <source_model>bronto_common/system_config_source_coupon</source_model>
97
+ <sort_order>31</sort_order>
98
+ <show_in_default>1</show_in_default>
99
+ <show_in_website>1</show_in_website>
100
+ <show_in_store>1</show_in_store>
101
+ <comment><![CDATA[Use API tag <em>%%%%#couponCode%%%%</em> within your message in Bronto. You are responsible for ensuring the Shopping Cart Price Rule is active and valid, or else it may appear blank.]]></comment>
102
+ </default_coupon>
103
+ <default_recommendation>
104
+ <label>Product Recommendation</label>
105
+ <depends>
106
+ <enabled>1</enabled>
107
+ </depends>
108
+ <frontend_type>select</frontend_type>
109
+ <source_model>bronto_product/recommendation</source_model>
110
+ <sort_order>32</sort_order>
111
+ <show_in_default>1</show_in_default>
112
+ <show_in_website>1</show_in_website>
113
+ <show_in_store>1</show_in_store>
114
+ <comment><![CDATA[Inject related product content in the message. Recommendations are created in <strong>Promotions</strong> &raquo; <strong>Bronto Product Recommendations]]></comment>
115
+ </default_recommendation>
116
  <url_suffix>
117
  <label>URL Suffix</label>
118
  <depends><enabled>1</enabled></depends>
119
  <frontend_type>text</frontend_type>
120
  <comment><![CDATA[This suffix will be added to both the Product URL and the Review URL.<br />Default: &quot;<code>#review-form</code>&quot;]]></comment>
121
+ <sort_order>33</sort_order>
122
  <show_in_default>1</show_in_default>
123
  <show_in_website>1</show_in_website>
124
  <show_in_store>1</show_in_store>
app/code/community/Bronto/Verify/Block/Adminhtml/System/Config/Form/Magecron.php CHANGED
@@ -17,23 +17,31 @@ class Bronto_Verify_Block_Adminhtml_System_Config_Form_Magecron
17
  */
18
  protected function _getFooterHtml($element)
19
  {
 
 
20
  $html = "<tr><td>&nbsp;</td>
21
- <td id=\"bronto-magecron-example\" colspan=\"3\"><strong style=\"margin:5px;\">To setup the cron script, you will need to add a command to your crontab file. Here are some examples:</strong>
 
 
 
22
  <div style=\"border:1px solid #ccc; padding:5px; margin:5px;\">
 
 
23
  <strong>To run the API Retry Cron every 2 minutes:</strong>
24
- <pre>*/2 * * * * rot /usr/bin/php /var/www/magento/shell/bronto/cron.php -a run -t api</pre>
25
  <strong>To run the Reminder Cron every 15 minutes:</strong>
26
- <pre>*/15 * * * * root /usr/bin/php /var/www/magento/shell/bronto/cron.php -a run -t reminder</pre>
27
  <strong>To run the Order Import Cron once Daily at Midnight:</strong>
28
- <pre>0 0 * * * root /usr/bin/php /var/www/magento/shell/bronto/cron.php -a run -t order</pre>
 
 
29
  <strong>To run the Customer Import Cron twice Daily:</strong>
30
- <pre>0 */2 * * * root /usr/bin/php /var/www/magento/shell/bronto/cron.php -a run -t customer</pre>
31
  <strong>To run the Newsletter Opt-In Cron every 30 minutes:</strong>
32
- <pre>*/30 * * * * root /usr/bin/php /var/www/magento/shell/bronto/cron.php -a run -t newsletter</pre>
33
  <strong>To run all Module Crons once Daily:</strong>
34
- <pre>0 0 * * * root /usr/bin/php /var/www/magento/shell/bronto/cron.php -a run</pre>
35
  </div>
36
- <em style=\"margin:5px;\">* Note: You will need to change the owner, php path, and path to magento to match your environment.</em>
37
  </td></tr>";
38
 
39
  return $html . parent::_getFooterHtml($element);
17
  */
18
  protected function _getFooterHtml($element)
19
  {
20
+ $cronPath = Mage::getBaseDir() . '/shell/bronto/cron.php';
21
+ $phpPath = exec('which php');
22
  $html = "<tr><td>&nbsp;</td>
23
+ <td id=\"bronto-magecron-example\" colspan=\"3\">
24
+ <em style=\"margin:5px;\">* Note: You will need to change the \$CRON_USER to match the cron user in your environment.</em>
25
+ <br/>
26
+ <strong style=\"margin:5px;\">To setup the cron script, you will need to add a command to your crontab file. Here are some examples:</strong>
27
  <div style=\"border:1px solid #ccc; padding:5px; margin:5px;\">
28
+ <strong>To run the API Send Cron every minute:</strong>
29
+ <pre>* * * * * \$CRON_USER {$phpPath} {$cronPath} -a run -t send</pre>
30
  <strong>To run the API Retry Cron every 2 minutes:</strong>
31
+ <pre>*/2 * * * * \$CRON_USER {$phpPath} {$cronPath} -a run -t api</pre>
32
  <strong>To run the Reminder Cron every 15 minutes:</strong>
33
+ <pre>*/15 * * * * \$CRON_USER {$phpPath} {$cronPath} -a run -t reminder</pre>
34
  <strong>To run the Order Import Cron once Daily at Midnight:</strong>
35
+ <pre>0 0 * * * \$CRON_USER {$phpPath} {$cronPath} -a run -t order</pre>
36
+ <strong>To run the Product Recommendation Cron once Daily at Midnight:</strong>
37
+ <pre>0 0 * * * \$CRON_USER {$phpPath} {$cronPath} -a run -t product</pre>
38
  <strong>To run the Customer Import Cron twice Daily:</strong>
39
+ <pre>0 */2 * * * \$CRON_USER {$phpPath} {$cronPath} -a run -t customer</pre>
40
  <strong>To run the Newsletter Opt-In Cron every 30 minutes:</strong>
41
+ <pre>*/30 * * * * \$CRON_USER {$phpPath} {$cronPath} -a run -t newsletter</pre>
42
  <strong>To run all Module Crons once Daily:</strong>
43
+ <pre>0 0 * * * \$CRON_USER {$phpPath} {$cronPath} -a run</pre>
44
  </div>
 
45
  </td></tr>";
46
 
47
  return $html . parent::_getFooterHtml($element);
app/code/community/Bronto/Verify/Model/Core/Config.php CHANGED
@@ -1012,7 +1012,7 @@ class Bronto_Verify_Model_Core_Config
1012
  *
1013
  * @return Bronto_Verify_Model_Core_Config_Base|Mage_Core_Model_Config_Base
1014
  */
1015
- public function loadModulesConfiguration($fileName, Mage_Core_Model_Config_Base $mergeToObject = null, $mergeModel = null)
1016
  {
1017
  $disableLocalModules = !$this->_canUseLocalModules();
1018
 
1012
  *
1013
  * @return Bronto_Verify_Model_Core_Config_Base|Mage_Core_Model_Config_Base
1014
  */
1015
+ public function loadModulesConfiguration($fileName, Bronto_Verify_Model_Core_Config_Base $mergeToObject = null, $mergeModel = null)
1016
  {
1017
  $disableLocalModules = !$this->_canUseLocalModules();
1018
 
app/code/community/Bronto/Verify/Model/Path/Locator/IteratorAbstract.php CHANGED
@@ -24,7 +24,7 @@ abstract class Bronto_Verify_Model_Path_Locator_IteratorAbstract
24
  *
25
  * @param Bronto_Verify_Model_Path_Locator_LocatorInterface $iterator
26
  */
27
- public function __construct(Bronto_Verify_Model_Path_Locator_LocatorInterface $iterator)
28
  {
29
  $this->_iterator = $iterator;
30
  }
24
  *
25
  * @param Bronto_Verify_Model_Path_Locator_LocatorInterface $iterator
26
  */
27
+ public function __construct($iterator)
28
  {
29
  $this->_iterator = $iterator;
30
  }
app/code/community/Bronto/Verify/Model/Roundtrip.php CHANGED
@@ -48,7 +48,8 @@ class Bronto_Verify_Model_Roundtrip
48
  ob_end_clean();
49
 
50
  // Set setting and return results
51
- if (200 == $retcode) {
 
52
  $this->_helper->writeDebug('Connection status SUCCESS');
53
  $this->_helper->setStatus($this->_helper->getPath('roundtrip_status'), '1');
54
  } else {
48
  ob_end_clean();
49
 
50
  // Set setting and return results
51
+ // If the token is valid, we can safely assume the API is up
52
+ if (200 == $retcode || Mage::helper('bronto_verify/apitoken')->getStatus()) {
53
  $this->_helper->writeDebug('Connection status SUCCESS');
54
  $this->_helper->setStatus($this->_helper->getPath('roundtrip_status'), '1');
55
  } else {
app/code/community/Bronto/Verify/Model/System/Config/Backend/Magecron.php CHANGED
@@ -23,6 +23,7 @@ class Bronto_Verify_Model_System_Config_Backend_Magecron extends Mage_Core_Model
23
  // If disabling using Magento Cron, delete from config
24
  if ($this->getValue() == '0') {
25
  $module = array_shift(explode('/', $realPath));
 
26
  $stringPath = Mage::helper($module)->getCronStringPath();
27
  $modelPath = Mage::helper($module)->getCronModelPath();
28
 
@@ -68,4 +69,4 @@ class Bronto_Verify_Model_System_Config_Backend_Magecron extends Mage_Core_Model
68
 
69
  return $this;
70
  }
71
- }
23
  // If disabling using Magento Cron, delete from config
24
  if ($this->getValue() == '0') {
25
  $module = array_shift(explode('/', $realPath));
26
+ $module = $module == 'bronto_api' ? 'bronto_common/api' : $module;
27
  $stringPath = Mage::helper($module)->getCronStringPath();
28
  $modelPath = Mage::helper($module)->getCronModelPath();
29
 
69
 
70
  return $this;
71
  }
72
+ }
app/code/community/Bronto/Verify/etc/config.xml CHANGED
@@ -61,6 +61,7 @@
61
  <bronto_customer-settings-mage_cron>1</bronto_customer-settings-mage_cron>
62
  <bronto_newsletter-settings-mage_cron>1</bronto_newsletter-settings-mage_cron>
63
  <bronto_order-settings-mage_cron>1</bronto_order-settings-mage_cron>
 
64
  <bronto_reminder-settings-mage_cron>1</bronto_reminder-settings-mage_cron>
65
  </cron_settings>
66
  <permissionchecker>
61
  <bronto_customer-settings-mage_cron>1</bronto_customer-settings-mage_cron>
62
  <bronto_newsletter-settings-mage_cron>1</bronto_newsletter-settings-mage_cron>
63
  <bronto_order-settings-mage_cron>1</bronto_order-settings-mage_cron>
64
+ <bronto_product-settings-mage_cron>1</bronto_product-settings-mage_cron>
65
  <bronto_reminder-settings-mage_cron>1</bronto_reminder-settings-mage_cron>
66
  </cron_settings>
67
  <permissionchecker>
app/code/community/Bronto/Verify/etc/system.xml CHANGED
@@ -190,12 +190,22 @@
190
  <![CDATA[This section is provided as an Advanced Option for handling the Cron processes for the Bronto Extension Modules. If you find that the Magento cron management system fails to trigger the cron processes for these modules, you may utilize the cron.php file provided with this extension. Simply set the 'Use Magento Cron' setting to 'No' for any modules you wish, click 'Save Config', and then follow the Cron configuration details below to set up the external cron.]]></comment>
191
  <expanded>0</expanded>
192
  <fields>
 
 
 
 
 
 
 
 
 
 
193
  <bronto_api-settings-mage_cron>
194
  <label>API Retry: Use Magento Cron</label>
195
  <frontend_type>select</frontend_type>
196
  <source_model>adminhtml/system_config_source_yesno</source_model>
197
  <backend_model>bronto_verify/system_config_backend_magecron</backend_model>
198
- <sort_order>0</sort_order>
199
  <show_in_default>1</show_in_default>
200
  <show_in_website>0</show_in_website>
201
  <show_in_store>0</show_in_store>
@@ -205,7 +215,7 @@
205
  <frontend_type>select</frontend_type>
206
  <source_model>adminhtml/system_config_source_yesno</source_model>
207
  <backend_model>bronto_verify/system_config_backend_magecron</backend_model>
208
- <sort_order>1</sort_order>
209
  <show_in_default>1</show_in_default>
210
  <show_in_website>0</show_in_website>
211
  <show_in_store>0</show_in_store>
@@ -215,7 +225,7 @@
215
  <frontend_type>select</frontend_type>
216
  <source_model>adminhtml/system_config_source_yesno</source_model>
217
  <backend_model>bronto_verify/system_config_backend_magecron</backend_model>
218
- <sort_order>2</sort_order>
219
  <show_in_default>1</show_in_default>
220
  <show_in_website>0</show_in_website>
221
  <show_in_store>0</show_in_store>
@@ -225,17 +235,27 @@
225
  <frontend_type>select</frontend_type>
226
  <source_model>adminhtml/system_config_source_yesno</source_model>
227
  <backend_model>bronto_verify/system_config_backend_magecron</backend_model>
228
- <sort_order>3</sort_order>
229
  <show_in_default>1</show_in_default>
230
  <show_in_website>0</show_in_website>
231
  <show_in_store>0</show_in_store>
232
  </bronto_order-settings-mage_cron>
 
 
 
 
 
 
 
 
 
 
233
  <bronto_reminder-settings-mage_cron>
234
  <label>Reminder Emails: Use Magento Cron</label>
235
  <frontend_type>select</frontend_type>
236
  <source_model>adminhtml/system_config_source_yesno</source_model>
237
  <backend_model>bronto_verify/system_config_backend_magecron</backend_model>
238
- <sort_order>4</sort_order>
239
  <show_in_default>1</show_in_default>
240
  <show_in_website>0</show_in_website>
241
  <show_in_store>0</show_in_store>
190
  <![CDATA[This section is provided as an Advanced Option for handling the Cron processes for the Bronto Extension Modules. If you find that the Magento cron management system fails to trigger the cron processes for these modules, you may utilize the cron.php file provided with this extension. Simply set the 'Use Magento Cron' setting to 'No' for any modules you wish, click 'Save Config', and then follow the Cron configuration details below to set up the external cron.]]></comment>
191
  <expanded>0</expanded>
192
  <fields>
193
+ <bronto_api-queue_settings-mage_cron>
194
+ <label>API Send: Use Magento Cron</label>
195
+ <frontend_type>select</frontend_type>
196
+ <source_model>adminhtml/system_config_source_yesno</source_model>
197
+ <backend_model>bronto_verify/system_config_backend_magecron</backend_model>
198
+ <sort_order>0</sort_order>
199
+ <show_in_default>1</show_in_default>
200
+ <show_in_website>0</show_in_website>
201
+ <show_in_store>0</show_in_store>
202
+ </bronto_api-queue_settings-mage_cron>
203
  <bronto_api-settings-mage_cron>
204
  <label>API Retry: Use Magento Cron</label>
205
  <frontend_type>select</frontend_type>
206
  <source_model>adminhtml/system_config_source_yesno</source_model>
207
  <backend_model>bronto_verify/system_config_backend_magecron</backend_model>
208
+ <sort_order>1</sort_order>
209
  <show_in_default>1</show_in_default>
210
  <show_in_website>0</show_in_website>
211
  <show_in_store>0</show_in_store>
215
  <frontend_type>select</frontend_type>
216
  <source_model>adminhtml/system_config_source_yesno</source_model>
217
  <backend_model>bronto_verify/system_config_backend_magecron</backend_model>
218
+ <sort_order>2</sort_order>
219
  <show_in_default>1</show_in_default>
220
  <show_in_website>0</show_in_website>
221
  <show_in_store>0</show_in_store>
225
  <frontend_type>select</frontend_type>
226
  <source_model>adminhtml/system_config_source_yesno</source_model>
227
  <backend_model>bronto_verify/system_config_backend_magecron</backend_model>
228
+ <sort_order>3</sort_order>
229
  <show_in_default>1</show_in_default>
230
  <show_in_website>0</show_in_website>
231
  <show_in_store>0</show_in_store>
235
  <frontend_type>select</frontend_type>
236
  <source_model>adminhtml/system_config_source_yesno</source_model>
237
  <backend_model>bronto_verify/system_config_backend_magecron</backend_model>
238
+ <sort_order>4</sort_order>
239
  <show_in_default>1</show_in_default>
240
  <show_in_website>0</show_in_website>
241
  <show_in_store>0</show_in_store>
242
  </bronto_order-settings-mage_cron>
243
+ <bronto_product-settings-mage_cron>
244
+ <label>Product Recommendations: Use Magento Cron</label>
245
+ <frontend_type>select</frontend_type>
246
+ <source_model>adminhtml/system_config_source_yesno</source_model>
247
+ <backend_model>bronto_verify/system_config_backend_magecron</backend_model>
248
+ <sort_order>5</sort_order>
249
+ <show_in_default>1</show_in_default>
250
+ <show_in_website>0</show_in_website>
251
+ <show_in_store>0</show_in_store>
252
+ </bronto_product-settings-mage_cron>
253
  <bronto_reminder-settings-mage_cron>
254
  <label>Reminder Emails: Use Magento Cron</label>
255
  <frontend_type>select</frontend_type>
256
  <source_model>adminhtml/system_config_source_yesno</source_model>
257
  <backend_model>bronto_verify/system_config_backend_magecron</backend_model>
258
+ <sort_order>6</sort_order>
259
  <show_in_default>1</show_in_default>
260
  <show_in_website>0</show_in_website>
261
  <show_in_store>0</show_in_store>
app/design/adminhtml/default/default/layout/bronto/common.xml CHANGED
@@ -23,7 +23,9 @@
23
  <block type="bronto_common/adminhtml_system_config_guide" name="bronto_reminder.adminhtml.guide" as="bronto_reminder_guide" template="bronto/reminder/guide.phtml" />
24
  <block type="bronto_common/adminhtml_system_config_guide" name="bronto_verify.adminhtml.guide" as="bronto_verify_guide" template="bronto/verify/guide.phtml" />
25
  <block type="bronto_common/adminhtml_system_config_guide" name="bronto_popup.adminhtml.guide" as="bronto_popup_guide" template="bronto/popup/guide.phtml" />
 
26
  <block type="bronto_common/adminhtml_system_config_guide" name="bronto_reviews.adminhtml.guide" as="bronto_reviews_guide" template="bronto/reviews/guide.phtml" />
 
27
  </block>
28
  </reference>
29
  </adminhtml_system_config_edit>
23
  <block type="bronto_common/adminhtml_system_config_guide" name="bronto_reminder.adminhtml.guide" as="bronto_reminder_guide" template="bronto/reminder/guide.phtml" />
24
  <block type="bronto_common/adminhtml_system_config_guide" name="bronto_verify.adminhtml.guide" as="bronto_verify_guide" template="bronto/verify/guide.phtml" />
25
  <block type="bronto_common/adminhtml_system_config_guide" name="bronto_popup.adminhtml.guide" as="bronto_popup_guide" template="bronto/popup/guide.phtml" />
26
+ <block type="bronto_common/adminhtml_system_config_guide" name="bronto_coupon.adminhtml.guide" as="bronto_coupon_guide" template="bronto/coupon/guide.phtml" />
27
  <block type="bronto_common/adminhtml_system_config_guide" name="bronto_reviews.adminhtml.guide" as="bronto_reviews_guide" template="bronto/reviews/guide.phtml" />
28
+ <block type="bronto_common/adminhtml_system_config_guide" name="bronto_product.adminhtml.guide" as="bronto_product_guide" template="bronto/product/guide.phtml" />
29
  </block>
30
  </reference>
31
  </adminhtml_system_config_edit>
app/design/adminhtml/default/default/template/bronto/api/guide.phtml CHANGED
@@ -138,12 +138,54 @@
138
  autoFocus: true, closeOnEscape: true,
139
  description: "<?php echo $this->__('This is where you can verify the status of the API Token and the API Connection. Just click the `Verify Now` button to the right of each one to update the status.') ?>",
140
  id: "bronto_api-api_status",
141
- next: "bronto_api-mage_cron",
142
  position: 9,
143
  title: "<?php echo $this->__('API Status') ?>",
144
  width: 200
145
  });
146
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
  /**
148
  * Explain Using Magento Cron
149
  */
@@ -160,7 +202,7 @@
160
  id: "bronto_api-mage_cron",
161
  next: "bronto_api-attempt_threshold",
162
  position: 10,
163
- title: "<?php echo $this->__('Cron Options') ?>",
164
  width: 200
165
  });
166
 
@@ -183,12 +225,11 @@
183
  width: 200
184
  });
185
 
186
-
187
  /**
188
  * Cron Table
189
  */
190
  guiders.createGuider({
191
- attachTo: '.bronto-cron-table',
192
  buttons: [
193
  {name: "<?php echo $this->__('Back') ?>"},
194
  {name: "<?php echo $this->__('Next') ?>"},
@@ -202,7 +243,7 @@
202
  id: "bronto_api-cron_table",
203
  next: "bronto_api-soap_options",
204
  position: 10,
205
- title: "<?php echo $this->__('Cron Table') ?>",
206
  width: 200
207
  });
208
 
138
  autoFocus: true, closeOnEscape: true,
139
  description: "<?php echo $this->__('This is where you can verify the status of the API Token and the API Connection. Just click the `Verify Now` button to the right of each one to update the status.') ?>",
140
  id: "bronto_api-api_status",
141
+ next: "bronto_api-send_mage_cron",
142
  position: 9,
143
  title: "<?php echo $this->__('API Status') ?>",
144
  width: 200
145
  });
146
 
147
+ /**
148
+ * Explain Using Magento Cron
149
+ */
150
+ <?php $advancedCronLink = $this->helper('bronto_common')->getScopeUrl('/system_config/edit/section/bronto_verify'); ?>
151
+ guiders.createGuider({
152
+ attachTo: '#row_bronto_api_queue_settings_mage_cron',
153
+ buttons: [
154
+ {name: "<?php echo $this->__('Back') ?>"},
155
+ {name: "<?php echo $this->__('Next') ?>"},
156
+ {name: "<?php echo $this->__('Close') ?>"}
157
+ ],
158
+ autoFocus: true, closeOnEscape: true,
159
+ description: "<?php echo $this->__('The `Use Magento Cron` setting, when set to No, allows you to create your own crontab entry on your server instead of using Magento\'s cron system. You should only change this if you are experiencing issues where the cron job for this module fails to run due to too many jobs.%sYou can find more details under the %s, including examples of how to configure the cron job.', '<br /><br />', '<a href=\"' . $advancedCronLink . '\" title=\"Advanced &raquo; Cron Settings\">Advanced Tab</a>') ?>",
160
+ id: "bronto_api-send_mage_cron",
161
+ next: "bronto_api-send_cron_table",
162
+ position: 10,
163
+ title: "<?php echo $this->__('Send Cron Options') ?>",
164
+ width: 200
165
+ });
166
+
167
+ /**
168
+ * Cron Table
169
+ */
170
+ guiders.createGuider({
171
+ attachTo: '.bronto-cron-table',
172
+ buttons: [
173
+ {name: "<?php echo $this->__('Back') ?>"},
174
+ {name: "<?php echo $this->__('Next') ?>"},
175
+ {name: "<?php echo $this->__('Close') ?>"}
176
+ ],
177
+ autoFocus: true,
178
+ closeOnEscape: true,
179
+ highlight: '.bronto-cron-table',
180
+ overlay: true,
181
+ description: "<?php echo $this->__('This table shows you the recent history of the Cron Jobs that are pending, running, have successfully completed, or have failed upon execution.') ?>",
182
+ id: "bronto_api-send_cron_table",
183
+ next: "bronto_api-mage_cron",
184
+ position: 10,
185
+ title: "<?php echo $this->__('Send Cron Table') ?>",
186
+ width: 200
187
+ });
188
+
189
  /**
190
  * Explain Using Magento Cron
191
  */
202
  id: "bronto_api-mage_cron",
203
  next: "bronto_api-attempt_threshold",
204
  position: 10,
205
+ title: "<?php echo $this->__('Retry Cron Options') ?>",
206
  width: 200
207
  });
208
 
225
  width: 200
226
  });
227
 
 
228
  /**
229
  * Cron Table
230
  */
231
  guiders.createGuider({
232
+ attachTo: '#bronto_api_settings ~ .bronto-cron',
233
  buttons: [
234
  {name: "<?php echo $this->__('Back') ?>"},
235
  {name: "<?php echo $this->__('Next') ?>"},
243
  id: "bronto_api-cron_table",
244
  next: "bronto_api-soap_options",
245
  position: 10,
246
+ title: "<?php echo $this->__('Retry Cron Table') ?>",
247
  width: 200
248
  });
249
 
app/design/adminhtml/default/default/template/bronto/common/suppressed.phtml CHANGED
@@ -28,6 +28,19 @@
28
  });
29
  });
30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  function loadSuppressionTable(page)
32
  {
33
  new Ajax.Request('<?php echo $this->getAjaxUrl() ?>page/' + page + '/', {
28
  });
29
  });
30
 
31
+ function resetAllSuppressed()
32
+ {
33
+ if (confirm("This will reset all suppressed entries in the queue.\n\nYou can then click on Run Now to perform an immediate retry.\n\nAre you sure you want to do this?")) {
34
+ new Ajax.Request('<?php echo $this->getResetUrl(); ?>', {
35
+ method: 'post',
36
+ parameters: { suppressed: 1 },
37
+ onComplete: function(transport) {
38
+ window.location.reload(true);
39
+ }
40
+ });
41
+ }
42
+ }
43
+
44
  function loadSuppressionTable(page)
45
  {
46
  new Ajax.Request('<?php echo $this->getAjaxUrl() ?>page/' + page + '/', {
app/design/adminhtml/default/default/template/bronto/coupon/guide.phtml ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if ($this->isBrontoSection('bronto_coupon')): ?>
2
+
3
+ /**
4
+ * Introduce them to the guide and provide instructions
5
+ */
6
+ guiders.createGuider({
7
+ buttons: [
8
+ {name: "<?php echo $this->__("Let's Get Started!") ?>", onclick: guiders.next},
9
+ {name: "<?php echo $this->__("No Thanks") ?>", onclick: guiders.hideAll}
10
+ ],
11
+ buttonCustomHTML: dontShowButtonHtml,
12
+ description: "<?php echo $this->__('This module provides you quick access to add your Bronto Coupon Manager Account ID.') ?>",
13
+ id: "start",
14
+ next: "bronto_coupon-site_hash",
15
+ overlay: true, closeOnEscape: true,
16
+ title: "Bronto Extension - <?php echo $this->__('Coupon Manager') ?>",
17
+ width: 600
18
+ });
19
+
20
+ /**
21
+ * Submit Script
22
+ */
23
+ guiders.createGuider({
24
+ attachTo: '#bronto_coupon_settings_site_hash',
25
+ buttons: [
26
+ {name: "<?php echo $this->__('Back') ?>"},
27
+ {name: "<?php echo $this->__('Next') ?>", onclick: function() {
28
+ if (jQuery('#bronto_popup_settings_site_hash').val() == '') {
29
+ alert("Don't forget to add your site hash!");
30
+ } else {
31
+ guiders.next();
32
+ }
33
+ }},
34
+ {name: "<?php echo $this->__('Close') ?>"}
35
+ ],
36
+ autoFocus: true,
37
+ highlight: '#bronto_coupon_settings_site_hash',
38
+ overlay: true, closeOnEscape: true,
39
+ description: "<?php echo $this->__('Once you have your Coupon Manager Account ID, you can simply paste it here.') ?>",
40
+ id: "bronto_coupon-site_hash",
41
+ next: "bronto_coupon-save_config_first",
42
+ position: 1,
43
+ title: "<?php echo $this->__('Pasting your Account ID') ?>",
44
+ width: 250
45
+ });
46
+
47
+ /**
48
+ * Save Configuration
49
+ */
50
+ guiders.createGuider({
51
+ attachTo: 'button.save',
52
+ buttons: [
53
+ {name: "<?php echo $this->__('Back') ?>"},
54
+ {name: "<?php echo $this->__('Save Config') ?>", onclick: function() {
55
+ configForm.submit()
56
+ }},
57
+ {name: "<?php echo $this->__('Next') ?>"}
58
+ ],
59
+ autoFocus: true,
60
+ highlight: 'button.save',
61
+ overlay: true, closeOnEscape: true,
62
+ description: "<?php echo $this->__("Now that you have added your site hash, you need to save it. Click `Save Config` now.") ?>",
63
+ id: "bronto_coupon-save_config_first",
64
+ next: "scope",
65
+ position: 5,
66
+ title: "<?php echo $this->__('Save Config') ?>"
67
+ });
68
+
69
+ <?php if ($this->canShowGuide()): ?>
70
+ guiders.show('start');
71
+ <?php endif; ?>
72
+
73
+ <?php endif; ?>
app/design/adminhtml/default/default/template/bronto/newsletter/guide.phtml CHANGED
@@ -176,7 +176,7 @@
176
  closeOnEscape: true,
177
  description: "<?php echo $this->__(
178
  'The Checkout section contains all the configurations for the Newsletter Subscription checkbox that displays on checkout. ' .
179
- 'You can determine when it should show, if it will be checked by default, and the text to show as the label for it.'
180
  ) ?>",
181
  id: "bronto_newsletter-checkout_settings",
182
  next: "bronto_newsletter-contacts_settings",
176
  closeOnEscape: true,
177
  description: "<?php echo $this->__(
178
  'The Checkout section contains all the configurations for the Newsletter Subscription checkbox that displays on checkout. ' .
179
+ 'You can determine when and where it should show, if it will be checked by default, and the text to show as the label for it.'
180
  ) ?>",
181
  id: "bronto_newsletter-checkout_settings",
182
  next: "bronto_newsletter-contacts_settings",
app/design/adminhtml/default/default/template/bronto/product/guide.phtml ADDED
@@ -0,0 +1,191 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ($this->isBrontoSection('bronto_product')) : ?>
4
+ <?php if (!Mage::helper($this->getCurrentSection())->isEnabled()): ?>
5
+ /**
6
+ * Introduce them to the guide and provide instructions
7
+ */
8
+ guiders.createGuider({
9
+ buttons: [
10
+ {name: "<?php echo $this->__("Let's Get Started!") ?>", onclick: guiders.next},
11
+ {name: "<?php echo $this->__('No Thanks') ?>", onclick: guiders.hideAll}
12
+ ],
13
+ buttonCustomHTML: dontShowButtonHtml,
14
+ description: "<?php echo $this->__(
15
+ 'This module allows you to create Product Recommendation that appear in Transactional, Reminder, and Review Emails.%sLet\'s get you set up!%sReady to Go?%s',
16
+ '<br /><br />',
17
+ '<br /><br /><div style=\"text-align:right; font-weight:bold;\">',
18
+ '</div>'
19
+ ) ?>",
20
+ id: "start",
21
+ next: "bronto_product-enable",
22
+ overlay: true,
23
+ closeOnEscape: true,
24
+ title: "Bronto Extension - <?php echo $this->__('Product Recommendations') ?>",
25
+ width: 600
26
+ });
27
+
28
+ /**
29
+ * Enable the Module
30
+ */
31
+ guiders.createGuider({
32
+ attachTo: '#bronto_product_settings_enabled',
33
+ buttons: [
34
+ {name: "<?php echo $this->__('Back') ?>"},
35
+ {name: "<?php echo $this->__('Next') ?>", onclick: function() {
36
+ if (jQuery('#bronto_product_settings_enabled').val() == '1') {
37
+ guiders.next();
38
+ } else {
39
+ alert("<?php echo $this->__("Do not forget to enable the module") ?>");
40
+ }
41
+ }},
42
+ {name: "<?php echo $this->__('Close') ?>"}
43
+ ],
44
+ autoFocus: true,
45
+ closeOnEscape: true,
46
+ highlight: '#bronto_product_settings_enabled',
47
+ description: "<?php echo $this->__("Enable the module and expose some more options. Just set `Enable Module` to Yes and click `Save Config`.") ?>",
48
+ id: "bronto_product-enable",
49
+ next: "bronto_product-configure_cron",
50
+ position: 11,
51
+ overlay: true,
52
+ title: "<?php echo $this->__('Enable the Module') ?>",
53
+ width: 200
54
+ });
55
+
56
+ /**
57
+ * Configure Cron
58
+ */
59
+ guiders.createGuider({
60
+ attachTo: '#row_bronto_product_settings_mage_cron',
61
+ buttons: [
62
+ {name: "<?php echo $this->__('Back') ?>"},
63
+ {name: "<?php echo $this->__('Next') ?>"},
64
+ {name: "<?php echo $this->__('Close') ?>"}
65
+ ],
66
+ autoFocus: true,
67
+ closeOnEscape: true,
68
+ description: "<?php echo $this->__('These options allow you to configure the cron schedule creating content tags containing product recommendations.') ?>",
69
+ id: "bronto_product-configure_cron",
70
+ next: "bronto_product-save_config_first",
71
+ position: 10,
72
+ title: "<?php echo $this->__('Configure the Cron') ?>",
73
+ width: 200
74
+ });
75
+
76
+ /**
77
+ * Save Configuration
78
+ */
79
+ guiders.createGuider({
80
+ attachTo: 'button.save',
81
+ buttons: [
82
+ {name: "<?php echo $this->__('Back') ?>"},
83
+ {name: "<?php echo $this->__('Save Config') ?>", onclick: function() {
84
+ configForm.submit()
85
+ }},
86
+ {name: "<?php echo $this->__('Close') ?>"}
87
+ ],
88
+ autoFocus: true,
89
+ closeOnEscape: true,
90
+ highlight: 'button.save',
91
+ description: "<?php echo $this->__('Now that the initial settings have been configured, you should save them. Click `Save Config` now.') ?>",
92
+ id: "bronto_product-save_config_first",
93
+ next: "final",
94
+ position: 5,
95
+ overlay: true,
96
+ title: "<?php echo $this->__('Save Config') ?>"
97
+ });
98
+ <?php else : ?>
99
+ /**
100
+ * Continue Guide now that module is enabled
101
+ */
102
+ guiders.createGuider({
103
+ buttons: [
104
+ {name: "<?php echo $this->__('Continue with Guide') ?>", onclick: guiders.next},
105
+ {name: "<?php echo $this->__('No Thanks') ?>", onclick: guiders.hideAll}
106
+ ],
107
+ buttonCustomHTML: dontShowButtonHtml,
108
+ description: "<?php echo $this->__(
109
+ 'With the Product Recommendation module enabled, you can add related products to Transactional, Reminder, and Review Emails.%sLet\'s get started.%s',
110
+ '<br /><br /><div style=\"text-align:right; font-weight:bold;\">',
111
+ '</div>'
112
+ ) ?>",
113
+ id: "start",
114
+ next: "bronto_product-api_info",
115
+ closeOnEscape: true,
116
+ title: "Bronto Extension - <?php echo $this->__('Product Recommendation') ?>",
117
+ width: 600
118
+ });
119
+
120
+ /**
121
+ * Explain API info
122
+ */
123
+ guiders.createGuider({
124
+ attachTo: '#api_info',
125
+ buttons: [
126
+ {name: "<?php echo $this->__('Back') ?>"},
127
+ {name: "<?php echo $this->__('Next') ?>"},
128
+ {name: "<?php echo $this->__('Close') ?>"}
129
+ ],
130
+ onShow: function() {
131
+ jQuery('.bronto-help').css({ 'text-indent': 0, 'overflow': 'inherit' });
132
+ },
133
+ onHide: function() {
134
+ jQuery('.bronto-help').removeAttr('style');
135
+ },
136
+ autoFocus: true, closeOnEscape: true,
137
+ description: "<?php echo $this->__('Some new API tags are added for messages taking advantage of related product information. These tags are used for email based recommendations and content tag recommendations.'); ?>",
138
+ id: "bronto_product-api_info",
139
+ next: "bronto_product-mage_cron",
140
+ position: 10,
141
+ title: "<?php echo $this->__('API Tags') ?>",
142
+ width: 200
143
+ });
144
+
145
+ /**
146
+ * Explain Using Magento Cron
147
+ */
148
+ <?php $advancedCronLink = $this->helper('bronto_common')->getScopeUrl('/system_config/edit/section/bronto_verify'); ?>
149
+ guiders.createGuider({
150
+ attachTo: '#row_bronto_product_settings_mage_cron',
151
+ buttons: [
152
+ {name: "<?php echo $this->__('Back') ?>"},
153
+ {name: "<?php echo $this->__('Next') ?>"},
154
+ {name: "<?php echo $this->__('Close') ?>"}
155
+ ],
156
+ autoFocus: true, closeOnEscape: true,
157
+ description: "<?php echo $this->__('The `Use Magento Cron` setting, when set to No, allows you to create your own crontab entry on your server instead of using Magento\'s cron system. You should only change this if you are experiencing issues where the cron job for this module fails to run due to too many jobs.%sYou can find more details under the %s, including examples of how to configure the cron job.', '<br /><br />', '<a href=\"' . $advancedCronLink . '\" title=\"Advanced &raquo; Cron Settings\">Advanced Tab</a>') ?>",
158
+ id: "bronto_product-mage_cron",
159
+ next: "bronto_product-cron_table",
160
+ position: 10,
161
+ title: "<?php echo $this->__('Cron Options') ?>",
162
+ width: 200
163
+ });
164
+
165
+ /**
166
+ * Cron Table
167
+ */
168
+ guiders.createGuider({
169
+ attachTo: '.bronto-cron-table',
170
+ buttons: [
171
+ {name: "<?php echo $this->__('Back') ?>"},
172
+ {name: "<?php echo $this->__('Next') ?>"},
173
+ {name: "<?php echo $this->__('Close') ?>"}
174
+ ],
175
+ autoFocus: true,
176
+ closeOnEscape: true,
177
+ highlight: '.bronto-cron-table',
178
+ overlay: true,
179
+ description: "<?php echo $this->__('This table shows you the recent history of the Cron Jobs that are pending, running, have successfully completed, or have failed upon execution.%sThe cron job only applies to creating content tags from product recommendations.', '<br/><br/>') ?>",
180
+ id: "bronto_product-cron_table",
181
+ next: "final",
182
+ position: 10,
183
+ title: "<?php echo $this->__('Cron Table') ?>",
184
+ width: 200
185
+ });
186
+ <?php endif; ?>
187
+
188
+ <?php if ($this->canShowGuide()): ?>
189
+ guiders.show('start');
190
+ <?php endif; ?>
191
+ <?php endif; ?>
app/design/adminhtml/default/default/template/bronto/product/recommendation/button.phtml ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ $_element = $this->getElement();
4
+ $_note = $_element->getNote();
5
+ $_trId = $_element->getHtmlContainerId();
6
+ $_class = $_element->getFieldsetHtmlClass();
7
+ ?>
8
+ <?php if (!$_element->getNoDisplay()): ?>
9
+ <tr<?php if($_trId): ?> id="<?php echo $_trId ?>"<?php endif; ?>>
10
+ <?php if ($_element->getType()=='hidden'): ?>
11
+ <td colspan="2" class="hidden"><?php echo trim($_element->getElementHtml()) ?></td>
12
+ <?php else: ?>
13
+ <?php $html = $this->isDisplayInLabel() ? $_element->getElementHtml() : $_element->getButton()->toHtml(); ?>
14
+ <td class="label<?php echo $_class ? " {$_class}-label" : ''?>"><?php echo trim($_element->getLabel()) ?></td>
15
+ <td class="<?php echo $_element->hasValueClass() ? $_element->getValueClass() : 'value' ?><?php echo $_class ? " {$_class}-value" : ''?>">
16
+ <?php echo trim($html) ?>
17
+ <?php if ($_note): ?>
18
+ <p class="note<?php echo $_class ? " {$_class}-note" : ''?>" id="note_<?php echo $_element->getId()?>"><span><?php echo $_note ?></span></p>
19
+ <?php endif ?>
20
+ </td>
21
+ <?php endif; ?>
22
+ </tr>
23
+ <?php endif; ?>
app/design/adminhtml/default/default/template/bronto/product/recommendation/default.phtml ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!-- Stacking Quarters Outer -->
2
+ <div>
3
+ <table style="border-collapse: collapse;" border="0" cellspacing="0" cellpadding="0" width="100%">
4
+ <tbody>
5
+ <tr>
6
+ <td><!-- Stacking Quarters Inner -->
7
+ <table class="content" style="border-collapse: collapse;" border="0" cellspacing="0" cellpadding="0" width="100%">
8
+ <tbody>
9
+ <tr>
10
+ <td width="640">{dynamic_code}{loop} <!-- Content One -->
11
+ <table style="border-collapse: collapse;" border="0" cellspacing="0" cellpadding="0" align="left">
12
+ <tbody>
13
+ <tr>
14
+ <td width="158" align="left">
15
+ <p style="mso-table-lspace: 0; mso-table-rspace: 0; margin: 0;"><!-- Content One Inner --></p>
16
+ <table style="border-collapse: collapse;" border="0" cellspacing="0" cellpadding="0">
17
+ <tbody>
18
+ <tr>
19
+ <td style="font-family: Arial, Helvetica, sans-serif; color: #000; font-size: 14px; padding: 9px;" align="left"><!-- Image Table -->
20
+ <table style="border-collapse: collapse;" border="0" cellspacing="0" cellpadding="0" align="center">
21
+ <tbody>
22
+ <tr>
23
+ <td style="padding-bottom: 10px;" width="140">
24
+ <div id="4grid1image"><a href="%%#relatedUrl_#%%"><img style="display: block; max-width: 100%;" src="%%#relatedImgUrl_#%%" alt="" width="140" height="140" /></a></div>
25
+ </td>
26
+ </tr>
27
+ </tbody>
28
+ </table>
29
+ <!-- End Image Table -->
30
+ <div id="4grid1text"><center><strong><a href="%%#relatedUrl_#%%">%%#relatedName_#%%<br/>$%%#relatedPrice_#%%</strong><br/>%%#relatedDescription_#%%</a></center></div>
31
+ </td>
32
+ </tr>
33
+ </tbody>
34
+ </table>
35
+ <!-- End Content One Inner -->
36
+ <p>&nbsp;</p>
37
+ </td>
38
+ </tr>
39
+ </tbody>
40
+ </table>
41
+ <!-- End Content One --> {/loop}{/dynamic_code}</td>
42
+ </tr>
43
+ </tbody>
44
+ </table>
45
+ <!-- End Stacking Quarters Inner--></td>
46
+ </tr>
47
+ </tbody>
48
+ </table>
49
+ </div>
50
+ <!-- End Stacking Quarters Outer -->
app/design/adminhtml/default/default/template/bronto/product/recommendation/edit.phtml ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php echo $this->getFormInitScripts(); ?>
2
+
3
+ <div class="content-header">
4
+ <?php echo $this->getHeaderHtml(); ?>
5
+ <p class="content-buttons form-buttons">
6
+ <?php echo $this->getButtonsHtml('header'); ?>
7
+ </p>
8
+ </div>
9
+
10
+ <form id="edit_form" method="post" action="<?php echo $this->getSaveUrl(); ?>">
11
+ <?php echo $this->getFormHtml(); ?>
12
+ </form>
13
+
14
+ <script type="text/javascript">
15
+ var editForm = new varienForm('edit_form', '<?php echo $this->getValidationUrl(); ?>');
16
+ </script>
17
+
18
+ <?php if ($this->hasFooterButtons()) : ?>
19
+ <div class="content-footer">
20
+ <p class="content-buttons form-buttons">
21
+ <?php echo $this->getButtonsHtml('footer'); ?>
22
+ </p>
23
+ </div>
24
+ <?php endif; ?>
25
+
26
+ <?php echo $this->getSelectedProductsJs(); ?>
27
+ <script type="text/javascript">
28
+ Event.observe(window, 'load', function() {
29
+ $$('#preview_button button').each(function($button) {
30
+ $button.observe('click', function(e) {
31
+ Dialog.info({
32
+ url: "<?php echo $this->getPreviewContentUrl(); ?>",
33
+ options: {
34
+ method: 'post',
35
+ parameters: $('edit_form').serialize()
36
+ }
37
+ }, {
38
+ title: $button.innerText,
39
+ width: 820,
40
+ height: 410,
41
+ id: 'browser_window',
42
+ top: 50,
43
+ hideEffect: Element.hide,
44
+ showEffect: Element.show,
45
+ recenterAuto: true,
46
+ className: 'magento',
47
+ draggable: false,
48
+ closable: true,
49
+ resizable: false,
50
+ windowClassName: 'popup-window',
51
+ zIndex: 400,
52
+ });
53
+ });
54
+ });
55
+ });
56
+ </script>
57
+
58
+ <?php echo $this->getFormScripts(); ?>
app/design/adminhtml/default/default/template/bronto/product/recommendation/grid.phtml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div style="padding:6px; margin-bottom:10px; background-color:#eee; border:1px solid #dedede">See <?php echo $this->getConfigLink() ?> for additional configuration </td></div>
2
+ <div class="content-header">
3
+ <table cellspacing="0">
4
+ <tr>
5
+ <td style="<?php echo $this->getHeaderWidth() ?>"><?php echo $this->getHeaderHtml() ?></td>
6
+ <td class="form-buttons"><?php echo $this->getButtonsHtml() ?></td>
7
+ </tr>
8
+ </table>
9
+ </div>
10
+ <div>
11
+ <?php echo $this->getGridHtml() ?>
12
+ </div>
app/design/adminhtml/default/default/template/bronto/product/recommendation/preview.phtml ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php echo $this->getFormInitScripts(); ?>
2
+
3
+ <div class="content-header">
4
+ <?php echo $this->getHeaderHtml(); ?>
5
+ <p class="content-buttons form-buttons">
6
+ <?php echo $this->getButtonsHtml('header'); ?>
7
+ </p>
8
+ </div>
9
+
10
+ <?php if (!$this->isSingleStoreMode()): ?>
11
+ <?php echo $this->getStoreSwitcherHtml(); ?>
12
+ <?php endif; ?>
13
+
14
+ <form id="preview_form" method="post">
15
+ <?php echo $this->getFormHtml(); ?>
16
+ </form>
17
+
18
+ <script type="text/javascript">
19
+ var previewForm = new varienForm('preview_form', '');
20
+ </script>
21
+
22
+ <?php if ($this->hasFooterButtons()) : ?>
23
+ <div class="content-footer">
24
+ <p class="content-buttons form-buttons">
25
+ <?php echo $this->getButtonsHtml('footer'); ?>
26
+ </p>
27
+ </div>
28
+ <?php endif; ?>
29
+
30
+ <script type="text/javascript">
31
+ function updateRecommendations() {
32
+ var preview = $('previewProductsGrid');
33
+ var recommendation = $('entity_id');
34
+ var productIds = $('product_ids').value.split(/\s*,\s*/);
35
+ var button = $$('button[onclick^=messagePicker]').first();
36
+
37
+ new Ajax.Request("<?php echo $this->getUpdatePreviewUrl(); ?>", {
38
+ method: 'post',
39
+ parameters: {
40
+ entity_id: recommendation.value,
41
+ 'product_ids[]': productIds
42
+ },
43
+ onSuccess: function(resp) {
44
+ preview.parentNode.innerHTML = resp.responseText;
45
+ }
46
+ });
47
+
48
+ if (recommendation.value == '') {
49
+ button
50
+ .writeAttribute('disabled', true)
51
+ .addClassName('disabled')
52
+ .removeClassName('go');
53
+ } else {
54
+ button
55
+ .writeAttribute('disabled', false)
56
+ .removeClassName('disabled')
57
+ .addClassName('go');
58
+ }
59
+ }
60
+
61
+ function selectedOkHandler() {
62
+ updateRecommendations();
63
+ }
64
+
65
+ function messagePicker() {
66
+ Dialog.confirm({
67
+ url: "<?php echo $this->getMessageDialogUrl(); ?>",
68
+ }, {
69
+ title: 'Test Recommended Products in Email',
70
+ okLabel: 'Send Email',
71
+ width: 640,
72
+ height: 230,
73
+ id: 'browser_window',
74
+ top: 50,
75
+ hideEffect: Element.hide,
76
+ showEffect: Element.show,
77
+ recenterAuto: true,
78
+ className: 'magento',
79
+ closable: true,
80
+ resizable: false,
81
+ windowClassName: 'popup-window',
82
+ zIndex: 400,
83
+ ok: function() {
84
+ var dialog = this;
85
+ new Ajax.Request("<?php echo $this->getSendMessageUrl(); ?>", {
86
+ method: 'post',
87
+ parameters: {
88
+ entity_id: $('entity_id').value,
89
+ message_id: $('hmessage_idh').value,
90
+ email_address: $('hemail_addressh').value,
91
+ 'product_ids[]': $('product_ids').value.split(/\s*,\s*/)
92
+ },
93
+ onSuccess: function(resp) {
94
+ var json = resp.responseJSON;
95
+ if (json.missingParentRequirement || json.success) {
96
+ $('messages').innerHTML = json.message;
97
+ dialog.close();
98
+ } else {
99
+ alert(json.message);
100
+ }
101
+ }
102
+ });
103
+ }
104
+ });
105
+ }
106
+ </script>
107
+
108
+ <?php echo $this->getSelectedProductsJs(); ?>
109
+
110
+ <?php echo $this->getFormScripts(); ?>
app/design/adminhtml/default/default/template/bronto/product/recommendation/selected.js.phtml ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script type="text/javascript">
2
+ function selectProducts(fieldId, matchesField) {
3
+ if (matchesField) {
4
+ var source = fieldId.split('_')[1];
5
+ var original = source + "_source";
6
+ var title = $$('label[for=' + original + ']').first().innerText.replace("*", '');
7
+ } else {
8
+ var source = 'none';
9
+ var title = 'Optional Products';
10
+ }
11
+
12
+ var selected = {};
13
+ var productIds = $(fieldId).value.split(/\s*,\s*/);
14
+ for (var i = 0; i < productIds.length; i++) {
15
+ selected[productIds[i]] = 1;
16
+ }
17
+
18
+ var selectedToProducts = function() {
19
+ var productIds = [];
20
+ for (var productId in selected) {
21
+ if (!productId) {
22
+ continue;
23
+ }
24
+ productIds.push(productId);
25
+ }
26
+ return productIds;
27
+ };
28
+
29
+ var setCheckbox = function(element, checked, callback) {
30
+ if (!isNaN(element.value)) {
31
+ if (element.checked) {
32
+ selected[element.value] = 1;
33
+ } else {
34
+ delete selected[element.value];
35
+ }
36
+ if (callback) {
37
+ callback(element, checked);
38
+ }
39
+ }
40
+ };
41
+
42
+ var dialog = Dialog.confirm({
43
+ url: "<?php echo $this->getSelectAjaxUrl(); ?>",
44
+ options: {
45
+ method: 'post',
46
+ parameters: {
47
+ source: source
48
+ },
49
+ }
50
+ }, {
51
+ title: title,
52
+ okLabel: "Select Products",
53
+ okButtonClass: 'go',
54
+ width: 820,
55
+ height: 410,
56
+ id: 'browser_window',
57
+ top: 50,
58
+ hideEffect: Element.hide,
59
+ showEffect: Element.show,
60
+ recenterAuto: true,
61
+ className: 'magento',
62
+ draggable: false,
63
+ closable: true,
64
+ resizable: false,
65
+ windowClassName: 'popup-window',
66
+ zIndex: 400,
67
+ ok: function() {
68
+ $(fieldId).value = selectedToProducts().join(', ');
69
+ this.close();
70
+ try {
71
+ selectedOkHandler();
72
+ } catch (e) {
73
+ // Swallow
74
+ }
75
+ }
76
+ });
77
+
78
+ Windows.addObserver({
79
+ onShow: function() {
80
+ var element = $$('#browser_window_content script').first();
81
+ if (element) {
82
+ var content = element.innerText;
83
+ eval(content);
84
+ var params = {
85
+ form_key: FORM_KEY,
86
+ source: source,
87
+ 'products[]': selectedToProducts(),
88
+ };
89
+ selectedProductsGridJsObject.checkboxCheckCallback = function(grid, element, checked) {
90
+ setCheckbox(element, checked, function() {
91
+ params['products[]'] = selectedToProducts();
92
+ });
93
+ };
94
+ selectedProductsGridJsObject.rowClickCallback = function(grid, event) {
95
+ var element = Event.element(event);
96
+ if (['input'].indexOf(element.tagName.toLowerCase()) != -1) {
97
+ setCheckbox(element, element.checked, function() {
98
+ params['products[]'] = selectedToProducts();
99
+ });
100
+ }
101
+ };
102
+ selectedProductsGridJsObject.reloadParams = params;
103
+ }
104
+ }
105
+ });
106
+ }
107
+ </script>
app/design/frontend/base/default/layout/bronto/newsletter.xml CHANGED
@@ -9,4 +9,4 @@
9
  </block>
10
  </reference>
11
  </checkout_onepage_index>
12
- </layout>
9
  </block>
10
  </reference>
11
  </checkout_onepage_index>
12
+ </layout>
app/design/frontend/base/default/layout/bronto/order.xml CHANGED
@@ -9,5 +9,14 @@
9
  </block>
10
  </reference>
11
  </default>
 
 
 
 
 
 
 
 
 
12
  </layout>
13
 
9
  </block>
10
  </reference>
11
  </default>
12
+ <checkout_onepage_success>
13
+ <reference name="content">
14
+ <block type="bronto_order/redemption" name="bronto.redemption" as="bronto_redemption" after="-">
15
+ <action method="setTemplate">
16
+ <template>bronto/order/redemption.phtml</template>
17
+ </action>
18
+ </block>
19
+ </reference>
20
+ </checkout_onepage_success>
21
  </layout>
22
 
app/design/frontend/base/default/template/bronto/common/popup.phtml CHANGED
@@ -1,3 +1,14 @@
1
  <?php /* @var $this Bronto_Common_Block_Popup */ ?>
2
 
3
- <?php echo $this->getPopupCode() ?>
 
 
 
 
 
 
 
 
 
 
 
1
  <?php /* @var $this Bronto_Common_Block_Popup */ ?>
2
 
3
+ <?php echo $this->getPopupCode() ?>
4
+
5
+ <script type="text/javascript">
6
+ if (document.addEventListener) {
7
+ document.addEventListener('bronto:popup-submitted', function(e) {
8
+ new Ajax.Request('<?php echo $this->getPopupSubmitUrl(); ?>', {
9
+ method: 'post',
10
+ parameters: { emailAddress: e.detail.email }
11
+ });
12
+ }, false);
13
+ }
14
+ </script>
app/design/frontend/base/default/template/bronto/emailcapture/js.phtml CHANGED
@@ -21,7 +21,7 @@
21
  captureEmail(item.value);
22
  });
23
  });
24
- });
25
  }
26
 
27
  // Trigger AJAX call to capture Email Address
21
  captureEmail(item.value);
22
  });
23
  });
24
+ }, false);
25
  }
26
 
27
  // Trigger AJAX call to capture Email Address
app/design/frontend/base/default/template/bronto/newsletter/checkbox.phtml CHANGED
@@ -2,10 +2,9 @@
2
  <?php $this->_setCheckboxStatus(); ?>
3
  <div class="input-box newsletter-signup"<?php echo $this->getCheckboxShow() ?>>
4
  <style>
5
- .col1-layout .billing_is_subscribed_box { margin-left: 240px !important; float:left; width: auto; margin: 2px 8px 0 0; }
6
- .col1-layout #billing_subscribed_label { width: auto; text-align: left; }
7
  </style>
8
  <input id="billing:is_subscribed" type="hidden" name="billing[is_subscribed]" value="<?php echo $this->getCheckboxValue() ?>" />
9
  <input id="billing:is_subscribed_box" class="billing_is_subscribed_box" type="checkbox" onchange="setSubscribedValue(); return false;"<?php echo $this->getCheckboxChecked() ?> title="<?php echo $this->__($this->getCheckboxLabelText()) ?>" />
10
  <label id="billing_subscribed_label" for="billing:is_subscribed_box"><?php echo $this->__($this->getCheckboxLabelText()) ?></label>
11
- </div>
2
  <?php $this->_setCheckboxStatus(); ?>
3
  <div class="input-box newsletter-signup"<?php echo $this->getCheckboxShow() ?>>
4
  <style>
5
+ <?php echo $this->getCheckboxStyle(); ?>
 
6
  </style>
7
  <input id="billing:is_subscribed" type="hidden" name="billing[is_subscribed]" value="<?php echo $this->getCheckboxValue() ?>" />
8
  <input id="billing:is_subscribed_box" class="billing_is_subscribed_box" type="checkbox" onchange="setSubscribedValue(); return false;"<?php echo $this->getCheckboxChecked() ?> title="<?php echo $this->__($this->getCheckboxLabelText()) ?>" />
9
  <label id="billing_subscribed_label" for="billing:is_subscribed_box"><?php echo $this->__($this->getCheckboxLabelText()) ?></label>
10
+ </div>
app/design/frontend/base/default/template/bronto/newsletter/js.phtml CHANGED
@@ -5,16 +5,22 @@
5
  //<![CDATA[
6
  // Observe Page and fetch checkbox code
7
  Event.observe(window, 'load', function() {
8
- // Check if we are on One-Step-Checkout
9
- if($('billing_address') != undefined) {
10
- var billingFieldset = $$('#billing_address ul');
 
 
 
 
 
 
 
 
 
11
  } else {
12
- var billingFieldset = $$('#co-billing-form fieldset ul.form-list');
 
13
  }
14
-
15
- // Build checkbox container
16
- var newRow = document.createElement('li').writeAttribute('id', 'billing-newsletter-signup');
17
- billingFieldset[0].insert(newRow);
18
 
19
  // If Register/Guest button is clicked, Load Checkbox Code
20
  if ($('onepage-guest-register-button') != null) {
5
  //<![CDATA[
6
  // Observe Page and fetch checkbox code
7
  Event.observe(window, 'load', function() {
8
+ var selector = "<?php echo $this->getCssSelector(); ?>";
9
+ var billingId = 'billing-newsletter-signup';
10
+ if (selector == '#billing_address') {
11
+ // Check if we are on One-Step-Checkout
12
+ if($('billing_address') != undefined) {
13
+ var billingFieldset = $$('#billing_address ul');
14
+ } else {
15
+ var billingFieldset = $$('#co-billing-form fieldset ul.form-list');
16
+ }
17
+ // Build checkbox container
18
+ var newRow = document.createElement('li').writeAttribute('id', billingId);
19
+ billingFieldset[0].insert(newRow);
20
  } else {
21
+ var content = document.createElement('div').writeAttribute('id', billingId);
22
+ $$(selector)[0].insert(content);
23
  }
 
 
 
 
24
 
25
  // If Register/Guest button is clicked, Load Checkbox Code
26
  if ($('onepage-guest-register-button') != null) {
app/design/frontend/base/default/template/bronto/order/redemption.phtml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if ($this->getOrder() && $this->getRedemptionSiteHash()) : ?>
2
+ <script type="text/javascript" src="https://cdn.bronto.com/coupon/js/bcm.js"></script>
3
+ <script type="text/javascript">
4
+ __bcm.redeemCoupon("<?php echo $this->getRedemptionSiteHash(); ?>", {
5
+ email: "<?php echo $this->getEmailAddress(); ?>",
6
+ coupon: "<?php echo $this->getCouponUsed(); ?>",
7
+ orderId: "<?php echo $this->getOrderIncrementId(); ?>",
8
+ orderSubtotal: "<?php echo $this->getOrderSubtotal(); ?>",
9
+ orderDiscount: "<?php echo $this->getDiscountAmount(); ?>"
10
+ });
11
+ </script>
12
+ <?php endif; ?>
app/etc/modules/Bronto_Product.xml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Bronto_Product>
5
+ <active>true</active>
6
+ <codePool>community</codePool>
7
+ <depends>
8
+ <Bronto_Common/>
9
+ </depends>
10
+ </Bronto_Product>
11
+ </modules>
12
+ </config>
package.xml CHANGED
@@ -1,7 +1,7 @@
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>Bronto_Extension</name>
4
- <version>2.2.2</version>
5
  <stability>stable</stability>
6
  <license uri="http://opensource.org/licenses/osl-3.0.php">OSL</license>
7
  <channel>community</channel>
@@ -55,9 +55,9 @@
55
  &lt;p /&gt;Bronto Software provides a cloud-based marketing platform for retailers to drive revenue through their email, mobile and social campaigns. The platform is used by over 1000 organizations worldwide, including Party City, Armani Exchange, Timex, Samsonite and Gander Mountain. Bronto is a Gold Magento Industry Partner and the leading self-service email marketing provider to the Internet Retailer Top 1000. Bronto is headquartered in Durham, NC with an office in London, UK. For more information, visit &lt;a href="http://bronto.com"&gt;bronto.com&lt;/a&gt;.&lt;/p&gt;</description>
56
  <notes>&lt;p /&gt;For installation and configuration instructions, as well as a full list of new features and known issues, please review the &lt;a href="http://a.bron.to/magento"&gt;Implementation Guide&lt;/a&gt;.</notes>
57
  <authors><author><name>Chris Geiss</name><user>BrontoSoftware</user><email>chris.geiss@bronto.com</email></author></authors>
58
- <date>2014-02-14</date>
59
- <time>22:13:23</time>
60
- <contents><target name="magecommunity"><dir name="Bronto"><dir name="Common"><dir name="Block"><dir name="Adminhtml"><dir name="System"><dir name="Config"><file name="About.php" hash="ceee3ef00dcfde90f82ce80a5119ed56"/><dir name="Cron"><file name="Error.php" hash="ccaf02afd320c2a60b271bcf728c723a"/></dir><file name="Cron.php" hash="ff26632f20d0474d45ae0549634b4f7c"/><dir name="Form"><dir name="Field"><file name="Apitoken.php" hash="48fe102c7d74b7646de1e256f87cfe87"/><file name="Debug.php" hash="6b3e65c774d25184e88c43e7364d68b4"/><file name="Download.php" hash="6521c641550b7c747632fe25dd5982ed"/><file name="Hidden.php" hash="c514ae120d4dced7b92ea30a13f0e4ea"/><file name="Image.php" hash="9de445fac8d262bb023f123d1e4df9e5"/><file name="List.php" hash="907853b5009661b6b63a3a2947fc9c59"/><dir name="Support"><file name="Site.php" hash="9e0b6acae1053a90a7513a3791ee258c"/></dir><file name="Support.php" hash="f680904d05213ec4d43726b714cf2b69"/></dir><file name="Field.php" hash="932af08da6e8dc20e74e97894b1a2518"/><file name="Fieldset.php" hash="a3d41e7bfc09bd81942c6f32bc1d1782"/></dir><file name="Guide.php" hash="3ad72b377da538047e5efedae5dd31ef"/><file name="Support.php" hash="be33bc95f1f713205dd11fb59598e166"/><file name="Suppressed.php" hash="5adada4485cc74566c512c4dbad8c8a0"/></dir></dir><dir name="Widget"><dir name="Button"><file name="Abstract.php" hash="8c082611a7e4131c897ae9f2ed1d6dcf"/><file name="Debug.php" hash="e841017705d9b45a33e8475144ff0587"/><file name="Download.php" hash="78de702f642111af6feb725b4dd0bf08"/></dir></dir></dir><file name="Popup.php" hash="50c59a6fec4ca29059dbef3fd098ed7e"/></dir><dir name="Helper"><file name="Api.php" hash="325c6738308ad46fda1674c2e2f2f76c"/><file name="Contact.php" hash="7a0e1497feec57466fd242cb85c0d550"/><file name="Data.php" hash="509ffce1f833a5211c5cd7ba68f5db25"/><file name="DataInterface.php" hash="d1691f590c315abd3178e769cf51fe2a"/><file name="Field.php" hash="7c208abd6c77057e1e400f6699be77df"/><file name="Message.php" hash="5484ec49ce8ab8fda12d9dc6c4c29c65"/><file name="Product.php" hash="11775a052258f97fc8456d4fef981c76"/><file name="Salesrule.php" hash="32feae8429a684adcf8be798f42c16b8"/><file name="Support.php" hash="c20c3e73c23a70cdaebb61815e2ce33e"/></dir><dir name="Model"><file name="Api.php" hash="72817e825da18d2c88800385cd3c6eca"/><file name="Archive.php" hash="b613e811bb673c72e6cec6770ed48fa5"/><file name="Delivery.php" hash="1c43e226d7c174f655533299bbf15359"/><dir name="Email"><dir name="Template"><file name="Filter.php" hash="c4d5d75ec6f6c7409320b6b36759e580"/><file name="Templatefilter.php" hash="c3acf3b4be3dcce490b1e07c0ab68e38"/></dir><file name="Template.php" hash="a24b72152b213b8b565493a5dceadd5c"/></dir><file name="Error.php" hash="8270252828229cad2c3b35f22e898b4d"/><file name="Keysentry.php" hash="ed1603a0954baaf716219d717e65f5b5"/><file name="List.php" hash="af9e2c5509d8b832278d29b2eeed51ad"/><dir name="Mysql4"><dir name="Api"><file name="Collection.php" hash="9b589f17c2efee2866369d6fd0c73279"/></dir><file name="Api.php" hash="79e25f0be61ef7ce5066c676545ab19d"/><dir name="Error"><file name="Collection.php" hash="cdd8617db0383a5dd23787850c26bfe3"/></dir><file name="Error.php" hash="2959715e0def582a6a0ecdf6f6442701"/></dir><file name="Observer.php" hash="74a4300ff5a5364f036ea5b7ea3d995f"/><dir name="Resource"><file name="Setup.php" hash="793a326c80af2420cd0511a9b65a6aa8"/></dir><file name="SoapClient.php" hash="38ea95b32c1271d3ac329979c4f5d7a0"/><dir name="System"><dir name="Config"><dir name="Backend"><dir name="Cron"><file name="Error.php" hash="38bbbcde58aa89e3f7be043a773feb26"/></dir><file name="Cron.php" hash="1aa481a63198c64fafc90abe93166116"/><file name="Enable.php" hash="2b641958cfa59bd18992a8b92af99301"/><file name="Token.php" hash="1580a2ebd534155356515b0738a8cc77"/></dir><dir name="Source"><dir name="Contact"><file name="Status.php" hash="811a360bffa20b92d4a7bdea66a73168"/></dir><dir name="Cron"><file name="Frequency.php" hash="3ef5bda79548019f9a7cb2007c6792f5"/><file name="Minutes.php" hash="136df1bc4c4723efdbe144ed7a08806e"/></dir><file name="Field.php" hash="7a4660fbc812dca134b69b3cef76ea57"/><file name="Image.php" hash="acb902acd1f8573887ed9d5a00410467"/><file name="Limit.php" hash="8891685ce2b9c338c316d16a2ae69a8d"/><file name="List.php" hash="c9fd7581386bc33c09e0e6edfdead420"/><file name="Message.php" hash="01c7e9d489c1ed7f07f011d5c044805a"/><file name="Role.php" hash="5a55bad277b8723130035d79d6e5b98b"/><file name="Synclimit.php" hash="40a063f7d2ac5e1ad6a9bfa773b22863"/></dir></dir></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="DebugController.php" hash="2a1b69ab086340a58fd96278cea9e4c2"/><file name="GuidersController.php" hash="8eae4825b247191bd166224ac79ea655"/></dir><file name="LogController.php" hash="c7e65dec2943bb1b0575396290629fdc"/></dir><dir name="etc"><file name="adminhtml.xml" hash="0bbd379c87b3a9ab5a6a2d48f864b1ec"/><file name="config.xml" hash="aefc5f63cad90b140f19fe1449aa17e1"/><file name="system.xml" hash="6e09668b64faaaf6769eddab6aaac204"/></dir><dir name="sql"><dir name="bronto_common_setup"><file name="mysql4-install-1.7.0.php" hash="c8459d26fdfea2fb9430e8829b3257e1"/><file name="mysql4-install-2.2.1.php" hash="f2a33e687c2a2ee784c63ca9ba58ad5f"/><file name="mysql4-upgrade-1.7.0-2.2.1.php" hash="f2a33e687c2a2ee784c63ca9ba58ad5f"/><file name="mysql4-upgrade-2.0.4-2.2.1.php" hash="f2a33e687c2a2ee784c63ca9ba58ad5f"/><file name="mysql4-upgrade-2.0.4.2-2.2.1.php" hash="f2a33e687c2a2ee784c63ca9ba58ad5f"/><file name="mysql4-upgrade-2.1.0-2.2.1.php" hash="f2a33e687c2a2ee784c63ca9ba58ad5f"/><file name="mysql4-upgrade-2.2.0-2.2.1.php" hash="f2a33e687c2a2ee784c63ca9ba58ad5f"/></dir></dir></dir><dir name="Customer"><dir name="Block"><dir name="Adminhtml"><dir name="System"><dir name="Config"><file name="About.php" hash="bc63c93b5ff46fe2e6cb84a8c3249d12"/><file name="Cron.php" hash="159344d5cd5b0bb0a770e7fa4132a754"/><dir name="Form"><dir name="Field"><file name="Rewardpoints.php" hash="c1918f7478737dcfba6b543fa006a4bc"/><file name="Storecredit.php" hash="489625264fff9d5a37621f1b80203099"/></dir><dir name="Fieldset"><dir name="Attributes"><file name="Address.php" hash="7871298d7b7410d5202b436a1f536d7c"/><file name="Customer.php" hash="b0060f6c8c71ec321387aa8071a5c483"/></dir><file name="Attributes.php" hash="0a93bc89eea36b70908ef805a4627d93"/></dir></dir><file name="Suppressed.php" hash="a65d86c60db621d6d202cf64c02024f8"/></dir></dir><dir name="Widget"><dir name="Button"><file name="Reset.php" hash="6dd540765670c2955160365319b9af22"/><file name="Run.php" hash="2b6332568132b633a1ee208e8b555b5a"/><file name="Sync.php" hash="be611c057f18b5da9e31927fc1788365"/></dir></dir></dir></dir><dir name="Helper"><file name="Data.php" hash="528d9a17f2e7dc654eecb5c9b3a92fbc"/></dir><dir name="Model"><dir name="Mysql4"><dir name="Queue"><file name="Collection.php" hash="5564536b725040d0652cba23e13e546e"/></dir><file name="Queue.php" hash="5aff6d99b2f3bf24cd2db7d0586f96ab"/><file name="Setup.php" hash="cb74c44bd42f407925a800fe3996d7a3"/></dir><file name="Observer.php" hash="6c12810ad6e671e22209faed6120f2ba"/><file name="Queue.php" hash="7851ed2790e205473cf848c63a4f13a8"/><dir name="Resource"><file name="Customer.php" hash="86f081e728c9d9f22e28018406d9f601"/></dir><dir name="System"><dir name="Config"><dir name="Backend"><file name="Brontofield.php" hash="54432d8d5b2aec5395d21d21b9262162"/><file name="Cron.php" hash="44d12cea40d1342ad065bd4aad936193"/><file name="Newfield.php" hash="118d2622277e919e1f316f0713f5a2b7"/></dir></dir></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="CustomerController.php" hash="b6521bc4a03414027470ffef4afb736c"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="bb58fa0df1e07c2d88527fed1920ffc2"/><file name="config.xml" hash="e1a4673cdc939b1177c5ee2e8af678f6"/><file name="system.xml" hash="36c06af831397b32776ec1b96929dc0d"/></dir><dir name="sql"><dir name="bronto_customer_setup"><file name="mysql4-install-1.0.0.php" hash="871c225318588b2804a05751bce45e1f"/><file name="mysql4-install-1.0.3.php" hash="79785fb104491dcc4713e55495f24ba0"/><file name="mysql4-upgrade-1.0.0-1.0.1.php" hash="1c00e987c9a1b1da70ad035ccdef194b"/><file name="mysql4-upgrade-1.0.1-1.0.2.php" hash="144999a033695bd72601f1f0e10de5e3"/><file name="mysql4-upgrade-1.0.2-1.0.3.php" hash="6e3c57a1c9272aa4b2d7d051a24ed87f"/></dir></dir></dir><dir name="Email"><dir name="Block"><dir name="Adminhtml"><dir name="System"><dir name="Config"><file name="About.php" hash="ab71e0649d5af1fe64f665ada8895be9"/><file name="Settings.php" hash="59f952e7baeff59ef013a9f39572370e"/><dir name="Templates"><file name="Field.php" hash="0b4d17701e352b6c28cd5262d3cd8e0e"/><file name="Fieldset.php" hash="01fa6905eec117df32519c7e461e05f8"/><file name="Label.php" hash="fed0e19a1dde5592ba2efcc3aa6a2bba"/><file name="Sendtype.php" hash="d93029708ba002781e365cb0215022ce"/></dir><file name="Templates.php" hash="5811fe4b83f7dd5d6f0c7c78314cd31c"/></dir><dir name="Email"><dir name="Import"><file name="Edit.php" hash="32d4219613247ff59a59b5031284159c"/><dir name="Grid"><dir name="Renderer"><file name="Action.php" hash="e5f3203f05d2fbc577a3e7f3dd5d6341"/></dir></dir><file name="Grid.php" hash="40551a1c6c11247925d2557c8c3fafde"/></dir><file name="Import.php" hash="a2f378383faebc5c0fabcd46feb4d7e3"/><dir name="Log"><dir name="Grid"><dir name="Renderer"><file name="Customer.php" hash="ee83b754d1a91920a79918991aa76ca6"/><file name="Fields.php" hash="dc0d7cbd5065382ccf51ff3f84054563"/></dir></dir><file name="Grid.php" hash="591f4aefd4fa2f7b5f53653f0d7780a7"/></dir><file name="Log.php" hash="755439eace3c8e1f5ee3c657562c476d"/><dir name="Template"><dir name="Edit"><file name="Form.php" hash="47b8b4a1e40b262f7b1811549a177261"/></dir><file name="Edit.php" hash="e76c3c82fc3c180041eeeb6251fecbaa"/><dir name="Grid"><dir name="Renderer"><file name="Action.php" hash="543cf476631d073e4de5ec59f1faf5b5"/><file name="Storename.php" hash="c5111a20ed0b3aed0078cecb1ae3d739"/></dir></dir><file name="Grid.php" hash="da86503c8e244821b08d60a50dc8973a"/></dir><file name="Template.php" hash="ea39c46962381b34377efa05ecbfa075"/></dir></dir></dir></dir><dir name="Helper"><file name="Contact.php" hash="60d8707e923f59ad7af130aa09557be0"/><file name="Data.php" hash="ca89f9dbc6ac7e380dde556d5455cf49"/><file name="Field.php" hash="fc67415cbe73614fe0bbc29df7f93148"/><file name="Message.php" hash="7f5a80ce2a9a75324f8e5df9b3a318f4"/></dir><dir name="Model"><file name="Log.php" hash="1c9b060a801312c0b929806708a9ac1a"/><file name="Message.php" hash="02bf1f9bef1f4ce1909cc3d5c6331969"/><dir name="Mysql4"><dir name="Log"><file name="Collection.php" hash="0cc3245eea5df5ca8607fc4ca8aabf99"/></dir><file name="Log.php" hash="aef3718e6ea1de42152099aeb444782f"/><dir name="Message"><file name="Collection.php" hash="4ad21710a8a2c403e83dcf40ad6eda22"/></dir><file name="Message.php" hash="f225d9ac332aa3b0fea5ff094a336926"/><dir name="Template"><file name="Collection.php" hash="27a2f2fcbf6210acbad20359eb673304"/></dir><file name="Template.php" hash="496380271268f9f949afb2a2ce1bdbf9"/></dir><file name="Observer.php" hash="f906c3827a17d77d6d54d6d32557b507"/><dir name="Resource"><file name="Setup.php" hash="13613a00761323dcb331325cc991e0a5"/></dir><dir name="System"><dir name="Config"><dir name="Backend"><dir name="Templates"><file name="Field.php" hash="e6f28eb62a469792eb61ca1044aae764"/><file name="Sendtype.php" hash="18dadd39cdf47f6cdc95e168fe2012bc"/></dir><file name="Usebronto.php" hash="d9c1e9b77810c922b058d5f03f03b02e"/></dir><dir name="Source"><dir name="Email"><file name="Template.php" hash="82c55d7a5833b1de31e0ca92fcac9b11"/></dir><file name="Sendtype.php" hash="4cc496295bd5b4c2bf71eae9fd87f803"/></dir></dir></dir><dir name="Template"><file name="Import.php" hash="1cdee619cc7c0890d374764e12347f8c"/><file name="Mailer.php" hash="b814a8f77ccfed075849c89cfb8be963"/></dir><file name="Template.php" hash="f74e29c0fcc7528488e19f6aa89c57d7"/></dir><dir name="controllers"><dir name="Adminhtml"><dir name="System"><dir name="Email"><file name="LogController.php" hash="471e58f342857be6f023527c0a1d2981"/><file name="TemplateController.php" hash="8f0c04684a6f789b3af69ef22cc1bfb9"/></dir></dir></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="2343ec1b1ac91db90d522cd64e797aa6"/><file name="config.xml" hash="eb4fd8d33950a989dc40332d94818977"/><file name="system.xml" hash="eed70edcf9317bbefa54606a35d73ca2"/></dir><dir name="sql"><dir name="bronto_email_setup"><file name="mysql4-install-1.0.0.php" hash="516265312ede986c1a35a19b9e5bbfea"/><file name="mysql4-install-1.0.2.php" hash="327ac219e947d608fbf9d3209dd03bab"/><file name="mysql4-install-1.0.5.php" hash="327ac219e947d608fbf9d3209dd03bab"/><file name="mysql4-install-1.0.8.php" hash="b572625c1380dfffe3b089275ac1dc7e"/><file name="mysql4-install-1.1.2.php" hash="2824a3ef8b9308e577c792398598e08c"/><file name="mysql4-install-1.1.7.php" hash="f49bc2913b1c2375499f21f2ac9727cd"/><file name="mysql4-install-1.1.8.php" hash="afa3c83fbfe45fc193a7eda4af6afacb"/><file name="mysql4-install-1.1.9.php" hash="4509540dda05675ee192e0330effddd3"/><file name="mysql4-upgrade-1.0.0-1.0.2.php" hash="1f797c3f909d72219ef5d00017b10554"/><file name="mysql4-upgrade-1.0.2-1.0.5.php" hash="f2c83b65500d9df0fd10c2e6721f2bfe"/><file name="mysql4-upgrade-1.0.5-1.0.8.php" hash="cdbda7aa084e51b9b222c56e548462a6"/><file name="mysql4-upgrade-1.0.8-1.1.1.php" hash="f2c83b65500d9df0fd10c2e6721f2bfe"/><file name="mysql4-upgrade-1.1.1-1.1.2.php" hash="53cf783db35699cdc1fee692752fe8de"/><file name="mysql4-upgrade-1.1.2-1.1.7.php" hash="105868a6253471d3eeeea46c7af18aa9"/><file name="mysql4-upgrade-1.1.7-1.1.8.php" hash="0a4abaf8c787bf656e3163489eb5d29e"/><file name="mysql4-upgrade-1.1.8-1.1.9.php" hash="65b7c540763c1817fef6e4eb1ca6cb9b"/></dir></dir></dir><dir name="Emailcapture"><dir name="Block"><file name="Emailcapture.php" hash="1c45388793ad609bd867c3a331bfb0c1"/></dir><dir name="Helper"><file name="Data.php" hash="4968f32e599a6fefe7b6876c486264ba"/></dir><dir name="Model"><dir name="Mysql4"><dir name="Queue"><file name="Collection.php" hash="104fe48ab81aa32769c95aae1b4e4988"/></dir><file name="Queue.php" hash="97ad38464595ed8a25aee9148d703e51"/></dir><file name="Observer.php" hash="041d29358d884b6a4444200d3a6e6b00"/><file name="Queue.php" hash="f95570e6972a31e17c9b4eb1d99aad07"/></dir><dir name="controllers"><file name="IndexController.php" hash="2162c4ce867cba627a66ba4c1b549e55"/></dir><dir name="etc"><file name="config.xml" hash="953a38982ad1ad62107558218b78d121"/><file name="system.xml" hash="7f748cfe607ca50519e51f8a9739feef"/></dir><dir name="sql"><dir name="bronto_emailcapture_setup"><file name="mysql4-install-1.0.0.php" hash="ff0cda179382b958d6a566963faae637"/></dir></dir></dir><dir name="News"><dir name="Block"><dir name="Adminhtml"><file name="ItemRender.php" hash="147c1b256abc1a3f0ffc9018d8af713d"/><file name="Redirect.php" hash="0b6928d1529e41c4e2ccc3a415e53bb8"/><dir name="System"><dir name="Config"><file name="About.php" hash="757f06422ff513218a9dfad2ff91cd0d"/><file name="Form.php" hash="853d55a3d7d5e73e87ae09f87f4764b9"/><file name="General.php" hash="8a19eee62442466ff28f23aa782e68c5"/><file name="News.php" hash="4fdda30cd100f4d1b57a74cb38a9b371"/><file name="Releases.php" hash="30f7b23081c69219473326620e6ccd06"/></dir></dir></dir></dir><dir name="Helper"><file name="Data.php" hash="79dd892352cda62c69ede789dcade61a"/></dir><dir name="Model"><file name="Item.php" hash="e3ce20de8f0422dcf00f389f5491e788"/><dir name="Mysql4"><dir name="Item"><file name="Collection.php" hash="6a79699559ffe750643c3f6da90d0280"/></dir><file name="Item.php" hash="bf9fae7b7e2241259dbdbe83623c3e6e"/></dir><file name="Observer.php" hash="236e8cec018d29f50c4aeff1f23f4880"/><dir name="Resource"><file name="Setup.php" hash="cb9d37d047d535b4928b279623283f30"/></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="AnnouncementController.php" hash="ca98e801e5503b04f4f60286e19edb2e"/></dir><file name="RouteController.php" hash="4819b7cab294e952238e2edb43a73c52"/></dir><dir name="etc"><file name="adminhtml.xml" hash="079a3f745967cc14906151cfcdc2c816"/><file name="config.xml" hash="590d56fb32cdb7460cbff22ab1bffa69"/><file name="system.xml" hash="ecd3a0edd0de407c85bb537a78c2380a"/></dir><dir name="sql"><dir name="bronto_news_setup"><file name="mysql4-install-1.0.0.php" hash="f574c4b2432334d0202d75ef71cb0006"/></dir></dir></dir><dir name="Newsletter"><dir name="Block"><dir name="Adminhtml"><dir name="System"><dir name="Config"><file name="About.php" hash="b5d17d62df37034cd48ea3022e546724"/><file name="Cron.php" hash="bd4c2cee5118bd9209606cfd749c770e"/><file name="Suppressed.php" hash="1d2e716ce0b0a76ea67a56d6c62f65df"/></dir></dir><dir name="Widget"><dir name="Button"><file name="Reset.php" hash="a2827fc3f6af2b94e1ed3bcc5989b015"/><file name="Run.php" hash="21e4d1c9eb2c882b967c5de6def6a97b"/><file name="Sync.php" hash="89112c7b858e9031050bcba50527b4d7"/></dir></dir></dir><dir name="Checkout"><dir name="Onepage"><file name="Newsletter.php" hash="9f0a75670696375dbfdbbc8914e8d6ab"/></dir></dir></dir><dir name="Helper"><file name="Contact.php" hash="bc7ec83130b8614881cf9476b4884bbf"/><file name="Data.php" hash="569f7e71196bc67b9a5b23dd720946aa"/></dir><dir name="Model"><dir name="Mysql4"><dir name="Queue"><file name="Collection.php" hash="b9c6858b2045ad66b7c331afba125d19"/></dir><file name="Queue.php" hash="4cf426f02c1e2889b77be9b6a105c91b"/></dir><file name="Observer.php" hash="b95f5c9bbfb932ef7f190af6eca10118"/><file name="Queue.php" hash="a9ef5813d95abcd1ee89a0372a0cfeb8"/><dir name="Resource"><file name="Setup.php" hash="1f72a1f56aca455ea0d0289450e9edf5"/></dir><dir name="System"><dir name="Config"><dir name="Backend"><file name="Cron.php" hash="282c40a155af7ea22f646e931fdb6732"/></dir></dir></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="NewsletterController.php" hash="0d6bd72d5a5518219548483f876a427b"/></dir><file name="IndexController.php" hash="ca4d3ed37230b73dc9cb81b1cbb39928"/></dir><dir name="etc"><file name="adminhtml.xml" hash="b685d64860bf37a09330bd9f89f5bc3d"/><file name="config.xml" hash="cbd0240c1ade0e8c787e6c1d3bfd0bc4"/><file name="system.xml" hash="ed040d43d75a1c4424ead1a886940141"/></dir><dir name="sql"><dir name="bronto_newsletter_setup"><file name="mysql4-install-1.0.0.php" hash="0f21d5315bbc4c27d0d38f9cf8c99bf3"/><file name="mysql4-install-1.4.0.php" hash="4a779a923947af258688d01143a16362"/><file name="mysql4-install-1.4.4.php" hash="089b40f9419c2fd21af62df207327a20"/><file name="mysql4-install-1.4.5.php" hash="8e97902e5e83992e678ba6144ed130b5"/><file name="mysql4-install-1.4.6.php" hash="74d29bc9655aeafa381ba5dc5f53df69"/><file name="mysql4-install-1.4.7.php" hash="74d29bc9655aeafa381ba5dc5f53df69"/><file name="mysql4-upgrade-1.4.0-1.4.1.php" hash="7eeba27e7b5480c8b502c3805554e2de"/><file name="mysql4-upgrade-1.4.1-1.4.2.php" hash="32f724b99d88e037ade72c8a9f1e0da7"/><file name="mysql4-upgrade-1.4.2-1.4.3.php" hash="63c728bb0cd7fa83bb5536d4500548f4"/><file name="mysql4-upgrade-1.4.3-1.4.4.php" hash="4f08a427c7706ea0988bcdcca6072218"/><file name="mysql4-upgrade-1.4.4-1.4.5.php" hash="c49018730275134d72f0802e1bc4da47"/><file name="mysql4-upgrade-1.4.5-1.4.6.php" hash="7de96310cf9bfe375e3026ed5c934ce2"/><file name="mysql4-upgrade-1.4.6-1.4.7.php" hash="6e40d94220fc0f2305546f7a8d5e754a"/></dir></dir></dir><dir name="Order"><dir name="Block"><dir name="Adminhtml"><dir name="Sales"><dir name="Order"><dir name="View"><dir name="Tab"><file name="Info.php" hash="4caacae5f31c84f898be5798cc85b7b7"/></dir></dir></dir></dir><dir name="System"><dir name="Config"><file name="About.php" hash="332c01d15a8b75f9add5988f35519135"/><file name="Cron.php" hash="ac79366d0bc9ad7ff74721d5b140e4ba"/><file name="Suppressed.php" hash="86af8a0b74f4f98e2a9b4d7ea08aa063"/></dir></dir><dir name="Widget"><dir name="Button"><file name="Reset.php" hash="4d64995d0f43ff3f3829287f8b8780f9"/><file name="Run.php" hash="700e3f9645a9e25e56ae1deb6764bf44"/><file name="Sync.php" hash="2ff1bf077cc56b3620fe87a494d7f770"/></dir></dir></dir><file name="Bta.php" hash="2ec920ce5a6ea57aff16c8d9cf89f7e9"/></dir><dir name="Helper"><file name="Data.php" hash="293672cfd547d65ff94b80b3bf932d39"/></dir><dir name="Model"><dir name="Mysql4"><dir name="Queue"><file name="Collection.php" hash="d041d29b798d10821e041c5b89fb5889"/></dir><file name="Queue.php" hash="2b0ba0993a43cc6856647684ac30add9"/><file name="Setup.php" hash="05b0a2d4806e712410479a3e7c709fd8"/></dir><file name="Observer.php" hash="b2f1bbc074be667a0cd60c2c886c372c"/><dir name="Order"><file name="Observer.php" hash="5a05f37813b04968a2274098fdf8b1f7"/></dir><file name="Queue.php" hash="7cd8b2d37481d42e6450bd1f7baf491d"/><dir name="Quote"><file name="Observer.php" hash="1633b1031f19bdd36145b1040d9d6692"/></dir><dir name="System"><dir name="Config"><dir name="Backend"><file name="Cron.php" hash="9bc2a90d644af8334aa22b952132b08f"/></dir><dir name="Source"><file name="Description.php" hash="7f497c17388c360f239e2aa90d943b9c"/><file name="Price.php" hash="283cc883ded57664870d89b22b547b19"/></dir></dir></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="OrderController.php" hash="9029b7316cf28467e03525000af880ad"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="784d322d920c63e63bed37c50e1c04d1"/><file name="config.xml" hash="57a8d0e86c320403b17676cf9de2eaca"/><file name="system.xml" hash="5333f04e2f8371c8ab7710ff42bea238"/></dir><dir name="sql"><dir name="bronto_order_setup"><file name="mysql4-install-1.0.0.php" hash="4988c452cc0d367f34e9c33df0d4256d"/><file name="mysql4-install-1.1.8.php" hash="afd415c7bb5a81b18c6705293f3978e6"/><file name="mysql4-upgrade-1.0.0-1.1.6.php" hash="0c42c6e3539b0f07c76b4f2c582d110f"/><file name="mysql4-upgrade-1.1.6-1.1.7.php" hash="7c4d2c1feed28b964ea82373e625a11f"/><file name="mysql4-upgrade-1.1.7-1.1.8.php" hash="ae58d4271deb9c60e61214020d46e755"/></dir></dir></dir><dir name="Reminder"><dir name="Block"><dir name="Adminhtml"><dir name="Delivery"><dir name="Grid"><dir name="Renderer"><file name="Customer.php" hash="be1537b58943a2cc27982deb03ec9e39"/><file name="Fields.php" hash="04f0dc7c4a24769cfc68f1508e0d338b"/></dir></dir><file name="Grid.php" hash="472fa8302dae712fbf9a6b6f5ea80dd0"/></dir><file name="Delivery.php" hash="b0bd1dcede57f8dad8ba4416b26d3986"/><dir name="Promo"><file name="Notice.php" hash="437ce674b25c14e33e17e09a0d471176"/></dir><dir name="Reminder"><dir name="Edit"><file name="Form.php" hash="2db520c0f438affbf477801ddde7f9cf"/><dir name="Tab"><file name="Bronto.php" hash="3b49a4f78038b8ac6de5390c2a73151d"/><file name="Conditions.php" hash="71d7c0a13352ec3d5b19b6bc059238bb"/><file name="Customers.php" hash="955c3e21ccc4a6e165abd38410383422"/><file name="General.php" hash="10012f0027d5ecf28a24ea84c2410be0"/></dir><file name="Tabs.php" hash="106e44febc4b6a7a3928c5dec68d6123"/></dir><file name="Edit.php" hash="783ca6f21744c56da930fd44ddc6e3a5"/><file name="Grid.php" hash="c87a852ef998ea17af709c0221abd15d"/></dir><file name="Reminder.php" hash="a55e63b29f9cafd9053696f60ffe993f"/><dir name="System"><dir name="Config"><file name="About.php" hash="8380b5e750fe0f2b5b95407c99d2e195"/><file name="Cron.php" hash="84100d0bffc2e16d84bc24577ba9c6bf"/><file name="Settings.php" hash="5d0042b1b2ad5df43856c0a68d63b3b4"/></dir></dir><dir name="Widget"><dir name="Grid"><dir name="Column"><dir name="Renderer"><file name="Email.php" hash="bcc3abd5bbbb5e8f6e19454850d2e8dd"/><file name="Id.php" hash="c35c0feeac92dce912bb8e3ad2cc7e6e"/></dir></dir></dir></dir></dir></dir><dir name="Helper"><file name="Contact.php" hash="4b3e67cf3a0ce095ca454fe4513c6e89"/><file name="Data.php" hash="b0ffcbf133cfeb61b93218f1846d6c34"/><file name="Message.php" hash="b65f0a4095ab4671c57a26451b3cc524"/></dir><dir name="Model"><dir name="Condition"><file name="Abstract.php" hash="3e164c6f67c1ca26c0be533cd9fc1b0c"/><dir name="Combine"><file name="Abstract.php" hash="2a43ca00f8bc4ab36bc87654ad9c6191"/></dir></dir><file name="Delivery.php" hash="41c3912dc5b5cb28d828358c1e0f7bc4"/><dir name="Email"><file name="Message.php" hash="c3b99ab7af9a776b98ffbcca3fecdcc6"/></dir><dir name="Mysql4"><dir name="Customer"><file name="Collection.php" hash="577bd12e2df9940fe551fe41c96133cf"/></dir><dir name="Delivery"><file name="Collection.php" hash="1247c3f58061d41f66ee6b9483c200ca"/></dir><file name="Delivery.php" hash="3639d2739b29734ba8aa8950e67e9621"/><dir name="Rule"><file name="Collection.php" hash="a99264c81d15780f305b02cde1564461"/></dir><file name="Rule.php" hash="07e9ddcf7c87a730fd9f8f9279a3fdb0"/></dir><file name="Observer.php" hash="299bca8979d361a027fe4ac1598df2f4"/><dir name="Rule"><dir name="Condition"><dir name="Cart"><file name="Amount.php" hash="b1bd2bd9aabb863184461b0594dad9b0"/><file name="Attributes.php" hash="74cfde1032d8d75241f7522ddc12e11d"/><file name="Combine.php" hash="660f6842b8c1a5acff2c3b4f12fc73a9"/><file name="Couponcode.php" hash="84ef3ecb8bcd57412af80a0d137335bb"/><file name="Itemsquantity.php" hash="50eae47f28bf3660ee0684c9037f5bf8"/><file name="Sku.php" hash="12a7af32e16e21d2a2e4e157c469d1e5"/><file name="Storeview.php" hash="c2310efcb3060e91bf2aab73b0ac8ca9"/><file name="Subcombine.php" hash="c8ad5b2c46116793e2f2df17fe0862c0"/><file name="Subselection.php" hash="0142065f76b4e24ec75b6685eea82642"/><file name="Totalquantity.php" hash="8e492fb70a94549b8d6adbc50b2a4e50"/><file name="Virtual.php" hash="cd12a3218daf4a447b4fd49141101305"/></dir><file name="Cart.php" hash="4d534abf3f1cf1459fe6713788efe66e"/><dir name="Combine"><file name="Root.php" hash="eb4b22b6554b507b61f3e6be30048b07"/></dir><file name="Combine.php" hash="2f15f1241aa71fd76bb511415c6882a3"/><dir name="Wishlist"><file name="Attributes.php" hash="0ecf162a2fc4225ce37de714da9e6210"/><file name="Combine.php" hash="279af17bec3eeb6a97243a93eb4e3f85"/><file name="Quantity.php" hash="8de8793029340cb8c813e0cf034f372d"/><file name="Sharing.php" hash="ad302122deb2065aa28b68748cfae492"/><file name="Storeview.php" hash="83716681ba30c6d4c48dada3a0973971"/><file name="Subcombine.php" hash="4804ad602e3cc622dbfcab4030dff1c2"/><file name="Subselection.php" hash="68d96f6943becdc728f2aa436a8ac4c7"/></dir><file name="Wishlist.php" hash="f5c474dd7b126d69a3e0f7000abd3a95"/></dir></dir><file name="Rule.php" hash="8912deab112d5789cd975b7907c0d4ea"/><dir name="System"><dir name="Config"><dir name="Backend"><file name="Allowsend.php" hash="61965e981ddd79976f0ee21b01e6a0ae"/><file name="Cron.php" hash="6e527885884985fca33236f40a7f3689"/></dir></dir></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="DeliveryController.php" hash="d4630eff20209e0d46b08a29b543979a"/><file name="RemindersController.php" hash="6cd60b0a9c33075640c5926d94a78405"/></dir><file name="LoadController.php" hash="16f4bf9c99a8e0bb0b369e75141f49b2"/></dir><dir name="etc"><file name="adminhtml.xml" hash="baaae901f8ff9d2ab12b0158ed5a4ca7"/><file name="config.xml" hash="47791bb04d1362ba39cd6ccff9eed0f7"/><file name="system.xml" hash="794fa3826fa84526997e4f8c3ef2e4ef"/></dir><dir name="sql"><dir name="bronto_reminder_setup"><file name="mysql4-install-1.4.12.php" hash="eae3eb4a69de44df200c52001783a4f0"/><file name="mysql4-install-1.4.13.php" hash="12419b6117a9e0e10f565453feed8740"/><file name="mysql4-install-1.4.14.php" hash="be67c1c55e1781c652d0036984fd0866"/><file name="mysql4-install-1.4.15.php" hash="f2bc98906fc36bf0640b292851ab99e1"/><file name="mysql4-install-1.4.16.php" hash="e34c42b202a7435abe2fa46f01bde257"/><file name="mysql4-install-1.4.2.php" hash="07b5a7b8ef247def75617e92738f0950"/><file name="mysql4-upgrade-1.4.0-1.4.2.php" hash="fefa638ca0ed7c5bc80a1b67e27c8703"/><file name="mysql4-upgrade-1.4.10-1.4.11.php" hash="130a688eb03e4f476308d0d11c32141a"/><file name="mysql4-upgrade-1.4.11-1.4.12.php" hash="766c901369f06aaadc8ffde3befb4aaa"/><file name="mysql4-upgrade-1.4.12-1.4.13.php" hash="172b48942497efd2305eff260bc28d9c"/><file name="mysql4-upgrade-1.4.13-1.4.14.php" hash="3218dae864cac00ff74655160ad31663"/><file name="mysql4-upgrade-1.4.14-1.4.15.php" hash="2e842e4c18259590cdafd2139dd4eb7e"/><file name="mysql4-upgrade-1.4.15-1.4.16.php" hash="671f39e2f90faf1165d50b517be8e04f"/><file name="mysql4-upgrade-1.4.2-1.4.9.php" hash="4692060e7c938aea129c53619f0b3c19"/><file name="mysql4-upgrade-1.4.9-1.4.10.php" hash="9698883135211d54a3c711fead02c187"/></dir><dir name="reference"><file name="saveMatchedCustomers.sql" hash="c4f32ee8be31f7a652369c148271a6c7"/></dir></dir></dir><dir name="Reviews"><dir name="Block"><dir name="Adminhtml"><dir name="System"><dir name="Config"><file name="About.php" hash="b62835e11224c3e8cb7256715d145814"/></dir></dir></dir></dir><dir name="Helper"><file name="Contact.php" hash="a85da1e1cc10dd48ac88b84d91cb9a1d"/><file name="Data.php" hash="5954ecf590d8c0e1587938c192d447fd"/><file name="Message.php" hash="df3015f886b4dd283d280cf26ee69cc7"/></dir><dir name="Model"><dir name="Mysql4"><dir name="Queue"><file name="Collection.php" hash="c36aecae4ebb1de05835be6c02cd6875"/></dir><file name="Queue.php" hash="52ecc7632d642c9ee3fec1141aba9c30"/></dir><file name="Observer.php" hash="cb1be9cbfcd1310502e7f476d911069a"/><file name="Queue.php" hash="45aea4c54a465d5ea9110cdd853de23b"/><dir name="System"><dir name="Config"><dir name="Source"><file name="Message.php" hash="9a5e15326017cbebd7b59b5c80693685"/><file name="Orderstatus.php" hash="8b1d5d0ede3627d212595be7fa93494e"/></dir></dir></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="35bed0690cd9f58063c0c5e03e057469"/><file name="config.xml" hash="77fe8f2486ae74b11ac75f8101a8a554"/><file name="system.xml" hash="4cd3c0bc7418c0b38dcc1b29006ad3ad"/></dir><dir name="sql"><dir name="bronto_reviews_setup"><file name="mysql4-install-0.0.1.php" hash="7c405d3819f5c79ec405dc372ee38dc5"/></dir></dir></dir><dir name="Verify"><dir name="Block"><dir name="Adminhtml"><dir name="System"><dir name="Config"><file name="About.php" hash="b50a08cd24985483cad82c76305da5ce"/><dir name="Advanced"><file name="Observersearch.php" hash="0351378eb6fbfa8e9b1cde55a9b589e5"/></dir><file name="Conflictchecker.php" hash="cf1736b689d1ef2b3f0b7d7d84b703ba"/><dir name="Form"><dir name="Field"><file name="Apitoken.php" hash="cb84fee5b4e18ca0092f385d6ede6711"/><file name="Button.php" hash="7041c0e923d9929796597160679bc94c"/><file name="Classpath.php" hash="c9c60b09c180960dd107d74f79b63edc"/><file name="Conflict.php" hash="3797f7f88329ecf4d5c9e3e48c9c89e5"/><file name="Events.php" hash="c88df55f9105d0aa5a1574bc37c5a8f8"/><file name="Index.php" hash="612cf825df2f10c0d4d00ac54f413aba"/><file name="Roundtrip.php" hash="4b84fb21a59f5939ab7361dcc816ce1d"/></dir><file name="Magecron.php" hash="2e3817a852f8a57444e8a0c54f87fda7"/><file name="Permission.php" hash="e5185de6bc1976ee7497956cc9162a17"/></dir><file name="Installs.php" hash="961665a9ceea68e9165fece4150fdfdb"/><file name="Permissionchecker.php" hash="6f0be4f5594afe1f6924b839db582180"/></dir></dir><dir name="Widget"><dir name="Button"><file name="Classpath.php" hash="1687def566fccc786c263d94b4c9c9b5"/><file name="Conflict.php" hash="473cda5cc65b9302efb3618c3b5af973"/><file name="Events.php" hash="3da5bc0026613dfd921a25a942fb3d7c"/><file name="Permissions.php" hash="b89e87e9b6848cde87a4f6343b3feb1a"/><file name="Runroundtrip.php" hash="5a98f930b382a7a0c01f3b346def4955"/><file name="Runtoken.php" hash="63a721c0a25bdbd58be941ba7c5d21c8"/></dir></dir></dir><file name="Conflictprinter.php" hash="05a32eca413a0eda87bcdb7bd0661642"/><file name="Permissionprinter.php" hash="8925da12d1e8dc5f180327dd94d18310"/></dir><dir name="Helper"><file name="Apitoken.php" hash="bc1f30a551a958011fbba91310cab77d"/><file name="Conflictchecker.php" hash="55e0aacf4cd6e9d2b4d52ebe21fe7850"/><file name="Data.php" hash="6622f73bf7af3e1e68ad27551fb7d920"/><file name="Permissionchecker.php" hash="da5fc3a69e6477299084d210aaaad6b7"/><file name="Roundtrip.php" hash="b5566d978e4e24cf06bee83ab92772fc"/></dir><dir name="Model"><dir name="Config"><file name="Blocks.php" hash="0000df779f3e1fb60350b14b8a6185e3"/><file name="Checker.php" hash="a38555d682b302967410b73ebab04b4f"/><file name="ConfigAbstract.php" hash="79024697562751ff46c939d9d680fc86"/><file name="ConfigInterface.php" hash="45cecfde48e4ef0657a6418019f02e4a"/><file name="Datastore.php" hash="fb5ea494075ce81380d1447c07fa052c"/><file name="Helpers.php" hash="1dc143d542d3fd85ccff785f913556f1"/><file name="Models.php" hash="3062f1f3c4950d965054afe6b75b4b0f"/><file name="Printer.php" hash="dfd6bfdcc94a1afb83ae6c3599abb21c"/><file name="Resources.php" hash="24bbf7de88b25250a81a2d7380d5baa2"/></dir><dir name="Contact"><file name="Builder.php" hash="9d578480a7e4c8fde2a33e698a9efced"/></dir><dir name="Core"><dir name="Config"><file name="Base.php" hash="c11b6cbaf1802d3c6ab58853b468f5d7"/><file name="Element.php" hash="8a7c9221a95c1317a8ae166e692a4ee0"/></dir><file name="Config.php" hash="4afa2c4a35fd81b282aad0d873c5700e"/></dir><dir name="Lib"><dir name="Varien"><dir name="Simplexml"><file name="Config.php" hash="076958ed612323869d2437872744ed2a"/><file name="Element.php" hash="a8c28fd3b6b00ad689d4850e79441dec"/></dir></dir></dir><dir name="Mysql4"><dir name="Core"><file name="Config.php" hash="3b8fb36a66a675c4d12926bceadb4ea5"/></dir></dir><dir name="Path"><dir name="Locator"><file name="Array.php" hash="42fd6c7004b0f02f954956563edde9a0"/><file name="Factory.php" hash="46007808ba897fa6816fb7771a2b18dd"/><file name="IteratorAbstract.php" hash="a0b728053dc63e73edc8231fd169cebc"/><file name="LocatorInterface.php" hash="b775ce0d189ef276c9bbeade7da67b4f"/><file name="Stack.php" hash="328481c9d963f653a95f333fb440bea5"/></dir></dir><dir name="Resource"><dir name="Core"><file name="Config.php" hash="aa2fb8c4fb153e742c690ab8bc8b5a75"/></dir><dir name="Db"><file name="Abstract.php" hash="d668c24c90f80bc197c83eb0a3e10aa6"/></dir></dir><file name="Roundtrip.php" hash="437aa07b0f001bb29b20e9dda2ae81f8"/><dir name="System"><dir name="Config"><dir name="Backend"><file name="Magecron.php" hash="2745874b81ae4235aa885f78c2076561"/></dir><dir name="Source"><file name="Classtypes.php" hash="772cab11a7470a2dd68ece3688c68d6a"/><file name="Wsdlcache.php" hash="b7d9c1c4d271c03a7486fc86eec3b6d9"/></dir></dir></dir><dir name="Validator"><file name="Checker.php" hash="35799249fcc93b31ff12da539cfb0d84"/><file name="Directory.php" hash="aa05ae40ad0b7aaffffaa6063bd8561e"/><file name="File.php" hash="c29c1cd2140186dc67c5e62064b79c0f"/><dir name="Filter"><file name="PatternIterator.php" hash="c129a6ee0fb4a45ff52644da2c0abfa1"/></dir><file name="Group.php" hash="59ad6dd4232ee113e1fe8161a82148ba"/><file name="Owner.php" hash="69e1c54dca88532208ce1f35f4491d99"/><file name="Printer.php" hash="23a00ec415b8665e5457ac09939e2ab2"/><file name="ValidatorAbstract.php" hash="d043c743309f5d64640698953269ece6"/><file name="ValidatorInterface.php" hash="02f543af08eda65263f4b005f3b3bdaf"/></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="AdvancedController.php" hash="0942ed5d83442e97af40d4572c3e21f8"/><file name="ApitokenController.php" hash="f804594b22260cb597cc0e5cfe633093"/><file name="ConflictcheckerController.php" hash="1d23621c640eecf2a813121cfc23850b"/><file name="PermissioncheckerController.php" hash="2e254bd755cd9d05d7eb6865a2ffb0e7"/><file name="RoundtripController.php" hash="efb601f3ceca89885d031f06218b2a4d"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="d7aa2c1c8fa26ad3ab910940abd9199e"/><file name="config.xml" hash="7e4888e5556ea0e1b30cb8fde1c1120a"/><file name="system.xml" hash="a3cf28dcbfc85e82d362d38704f6da56"/></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Bronto_All.xml" hash="5a9c06b6313882589765b9bcf0402bbb"/><file name="Bronto_Customer.xml" hash="a11c20f008ee2eae14baa3b549d5adee"/><file name="Bronto_Email.xml" hash="b7cdca4b15753edcefe8b9e0abb780bd"/><file name="Bronto_Newsletter.xml" hash="2115c5225e02ab5d4e56749cc5eff6ad"/><file name="Bronto_Order.xml" hash="63f1537add6088417945657bec98ffe9"/><file name="Bronto_Reminder.xml" hash="08503ab78994178b822ef9b0add243f9"/><file name="Bronto_Verify.xml" hash="ad72ea2ebfd99dbe2773b2735d0ec973"/><file name="Bronto_News.xml" hash="3496cd7578991889909fbd8daa170d2d"/><file name="Bronto_Reviews.xml" hash="23a398c055d062c4a5e19e72a0c2df95"/><file name="Bronto_Emailcapture.xml" hash="98b59bbf388d6c715f345b8906bd2fa1"/></dir></target><target name="magelib"><dir name="Bronto"><dir name="Api"><dir name="Account"><file name="Exception.php" hash="1a851457b2a032fb6d149fe9ef111c57"/><file name="Row.php" hash="3ab1e97019ef87bcd464eeaabf652886"/></dir><file name="Account.php" hash="33b9ba8867fe69135391c26f98b5852a"/><dir name="Activity"><file name="Exception.php" hash="3ac1f2caea6465931cbf927f1033ec06"/><file name="Row.php" hash="de166130c57670bf486a783a4501e2d4"/></dir><file name="Activity.php" hash="f5f48488e40507bc108b35c599e4e5a2"/><dir name="ApiToken"><file name="Exception.php" hash="e06d0a4c9469da7333e6a596e9c37c5d"/><file name="Row.php" hash="f3742811cec1cbf0be583296b617dfbd"/></dir><file name="ApiToken.php" hash="65bbd18974bbbf620dc2df23bdeb4469"/><dir name="Contact"><file name="Exception.php" hash="809bdce6db3bb9c72a3173bb08c1b19e"/><file name="Row.php" hash="2e360d131c2abe19e154b5f3795a58f0"/></dir><file name="Contact.php" hash="55bab8398154e96db6b0ca3ed88718e0"/><dir name="ContentTag"><file name="Exception.php" hash="5a8bc58af480a574e8061c62ad5590b4"/><file name="Row.php" hash="e470d8bcd686d42a886e59d5184b5eed"/></dir><file name="ContentTag.php" hash="14f1cbefe1027338d28db301a1c2df3d"/><dir name="Conversion"><file name="Exception.php" hash="73dd991a663b99050428f54fc13fb433"/><file name="Row.php" hash="115d01ea0e0e6ade42fcab76dff71c35"/></dir><file name="Conversion.php" hash="60ec52dcfeda92294d1ab10bb29a486a"/><dir name="Delivery"><file name="Exception.php" hash="003dbb49ea3be65fe35dfa9b7ec743c5"/><file name="Recipient.php" hash="562bdc8d86b92ec293a338fdd7bf928a"/><file name="Row.php" hash="9c6149e74a305f62b9806df5a20e6a00"/></dir><file name="Delivery.php" hash="668dc6493cefe960c7dc8fe1fe87bf08"/><dir name="DeliveryGroup"><file name="Exception.php" hash="9291b2adb576a6781a0d624cc3288453"/><file name="Row.php" hash="29adb1f866cf1d24ef0abac19f95fbd0"/></dir><file name="DeliveryGroup.php" hash="7dd295b65f22e65dff3bf45c4336e985"/><file name="Exception.php" hash="bacb7c782ef7f612edaf3d39c20118ef"/><dir name="Field"><file name="Exception.php" hash="db651b9fa4b5161e3a32af49cc12cc64"/><file name="Predefined.php" hash="15fadb32175098d9ded60550d1748a4a"/><file name="Row.php" hash="6871d05f399a8a9dfa0742952eaa6481"/><file name="TypeGuesser.php" hash="1027ea97675a16cc964aa0d8ba63e642"/></dir><file name="Field.php" hash="32d5876335ec815acb50d3b4e7bf3ccd"/><dir name="List"><file name="Exception.php" hash="0f964fac998c89a0d4d515979bd81b98"/><file name="Row.php" hash="6516df43a1a94beee7b57fae71c27134"/></dir><file name="List.php" hash="ef240fe5e1422479a83291ad30b468ac"/><dir name="Login"><file name="ContactInformation.php" hash="bc1ce7f57c67fa21cd0881d0384a1cac"/><file name="Exception.php" hash="fff7546235b416b7008a9e4bd646fc19"/><file name="Row.php" hash="578553fcbf1941d0eb5890614c57ae91"/></dir><file name="Login.php" hash="a61cf5ac4c3ea76b03a71750e085df88"/><dir name="Message"><file name="Exception.php" hash="755f7f14cdb234931708968ac0bad4a4"/><file name="Row.php" hash="5732b5550c8c6444790f2f20e626ff08"/></dir><file name="Message.php" hash="cc3c9939757371ad7fd2d297df394621"/><dir name="MessageRule"><file name="Exception.php" hash="b0398ee96ed70c483f38b50f305e82a8"/><file name="Row.php" hash="8e7532184ee265a927a195ac36e5a518"/></dir><file name="MessageRule.php" hash="ae1b3f16683656066a83bcf9f2863710"/><file name="Object.php" hash="4ea2880431ac5761cbf7478d809577f6"/><dir name="Order"><file name="Exception.php" hash="8312e1a1ab46bcf88b72983bb11a6493"/><file name="Product.php" hash="3785f2f460fec6c18c6164176de52449"/><file name="Row.php" hash="1400de022188806bb94e98544c054ef6"/></dir><file name="Order.php" hash="ad690b37bc577879020d10e5ac70ef3d"/><dir name="Row"><file name="Exception.php" hash="4c1a45512e0912644f94a88d4298d3a9"/></dir><file name="Row.php" hash="259418b11987939378747a9c46fae1ae"/><dir name="Rowset"><file name="Exception.php" hash="b5202ed6f61bfe06b90f73c03ca28ffa"/><file name="Iterator.php" hash="9ea7a244b83e7b9318bfe8ed371a149f"/></dir><file name="Rowset.php" hash="3f40382933e2f392b6320fd79db720cd"/><dir name="Segment"><file name="Exception.php" hash="bd5c2302ef222ff55981cc38477a9310"/><file name="Row.php" hash="b840493b8b2c3cb6686de0e5bedfa2ba"/></dir><file name="Segment.php" hash="0cf99babff6169afa427f302c76023dd"/></dir><file name="Api.php" hash="17aace21dbebcab84a80091230ca03e9"/><file name="Observer.php" hash="21bc70d405fcd47b0473ac89fd3d4ae2"/><file name="SoapClient.php" hash="81dd0a8a8c15ac96280d2f1b6bb3311e"/><dir name="Util"><file name="Colors.php" hash="14313213b3a70c79a56c574523b9b90b"/><file name="CountryCodes.php" hash="4efb9c354d29a901368c46aab40f79d4"/><dir name="Retryer"><file name="FileRetryer.php" hash="bdc72ace54ace32081115442d28cb972"/><file name="RetryerException.php" hash="54b70d7abbc32b55649a193e8e70dcb5"/><file name="RetryerInterface.php" hash="cc57d5a02a55811a13a31ed9beff126f"/></dir><file name="Uuid.php" hash="ba62bdec6488ccb621e0bfd726c6107a"/></dir></dir></target><target name="mageskin"><dir name="adminhtml"><dir name="base"><dir name="default"><dir name="bronto"><file name="bronto.css" hash="ebc2f1ade554e3cad4bf0b091ff674d1"/><file name="cron.css" hash="90af6378226e13e17b7329132d41e0e7"/><dir name="images"><file name="BrontoGuide.png" hash="be2bb3605cc5f1899ad996fcd2ceae84"/><file name="InstallStatusDisabled.png" hash="5cf8d7dd8ed623f8b38e6ea3ed89861a"/><file name="InstallStatusEnabled.png" hash="11ea6d1f0ba319b62ed1728e9b747108"/><file name="InstallStatusError.png" hash="91fdd0af3ffd20d0b8a77645bb9cfcdc"/><file name="ajax-loader-tr.gif" hash="1ae32bc8232ff2527c627e5b38eb319a"/><file name="bg_notifications.gif" hash="df73b8aa7e48bb56e0a644245aa3683f"/><file name="bronto-mini-off.png" hash="af2c6a5434604db0bb3a2cc4a51b5c77"/><file name="bronto-mini.png" hash="7989c68c0e83b7b04af308780aa82259"/><file name="bronto_contact-mini.png" hash="e221b304ad42cba129a9dcf17ce5180e"/><file name="bronto_contact_import-mini.png" hash="a9e0904f7219be45fd1ed88c5b9a1650"/><file name="bronto_general-mini.png" hash="aca50d84fe324abbb36ff2853d9cad01"/><file name="bronto_help.png" hash="d0ed63d7c68e8b52583ce428b3846afc"/><file name="bronto_news-mini.png" hash="bb8b3beb16c10d8b38ddb11f3f4347e8"/><file name="bronto_newsletter-mini.png" hash="9c45a6dd689ad758cf927cb381621b35"/><file name="bronto_order_import-mini.png" hash="a2b13488fccfdd5b2194843800abadda"/><file name="bronto_reminders-mini.png" hash="c85bafdc82718769c8b801fd64e7bd72"/><file name="guide.png" hash="10c880d9e40f1283f99e02ce2d025a4f"/><file name="logo.png" hash="3b7c4cb9faf220091a5fbae3c7f87afa"/><file name="message_approved.gif" hash="465a056a3ba3d94367f51c3c0b751391"/><file name="message_not_approved.gif" hash="e4f28607f075a105e53fa3113d84bd26"/><file name="section_logo.png" hash="98f2570d14580cee2c6cf66cca540b39"/><file name="site_name.png" hash="fb2cc4e1e00cdc95a94c04fccfa5e1b3"/><file name="support.png" hash="0910e2eb718379d037ead6e0af9c4855"/></dir><dir name="js"><dir name="guider"><file name="README.html" hash="be17cdbc961dc921944cef4e7daa33c3"/><file name="README.md" hash="1c11ec7951035fe0611edded566901a0"/><file name="changelog.txt" hash="4c107fe228a620f6f3118b128e62c0b5"/><file name="clock.gif" hash="12aa3f72e722ac8e5eeb68823024278f"/><file name="component.json" hash="05fe7fcf63c00abd58efa072baa8248f"/><file name="guiders.css" hash="a6df4a6e2d4f3075e29841a6844ee30b"/><file name="guiders.jquery.json" hash="261d2b3a2d3a21e49a0153f0c8f2c3e9"/><file name="guiders.js" hash="42b1675f9d1a93b89d62e97f2db895bb"/><file name="guiders_arrows.png" hash="757812709656e9592d9d724a63624d0d"/><file name="guiders_x_button.jpg" hash="2af6c2b68534a8b2c48d0ddc14a5b801"/><file name="jquery.min.js" hash="0652da382b6fceb033dfe2b6c06d4d11"/><file name="promo_gmail.png" hash="4837435633204a9001b88c2d8ef451ed"/></dir><file name="jquery-1.10.2.js" hash="91515770ce8c55de23b306444d8ea998"/><file name="jquery-1.10.2.min.js" hash="628072e7212db1e8cdacb22b21752cda"/><file name="jquery-1.10.2.min.map" hash="6c3ccfc221d36777d383b6e04d0b8af9"/><file name="jquery-noconflict.js" hash="3179f2255b046d5f2e9a71e365287bef"/></dir><file name="news.css" hash="84d2866b08b706164c6e545767ff331a"/></dir></dir></dir></dir></target><target name="magedesign"><dir name="frontend"><dir name="base"><dir name="default"><dir name="template"><dir name="bronto"><dir name="common"><file name="popup.phtml" hash="d81fa7237b4fb63fcc970e73d71a6cc6"/></dir><dir name="emailcapture"><file name="js.phtml" hash="d7920693b4aefb498610d65dbebca42a"/></dir><dir name="newsletter"><file name="checkbox.phtml" hash="a19c0ff807258ffe398704fde325cfab"/><file name="js.phtml" hash="dc11829ac113c50e93bdc08580998af0"/></dir><dir name="order"><file name="js.phtml" hash="e398cfbfe9df41feeadb251216422cd9"/></dir></dir></dir><dir name="layout"><dir name="bronto"><file name="common.xml" hash="f1e7ee067163e84f2e3bfc5474b3647d"/><file name="emailcapture.xml" hash="b5d3b0efc5daffb5fa66561f690013d0"/><file name="newsletter.xml" hash="b7d4c9b1fb4fabb4255c6df64e98d332"/><file name="order.xml" hash="fba740927a514649988b16e8f936072b"/></dir></dir></dir></dir></dir><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="template"><dir name="bronto"><dir name="api"><file name="guide.phtml" hash="e0be3aa741add86dc5f297fcc09c714a"/></dir><dir name="common"><file name="about.phtml" hash="fa5886d9dba15226eec520916b7c4aa2"/><file name="cron.phtml" hash="80af8ca4a8e2c74449904748aeaf718b"/><file name="guide.phtml" hash="07bcf3ad2e6a9136888bbf4a8bf0b51d"/><file name="guiders.phtml" hash="790ac5e5f8df13753db5ac3e68d08d76"/><file name="suppressed.phtml" hash="07fd355b58dd1c9ee074c7fb132545e2"/></dir><dir name="customer"><file name="guide.phtml" hash="14e9b74f62bde430a6df96cf04ee94dc"/></dir><dir name="email"><file name="guide.phtml" hash="c8fe9f3cadf5e50d6f0e69979462c407"/><dir name="template"><file name="edit.phtml" hash="802ef394d1943f18d33d39d0b85dcc3d"/><file name="list.phtml" hash="e9eb7ffc48f9d17a21917d86ff18b0fc"/></dir></dir><dir name="news"><file name="guide.phtml" hash="19026e62d49476371edc4f9e7f68d2c1"/><file name="item.phtml" hash="7146fcc10eeb0bdc33a78ea8fe060f74"/></dir><dir name="newsletter"><file name="guide.phtml" hash="58cb7d63937a756afd939c0c69edeccb"/></dir><dir name="order"><file name="guide.phtml" hash="831ff327cf49d198bec62ad968587593"/></dir><dir name="popup"><file name="guide.phtml" hash="6bd6240f1402a03dd0d5022b8c39b3ab"/></dir><dir name="reminder"><dir name="grid"><file name="container.phtml" hash="28518ad2522f1b213102eb52071ef247"/></dir><file name="guide.phtml" hash="db033c357b5e335b6d65a44fa78c7c7e"/></dir><dir name="reviews"><file name="guide.phtml" hash="caad8c25594859c554a1fa1e505c92f0"/></dir><dir name="verify"><dir name="advanced"><file name="observer.phtml" hash="775deb643169f76f72793873a258eac1"/></dir><file name="advanced.phtml" hash="8479f4762de8943de234407bbc80b679"/><dir name="conflictchecker"><file name="errors.phtml" hash="91adf7e31ce9ec1ae06c18adb489bf54"/></dir><file name="guide.phtml" hash="664368c479f04ef022e9f0f96b2b9eca"/><file name="installs.phtml" hash="34b6bd602043376f8c17ef7744a27537"/><dir name="permissionchecker"><file name="button.phtml" hash="0a98a58dcb6d28d768e83556e6e690bc"/><file name="errors.phtml" hash="6da7357831323392e3badcb1cc8268aa"/><file name="index.phtml" hash="628a80e9245642cb92cc75a6dd07d1d7"/></dir></dir></dir></dir><dir name="layout"><dir name="bronto"><file name="common.xml" hash="17249c1370a12a8c0a68959d217f88f0"/><file name="email.xml" hash="be77c906770a0d818898a910b03cbe4f"/><file name="news.xml" hash="96d679b735d551a3e83fb71bfe2a7fca"/><file name="reminder.xml" hash="07186394676c6db016d00bdee53e8394"/><file name="verify.xml" hash="e5676df09f0a79bdedc314e2bfdb4b59"/></dir></dir></dir></dir></dir></target><target name="mage"><dir name="shell"><dir name="bronto"><file name="cron.php" hash="7f6eaae8f93fd3a63df8b498d485c108"/><file name="fix.php" hash="98e9ea41e1faae9a3f211b1a82afe217"/></dir></dir></target></contents>
61
  <compatible/>
62
  <dependencies><required><php><min>5.2.13</min><max>6.0.0</max></php><extension><name>soap</name><min></min><max></max></extension><extension><name>openssl</name><min></min><max></max></extension></required></dependencies>
63
  </package>
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>Bronto_Extension</name>
4
+ <version>2.3.0</version>
5
  <stability>stable</stability>
6
  <license uri="http://opensource.org/licenses/osl-3.0.php">OSL</license>
7
  <channel>community</channel>
55
  &lt;p /&gt;Bronto Software provides a cloud-based marketing platform for retailers to drive revenue through their email, mobile and social campaigns. The platform is used by over 1000 organizations worldwide, including Party City, Armani Exchange, Timex, Samsonite and Gander Mountain. Bronto is a Gold Magento Industry Partner and the leading self-service email marketing provider to the Internet Retailer Top 1000. Bronto is headquartered in Durham, NC with an office in London, UK. For more information, visit &lt;a href="http://bronto.com"&gt;bronto.com&lt;/a&gt;.&lt;/p&gt;</description>
56
  <notes>&lt;p /&gt;For installation and configuration instructions, as well as a full list of new features and known issues, please review the &lt;a href="http://a.bron.to/magento"&gt;Implementation Guide&lt;/a&gt;.</notes>
57
  <authors><author><name>Chris Geiss</name><user>BrontoSoftware</user><email>chris.geiss@bronto.com</email></author></authors>
58
+ <date>2014-05-16</date>
59
+ <time>18:38:36</time>
60
+ <contents><target name="magecommunity"><dir name="Bronto"><dir name="Common"><dir name="Block"><dir name="Adminhtml"><dir name="System"><dir name="Config"><file name="About.php" hash="ceee3ef00dcfde90f82ce80a5119ed56"/><dir name="Cron"><file name="Error.php" hash="ccaf02afd320c2a60b271bcf728c723a"/><file name="Queue.php" hash="07a829044a251dbfdcc39fcdd0d643b9"/></dir><file name="Cron.php" hash="ff26632f20d0474d45ae0549634b4f7c"/><dir name="Form"><dir name="Field"><file name="Apitoken.php" hash="48fe102c7d74b7646de1e256f87cfe87"/><file name="Debug.php" hash="6b3e65c774d25184e88c43e7364d68b4"/><file name="Download.php" hash="6521c641550b7c747632fe25dd5982ed"/><file name="Hidden.php" hash="c514ae120d4dced7b92ea30a13f0e4ea"/><file name="Image.php" hash="9de445fac8d262bb023f123d1e4df9e5"/><file name="List.php" hash="907853b5009661b6b63a3a2947fc9c59"/><dir name="Support"><file name="Site.php" hash="9e0b6acae1053a90a7513a3791ee258c"/></dir><file name="Support.php" hash="f680904d05213ec4d43726b714cf2b69"/></dir><file name="Field.php" hash="932af08da6e8dc20e74e97894b1a2518"/><file name="Fieldset.php" hash="a3d41e7bfc09bd81942c6f32bc1d1782"/></dir><file name="Guide.php" hash="2f283c5082306106c6793a53846ce403"/><file name="Support.php" hash="be33bc95f1f713205dd11fb59598e166"/><dir name="Suppressed"><file name="Reset.php" hash="50dfcb14e043c3128ac9c33dc14c2951"/></dir><file name="Suppressed.php" hash="064ad003588f58f65d6b827109ea2d94"/></dir></dir><dir name="Widget"><dir name="Button"><file name="Abstract.php" hash="8c082611a7e4131c897ae9f2ed1d6dcf"/><file name="Debug.php" hash="e841017705d9b45a33e8475144ff0587"/><file name="Download.php" hash="78de702f642111af6feb725b4dd0bf08"/></dir><dir name="Queue"><dir name="Button"><file name="Run.php" hash="d05c28fcd3f1ee0fb031ebb9d4fcfe39"/></dir></dir></dir></dir><file name="Popup.php" hash="37f63a3196ff4e533069753569b83ff6"/></dir><dir name="Helper"><file name="Api.php" hash="aa11d557111359c4310006c41764a4a3"/><file name="Contact.php" hash="261a6f75641e8b523f9732642244e8ce"/><file name="Data.php" hash="1ef11fbb9bf92965d4406b57e3b515cb"/><file name="DataInterface.php" hash="d1691f590c315abd3178e769cf51fe2a"/><file name="Field.php" hash="7c208abd6c77057e1e400f6699be77df"/><file name="Message.php" hash="5484ec49ce8ab8fda12d9dc6c4c29c65"/><file name="Product.php" hash="11775a052258f97fc8456d4fef981c76"/><file name="Salesrule.php" hash="6b7fcccb7b96f27b02ff864e7d9640dd"/><file name="Support.php" hash="c20c3e73c23a70cdaebb61815e2ce33e"/></dir><dir name="Model"><file name="Api.php" hash="72817e825da18d2c88800385cd3c6eca"/><file name="Archive.php" hash="b613e811bb673c72e6cec6770ed48fa5"/><file name="Delivery.php" hash="1c43e226d7c174f655533299bbf15359"/><dir name="Email"><dir name="Template"><file name="Filter.php" hash="243b2d9c62c643d518222f4a8b1f87d5"/><file name="Templatefilter.php" hash="c3acf3b4be3dcce490b1e07c0ab68e38"/></dir><file name="Template.php" hash="3624e7a3cdf1a469af6b5bd8d7e7e41e"/></dir><file name="Error.php" hash="8270252828229cad2c3b35f22e898b4d"/><file name="Keysentry.php" hash="ed1603a0954baaf716219d717e65f5b5"/><file name="List.php" hash="2c8dfbafde292aaff1df9edf83764768"/><dir name="Mysql4"><dir name="Api"><file name="Collection.php" hash="9b589f17c2efee2866369d6fd0c73279"/></dir><file name="Api.php" hash="79e25f0be61ef7ce5066c676545ab19d"/><dir name="Error"><file name="Collection.php" hash="cdd8617db0383a5dd23787850c26bfe3"/></dir><file name="Error.php" hash="2959715e0def582a6a0ecdf6f6442701"/><dir name="Queue"><file name="Collection.php" hash="f01c3c398021de80f48482067aa00f83"/></dir><file name="Queue.php" hash="3cdfeee0097797c9fc5955f4e777b2b5"/></dir><file name="Observer.php" hash="cc2332796caeed955bae5cd57aaf6ada"/><file name="Queue.php" hash="4ba90f26cb73865f2a421cbae77e7b5f"/><dir name="Resource"><file name="Abstract.php" hash="94c055df340089d679a7537318bcae2c"/><file name="Setup.php" hash="ecf628dc377923417762fc5f46374dec"/></dir><file name="SoapClient.php" hash="38ea95b32c1271d3ac329979c4f5d7a0"/><dir name="System"><dir name="Config"><dir name="Backend"><dir name="Cron"><file name="Error.php" hash="38bbbcde58aa89e3f7be043a773feb26"/><file name="Queue.php" hash="4c869a3fcddd597d217f3c3d721ee272"/></dir><file name="Cron.php" hash="1aa481a63198c64fafc90abe93166116"/><file name="Enable.php" hash="2b641958cfa59bd18992a8b92af99301"/><file name="Token.php" hash="b553ffa7c97b9d82c0e2bd389cc64d4f"/></dir><dir name="Source"><dir name="Contact"><file name="Status.php" hash="811a360bffa20b92d4a7bdea66a73168"/></dir><file name="Coupon.php" hash="b567df5b6e6f58681267855ec1399c59"/><dir name="Cron"><file name="Frequency.php" hash="3ef5bda79548019f9a7cb2007c6792f5"/><file name="Minutes.php" hash="136df1bc4c4723efdbe144ed7a08806e"/></dir><file name="Field.php" hash="7a4660fbc812dca134b69b3cef76ea57"/><file name="Image.php" hash="acb902acd1f8573887ed9d5a00410467"/><file name="Limit.php" hash="650092f63a83e7cb3c63d089c52820cd"/><file name="List.php" hash="c9fd7581386bc33c09e0e6edfdead420"/><file name="Message.php" hash="01c7e9d489c1ed7f07f011d5c044805a"/><file name="Related.php" hash="abcdf472699f5857d7755f0423bd27dd"/><file name="Role.php" hash="5a55bad277b8723130035d79d6e5b98b"/><file name="Synclimit.php" hash="40a063f7d2ac5e1ad6a9bfa773b22863"/></dir></dir></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="DebugController.php" hash="475d0fe8b46eb8a85c25d4f511a25196"/><file name="GuidersController.php" hash="8eae4825b247191bd166224ac79ea655"/></dir><file name="LogController.php" hash="c7e65dec2943bb1b0575396290629fdc"/></dir><dir name="etc"><file name="adminhtml.xml" hash="607b20af88d8bcb436ede8cfdbaeca73"/><file name="config.xml" hash="4f9ae15c9696bc76cb9d4826b2597601"/><file name="system.xml" hash="9c317f93497f702f12e07df80f0b1529"/></dir><dir name="sql"><dir name="bronto_common_setup"><file name="mysql4-install-1.7.0.php" hash="c8459d26fdfea2fb9430e8829b3257e1"/><file name="mysql4-install-2.2.1.php" hash="f2a33e687c2a2ee784c63ca9ba58ad5f"/><file name="mysql4-install-2.3.0.php" hash="f0f0313161b5b70ccd9f05d59f8f5e2b"/><file name="mysql4-upgrade-1.7.0-2.2.1.php" hash="f2a33e687c2a2ee784c63ca9ba58ad5f"/><file name="mysql4-upgrade-2.0.4-2.2.1.php" hash="f2a33e687c2a2ee784c63ca9ba58ad5f"/><file name="mysql4-upgrade-2.0.4.2-2.2.1.php" hash="f2a33e687c2a2ee784c63ca9ba58ad5f"/><file name="mysql4-upgrade-2.1.0-2.2.1.php" hash="f2a33e687c2a2ee784c63ca9ba58ad5f"/><file name="mysql4-upgrade-2.2.0-2.2.1.php" hash="f2a33e687c2a2ee784c63ca9ba58ad5f"/><file name="mysql4-upgrade-2.2.2-2.3.0.php" hash="f0b61c65157c4e1a71c775d3eecddca2"/></dir></dir></dir><dir name="Customer"><dir name="Block"><dir name="Adminhtml"><dir name="System"><dir name="Config"><file name="About.php" hash="bc63c93b5ff46fe2e6cb84a8c3249d12"/><file name="Cron.php" hash="418068c27078a2a4e56cdc36469f660b"/><dir name="Form"><dir name="Field"><file name="Rewardpoints.php" hash="c1918f7478737dcfba6b543fa006a4bc"/><file name="Storecredit.php" hash="489625264fff9d5a37621f1b80203099"/></dir><dir name="Fieldset"><dir name="Attributes"><file name="Address.php" hash="7871298d7b7410d5202b436a1f536d7c"/><file name="Customer.php" hash="b0060f6c8c71ec321387aa8071a5c483"/></dir><file name="Attributes.php" hash="0a93bc89eea36b70908ef805a4627d93"/></dir></dir><file name="Suppressed.php" hash="490d859076b067d91edc13eee7b91de8"/></dir></dir><dir name="Widget"><dir name="Button"><file name="Mark.php" hash="0c84d1f0e6ce3867e76d19ac7c451218"/><file name="Reset.php" hash="6dd540765670c2955160365319b9af22"/><file name="Run.php" hash="2b6332568132b633a1ee208e8b555b5a"/><file name="Sync.php" hash="be611c057f18b5da9e31927fc1788365"/></dir></dir></dir></dir><dir name="Helper"><file name="Data.php" hash="528d9a17f2e7dc654eecb5c9b3a92fbc"/></dir><dir name="Model"><dir name="Mysql4"><dir name="Queue"><file name="Collection.php" hash="5564536b725040d0652cba23e13e546e"/></dir><file name="Queue.php" hash="5aff6d99b2f3bf24cd2db7d0586f96ab"/><file name="Setup.php" hash="cb74c44bd42f407925a800fe3996d7a3"/></dir><file name="Observer.php" hash="9add6d23791f0b3ecb09c29def4038d7"/><file name="Queue.php" hash="7851ed2790e205473cf848c63a4f13a8"/><dir name="Resource"><file name="Customer.php" hash="86f081e728c9d9f22e28018406d9f601"/></dir><dir name="System"><dir name="Config"><dir name="Backend"><file name="Brontofield.php" hash="54432d8d5b2aec5395d21d21b9262162"/><file name="Cron.php" hash="44d12cea40d1342ad065bd4aad936193"/><file name="Newfield.php" hash="118d2622277e919e1f316f0713f5a2b7"/></dir></dir></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="CustomerController.php" hash="2d1104ca64e92a3e2afc475fc3792149"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="bb58fa0df1e07c2d88527fed1920ffc2"/><file name="config.xml" hash="e1a4673cdc939b1177c5ee2e8af678f6"/><file name="system.xml" hash="f88edd1bb6e03c332c4e15182d352c3a"/></dir><dir name="sql"><dir name="bronto_customer_setup"><file name="mysql4-install-1.0.0.php" hash="871c225318588b2804a05751bce45e1f"/><file name="mysql4-install-1.0.3.php" hash="79785fb104491dcc4713e55495f24ba0"/><file name="mysql4-upgrade-1.0.0-1.0.1.php" hash="1c00e987c9a1b1da70ad035ccdef194b"/><file name="mysql4-upgrade-1.0.1-1.0.2.php" hash="144999a033695bd72601f1f0e10de5e3"/><file name="mysql4-upgrade-1.0.2-1.0.3.php" hash="6e3c57a1c9272aa4b2d7d051a24ed87f"/></dir></dir></dir><dir name="Email"><dir name="Block"><dir name="Adminhtml"><dir name="System"><dir name="Config"><file name="About.php" hash="ab71e0649d5af1fe64f665ada8895be9"/><file name="Settings.php" hash="59f952e7baeff59ef013a9f39572370e"/><dir name="Templates"><file name="Field.php" hash="0b4d17701e352b6c28cd5262d3cd8e0e"/><file name="Fieldset.php" hash="01fa6905eec117df32519c7e461e05f8"/><file name="Label.php" hash="fed0e19a1dde5592ba2efcc3aa6a2bba"/><file name="Sendtype.php" hash="d93029708ba002781e365cb0215022ce"/></dir><file name="Templates.php" hash="5811fe4b83f7dd5d6f0c7c78314cd31c"/></dir><dir name="Email"><dir name="Import"><file name="Edit.php" hash="32d4219613247ff59a59b5031284159c"/><dir name="Grid"><dir name="Renderer"><file name="Action.php" hash="4227539615a40aa44810dc58f98b0ee8"/></dir></dir><file name="Grid.php" hash="8b4bc3d73c71763ef49f0ebd9ec6899a"/></dir><file name="Import.php" hash="a2f378383faebc5c0fabcd46feb4d7e3"/><dir name="Log"><dir name="Grid"><dir name="Renderer"><file name="Customer.php" hash="ee83b754d1a91920a79918991aa76ca6"/><file name="Fields.php" hash="dc0d7cbd5065382ccf51ff3f84054563"/></dir></dir><file name="Grid.php" hash="591f4aefd4fa2f7b5f53653f0d7780a7"/></dir><file name="Log.php" hash="755439eace3c8e1f5ee3c657562c476d"/><dir name="Template"><dir name="Edit"><file name="Form.php" hash="368b8f78e9f63ba8cf08b274fdad53b3"/></dir><file name="Edit.php" hash="e76c3c82fc3c180041eeeb6251fecbaa"/><dir name="Grid"><dir name="Renderer"><file name="Action.php" hash="543cf476631d073e4de5ec59f1faf5b5"/><file name="Storename.php" hash="c5111a20ed0b3aed0078cecb1ae3d739"/></dir></dir><file name="Grid.php" hash="1b459ceed577ff004f0c2725059da0d5"/></dir><file name="Template.php" hash="ea39c46962381b34377efa05ecbfa075"/></dir></dir></dir></dir><dir name="Helper"><file name="Contact.php" hash="60d8707e923f59ad7af130aa09557be0"/><file name="Data.php" hash="74ebeb479ac05c453d013387e449e306"/><file name="Field.php" hash="fc67415cbe73614fe0bbc29df7f93148"/><file name="Message.php" hash="7f5a80ce2a9a75324f8e5df9b3a318f4"/></dir><dir name="Model"><file name="Log.php" hash="1c9b060a801312c0b929806708a9ac1a"/><file name="Message.php" hash="02bf1f9bef1f4ce1909cc3d5c6331969"/><dir name="Mysql4"><dir name="Log"><file name="Collection.php" hash="0cc3245eea5df5ca8607fc4ca8aabf99"/></dir><file name="Log.php" hash="aef3718e6ea1de42152099aeb444782f"/><dir name="Message"><file name="Collection.php" hash="4ad21710a8a2c403e83dcf40ad6eda22"/></dir><file name="Message.php" hash="f225d9ac332aa3b0fea5ff094a336926"/><dir name="Template"><file name="Collection.php" hash="18afcaa13df2f01598598ad16d06d68a"/></dir><file name="Template.php" hash="496380271268f9f949afb2a2ce1bdbf9"/></dir><file name="Observer.php" hash="cd5b5e10dabdc615d77a99cb695d685c"/><dir name="Resource"><file name="Setup.php" hash="a5ffbf680ca31b236a6b8ce85766d064"/></dir><dir name="System"><dir name="Config"><dir name="Backend"><dir name="Templates"><file name="Field.php" hash="e6f28eb62a469792eb61ca1044aae764"/><file name="Sendtype.php" hash="18dadd39cdf47f6cdc95e168fe2012bc"/></dir><file name="Usebronto.php" hash="d9c1e9b77810c922b058d5f03f03b02e"/></dir><dir name="Source"><dir name="Email"><file name="Template.php" hash="81682056f6ab2a1deac481daea05ec46"/></dir><file name="Sendtype.php" hash="4cc496295bd5b4c2bf71eae9fd87f803"/></dir></dir></dir><dir name="Template"><file name="Import.php" hash="54b58a617a783f66493793a041abef2f"/><file name="Mailer.php" hash="4792fa983cec3d29aca946c393232b3b"/></dir><file name="Template.php" hash="f74e29c0fcc7528488e19f6aa89c57d7"/></dir><dir name="controllers"><dir name="Adminhtml"><dir name="System"><dir name="Email"><file name="LogController.php" hash="471e58f342857be6f023527c0a1d2981"/><file name="TemplateController.php" hash="7c5a78f80098c2b3a26690f72074fe91"/></dir></dir></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="2343ec1b1ac91db90d522cd64e797aa6"/><file name="config.xml" hash="47889f74fb4d8958f5d33b17a930dfd2"/><file name="system.xml" hash="6d44e576659600c2eee39ff95d9987de"/></dir><dir name="sql"><dir name="bronto_email_setup"><file name="mysql4-install-1.0.0.php" hash="516265312ede986c1a35a19b9e5bbfea"/><file name="mysql4-install-1.0.2.php" hash="327ac219e947d608fbf9d3209dd03bab"/><file name="mysql4-install-1.0.5.php" hash="327ac219e947d608fbf9d3209dd03bab"/><file name="mysql4-install-1.0.8.php" hash="b572625c1380dfffe3b089275ac1dc7e"/><file name="mysql4-install-1.1.2.php" hash="2824a3ef8b9308e577c792398598e08c"/><file name="mysql4-install-1.1.7.php" hash="f49bc2913b1c2375499f21f2ac9727cd"/><file name="mysql4-install-1.1.8.php" hash="afa3c83fbfe45fc193a7eda4af6afacb"/><file name="mysql4-install-1.1.9.php" hash="4509540dda05675ee192e0330effddd3"/><file name="mysql4-install-1.2.0.php" hash="153fc8a27833bda06046231eb0293230"/><file name="mysql4-upgrade-1.0.0-1.0.2.php" hash="1f797c3f909d72219ef5d00017b10554"/><file name="mysql4-upgrade-1.0.2-1.0.5.php" hash="f2c83b65500d9df0fd10c2e6721f2bfe"/><file name="mysql4-upgrade-1.0.5-1.0.8.php" hash="cdbda7aa084e51b9b222c56e548462a6"/><file name="mysql4-upgrade-1.0.8-1.1.1.php" hash="f2c83b65500d9df0fd10c2e6721f2bfe"/><file name="mysql4-upgrade-1.1.1-1.1.2.php" hash="53cf783db35699cdc1fee692752fe8de"/><file name="mysql4-upgrade-1.1.2-1.1.7.php" hash="105868a6253471d3eeeea46c7af18aa9"/><file name="mysql4-upgrade-1.1.7-1.1.8.php" hash="0a4abaf8c787bf656e3163489eb5d29e"/><file name="mysql4-upgrade-1.1.8-1.1.9.php" hash="65b7c540763c1817fef6e4eb1ca6cb9b"/><file name="mysql4-upgrade-1.1.9-1.2.0.php" hash="41aa0b0e87d7f3d97388d5d2733defbd"/></dir></dir></dir><dir name="Emailcapture"><dir name="Block"><file name="Emailcapture.php" hash="ee643896bf37e123fdb046f2c3aafd00"/></dir><dir name="Helper"><file name="Data.php" hash="4968f32e599a6fefe7b6876c486264ba"/></dir><dir name="Model"><dir name="Mysql4"><dir name="Queue"><file name="Collection.php" hash="104fe48ab81aa32769c95aae1b4e4988"/></dir><file name="Queue.php" hash="97ad38464595ed8a25aee9148d703e51"/></dir><file name="Observer.php" hash="041d29358d884b6a4444200d3a6e6b00"/><file name="Queue.php" hash="f95570e6972a31e17c9b4eb1d99aad07"/></dir><dir name="controllers"><file name="IndexController.php" hash="2162c4ce867cba627a66ba4c1b549e55"/></dir><dir name="etc"><file name="config.xml" hash="953a38982ad1ad62107558218b78d121"/><file name="system.xml" hash="7f748cfe607ca50519e51f8a9739feef"/></dir><dir name="sql"><dir name="bronto_emailcapture_setup"><file name="mysql4-install-1.0.0.php" hash="ff0cda179382b958d6a566963faae637"/></dir></dir></dir><dir name="News"><dir name="Block"><dir name="Adminhtml"><file name="ItemRender.php" hash="147c1b256abc1a3f0ffc9018d8af713d"/><file name="Redirect.php" hash="0b6928d1529e41c4e2ccc3a415e53bb8"/><dir name="System"><dir name="Config"><file name="About.php" hash="757f06422ff513218a9dfad2ff91cd0d"/><file name="Form.php" hash="853d55a3d7d5e73e87ae09f87f4764b9"/><file name="General.php" hash="8a19eee62442466ff28f23aa782e68c5"/><file name="News.php" hash="4fdda30cd100f4d1b57a74cb38a9b371"/><file name="Releases.php" hash="30f7b23081c69219473326620e6ccd06"/></dir></dir></dir></dir><dir name="Helper"><file name="Data.php" hash="79dd892352cda62c69ede789dcade61a"/></dir><dir name="Model"><file name="Item.php" hash="e3ce20de8f0422dcf00f389f5491e788"/><dir name="Mysql4"><dir name="Item"><file name="Collection.php" hash="6a79699559ffe750643c3f6da90d0280"/></dir><file name="Item.php" hash="bf9fae7b7e2241259dbdbe83623c3e6e"/></dir><file name="Observer.php" hash="236e8cec018d29f50c4aeff1f23f4880"/><dir name="Resource"><file name="Setup.php" hash="cb9d37d047d535b4928b279623283f30"/></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="AnnouncementController.php" hash="ca98e801e5503b04f4f60286e19edb2e"/></dir><file name="RouteController.php" hash="4819b7cab294e952238e2edb43a73c52"/></dir><dir name="etc"><file name="adminhtml.xml" hash="079a3f745967cc14906151cfcdc2c816"/><file name="config.xml" hash="590d56fb32cdb7460cbff22ab1bffa69"/><file name="system.xml" hash="ecd3a0edd0de407c85bb537a78c2380a"/></dir><dir name="sql"><dir name="bronto_news_setup"><file name="mysql4-install-1.0.0.php" hash="f574c4b2432334d0202d75ef71cb0006"/></dir></dir></dir><dir name="Newsletter"><dir name="Block"><dir name="Adminhtml"><dir name="System"><dir name="Config"><file name="About.php" hash="b5d17d62df37034cd48ea3022e546724"/><file name="Cron.php" hash="4085792ad95b00e5c49a6d9226c6f1c2"/><file name="Suppressed.php" hash="981094eef35a29b7ee10d9ccf395d975"/></dir></dir><dir name="Widget"><dir name="Button"><file name="Mark.php" hash="fc5b7ca0c406b2677b8af8d19539ffa2"/><file name="Reset.php" hash="a2827fc3f6af2b94e1ed3bcc5989b015"/><file name="Run.php" hash="21e4d1c9eb2c882b967c5de6def6a97b"/><file name="Sync.php" hash="89112c7b858e9031050bcba50527b4d7"/></dir></dir></dir><dir name="Checkout"><dir name="Onepage"><file name="Newsletter.php" hash="cc98f4590cf2dfb4cbb584a47e440906"/></dir></dir></dir><dir name="Helper"><file name="Contact.php" hash="bc7ec83130b8614881cf9476b4884bbf"/><file name="Data.php" hash="b34622a3ed7fd6df8277b4079e763697"/></dir><dir name="Model"><dir name="Mysql4"><dir name="Queue"><file name="Collection.php" hash="b9c6858b2045ad66b7c331afba125d19"/></dir><file name="Queue.php" hash="4cf426f02c1e2889b77be9b6a105c91b"/></dir><file name="Observer.php" hash="e39582657491ed6d63d7fb534d6c9e03"/><file name="Queue.php" hash="a9ef5813d95abcd1ee89a0372a0cfeb8"/><dir name="Resource"><file name="Setup.php" hash="1f72a1f56aca455ea0d0289450e9edf5"/></dir><dir name="System"><dir name="Config"><dir name="Backend"><file name="Cron.php" hash="282c40a155af7ea22f646e931fdb6732"/></dir></dir></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="NewsletterController.php" hash="c025c586987c04b029c97cf584296b21"/></dir><file name="IndexController.php" hash="1a0abafaaa208e0d7600e340d0f829ce"/></dir><dir name="etc"><file name="adminhtml.xml" hash="b685d64860bf37a09330bd9f89f5bc3d"/><file name="config.xml" hash="4f33f6124fb207fab0f5b37d97bbfd25"/><file name="system.xml" hash="0df493aaf21c3fce1bfb7a05a18094ec"/></dir><dir name="sql"><dir name="bronto_newsletter_setup"><file name="mysql4-install-1.0.0.php" hash="0f21d5315bbc4c27d0d38f9cf8c99bf3"/><file name="mysql4-install-1.4.0.php" hash="4a779a923947af258688d01143a16362"/><file name="mysql4-install-1.4.4.php" hash="089b40f9419c2fd21af62df207327a20"/><file name="mysql4-install-1.4.5.php" hash="8e97902e5e83992e678ba6144ed130b5"/><file name="mysql4-install-1.4.6.php" hash="74d29bc9655aeafa381ba5dc5f53df69"/><file name="mysql4-install-1.4.7.php" hash="74d29bc9655aeafa381ba5dc5f53df69"/><file name="mysql4-upgrade-1.4.0-1.4.1.php" hash="7eeba27e7b5480c8b502c3805554e2de"/><file name="mysql4-upgrade-1.4.1-1.4.2.php" hash="32f724b99d88e037ade72c8a9f1e0da7"/><file name="mysql4-upgrade-1.4.2-1.4.3.php" hash="63c728bb0cd7fa83bb5536d4500548f4"/><file name="mysql4-upgrade-1.4.3-1.4.4.php" hash="4f08a427c7706ea0988bcdcca6072218"/><file name="mysql4-upgrade-1.4.4-1.4.5.php" hash="c49018730275134d72f0802e1bc4da47"/><file name="mysql4-upgrade-1.4.5-1.4.6.php" hash="7de96310cf9bfe375e3026ed5c934ce2"/><file name="mysql4-upgrade-1.4.6-1.4.7.php" hash="6e40d94220fc0f2305546f7a8d5e754a"/></dir></dir></dir><dir name="Order"><dir name="Block"><dir name="Adminhtml"><dir name="Sales"><dir name="Order"><dir name="View"><dir name="Tab"><file name="Info.php" hash="4caacae5f31c84f898be5798cc85b7b7"/></dir></dir></dir></dir><dir name="System"><dir name="Config"><file name="About.php" hash="332c01d15a8b75f9add5988f35519135"/><file name="Cron.php" hash="62d625df775ca2b81503b1c97c4f7e79"/><file name="Suppressed.php" hash="fd39306031d9b20dc050a69afbd32cd0"/></dir></dir><dir name="Widget"><dir name="Button"><file name="Mark.php" hash="c2364f2b1bf5dd4247562443b6f5744d"/><file name="Reset.php" hash="4d64995d0f43ff3f3829287f8b8780f9"/><file name="Run.php" hash="700e3f9645a9e25e56ae1deb6764bf44"/><file name="Sync.php" hash="2ff1bf077cc56b3620fe87a494d7f770"/></dir></dir></dir><file name="Bta.php" hash="2ec920ce5a6ea57aff16c8d9cf89f7e9"/><file name="Redemption.php" hash="cb6bfc3d06e4f7287c8314f539fce0c5"/></dir><dir name="Helper"><file name="Data.php" hash="2d955b65273e50f9f4e8cb803f56baf1"/></dir><dir name="Model"><dir name="Mysql4"><dir name="Queue"><file name="Collection.php" hash="d041d29b798d10821e041c5b89fb5889"/></dir><file name="Queue.php" hash="2b0ba0993a43cc6856647684ac30add9"/><file name="Setup.php" hash="05b0a2d4806e712410479a3e7c709fd8"/></dir><file name="Observer.php" hash="21a9705ab5d8ac8608cd2d091446a115"/><dir name="Order"><file name="Observer.php" hash="5a05f37813b04968a2274098fdf8b1f7"/></dir><file name="Queue.php" hash="7cd8b2d37481d42e6450bd1f7baf491d"/><dir name="Quote"><file name="Observer.php" hash="1633b1031f19bdd36145b1040d9d6692"/></dir><dir name="System"><dir name="Config"><dir name="Backend"><file name="Cron.php" hash="9bc2a90d644af8334aa22b952132b08f"/></dir><dir name="Source"><file name="Bulk.php" hash="77b7aa28a1e7912c2a23b45155a46623"/><file name="Description.php" hash="7f497c17388c360f239e2aa90d943b9c"/><file name="Price.php" hash="283cc883ded57664870d89b22b547b19"/></dir></dir></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="OrderController.php" hash="ade912efc4d727f6648eed6b4e08af5f"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="784d322d920c63e63bed37c50e1c04d1"/><file name="config.xml" hash="278545fed031c2d6946ff4f539cbc607"/><file name="system.xml" hash="25c18e993bc8e35234a801dd7893e462"/></dir><dir name="sql"><dir name="bronto_order_setup"><file name="mysql4-install-1.0.0.php" hash="4988c452cc0d367f34e9c33df0d4256d"/><file name="mysql4-install-1.1.8.php" hash="afd415c7bb5a81b18c6705293f3978e6"/><file name="mysql4-upgrade-1.0.0-1.1.6.php" hash="0c42c6e3539b0f07c76b4f2c582d110f"/><file name="mysql4-upgrade-1.1.6-1.1.7.php" hash="7c4d2c1feed28b964ea82373e625a11f"/><file name="mysql4-upgrade-1.1.7-1.1.8.php" hash="ae58d4271deb9c60e61214020d46e755"/></dir></dir></dir><dir name="Product"><dir name="Block"><dir name="Adminhtml"><dir name="System"><dir name="Config"><file name="About.php" hash="f3e3d3f6bca7f3b065e25f22b5578d2e"/><file name="Cron.php" hash="53c81d5081e3d4204694c468eff18c39"/><file name="Information.php" hash="cc968073e785221272c6f924e7105036"/></dir><dir name="Recommendation"><file name="Default.php" hash="907b566bfb4bbe4e1c46749182556d77"/><dir name="Edit"><file name="Button.php" hash="d6685785f649dde452fca3a18c78530d"/><file name="Form.php" hash="df406a3476a3e27a4f7a5467d653047c"/></dir><file name="Edit.php" hash="87c571a236297ce4d9b6e692a4ffa852"/><dir name="Grid"><dir name="Renderer"><file name="Action.php" hash="486077c93f6a3b2dd076bd3c9e7d529c"/><file name="Description.php" hash="2eeb64ad510ac9d4cdbb5edf99211b82"/><file name="Image.php" hash="122e3ae80a3a4c260d09374476174c84"/><file name="Price.php" hash="c4af2d40e24f895bba7681851ec8aec2"/><file name="Url.php" hash="b03b06cf5eea764706db123a4b55aefc"/></dir></dir><file name="Grid.php" hash="61938cdc68e52840cf387c512db5e8e2"/><dir name="Message"><file name="Form.php" hash="81f6f8f259e940a82f6626c2b74e89ca"/></dir><dir name="Preview"><file name="Form.php" hash="4c24d8207c53bca40dd7760c2402d9c6"/><file name="Grid.php" hash="677ea4391f5964aef2dbd83d06222540"/><file name="GridElement.php" hash="251201019431ab9596778b0290c71395"/></dir><file name="Preview.php" hash="abc472e9d896a6f417b2ffaa735ce373"/><dir name="Selected"><file name="Grid.php" hash="843022c5636af8e962503e53479f15c0"/><file name="Js.php" hash="dba81b98bd95dbebd22709efc1a3655c"/></dir></dir><file name="Recommendation.php" hash="121626c24b44ad88a918db07f97cfa66"/></dir><dir name="Widget"><dir name="Button"><file name="Run.php" hash="fe948d6a6a08f2876eeccd7db0c3a8b5"/></dir></dir></dir></dir><dir name="Helper"><file name="Data.php" hash="da0200909240213fc5bd3dda00550e49"/></dir><dir name="Model"><dir name="Collect"><file name="Abstract.php" hash="3d90b952ceff07557ad01cee2f916742"/><file name="Bestseller.php" hash="c043c64244b20b33408959d68518cde6"/><file name="Crosssell.php" hash="3479888fc18d4160ee7695ac5fd4face"/><file name="Custom.php" hash="56dec8c92a649396b8685183fdf1c1a6"/><file name="Mostviewed.php" hash="50d58b2678da7259a0bd47ad048afad7"/><file name="New.php" hash="da42c2190202e931a46f9730398b42fe"/><file name="Recentlyviewed.php" hash="2e5c66216ccd815a9a90e33994cc0f9a"/><file name="Related.php" hash="bed15693d124080b58efe577517f7815"/><file name="Upsell.php" hash="ccb8944985ce0b4adfed2bcdda4c8556"/></dir><file name="Collect.php" hash="57c270f1ccd7c7887639d9932a24ad8b"/><file name="Content.php" hash="da798d9df324c6919460983f8c2e378b"/><file name="Filter.php" hash="b52b98c7cd452bfdc779b70deb09eafa"/><dir name="Mysql4"><dir name="Recommendation"><file name="Collection.php" hash="92ae6f624c68d971439d16c79e3e1d08"/></dir><file name="Recommendation.php" hash="e99ebd40f8c942a33b743ad276db23c7"/></dir><file name="Observer.php" hash="de5635441fa96dc582b909fb96cee16e"/><file name="Recommendation.php" hash="6f2759720e14b5f161d1262982e3e22f"/><dir name="Resource"><file name="Setup.php" hash="bd46110dbb737e76364c9523660d093a"/></dir><dir name="System"><dir name="Config"><file name="Cron.php" hash="df7c9a3ff5318013f9afa0148d41fe84"/><dir name="Source"><file name="Recommendation.php" hash="479472b2ed049a745c12c6f499f13cc9"/></dir></dir></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="RecommendationsController.php" hash="8edc3dce0f442bb9e8819e003f5838fa"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="e8eeed8f3589872c7e6e374557cfc613"/><file name="config.xml" hash="2de8b3eed46840c36bac9340bb81b877"/><file name="system.xml" hash="eab93fdc971f74689d4f51a945db9ac8"/></dir><dir name="sql"><dir name="bronto_product_setup"><file name="mysql4-install-1.0.0.php" hash="d04672913acece60326290535f677514"/></dir></dir></dir><dir name="Reminder"><dir name="Block"><dir name="Adminhtml"><dir name="Delivery"><dir name="Grid"><dir name="Renderer"><file name="Customer.php" hash="be1537b58943a2cc27982deb03ec9e39"/><file name="Fields.php" hash="04f0dc7c4a24769cfc68f1508e0d338b"/></dir></dir><file name="Grid.php" hash="472fa8302dae712fbf9a6b6f5ea80dd0"/></dir><file name="Delivery.php" hash="b0bd1dcede57f8dad8ba4416b26d3986"/><dir name="Promo"><file name="Notice.php" hash="437ce674b25c14e33e17e09a0d471176"/></dir><dir name="Reminder"><dir name="Edit"><file name="Form.php" hash="2db520c0f438affbf477801ddde7f9cf"/><dir name="Tab"><file name="Bronto.php" hash="3b49a4f78038b8ac6de5390c2a73151d"/><file name="Conditions.php" hash="71d7c0a13352ec3d5b19b6bc059238bb"/><file name="Customers.php" hash="2ba680131f4b31175c7425c0648c6807"/><file name="General.php" hash="eb05a598a2eafd88d2a199c286b11836"/></dir><file name="Tabs.php" hash="106e44febc4b6a7a3928c5dec68d6123"/></dir><file name="Edit.php" hash="783ca6f21744c56da930fd44ddc6e3a5"/><file name="Grid.php" hash="c87a852ef998ea17af709c0221abd15d"/></dir><file name="Reminder.php" hash="a55e63b29f9cafd9053696f60ffe993f"/><dir name="System"><dir name="Config"><file name="About.php" hash="8380b5e750fe0f2b5b95407c99d2e195"/><file name="Cron.php" hash="84100d0bffc2e16d84bc24577ba9c6bf"/><file name="Settings.php" hash="5d0042b1b2ad5df43856c0a68d63b3b4"/></dir></dir><dir name="Widget"><dir name="Grid"><dir name="Column"><dir name="Renderer"><file name="Email.php" hash="bcc3abd5bbbb5e8f6e19454850d2e8dd"/><file name="Id.php" hash="c35c0feeac92dce912bb8e3ad2cc7e6e"/></dir></dir></dir></dir></dir></dir><dir name="Helper"><file name="Contact.php" hash="4b3e67cf3a0ce095ca454fe4513c6e89"/><file name="Data.php" hash="b0ffcbf133cfeb61b93218f1846d6c34"/><file name="Message.php" hash="b65f0a4095ab4671c57a26451b3cc524"/></dir><dir name="Model"><dir name="Condition"><file name="Abstract.php" hash="3e164c6f67c1ca26c0be533cd9fc1b0c"/><dir name="Combine"><file name="Abstract.php" hash="2a43ca00f8bc4ab36bc87654ad9c6191"/></dir></dir><file name="Delivery.php" hash="41c3912dc5b5cb28d828358c1e0f7bc4"/><dir name="Email"><file name="Message.php" hash="41a2e2068a8452d624df1b2e9343be2a"/></dir><dir name="Mysql4"><dir name="Customer"><file name="Collection.php" hash="577bd12e2df9940fe551fe41c96133cf"/></dir><dir name="Delivery"><file name="Collection.php" hash="1247c3f58061d41f66ee6b9483c200ca"/></dir><file name="Delivery.php" hash="3639d2739b29734ba8aa8950e67e9621"/><dir name="Rule"><file name="Collection.php" hash="a99264c81d15780f305b02cde1564461"/></dir><file name="Rule.php" hash="763fd5d432897ae6e8fbb26891fb2c22"/></dir><file name="Observer.php" hash="299bca8979d361a027fe4ac1598df2f4"/><dir name="Resource"><file name="Setup.php" hash="fa36f813f36534194c7ee1d75206d403"/></dir><dir name="Rule"><dir name="Condition"><dir name="Cart"><file name="Amount.php" hash="b1bd2bd9aabb863184461b0594dad9b0"/><file name="Attributes.php" hash="74cfde1032d8d75241f7522ddc12e11d"/><file name="Combine.php" hash="660f6842b8c1a5acff2c3b4f12fc73a9"/><file name="Couponcode.php" hash="84ef3ecb8bcd57412af80a0d137335bb"/><file name="Itemsquantity.php" hash="50eae47f28bf3660ee0684c9037f5bf8"/><file name="Sku.php" hash="12a7af32e16e21d2a2e4e157c469d1e5"/><file name="Storeview.php" hash="c2310efcb3060e91bf2aab73b0ac8ca9"/><file name="Subcombine.php" hash="c8ad5b2c46116793e2f2df17fe0862c0"/><file name="Subselection.php" hash="0142065f76b4e24ec75b6685eea82642"/><file name="Totalquantity.php" hash="8e492fb70a94549b8d6adbc50b2a4e50"/><file name="Virtual.php" hash="cd12a3218daf4a447b4fd49141101305"/></dir><file name="Cart.php" hash="4d534abf3f1cf1459fe6713788efe66e"/><dir name="Combine"><file name="Root.php" hash="eb4b22b6554b507b61f3e6be30048b07"/></dir><file name="Combine.php" hash="2f15f1241aa71fd76bb511415c6882a3"/><dir name="Wishlist"><file name="Attributes.php" hash="0ecf162a2fc4225ce37de714da9e6210"/><file name="Combine.php" hash="279af17bec3eeb6a97243a93eb4e3f85"/><file name="Quantity.php" hash="8de8793029340cb8c813e0cf034f372d"/><file name="Sharing.php" hash="ad302122deb2065aa28b68748cfae492"/><file name="Storeview.php" hash="83716681ba30c6d4c48dada3a0973971"/><file name="Subcombine.php" hash="4804ad602e3cc622dbfcab4030dff1c2"/><file name="Subselection.php" hash="68d96f6943becdc728f2aa436a8ac4c7"/></dir><file name="Wishlist.php" hash="f5c474dd7b126d69a3e0f7000abd3a95"/></dir></dir><file name="Rule.php" hash="653b47dcae586823c45815d62e97319c"/><dir name="System"><dir name="Config"><dir name="Backend"><file name="Allowsend.php" hash="61965e981ddd79976f0ee21b01e6a0ae"/><file name="Cron.php" hash="6e527885884985fca33236f40a7f3689"/></dir></dir></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="DeliveryController.php" hash="d4630eff20209e0d46b08a29b543979a"/><file name="RemindersController.php" hash="6cd60b0a9c33075640c5926d94a78405"/></dir><file name="LoadController.php" hash="dd5736d47443d0a241d97073dee3080f"/></dir><dir name="etc"><file name="adminhtml.xml" hash="baaae901f8ff9d2ab12b0158ed5a4ca7"/><file name="config.xml" hash="74b586ae283834ff1275f1c0cb6959f3"/><file name="system.xml" hash="794fa3826fa84526997e4f8c3ef2e4ef"/></dir><dir name="sql"><dir name="bronto_reminder_setup"><file name="mysql4-install-1.4.12.php" hash="eae3eb4a69de44df200c52001783a4f0"/><file name="mysql4-install-1.4.13.php" hash="12419b6117a9e0e10f565453feed8740"/><file name="mysql4-install-1.4.14.php" hash="be67c1c55e1781c652d0036984fd0866"/><file name="mysql4-install-1.4.15.php" hash="f2bc98906fc36bf0640b292851ab99e1"/><file name="mysql4-install-1.4.16.php" hash="e34c42b202a7435abe2fa46f01bde257"/><file name="mysql4-install-1.4.17.php" hash="26c94634150797a07af197a4a81f45f8"/><file name="mysql4-install-1.4.2.php" hash="07b5a7b8ef247def75617e92738f0950"/><file name="mysql4-upgrade-1.4.0-1.4.2.php" hash="fefa638ca0ed7c5bc80a1b67e27c8703"/><file name="mysql4-upgrade-1.4.10-1.4.11.php" hash="130a688eb03e4f476308d0d11c32141a"/><file name="mysql4-upgrade-1.4.11-1.4.12.php" hash="766c901369f06aaadc8ffde3befb4aaa"/><file name="mysql4-upgrade-1.4.12-1.4.13.php" hash="172b48942497efd2305eff260bc28d9c"/><file name="mysql4-upgrade-1.4.13-1.4.14.php" hash="3218dae864cac00ff74655160ad31663"/><file name="mysql4-upgrade-1.4.14-1.4.15.php" hash="2e842e4c18259590cdafd2139dd4eb7e"/><file name="mysql4-upgrade-1.4.15-1.4.16.php" hash="671f39e2f90faf1165d50b517be8e04f"/><file name="mysql4-upgrade-1.4.16-1.4.17.php" hash="d789e8fbb7e9dad163643b7b7d2f37b1"/><file name="mysql4-upgrade-1.4.2-1.4.9.php" hash="4692060e7c938aea129c53619f0b3c19"/><file name="mysql4-upgrade-1.4.9-1.4.10.php" hash="9698883135211d54a3c711fead02c187"/></dir><dir name="reference"><file name="saveMatchedCustomers.sql" hash="c4f32ee8be31f7a652369c148271a6c7"/></dir></dir></dir><dir name="Reviews"><dir name="Block"><dir name="Adminhtml"><dir name="System"><dir name="Config"><file name="About.php" hash="b62835e11224c3e8cb7256715d145814"/></dir></dir></dir></dir><dir name="Helper"><file name="Contact.php" hash="a85da1e1cc10dd48ac88b84d91cb9a1d"/><file name="Data.php" hash="c015948fe8ed710617dc652edffa44f9"/><file name="Message.php" hash="df3015f886b4dd283d280cf26ee69cc7"/></dir><dir name="Model"><file name="Message.php" hash="79db458ac23eeb818df57eb828ed1cb5"/><dir name="Mysql4"><dir name="Queue"><file name="Collection.php" hash="c36aecae4ebb1de05835be6c02cd6875"/></dir><file name="Queue.php" hash="52ecc7632d642c9ee3fec1141aba9c30"/></dir><file name="Observer.php" hash="3e443daa54a2052aa7b961a4ce0a2e7a"/><file name="Queue.php" hash="68364c793035e9e6a97ce5969250c3fe"/><dir name="System"><dir name="Config"><dir name="Source"><file name="Message.php" hash="9a5e15326017cbebd7b59b5c80693685"/><file name="Orderstatus.php" hash="4c9719d14ceee3cb5261cbaca132270f"/></dir></dir></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="35bed0690cd9f58063c0c5e03e057469"/><file name="config.xml" hash="77fe8f2486ae74b11ac75f8101a8a554"/><file name="system.xml" hash="762839d4e2dd61b00619eb895147b976"/></dir><dir name="sql"><dir name="bronto_reviews_setup"><file name="mysql4-install-0.0.1.php" hash="7c405d3819f5c79ec405dc372ee38dc5"/></dir></dir></dir><dir name="Verify"><dir name="Block"><dir name="Adminhtml"><dir name="System"><dir name="Config"><file name="About.php" hash="b50a08cd24985483cad82c76305da5ce"/><dir name="Advanced"><file name="Observersearch.php" hash="0351378eb6fbfa8e9b1cde55a9b589e5"/></dir><file name="Conflictchecker.php" hash="cf1736b689d1ef2b3f0b7d7d84b703ba"/><dir name="Form"><dir name="Field"><file name="Apitoken.php" hash="cb84fee5b4e18ca0092f385d6ede6711"/><file name="Button.php" hash="7041c0e923d9929796597160679bc94c"/><file name="Classpath.php" hash="c9c60b09c180960dd107d74f79b63edc"/><file name="Conflict.php" hash="3797f7f88329ecf4d5c9e3e48c9c89e5"/><file name="Events.php" hash="c88df55f9105d0aa5a1574bc37c5a8f8"/><file name="Index.php" hash="612cf825df2f10c0d4d00ac54f413aba"/><file name="Roundtrip.php" hash="4b84fb21a59f5939ab7361dcc816ce1d"/></dir><file name="Magecron.php" hash="109e8427d968973ec3d4b0e5de6e4064"/><file name="Permission.php" hash="e5185de6bc1976ee7497956cc9162a17"/></dir><file name="Installs.php" hash="961665a9ceea68e9165fece4150fdfdb"/><file name="Permissionchecker.php" hash="6f0be4f5594afe1f6924b839db582180"/></dir></dir><dir name="Widget"><dir name="Button"><file name="Classpath.php" hash="1687def566fccc786c263d94b4c9c9b5"/><file name="Conflict.php" hash="473cda5cc65b9302efb3618c3b5af973"/><file name="Events.php" hash="3da5bc0026613dfd921a25a942fb3d7c"/><file name="Permissions.php" hash="b89e87e9b6848cde87a4f6343b3feb1a"/><file name="Runroundtrip.php" hash="5a98f930b382a7a0c01f3b346def4955"/><file name="Runtoken.php" hash="63a721c0a25bdbd58be941ba7c5d21c8"/></dir></dir></dir><file name="Conflictprinter.php" hash="05a32eca413a0eda87bcdb7bd0661642"/><file name="Permissionprinter.php" hash="8925da12d1e8dc5f180327dd94d18310"/></dir><dir name="Helper"><file name="Apitoken.php" hash="bc1f30a551a958011fbba91310cab77d"/><file name="Conflictchecker.php" hash="55e0aacf4cd6e9d2b4d52ebe21fe7850"/><file name="Data.php" hash="6622f73bf7af3e1e68ad27551fb7d920"/><file name="Permissionchecker.php" hash="da5fc3a69e6477299084d210aaaad6b7"/><file name="Roundtrip.php" hash="b5566d978e4e24cf06bee83ab92772fc"/></dir><dir name="Model"><dir name="Config"><file name="Blocks.php" hash="0000df779f3e1fb60350b14b8a6185e3"/><file name="Checker.php" hash="a38555d682b302967410b73ebab04b4f"/><file name="ConfigAbstract.php" hash="79024697562751ff46c939d9d680fc86"/><file name="ConfigInterface.php" hash="45cecfde48e4ef0657a6418019f02e4a"/><file name="Datastore.php" hash="fb5ea494075ce81380d1447c07fa052c"/><file name="Helpers.php" hash="1dc143d542d3fd85ccff785f913556f1"/><file name="Models.php" hash="3062f1f3c4950d965054afe6b75b4b0f"/><file name="Printer.php" hash="dfd6bfdcc94a1afb83ae6c3599abb21c"/><file name="Resources.php" hash="24bbf7de88b25250a81a2d7380d5baa2"/></dir><dir name="Contact"><file name="Builder.php" hash="9d578480a7e4c8fde2a33e698a9efced"/></dir><dir name="Core"><dir name="Config"><file name="Base.php" hash="c11b6cbaf1802d3c6ab58853b468f5d7"/><file name="Element.php" hash="8a7c9221a95c1317a8ae166e692a4ee0"/></dir><file name="Config.php" hash="91877cb5fb11c545f4c0b2069e1407b0"/></dir><dir name="Lib"><dir name="Varien"><dir name="Simplexml"><file name="Config.php" hash="076958ed612323869d2437872744ed2a"/><file name="Element.php" hash="a8c28fd3b6b00ad689d4850e79441dec"/></dir></dir></dir><dir name="Mysql4"><dir name="Core"><file name="Config.php" hash="3b8fb36a66a675c4d12926bceadb4ea5"/></dir></dir><dir name="Path"><dir name="Locator"><file name="Array.php" hash="42fd6c7004b0f02f954956563edde9a0"/><file name="Factory.php" hash="46007808ba897fa6816fb7771a2b18dd"/><file name="IteratorAbstract.php" hash="1debe4adc34aa5d60a94328fd67032da"/><file name="LocatorInterface.php" hash="b775ce0d189ef276c9bbeade7da67b4f"/><file name="Stack.php" hash="328481c9d963f653a95f333fb440bea5"/></dir></dir><dir name="Resource"><dir name="Core"><file name="Config.php" hash="aa2fb8c4fb153e742c690ab8bc8b5a75"/></dir><dir name="Db"><file name="Abstract.php" hash="d668c24c90f80bc197c83eb0a3e10aa6"/></dir></dir><file name="Roundtrip.php" hash="f2166b39afed3e32de4e03cfa3416ff6"/><dir name="System"><dir name="Config"><dir name="Backend"><file name="Magecron.php" hash="ba8b8f5ef43bed77ed03dba3e98df1df"/></dir><dir name="Source"><file name="Classtypes.php" hash="772cab11a7470a2dd68ece3688c68d6a"/><file name="Wsdlcache.php" hash="b7d9c1c4d271c03a7486fc86eec3b6d9"/></dir></dir></dir><dir name="Validator"><file name="Checker.php" hash="35799249fcc93b31ff12da539cfb0d84"/><file name="Directory.php" hash="aa05ae40ad0b7aaffffaa6063bd8561e"/><file name="File.php" hash="c29c1cd2140186dc67c5e62064b79c0f"/><dir name="Filter"><file name="PatternIterator.php" hash="c129a6ee0fb4a45ff52644da2c0abfa1"/></dir><file name="Group.php" hash="59ad6dd4232ee113e1fe8161a82148ba"/><file name="Owner.php" hash="69e1c54dca88532208ce1f35f4491d99"/><file name="Printer.php" hash="23a00ec415b8665e5457ac09939e2ab2"/><file name="ValidatorAbstract.php" hash="d043c743309f5d64640698953269ece6"/><file name="ValidatorInterface.php" hash="02f543af08eda65263f4b005f3b3bdaf"/></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="AdvancedController.php" hash="0942ed5d83442e97af40d4572c3e21f8"/><file name="ApitokenController.php" hash="f804594b22260cb597cc0e5cfe633093"/><file name="ConflictcheckerController.php" hash="1d23621c640eecf2a813121cfc23850b"/><file name="PermissioncheckerController.php" hash="2e254bd755cd9d05d7eb6865a2ffb0e7"/><file name="RoundtripController.php" hash="efb601f3ceca89885d031f06218b2a4d"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="d7aa2c1c8fa26ad3ab910940abd9199e"/><file name="config.xml" hash="a4e251c636842385f7e9e9a1370ed8b5"/><file name="system.xml" hash="855eb0390cb0a198236cba9383749d54"/></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Bronto_All.xml" hash="5a9c06b6313882589765b9bcf0402bbb"/><file name="Bronto_Customer.xml" hash="a11c20f008ee2eae14baa3b549d5adee"/><file name="Bronto_Email.xml" hash="b7cdca4b15753edcefe8b9e0abb780bd"/><file name="Bronto_Newsletter.xml" hash="2115c5225e02ab5d4e56749cc5eff6ad"/><file name="Bronto_Order.xml" hash="63f1537add6088417945657bec98ffe9"/><file name="Bronto_Reminder.xml" hash="08503ab78994178b822ef9b0add243f9"/><file name="Bronto_Verify.xml" hash="ad72ea2ebfd99dbe2773b2735d0ec973"/><file name="Bronto_News.xml" hash="3496cd7578991889909fbd8daa170d2d"/><file name="Bronto_Reviews.xml" hash="23a398c055d062c4a5e19e72a0c2df95"/><file name="Bronto_Product.xml" hash="2805533fff08aef167af474799bd4faf"/><file name="Bronto_Emailcapture.xml" hash="98b59bbf388d6c715f345b8906bd2fa1"/></dir></target><target name="magelib"><dir name="Bronto"><dir name="Api"><dir name="Account"><file name="Exception.php" hash="1a851457b2a032fb6d149fe9ef111c57"/><file name="Row.php" hash="3ab1e97019ef87bcd464eeaabf652886"/></dir><file name="Account.php" hash="33b9ba8867fe69135391c26f98b5852a"/><dir name="Activity"><file name="Exception.php" hash="3ac1f2caea6465931cbf927f1033ec06"/><file name="Row.php" hash="de166130c57670bf486a783a4501e2d4"/></dir><file name="Activity.php" hash="f5f48488e40507bc108b35c599e4e5a2"/><dir name="ApiToken"><file name="Exception.php" hash="e06d0a4c9469da7333e6a596e9c37c5d"/><file name="Row.php" hash="f3742811cec1cbf0be583296b617dfbd"/></dir><file name="ApiToken.php" hash="65bbd18974bbbf620dc2df23bdeb4469"/><dir name="Contact"><file name="Exception.php" hash="809bdce6db3bb9c72a3173bb08c1b19e"/><file name="Row.php" hash="2e360d131c2abe19e154b5f3795a58f0"/></dir><file name="Contact.php" hash="55bab8398154e96db6b0ca3ed88718e0"/><dir name="ContentTag"><file name="Exception.php" hash="5a8bc58af480a574e8061c62ad5590b4"/><file name="Row.php" hash="e470d8bcd686d42a886e59d5184b5eed"/></dir><file name="ContentTag.php" hash="14f1cbefe1027338d28db301a1c2df3d"/><dir name="Conversion"><file name="Exception.php" hash="73dd991a663b99050428f54fc13fb433"/><file name="Row.php" hash="115d01ea0e0e6ade42fcab76dff71c35"/></dir><file name="Conversion.php" hash="60ec52dcfeda92294d1ab10bb29a486a"/><dir name="Delivery"><file name="Exception.php" hash="003dbb49ea3be65fe35dfa9b7ec743c5"/><file name="Recipient.php" hash="562bdc8d86b92ec293a338fdd7bf928a"/><file name="Row.php" hash="9c6149e74a305f62b9806df5a20e6a00"/></dir><file name="Delivery.php" hash="668dc6493cefe960c7dc8fe1fe87bf08"/><dir name="DeliveryGroup"><file name="Exception.php" hash="9291b2adb576a6781a0d624cc3288453"/><file name="Row.php" hash="29adb1f866cf1d24ef0abac19f95fbd0"/></dir><file name="DeliveryGroup.php" hash="7dd295b65f22e65dff3bf45c4336e985"/><file name="Exception.php" hash="bacb7c782ef7f612edaf3d39c20118ef"/><dir name="Field"><file name="Exception.php" hash="db651b9fa4b5161e3a32af49cc12cc64"/><file name="Predefined.php" hash="15fadb32175098d9ded60550d1748a4a"/><file name="Row.php" hash="6871d05f399a8a9dfa0742952eaa6481"/><file name="TypeGuesser.php" hash="1027ea97675a16cc964aa0d8ba63e642"/></dir><file name="Field.php" hash="32d5876335ec815acb50d3b4e7bf3ccd"/><dir name="List"><file name="Exception.php" hash="0f964fac998c89a0d4d515979bd81b98"/><file name="Row.php" hash="6516df43a1a94beee7b57fae71c27134"/></dir><file name="List.php" hash="ef240fe5e1422479a83291ad30b468ac"/><dir name="Login"><file name="ContactInformation.php" hash="bc1ce7f57c67fa21cd0881d0384a1cac"/><file name="Exception.php" hash="fff7546235b416b7008a9e4bd646fc19"/><file name="Row.php" hash="578553fcbf1941d0eb5890614c57ae91"/></dir><file name="Login.php" hash="a61cf5ac4c3ea76b03a71750e085df88"/><dir name="Message"><file name="Exception.php" hash="755f7f14cdb234931708968ac0bad4a4"/><file name="Row.php" hash="5732b5550c8c6444790f2f20e626ff08"/></dir><file name="Message.php" hash="cc3c9939757371ad7fd2d297df394621"/><dir name="MessageRule"><file name="Exception.php" hash="b0398ee96ed70c483f38b50f305e82a8"/><file name="Row.php" hash="8e7532184ee265a927a195ac36e5a518"/></dir><file name="MessageRule.php" hash="ae1b3f16683656066a83bcf9f2863710"/><file name="Object.php" hash="4ea2880431ac5761cbf7478d809577f6"/><dir name="Order"><file name="Exception.php" hash="8312e1a1ab46bcf88b72983bb11a6493"/><file name="Product.php" hash="3785f2f460fec6c18c6164176de52449"/><file name="Row.php" hash="1400de022188806bb94e98544c054ef6"/></dir><file name="Order.php" hash="ad690b37bc577879020d10e5ac70ef3d"/><dir name="Row"><file name="Exception.php" hash="4c1a45512e0912644f94a88d4298d3a9"/></dir><file name="Row.php" hash="259418b11987939378747a9c46fae1ae"/><dir name="Rowset"><file name="Exception.php" hash="b5202ed6f61bfe06b90f73c03ca28ffa"/><file name="Iterator.php" hash="9ea7a244b83e7b9318bfe8ed371a149f"/></dir><file name="Rowset.php" hash="3f40382933e2f392b6320fd79db720cd"/><dir name="Segment"><file name="Exception.php" hash="bd5c2302ef222ff55981cc38477a9310"/><file name="Row.php" hash="b840493b8b2c3cb6686de0e5bedfa2ba"/></dir><file name="Segment.php" hash="0cf99babff6169afa427f302c76023dd"/></dir><file name="Api.php" hash="17aace21dbebcab84a80091230ca03e9"/><file name="Observer.php" hash="21bc70d405fcd47b0473ac89fd3d4ae2"/><file name="SoapClient.php" hash="81dd0a8a8c15ac96280d2f1b6bb3311e"/><dir name="Util"><file name="Colors.php" hash="14313213b3a70c79a56c574523b9b90b"/><file name="CountryCodes.php" hash="4efb9c354d29a901368c46aab40f79d4"/><dir name="Retryer"><file name="FileRetryer.php" hash="bdc72ace54ace32081115442d28cb972"/><file name="RetryerException.php" hash="54b70d7abbc32b55649a193e8e70dcb5"/><file name="RetryerInterface.php" hash="cc57d5a02a55811a13a31ed9beff126f"/></dir><file name="Uuid.php" hash="ba62bdec6488ccb621e0bfd726c6107a"/></dir></dir></target><target name="mageskin"><dir name="adminhtml"><dir name="base"><dir name="default"><dir name="bronto"><file name="bronto.css" hash="ebc2f1ade554e3cad4bf0b091ff674d1"/><file name="cron.css" hash="99b49b9ec245e75b81e62e78605f106f"/><dir name="images"><file name="BrontoGuide.png" hash="be2bb3605cc5f1899ad996fcd2ceae84"/><file name="InstallStatusDisabled.png" hash="5cf8d7dd8ed623f8b38e6ea3ed89861a"/><file name="InstallStatusEnabled.png" hash="11ea6d1f0ba319b62ed1728e9b747108"/><file name="InstallStatusError.png" hash="91fdd0af3ffd20d0b8a77645bb9cfcdc"/><file name="ajax-loader-tr.gif" hash="1ae32bc8232ff2527c627e5b38eb319a"/><file name="bg_notifications.gif" hash="df73b8aa7e48bb56e0a644245aa3683f"/><file name="bronto-mini-off.png" hash="af2c6a5434604db0bb3a2cc4a51b5c77"/><file name="bronto-mini.png" hash="7989c68c0e83b7b04af308780aa82259"/><file name="bronto_contact-mini.png" hash="e221b304ad42cba129a9dcf17ce5180e"/><file name="bronto_contact_import-mini.png" hash="a9e0904f7219be45fd1ed88c5b9a1650"/><file name="bronto_general-mini.png" hash="aca50d84fe324abbb36ff2853d9cad01"/><file name="bronto_help.png" hash="d0ed63d7c68e8b52583ce428b3846afc"/><file name="bronto_news-mini.png" hash="bb8b3beb16c10d8b38ddb11f3f4347e8"/><file name="bronto_newsletter-mini.png" hash="9c45a6dd689ad758cf927cb381621b35"/><file name="bronto_order_import-mini.png" hash="a2b13488fccfdd5b2194843800abadda"/><file name="bronto_reminders-mini.png" hash="c85bafdc82718769c8b801fd64e7bd72"/><file name="guide.png" hash="10c880d9e40f1283f99e02ce2d025a4f"/><file name="logo.png" hash="3b7c4cb9faf220091a5fbae3c7f87afa"/><file name="message_approved.gif" hash="465a056a3ba3d94367f51c3c0b751391"/><file name="message_not_approved.gif" hash="e4f28607f075a105e53fa3113d84bd26"/><file name="section_logo.png" hash="98f2570d14580cee2c6cf66cca540b39"/><file name="site_name.png" hash="fb2cc4e1e00cdc95a94c04fccfa5e1b3"/><file name="support.png" hash="0910e2eb718379d037ead6e0af9c4855"/></dir><dir name="js"><dir name="guider"><file name="README.html" hash="be17cdbc961dc921944cef4e7daa33c3"/><file name="README.md" hash="1c11ec7951035fe0611edded566901a0"/><file name="changelog.txt" hash="4c107fe228a620f6f3118b128e62c0b5"/><file name="clock.gif" hash="12aa3f72e722ac8e5eeb68823024278f"/><file name="component.json" hash="05fe7fcf63c00abd58efa072baa8248f"/><file name="guiders.css" hash="a6df4a6e2d4f3075e29841a6844ee30b"/><file name="guiders.jquery.json" hash="261d2b3a2d3a21e49a0153f0c8f2c3e9"/><file name="guiders.js" hash="42b1675f9d1a93b89d62e97f2db895bb"/><file name="guiders_arrows.png" hash="757812709656e9592d9d724a63624d0d"/><file name="guiders_x_button.jpg" hash="2af6c2b68534a8b2c48d0ddc14a5b801"/><file name="jquery.min.js" hash="0652da382b6fceb033dfe2b6c06d4d11"/><file name="promo_gmail.png" hash="4837435633204a9001b88c2d8ef451ed"/></dir><file name="jquery-1.10.2.js" hash="91515770ce8c55de23b306444d8ea998"/><file name="jquery-1.10.2.min.js" hash="628072e7212db1e8cdacb22b21752cda"/><file name="jquery-1.10.2.min.map" hash="6c3ccfc221d36777d383b6e04d0b8af9"/><file name="jquery-noconflict.js" hash="3179f2255b046d5f2e9a71e365287bef"/></dir><file name="news.css" hash="84d2866b08b706164c6e545767ff331a"/></dir></dir></dir></dir></target><target name="magedesign"><dir name="frontend"><dir name="base"><dir name="default"><dir name="template"><dir name="bronto"><dir name="common"><file name="popup.phtml" hash="996c1d74465c319465bdfd1ee0b5845d"/></dir><dir name="emailcapture"><file name="js.phtml" hash="37b3d102efdd3685e09822615c72db3e"/></dir><dir name="newsletter"><file name="checkbox.phtml" hash="281d8b8a7a078965f6b8386c5a1c6136"/><file name="js.phtml" hash="c88851be407f642e13d0c563f537e3c2"/></dir><dir name="order"><file name="js.phtml" hash="e398cfbfe9df41feeadb251216422cd9"/><file name="redemption.phtml" hash="4a344720766b9ea957210fbb5059c605"/></dir></dir></dir><dir name="layout"><dir name="bronto"><file name="common.xml" hash="f1e7ee067163e84f2e3bfc5474b3647d"/><file name="emailcapture.xml" hash="b5d3b0efc5daffb5fa66561f690013d0"/><file name="newsletter.xml" hash="30e90ef74659bafca7f1cb7d36a63717"/><file name="order.xml" hash="2c74121ed741ca74dbb6958f59cb3d3b"/></dir></dir></dir></dir></dir><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="template"><dir name="bronto"><dir name="api"><file name="guide.phtml" hash="2bd6d0a65c67190e388c18aef0acfcc3"/></dir><dir name="common"><file name="about.phtml" hash="fa5886d9dba15226eec520916b7c4aa2"/><file name="cron.phtml" hash="80af8ca4a8e2c74449904748aeaf718b"/><file name="guide.phtml" hash="07bcf3ad2e6a9136888bbf4a8bf0b51d"/><file name="guiders.phtml" hash="790ac5e5f8df13753db5ac3e68d08d76"/><file name="suppressed.phtml" hash="3c724d43b2cef9b13532e6d2b8e05f06"/></dir><dir name="coupon"><file name="guide.phtml" hash="ad8749755efbc04c54318a1634507fc5"/></dir><dir name="customer"><file name="guide.phtml" hash="14e9b74f62bde430a6df96cf04ee94dc"/></dir><dir name="email"><file name="guide.phtml" hash="c8fe9f3cadf5e50d6f0e69979462c407"/><dir name="template"><file name="edit.phtml" hash="802ef394d1943f18d33d39d0b85dcc3d"/><file name="list.phtml" hash="e9eb7ffc48f9d17a21917d86ff18b0fc"/></dir></dir><dir name="news"><file name="guide.phtml" hash="19026e62d49476371edc4f9e7f68d2c1"/><file name="item.phtml" hash="7146fcc10eeb0bdc33a78ea8fe060f74"/></dir><dir name="newsletter"><file name="guide.phtml" hash="4d4ac3dc42265d9521ec75383da40a10"/></dir><dir name="order"><file name="guide.phtml" hash="831ff327cf49d198bec62ad968587593"/></dir><dir name="popup"><file name="guide.phtml" hash="6bd6240f1402a03dd0d5022b8c39b3ab"/></dir><dir name="product"><file name="guide.phtml" hash="db1f4d377f1026bd187270d6661f0d47"/><dir name="recommendation"><file name="button.phtml" hash="3583ae800ae50fcdee59cff78d2fe1d9"/><file name="default.phtml" hash="b90f72f90eb11e32c0a7c31cf04ee301"/><file name="edit.phtml" hash="74cfbb9a25506210ad1a446dbdaa8e89"/><file name="grid.phtml" hash="51e74eba64b3e2a898114c2ffb42f588"/><file name="preview.phtml" hash="0fbfb3c0834c2103a4e68e6d726c679b"/><file name="selected.js.phtml" hash="c200e113619846ba8a5e11273c60a6d4"/></dir></dir><dir name="reminder"><dir name="grid"><file name="container.phtml" hash="28518ad2522f1b213102eb52071ef247"/></dir><file name="guide.phtml" hash="db033c357b5e335b6d65a44fa78c7c7e"/></dir><dir name="reviews"><file name="guide.phtml" hash="caad8c25594859c554a1fa1e505c92f0"/></dir><dir name="verify"><dir name="advanced"><file name="observer.phtml" hash="775deb643169f76f72793873a258eac1"/></dir><file name="advanced.phtml" hash="8479f4762de8943de234407bbc80b679"/><dir name="conflictchecker"><file name="errors.phtml" hash="91adf7e31ce9ec1ae06c18adb489bf54"/></dir><file name="guide.phtml" hash="664368c479f04ef022e9f0f96b2b9eca"/><file name="installs.phtml" hash="34b6bd602043376f8c17ef7744a27537"/><dir name="permissionchecker"><file name="button.phtml" hash="0a98a58dcb6d28d768e83556e6e690bc"/><file name="errors.phtml" hash="6da7357831323392e3badcb1cc8268aa"/><file name="index.phtml" hash="628a80e9245642cb92cc75a6dd07d1d7"/></dir></dir></dir></dir><dir name="layout"><dir name="bronto"><file name="common.xml" hash="78716037b527736c77da53251c89e591"/><file name="email.xml" hash="be77c906770a0d818898a910b03cbe4f"/><file name="news.xml" hash="96d679b735d551a3e83fb71bfe2a7fca"/><file name="reminder.xml" hash="07186394676c6db016d00bdee53e8394"/><file name="verify.xml" hash="e5676df09f0a79bdedc314e2bfdb4b59"/></dir></dir></dir></dir></dir></target><target name="mage"><dir name="shell"><dir name="bronto"><file name="cron.php" hash="675049a8c5b735fcf35ea19e85b593ae"/><file name="fix.php" hash="2e567898588544863eb2eec2abd84562"/><file name="rewrite.php" hash="38f1c593dfc30e60d68f59381fd36d04"/></dir></dir></target></contents>
61
  <compatible/>
62
  <dependencies><required><php><min>5.2.13</min><max>6.0.0</max></php><extension><name>soap</name><min></min><max></max></extension><extension><name>openssl</name><min></min><max></max></extension></required></dependencies>
63
  </package>
shell/bronto/cron.php CHANGED
@@ -18,9 +18,11 @@ class Bronto_Cron_Os_Script extends Mage_Shell_Abstract {
18
  */
19
  protected $_validCronTasks = array(
20
  'api',
 
21
  'customer',
22
  'newsletter',
23
  'order',
 
24
  'reminder',
25
  );
26
 
@@ -57,6 +59,8 @@ USAGE;
57
  {
58
  if ($task == 'api') {
59
  $task = 'common/' . $task;
 
 
60
  }
61
  return Mage::helper('bronto_' . $task)->getName();
62
  }
@@ -74,9 +78,11 @@ USAGE;
74
  Tasks:
75
 
76
  api {$this->_getTaskName('api')}
 
77
  customer {$this->_getTaskName('customer')}
78
  newsletter {$this->_getTaskName('newsletter')}
79
  order {$this->_getTaskName('order')}
 
80
  reminder {$this->_getTaskName('reminder')}
81
 
82
 
@@ -123,6 +129,9 @@ LIST;
123
  case 'api':
124
  $result = Mage::getModel('bronto_common/observer')->processApiErrors();
125
  break;
 
 
 
126
  case 'customer':
127
  $result = Mage::getModel('bronto_customer/observer')->processCustomers(true);
128
  break;
@@ -132,6 +141,9 @@ LIST;
132
  case 'order':
133
  $result = Mage::getModel('bronto_order/observer')->processOrders(true);
134
  break;
 
 
 
135
  case 'reminder':
136
  $result = Mage::getModel('bronto_reminder/observer')->scheduledNotification(true);
137
  break;
18
  */
19
  protected $_validCronTasks = array(
20
  'api',
21
+ 'send',
22
  'customer',
23
  'newsletter',
24
  'order',
25
+ 'product',
26
  'reminder',
27
  );
28
 
59
  {
60
  if ($task == 'api') {
61
  $task = 'common/' . $task;
62
+ } else if ($task == 'send') {
63
+ return Mage::helper('bronto_common/api')->getSendName();
64
  }
65
  return Mage::helper('bronto_' . $task)->getName();
66
  }
78
  Tasks:
79
 
80
  api {$this->_getTaskName('api')}
81
+ send {$this->_getTaskName('send')}
82
  customer {$this->_getTaskName('customer')}
83
  newsletter {$this->_getTaskName('newsletter')}
84
  order {$this->_getTaskName('order')}
85
+ product {$this->_getTaskName('product')}
86
  reminder {$this->_getTaskName('reminder')}
87
 
88
 
129
  case 'api':
130
  $result = Mage::getModel('bronto_common/observer')->processApiErrors();
131
  break;
132
+ case 'send':
133
+ $result = Mage::getModel('bronto_common/observer')->processSendQueue();
134
+ break;
135
  case 'customer':
136
  $result = Mage::getModel('bronto_customer/observer')->processCustomers(true);
137
  break;
141
  case 'order':
142
  $result = Mage::getModel('bronto_order/observer')->processOrders(true);
143
  break;
144
+ case 'product':
145
+ $result = Mage::getModel('bronto_product/observer')->processContentTags();
146
+ break;
147
  case 'reminder':
148
  $result = Mage::getModel('bronto_reminder/observer')->scheduledNotification(true);
149
  break;
shell/bronto/fix.php CHANGED
@@ -23,6 +23,7 @@ class Bronto_Fix_Os_Script extends Mage_Shell_Abstract {
23
  'news',
24
  'newsletter',
25
  'order',
 
26
  'reminder',
27
  'reviews',
28
  );
@@ -69,7 +70,7 @@ USAGE;
69
  * @see run
70
  */
71
  public function run() {
72
- $action = $this->getArg('action') ?: $this->getArg('a');
73
 
74
  switch ($action) {
75
  case 'list':
@@ -84,6 +85,7 @@ Tasks:
84
  news {$this->_getTaskName('news')}
85
  newsletter {$this->_getTaskName('newsletter')}
86
  order {$this->_getTaskName('order')}
 
87
  reminder {$this->_getTaskName('reminder')}
88
  reviews {$this->_getTaskName('reviews')}
89
 
23
  'news',
24
  'newsletter',
25
  'order',
26
+ 'product',
27
  'reminder',
28
  'reviews',
29
  );
70
  * @see run
71
  */
72
  public function run() {
73
+ $action = $this->getArg('action') ? $this->getArg('action') : $this->getArg('a');
74
 
75
  switch ($action) {
76
  case 'list':
85
  news {$this->_getTaskName('news')}
86
  newsletter {$this->_getTaskName('newsletter')}
87
  order {$this->_getTaskName('order')}
88
+ product {$this->_getTaskName('product')}
89
  reminder {$this->_getTaskName('reminder')}
90
  reviews {$this->_getTaskName('reviews')}
91
 
shell/bronto/rewrite.php ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // Can either be run from shell dir, modman, or cron
4
+ if (file_exists('abstract.php')) {
5
+ require_once 'abstract.php';
6
+ } else if (preg_match('/\.modman/', dirname(__FILE__))) {
7
+ require_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . '/shell/abstract.php';
8
+ } else {
9
+ require_once dirname(dirname(dirname(__FILE__))) . '/shell/abstract.php';
10
+ }
11
+
12
+ class Bronto_Rewrite_Os_Script extends Mage_Shell_Abstract
13
+ {
14
+ protected $_out;
15
+
16
+ /**
17
+ * Returns the help
18
+ *
19
+ * @see parent
20
+ * @return string
21
+ */
22
+ public function usageHelp()
23
+ {
24
+ return <<<USAGE
25
+ Usage: php -f bronto/rewrite.php -- <options>
26
+ -h --help Shows usage
27
+ -w --with-observer Writes Observers and event handlers as well
28
+ -p --base-path Use this base path
29
+
30
+ USAGE;
31
+ }
32
+
33
+ /**
34
+ * Runs the rewrite program on a given base path
35
+ *
36
+ * @return void
37
+ */
38
+ public function run()
39
+ {
40
+ $help = $this->getArg('help') || $this->getArg('h');
41
+ if ($help) {
42
+ $this->_showHelp();
43
+ } else {
44
+ $this->_setupOutput();
45
+ try {
46
+ $this->_processRewrites();
47
+ } catch (Exception $e) {
48
+ $this->_write($e->getTraceAsString());
49
+ }
50
+ $this->_cleanOut();
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Processes the rewrites on the all of the config.xmls in a given path
56
+ *
57
+ * @return void
58
+ */
59
+ protected function _processRewrites()
60
+ {
61
+ $baseIter = new RecursiveDirectoryIterator($this->_basePath());
62
+ $recurse = new RecursiveIteratorIterator($baseIter);
63
+ $configs = new RegexIterator($recurse, '/config\.xml$/');
64
+
65
+ $reportsObserver = $this->_reportObserver();
66
+ foreach ($configs as $configFile) {
67
+ $this->_writeLine("Consuming file $configFile");
68
+ $xml = new SimpleXMLElement($configFile, 0, true);
69
+ $models = $xml->xpath('//models/*/rewrite');
70
+ foreach ($models as $model) {
71
+ foreach (get_object_vars($model) as $key => $class) {
72
+ $this->_writeLine("|_ Found model rewrite $key: $class");
73
+ }
74
+ }
75
+ $block = $xml->xpath('//blocks/*/rewrite');
76
+ foreach ($blocks as $block) {
77
+ foreach (get_object_vars($block) as $key => $path) {
78
+ $this->_writeLine("|_ Found block rewrite $key: $path");
79
+ }
80
+ }
81
+ if ($reportsObserver) {
82
+ $events = $xml->xpath('//events');
83
+ foreach ($events as $observers) {
84
+ foreach ($observers->children() as $event) {
85
+ $this->_writeLine("|_ Found observer(s) for {$event->getName()}:");
86
+ foreach ($event->xpath('observers/*') as $observer) {
87
+ $this->_writeLine("|__ Observer {$observer->getName()}: {$observer->class->__toString()}::{$observer->method->__toString()}");
88
+ }
89
+ }
90
+ }
91
+ }
92
+ }
93
+ }
94
+
95
+ /**
96
+ * Creates the filehandle resource to be used internally
97
+ *
98
+ * @return Bronto_Rewrite_Os_Script
99
+ */
100
+ protected function _setupOutput()
101
+ {
102
+ $this->_out = fopen('php://output', 'w');
103
+ return $this;
104
+ }
105
+
106
+ /**
107
+ * Writes some string to the output handler
108
+ *
109
+ * @param string $message
110
+ * @return Bronto_Rewrite_Os_Script
111
+ */
112
+ protected function _write($message)
113
+ {
114
+ fwrite($this->_out, $message);
115
+ return $this;
116
+ }
117
+
118
+ /**
119
+ * Writes a line of output to the output handler
120
+ *
121
+ * @param string $message
122
+ * @return Bronto_Rewrite_Os_Script
123
+ */
124
+ protected function _writeLine($message)
125
+ {
126
+ return $this->_write("$message\n");
127
+ }
128
+
129
+ /**
130
+ * Destroys the file handle resource
131
+ * @return Bronto_Rewrite_Os_Script
132
+ */
133
+ protected function _cleanOut()
134
+ {
135
+ if ($this->_out) {
136
+ fclose($this->_out);
137
+ }
138
+ return $this;
139
+ }
140
+
141
+ /**
142
+ * Gets the base path to use for scanning
143
+ *
144
+ * @return string
145
+ */
146
+ protected function _basePath()
147
+ {
148
+ $basePath = $this->getArg('p') ? $this->getArg('p') : $this->getArg('base-path');
149
+ if (empty($basePath)) {
150
+ $basePath = '.';
151
+ }
152
+ return $basePath;
153
+ }
154
+
155
+ /**
156
+ * Should report the observers?
157
+ *
158
+ * @return boolean
159
+ */
160
+ protected function _reportObserver()
161
+ {
162
+ return $this->getArg('w') || $this->getArg('with-observer');
163
+ }
164
+ }
165
+
166
+ $shell = new Bronto_Rewrite_Os_Script();
167
+ $shell->run();
skin/adminhtml/base/default/bronto/cron.css CHANGED
@@ -49,7 +49,7 @@
49
  .bronto-cron .form-buttons {
50
  margin-bottom: 10px;
51
  padding-right: 4px;
52
- width: 45%;
53
  text-align: right;
54
  }
55
 
@@ -78,7 +78,7 @@
78
 
79
  .bronto-progress-bar {
80
  float: left;
81
- width: 48%;
82
  background-color: #ccc;
83
  border-radius: 2px;
84
  padding: 2px;
49
  .bronto-cron .form-buttons {
50
  margin-bottom: 10px;
51
  padding-right: 4px;
52
+ width: 60%;
53
  text-align: right;
54
  }
55
 
78
 
79
  .bronto-progress-bar {
80
  float: left;
81
+ width: 34%;
82
  background-color: #ccc;
83
  border-radius: 2px;
84
  padding: 2px;