RetentionScience_Waves - Version 3.0.1

Version Notes

Brand new API 3.0 Integration

Download this release

Release Info

Developer Retention Science
Extension RetentionScience_Waves
Version 3.0.1
Comparing to
See all releases


Code changes from version 2.3.0 to 3.0.1

Files changed (47) hide show
  1. app/code/community/RetentionScience/.DS_Store +0 -0
  2. app/code/community/RetentionScience/Waves/Block/Adminhtml/Rscore.php +2 -4
  3. app/code/community/RetentionScience/Waves/Block/Adminhtml/Syncbutton.php +24 -24
  4. app/code/community/RetentionScience/Waves/Block/Waves.php +52 -72
  5. app/code/community/RetentionScience/Waves/Helper/Data.php +247 -5
  6. app/code/community/RetentionScience/Waves/Helper/Storeselect.php +0 -13
  7. app/code/community/RetentionScience/Waves/Model/Configfieldlistener.php +15 -0
  8. app/code/community/RetentionScience/Waves/Model/Connection/AwsCloudWatch.php +370 -0
  9. app/code/community/RetentionScience/Waves/Model/{retention_science_api.php → Connection/RetentionScienceApi.php} +163 -205
  10. app/code/community/RetentionScience/Waves/Model/Container/Waves.php +27 -0
  11. app/code/community/RetentionScience/Waves/Model/Cron.php +22 -0
  12. app/code/community/RetentionScience/Waves/Model/Export/Abstract.php +269 -0
  13. app/code/community/RetentionScience/Waves/Model/Export/Category.php +66 -0
  14. app/code/community/RetentionScience/Waves/Model/Export/Customer.php +174 -0
  15. app/code/community/RetentionScience/Waves/Model/Export/Order.php +101 -0
  16. app/code/community/RetentionScience/Waves/Model/Export/Order/Customer.php +93 -0
  17. app/code/community/RetentionScience/Waves/Model/Export/Order/Items.php +132 -0
  18. app/code/community/RetentionScience/Waves/Model/Export/Product.php +362 -0
  19. app/code/community/RetentionScience/Waves/Model/Mysql4/Product/Collection.php +0 -34
  20. app/code/community/RetentionScience/Waves/Model/Observer.php +411 -517
  21. app/code/community/RetentionScience/Waves/Model/Source/Categorytree.php +0 -47
  22. app/code/community/RetentionScience/Waves/Model/Source/Credentials.php +59 -0
  23. app/code/community/RetentionScience/Waves/Model/Source/Cron/Frequency.php +0 -29
  24. app/code/community/RetentionScience/Waves/Model/Source/Cron/Hours.php +0 -19
  25. app/code/community/RetentionScience/Waves/Model/Source/Cronconfig.php +11 -11
  26. app/code/community/RetentionScience/Waves/Model/Source/Rscoredata.php +27 -24
  27. app/code/community/RetentionScience/Waves/Model/Source/Stores.php +15 -0
  28. app/code/community/RetentionScience/Waves/Model/rs_get_save_config.php +0 -28
  29. app/code/community/RetentionScience/Waves/Model/rs_send_categories.php +0 -27
  30. app/code/community/RetentionScience/Waves/Model/rs_send_orders.php +0 -38
  31. app/code/community/RetentionScience/Waves/Model/rs_send_products.php +0 -34
  32. app/code/community/RetentionScience/Waves/Model/rs_send_users.php +0 -37
  33. app/code/community/RetentionScience/Waves/Model/rs_sync_data.php +0 -201
  34. app/code/community/RetentionScience/Waves/controllers/AdminController.php +0 -15
  35. app/code/community/RetentionScience/Waves/controllers/Adminhtml/WavesController.php +42 -0
  36. app/code/community/RetentionScience/Waves/controllers/{IndexController.php → Frontend/IndexController.php} +10 -9
  37. app/code/community/RetentionScience/Waves/etc/adminhtml.xml +23 -23
  38. app/code/community/RetentionScience/Waves/etc/cache.xml +12 -0
  39. app/code/community/RetentionScience/Waves/etc/config.xml +115 -102
  40. app/code/community/RetentionScience/Waves/etc/system.xml +168 -209
  41. app/design/adminhtml/default/default/template/waves/rscore.phtml +0 -101
  42. app/design/frontend/base/default/layout/waves.xml +8 -9
  43. app/design/frontend/base/default/template/waves/waves.phtml +65 -68
  44. app/etc/modules/RetentionScience_Waves.xml +0 -9
  45. js/RetentionScience/retention_science_wave.js +0 -27
  46. js/waves/waves.js +53 -0
  47. package.xml +10 -17
app/code/community/RetentionScience/.DS_Store DELETED
Binary file
app/code/community/RetentionScience/Waves/Block/Adminhtml/Rscore.php CHANGED
@@ -1,12 +1,10 @@
1
  <?php
2
 
3
  class RetentionScience_Waves_Block_Adminhtml_Rscore extends Mage_Adminhtml_Block_Abstract
4
- implements Varien_Data_Form_Element_Renderer_Interface
5
  {
6
  public function render(Varien_Data_Form_Element_Abstract $fieldset)
7
  {
8
- if (Mage::getStoreConfig('waves/retentionscience_settings/enable') == 0) {
9
- return $this->getLayout()->createBlock('waves/adminhtml_rscore')->setTemplate('waves/rscore.phtml')->assign('in_config', true)->toHtml();
10
- }
11
  }
12
  }
1
  <?php
2
 
3
  class RetentionScience_Waves_Block_Adminhtml_Rscore extends Mage_Adminhtml_Block_Abstract
4
+ implements Varien_Data_Form_Element_Renderer_Interface
5
  {
6
  public function render(Varien_Data_Form_Element_Abstract $fieldset)
7
  {
8
+ return $this->getLayout()->createBlock('waves/adminhtml_rscore')->setTemplate('waves/rscore.phtml')->assign('in_config', true)->toHtml();
 
 
9
  }
10
  }
app/code/community/RetentionScience/Waves/Block/Adminhtml/Syncbutton.php CHANGED
@@ -2,34 +2,34 @@
2
 
3
 
4
  class RetentionScience_Waves_Block_Adminhtml_Syncbutton
5
- extends Mage_Adminhtml_Block_System_Config_Form_Field
6
  {
7
 
8
- protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
9
- {
10
- $this->setElement($element);
11
- $originalData = $element->getOriginalData();
12
- $action = $originalData['rs_button_url'];
13
- $link_url = $this->_getLink($action);
14
- return $this->_getAddRowButtonHtml($link_url);
15
- }
16
 
17
 
18
- protected function _getAddRowButtonHtml($link_url)
19
- {
20
- $title = "Run Now";
21
- return $this->getLayout()->createBlock('adminhtml/widget_button')
22
- ->setType('button')
23
- ->setClass('run_now_button')
24
- ->setLabel($title)
25
- ->setOnClick("location.href='$link_url';")
26
- ->setDisabled(false)
27
- ->toHtml();
28
- }
29
 
30
- protected function _getLink($action){
31
- $baseurl = Mage::app()->getStore()->getBaseUrl();
32
- return Mage::helper('adminhtml')->getUrl("waves/admin/$action");
33
- }
34
 
35
  }
2
 
3
 
4
  class RetentionScience_Waves_Block_Adminhtml_Syncbutton
5
+ extends Mage_Adminhtml_Block_System_Config_Form_Field
6
  {
7
 
8
+ protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
9
+ {
10
+ $this->setElement($element);
11
+ $originalData = $element->getOriginalData();
12
+ $action = $originalData['rs_button_url'];
13
+ $link_url = $this->_getLink($action);
14
+ return $this->_getAddRowButtonHtml($link_url);
15
+ }
16
 
17
 
18
+ protected function _getAddRowButtonHtml($link_url)
19
+ {
20
+ $title = "Run Now";
21
+ return $this->getLayout()->createBlock('adminhtml/widget_button')
22
+ ->setType('button')
23
+ ->setClass('run_now_button')
24
+ ->setLabel($title)
25
+ ->setOnClick("location.href='$link_url';")
26
+ ->setDisabled(false)
27
+ ->toHtml();
28
+ }
29
 
30
+ protected function _getLink($action){
31
+ $baseurl = Mage::app()->getStore()->getBaseUrl();
32
+ return Mage::helper('adminhtml')->getUrl("adminhtml/waves/$action");
33
+ }
34
 
35
  }
app/code/community/RetentionScience/Waves/Block/Waves.php CHANGED
@@ -1,73 +1,53 @@
1
- <?php
2
- /**
3
- * Magento
4
- *
5
- * NOTICE OF LICENSE
6
- *
7
- * This source file is subject to the Open Software License (OSL 3.0)
8
- * that is bundled with this package in the file LICENSE.txt.
9
- * It is also available through the world-wide-web at this URL:
10
- * http://opensource.org/licenses/osl-3.0.php
11
- * If you did not receive a copy of the license and are unable to
12
- * obtain it through the world-wide-web, please send an email
13
- * to license@magentocommerce.com so we can send you a copy immediately.
14
- *
15
- * DISCLAIMER
16
- *
17
- * Do not edit or add to this file if you wish to upgrade Magento to newer
18
- * versions in the future. If you wish to customize Magento for your
19
- * needs please refer to http://www.magentocommerce.com for more information.
20
- *
21
- * @category Mage
22
- * @package Mage_Adminhtml
23
- * @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com)
24
- * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
- */
26
-
27
- /**
28
- * Adminhtml cms blocks content block
29
- *
30
- * @category Mage
31
- * @package Mage_Adminhtml
32
- * @author Magento Core Team <core@magentocommerce.com>
33
- */
34
- class RetentionScience_Waves_Block_Waves extends Mage_Core_Block_Template
35
- {
36
-
37
- public function customerLoggedIn(){
38
- $customerLoggedIn = Mage::getSingleton('customer/session')->isLoggedIn();
39
- if($customerLoggedIn){
40
- return true;
41
- }
42
- return false;
43
- }
44
- public function getSiteid(){
45
- $siteID = Mage::getStoreConfig('waves/retentionscience_settings/site_id');
46
- return $siteID;
47
-
48
- }
49
- public function isEnable(){
50
- $staus = Mage::getStoreConfig('waves/retentionscience_settings/enable');
51
- if($staus){
52
- return true;
53
- }
54
- return false;
55
-
56
- }
57
- public function isAjaxAddToCartEnable(){
58
- return Mage::getStoreConfig('waves/retentionscience_settings/ajaxaddtocartenable');
59
- }
60
- public function customerId(){
61
- $email = Mage::getSingleton('customer/session')->getCustomer()->getEmail();
62
- $user_record_id = md5(trim(strtolower($email)));
63
- return $user_record_id;
64
- }
65
- public function getOrderId(){
66
- $lastOrderId = Mage::getSingleton('checkout/session')->getLastOrderId();
67
- return $lastOrderId;
68
- }
69
- public function getOrder(){
70
- $order = Mage::getSingleton('sales/order')->load($this->getOrderId());
71
- return $order;
72
- }
73
  }
1
+ <?php
2
+
3
+ class RetentionScience_Waves_Block_Waves extends Mage_Core_Block_Template {
4
+
5
+ public function customerLoggedIn(){
6
+ $customerLoggedIn = Mage::getSingleton('customer/session')->isLoggedIn();
7
+ if($customerLoggedIn){
8
+ return true;
9
+ }
10
+ return false;
11
+ }
12
+ public function getSiteId(){
13
+ return Mage::helper('waves')->getSiteId();
14
+ }
15
+ public function isEnabled(){
16
+ return Mage::helper('waves')->isEnabled() AND Mage::helper('waves')->getStoreId() == Mage::app()->getStore()->getId();
17
+
18
+ }
19
+ public function isAjaxAddToCartEnable(){
20
+ return Mage::helper('waves')->isAjaxCartEnabled();
21
+ }
22
+ public function customerId(){
23
+ $email = Mage::getSingleton('customer/session')->getCustomer()->getEmail();
24
+ $user_record_id = md5(trim(strtolower($email)));
25
+ return $user_record_id;
26
+ }
27
+
28
+ public function getCacheKeyInfo() {
29
+ return array('block_id' => $this->getBlockId(), 'template' => $this->getTemplate(), 'product_id' => $this->getProductId());
30
+ }
31
+
32
+ public function getProductId() {
33
+ if($_product = Mage::registry('current_product')) {
34
+ return $_product->getId();
35
+ }
36
+ if($this->getData('product_id')) {
37
+ return $this->getData('product_id');
38
+ }
39
+ return FALSE;
40
+ }
41
+
42
+ public function getOrders() {
43
+ $orderIds = $this->getOrderIds();
44
+ $ret = array();
45
+ if(! empty($orderIds) AND is_array($orderIds)) {
46
+ foreach($orderIds AS $orderId) {
47
+ $ret[] = Mage::getModel('sales/order')->load($orderId);
48
+ }
49
+ }
50
+ return $ret;
51
+ }
52
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  }
app/code/community/RetentionScience/Waves/Helper/Data.php CHANGED
@@ -1,5 +1,247 @@
1
- <?php
2
-
3
- class RetentionScience_Waves_Helper_Data extends Mage_Core_Helper_Abstract{
4
-
5
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class RetentionScience_Waves_Helper_Data extends Mage_Core_Helper_Abstract
4
+ {
5
+
6
+ CONST WAVES_SETTINGS_ENABLED = 'waves/retentionscience_settings/enable';
7
+
8
+ CONST WAVES_SETTINGS_API_USER = 'waves/retentionscience_settings/api_user';
9
+
10
+ CONST WAVES_SETTINGS_API_PASSWORD = 'waves/retentionscience_settings/api_pass';
11
+
12
+ CONST WAVES_SETTINGS_SITE_ID = 'waves/retentionscience_settings/site_id';
13
+
14
+ CONST WAVES_SETTINGS_TEST_MODE = 'waves/retentionscience_settings/testmode';
15
+
16
+ CONST WAVES_SETTINGS_AJAX_CART_ENABLED = 'waves/retentionscience_settings/ajaxaddtocartenable';
17
+
18
+ CONST WAVES_SETTINGS_STORE_ID = 'waves/retentionscience_settings/store_id';
19
+
20
+ CONST WAVES_SETTINGS_BULK_COMPRESSION_ENABLED = 'waves/rs_sync_advanced/rs_use_bulk_compression';
21
+
22
+ CONST WAVES_SETTINGS_AWS_ACCESS_KEY_ID = 'waves/rs_log_settings/aws_access_key_id';
23
+
24
+ CONST WAVES_SETTINGS_AWS_SECRET_ACCESS_KEY = 'waves/rs_log_settings/aws_secret_access_key';
25
+
26
+ CONST WAVES_SETTINGS_AWS_LOG_STREAM = 'waves/rs_log_settings/aws_log_stream';
27
+
28
+ CONST WAVES_SETTINGS_AWS_LOG_GROUP = 'waves/rs_log_settings/aws_log_group';
29
+
30
+ CONST WAVES_SETTINGS_AWS_SESSION_TOKEN = 'waves/rs_log_settings/aws_session_token';
31
+
32
+ CONST WAVES_CACHE_KEY_RSCOREDATA = 'waves_rscoredata';
33
+
34
+ CONST WAVES_CACHE_LIFETIME = 600;
35
+
36
+ protected $_regionNames;
37
+
38
+ protected $_AWS_ACCESS_KEY_ID;
39
+
40
+ protected $_AWS_SECRET_ACCESS_KEY;
41
+
42
+ protected $_AWS_SESSION_TOKEN;
43
+
44
+ protected $_AWS_LOG_GROUP;
45
+
46
+ protected $_AWS_LOG_STREAM;
47
+
48
+ protected $_RS_SITE_ID;
49
+
50
+ public function getRegionNameById($regionId) {
51
+ if(is_null($this->_regionNames)) {
52
+ $collection = Mage::getModel('directory/region')->getCollection();
53
+ foreach($collection AS $region) {
54
+ $this->_regionNames[$region->getId()] = $region->getName();
55
+ }
56
+ }
57
+ return isset($this->_regionNames[$regionId]) ? $this->_regionNames[$regionId] : '';
58
+ }
59
+
60
+ public function isEnabled() {
61
+ return Mage::getStoreConfig(self::WAVES_SETTINGS_ENABLED);
62
+ }
63
+
64
+ public function disable() {
65
+ Mage::getConfig()->saveConfig(self::WAVES_SETTINGS_ENABLED, 0);
66
+ $this->setSiteId('');
67
+ Mage::getConfig()->cleanCache();
68
+
69
+ return $this;
70
+ }
71
+
72
+ public function getApiUser() {
73
+ return Mage::getStoreConfig(self::WAVES_SETTINGS_API_USER);
74
+ }
75
+
76
+ public function getApiPassword() {
77
+ return Mage::getStoreConfig(self::WAVES_SETTINGS_API_PASSWORD);
78
+ }
79
+
80
+ public function getSiteId() {
81
+ if(! is_null($this->_RS_SITE_ID)) {
82
+ return $this->_RS_SITE_ID;
83
+ }
84
+ return Mage::getStoreConfig(self::WAVES_SETTINGS_SITE_ID);
85
+ }
86
+
87
+ public function isTestMode() {
88
+ return Mage::getStoreConfig(self::WAVES_SETTINGS_TEST_MODE);
89
+ }
90
+
91
+ public function isAjaxCartEnabled() {
92
+ return Mage::getStoreConfig(self::WAVES_SETTINGS_AJAX_CART_ENABLED);
93
+ }
94
+
95
+ public function getStoreId() {
96
+ return Mage::getStoreConfig(self::WAVES_SETTINGS_STORE_ID);
97
+ }
98
+
99
+ public function getWebsiteId() {
100
+ static $websiteId;
101
+ if(is_null($websiteId)) {
102
+ $store = Mage::getModel('core/store')->load($this->getStoreId());
103
+ $websiteId = $store->getWebsiteId();
104
+ }
105
+ return $websiteId;
106
+ }
107
+
108
+ public function isBulkCompressionEnabled() {
109
+ $enabled = (bool) Mage::getStoreConfig(self::WAVES_SETTINGS_BULK_COMPRESSION_ENABLED);
110
+ if($enabled) {
111
+ if(! function_exists('gzopen') OR ! function_exists('gzwrite') OR ! function_exists('gzclose')) {
112
+ $enabled = FALSE;
113
+ }
114
+ }
115
+ return $enabled;
116
+ }
117
+
118
+ public function getAWSAccessKeyId() {
119
+ if(! is_null($this->_AWS_ACCESS_KEY_ID)) {
120
+ return $this->_AWS_ACCESS_KEY_ID;
121
+ }
122
+ return Mage::getStoreConfig(self::WAVES_SETTINGS_AWS_ACCESS_KEY_ID);
123
+ }
124
+
125
+ public function getAWSSecretAccessKey() {
126
+ if(! is_null($this->_AWS_SECRET_ACCESS_KEY)) {
127
+ return $this->_AWS_SECRET_ACCESS_KEY;
128
+ }
129
+ return Mage::getStoreConfig(self::WAVES_SETTINGS_AWS_SECRET_ACCESS_KEY);
130
+ }
131
+
132
+ public function getAWSLogStream() {
133
+ if(! is_null($this->_AWS_LOG_STREAM)) {
134
+ return $this->_AWS_LOG_STREAM;
135
+ }
136
+ return Mage::getStoreConfig(self::WAVES_SETTINGS_AWS_LOG_STREAM);
137
+ }
138
+
139
+ public function getAWSLogGroup() {
140
+ if(! is_null($this->_AWS_LOG_GROUP)) {
141
+ return $this->_AWS_LOG_GROUP;
142
+ }
143
+ return Mage::getStoreConfig(self::WAVES_SETTINGS_AWS_LOG_GROUP);
144
+ }
145
+
146
+ public function getAWSSessionToken() {
147
+ if(! is_null($this->_AWS_SESSION_TOKEN)) {
148
+ return $this->_AWS_SESSION_TOKEN;
149
+ }
150
+ return Mage::getStoreConfig(self::WAVES_SETTINGS_AWS_SESSION_TOKEN);
151
+ }
152
+
153
+ public function setAWSSessionToken($value) {
154
+ $this->_AWS_SESSION_TOKEN = $value;
155
+ Mage::getConfig()->saveConfig(self::WAVES_SETTINGS_AWS_SESSION_TOKEN, $value);
156
+ Mage::getConfig()->cleanCache();
157
+ return $this;
158
+ }
159
+
160
+ public function setAWSAccessKeyId($value) {
161
+ $this->_AWS_ACCESS_KEY_ID = $value;
162
+ Mage::getConfig()->saveConfig(self::WAVES_SETTINGS_AWS_ACCESS_KEY_ID, $value);
163
+ Mage::getConfig()->cleanCache();
164
+ return $this;
165
+ }
166
+
167
+ public function setAWSSecretAccessKey($value) {
168
+ $this->_AWS_SECRET_ACCESS_KEY = $value;
169
+ Mage::getConfig()->saveConfig(self::WAVES_SETTINGS_AWS_SECRET_ACCESS_KEY, $value);
170
+ Mage::getConfig()->cleanCache();
171
+ return $this;
172
+ }
173
+
174
+ public function setAWSLogStream($value) {
175
+ $this->_AWS_LOG_STREAM = $value;
176
+ Mage::getConfig()->saveConfig(self::WAVES_SETTINGS_AWS_LOG_STREAM, $value);
177
+ Mage::getConfig()->cleanCache();
178
+ return $this;
179
+ }
180
+
181
+ public function setAWSLogGroup($value) {
182
+ $this->_AWS_LOG_GROUP = $value;
183
+ Mage::getConfig()->saveConfig(self::WAVES_SETTINGS_AWS_LOG_GROUP, $value);
184
+ Mage::getConfig()->cleanCache();
185
+ return $this;
186
+ }
187
+
188
+ public function setSiteId($value) {
189
+ $this->_RS_SITE_ID = $value;
190
+ Mage::getConfig()->saveConfig(self::WAVES_SETTINGS_SITE_ID, $value);
191
+ Mage::getConfig()->cleanCache();
192
+ return $this;
193
+ }
194
+
195
+ public function getRScore($forceLoad = TRUE) {
196
+ $cache = Mage::app()->getCache();
197
+ if(! ($rscore = $cache->load(self::WAVES_CACHE_KEY_RSCOREDATA)) AND $forceLoad) {
198
+ try {
199
+ $rscore_data = Mage::getModel('waves/source_rscoredata')->getDataArray();
200
+ $api = $this->getApi();
201
+ $rscore_json = $api->calculate_rscore($rscore_data);
202
+ $rscore = Zend_Json::decode($rscore_json);
203
+ if($rscore) {
204
+ $cache->save(Zend_Json::encode($rscore), self::WAVES_CACHE_KEY_RSCOREDATA, array(), self::WAVES_CACHE_LIFETIME);
205
+ }
206
+ } catch(Exception $e) {
207
+ // Do nothing
208
+ }
209
+ } else {
210
+ $rscore = Zend_Json::decode($rscore);
211
+ }
212
+ return $rscore;
213
+ }
214
+
215
+ /**
216
+ * @return RetentionScience_Waves_Model_Connection_RetentionScienceApi
217
+ */
218
+ public function getApi() {
219
+ static $api;
220
+ if(is_null($api)) {
221
+ $api = Mage::getModel('waves/connection_retentionScienceApi', array(
222
+ 'username' => Mage::helper('waves')->getApiUser(),
223
+ 'password' => Mage::helper('waves')->getApiPassword(),
224
+ 'testmode' => Mage::helper('waves')->isTestMode(),
225
+ ));
226
+ }
227
+ return $api;
228
+ }
229
+
230
+ public function updateAWSCredentials() {
231
+ try {
232
+ $aws_credentials = $this->getApi()->get_aws_credentials();
233
+ $aws_credentials = Zend_Json::decode($aws_credentials);
234
+ if(isset($aws_credentials) AND is_array($aws_credentials) AND isset($aws_credentials['status']) AND $aws_credentials['status'] === 'success') {
235
+ Mage::helper('waves')->setAWSAccessKeyId($aws_credentials['access_key_id']);
236
+ Mage::helper('waves')->setAWSSecretAccessKey($aws_credentials['secret_access_key']);
237
+ Mage::helper('waves')->setAWSLogStream($aws_credentials['log_stream']);
238
+ Mage::helper('waves')->setAWSLogGroup($aws_credentials['log_group']);
239
+ Mage::helper('waves')->setAWSSessionToken($aws_credentials['session_token']);
240
+ }
241
+ return TRUE;
242
+ } catch(Exception $e) {
243
+ return FALSE;
244
+ }
245
+ }
246
+
247
+ }
app/code/community/RetentionScience/Waves/Helper/Storeselect.php DELETED
@@ -1,13 +0,0 @@
1
- <?php
2
-
3
- class RetentionScience_Waves_Helper_Storeselect {
4
- public function toOptionArray()
5
- {
6
- $stores = Mage::app()->getStores();
7
- $options = array(array('value' => null, 'label' => "Select a Store"));
8
- foreach ($stores as $store_id => $store) {
9
- array_push($options, array('value' => $store_id, 'label' => $store->getWebsite()->getName() . " - " . $store->getName()));
10
- }
11
- return $options;
12
- }
13
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
app/code/community/RetentionScience/Waves/Model/Configfieldlistener.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class RetentionScience_Waves_Model_Configfieldlistener extends Varien_Object {
4
+
5
+
6
+ public function logParameters($observer) {
7
+ $post_vars = Mage::app()->getRequest()->getPost();
8
+ $results = print_r($post_vars, true);
9
+ $results = "Waves Config Saved with params: \n" . $results;
10
+
11
+ Mage::getSingleton('waves/connection_awsCloudWatch')->logMessage($results);
12
+ }
13
+
14
+
15
+ }
app/code/community/RetentionScience/Waves/Model/Connection/AwsCloudWatch.php ADDED
@@ -0,0 +1,370 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once 'aws-sdk-php' . DIRECTORY_SEPARATOR . 'aws-autoloader.php';
4
+
5
+ use Aws\CloudWatchLogs\CloudWatchLogsClient;
6
+
7
+ class RetentionScience_Waves_Model_Connection_AwsCloudWatch extends Varien_Object {
8
+
9
+ const AWS_DEFAULT_REGION = 'us-east-1';
10
+
11
+ const AWS_VERSION = '2014-03-28';
12
+
13
+ const MAX_LOG_EVENTS = 10000;
14
+
15
+ const MAX_BATCH_SIZE = 1048576;
16
+
17
+ const EVENT_ADDITIONAL_SIZE = 26;
18
+
19
+ protected $_logs = array();
20
+
21
+ protected $_logSize = array();
22
+
23
+ protected $_logBatches = array();
24
+
25
+ public function __construct() {
26
+ parent::__construct();
27
+
28
+ $this->setRegion(self::AWS_DEFAULT_REGION);
29
+ $this->setAccessKeyId(Mage::helper('waves')->getAWSAccessKeyId());
30
+ $this->setSecretAccessKey(Mage::helper('waves')->getAWSSecretAccessKey());
31
+ $this->setSessionToken(Mage::helper('waves')->getAWSSessionToken());
32
+
33
+ $this->setClient(CloudWatchLogsClient::factory(array(
34
+ 'region' => $this->getRegion(),
35
+ 'version' => self::AWS_VERSION,
36
+ 'credentials' => array(
37
+ 'key' => $this->getAccessKeyId(),
38
+ 'secret' => $this->getSecretAccessKey(),
39
+ 'token' => $this->getSessionToken(),
40
+ ),
41
+ )));
42
+
43
+ // Bug fix for errors during class loading
44
+ try {
45
+ $result = new Aws\Result;
46
+ $this->getClient()->putLogEvents(array(
47
+ 'logGroupName' => 'test',
48
+ 'logStreamName' => 'test',
49
+ 'logEvents' => array(
50
+ array(
51
+ 'timestamp' => 1000,
52
+ 'message' => 'test',
53
+ ),
54
+ ),
55
+ ));
56
+ } catch(Exception $e) {}
57
+ }
58
+
59
+ public function reinitClient() {
60
+ $this->setAccessKeyId(Mage::helper('waves')->getAWSAccessKeyId());
61
+ $this->setSecretAccessKey(Mage::helper('waves')->getAWSSecretAccessKey());
62
+ $this->setSessionToken(Mage::helper('waves')->getAWSSessionToken());
63
+
64
+ $this->setClient(CloudWatchLogsClient::factory(array(
65
+ 'region' => $this->getRegion(),
66
+ 'version' => self::AWS_VERSION,
67
+ 'credentials' => array(
68
+ 'key' => $this->getAccessKeyId(),
69
+ 'secret' => $this->getSecretAccessKey(),
70
+ 'token' => $this->getSessionToken(),
71
+ ),
72
+ )));
73
+ }
74
+
75
+ /**
76
+ *
77
+ * Log one message
78
+ * Example:
79
+ * $this->log_message("hello testing");
80
+ * @param string $msg
81
+ */
82
+ public function logMessage($msg) {
83
+ $siteId = Mage::helper('waves')->getSiteId();
84
+ $prefix = date('Y-m-d H:i:s'). ' UTC - [site_id ' . $siteId . '] ';
85
+
86
+ $this->log(array(
87
+ 'send' => TRUE,
88
+ 'logGroupName' => Mage::helper('waves')->getAWSLogGroup(),
89
+ 'logStreamName' => Mage::helper('waves')->getAWSLogStream(),
90
+ 'message' => $prefix . $msg
91
+ ));
92
+ }
93
+
94
+ /**
95
+ *
96
+ * Log event
97
+ * Example:
98
+ * $this->log(array(
99
+ * //Required
100
+ * 'logGroupName' => 'test',
101
+ * // Required
102
+ * 'logStreamName' => 'test',
103
+ * // Required
104
+ * 'message' => 'qwerty',
105
+ * // Optional
106
+ * 'timestamp' => round(microtime(true) * 1000),
107
+ * // Optional
108
+ * 'send' => TRUE || FALSE, // If set tu true - log will be send to AWS CloudWatchLogs immediately
109
+ * ));
110
+ * @param array $log
111
+ */
112
+ public function log(array $log) {
113
+ if(! isset($log['logGroupName']) OR ! isset($log['logStreamName']) OR ! isset($log['message'])) {
114
+ return;
115
+ }
116
+ if(! isset($log['timestamp'])) {
117
+ $log['timestamp'] = round(microtime(true) * 1000);
118
+ }
119
+ $newBatch = FALSE;
120
+ if(isset($log['send']) AND $log['send']) {
121
+ $location = array(
122
+ 'logGroupName' => $log['logGroupName'],
123
+ 'logStreamName' => $log['logStreamName'],
124
+ );
125
+ $location['logGroupName'] = $this->getLogGroup($location['logGroupName']);
126
+ $location['logStreamName'] = $this->getLogStream($location['logGroupName'], $location['logStreamName']);
127
+ $this->putLogEvents($location, array(
128
+ array('timestamp' => $log['timestamp'], 'message' => $log['message'],),
129
+ ));
130
+ } else {
131
+ $logGroupName = $log['logGroupName'];
132
+ $logStreamName = $log['logStreamName'];
133
+ if(! isset($this->_logs[$logGroupName])) {
134
+ $this->_logs[$logGroupName] = array();
135
+ $this->_logSize[$logGroupName] = array();
136
+ $this->_logBatches[$logGroupName] = array();
137
+ }
138
+ if(! isset($this->_logs[$logGroupName][$logStreamName])) {
139
+ $this->_logs[$logGroupName][$logStreamName] = array();
140
+ $this->_logSize[$logGroupName][$logStreamName] = 0;
141
+ $this->_logBatches[$logGroupName][$logStreamName] = 0;
142
+ }
143
+ $batch = $this->_logBatches[$logGroupName][$logStreamName];
144
+ if(! isset($this->_logs[$logGroupName][$logStreamName][$batch])) {
145
+ $this->_logs[$logGroupName][$logStreamName][$batch] = array();
146
+ }
147
+ if(
148
+ (strlen($log['message']) + self::EVENT_ADDITIONAL_SIZE + $this->_logSize[$logGroupName][$logStreamName] > self::MAX_BATCH_SIZE)
149
+ OR
150
+ (count($this->_logs[$logGroupName][$logStreamName][$batch]) >= self::MAX_LOG_EVENTS)
151
+ ) {
152
+ $this->_logSize[$logGroupName][$logStreamName] = 0;
153
+ $this->_logBatches[$logGroupName][$logStreamName] ++;
154
+ $batch = $this->_logBatches[$logGroupName][$logStreamName];
155
+ $newBatch = TRUE;
156
+ }
157
+ $this->_logSize[$logGroupName][$logStreamName] += strlen($log['message']) + self::EVENT_ADDITIONAL_SIZE;
158
+ $this->_logs[$logGroupName][$logStreamName][$batch][] = array(
159
+ 'timestamp' => $log['timestamp'],
160
+ 'message' => $log['message'],
161
+ );
162
+ }
163
+ // If batch is full - send and clean - if there would be a lot of errors - to save memory
164
+ if($newBatch) {
165
+ $this->sendLogs();
166
+ gc_collect_cycles();
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Send all logs to AWS CloudWatchLogs if 'send' wasn't set to TRUE in $this->log() method
172
+ */
173
+ public function sendLogs() {
174
+ if(empty($this->_logs)) {
175
+ return;
176
+ }
177
+ foreach($this->_logs AS $logGroupName => $logStreams) {
178
+ $location = array(
179
+ 'logGroupName' => $logGroupName,
180
+ );
181
+ $location['logGroupName'] = $this->getLogGroup($location['logGroupName']);
182
+ foreach($logStreams AS $logStreamName => $logEventsBatches) {
183
+ $location['logStreamName'] = $this->getLogStream($location['logGroupName'], $logStreamName);
184
+ foreach($logEventsBatches AS $logEvents) {
185
+ $this->putLogEvents($location, $logEvents);
186
+ }
187
+ }
188
+ }
189
+ $this->_logs = array();
190
+ }
191
+
192
+ public function getReadableEventLog($logGroupName, $logStreamNames = '') {
193
+ $ret = '';
194
+ $ret .= 'LogGroupName: ' . $logGroupName . "\n";
195
+ try {
196
+ if (empty($logStreamNames)) {
197
+ $streams = $this->getClient()->describeLogStreams(array(
198
+ 'logGroupName' => $logGroupName,
199
+ ))->get('logStreams');
200
+ $logStreamNames = array();
201
+ if (!empty($streams)) {
202
+ foreach ($streams AS $stream) {
203
+ $logStreamNames[] = $stream['logStreamName'];
204
+ }
205
+ }
206
+ } else {
207
+ $logStreamNames = array($logStreamNames);
208
+ }
209
+ if (empty($logStreamNames)) {
210
+ $ret .= "\tNo streams found\n";
211
+ } else {
212
+ foreach ($logStreamNames AS $logStreamName) {
213
+ $ret .= "\tLogStreamName: {$logStreamName}\n";
214
+ $logEvents = $this->getClient()->getLogEvents(array(
215
+ 'logGroupName' => $logGroupName,
216
+ 'logStreamName' => $logStreamName,
217
+ ))->get('events');
218
+ if (empty($logEvents)) {
219
+ $ret .= "\t\tNo log events found\n";
220
+ } else {
221
+ foreach ($logEvents AS $logEvent) {
222
+ $ret .= "\t\t" . $logEvent['timestamp'] . " {$logEvent['message']}\n";
223
+ }
224
+ }
225
+ }
226
+ }
227
+ } catch(Exception $e) {
228
+ $ret .= "\t" . $e->getMessage() . "\n";
229
+ }
230
+ return $ret;
231
+ }
232
+
233
+ public function cleanAll() {
234
+ $nextToken = TRUE;
235
+ while($nextToken) {
236
+ $request = array();
237
+ if(is_string($nextToken)) {
238
+ $request['nextToken'] = $nextToken;
239
+ }
240
+ $result = $this->getClient()->describeLogGroups($request);
241
+ $nextToken = $result->get('nextToken');
242
+ $logGroups = $result->get('logGroups');
243
+ if(! empty($logGroups)) foreach($logGroups AS $logGroup) {
244
+ $this->getClient()->deleteLogGroup($logGroup);
245
+ }
246
+ }
247
+ }
248
+
249
+ /**
250
+ * Get/Create log group
251
+ * @param $logGroupName
252
+ * @return mixed
253
+ */
254
+ protected function getLogGroup($logGroupName) {
255
+ try {
256
+ $logGroupName = preg_replace('#[^a-zA-Z0-9_\-\/\.]#', '', $logGroupName);
257
+ return $logGroupName;
258
+ $this->getClient()->createLogGroup(array(
259
+ 'logGroupName' => $logGroupName,
260
+ ));
261
+ return $logGroupName;
262
+ } catch(Aws\CloudWatchLogs\Exception\CloudWatchLogsException $e) {
263
+ if($e->getAwsErrorCode() === 'ResourceAlreadyExistsException') {
264
+ return $logGroupName;
265
+ }
266
+ throw $e;
267
+ }
268
+ }
269
+
270
+ /**
271
+ * Get/Create log stream
272
+ * @param $logGroupName
273
+ * @param $logStreamName
274
+ * @return mixed
275
+ */
276
+ protected function getLogStream($logGroupName, $logStreamName) {
277
+ try {
278
+ $logStreamName = preg_replace('#[:]#', '', $logStreamName);
279
+ $this->getClient()->createLogStream(array(
280
+ 'logGroupName' => $logGroupName,
281
+ 'logStreamName' => $logStreamName,
282
+ ));
283
+ return $logStreamName;
284
+ } catch(Aws\CloudWatchLogs\Exception\CloudWatchLogsException $e) {
285
+ return $logStreamName;
286
+ if($e->getAwsErrorCode() === 'ResourceAlreadyExistsException') {
287
+ return $logStreamName;
288
+ }
289
+ throw $e;
290
+ }
291
+ }
292
+
293
+ /**
294
+ * Send log events
295
+ * @param array $location
296
+ * @param array $events
297
+ */
298
+ protected function putLogEvents(array $location, array $events = array(), $catchException = TRUE) {
299
+ if(empty($events)) {
300
+ return;
301
+ }
302
+ $sequenceToken = $this->getSequenceToken($location);
303
+ $request = $location;
304
+ $request['logEvents'] = $events;
305
+ if(! is_null($sequenceToken)) {
306
+ $request['sequenceToken'] = $sequenceToken;
307
+ }
308
+ try {
309
+ $result = $this->getClient()->putLogEvents($request);
310
+ $this->setSequenceToken($location, $result->get('nextSequenceToken'));
311
+ return $result;
312
+ } catch(Aws\CloudWatchLogs\Exception\CloudWatchLogsException $e) {
313
+ if($e->getAwsErrorCode() === 'InvalidSequenceTokenException') {
314
+ $result = $this->getClient()->describeLogStreams(array(
315
+ 'logGroupName' => $location['logGroupName'],
316
+ 'logStreamNamePrefix' => $location['logStreamName'],
317
+ ));
318
+ $logStreams = $result->get('logStreams');
319
+ if(! empty($logStreams)) {
320
+ $logStream = array_shift($logStreams);
321
+ $this->setSequenceToken($location, $logStream['uploadSequenceToken']);
322
+ return $this->putLogEvents($location, $events);
323
+ }
324
+ } else {
325
+ if(! $catchException) {
326
+ throw $e;
327
+ }
328
+ Mage::helper('waves')->updateAWSCredentials();
329
+ $this->reinitClient();
330
+ $this->putLogEvents($location, $events, FALSE);
331
+ }
332
+ } catch(Exception $e) {
333
+ if(! $catchException) {
334
+ throw $e;
335
+ }
336
+ Mage::helper('waves')->updateAWSCredentials();
337
+ $this->reinitClient();
338
+ $this->putLogEvents($location, $events, FALSE);
339
+ }
340
+ }
341
+
342
+ /**
343
+ * Get Sequence Token
344
+ * @param array $location
345
+ * @return mixed
346
+ */
347
+ protected function getSequenceToken(array $location) {
348
+ $tokens = $this->getSequenceTokens();
349
+ $key = $location['logGroupName'] . '::' . $location['logStreamName'];
350
+ if(isset($tokens[$key])) {
351
+ return $tokens[$key];
352
+ }
353
+ }
354
+
355
+ /**
356
+ * Set Sequence Token
357
+ * @param array $location
358
+ * @param $sequenceToken
359
+ */
360
+ protected function setSequenceToken(array $location, $sequenceToken) {
361
+ $tokens = $this->getSequenceTokens();
362
+ if(! is_array($tokens)) {
363
+ $tokens = array();
364
+ }
365
+ $key = $location['logGroupName'] . '::' . $location['logStreamName'];
366
+ $tokens[$key] = $sequenceToken;
367
+ $this->setSequenceTokens($tokens);
368
+ }
369
+
370
+ }
app/code/community/RetentionScience/Waves/Model/{retention_science_api.php → Connection/RetentionScienceApi.php} RENAMED
@@ -1,205 +1,163 @@
1
- <?php
2
- ini_set('memory_limit', '-1');
3
-
4
- /*
5
- Retention Science PHP API Client
6
-
7
- Copyright (c) 2012 Retention Science
8
-
9
- Released under the GNU General Public License
10
- */
11
- class RetentionScienceApi {
12
- const API_DEV_URL = 'http://api.rsapi.dev';
13
- const API_TEST_URL = 'http://api.retentionsandbox.com';
14
- const API_URL = 'http://api.retentionscience.com';
15
- const API_PORT = 80;
16
- const API_VERSION = '1';
17
-
18
- private $password;
19
- private $time_out = 60;
20
- private $username;
21
- private $testmode;
22
-
23
- // class methods
24
- public function __construct($username = null, $password = null, $testmode=false) {
25
- if($username !== null) $this->set_username($username);
26
- if($password !== null) $this->set_password($password);
27
- if($testmode) $this->set_testmode($testmode);
28
- }
29
-
30
- private function perform_call($url, $params = array(), $authenticate = false, $use_post = true) {
31
- // redefine
32
- $url = (string) $url;
33
- $aParameters = (array) $params;
34
- $authenticate = (bool) $authenticate;
35
- $use_post = (bool) $use_post;
36
-
37
- // build url
38
- $request_url = parse_url('http://' . $_SERVER['HTTP_HOST']);
39
-
40
- if ($request_url['host'] == 'rsapi.dev' || $request_url['host'] == 'magento.dev') {
41
- $url = self::API_DEV_URL .'/' . $url;
42
- } elseif ($this->get_testmode()) {
43
- $url = self::API_TEST_URL .'/' . $url;
44
- } else {
45
- $url = self::API_URL .'/' . $url;
46
- }
47
-
48
- // validate needed authentication
49
- if($authenticate && ($this->get_username() == '' || $this->get_password() == '')) {
50
- throw new RetentionScienceException('No username or password was set.');
51
- }
52
-
53
- // build GET URL if not using post
54
- if(!empty($params) && !$use_post){
55
- $url .= '?'. http_build_query( $params );
56
- }
57
-
58
- // set options
59
- $options[CURLOPT_URL] = $url;
60
- $options[CURLOPT_PORT] = self::API_PORT;
61
- $options[CURLOPT_USERAGENT] = $this->get_user_agent();
62
- // follow on only if allowed - 20120221
63
- if (ini_get('open_basedir') == '' && ini_get('safe_mode' == 'Off')){
64
- $options[CURLOPT_FOLLOWLOCATION] = true;
65
- }
66
- $options[CURLOPT_RETURNTRANSFER] = true;
67
- $options[CURLOPT_TIMEOUT] = (int) $this->time_out;
68
-
69
- // HTTP basic auth
70
- if($authenticate) {
71
- $options[CURLOPT_HTTPAUTH] = CURLAUTH_BASIC;
72
- $options[CURLOPT_USERPWD] = $this->get_username() .':'. $this->get_password();
73
- }
74
-
75
- // build post params if $use_post
76
- if(!empty($params) && $use_post) {
77
- $options[CURLOPT_POST] = true;
78
- $options[CURLOPT_POSTFIELDS] = $params;
79
- }
80
-
81
- // curl init
82
- $curl = curl_init();
83
- // set options
84
- curl_setopt_array($curl, $options);
85
- // execute
86
- $response = curl_exec($curl);
87
- $headers = curl_getinfo($curl);
88
- // fetch errors and status code
89
- $errorNumber = curl_errno($curl);
90
- $errorMessage = curl_error($curl);
91
- $http_status_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
92
-
93
- if ($errorNumber != 0) {
94
- $response = 'cURL ERROR: [' . $errorNumber . "] " . $errorMessage;
95
- }
96
- // close
97
- curl_close($curl);
98
- return array('response_code' => $http_status_code,
99
- 'response' => $response);
100
- }
101
-
102
- private function handle_response($response){
103
- // decode the returned json
104
- if ($response['response_code'] == 200 || $response['response_code'] == 201 ){
105
- return $response['response'];
106
- } else {
107
- throw new RetentionScienceException($response['response_code'] . ' - ' . $response['response']);
108
- }
109
- }
110
-
111
-
112
- // Getters
113
- private function get_password(){
114
- return (string) $this->password;
115
- }
116
- private function get_user_agent(){
117
- return (string) 'Retention Science PHP API Client / v'. self::API_VERSION;
118
- }
119
- private function get_username(){
120
- return (string) $this->username;
121
- }
122
- private function get_testmode(){
123
- return (boolean) $this->testmode;
124
- }
125
-
126
- // Setters
127
- private function set_username($username){
128
- $this->username = (string) $username;
129
- }
130
- private function set_password($password){
131
- $this->password = (string) $password;
132
- }
133
- private function set_testmode($testmode){
134
- $this->testmode = (boolean) $testmode;
135
- }
136
-
137
- /* Users resource */
138
- public function user_exists($record_id) {
139
- $url = 'users/exists/' . $record_id;
140
- $response = $this->perform_call($url, array(), true, false);
141
- return ($this->handle_response($response) == 'true');
142
- }
143
-
144
- public function get_last_user_record_id() {
145
- $url = 'users/last_record_id';
146
- $response = $this->perform_call($url, array(), true, false);
147
- return $this->handle_response($response);
148
- }
149
-
150
- public function show_user($record_id) {
151
- $url = 'users/show/' . urlencode($record_id);
152
- $response = $this->perform_call($url, array(), true, false);
153
- return json_decode($this->handle_response($response), true);
154
- }
155
-
156
- /* Orders resource */
157
- public function get_last_order_record_id() {
158
- $url = 'orders/last_record_id';
159
- $response = $this->perform_call($url, array(), true, false);
160
- return $this->handle_response($response);
161
- }
162
-
163
- public function show_order($record_id) {
164
- $url = 'orders/show/' . urlencode($record_id);
165
- $response = $this->perform_call($url, array(), true, false);
166
- return json_decode($this->handle_response($response), true);
167
- }
168
-
169
- /* Items resource */
170
- public function show_item($record_id) {
171
- $url = 'items/show/' . urlencode($record_id);
172
- $response = $this->perform_call($url, array(), true, false);
173
- return json_decode($this->handle_response($response), true);
174
- }
175
-
176
- /* Categories resource */
177
- public function show_category($record_id) {
178
- $url = 'categories/show/' . urlencode($record_id);
179
- $response = $this->perform_call($url, array(), true, false);
180
- return json_decode($this->handle_response($response), true);
181
- }
182
-
183
- /* RScore resource */
184
- public function calculate_rscore($rscore_data_array) {
185
- $url = 'r_scores/calculate';
186
- $response = $this->perform_call($url, array('data' => json_encode($rscore_data_array)), false, true);
187
- return $this->handle_response($response);
188
- }
189
-
190
- /* Data Sync */
191
- public function sync_data($file_hash) {
192
- $url = 'bulk_import/import';
193
-
194
- $upload_files = array();
195
- foreach ($file_hash as $type => $file) {
196
- $upload_files[$type] = "@$file";
197
- }
198
-
199
- $response = $this->perform_call($url, $upload_files, true, true);
200
- return $this->handle_response($response);
201
- }
202
- }
203
-
204
-
205
- class RetentionScienceException extends Exception { }
1
+ <?php
2
+
3
+ class RetentionScience_Waves_Model_Connection_RetentionScienceApi {
4
+
5
+ const API_TEST_URL = 'https://api.retentionsandbox.com';
6
+ const API_URL = 'https://api.retentionscience.com';
7
+ const API_PORT = 80;
8
+ const API_VERSION = '1';
9
+
10
+ private $password;
11
+ private $time_out = 60;
12
+ private $username;
13
+ private $testmode;
14
+
15
+ // class methods
16
+ public function __construct($username = null, $password = null, $testmode=false) {
17
+ if(is_array($username) AND isset($username['username']) AND isset($username['password'])) {
18
+ $password = $username['password'];
19
+ $testmode = isset($username['testmode']) ? $username['testmode'] : FALSE;
20
+ $username = $username['username'];
21
+ }
22
+ if($username !== null) $this->set_username($username);
23
+ if($password !== null) $this->set_password($password);
24
+ if($testmode) $this->set_testmode($testmode);
25
+ }
26
+
27
+ private function perform_call($url, $params = array(), $authenticate = false, $use_post = true) {
28
+ // redefine
29
+ $url = (string) $url;
30
+ $aParameters = (array) $params;
31
+ $authenticate = (bool) $authenticate;
32
+ $use_post = (bool) $use_post;
33
+
34
+ if ($this->get_testmode()) {
35
+ $url = self::API_TEST_URL .'/' . $url;
36
+ } else {
37
+ $url = self::API_URL .'/' . $url;
38
+ }
39
+
40
+ // validate needed authentication
41
+ if($authenticate && ($this->get_username() == '' || $this->get_password() == '')) {
42
+ throw new RetentionScienceException('No username or password was set.');
43
+ }
44
+
45
+ // build GET URL if not using post
46
+ if(!empty($params) && !$use_post){
47
+ $url .= '?'. http_build_query( $params );
48
+ }
49
+
50
+ // set options
51
+ $options[CURLOPT_URL] = $url;
52
+ $options[CURLOPT_PORT] = self::API_PORT;
53
+ $options[CURLOPT_USERAGENT] = $this->get_user_agent();
54
+ // follow on only if allowed - 20120221
55
+ if (ini_get('open_basedir') == '' && ini_get('safe_mode' == 'Off')){
56
+ $options[CURLOPT_FOLLOWLOCATION] = true;
57
+ }
58
+ $options[CURLOPT_RETURNTRANSFER] = true;
59
+ $options[CURLOPT_TIMEOUT] = (int) $this->time_out;
60
+
61
+ // HTTP basic auth
62
+ if($authenticate) {
63
+ $options[CURLOPT_HTTPAUTH] = CURLAUTH_BASIC;
64
+ $options[CURLOPT_USERPWD] = $this->get_username() .':'. $this->get_password();
65
+ }
66
+
67
+ // build post params if $use_post
68
+ if(!empty($params) && $use_post) {
69
+ $options[CURLOPT_POST] = true;
70
+ $options[CURLOPT_POSTFIELDS] = $params;
71
+ }
72
+
73
+ // curl init
74
+ $curl = curl_init();
75
+ // set options
76
+ curl_setopt_array($curl, $options);
77
+ // execute
78
+ $response = curl_exec($curl);
79
+ $headers = curl_getinfo($curl);
80
+ // fetch errors and status code
81
+ $errorNumber = curl_errno($curl);
82
+ $errorMessage = curl_error($curl);
83
+ $http_status_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
84
+
85
+ if ($errorNumber != 0) {
86
+ $response = 'cURL ERROR: [' . $errorNumber . "] " . $errorMessage;
87
+ }
88
+ // close
89
+ curl_close($curl);
90
+ return array('response_code' => $http_status_code,
91
+ 'response' => $response);
92
+ }
93
+
94
+ private function handle_response($response){
95
+ // decode the returned json
96
+ if ($response['response_code'] == 200 || $response['response_code'] == 201 ){
97
+ return $response['response'];
98
+ } else {
99
+ throw new RetentionScienceException($response['response_code'] . ' - ' . $response['response']);
100
+ }
101
+ }
102
+
103
+
104
+ // Getters
105
+ private function get_password(){
106
+ return (string) $this->password;
107
+ }
108
+ private function get_user_agent(){
109
+ return (string) 'Retention Science PHP API Client / v'. self::API_VERSION;
110
+ }
111
+ private function get_username(){
112
+ return (string) $this->username;
113
+ }
114
+ private function get_testmode(){
115
+ return (boolean) $this->testmode;
116
+ }
117
+
118
+ // Setters
119
+ private function set_username($username){
120
+ $this->username = (string) $username;
121
+ }
122
+ private function set_password($password){
123
+ $this->password = (string) $password;
124
+ }
125
+ private function set_testmode($testmode){
126
+ $this->testmode = (boolean) $testmode;
127
+ }
128
+
129
+
130
+ /* log_credentials resource */
131
+ public function get_aws_credentials() {
132
+ $url = 'magento/log_credentials';
133
+ $response = $this->perform_call($url, array(), true, false);
134
+ return $this->handle_response($response);
135
+ }
136
+
137
+ /* site_id */
138
+ public function get_site_id() {
139
+ $url = 'sites/id';
140
+ $response = $this->perform_call($url, array(), true, false);
141
+ return $this->handle_response($response);
142
+ }
143
+
144
+ /* Data Sync */
145
+ public function sync_data($file_hash) {
146
+ $url = 'bulk_import/import';
147
+
148
+ $upload_files = array('import_type' => 'magento');
149
+ foreach ($file_hash as $type => $file) {
150
+ if(! function_exists('curl_file_create')) {
151
+ $upload_files[$type] = "@$file";
152
+ } else {
153
+ $upload_files[$type] = curl_file_create($file);
154
+ }
155
+ }
156
+
157
+ $response = $this->perform_call($url, $upload_files, true, true);
158
+ return $this->handle_response($response);
159
+ }
160
+
161
+ }
162
+
163
+ class RetentionScienceException extends Exception { }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/code/community/RetentionScience/Waves/Model/Container/Waves.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class RetentionScience_Waves_Model_Container_Waves extends Enterprise_PageCache_Model_Container_Abstract {
4
+
5
+ public function applyWithoutApp(&$content)
6
+ {
7
+ return false;
8
+ }
9
+
10
+ protected function _getCacheId()
11
+ {
12
+ $id = 'WAVES_' . microtime() . '_' . rand(0,99);
13
+ return $id;
14
+ }
15
+
16
+ protected function _renderBlock()
17
+ {
18
+ $class = $this->_placeholder->getAttribute('block');
19
+ $block = new $class;
20
+ $block->setBlockId($this->_placeholder->getAttribute('block_id'));
21
+ $block->setLayout(Mage::app()->getLayout());
22
+ $block->setTemplate($this->_placeholder->getAttribute('template'));
23
+ $block->setProductId($this->_placeholder->getAttribute('product_id']));
24
+ return $block->toHtml();
25
+ }
26
+
27
+ }
app/code/community/RetentionScience/Waves/Model/Cron.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class RetentionScience_Waves_Model_Cron {
4
+
5
+ public function export() {
6
+
7
+ $event = new Varien_Object();
8
+
9
+ $event->setData(array(
10
+ 'type' => 'batch',
11
+ 'groups' => 'all',
12
+ ));
13
+
14
+ $event->setSource('magento_cron');
15
+
16
+ Mage::dispatchEvent('waves_init_export', array(
17
+ 'event' => $event,
18
+ ));
19
+
20
+ }
21
+
22
+ }
app/code/community/RetentionScience/Waves/Model/Export/Abstract.php ADDED
@@ -0,0 +1,269 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ abstract class RetentionScience_Waves_Model_Export_Abstract {
4
+
5
+ protected $_resource;
6
+
7
+ protected $_readConnection;
8
+
9
+ protected $_eavConfig;
10
+
11
+ protected $_eavAttributes = array();
12
+
13
+ protected $_exportedFields = array();
14
+
15
+ protected $_data = array();
16
+
17
+ protected $_start;
18
+
19
+ protected $_limit = 100;
20
+
21
+ protected $_totalRecords;
22
+
23
+ protected $_processedRecords;
24
+
25
+ protected $_entityIds;
26
+
27
+ protected $_timestamp;
28
+
29
+ protected $_bulkFile;
30
+
31
+ protected $_store_id = 0;
32
+
33
+ protected $_idsToProcess;
34
+
35
+ public function setIdsToProcess($ids) {
36
+ $this->_idsToProcess = $ids;
37
+ }
38
+
39
+ protected function getResource() {
40
+ if(is_null($this->_resource)) {
41
+ $this->_resource = Mage::getSingleton('core/resource');
42
+ }
43
+ return $this->_resource;
44
+ }
45
+
46
+ protected function getReadConnection() {
47
+ if(is_null($this->_readConnection)) {
48
+ $this->_readConnection = $this->getResource()->getConnection('core_read');
49
+ }
50
+ return $this->_readConnection;
51
+ }
52
+
53
+ protected function getTableName($entity) {
54
+ return $this->getResource()->getTableName($entity);
55
+ }
56
+
57
+ public function getBulkFile() {
58
+ if(is_null($this->_bulkFile)) {
59
+ $this->_bulkFile = Mage::getBaseDir('tmp') . DIRECTORY_SEPARATOR . 'rs_bulk_' . $this->_bulkUploadFile . '_' . $this->_timestamp . '.bulk';
60
+ }
61
+ return $this->_bulkFile;
62
+ }
63
+
64
+ public function getExportModelTitle() {
65
+ return $this->_bulkUploadFile;
66
+ }
67
+
68
+ public function getProcessedRecords() {
69
+ return $this->_processedRecords;
70
+ }
71
+
72
+ public function getTotalRecordsCalculated() {
73
+ return $this->_totalRecords;
74
+ }
75
+
76
+ protected function getEavConfig() {
77
+ if(is_null($this->_eavConfig)) {
78
+ $this->_eavConfig = Mage::getSingleton('eav/config');
79
+ }
80
+ return $this->_eavConfig;
81
+ }
82
+
83
+ protected function getEavAttribute($entity, $attribute) {
84
+ if(! isset($this->_eavAttributes[$entity . '_' . $attribute])) {
85
+ $this->_eavAttributes[$entity . '_' . $attribute] = $this->getEavConfig()->getAttribute($entity, $attribute);
86
+ }
87
+ return $this->_eavAttributes[$entity . '_' . $attribute];
88
+ }
89
+
90
+ protected function getAttributeData($entity, $attribute, $entityIdField = NULL, $useStore = TRUE) {
91
+ $attribute = $this->getEavAttribute($entity, $attribute);
92
+ if($attribute->getAttributeId()) {
93
+ $backendTable = $attribute->getBackendTable();
94
+ if(! empty($entityIdField)) {
95
+ $_entityIds = array();
96
+ $_mapIds = array();
97
+ if(! empty($this->_data)) {
98
+ foreach($this->_data AS $record) {
99
+ if(! empty($record[$entityIdField])) {
100
+ $_entityIds[] = $record[$entityIdField];
101
+ $_mapIds[$record[$entityIdField]] = $record['entity_id'];
102
+ }
103
+ }
104
+ if(! empty($_entityIds)) {
105
+ if($useStore) {
106
+ $attributeData = $this->getReadConnection()->fetchAll(
107
+ ' SELECT
108
+ `default_value`.`entity_id` AS `' . $entityIdField . '`,
109
+ IF(`store_value`.`value` IS NULL, `default_value`.`value`, `store_value`.`value`) AS `value`
110
+ FROM
111
+ `' . $backendTable . '` AS `default_value`
112
+ LEFT OUTER JOIN
113
+ `' . $backendTable . '` AS `store_value`
114
+ ON
115
+ `store_value`.`entity_id` = `default_value`.`entity_id` AND
116
+ `store_value`.`attribute_id` = `default_value`.`attribute_id` AND
117
+ `store_value`.`store_id` = ' . $this->getStoreId() . '
118
+ WHERE
119
+ `default_value`.`attribute_id` = ' . $attribute->getAttributeId() . ' AND
120
+ `default_value`.`entity_id` IN (' . implode(', ', $_entityIds) . ') AND
121
+ `default_value`.`store_id` = 0
122
+ ');
123
+ } else {
124
+ $attributeData = $this->getReadConnection()->fetchAll(
125
+ ' SELECT
126
+ `default_value`.`entity_id` AS `' . $entityIdField . '`,
127
+ `default_value`.`value`
128
+ FROM
129
+ `' . $backendTable . '` AS `default_value`
130
+ WHERE
131
+ `default_value`.`attribute_id` = ' . $attribute->getAttributeId() . ' AND
132
+ `default_value`.`entity_id` IN (' . implode(', ', $_entityIds) . ')
133
+ ');
134
+ }
135
+ if(! empty($attributeData)) {
136
+ foreach($attributeData AS & $data) {
137
+ $dataAttributeId = $data[$entityIdField];
138
+ $entityId = $_mapIds[$dataAttributeId];
139
+ $data['entity_id'] = $entityId;
140
+ }
141
+ }
142
+ return $attributeData;
143
+ }
144
+ }
145
+ } else {
146
+ if($useStore) {
147
+ return $this->getReadConnection()->fetchAll(' SELECT
148
+ `default_value`.`entity_id`,
149
+ IF(`store_value`.`value` IS NULL, `default_value`.`value`, `store_value`.`value`) AS `value`
150
+ FROM
151
+ `' . $backendTable . '` AS `default_value`
152
+ LEFT OUTER JOIN
153
+ `' . $backendTable . '` AS `store_value`
154
+ ON
155
+ `store_value`.`entity_id` = `default_value`.`entity_id` AND
156
+ `store_value`.`attribute_id` = `default_value`.`attribute_id` AND
157
+ `store_value`.`store_id` = ' . $this->getStoreId() . '
158
+ WHERE
159
+ `default_value`.`attribute_id` = ' . $attribute->getAttributeId() . ' AND
160
+ `default_value`.`entity_id` IN (' . implode(', ', $this->_entityIds) . ') AND
161
+ `default_value`.`store_id` = 0
162
+ ');
163
+ } else {
164
+ return $this->getReadConnection()->fetchAll(' SELECT
165
+ `default_value`.`entity_id`,
166
+ `default_value`.`value`
167
+ FROM
168
+ `' . $backendTable . '` AS `default_value`
169
+ WHERE
170
+ `default_value`.`attribute_id` = ' . $attribute->getAttributeId() . ' AND
171
+ `default_value`.`entity_id` IN (' . implode(', ', $this->_entityIds) . ')
172
+ ');
173
+ }
174
+ }
175
+ }
176
+ }
177
+
178
+ protected function fillAttributeData($entity, $attribute, $entityIdField = NULL, $getLabel = TRUE, $useStore = TRUE) {
179
+ $data = $this->getAttributeData($entity, $attribute, $entityIdField, $useStore);
180
+ if(! empty($data)) {
181
+ foreach($data AS $record) {
182
+ if($this->getEavAttribute($entity, $attribute)->getFrontendInput() === 'select' AND $getLabel) {
183
+ $this->_data[$record['entity_id']][$attribute] = $this
184
+ ->getEavAttribute($entity, $attribute)
185
+ ->getSource()
186
+ ->getOptionText($record['value']);
187
+ } else {
188
+ $this->_data[$record['entity_id']][$attribute] = $record['value'];
189
+ }
190
+ }
191
+ }
192
+ }
193
+
194
+ protected function fillTableData($tableName, $key, array $fields, $where = '') {
195
+ $tableData = $this->getReadConnection()->fetchAll(
196
+ 'SELECT `' . $key . '` AS `entity_id`, `' . implode('`, `', array_keys($fields)) . '` FROM `' . $tableName . '`' .
197
+ ' WHERE `' . $key . '` IN (' . implode(', ', $this->_entityIds) . ')' . ($where ? ' AND ' . $where : '')
198
+ );
199
+ if(! empty($tableData)) {
200
+ foreach($tableData AS $data) {
201
+ foreach($fields AS $key => $alias) {
202
+ $this->_data[$data['entity_id']][$alias] = $data[$key];
203
+ }
204
+ }
205
+ }
206
+ }
207
+
208
+ public function run($timestamp) {
209
+ $time = time();
210
+ $this->_timestamp = $timestamp;
211
+ $this->_bulkFile = NULL;
212
+ $this->_totalRecords = $this->getTotalRecords();
213
+ $this->_start = 0;
214
+ $this->_processedRecords = 0;
215
+ Mage::getSingleton('waves/connection_awsCloudWatch')->logMessage("run called for file " . $this->getBulkFile() . " TotalRecords " . $this->_totalRecords);
216
+
217
+ while($this->_start < $this->_totalRecords) {
218
+
219
+ $this->getEntityData();
220
+ $this->getAdditionalData();
221
+ $this->exportFields();
222
+ $this->cleanupData();
223
+
224
+ $this->_start += $this->_limit;
225
+ }
226
+ $this->_idsToProcess = NULL;
227
+ }
228
+
229
+ protected function exportFields() {
230
+ if(! empty($this->_exportedFields) AND ! empty($this->_data)) {
231
+ foreach($this->_data AS $data) {
232
+ $record = array();
233
+ foreach($this->_exportedFields AS $field) {
234
+ $record[$field] = $this->{'get' . str_replace('_', '', $field)}($data);
235
+ }
236
+ $this->writeBulk($this->getPrimaryKey($data), $record);
237
+ }
238
+ }
239
+ }
240
+
241
+ protected function writeBulk($key, $record) {
242
+ // $record['record_id'] = $key;
243
+ $msg = json_encode($record) . "\n";
244
+ file_put_contents($this->getBulkFile(), $msg, FILE_APPEND);
245
+ }
246
+
247
+ protected function cleanupData() {
248
+ $this->_data = NULL;
249
+ gc_collect_cycles();
250
+ }
251
+
252
+ public function getStoreId() {
253
+ return $this->_store_id;
254
+ }
255
+
256
+ public function setStoreId($storeId) {
257
+ $this->_store_id = (int) $storeId;
258
+ return $this;
259
+ }
260
+
261
+ abstract protected function getEntityData();
262
+
263
+ abstract protected function getAdditionalData();
264
+
265
+ abstract protected function getTotalRecords();
266
+
267
+ abstract protected function getPrimaryKey($data);
268
+
269
+ }
app/code/community/RetentionScience/Waves/Model/Export/Category.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class RetentionScience_Waves_Model_Export_Category extends RetentionScience_Waves_Model_Export_Abstract {
4
+
5
+ protected $_limit = 1000;
6
+
7
+ protected $_exportedFields = array(
8
+ 'record_id',
9
+ 'name',
10
+ 'description',
11
+ 'parent_record_id',
12
+ );
13
+
14
+ protected $_bulkUploadFile = 'categories';
15
+
16
+ protected function getEntityData() {
17
+ $tableName = $this->getTableName('catalog/category');
18
+ $query = 'SELECT `entity_id`, `parent_id` FROM `' . $tableName . '`' . (empty($this->_idsToProcess) ? '' : ' WHERE `entity_id` IN (' . implode(', ', $this->_idsToProcess) . ')') . ' ORDER BY `level` ASC LIMIT ' . $this->_start . ', ' . $this->_limit;
19
+ $this->_data = $this->getReadConnection()->fetchAll($query);
20
+ $this->_processedRecords += count($this->_data);
21
+ $this->_entityIds = array();
22
+ if(! empty($this->_data)) {
23
+ $sortedData = array();
24
+ foreach($this->_data AS $record) {
25
+ $this->_entityIds[] = $record['entity_id'];
26
+ $sortedData[$record['entity_id']] = $record;
27
+ }
28
+ $this->_data = $sortedData;
29
+ }
30
+ }
31
+
32
+ protected function getAdditionalData() {
33
+ /* CATEGORY DATA */
34
+ $this->fillAttributeData('catalog_category', 'name');
35
+ $this->fillAttributeData('catalog_category', 'description');
36
+ }
37
+
38
+ protected function getTotalRecords() {
39
+ return (int) $this
40
+ ->getReadConnection()
41
+ ->fetchOne('SELECT COUNT(*) FROM `' . $this->getTableName('catalog/category') . '`' . (empty($this->_idsToProcess) ? '' : ' WHERE `entity_id` IN (' . implode(', ', $this->_idsToProcess) . ')'));
42
+ }
43
+
44
+ /* Fields */
45
+
46
+ protected function getPrimaryKey($data) {
47
+ return $data['entity_id'];
48
+ }
49
+
50
+ protected function getRecordId($data) {
51
+ return $this->getPrimaryKey($data);
52
+ }
53
+
54
+ protected function getName($data) {
55
+ return isset($data['name']) ? $data['name'] : '';
56
+ }
57
+
58
+ protected function getDescription($data) {
59
+ return isset($data['description']) ? $data['description'] : '';
60
+ }
61
+
62
+ protected function getParentRecordId($data) {
63
+ return isset($data['parent_id']) ? $data['parent_id'] : NULL;
64
+ }
65
+
66
+ }
app/code/community/RetentionScience/Waves/Model/Export/Customer.php ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class RetentionScience_Waves_Model_Export_Customer extends RetentionScience_Waves_Model_Export_Abstract {
4
+
5
+ protected $_limit = 1000;
6
+
7
+ protected $_exportedFields = array(
8
+ 'record_id',
9
+ 'email',
10
+ 'full_name',
11
+ 'address1',
12
+ 'city',
13
+ 'state',
14
+ 'zip',
15
+ 'country',
16
+ 'phone',
17
+ 'birth_date',
18
+ 'gender',
19
+ 'account_created_on',
20
+ 'last_logon_at',
21
+ );
22
+
23
+ protected $_bulkUploadFile = 'users';
24
+
25
+ protected $_exportedIds = array();
26
+
27
+ public function run($timestamp) {
28
+ parent::run($timestamp);
29
+ $exportModel = Mage::getModel('waves/export_order_customer');
30
+ $exportModel->setStoreId($this->getStoreId());
31
+ $exportModel->setExportedPks($this->_exportedIds);
32
+ $exportModel->run($timestamp);
33
+ }
34
+
35
+ protected function getEntityData() {
36
+ $tableName = $this->getTableName('customer/entity');
37
+ $query = 'SELECT `entity_id`, `email`, `created_at`, `updated_at` FROM `' . $tableName . '`' . (empty($this->_idsToProcess) ? '' : ' WHERE `entity_id` IN (' . implode(', ', $this->_idsToProcess) . ')') . ' LIMIT ' . $this->_start . ', ' . $this->_limit;
38
+ $this->_data = $this->getReadConnection()->fetchAll($query);
39
+ $this->_processedRecords += count($this->_data);
40
+ $this->_entityIds = array();
41
+ if(! empty($this->_data)) {
42
+ $sortedData = array();
43
+ foreach($this->_data AS $record) {
44
+ $this->_entityIds[] = $record['entity_id'];
45
+ $sortedData[$record['entity_id']] = $record;
46
+ }
47
+ $this->_data = $sortedData;
48
+ }
49
+ }
50
+
51
+ protected function getAdditionalData() {
52
+ /* CUSTOMER DATA */
53
+ $this->fillAttributeData('customer', 'firstname', NULL, TRUE, FALSE);
54
+ $this->fillAttributeData('customer', 'lastname', NULL, TRUE, FALSE);
55
+ $this->fillAttributeData('customer', 'prefix', NULL, TRUE, FALSE);
56
+ $this->fillAttributeData('customer', 'middlename', NULL, TRUE, FALSE);
57
+ $this->fillAttributeData('customer', 'suffix', NULL, TRUE, FALSE);
58
+ $this->fillAttributeData('customer', 'default_billing', NULL, TRUE, FALSE);
59
+ $this->fillAttributeData('customer', 'dob', NULL, TRUE, FALSE);
60
+ $this->fillAttributeData('customer', 'gender', NULL, TRUE, FALSE);
61
+ /* ADDRESS DATA */
62
+ $this->fillAttributeData('customer_address', 'street', 'default_billing', TRUE, FALSE);
63
+ $this->fillAttributeData('customer_address', 'city', 'default_billing', TRUE, FALSE);
64
+ $this->fillAttributeData('customer_address', 'region_id', 'default_billing', TRUE, FALSE);
65
+ $this->fillAttributeData('customer_address', 'postcode', 'default_billing', TRUE, FALSE);
66
+ $this->fillAttributeData('customer_address', 'country_id', 'default_billing', TRUE, FALSE);
67
+ $this->fillAttributeData('customer_address', 'telephone', 'default_billing', TRUE, FALSE);
68
+ }
69
+
70
+ protected function getTotalRecords() {
71
+ return (int) $this
72
+ ->getReadConnection()
73
+ ->fetchOne('SELECT COUNT(*) FROM `' . $this->getTableName('customer/entity') . '`' . (empty($this->_idsToProcess) ? '' : ' WHERE `entity_id` IN (' . implode(', ', $this->_idsToProcess) . ')'));
74
+ }
75
+
76
+ /* Fields */
77
+
78
+ protected function getPrimaryKey($data) {
79
+ $pk = md5(trim(strtolower($data['email'])));
80
+ $this->_exportedIds[$pk] = TRUE;
81
+ return $pk;
82
+ }
83
+
84
+ protected function getRecordId($data) {
85
+ return $this->getPrimaryKey($data);
86
+ }
87
+
88
+ protected function getEmail($data) {
89
+ return isset($data['email']) ? $data['email'] : '';
90
+ }
91
+
92
+ protected function getFullname($data) {
93
+ $name = '';
94
+ if ($this->getEavAttribute('customer', 'prefix')->getIsVisible() && isset($data['prefix'])) {
95
+ $name .= $data['prefix'] . ' ';
96
+ }
97
+ $name .= isset($data['firstname']) ? $data['firstname'] : '';
98
+ if ($this->getEavAttribute('customer', 'middlename')->getIsVisible() && isset($data['middlename'])) {
99
+ $name .= ' ' . $data['middlename'];
100
+ }
101
+ $name .= isset($data['lastname']) ? ' ' . $data['lastname'] : '';
102
+ if ($this->getEavAttribute('customer', 'suffix')->getIsVisible() && isset($data['suffix'])) {
103
+ $name .= ' ' . $data['suffix'];
104
+ }
105
+ return $name;
106
+ }
107
+
108
+ protected function getAddress1($data) {
109
+ return isset($data['street']) ? str_replace("\n", ' ', $data['street']) : '';
110
+ }
111
+
112
+ protected function getCity($data) {
113
+ return isset($data['city']) ? $data['city'] : '';
114
+ }
115
+
116
+ protected function getState($data) {
117
+ return isset($data['region_id']) ? Mage::helper('waves')->getRegionNameById($data['region_id']) : '';
118
+ }
119
+
120
+ protected function getZip($data) {
121
+ return isset($data['postcode']) ? $data['postcode'] : '';
122
+ }
123
+
124
+ protected function getCountry($data) {
125
+ if(isset($data['country_id'])) {
126
+ // shorten to US
127
+ if ($data['country_id'] == 'United States') {
128
+ return 'US';
129
+ } elseif ($data['country_id'] == 'United Kingdom') {
130
+ return 'UK';
131
+ } else {
132
+ return $data['country_id'];
133
+ }
134
+
135
+ }
136
+ return '';
137
+ }
138
+
139
+ protected function getPhone($data) {
140
+ return isset($data['telephone']) ? $data['telephone'] : '';
141
+ }
142
+
143
+ // @return yyyy-mm-dd
144
+ protected function getBirthdate($data) {
145
+ if(isset($data['dob'])) {
146
+ $birthDateTime = explode(' ', $data['dob']);
147
+ return $birthDateTime[0];
148
+ }
149
+ return '';
150
+ }
151
+
152
+ protected function getGender($data) {
153
+ if (isset($data['gender'])) {
154
+ $gender = strtolower($data['gender']);
155
+ if ($gender == 'female') {
156
+ return 'f';
157
+ } elseif ($gender == 'male') {
158
+ return 'm';
159
+ } else {
160
+ return $gender;
161
+ }
162
+ }
163
+ return '';
164
+ }
165
+
166
+ protected function getAccountCreatedOn($data) {
167
+ return date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(strtotime($data['created_at'])));
168
+ }
169
+
170
+ protected function getLastLogOnAt($data) {
171
+ return date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(strtotime($data['updated_at'])));
172
+ }
173
+
174
+ }
app/code/community/RetentionScience/Waves/Model/Export/Order.php ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class RetentionScience_Waves_Model_Export_Order extends RetentionScience_Waves_Model_Export_Abstract {
4
+
5
+ protected $_limit = 1000;
6
+
7
+ protected $_exportedFields = array(
8
+ 'record_id',
9
+ 'user_record_id',
10
+ 'total_price',
11
+ 'discount_amount',
12
+ 'shipping_amount',
13
+ 'tax_amount',
14
+ 'ordered_at',
15
+ 'payment_method',
16
+ 'order_status',
17
+ );
18
+
19
+ protected $_bulkUploadFile = 'orders';
20
+
21
+ protected function getEntityData() {
22
+ $tableName = $this->getTableName('sales/order');
23
+ $query = 'SELECT `entity_id`, `state`, `customer_email`, `base_subtotal`, `base_discount_amount`, `shipping_amount`, `base_tax_amount`, `created_at` FROM `' . $tableName . '`' . (empty($this->_idsToProcess) ? '' : ' WHERE `entity_id` IN (' . implode(', ', $this->_idsToProcess) . ')') . ' ORDER BY `entity_id` ASC LIMIT ' . $this->_start . ', ' . $this->_limit;
24
+ $this->_data = $this->getReadConnection()->fetchAll($query);
25
+ $this->_processedRecords += count($this->_data);
26
+ $this->_entityIds = array();
27
+ if(! empty($this->_data)) {
28
+ $sortedData = array();
29
+ foreach($this->_data AS $record) {
30
+ $this->_entityIds[] = $record['entity_id'];
31
+ $sortedData[$record['entity_id']] = $record;
32
+ }
33
+ $this->_data = $sortedData;
34
+ }
35
+ }
36
+
37
+ protected function getAdditionalData() {
38
+ /* Get Payment Method Code */
39
+ $this->fillTableData($this->getTableName('sales/order_payment'), 'parent_id', array(
40
+ 'method' => 'payment_method',
41
+ ));
42
+ }
43
+
44
+ protected function getTotalRecords() {
45
+ return (int) $this
46
+ ->getReadConnection()
47
+ ->fetchOne('SELECT COUNT(*) FROM `' . $this->getTableName('sales/order') . '`' . (empty($this->_idsToProcess) ? '' : ' WHERE `entity_id` IN (' . implode(', ', $this->_idsToProcess) . ')'));
48
+ }
49
+
50
+ /* Fields */
51
+
52
+ protected function getPrimaryKey($data) {
53
+ return $data['entity_id'];
54
+ }
55
+
56
+ protected function getRecordId($data) {
57
+ return $this->getPrimaryKey($data);
58
+ }
59
+
60
+ protected function getUserRecordId($data) {
61
+ return md5(trim(strtolower($data['customer_email'])));
62
+ }
63
+
64
+ protected function getTotalPrice($data) {
65
+ return number_format($data['base_subtotal'], 2, '.', '');
66
+ }
67
+
68
+ protected function getDiscountAmount($data) {
69
+ return number_format($data['base_discount_amount'], 2, '.', '');
70
+ }
71
+
72
+ protected function getShippingAmount($data) {
73
+ return number_format($data['shipping_amount'], 2, '.', '');
74
+ }
75
+
76
+ protected function getTaxAmount($data) {
77
+ return number_format($data['base_tax_amount'], 2, '.', '');
78
+ }
79
+
80
+ protected function getOrderedAt($data) {
81
+ return date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(strtotime($data['created_at'])));
82
+ }
83
+
84
+ protected function getPaymentMethod($data) {
85
+ if(isset($data['payment_method'])) {
86
+ $instance = Mage::helper('payment')->getMethodInstance($data['payment_method']);
87
+ if($instance) {
88
+ return $instance->getTitle();
89
+ }
90
+ }
91
+ }
92
+
93
+ protected function getOrderStatus($data) {
94
+ if(isset($data['state'])) {
95
+ return $data['state'];
96
+ } else {
97
+ return '';
98
+ }
99
+ }
100
+
101
+ }
app/code/community/RetentionScience/Waves/Model/Export/Order/Customer.php ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class RetentionScience_Waves_Model_Export_Order_Customer extends RetentionScience_Waves_Model_Export_Customer {
4
+
5
+ protected $_limit = 1000;
6
+
7
+ protected $_exportedFields = array(
8
+ 'record_id',
9
+ 'email',
10
+ 'full_name',
11
+ 'address1',
12
+ 'city',
13
+ 'state',
14
+ 'zip',
15
+ 'country',
16
+ 'phone',
17
+ 'birth_date',
18
+ 'gender',
19
+ 'account_created_on',
20
+ 'last_logon_at',
21
+ );
22
+
23
+ protected $_bulkUploadFile = 'users';
24
+
25
+ protected $_exportedPks = array();
26
+
27
+ public function setExportedPks($exportedPks) {
28
+ $this->_exportedPks = $exportedPks;
29
+ }
30
+
31
+ protected function exportFields() {
32
+ if(! empty($this->_exportedFields) AND ! empty($this->_data)) {
33
+ foreach($this->_data AS $data) {
34
+ $pk = $this->getPrimaryKey($data);
35
+ if(isset($this->_exportedPks[$pk])) {
36
+ continue;
37
+ }
38
+ $record = array();
39
+ foreach($this->_exportedFields AS $field) {
40
+ $record[$field] = $this->{'get' . str_replace('_', '', $field)}($data);
41
+ }
42
+ $this->writeBulk($pk, $record);
43
+ }
44
+ }
45
+ }
46
+
47
+ public function run($timestamp) {
48
+ RetentionScience_Waves_Model_Export_Abstract::run($timestamp);
49
+ }
50
+
51
+ protected function getEntityData() {
52
+ $tableName = $this->getTableName('sales/order');
53
+ $query = 'SELECT `entity_id`, `customer_email` AS `email`, `customer_firstname` AS `firstname`, `customer_lastname` AS `lastname`, `created_at` FROM `' . $tableName . '` WHERE `customer_is_guest` = 1' . (empty($this->_idsToProcess) ? '' : ' AND `entity_id` IN (' . implode(', ', $this->_idsToProcess) . ')') . ' LIMIT ' . $this->_start . ', ' . $this->_limit;
54
+ $this->_data = $this->getReadConnection()->fetchAll($query);
55
+ $this->_processedRecords += count($this->_data);
56
+ $this->_entityIds = array();
57
+ if(! empty($this->_data)) {
58
+ $sortedData = array();
59
+ foreach($this->_data AS $record) {
60
+ $this->_entityIds[] = $record['entity_id'];
61
+ $sortedData[$record['entity_id']] = $record;
62
+ }
63
+ $this->_data = $sortedData;
64
+ }
65
+ }
66
+
67
+ protected function getAdditionalData() {
68
+ /* Address Data */
69
+ $this->fillTableData($this->getTableName('sales/order_address'), 'parent_id', array(
70
+ 'street' => 'street',
71
+ 'city' => 'city',
72
+ 'region_id' => 'region_id',
73
+ 'postcode' => 'postcode',
74
+ 'country_id' => 'country_id',
75
+ 'telephone' => 'telephone',
76
+ ), '`address_type` = "billing"');
77
+ }
78
+
79
+ protected function getTotalRecords() {
80
+ return (int) $this
81
+ ->getReadConnection()
82
+ ->fetchOne('SELECT COUNT(*) FROM `' . $this->getTableName('sales/order') . '` WHERE `customer_is_guest` = 1' . (empty($this->_idsToProcess) ? '' : ' WHERE `entity_id` IN (' . implode(', ', $this->_idsToProcess) . ')'));
83
+ }
84
+
85
+ protected function getLastLogOnAt($data) {
86
+ return date("Y-m-d", Mage::getModel('core/date')->timestamp(strtotime($data['created_at'])));
87
+ }
88
+
89
+ protected function getPrimaryKey($data) {
90
+ return md5(trim(strtolower($data['email'])));
91
+ }
92
+
93
+ }
app/code/community/RetentionScience/Waves/Model/Export/Order/Items.php ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class RetentionScience_Waves_Model_Export_Order_Items extends RetentionScience_Waves_Model_Export_Customer {
4
+
5
+ protected $_limit = 1000;
6
+
7
+ protected $_exportedFields = array(
8
+ 'order_record_id',
9
+ 'item_record_id',
10
+ 'name',
11
+ 'quantity',
12
+ 'price',
13
+ 'final_price',
14
+ 'attribute_1',
15
+ 'categories',
16
+ );
17
+
18
+ protected $_bulkUploadFile = 'order_items';
19
+
20
+ protected function getEntityData() {
21
+ $tableName = $this->getTableName('sales/order_item');
22
+ $query = 'SELECT `item_id` AS `entity_id`, `order_id` AS `order_record_id`, `product_id`, `name`, `qty_ordered`, `price`, `sku` FROM `' . $tableName . '`' . (empty($this->_idsToProcess) ? '' : ' WHERE `entity_id` IN (' . implode(', ', $this->_idsToProcess) . ')') . ' ORDER BY `item_id` ASC LIMIT ' . $this->_start . ', ' . $this->_limit;
23
+ $this->_data = $this->getReadConnection()->fetchAll($query);
24
+ $this->_processedRecords += count($this->_data);
25
+ $this->_entityIds = array();
26
+ if(! empty($this->_data)) {
27
+ $sortedData = array();
28
+ foreach($this->_data AS $record) {
29
+ $this->_entityIds[] = $record['entity_id'];
30
+ $sortedData[$record['entity_id']] = $record;
31
+ }
32
+ $this->_data = $sortedData;
33
+ }
34
+ }
35
+
36
+ protected function getAdditionalData() {
37
+ $this->fillProductCategories();
38
+ }
39
+
40
+ protected function fillProductCategories() {
41
+ if(empty($this->_entityIds)) {
42
+ return;
43
+ }
44
+ // Add categories to products
45
+ $products = array();
46
+ $productIds = array();
47
+ if(! empty($this->_data)) {
48
+ foreach($this->_data AS $row) {
49
+ $productId = $row['product_id'];
50
+ if(! in_array($productId, $productIds)) {
51
+ $productIds[] = $productId;
52
+ }
53
+ if(! isset($products[$productId])) {
54
+ $products[$productId] = array();
55
+ }
56
+ }
57
+ }
58
+ if(! empty($productIds)) {
59
+ $categoryProductTable = $this->getTableName('catalog/category_product');
60
+ $cats = $this->getReadConnection()->fetchAll('
61
+ SELECT `category_id`, `product_id` AS `entity_id` FROM `' . $categoryProductTable . '`
62
+ WHERE `product_id` IN (' . implode(', ', $productIds) . ') ORDER BY `position` ASC
63
+ ');
64
+ if(! empty($cats)) {
65
+ foreach($cats AS $cat) {
66
+ $entityId = $cat['entity_id'];
67
+ $categoryId = $cat['category_id'];
68
+ $products[$entityId][] = $categoryId;
69
+ }
70
+ }
71
+ }
72
+ // Fill data
73
+ if(! empty($this->_data)) {
74
+ foreach($this->_data AS $row) {
75
+ $entityId = $row['entity_id'];
76
+ $productId = $row['product_id'];
77
+ if(isset($products[$productId])) {
78
+ $this->_data[$entityId]['categories'] = $products[$productId];
79
+ }
80
+ }
81
+ }
82
+ }
83
+
84
+ protected function getTotalRecords() {
85
+ return (int) $this
86
+ ->getReadConnection()
87
+ ->fetchOne('SELECT COUNT(*) FROM `' . $this->getTableName('sales/order_item') . '`' . (empty($this->_idsToProcess) ? '' : ' WHERE `entity_id` IN (' . implode(', ', $this->_idsToProcess) . ')'));
88
+ }
89
+
90
+ /* Fields */
91
+
92
+ protected function getPrimaryKey($data) {
93
+ return $data['entity_id'];
94
+ }
95
+
96
+ protected function getOrderRecordId($data) {
97
+ return $data['order_record_id'];
98
+ }
99
+
100
+ protected function getItemRecordId($data) {
101
+ return $this->getPrimaryKey($data);
102
+ }
103
+
104
+ protected function getName($data) {
105
+ return $data['name'];
106
+ }
107
+
108
+ protected function getQuantity($data) {
109
+ return (int) $data['qty_ordered'];
110
+ }
111
+
112
+ protected function getPrice($data) {
113
+ return number_format($data['price'], 2, '.', '');
114
+ }
115
+
116
+ protected function getFinalPrice($data) {
117
+ return number_format($data['price'] * $data['qty_ordered'], 2, '.', '');
118
+ }
119
+
120
+ protected function getAttribute1($data) {
121
+ return $data['sku'];
122
+ }
123
+
124
+ protected function getCategories($data) {
125
+ if(isset($data['categories'])) {
126
+ return implode(',', $data['categories']);
127
+ } else {
128
+ return '';
129
+ }
130
+ }
131
+
132
+ }
app/code/community/RetentionScience/Waves/Model/Export/Product.php ADDED
@@ -0,0 +1,362 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class RetentionScience_Waves_Model_Export_Product extends RetentionScience_Waves_Model_Export_Abstract {
4
+
5
+ protected $_limit = 1000;
6
+
7
+ protected $_exportedFields = array(
8
+ 'record_id',
9
+ 'name',
10
+ 'manufacturer',
11
+ 'model',
12
+ 'quantity',
13
+ 'price',
14
+ 'active',
15
+ 'image_list',
16
+ 'item_url',
17
+ 'parent_record_id',
18
+ 'attribute_1',
19
+ 'categories',
20
+ );
21
+
22
+ protected $_bulkUploadFile = 'items';
23
+
24
+ protected $_simpleActive = array();
25
+
26
+ protected $_simpleProducts = array('simple', 'virtual', 'downloadable');
27
+
28
+ protected $_compositeProducts = array('configurable', 'grouped', 'bundle');
29
+
30
+ protected $_manageStock;
31
+
32
+ protected $_mediaUrl;
33
+
34
+ protected $_productModel;
35
+
36
+ protected $_configurableLinks = array();
37
+
38
+ protected $_groupedLinks = array();
39
+
40
+ protected $_bundleLinks = array();
41
+
42
+ protected $_configurableActive = array();
43
+
44
+ protected $_groupedActive = array();
45
+
46
+ protected $_bundleActive = array();
47
+
48
+ protected function getEntityData() {
49
+ $this->_manageStock = Mage::getStoreConfig(Mage_CatalogInventory_Model_Stock_Item::XML_PATH_MANAGE_STOCK);
50
+ $this->_mediaUrl = Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_MEDIA) . 'catalog/product';
51
+ $this->_productModel = Mage::getModel('catalog/product');
52
+
53
+ $tableName = $this->getTableName('catalog/product');
54
+ $query = 'SELECT `entity_id`, `type_id`, `sku` FROM `' . $tableName . '`' . (empty($this->_idsToProcess) ? '' : ' WHERE `entity_id` IN (' . implode(', ', $this->_idsToProcess) . ')') . '
55
+ ORDER BY FIELD(`type_id`, "simple", "virtual", "downloadable", "configurable", "grouped", "bundle")
56
+ , `entity_id` ASC LIMIT ' . $this->_start . ', ' . $this->_limit;
57
+ $this->_data = $this->getReadConnection()->fetchAll($query);
58
+ $this->_processedRecords += count($this->_data);
59
+ $this->_entityIds = array();
60
+ if(! empty($this->_data)) {
61
+ $sortedData = array();
62
+ foreach($this->_data AS $record) {
63
+ $this->_entityIds[] = $record['entity_id'];
64
+ $sortedData[$record['entity_id']] = $record;
65
+ }
66
+ $this->_data = $sortedData;
67
+ }
68
+ }
69
+
70
+ protected function getAdditionalData() {
71
+ /* PRODUCT DATA */
72
+ $this->fillAttributeData('catalog_product', 'name');
73
+ $this->fillAttributeData('catalog_product', 'manufacturer');
74
+ $this->fillAttributeData('catalog_product', 'price');
75
+ $this->fillAttributeData('catalog_product', 'special_price');
76
+ $this->fillAttributeData('catalog_product', 'image');
77
+ $this->fillAttributeData('catalog_product', 'status', NULL, FALSE);
78
+ $this->fillAttributeData('catalog_product', 'url_key');
79
+ /* STOCK DATA */
80
+ $this->fillTableData($this->getTableName('cataloginventory/stock_item'), 'product_id', array(
81
+ 'qty' => 'stock_qty',
82
+ 'use_config_manage_stock' => 'stock_use_config_manage_stock',
83
+ 'manage_stock' => 'stock_manage_stock',
84
+ 'is_in_stock' => 'stock_is_in_stock',
85
+ ));
86
+ /* Media Gallery */
87
+ $this->fillMediaGallery();
88
+ /* Categories */
89
+ $this->fillCategories();
90
+ /* Configurable Links */
91
+ $this->fillConfigurableLinks();
92
+ /* Grouped Links */
93
+ $this->fillGroupedLInks();
94
+ /* Bundle links */
95
+ $this->fillBundleLinks();
96
+ }
97
+
98
+ protected function fillBundleLinks() {
99
+ if(empty($this->_entityIds)) {
100
+ return;
101
+ }
102
+ $bundleTable = $this->getTableName('bundle/selection');
103
+ $rows = $this->getReadConnection()->fetchAll('
104
+ SELECT `parent_product_id` AS `parent_id`, `product_id` AS `entity_id` FROM `' . $bundleTable . '`
105
+ WHERE `product_id` IN (' . implode(', ', $this->_entityIds) . ')
106
+ ');
107
+ if(! empty($rows)) {
108
+ foreach($rows AS $row) {
109
+ $entityId = $row['entity_id'];
110
+ $parentId = $row['parent_id'];
111
+ $this->_bundleLinks[$entityId] = $parentId;
112
+ }
113
+ }
114
+ }
115
+
116
+ protected function fillGroupedLInks() {
117
+ if(empty($this->_entityIds)) {
118
+ return;
119
+ }
120
+ $linkTable = $this->getTableName('catalog/product_link');
121
+ $rows = $this->getReadConnection()->fetchAll('
122
+ SELECT `linked_product_id` AS `entity_id`, `product_id` AS `parent_id` FROM `' . $linkTable . '`
123
+ WHERE `linked_product_id` IN (' . implode(', ', $this->_entityIds) . ')
124
+ AND `link_type_id` = ' . Mage_Catalog_Model_Product_Link::LINK_TYPE_GROUPED . '
125
+ ');
126
+ if(! empty($rows)) {
127
+ foreach($rows AS $row) {
128
+ $entityId = $row['entity_id'];
129
+ $parentId = $row['parent_id'];
130
+ $this->_groupedLinks[$entityId] = $parentId;
131
+ }
132
+ }
133
+ }
134
+
135
+ protected function fillConfigurableLinks() {
136
+ if(empty($this->_entityIds)) {
137
+ return;
138
+ }
139
+ $configurableLinkTable = $this->getTableName('catalog/product_super_link');
140
+ $rows = $this->getReadConnection()->fetchAll('
141
+ SELECT `product_id` AS `entity_id`, `parent_id` FROM `' . $configurableLinkTable . '`
142
+ WHERE `product_id` IN (' . implode(', ', $this->_entityIds) . ')
143
+ ');
144
+ if(! empty($rows)) {
145
+ foreach($rows AS $row) {
146
+ $entityId = $row['entity_id'];
147
+ $parentId = $row['parent_id'];
148
+ $this->_configurableLinks[$entityId] = $parentId;
149
+ }
150
+ }
151
+ }
152
+
153
+ protected function fillCategories() {
154
+ if(empty($this->_entityIds)) {
155
+ return;
156
+ }
157
+ $categoryProductTable = $this->getTableName('catalog/category_product');
158
+ $rows = $this->getReadConnection()->fetchAll('
159
+ SELECT `category_id`, `product_id` AS `entity_id` FROM `' . $categoryProductTable . '`
160
+ WHERE `product_id` IN (' . implode(', ', $this->_entityIds) . ') ORDER BY `position` ASC
161
+ ');
162
+ if(! empty($rows)) {
163
+ foreach($rows AS $row) {
164
+ $entityId = $row['entity_id'];
165
+ $categoryId = $row['category_id'];
166
+ if(! isset($this->_data[$entityId]['categories'])) {
167
+ $this->_data[$entityId]['categories'] = array();
168
+ }
169
+ $this->_data[$entityId]['categories'][] = $categoryId;
170
+ }
171
+ }
172
+ }
173
+
174
+ protected function fillMediaGallery() {
175
+ if(empty($this->_entityIds)) {
176
+ return;
177
+ }
178
+ $mediaGalleryTable = $this->getTableName('catalog/product_attribute_media_gallery');
179
+ $mediaGalleryValueTable = $this->getTableName('catalog/product_attribute_media_gallery_value');
180
+ $query = 'SELECT mgt.`entity_id`, mgt.`value` FROM `' . $mediaGalleryTable . '` AS mgt '
181
+ . 'INNER JOIN `' . $mediaGalleryValueTable . '` AS mgvt ON mgt.`value_id` = mgvt.`value_id` '
182
+ . 'WHERE mgt.`entity_id` IN (' . implode(', ', $this->_entityIds) . ') AND mgvt.`store_id` = ' . $this->_store_id . ' AND mgvt.`disabled` = 0';
183
+ $results = $this->getReadConnection()->fetchAll($query);
184
+ if(! empty($results)) {
185
+ foreach($results AS $row) {
186
+ $entityId = $row['entity_id'];
187
+ $image = $row['value'];
188
+ if(! isset($this->_data[$entityId]['gallery'])) {
189
+ $this->_data[$entityId]['gallery'] = array();
190
+ }
191
+ $this->_data[$entityId]['gallery'][] = $image;
192
+ }
193
+ }
194
+ }
195
+
196
+ protected function getTotalRecords() {
197
+ return (int) $this
198
+ ->getReadConnection()
199
+ ->fetchOne('SELECT COUNT(*) FROM `' . $this->getTableName('catalog/product') . '`' . (empty($this->_idsToProcess) ? '' : ' WHERE `entity_id` IN (' . implode(', ', $this->_idsToProcess) . ')'));
200
+ }
201
+
202
+ /* Fields */
203
+
204
+ protected function getPrimaryKey($data) {
205
+ return $data['entity_id'];
206
+ }
207
+
208
+ protected function getRecordId($data) {
209
+ return $this->getPrimaryKey($data);
210
+ }
211
+
212
+ protected function getName($data) {
213
+ return isset($data['name']) ? $data['name'] : '';
214
+ }
215
+
216
+ protected function getManufacturer($data) {
217
+ return isset($data['manufacturer']) ? $data['manufacturer'] : '';
218
+ }
219
+
220
+ protected function getModel($data) {
221
+ return isset($data['sku']) ? $data['sku'] : '';
222
+ }
223
+
224
+ protected function getQuantity($data) {
225
+ return isset($data['stock_qty']) ? $data['stock_qty'] : 0;
226
+ }
227
+
228
+ // @TODO: Ask Andrew about special price date range
229
+ protected function getPrice($data) {
230
+ return isset($data['special_price']) ? $data['special_price'] : (isset($data['price']) ? $data['price'] : '');
231
+ }
232
+
233
+ protected function getActive($data) {
234
+ $active = 1;
235
+ $entityId = $data['entity_id'];
236
+ if(isset($data['status'])) {
237
+ if($data['status'] != Mage_Catalog_Model_Product_Status::STATUS_ENABLED) {
238
+ $active = 0;
239
+ }
240
+ } else {
241
+ $active = 0;
242
+ }
243
+ if($active) {
244
+ if(in_array($data['type_id'], $this->_compositeProducts)) {
245
+ switch($data['type_id']) {
246
+ case 'configurable':
247
+ return isset($this->_configurableActive[$entityId]) ? $this->_configurableActive[$entityId] : 0;
248
+ break;
249
+ case 'grouped':
250
+ return isset($this->_groupedActive[$entityId]) ? $this->_groupedActive[$entityId] : 0;
251
+ break;
252
+ case 'bundle':
253
+ return isset($this->_bundleActive[$entityId]) ? $this->_bundleActive[$entityId] : 0;
254
+ break;
255
+ }
256
+ return $active;
257
+ } else {
258
+ // If no data - product is not salable
259
+ if(! isset($data['stock_use_config_manage_stock'])) {
260
+ if($this->_manageStock) {
261
+ return 0;
262
+ } else {
263
+ return 1;
264
+ }
265
+ }
266
+ // From Mage_CatalogInventory_Model_Resource_Stock
267
+ if(
268
+ ($data['stock_use_config_manage_stock'] == 0 AND $data['stock_manage_stock'] == 1 AND $data['stock_is_in_stock'] == 1)
269
+ OR
270
+ ($data['stock_use_config_manage_stock'] == 0 AND $data['stock_manage_stock'] == 0)
271
+ OR (
272
+ $this->_manageStock ? (
273
+ $data['stock_use_config_manage_stock'] == 1 AND $data['stock_is_in_stock'] == 1
274
+ ) : (
275
+ $data['stock_use_config_manage_stock'] == 1
276
+ )
277
+ )
278
+ ) {
279
+ $active = 1;
280
+ } else {
281
+ $active = 0;
282
+ }
283
+ $this->setIsSimpleActive($data['entity_id'], $active);
284
+ }
285
+ }
286
+ return $active;
287
+ }
288
+
289
+ // space-delimited string of image URLs
290
+ protected function getImageList($data) {
291
+ $imageList = array();
292
+ if(isset($data['image'])) {
293
+ $imageList[] = $this->_mediaUrl . $data['image'];
294
+ }
295
+ if(! empty($data['gallery']) AND is_array($data['gallery'])) {
296
+ foreach($data['gallery'] AS $image) {
297
+ $imageList[] = $this->_mediaUrl . $image;
298
+ }
299
+ }
300
+ return implode(' ', $imageList);
301
+ }
302
+
303
+ protected function getItemUrl($data) {
304
+ Mage::getSingleton('core/url')->setStoreId($this->_store_id);
305
+ Mage::unregister('custom_entry_point');
306
+ Mage::register('custom_entry_point', TRUE);
307
+ $this->_productModel->setData($data);
308
+ return $this->_productModel->getProductUrl();
309
+ }
310
+
311
+ protected function getParentRecordId($data) {
312
+ // In the future, we may choose to include grouped / bundle hierarchy
313
+ $simpleParentIds = TRUE;
314
+ $groupedParentIds = FALSE;
315
+ $bundleParentIds = FALSE;
316
+
317
+ $entityId = $data['entity_id'];
318
+ $parentIds = array();
319
+
320
+ if($simpleParentIds && isset($this->_configurableLinks[$entityId])) {
321
+ $parentIds[] = $this->_configurableLinks[$entityId];
322
+ $isActive = isset($this->_configurableActive[$this->_configurableLinks[$entityId]]) ? $this->_configurableActive[$this->_configurableLinks[$entityId]] : 0;
323
+ $this->_configurableActive[$this->_configurableLinks[$entityId]] = $isActive ? 1 : $this->getIsSimpleActive($entityId);
324
+ }
325
+ if($groupedParentIds && isset($this->_groupedLinks[$entityId])) {
326
+ $parentIds[] = $this->_groupedLinks[$entityId];
327
+ $isActive = isset($this->_groupedActive[$this->_groupedLinks[$entityId]]) ? $this->_groupedActive[$this->_groupedLinks[$entityId]] : 0;
328
+ $this->_groupedActive[$this->_groupedLinks[$entityId]] = $isActive ? 1 : $this->getIsSimpleActive($entityId);
329
+ }
330
+ if($bundleParentIds && isset($this->_bundleLinks[$entityId])) {
331
+ $parentIds[] = $this->_bundleLinks[$entityId];
332
+ $isActive = isset($this->_bundleActive[$this->_bundleLinks[$entityId]]) ? $this->_bundleActive[$this->_bundleLinks[$entityId]] : 0;
333
+ $this->_bundleActive[$this->_bundleLinks[$entityId]] = $isActive ? 1 : $this->getIsSimpleActive($entityId);
334
+ }
335
+ return implode(',', $parentIds);
336
+ }
337
+
338
+ protected function getAttribute1($data) {
339
+ return $data['type_id'];
340
+ }
341
+
342
+ // comma-delimited string of category ids
343
+ protected function getCategories($data) {
344
+ if(isset($data['categories'])) {
345
+ return implode(',', $data['categories']);
346
+ }
347
+ return '';
348
+ }
349
+
350
+ protected function setIsSimpleActive($productId, $active) {
351
+ $this->_simpleActive[$productId] = $active;
352
+ }
353
+
354
+ protected function getIsSimpleActive($productId) {
355
+ if(isset($this->_simpleActive[$productId])) {
356
+ return $this->_simpleActive[$productId];
357
+ } else {
358
+ return 0;
359
+ }
360
+ }
361
+
362
+ }
app/code/community/RetentionScience/Waves/Model/Mysql4/Product/Collection.php DELETED
@@ -1,34 +0,0 @@
1
- <?php
2
- /**
3
- * Magento
4
- *
5
- * NOTICE OF LICENSE
6
- *
7
- * This source file is subject to the Open Software License (OSL 3.0)
8
- * that is bundled with this package in the file LICENSE.txt.
9
- * It is also available through the world-wide-web at this URL:
10
- * http://opensource.org/licenses/osl-3.0.php
11
- * If you did not receive a copy of the license and are unable to
12
- * obtain it through the world-wide-web, please send an email
13
- * to license@magentocommerce.com so we can send you a copy immediately.
14
- *
15
- * DISCLAIMER
16
- *
17
- * Do not edit or add to this file if you wish to upgrade Magento to newer
18
- * versions in the future. If you wish to customize Magento for your
19
- * needs please refer to http://www.magentocommerce.com for more information.
20
- *
21
- * @category Mage
22
- * @package Mage_Eav
23
- * @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com)
24
- * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
- */
26
-
27
-
28
- class RetentionScience_Waves_Model_Mysql4_Product_Collection extends Mage_Catalog_Model_Resource_Product_Collection
29
- {
30
- public function isEnabledFlat()
31
- {
32
- return false;
33
- }
34
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/code/community/RetentionScience/Waves/Model/Observer.php CHANGED
@@ -1,517 +1,411 @@
1
- <?php
2
- include('retention_science_api.php');
3
- $last_processed_order_record_id;
4
- $last_processed_user_entity_id;
5
- $last_processed_product_entity_id;
6
-
7
- // if sendBulkUpload, do not access the RS API for individual records, instead just ouput all entities to a file
8
-
9
- class RetentionScience_Waves_Model_Observer
10
- {
11
- protected $phpBin = 'php';
12
- protected $sendBulkUpload = true;
13
- protected $useBulkCompression = true; // only used if sendBulkUpload==true
14
- protected $removeFileAfterSend = true; // only used if sendBulkUpload==true
15
- protected $logToFile = false;
16
- protected $elementsPerPage = 2000;
17
- protected $apiClient;
18
-
19
- public function getRetentionScienceApiClient(){
20
- if(!$this->apiClient){
21
- $api_user = Mage::getStoreConfig('waves/retentionscience_settings/api_user');
22
- $api_pass = Mage::getStoreConfig('waves/retentionscience_settings/api_pass');
23
- $testmode = Mage::getStoreConfig('waves/retentionscience_settings/testmode');
24
- $this->apiClient = new RetentionScienceApi($api_user, $api_pass, $testmode);
25
- }
26
- return $this->apiClient;
27
- }
28
-
29
- public function getPhpBin(){
30
- $php_bin = Mage::getStoreConfig('waves/rs_sync_advanced/rs_php_bin');
31
- if ($php_bin == NULL){
32
- $php_bin = $this->phpBin;
33
- }
34
- return $php_bin;
35
- }
36
-
37
- public function logToFile(){
38
- return $this->logToFile;
39
- }
40
-
41
- public function sendBulkUpload(){
42
- $send_bulk_upload = Mage::getStoreConfig('waves/rs_sync_advanced/rs_send_bulk_upload');
43
- if ($send_bulk_upload == NULL){
44
- $send_bulk_upload = $this->sendBulkUpload;
45
- }
46
- return $send_bulk_upload;
47
- }
48
-
49
- public function useBulkCompression(){
50
- $use_bulk_compression = Mage::getStoreConfig('waves/rs_sync_advanced/rs_use_bulk_compression');
51
- if ($use_bulk_compression == NULL){
52
- $use_bulk_compression = $this->useBulkCompression;
53
- }
54
- return $use_bulk_compression;
55
- }
56
-
57
- public function elementsPerPage(){
58
- return $this->elementsPerPage;
59
- }
60
-
61
- public function writeToLog($msg, $category){
62
- $msg = $msg . "\n";
63
- $file = dirname(__FILE__) . '/retention_science_'. $category.'.log';
64
- file_put_contents($file, $msg, FILE_APPEND);
65
- }
66
-
67
- public function get_last_processed_order_record_id(){
68
- global $last_processed_order_record_id;
69
- return $last_processed_order_record_id;
70
- }
71
-
72
- public function get_last_processed_user_entity_id(){
73
- global $last_processed_user_entity_id;
74
- return $last_processed_user_entity_id;
75
- }
76
-
77
- public function get_last_processed_product_entity_id(){
78
- global $last_processed_product_entity_id;
79
- return $last_processed_product_entity_id;
80
- }
81
-
82
- public function writeBulkUploadFile($entity_hash, $category, $timestamp){
83
- $tmp_base = Mage::getBaseDir('tmp');
84
-
85
- $msg = json_encode($entity_hash) . "\n";
86
- $file = $tmp_base . '/rs_bulk_'. $category.'_'.$timestamp.'.log';
87
- file_put_contents($file, $msg, FILE_APPEND);
88
- }
89
-
90
- public function sendDataSyncFiles($timestamp) {
91
- $tmp_base = Mage::getBaseDir('tmp');
92
-
93
- $types = array("categories", "items", "users", "orders", "orders_users");
94
- $files = array();
95
- $gzfiles = array();
96
- foreach ($types as $type) {
97
- $file = $tmp_base . '/rs_bulk_'. $type.'_'.$timestamp.'.log';
98
- if (($type == "orders_users") && !file_exists($file)) {
99
- touch($file);
100
- }
101
- if (file_exists($file)) {
102
- $files[$type] = $file;
103
- if ($this->useBulkCompression()) {
104
- $gzfile = $file . ".gz";
105
- $fp = gzopen($gzfile, 'wb');
106
- gzwrite($fp, file_get_contents($file));
107
- gzclose($fp);
108
- $gzfiles[$type] = $gzfile;
109
- }
110
- }
111
- }
112
-
113
- $files_to_send = (count($gzfiles) > 0) ? $gzfiles : $files;
114
-
115
- if (count($files_to_send) > 0) {
116
- $this->getRetentionScienceApiClient()->sync_data($files_to_send);
117
-
118
- if ($this->removeFileAfterSend) {
119
- array_map("unlink", array_values($files));
120
- array_map("unlink", array_values($gzfiles));
121
- }
122
- }
123
- }
124
-
125
- public function productCallback($args){
126
-
127
- global $last_processed_product_entity_id;
128
-
129
- $timestamp = $args['timestamp'];
130
-
131
- $product_id = $args['product_id'];
132
- $product = Mage::getModel('catalog/product')->load($product_id);
133
- $product_name = $product->getName();
134
-
135
- // OLDER VERSIONS OF MAGENTO HAVE A FATAL ERROR for this bug in magento: http://www.magentocommerce.com/boards/viewthread/53871/#t215589
136
- // MUST PATCH app/code/core/Mage/Catalog/Model/Product.php
137
- $manufacturer = $product->getAttributeText('manufacturer');
138
- $manufacturer = $manufacturer ? $manufacturer : null;
139
- $model = $product->getSku();
140
- $qty_stock = (int) Mage::getModel('cataloginventory/stock_item')->loadByProduct($product)->getQty();
141
- $price = $product->getPrice();
142
- if($product->getSpecialPrice()){
143
- $price = $product->getSpecialPrice();
144
- }
145
- $price = number_format($price, 2, '.', '');
146
- $active = ($product->isSalable()) ? true : false;
147
- $images_url = array($product->getImageUrl());
148
- $media_images = $product->getMediaGalleryImages();
149
- foreach($media_images as $media_image){
150
- $images_url[] = $media_image->getUrl();
151
- }
152
- $categories = $product->getCategoryIds();
153
- $item_url = $product->getProductUrl();
154
-
155
- // Get the parent_item_record_id
156
- $parent_record_id = null;
157
- $product_type_id = $product->getTypeId();
158
- if($product_type_id == "simple"){
159
- $parentIds = Mage::getModel('catalog/product_type_configurable')->getParentIdsByChild($product_id);
160
- if(!$parentIds){
161
- $parentIds = Mage::getModel('catalog/product_type_grouped')->getParentIdsByChild($product_id);
162
- }
163
- if(isset($parentIds[0])){
164
- $parent_record_id = $parentIds[0];
165
- }
166
- }
167
-
168
- $product_array = array(
169
- 'name'=> $product_name,
170
- 'manufacturer' => $manufacturer,
171
- 'model' => $model,
172
- 'quantity' => $qty_stock,
173
- 'price' => $price,
174
- 'active' => $active,
175
- 'image_list' => $images_url,
176
- 'item_url' => $item_url,
177
- 'parent_record_id' => $parent_record_id,
178
- 'attribute_1' => $product_type_id,
179
- 'categories' => $categories
180
- );
181
-
182
- if ($this->sendBulkUpload()){
183
- $this->writeBulkUploadFile(array($product_id => $product_array), 'items', $timestamp);
184
- } else {
185
- try{
186
- $this->getRetentionScienceApiClient()->update_item($product_id, $product_array);
187
- } catch (Exception $e){
188
- // do nothing
189
- }
190
- }
191
-
192
- // Update this as we iterate
193
- $last_processed_product_entity_id = $product_id;
194
- }
195
-
196
- public function userCallback($args){
197
- global $last_processed_user_entity_id;
198
-
199
- $timestamp = $args['timestamp'];
200
- $user = Mage::getModel('customer/customer')->load($args['user_record_id']);
201
- $email = $user->getEmail();
202
- $user_entity_id = $user->getEntityId();
203
- $user_record_id = md5(trim(strtolower($email)));
204
- $fullName = $user->getName();
205
- $address = Mage::getModel('customer/address')->load($user->getdefault_billing());
206
- $address1 = $address->getStreetFull();
207
- $address1 = str_replace("\n"," ",$address1);
208
- $city = $address->getCity();
209
- $regionModel = Mage::getModel('directory/region')->load($address->getRegionId());
210
- $region = $regionModel->getName();
211
- $zip = $address->getPostcode();
212
- $country = $address->getCountryId();
213
- $phone = $address->getTelephone();
214
- $birthDate = $user->getDob();
215
- $birthDate = explode('-',$birthDate);
216
- $birth_year = $birthDate[0];
217
- $gender = $user->getGender();
218
- // $ipAddress = '117.196.42.219';
219
- // $numberLogons = '2';
220
- $accountCreatedAt = $user->getCreatedAt();
221
- $accountCreatedAt = date("Y-m-d", Mage::getModel('core/date')->timestamp(strtotime($accountCreatedAt)));
222
-
223
- $accountUpdatedDate = $user->getUpdatedAt();
224
- $accountUpdatedAt = date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(strtotime($accountUpdatedDate)));
225
-
226
- if (!$this->sendBulkUpload()){
227
- // only update some fields (like created_at) if this is a new user.
228
- $user_exists_already = $this->getRetentionScienceApiClient()->user_exists($user_record_id);
229
- $existing_user = ($user_exists_already) ? $this->getRetentionScienceApiClient()->show_user($user_record_id) : null;
230
- }
231
-
232
- $user_array = array();
233
- if($email){
234
- $user_array['email'] = $email;
235
- }
236
- if($fullName){
237
- $user_array['full_name'] = $fullName;
238
- }
239
- if($address1){
240
- $user_array['address1'] = $address1;
241
- }
242
- if($city){
243
- $user_array['city'] = $city;
244
- }
245
- if($region){
246
- $user_array['state'] = $region;
247
- }
248
- if($zip){
249
- $user_array['zip'] = $zip;
250
- }
251
- if($country){
252
- $user_array['country'] = $country;
253
- }
254
- if($phone){
255
- $user_array['phone'] = $phone;
256
- }
257
- if($birth_year){
258
- $user_array['birth_year'] = $birth_year;
259
- }
260
- if($gender){
261
- $user_array['gender'] = $gender;
262
- }
263
- if($accountCreatedAt){
264
- if ($this->sendBulkUpload()){
265
- $user_array['account_created_on'] = $accountCreatedAt;
266
-
267
- } else {
268
- // Only send this if user has not already been created
269
- if (!($user_exists_already) || ($existing_user && (strtotime($existing_user['account_created_on']) > strtotime($accountCreatedAt))) ){
270
- $user_array['account_created_on'] = $accountCreatedAt;
271
- }
272
- }
273
- }
274
- if($accountUpdatedAt){
275
- $user_array['last_logon_at'] = $accountUpdatedAt;
276
- }
277
- if ($this->logToFile()){
278
- $this->writeToLog($user_record_id, 'users');
279
- $this->writeToLog(http_build_query($user_array), 'users');
280
- }
281
-
282
- if ($this->sendBulkUpload()){
283
- $this->writeBulkUploadFile(array($user_record_id => $user_array), 'users', $timestamp);
284
- } else {
285
- try{
286
- $this->getRetentionScienceApiClient()->update_user($user_record_id, $user_array);
287
- } catch (Exception $e){
288
- // do nothing
289
- }
290
- }
291
- // Update this as we iterate
292
- $last_processed_user_entity_id = $user_entity_id;
293
- }
294
-
295
- public function orderCallback($args){
296
- try {
297
- $timestamp = $args['timestamp'];
298
- global $last_processed_order_record_id;
299
-
300
- $order = Mage::getModel('sales/order')->load($args['order_record_id']);
301
- $order_array = array();
302
- $order_record_id = $order->getEntityId();
303
- $orderAllItems = $order->getAllVisibleItems();
304
- $order_item_array = array();
305
- foreach($orderAllItems as $orderAllItem){
306
- $item_record_id = $orderAllItem->getProductId();
307
- $name = $orderAllItem->getName();
308
- $quantity = (int) $orderAllItem->getQtyOrdered();
309
- $price = $orderAllItem->getPrice();
310
- $price = number_format($price, 2, '.', '');
311
- $final_price = $price * $quantity;
312
- $sku = $orderAllItem->getSku();
313
- $productId = $orderAllItem->getProductId();
314
- $product = Mage::getModel('catalog/product')->load($productId);
315
- $categoryIds = $product->getCategoryIds();
316
- $order_item_array[] = array(
317
- 'item_record_id' => $item_record_id,
318
- 'name' => $name,
319
- 'quantity' => $quantity,
320
- 'price' => $price,
321
- 'final_price' => $final_price,
322
- 'attribute_1' => $sku,
323
- 'categories' => $categoryIds
324
- );
325
- // save memory - Note, $product->clearInstance(); doesnt work on older magento installs
326
- unset($product);
327
- }
328
- unset($orderAllItems);
329
-
330
- $user_record_id = md5(trim(strtolower($order->getCustomerEmail())));
331
- if($order->getCustomerIsGuest()){
332
- $email = $order->getCustomerEmail();
333
- $user_record_id = md5(trim(strtolower($email)));
334
-
335
- // get billing address
336
- $address = $order->getBillingAddress();
337
- $fullName = $order->getCustomerFirstname()." ".$order->getCustomerLastname();
338
-
339
- $address1 = $address->getStreetFull();
340
- $address1 = str_replace("\n"," ",$address1);
341
- $city = $address->getCity();
342
- $regionModel = Mage::getModel('directory/region')->load($address->getRegionId());
343
- $region = $regionModel->getName();
344
- $zip = $address->getPostcode();
345
- $country = $address->getCountryId();
346
- $phone = $address->getTelephone();
347
- $accountCreatedAt = $order->getCreatedAt();
348
- $accountUpdatedAt = date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(strtotime($accountCreatedAt)));
349
- $accountCreatedAt = date("Y-m-d", Mage::getModel('core/date')->timestamp(strtotime($accountCreatedAt)));
350
-
351
- if (!$this->sendBulkUpload()){
352
- // only update some fields (like created_at) if this is a new user.
353
- $user_exists_already = $this->getRetentionScienceApiClient()->user_exists($user_record_id);
354
- $existing_user = ($user_exists_already) ? $this->getRetentionScienceApiClient()->show_user($user_record_id) : null;
355
- }
356
-
357
- // send this user to api as well
358
- $user_array = array();
359
- if($email){
360
- $user_array['email'] = $email;
361
- }
362
- if($fullName){
363
- $user_array['full_name'] = $fullName;
364
- }
365
- if($address1){
366
- $user_array['address1'] = $address1;
367
- }
368
- if($city){
369
- $user_array['city'] = $city;
370
- }
371
- if($region){
372
- $user_array['state'] = $region;
373
- }
374
- if($zip){
375
- $user_array['zip'] = $zip;
376
- }
377
- if($country){
378
- $user_array['country'] = $country;
379
- }
380
- if($phone){
381
- $user_array['phone'] = $phone;
382
- }
383
- if($accountCreatedAt){
384
- if ($this->sendBulkUpload()){
385
- $user_array['account_created_on'] = $accountCreatedAt;
386
-
387
- } else {
388
- if (!($user_exists_already)){
389
- $this->writeToLog("User does not exist yet ***** - creating with account_created_on as [" . $accountCreatedAt . ']', 'order_users');
390
- } else if ($existing_user) {
391
- $this->writeToLog(http_build_query($existing_user), 'existing_users');
392
- $themsg = "Existing user is PRESENT. His account_created_on is [" . $existing_user['account_created_on'] . "]. My accountCreatedAt is [" . $accountCreatedAt . "]";
393
- $this->writeToLog($themsg, 'order_users');
394
- }
395
-
396
- if (!($user_exists_already) || ($existing_user && (strtotime($existing_user['account_created_on']) > strtotime($accountCreatedAt))) ){
397
- $user_array['account_created_on'] = $accountCreatedAt;
398
- }
399
- }
400
- }
401
- if($accountUpdatedAt){
402
- $user_array['last_logon_at'] = $accountUpdatedAt;
403
- }
404
-
405
- if ($this->logToFile()){
406
- $this->writeToLog($user_record_id, 'order_users');
407
- $this->writeToLog(http_build_query($user_array), 'order_users');
408
- }
409
- try{
410
- if ($this->sendBulkUpload()){
411
- $this->writeBulkUploadFile(array($user_record_id => $user_array), 'orders_users', $timestamp);
412
- } else {
413
- $this->getRetentionScienceApiClient()->update_user($user_record_id, $user_array);
414
- }
415
- } catch (Exception $e){
416
- // do nothing
417
- }
418
- }
419
-
420
- $total_price = $order->getBaseSubtotal();
421
- $total_price = number_format($total_price, 2, '.', '');
422
- $discount_amount = $order->getBaseDiscountAmount();
423
- $shipping_amount = $order->getShippingAmount();
424
- $tax_amount = $order->getBaseTaxAmount();
425
- $date = $order->getCreatedAt();
426
- $ordered_at = date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(strtotime($date)));
427
- $payment = $order->getPayment();
428
- if (!is_object($payment)) {
429
- throw new Exception('Order ' . $order_record_id . 'does not have valid payment information');
430
- }
431
- $payment_method = $payment->getMethodInstance();
432
- if (!is_object($payment_method)) {
433
- throw new Exception('Order ' . $order_record_id . 'does not have a valid payment method');
434
- }
435
- $order_array = array(
436
- 'user_record_id' => $user_record_id,
437
- 'total_price' => $total_price,
438
- 'discount_amount' => $discount_amount,
439
- 'shipping_amount' => $shipping_amount,
440
- 'tax_amount' => $tax_amount,
441
- 'ordered_at' => $ordered_at,
442
- 'payment_method' => $payment_method->getTitle(),
443
- 'order_items'=> $order_item_array
444
- );
445
- if ($this->sendBulkUpload()){
446
- $this->writeBulkUploadFile(array($order_record_id => $order_array), 'orders', $timestamp);
447
- } else {
448
- try {
449
- $this->getRetentionScienceApiClient()->update_order($order_record_id, $order_array);
450
- } catch (Exception $e){
451
- // do nothing
452
- }
453
- }
454
-
455
- // Update this as we iterate
456
- $last_processed_order_record_id = $order_record_id;
457
- // Release memory. Note: $order->clearInstance(); doesnt work on older magento ver
458
- unset($order_array);
459
- unset($order);
460
- } catch (Exception $e) {
461
- Mage::logException($e);
462
- }
463
- }
464
-
465
- public function coreBlockAbstractPrepareLayoutAfter(Varien_Event_Observer $observer)
466
- {
467
- if (Mage::app()->getFrontController()->getAction()->getFullActionName() === 'adminhtml_dashboard_index')
468
- {
469
- $block = $observer->getBlock();
470
- if ($block->getNameInLayout() === 'dashboard')
471
- {
472
- $block->getChild('topSearches')->setUseAsDashboardHook(true);
473
- }
474
- }
475
- }
476
-
477
- public function coreBlockAbstractToHtmlAfter(Varien_Event_Observer $observer)
478
- {
479
- if (Mage::app()->getFrontController()->getAction()->getFullActionName() === 'adminhtml_dashboard_index')
480
- {
481
- if ($observer->getBlock()->getUseAsDashboardHook())
482
- {
483
- $transport = $observer->getTransport();
484
- $html = $transport->getHtml();
485
- $myBlock = $observer->getBlock()->getLayout()->createBlock('waves/adminhtml_rscore')->setTemplate('waves/rscore.phtml');
486
- $html .= $myBlock->toHtml();
487
- $transport->setHtml($html);
488
- }
489
- }
490
- }
491
-
492
- public function updateRScore()
493
- {
494
- $rscore_data = Mage::getModel('waves/source_rscoredata')->getDataArray();
495
- $rscore_json = $this->getRetentionScienceApiClient()->calculate_rscore($rscore_data);
496
- Mage::getModel('core/config')->saveConfig('waves/calculated_rscore_json', $rscore_json);
497
- return $rscore_json;
498
- }
499
-
500
- public function syncData() {
501
- if (Mage::getStoreConfig('waves/retentionscience_settings/enable') == 1) {
502
- $phpbin = $this->getPhpBin();
503
- $sync_data_script = escapeshellarg(dirname(__FILE__) . "/rs_sync_data.php");
504
-
505
- $store_id = Mage::getStoreConfig('waves/retentionscience_settings/store_id');
506
- $valid_store_ids = array_keys(Mage::app()->getStores());
507
-
508
- if (in_array($store_id, $valid_store_ids)) {
509
- exec("$phpbin $sync_data_script $store_id > /dev/null &");
510
- } else {
511
- Mage::getSingleton('core/session')->addError("You must select a valid Store ID!");
512
- }
513
- } else {
514
- Mage::getSingleton('core/session')->addError("You can't sync data unless Retention Science is enabled!");
515
- }
516
- }
517
- }
1
+ <?php
2
+
3
+ class RetentionScience_Waves_Model_Observer extends Varien_Object {
4
+
5
+ const EXPORT_TYPE_BATCH = 'batch';
6
+
7
+ const EXPORT_TYPE_RECORD = 'record';
8
+
9
+ const LOG_GROUP = 'Magento';
10
+
11
+ const LOG_STREAM = 'default';
12
+
13
+ protected $_delayedUpload = TRUE;
14
+
15
+ protected $_delayedFiles = array();
16
+
17
+ protected $_logGroup;
18
+
19
+ protected $_logStream;
20
+
21
+ protected $_rsAPI;
22
+
23
+ protected $_allowedGroups = array(
24
+ 'categories' => 'waves/export_category',
25
+ 'users' => 'waves/export_customer',
26
+ 'orders' => 'waves/export_order',
27
+ 'items' => 'waves/export_product',
28
+ 'order_items' => 'waves/export_order_items',
29
+ );
30
+
31
+ protected $_allowedTypes = array(
32
+ self::EXPORT_TYPE_BATCH,
33
+ // self::EXPORT_TYPE_RECORD,
34
+ );
35
+
36
+ protected $_reserved_memory;
37
+
38
+ protected $_signals;
39
+
40
+ public function __construct() {
41
+ parent::__construct();
42
+ $this->_logStream = Mage::helper('waves')->getAWSLogStream();
43
+ $this->_logGroup = Mage::helper('waves')->getAWSLogGroup();
44
+ $this->registerShutdownFunction();
45
+ $this->setErrorHandler();
46
+ if(function_exists('pcntl_signal')) {
47
+ $this->_signals = array(
48
+ SIGINT => 'SIGINT',
49
+ SIGTERM => 'SIGTERM',
50
+ SIGHUP => 'SIGHUP',
51
+ );
52
+ }
53
+ $this->registerPosixHandlers();
54
+ }
55
+
56
+ public function performExport($observer) {
57
+ $this->setEvent($observer->getEvent());
58
+ if(! Mage::helper('waves')->isEnabled()) {
59
+ $this->getEvent()->setStatus('error');
60
+ $this->getEvent()->setMessage('Retention Science Module is inactive');
61
+ return;
62
+ }
63
+ if(! $this->validate()) {
64
+ return;
65
+ }
66
+ $this->export();
67
+ }
68
+
69
+ protected function exportBatch() {
70
+ $timestamp = microtime(TRUE);
71
+ $groups = $this->getGroups();
72
+ // Export groups
73
+ foreach($groups AS $groupName) {
74
+ $exportModel = Mage::getModel($this->_allowedGroups[$groupName]);
75
+ $exportModel->setStoreId(Mage::helper('waves')->getStoreId());
76
+ $this->setExportModel($exportModel);
77
+ try {
78
+ $this->logStart();
79
+ $this->setListenErrors(TRUE);
80
+ $exportModel->run($timestamp);
81
+ $this->logSuccess();
82
+ if(file_exists($exportModel->getBulkFile())) {
83
+ if($this->_delayedUpload) {
84
+ $this->_delayedFiles[$exportModel->getExportModelTitle()] = $exportModel->getBulkFile();
85
+ } else {
86
+ $this->uploadBulkFile($exportModel->getExportModelTitle(), $exportModel->getBulkFile());
87
+ }
88
+ }
89
+ } catch(Exception $e) {
90
+ // Catch exception
91
+ $errno = $e->getCode();
92
+ $errstr = $e->getMessage();
93
+ $errfile = $e->getFile();
94
+ $errline = $e->getLine();
95
+ // Do stuff
96
+ $this->logException($errno, $errstr, $errfile, $errline);
97
+ }
98
+
99
+ if(! $this->_delayedUpload) {
100
+ // temporarily disabling so we can inspect files
101
+ // if(file_exists($exportModel->getBulkFile())) {
102
+ // @ unlink($exportModel->getBulkFile());
103
+ // }
104
+
105
+ if(file_exists($exportModel->getBulkFile() . '.gz')) {
106
+ @ unlink($exportModel->getBulkFile() . '.gz');
107
+ }
108
+ }
109
+
110
+ $this->setListenErrors(FALSE);
111
+ $this->getLog()->sendLogs();
112
+ }
113
+ if($this->_delayedUpload AND ! empty($this->_delayedFiles)) {
114
+ $this->uploadBulkFile($this->_delayedFiles);
115
+ foreach($this->_delayedFiles AS $_file) {
116
+ // temporarily disabling so we can inspect files
117
+ // if(file_exists($_file)) {
118
+ // @ unlink($_file);
119
+ // }
120
+
121
+ if(file_exists($_file . '.gz')) {
122
+ @ unlink($_file . '.gz');
123
+ }
124
+ }
125
+ }
126
+ // Set status
127
+ if(! $this->getStatus()) {
128
+ $this->getEvent()->setStatus('success');
129
+ $this->getEvent()->setMessage('Exported ' . implode(', ', $groups));
130
+ }
131
+ }
132
+
133
+ protected function uploadBulkFile($files, $filename = NULL) {
134
+ if(! is_array($files)) {
135
+ $files = array($files => $filename);
136
+ }
137
+
138
+ $uploadFiles = array();
139
+
140
+ foreach($files AS $group => $filename) {
141
+ // Maybe we have no records for some type of export
142
+ if(! file_exists($filename)) {
143
+ continue;
144
+ }
145
+ if(! is_readable($filename)) {
146
+ throw new Exception('File "' . $filename . '" is not readable');
147
+ }
148
+ if(! is_writable($filename)) {
149
+ throw new Exception('File "' . $filename . '" is not writable');
150
+ }
151
+ if(Mage::helper('waves')->isBulkCompressionEnabled()) {
152
+ $gzfilename = $filename . '.gz';
153
+ $fp = fopen($filename, 'rb');
154
+ $gzfp = gzopen($gzfilename, 'wb');
155
+ while(! feof($fp)) {
156
+ gzwrite($gzfp, fread($fp, 1024 * 512));
157
+ }
158
+ gzclose($fp);
159
+ fclose($gzfp);
160
+ $filename = $gzfilename;
161
+ }
162
+ $uploadFiles[$group] = $filename;
163
+ }
164
+
165
+ if(is_null($this->_rsAPI)) {
166
+ $this->_rsAPI = Mage::getModel('waves/connection_retentionScienceApi', array(
167
+ 'username' => Mage::helper('waves')->getApiUser(),
168
+ 'password' => Mage::helper('waves')->getApiPassword(),
169
+ 'testmode' => Mage::helper('waves')->isTestMode(),
170
+ ));
171
+ }
172
+ $this->_rsAPI->sync_data($uploadFiles);
173
+ }
174
+
175
+ protected function exportRecord() {
176
+ $timestamp = microtime(TRUE);
177
+ $groupName = $this->getGroup();
178
+ $exportModel = Mage::getModel($this->_allowedGroups[$groupName]);
179
+ $exportModel->setIdsToProcess($this->getIds());
180
+ $this->setExportModel($exportModel);
181
+ try {
182
+ $this->logStart();
183
+ $this->setListenErrors(TRUE);
184
+ $exportModel->run($timestamp);
185
+ $this->logSuccess();
186
+ } catch(Exception $e) {
187
+ // Catch exception
188
+ $errno = $e->getCode();
189
+ $errstr = $e->getMessage();
190
+ $errfile = $e->getFile();
191
+ $errline = $e->getLine();
192
+ // Do stuff
193
+ $this->logException($errno, $errstr, $errfile, $errline);
194
+ }
195
+ $this->setListenErrors(FALSE);
196
+ $this->getLog()->sendLogs();
197
+ }
198
+
199
+ protected function log($logStreamName, $message) {
200
+ // There are some errors during including AWS SDK files - ignore them
201
+ $oldListen = $this->getListenErrors();
202
+ $this->setListenErrors(FALSE);
203
+ $logTime = Mage::getSingleton('core/date')->gmtDate() . ' UTC';
204
+ $siteId = Mage::helper('waves')->getSiteId();
205
+ $this->getLog()->log(array(
206
+ 'logGroupName' => $this->_logGroup,
207
+ 'logStreamName' => $this->_logStream,
208
+ 'message' => $logTime . ' - [site_id ' . $siteId . '] [' . strtoupper($logStreamName) . ']: [' . $this->getGUID() . '] ' . $message,
209
+ ));
210
+ $this->setListenErrors($oldListen);
211
+ }
212
+
213
+ protected function logStart() {
214
+ $this->setStartTime(round(microtime(true)));
215
+ $this->setStartMemory(memory_get_usage(TRUE));
216
+ $this->setGUID(substr(md5(rand()), 0, 8) . '-' . substr(md5(rand()), 0, 4) . '-' . substr(md5(rand()), 0, 4) . '-' . substr(md5(rand()), 0, 12));
217
+ $start = $this->getExportModel()->getExportModelTitle() . ' export started';
218
+ if($this->getEvent()->getSource()) {
219
+ $start .= ' [source ' . $this->getEvent()->getSource() . ']';
220
+ }
221
+ $start .= ' [memstart ' . $this->getStartMemory() . ']';
222
+ $this->log('start', $start);
223
+ }
224
+
225
+ protected function logSuccess() {
226
+ $memdiff = memory_get_usage(TRUE) - $this->getStartMemory();
227
+ $processedRecords = $this->getExportModel()->getProcessedRecords();
228
+ $timediff = round(microtime(true)) - $this->getStartTime();
229
+ $this->log('success', $this->getExportModel()->getExportModelTitle() . ' export ended successful [processed ' . $processedRecords . '] [memdiff ' . ($memdiff > 0 ? '+' : '') . $memdiff . '] [timediff ' . $timediff . ']');
230
+ }
231
+
232
+ protected function logFail() {
233
+ $memdiff = memory_get_usage(TRUE) - $this->getStartMemory();
234
+ $processedRecords = $this->getExportModel()->getProcessedRecords();
235
+ $timediff = round(microtime(true)) - $this->getStartTime();
236
+ $totalRecords = $this->getExportModel()->getTotalRecordsCalculated();
237
+ $this->log('fail', $this->getExportModel()->getExportModelTitle() . ' export failed [processed=' . $processedRecords . '] [total ' . $totalRecords . '] [memdiff ' . ($memdiff > 0 ? '+' : '') . $memdiff . '] [timediff=' . $timediff . ']');
238
+ }
239
+
240
+ protected function logException($errno, $errstr, $errfile, $errline) {
241
+ $this->logError('exception', $errno, $errstr, $errfile, $errline);
242
+ $this->logFail();
243
+ }
244
+
245
+ protected function logRecoverableError($errno, $errstr, $errfile, $errline) {
246
+ $this->logError('recoverable_error', $errno, $errstr, $errfile, $errline);
247
+ }
248
+
249
+ protected function logUnrecoverableError($errno, $errstr, $errfile, $errline) {
250
+ $this->logError('unrecoverable_error', $errno, $errstr, $errfile, $errline);
251
+ $this->logFail();
252
+ $this->getLog()->sendLogs();
253
+ }
254
+
255
+ protected function logError($type, $errno, $errstr, $errfile, $errline) {
256
+ $memdiff = memory_get_usage(TRUE) - $this->getStartMemory();
257
+ $processedRecords = $this->getExportModel()->getProcessedRecords();
258
+ $timediff = round(microtime(true)) - $this->getStartTime();
259
+ $totalRecords = $this->getExportModel()->getTotalRecordsCalculated();
260
+ $this->log($type, $this->getExportModel()->getExportModelTitle() . ' error occured [errno ' . $errno . '] [errstr ' . $errstr . '] [errfile' . $errfile . '] [errline ' . $errline . '] [processed ' . $processedRecords . '] [total ' . $totalRecords . '] [memdiff ' . ($memdiff > 0 ? '+' : '') . $memdiff . '] [timediff ' . $timediff . ']');
261
+ }
262
+
263
+ protected function registerShutdownFunction() {
264
+ // Save 5MB of reserved memory, because PHP not allows to do anything else if out of memory
265
+ $this->_reserved_memory = str_repeat('*', 10 * 1024 * 1024);
266
+ register_shutdown_function(array($this, 'shutdownHandler'));
267
+ }
268
+
269
+ protected function setErrorHandler() {
270
+ set_error_handler(array($this, 'errorHandler'), E_ALL | E_STRICT);
271
+ }
272
+
273
+ protected function registerPosixHandlers() {
274
+ if(function_exists('pcntl_signal')) {
275
+ declare(ticks = 1);
276
+ foreach($this->_signals AS $signo => $code) {
277
+ pcntl_signal($signo, array($this, 'posixHandler'));
278
+ }
279
+ }
280
+ }
281
+
282
+ public function posixHandler($signo) {
283
+ if(! $this->getListenErrors()) {
284
+ return;
285
+ }
286
+ $this->logError('manual_shutodown', $signo, 'Processed was manually stopped with ' . $this->_signals[$signo], 'unknown file', 0);
287
+ $this->logFail();
288
+ $this->getLog()->sendLogs();
289
+ exit;
290
+ }
291
+
292
+ public function errorHandler($errno, $errstr, $errfile, $errline) {
293
+ if(! $this->getListenErrors()) {
294
+ return;
295
+ }
296
+ // Catch recoverable error
297
+ // Do stuff
298
+ $this->logRecoverableError($errno, $errstr, $errfile, $errline);
299
+ }
300
+
301
+ public function shutdownHandler() {
302
+ if(! $this->getListenErrors()) {
303
+ return;
304
+ }
305
+ $this->setListenErrors(FALSE);
306
+ // Free reserved memory, because PHP not allows to do anything else if out of memory
307
+ $this->_reserved_memory = NULL;
308
+ // Catch non-recoverable error
309
+ $errno = E_CORE_ERROR;
310
+ $errstr = "shutdown";
311
+ $errfile = "unknown file";
312
+ $errline = 0;
313
+ $error = error_get_last();
314
+ if( $error !== NULL) {
315
+ $errno = $error["type"];
316
+ $errfile = $error["file"];
317
+ $errline = $error["line"];
318
+ $errstr = $error["message"];
319
+ }
320
+ // Do stuff
321
+ $this->logUnrecoverableError($errno, $errstr, $errfile, $errline);
322
+ }
323
+
324
+ protected function getLog() {
325
+ $log = $this->getData('log');
326
+ if(is_null($log)) {
327
+ $this->setData('log', Mage::getSingleton('waves/connection_awsCloudWatch'));
328
+ }
329
+ return $this->getData('log');
330
+ }
331
+
332
+ protected function export() {
333
+ switch($this->getType()) {
334
+ case self::EXPORT_TYPE_BATCH:
335
+ $this->exportBatch();
336
+ break;
337
+ case self::EXPORT_TYPE_RECORD:
338
+ $this->exportRecord();
339
+ break;
340
+ }
341
+ }
342
+
343
+ protected function validate() {
344
+ $event = $this->getEvent();
345
+ if(! in_array($event->getType(), $this->_allowedTypes, TRUE)) {
346
+ $event->setStatus('error');
347
+ $event->setMessage('Not valid export type. Allowed types: ' . implode(', ', $this->_allowedTypes));
348
+ return FALSE;
349
+ }
350
+ $this->setType($event->getType());
351
+ switch($event->getType()) {
352
+ case self::EXPORT_TYPE_BATCH:
353
+ $groups = $event->getGroups();
354
+ if(! empty($groups) AND $groups !== 'all') {
355
+ $groups = explode(',', $groups);
356
+ if(! empty($groups)) {
357
+ foreach($groups AS $group) {
358
+ if(! isset($this->_allowedGroups[$group])) {
359
+ $event->setStatus('error');
360
+ $event->setMessage('Not valid export groups. Allowed groups: all or any/comma-separated of(' . implode(', ', array_keys($this->_allowedGroups)) . ')');
361
+ return FALSE;
362
+ }
363
+ }
364
+ $this->setGroups($groups);
365
+ } else {
366
+ $event->setStatus('error');
367
+ $event->setMessage('Validation failed');
368
+ return FALSE;
369
+ }
370
+ } else {
371
+ $this->setGroups(array_keys($this->_allowedGroups));
372
+ }
373
+ break;
374
+ case self::EXPORT_TYPE_RECORD:
375
+ $group = $event->getGroup();
376
+ if(empty($group) OR ! isset($this->_allowedGroups[$group])) {
377
+ $event->setStatus('error');
378
+ $event->setMessage('Not valid export groups. You should specify one of ' . implode(', ', array_keys($this->_allowedGroups)));
379
+ return FALSE;
380
+ }
381
+ $this->setGroup($group);
382
+ $ids = $event->getIds();
383
+ if(! is_string($ids)) {
384
+ $event->setStatus('error');
385
+ $event->setMessage('Not specified record ids');
386
+ return FALSE;
387
+ }
388
+ $ids = explode(',', $ids);
389
+ if(! empty($ids)) {
390
+ $exportIds = array();
391
+ foreach($ids AS $id) {
392
+ $id = (int) $id;
393
+ if($id <= 0) {
394
+ $event->setStatus('error');
395
+ $event->setMessage('Id should be more than zero');
396
+ return FALSE;
397
+ }
398
+ $exportIds[] = $id;
399
+ }
400
+ $this->setIds($exportIds);
401
+ } else {
402
+ $event->setStatus('error');
403
+ $event->setMessage('Not specified record ids');
404
+ return FALSE;
405
+ }
406
+ break;
407
+ }
408
+ return TRUE;
409
+ }
410
+
411
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/code/community/RetentionScience/Waves/Model/Source/Categorytree.php DELETED
@@ -1,47 +0,0 @@
1
- <?php
2
- /**
3
- * Magento
4
- *
5
- * NOTICE OF LICENSE
6
- *
7
- * This source file is subject to the Open Software License (OSL 3.0)
8
- * that is bundled with this package in the file LICENSE.txt.
9
- * It is also available through the world-wide-web at this URL:
10
- * http://opensource.org/licenses/osl-3.0.php
11
- * If you did not receive a copy of the license and are unable to
12
- * obtain it through the world-wide-web, please send an email
13
- * to license@magentocommerce.com so we can send you a copy immediately.
14
- *
15
- * DISCLAIMER
16
- *
17
- * Do not edit or add to this file if you wish to upgrade Magento to newer
18
- * versions in the future. If you wish to customize Magento for your
19
- * needs please refer to http://www.magentocommerce.com for more information.
20
- *
21
- * @category Mage
22
- * @package Mage_Eav
23
- * @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com)
24
- * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
- */
26
-
27
-
28
- class RetentionScience_Waves_Model_Source_Categorytree extends Mage_Eav_Model_Entity_Attribute_Source_Abstract
29
- {
30
- protected $_options;
31
-
32
- public function getAllCategories(){
33
- $categories = Mage::getModel('catalog/category')->getCollection()
34
- ->addAttributeToSelect('*')
35
- ;
36
- $categories->getSelect()->order("level asc");
37
- $this->_options['categories'] = $categories;
38
- }
39
-
40
- public function getAllOptions()
41
- {
42
- if (!$this->_options) {
43
- $this->getAllCategories();
44
- }
45
- return $this->_options['categories'];
46
- }
47
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/code/community/RetentionScience/Waves/Model/Source/Credentials.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class RetentionScience_Waves_Model_Source_Credentials extends Mage_Core_Model_Config_Data {
4
+
5
+ protected function _afterSave()
6
+ {
7
+ static $_credentials = array();
8
+ $_credentials[$this->getPath()] = $this->getValue();
9
+ if(count($_credentials) == 3) {
10
+ // Updating AWS credentials
11
+ $api = Mage::getModel('waves/connection_retentionScienceApi', array(
12
+ 'username' => $_credentials[RetentionScience_Waves_Helper_Data::WAVES_SETTINGS_API_USER],
13
+ 'password' => $_credentials[RetentionScience_Waves_Helper_Data::WAVES_SETTINGS_API_PASSWORD],
14
+ 'testmode' => (bool) $_credentials[RetentionScience_Waves_Helper_Data::WAVES_SETTINGS_TEST_MODE]
15
+ ));
16
+ try {
17
+ $aws_credentials = $api->get_aws_credentials();
18
+ $aws_credentials = Zend_Json::decode($aws_credentials);
19
+ $site_id = $api->get_site_id();
20
+ $site_id = Zend_Json::decode($site_id);
21
+
22
+ $valid_aws_credentials = (isset($aws_credentials) AND is_array($aws_credentials) AND isset($aws_credentials['status']) AND $aws_credentials['status'] === 'success');
23
+ $valid_site_id = (isset($site_id) AND is_array($site_id) AND isset($site_id['status']) AND $site_id['status'] === 'success');
24
+
25
+ if(! $valid_aws_credentials) {
26
+ throw new Exception('Error 8a with API call. Please check credentials and try again.');
27
+ }
28
+
29
+ if(! $valid_site_id) {
30
+ throw new Exception('Error 8b with API call. Please check credentials and try again.');
31
+ }
32
+
33
+ } catch(Exception $e) {
34
+ Mage::helper('waves')->disable();
35
+ Mage::getSingleton('core/session')->addError('Unable to connect to Retention Science API. Module is disabled. ' . $e->getMessage());
36
+ }
37
+
38
+
39
+ if($valid_aws_credentials && $valid_site_id) {
40
+ $msg = "Saving helper details: site_id " . $site_id['id'];
41
+ $msg .= ", access_key_id " . $aws_credentials['access_key_id'];
42
+ $msg .= ", secret_access_key " . $aws_credentials['secret_access_key'];
43
+ $msg .= ", log_group " . $aws_credentials['log_group'];
44
+ $msg .= ", log_stream " . $aws_credentials['log_stream'];
45
+ $msg .= ", session_token " . $aws_credentials['session_token'];
46
+
47
+ Mage::getSingleton('waves/connection_awsCloudWatch')->logMessage($msg);
48
+
49
+ Mage::helper('waves')->setAWSAccessKeyId($aws_credentials['access_key_id']);
50
+ Mage::helper('waves')->setAWSSecretAccessKey($aws_credentials['secret_access_key']);
51
+ Mage::helper('waves')->setAWSLogStream($aws_credentials['log_stream']);
52
+ Mage::helper('waves')->setAWSLogGroup($aws_credentials['log_group']);
53
+ Mage::helper('waves')->setAWSSessionToken($aws_credentials['session_token']);
54
+ Mage::helper('waves')->setSiteId($site_id['id']);
55
+ }
56
+ }
57
+ }
58
+
59
+ }
app/code/community/RetentionScience/Waves/Model/Source/Cron/Frequency.php DELETED
@@ -1,29 +0,0 @@
1
- <?php
2
- /**
3
- * Source for Cron Frequency
4
- *
5
- * @category RetentionScience
6
- * @package Waves
7
- */
8
- class RetentionScience_Waves_Model_Source_Cron_Frequency
9
- {
10
- const DAILY = 1;
11
- const WEEKLY = 2;
12
- const MONTHLY = 3;
13
-
14
- public function toOptionArray()
15
- {
16
- return array(
17
- array(
18
- 'label' => 'Daily',
19
- 'value' => self::DAILY),
20
- array(
21
- 'label' => 'Weekly',
22
- 'value' => self::WEEKLY),
23
- array(
24
- 'label' => 'Monthly',
25
- 'value' => self::MONTHLY)
26
-
27
- );
28
- }
29
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/code/community/RetentionScience/Waves/Model/Source/Cron/Hours.php DELETED
@@ -1,19 +0,0 @@
1
- <?php
2
- /**
3
- * Source for Cron Hours
4
- *
5
- * @category RetentionScience
6
- * @package Waves
7
- */
8
- class RetentionScience_Waves_Model_Source_Cron_Hours
9
- {
10
-
11
- public function toOptionArray()
12
- {
13
- $hours = array();
14
- for ($i = 1; $i <= 24; $i++) {
15
- $hours[] = array('label' => $i, 'value' => $i);
16
- }
17
- return $hours;
18
- }
19
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/code/community/RetentionScience/Waves/Model/Source/Cronconfig.php CHANGED
@@ -4,9 +4,9 @@ class RetentionScience_Waves_Model_Source_Cronconfig extends Mage_Core_Model_Con
4
  {
5
 
6
  protected function _afterSave()
7
- {
8
  // category, product, user, order
9
- $rs_cron_job = $this->getFieldConfig()->rs_cron_job;
10
  $cron_string_path = 'crontab/jobs/' . $rs_cron_job . '/schedule/cron_expr';
11
  $cron_model_path = 'crontab/jobs/' . $rs_cron_job . '/run/model';
12
  $cron_expr_string = $this->getValue();
@@ -14,18 +14,18 @@ class RetentionScience_Waves_Model_Source_Cronconfig extends Mage_Core_Model_Con
14
 
15
  try {
16
  Mage::getModel('core/config_data')
17
- ->load($cron_string_path, 'path')
18
- ->setValue($cron_expr_string)
19
- ->setPath($cron_string_path)
20
- ->save();
21
  Mage::getModel('core/config_data')
22
- ->load($cron_model_path, 'path')
23
- ->setValue((string) Mage::getConfig()->getNode($cron_model_path))
24
- ->setPath($cron_model_path)
25
- ->save();
26
  } catch (Exception $e) {
27
  throw new Exception(Mage::helper('cron')->__('Unable to save the cron expression.'));
28
  }
29
  }
30
 
31
- }
4
  {
5
 
6
  protected function _afterSave()
7
+ {
8
  // category, product, user, order
9
+ $rs_cron_job = $this->getFieldConfig()->rs_cron_job;
10
  $cron_string_path = 'crontab/jobs/' . $rs_cron_job . '/schedule/cron_expr';
11
  $cron_model_path = 'crontab/jobs/' . $rs_cron_job . '/run/model';
12
  $cron_expr_string = $this->getValue();
14
 
15
  try {
16
  Mage::getModel('core/config_data')
17
+ ->load($cron_string_path, 'path')
18
+ ->setValue($cron_expr_string)
19
+ ->setPath($cron_string_path)
20
+ ->save();
21
  Mage::getModel('core/config_data')
22
+ ->load($cron_model_path, 'path')
23
+ ->setValue((string) Mage::getConfig()->getNode($cron_model_path))
24
+ ->setPath($cron_model_path)
25
+ ->save();
26
  } catch (Exception $e) {
27
  throw new Exception(Mage::helper('cron')->__('Unable to save the cron expression.'));
28
  }
29
  }
30
 
31
+ }
app/code/community/RetentionScience/Waves/Model/Source/Rscoredata.php CHANGED
@@ -1,30 +1,32 @@
1
  <?php
2
 
3
- class RetentionScience_Waves_Model_Source_Rscoredata
4
- {
5
  protected $resource;
6
  protected $readConnection;
7
-
8
  public function getDataArray()
9
  {
 
 
10
  $this->resource = Mage::getSingleton('core/resource');
11
  $this->readConnection = $this->resource->getConnection('core_read');
12
-
13
  return array( "name" => Mage::getStoreConfig('general/store_information/name'),
14
- "url" => Mage::getStoreConfig('web/secure/base_url'),
15
- "source" => "magento",
16
- "extra_info" => array(
17
- "phone" => Mage::getStoreConfig('general/store_information/phone'),
18
- "email" => Mage::getStoreConfig('trans_email/ident_general/email'),
19
- "num_users" => Mage::getModel('customer/customer')->getCollection()->getSize(),
20
- "num_orders" => Mage::getModel('sales/order')->getCollection()->getSize()
21
- ),
22
- "rscore_metrics" => array(
23
- "churn_array" => $this->getChurnArray(),
24
- "engagement_rate" => $this->getEngagementRate(),
25
- "rpr_rate" => $this->getRprRate()));
26
  }
27
-
28
  private function getChurnArray()
29
  {
30
  $customer_table = $this->resource->getTableName('customer_entity');
@@ -39,20 +41,20 @@ class RetentionScience_Waves_Model_Source_Rscoredata
39
  ORDER BY days ASC;";
40
  return array_map("array_values", $this->readConnection->fetchAll($query));
41
  }
42
-
43
  private function getEngagementRate()
44
  {
45
  $customer_table = $this->resource->getTableName('customer_entity');
46
  $order_table = $this->resource->getTableName('sales_flat_order');
47
- $query = "SELECT
48
- (SELECT COUNT(DISTINCT customer_email) FROM $order_table) /
49
  (SELECT count(*) FROM ((SELECT email FROM $customer_table) UNION (SELECT customer_email FROM $order_table WHERE customer_is_guest IS TRUE)) a);";
50
  return $this->readConnection->fetchOne($query);
51
  }
52
-
53
  private function getRprRate()
54
  {
55
- $writeConnection = $this->resource->getConnection();
56
  $customer_table = $this->resource->getTableName('customer_entity');
57
  $order_table = $this->resource->getTableName('sales_flat_order');
58
  $writeConnection->query("DROP TEMPORARY TABLE IF EXISTS _temp_orders_1;");
@@ -89,7 +91,7 @@ class RetentionScience_Waves_Model_Source_Rscoredata
89
  GROUP BY yearmonth;";
90
  $results = $writeConnection->fetchAll($query);
91
  array_shift($results); // ignore first month
92
-
93
  if (count($results) == 0) {
94
  return null;
95
  } else {
@@ -103,4 +105,5 @@ class RetentionScience_Waves_Model_Source_Rscoredata
103
  return array_sum($rates) / count($rates);
104
  }
105
  }
106
- }
 
1
  <?php
2
 
3
+ class RetentionScience_Waves_Model_Source_Rscoredata {
4
+
5
  protected $resource;
6
  protected $readConnection;
7
+
8
  public function getDataArray()
9
  {
10
+ Mage::getSingleton('waves/connection_awsCloudWatch')->logMessage("getDataArray called in Rscore");
11
+
12
  $this->resource = Mage::getSingleton('core/resource');
13
  $this->readConnection = $this->resource->getConnection('core_read');
14
+
15
  return array( "name" => Mage::getStoreConfig('general/store_information/name'),
16
+ "url" => Mage::getStoreConfig('web/secure/base_url'),
17
+ "source" => "magento",
18
+ "extra_info" => array(
19
+ "phone" => Mage::getStoreConfig('general/store_information/phone'),
20
+ "email" => Mage::getStoreConfig('trans_email/ident_general/email'),
21
+ "num_users" => Mage::getModel('customer/customer')->getCollection()->getSize(),
22
+ "num_orders" => Mage::getModel('sales/order')->getCollection()->getSize()
23
+ ),
24
+ "rscore_metrics" => array(
25
+ "churn_array" => $this->getChurnArray(),
26
+ "engagement_rate" => $this->getEngagementRate(),
27
+ "rpr_rate" => $this->getRprRate()));
28
  }
29
+
30
  private function getChurnArray()
31
  {
32
  $customer_table = $this->resource->getTableName('customer_entity');
41
  ORDER BY days ASC;";
42
  return array_map("array_values", $this->readConnection->fetchAll($query));
43
  }
44
+
45
  private function getEngagementRate()
46
  {
47
  $customer_table = $this->resource->getTableName('customer_entity');
48
  $order_table = $this->resource->getTableName('sales_flat_order');
49
+ $query = "SELECT
50
+ (SELECT COUNT(DISTINCT customer_email) FROM $order_table) /
51
  (SELECT count(*) FROM ((SELECT email FROM $customer_table) UNION (SELECT customer_email FROM $order_table WHERE customer_is_guest IS TRUE)) a);";
52
  return $this->readConnection->fetchOne($query);
53
  }
54
+
55
  private function getRprRate()
56
  {
57
+ $writeConnection = $this->resource->getConnection('core_read');
58
  $customer_table = $this->resource->getTableName('customer_entity');
59
  $order_table = $this->resource->getTableName('sales_flat_order');
60
  $writeConnection->query("DROP TEMPORARY TABLE IF EXISTS _temp_orders_1;");
91
  GROUP BY yearmonth;";
92
  $results = $writeConnection->fetchAll($query);
93
  array_shift($results); // ignore first month
94
+
95
  if (count($results) == 0) {
96
  return null;
97
  } else {
105
  return array_sum($rates) / count($rates);
106
  }
107
  }
108
+
109
+ }
app/code/community/RetentionScience/Waves/Model/Source/Stores.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class RetentionScience_Waves_Model_Source_Stores {
4
+
5
+ public function toOptionArray()
6
+ {
7
+ $stores = Mage::app()->getStores();
8
+ $options = array(array('value' => null, 'label' => "Select a Store"));
9
+ foreach ($stores as $store_id => $store) {
10
+ array_push($options, array('value' => $store_id, 'label' => $store->getWebsite()->getName() . " - " . $store->getName()));
11
+ }
12
+ return $options;
13
+ }
14
+
15
+ }
app/code/community/RetentionScience/Waves/Model/rs_get_save_config.php DELETED
@@ -1,28 +0,0 @@
1
- <?php
2
- // Get or Save a store config value
3
- // This will make a new db connection so it's guaranteed not to result in connection-timeout
4
-
5
- define('MAGENTO', realpath(dirname(__FILE__)));
6
- require_once MAGENTO . '/../../../../../../app/Mage.php';
7
-
8
- $store_id = $argv[1];
9
- $get_save = $argv[2];
10
- $key = $argv[3];
11
-
12
- try {
13
- Mage::app()->setCurrentStore($store_id);
14
-
15
- $result = '';
16
- if ($get_save == 'GET'){
17
- $result = Mage::getStoreConfig($key);
18
- echo $result;
19
- } else if ($get_save == 'SAVE'){
20
- $val = $argv[4];
21
- $result = Mage::getModel('core/config')->saveConfig($key, $val);
22
- }
23
- die(0);
24
- } catch (Exception $e){
25
- Mage::logException($e);
26
- die(1);
27
- }
28
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/code/community/RetentionScience/Waves/Model/rs_send_categories.php DELETED
@@ -1,27 +0,0 @@
1
- <?php
2
- // Generates all the categories in a separate PHP process for memory efficiency
3
-
4
- define('MAGENTO', realpath(dirname(__FILE__)));
5
- require_once MAGENTO . '/../../../../../../app/Mage.php';
6
-
7
- $store_id = $argv[1];
8
- $timestamp = $argv[2];
9
-
10
- try {
11
- Mage::app()->setCurrentStore($store_id);
12
- $observer = new RetentionScience_Waves_Model_Observer();
13
- $categorytree = Mage::getModel('waves/source_categorytree')->getAllOptions();
14
-
15
- foreach($categorytree as $category){
16
- $parentId = ($category->getParentId())?$category->getParentId():null;
17
- $categoryId = $category->getEntityId();
18
- $categoryName = $category->getName();
19
- $categoryDescription = $category->getDescripton();
20
- $category_array = array('name' => $categoryName, 'description' => $categoryDescription, 'parent_record_id' => $parentId);
21
- $observer->writeBulkUploadFile(array($categoryId => $category_array), 'categories', $timestamp);
22
- }
23
- die(0);
24
- } catch (Exception $e){
25
- Mage::logException($e);
26
- die(1);
27
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/code/community/RetentionScience/Waves/Model/rs_send_orders.php DELETED
@@ -1,38 +0,0 @@
1
- <?php
2
- // Generates all the orders in a separate PHP process for memory efficiency
3
-
4
- define('MAGENTO', realpath(dirname(__FILE__)));
5
- require_once MAGENTO . '/../../../../../../app/Mage.php';
6
-
7
- $store_id = $argv[1];
8
- $timestamp = $argv[2];
9
- $page_counter = $argv[3];
10
- $last_order_record_id = $argv[4];
11
-
12
- Mage::app()->setCurrentStore($store_id);
13
-
14
-
15
-
16
- $observer = new RetentionScience_Waves_Model_Observer();
17
- $elements_per_page = $observer->elementsPerPage();
18
- $orderCollection = Mage::getModel('sales/order')->getCollection();
19
- $orderCollection->addAttributeToSelect('entity_id');
20
- if($last_order_record_id>0){
21
- $orderCollection->addFieldToFilter('entity_id', array('gt'=>$last_order_record_id));
22
- }
23
-
24
- $orderCollection->setPage($page_counter, $elements_per_page);
25
-
26
- try {
27
- foreach($orderCollection as $order){
28
- $observer->orderCallback(array('order_record_id' => $order->getEntityId(), 'timestamp' => $timestamp));
29
- }
30
- echo $observer->get_last_processed_order_record_id();
31
- die(0);
32
-
33
- } catch (Exception $e){
34
- Mage::logException($e);
35
- echo $observer->get_last_processed_order_record_id();
36
- die(1);
37
- }
38
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/code/community/RetentionScience/Waves/Model/rs_send_products.php DELETED
@@ -1,34 +0,0 @@
1
- <?php
2
- // Generates all the items in a separate PHP process for memory efficiency
3
-
4
- define('MAGENTO', dirname(__FILE__));
5
- require_once MAGENTO . '/../../../../../../app/Mage.php';
6
-
7
- $store_id = $argv[1];
8
- $timestamp = $argv[2];
9
- $page_counter = $argv[3];
10
-
11
- Mage::app()->setCurrentStore($store_id);
12
- $observer = new RetentionScience_Waves_Model_Observer();
13
- $elements_per_page = $observer->elementsPerPage();
14
-
15
- // Retrieve products collection
16
- // Note: we use our own model for ProductCollection because this selects all rows from the catalog_product_entity
17
- // table rather than only selecting those values in the catalog_product_flat_1 (flattened) table.
18
- // There were some products that were not being captured because they were not enabled or not simple products
19
- $productCollection = new RetentionScience_Waves_Model_Mysql4_Product_Collection();
20
- $productCollection->setPage($page_counter, $elements_per_page);
21
-
22
- try {
23
- foreach($productCollection as $product){
24
- $observer->productCallback(array('product_id' => $product->getId(), 'timestamp' => $timestamp));
25
- }
26
- echo $observer->get_last_processed_product_entity_id();
27
- die(0);
28
-
29
- } catch (Exception $e){
30
- Mage::logException($e);
31
- echo $observer->get_last_processed_product_entity_id();
32
- die(1);
33
- }
34
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/code/community/RetentionScience/Waves/Model/rs_send_users.php DELETED
@@ -1,37 +0,0 @@
1
- <?php
2
- // Generates all the users in a separate PHP process for memory efficiency
3
-
4
- define('MAGENTO', realpath(dirname(__FILE__)));
5
- require_once MAGENTO . '/../../../../../../app/Mage.php';
6
-
7
- $store_id = $argv[1];
8
- $timestamp = $argv[2];
9
- $page_counter = $argv[3];
10
- $last_user_record_id = $argv[4];
11
-
12
- Mage::app()->setCurrentStore($store_id);
13
-
14
- $observer = new RetentionScience_Waves_Model_Observer();
15
- $elements_per_page = $observer->elementsPerPage();
16
-
17
- // Retrieves the user collection
18
- $userCollection = Mage::getModel('customer/customer')->getCollection();
19
- $userCollection->addAttributeToSelect('entity_id');
20
- if($last_user_record_id>0){
21
- $userCollection->addFieldToFilter('entity_id', array('gt'=>$last_user_record_id));
22
- }
23
- $userCollection->setPage($page_counter, $elements_per_page);
24
-
25
- try {
26
- foreach($userCollection as $user){
27
- $observer->userCallback(array('user_record_id' => $user->getEntityId(), 'timestamp' => $timestamp));
28
- }
29
- echo $observer->get_last_processed_user_entity_id();
30
- die(0);
31
-
32
- } catch (Exception $e){
33
- Mage::logException($e);
34
- echo $observer->get_last_processed_user_entity_id();
35
- die(1);
36
- }
37
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/code/community/RetentionScience/Waves/Model/rs_sync_data.php DELETED
@@ -1,201 +0,0 @@
1
- <?php
2
- // Runs the sync which will generate all the different file types.
3
- // Each is done in a separate PHP process for memory efficiency when dealing with extremely large data exports
4
- // This is much faster and memory efficient than running via 1 single process
5
-
6
- define('MAGENTO', dirname(__FILE__));
7
- require_once MAGENTO . '/../../../../../../app/Mage.php';
8
-
9
- $last_processed_order_record_id;
10
- $last_processed_user_entity_id;
11
- $last_processed_product_entity_id;
12
-
13
- $timestamp = date("YmdHis");
14
- $store_id = $argv[1];
15
- $observer = new RetentionScience_Waves_Model_Observer();
16
- $phpBin = $observer->getPhpBin();
17
- $elementsPerPage = $observer->elementsPerPage();
18
-
19
- // Scripts to export data
20
- $send_orders_script = escapeshellarg(dirname(__FILE__) . "/rs_send_orders.php");
21
- $send_products_script = escapeshellarg(dirname(__FILE__) . "/rs_send_products.php");
22
- $send_users_script = escapeshellarg(dirname(__FILE__) . "/rs_send_users.php");
23
- $rs_send_categories_script = escapeshellarg(dirname(__FILE__) . "/rs_send_categories.php");
24
- $get_save_config_script = escapeshellarg(dirname(__FILE__) . "/rs_get_save_config.php");
25
-
26
- // get / save functions to access the Magento config
27
- function getStoreConfig($key) {
28
- global $phpBin;
29
- global $get_save_config_script;
30
- global $store_id;
31
- $output = array();
32
- $return_val = null;
33
- $cmd = "$phpBin $get_save_config_script $store_id GET '" . $key . "'";
34
- exec($cmd, $output, $return_val);
35
- return $output[0];
36
- }
37
-
38
- function saveStoreConfig($key, $val) {
39
- global $phpBin;
40
- global $get_save_config_script;
41
- global $store_id;
42
- $output = array();
43
- $return_val = null;
44
- $cmd = "$phpBin $get_save_config_script $store_id SAVE '" . $key . "' '" . $val . "'";
45
- exec($cmd, $output, $return_val);
46
- return $output[0];
47
- }
48
-
49
- $syncDataStatus = getStoreConfig('waves/rs_sync_settings/sync_data_status');
50
- // If it's already running, just exit
51
- if(stristr($syncDataStatus, "running")){
52
- die(1);
53
- }
54
-
55
- // Perform all counts up front, so we don't need to make any further MySQL connections in this script
56
- try {
57
- saveStoreConfig('waves/rs_sync_settings/sync_data_status', '[running] Calculating counts at: ' . date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(time())));
58
-
59
- // Count Orders
60
- $last_order_record_id = (int) getStoreConfig('waves/rs_sync_advanced/last_order_record_id');
61
- $orderCollection = Mage::getModel('sales/order')->getCollection();
62
- if($last_order_record_id>0){
63
- $orderCollection->addFieldToFilter('entity_id', array('gt' => $last_order_record_id));
64
- }
65
- $num_orders_to_send = $orderCollection->getSize(); // Don't use count()
66
-
67
- // Count Users
68
- $last_user_record_id = (int) getStoreConfig('waves/rs_sync_advanced/last_user_record_id');
69
- $userCollection = Mage::getModel('customer/customer')
70
- ->getCollection()
71
- ->addAttributeToSelect('name')
72
- ->addAttributeToSelect('*');
73
- if($last_user_record_id>0){
74
- $userCollection->addFieldToFilter('entity_id', array('gt' => $last_user_record_id));
75
- }
76
- $num_users_to_send = $userCollection->getSize(); // Don't use count()
77
-
78
- // Count Products
79
- $productCollection = Mage::getModel('catalog/product')->getCollection()->addAttributeToSelect('*');
80
- $num_products_to_send = $productCollection->getSize();
81
-
82
-
83
- } catch(Exception $e) {
84
- Mage::logException($e);
85
- saveStoreConfig('waves/rs_sync_settings/sync_data_status', '[stopped] error performing counts at: ' . date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(time())));
86
- die(1);
87
- }
88
-
89
- // Export Orders
90
- try{
91
- saveStoreConfig('waves/rs_sync_settings/sync_data_status', '[running] exporting orders - last updated at: ' . date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(time())));
92
-
93
- // this will be updated as we iterate
94
- $last_processed_order_record_id = $last_order_record_id;
95
-
96
- $pages = ceil($num_orders_to_send / $elementsPerPage);
97
- $page_counter = 1;
98
-
99
- while($page_counter <= $pages){
100
- $cmd = "$phpBin $send_orders_script $store_id $timestamp $page_counter $last_order_record_id";
101
- $output = array();
102
- $return_val = null;
103
- exec($cmd, $output, $return_val);
104
- if ($return_val != 0){
105
- var_dump($output);
106
- throw new Exception('Send orders script returned with non-zero return code.');
107
- } else {
108
- $last_processed_order_record_id = $output[0];
109
- }
110
- $page_counter = $page_counter + 1;
111
- }
112
-
113
- } catch(Exception $e) {
114
- Mage::logException($e);
115
- saveStoreConfig('waves/rs_sync_settings/sync_data_status', '[stopped] error on orders at: ' . date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(time())));
116
- die(1);
117
- }
118
-
119
- // Export Users
120
- try {
121
- saveStoreConfig('waves/rs_sync_settings/sync_data_status', '[running] exporting users - last updated at: ' . date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(time())));
122
-
123
-
124
- $pages = ceil($num_users_to_send / $elementsPerPage);
125
- $page_counter = 1;
126
-
127
- while($page_counter <= $pages){
128
- $cmd = "$phpBin $send_users_script $store_id $timestamp $page_counter $last_user_record_id";
129
- $output = array();
130
- $return_val = null;
131
- exec($cmd, $output, $return_val);
132
- if ($return_val != 0){
133
- var_dump($output);
134
- throw new Exception('Send users script returned with non-zero return code.');
135
- } else {
136
- $last_processed_user_record_id = $output[0];
137
- }
138
- $page_counter = $page_counter + 1;
139
- }
140
- } catch (Exception $e){
141
- Mage::logException($e);
142
- saveStoreConfig('waves/rs_sync_settings/sync_data_status', '[stopped] error on users at: ' . date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(time())));
143
- die(1);
144
- }
145
-
146
- // Export Products
147
- try{
148
- saveStoreConfig('waves/rs_sync_settings/sync_data_status', '[running] exporting products - last updated at: ' . date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(time())));
149
-
150
- $pages = ceil($num_products_to_send / $elementsPerPage);
151
- $page_counter = 1;
152
-
153
- while($page_counter <= $pages){
154
- $cmd = "$phpBin $send_products_script $store_id $timestamp $page_counter";
155
- $output = array();
156
- $return_val = null;
157
- exec($cmd, $output, $return_val);
158
- if ($return_val != 0){
159
- var_dump($output);
160
- throw new Exception('Send products script returned with non-zero return code.');
161
- }
162
- $page_counter = $page_counter + 1;
163
- }
164
- } catch (Exception $e){
165
- Mage::logException($e);
166
- saveStoreConfig('waves/rs_sync_settings/sync_data_status', '[stopped] error on products at: ' . date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(time())));
167
- die(1);
168
- }
169
-
170
- // Export Categories
171
- try {
172
- saveStoreConfig('waves/rs_sync_settings/sync_data_status', '[running] exporting categories - last updated at: ' . date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(time())));
173
-
174
- $output = array();
175
- $return_val = null;
176
- $cmd = "$phpBin $rs_send_categories_script $store_id $timestamp";
177
- exec($cmd, $output, $return_val);
178
- if ($return_val != 0){
179
- var_dump($output);
180
- throw new Exception('Send categories script returned with non-zero return code.');
181
- }
182
-
183
- } catch (Exception $e) {
184
- Mage::logException($e);
185
- saveStoreConfig('waves/rs_sync_settings/sync_data_status', '[stopped] error on categories at: ' . date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(time())) );
186
- die(1);
187
- }
188
-
189
- // Send to rs api
190
- try {
191
- $observer->sendDataSyncFiles($timestamp);
192
- } catch (Exception $e) {
193
- Mage::logException($e);
194
- saveStoreConfig('waves/rs_sync_settings/sync_data_status', '[stopped] error on upload at: ' . date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(time())) );
195
- die(1);
196
- }
197
-
198
- // Update last exported IDs and status
199
- saveStoreConfig('waves/rs_sync_advanced/last_order_record_id', $last_processed_order_record_id);
200
- saveStoreConfig('waves/rs_sync_advanced/last_user_record_id', $last_processed_user_record_id);
201
- saveStoreConfig('waves/rs_sync_settings/sync_data_status', '[stopped] last run at: '. date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(time())));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/code/community/RetentionScience/Waves/controllers/AdminController.php DELETED
@@ -1,15 +0,0 @@
1
- <?php
2
- class RetentionScience_Waves_AdminController extends Mage_Adminhtml_Controller_Action
3
- {
4
- public function updateRScoreAction() {
5
- $obj = new RetentionScience_Waves_Model_Observer();
6
- $rscore_json = $obj->updateRScore();
7
- die($rscore_json);
8
- }
9
-
10
- public function syncDataAction() {
11
- $obj = new RetentionScience_Waves_Model_Observer();
12
- $obj->syncData();
13
- $this->_redirectUrl(Mage::helper('adminhtml')->getUrl("adminhtml/system_config/edit/section/waves/"));
14
- }
15
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/code/community/RetentionScience/Waves/controllers/Adminhtml/WavesController.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class RetentionScience_Waves_Adminhtml_WavesController extends Mage_Adminhtml_Controller_Action {
4
+
5
+ public function updateRScoreAction() {
6
+ $rscore = Mage::helper('waves')->getRScore();
7
+ echo Zend_Json::encode($rscore);
8
+ }
9
+
10
+ public function syncDataAction() {
11
+
12
+ try {
13
+ Mage::getSingleton('waves/connection_awsCloudWatch')->logMessage("SyncData Button - button clicked");
14
+
15
+ $event = new Varien_Object();
16
+
17
+ $event->setData(array(
18
+ 'type' => 'batch',
19
+ 'groups' => 'all',
20
+ ));
21
+
22
+ $event->setSource('magento_admin');
23
+
24
+ Mage::dispatchEvent('waves_init_export', array(
25
+ 'event' => $event,
26
+ ));
27
+
28
+ Mage::getSingleton('waves/connection_awsCloudWatch')->logMessage("SyncData Button - Data successfully exported");
29
+
30
+ Mage::getSingleton('core/session')->addSuccess('Data successfully exported');
31
+
32
+ } catch(Exception $e) {
33
+ Mage::getSingleton('waves/connection_awsCloudWatch')->logMessage("SyncData Button - Exception: " . $e->getMessage());
34
+
35
+ Mage::getSingleton('core/session')->addError('Error: ' . $e->getMessage());
36
+ }
37
+
38
+ $this->_redirectUrl(Mage::helper('adminhtml')->getUrl("adminhtml/system_config/edit/section/waves/"));
39
+
40
+ }
41
+
42
+ }
app/code/community/RetentionScience/Waves/controllers/{IndexController.php → Frontend/IndexController.php} RENAMED
@@ -1,19 +1,19 @@
1
  <?php
2
- class RetentionScience_Waves_IndexController extends Mage_Core_Controller_Front_Action
3
- {
4
- public function scriptRunAction(){
5
- $status = Mage::getStoreConfig('waves/retentionscience_settings/enable');
6
- $siteID = Mage::getStoreConfig('waves/retentionscience_settings/site_id');
7
- if($status && $siteID){
8
 
9
- $result['siteID'] = $siteID;
 
 
 
 
 
 
10
  $result['customerId'] = "";
11
  if(Mage::getSingleton('customer/session')->isLoggedIn()){
12
  $customerId = Mage::getSingleton('customer/session')->getCustomerId();
13
  $result['customerId'] = $customerId;
14
  }
15
-
16
-
17
  $allItems = Mage::getModel('checkout/cart')->getQuote()->getAllVisibleItems();
18
  $items = array();
19
  $count = 0;
@@ -28,4 +28,5 @@ class RetentionScience_Waves_IndexController extends Mage_Core_Controller_Front_
28
  die();
29
  }
30
  }
 
31
  }
1
  <?php
 
 
 
 
 
 
2
 
3
+ class RetentionScience_Waves_Frontend_IndexController extends Mage_Core_Controller_Front_Action {
4
+
5
+ public function indexAction(){
6
+ $helper = Mage::helper('waves');
7
+ if($helper->isEnabled() && $helper->getStoreId() == Mage::app()->getStore()->getId()){
8
+
9
+ $result['siteID'] = $helper->getWebsiteId();
10
  $result['customerId'] = "";
11
  if(Mage::getSingleton('customer/session')->isLoggedIn()){
12
  $customerId = Mage::getSingleton('customer/session')->getCustomerId();
13
  $result['customerId'] = $customerId;
14
  }
15
+
16
+
17
  $allItems = Mage::getModel('checkout/cart')->getQuote()->getAllVisibleItems();
18
  $items = array();
19
  $count = 0;
28
  die();
29
  }
30
  }
31
+
32
  }
app/code/community/RetentionScience/Waves/etc/adminhtml.xml CHANGED
@@ -1,23 +1,23 @@
1
- <?xml version="1.0"?>
2
- <config>
3
- <acl>
4
- <resources>
5
- <admin>
6
- <children>
7
- <system>
8
- <children>
9
- <config>
10
- <children>
11
- <waves translate="title">
12
- <title>Retention Science</title>
13
- <sort_order>60</sort_order>
14
- </waves>
15
- </children>
16
- </config>
17
- </children>
18
- </system>
19
- </children>
20
- </admin>
21
- </resources>
22
- </acl>
23
- </config>
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <acl>
4
+ <resources>
5
+ <admin>
6
+ <children>
7
+ <system>
8
+ <children>
9
+ <config>
10
+ <children>
11
+ <waves translate="title">
12
+ <title>Retention Science</title>
13
+ <sort_order>60</sort_order>
14
+ </waves>
15
+ </children>
16
+ </config>
17
+ </children>
18
+ </system>
19
+ </children>
20
+ </admin>
21
+ </resources>
22
+ </acl>
23
+ </config>
app/code/community/RetentionScience/Waves/etc/cache.xml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <placeholders>
4
+ <waves>
5
+ <block>waves/waves</block>
6
+ <name>waves_waves</name>
7
+ <placeholder>WAVES</placeholder>
8
+ <container>RetentionScience_Waves_Model_Container_Waves</container>
9
+ <cache_lifetime>0</cache_lifetime>
10
+ </waves>
11
+ </placeholders>
12
+ </config>
app/code/community/RetentionScience/Waves/etc/config.xml CHANGED
@@ -1,102 +1,115 @@
1
- <?xml version="1.0"?>
2
- <config>
3
- <modules>
4
- <RetentionScience_Waves>
5
- <version>2.3.0</version>
6
- </RetentionScience_Waves>
7
- </modules>
8
- <global>
9
- <helpers>
10
- <waves><class>RetentionScience_Waves_Helper</class></waves>
11
- </helpers>
12
- <blocks>
13
- <waves><class>RetentionScience_Waves_Block</class></waves>
14
- </blocks>
15
- <models>
16
- <waves><class>RetentionScience_Waves_Model</class></waves>
17
- </models>
18
- </global>
19
- <frontend>
20
- <routers>
21
- <waves>
22
- <use>standard</use>
23
- <args>
24
- <module>RetentionScience_Waves</module>
25
- <frontName>waves</frontName>
26
- </args>
27
- </waves>
28
- </routers>
29
- <layout>
30
- <updates>
31
- <waves>
32
- <file>waves.xml</file>
33
- </waves>
34
- </updates>
35
- </layout>
36
- </frontend>
37
- <admin>
38
- <routers>
39
- <waves>
40
- <use>admin</use>
41
- <args>
42
- <module>RetentionScience_Waves</module>
43
- <frontName>waves</frontName>
44
- </args>
45
- </waves>
46
- </routers>
47
- <layout>
48
- <updates>
49
- <waves>
50
- <file>waves.xml</file>
51
- </waves>
52
- </updates>
53
- </layout>
54
- </admin>
55
-
56
- <crontab>
57
- <jobs>
58
- <retentionscience_waves_syncdata>
59
- <run>
60
- <model>waves/observer::syncData</model>
61
- </run>
62
- </retentionscience_waves_syncdata>
63
- </jobs>
64
- </crontab>
65
-
66
- <default>
67
- <waves>
68
- <rs_sync_settings>
69
- <sync_data_cron>0 2 * * *</sync_data_cron>
70
- </rs_sync_settings>
71
-
72
- <rs_sync_advanced>
73
- <rs_php_bin>php</rs_php_bin>
74
- <rs_send_bulk_upload>1</rs_send_bulk_upload>
75
- <rs_use_bulk_compression>1</rs_use_bulk_compression>
76
- <last_user_record_id>0</last_user_record_id>
77
- <last_order_record_id>0</last_order_record_id>
78
- </rs_sync_advanced>
79
- </waves>
80
- </default>
81
-
82
- <adminhtml>
83
- <events>
84
- <core_block_abstract_prepare_layout_after>
85
- <observers>
86
- <retentionscience_waves>
87
- <class>RetentionScience_Waves_Model_Observer</class>
88
- <method>coreBlockAbstractPrepareLayoutAfter</method>
89
- </retentionscience_waves>
90
- </observers>
91
- </core_block_abstract_prepare_layout_after>
92
- <core_block_abstract_to_html_after>
93
- <observers>
94
- <retentionscience_waves>
95
- <class>RetentionScience_Waves_Model_Observer</class>
96
- <method>coreBlockAbstractToHtmlAfter</method>
97
- </retentionscience_waves>
98
- </observers>
99
- </core_block_abstract_to_html_after>
100
- </events>
101
- </adminhtml>
102
- </config>
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <RetentionScience_Waves>
5
+ <version>3.0.1</version>
6
+ </RetentionScience_Waves>
7
+ </modules>
8
+ <global>
9
+ <helpers>
10
+ <waves>
11
+ <class>RetentionScience_Waves_Helper</class>
12
+ </waves>
13
+ </helpers>
14
+ <models>
15
+ <waves>
16
+ <class>RetentionScience_Waves_Model</class>
17
+ </waves>
18
+ </models>
19
+ <blocks>
20
+ <waves>
21
+ <class>RetentionScience_Waves_Block</class>
22
+ </waves>
23
+ </blocks>
24
+ <events>
25
+ <waves_init_export>
26
+ <observers>
27
+ <waves_perform_export_observer>
28
+ <type>singleton</type>
29
+ <class>RetentionScience_Waves_Model_Observer</class>
30
+ <method>performExport</method>
31
+ </waves_perform_export_observer>
32
+ </observers>
33
+ </waves_init_export>
34
+ </events>
35
+ </global>
36
+ <frontend>
37
+ <layout>
38
+ <updates>
39
+ <waves>
40
+ <file>waves.xml</file>
41
+ </waves>
42
+ </updates>
43
+ </layout>
44
+ <routers>
45
+ <waves>
46
+ <use>standard</use>
47
+ <args>
48
+ <module>RetentionScience_Waves_Frontend</module>
49
+ <frontName>waves</frontName>
50
+ </args>
51
+ </waves>
52
+ </routers>
53
+ <events>
54
+ <checkout_onepage_controller_success_action>
55
+ <observers>
56
+ <waves_order_success>
57
+ <class>waves/observer_default</class>
58
+ <method>setWavesOnOrderSuccessPageView</method>
59
+ </waves_order_success>
60
+ </observers>
61
+ </checkout_onepage_controller_success_action>
62
+ <checkout_multishipping_controller_success_action>
63
+ <observers>
64
+ <waves_order_success>
65
+ <class>waves/observer_default</class>
66
+ <method>setWavesOnOrderSuccessPageView</method>
67
+ </waves_order_success>
68
+ </observers>
69
+ </checkout_multishipping_controller_success_action>
70
+ </events>
71
+ </frontend>
72
+ <admin>
73
+ <routers>
74
+ <adminhtml>
75
+ <args>
76
+ <modules>
77
+ <RetentionScience_Waves after="Mage_Adminhtml">RetentionScience_Waves_Adminhtml</RetentionScience_Waves>
78
+ </modules>
79
+ </args>
80
+ </adminhtml>
81
+ </routers>
82
+ </admin>
83
+ <adminhtml>
84
+ <events>
85
+ <controller_action_predispatch_adminhtml_system_config_save>
86
+ <observers>
87
+ <waves_system_config_save>
88
+ <type>singleton</type>
89
+ <class>waves/configfieldlistener</class>
90
+ <method>logParameters</method>
91
+ </waves_system_config_save>
92
+ </observers>
93
+ </controller_action_predispatch_adminhtml_system_config_save>
94
+ </events>
95
+ </adminhtml>
96
+ <crontab>
97
+ <jobs>
98
+ <retentionscience_waves_syncdata>
99
+ <run>
100
+ <model>waves/cron::export</model>
101
+ </run>
102
+ </retentionscience_waves_syncdata>
103
+ </jobs>
104
+ </crontab>
105
+ <default>
106
+ <waves>
107
+ <rs_sync_settings>
108
+ <sync_data_cron>0 2 * * *</sync_data_cron>
109
+ </rs_sync_settings>
110
+ <rs_sync_advanced>
111
+ <rs_use_bulk_compression>1</rs_use_bulk_compression>
112
+ </rs_sync_advanced>
113
+ </waves>
114
+ </default>
115
+ </config>
app/code/community/RetentionScience/Waves/etc/system.xml CHANGED
@@ -1,210 +1,169 @@
1
- <?xml version="1.0"?>
2
- <config>
3
-
4
-
5
- <tabs>
6
- <retentionsciencetab translate="label" module="waves">
7
- <label>Retention Science</label>
8
- <sort_order>400</sort_order>
9
- </retentionsciencetab>
10
- </tabs>
11
-
12
- <sections>
13
- <waves translate="label" module="waves">
14
- <label>Retention Science</label>
15
- <tab>retentionsciencetab</tab>
16
- <frontend_type>text</frontend_type>
17
- <sort_order>50</sort_order>
18
- <show_in_default>1</show_in_default>
19
- <show_in_website>1</show_in_website>
20
- <show_in_store>1</show_in_store>
21
- <groups>
22
- <rscore translate="label">
23
- <label>Retention Score</label>
24
- <sort_order>0</sort_order>
25
- <show_in_default>1</show_in_default>
26
- <show_in_website>1</show_in_website>
27
- <show_in_store>1</show_in_store>
28
- <frontend_type>text</frontend_type>
29
- <frontend_model>waves/adminhtml_rscore</frontend_model>
30
- </rscore>
31
-
32
- <retentionscience_settings translate="label">
33
- <label>Basic Settings</label>
34
- <sort_order>1</sort_order>
35
- <show_in_default>1</show_in_default>
36
- <show_in_website>1</show_in_website>
37
- <show_in_store>1</show_in_store>
38
- <fields>
39
- <enable translate="label">
40
- <label>Retention Science enabled</label>
41
- <frontend_type>select</frontend_type>
42
- <source_model>adminhtml/system_config_source_yesno</source_model>
43
- <sort_order>10</sort_order>
44
- <show_in_default>1</show_in_default>
45
- <show_in_website>1</show_in_website>
46
- <show_in_store>1</show_in_store>
47
- </enable>
48
-
49
- <api_user translate="label">
50
- <label>API User</label>
51
- <frontend_type>text</frontend_type>
52
- <sort_order>15</sort_order>
53
- <show_in_default>1</show_in_default>
54
- <show_in_website>1</show_in_website>
55
- <show_in_store>1</show_in_store>
56
- </api_user>
57
- <api_pass translate="label">
58
- <label>API Password</label>
59
- <frontend_type>text</frontend_type>
60
- <sort_order>16</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
- </api_pass>
65
- <testmode translate="label">
66
- <label>Test Mode</label>
67
- <frontend_type>select</frontend_type>
68
- <source_model>adminhtml/system_config_source_yesno</source_model>
69
- <sort_order>18</sort_order>
70
- <show_in_default>1</show_in_default>
71
- <show_in_website>1</show_in_website>
72
- <show_in_store>1</show_in_store>
73
- </testmode>
74
- <ajaxaddtocartenable translate="label">
75
- <label>AJAX add-to-cart support enabled</label>
76
- <frontend_type>select</frontend_type>
77
- <source_model>adminhtml/system_config_source_yesno</source_model>
78
- <sort_order>20</sort_order>
79
- <show_in_default>1</show_in_default>
80
- <show_in_website>1</show_in_website>
81
- <show_in_store>1</show_in_store>
82
- </ajaxaddtocartenable>
83
-
84
- <site_id translate="label">
85
- <label>Site ID</label>
86
- <frontend_type>text</frontend_type>
87
- <sort_order>25</sort_order>
88
- <show_in_default>1</show_in_default>
89
- <show_in_website>1</show_in_website>
90
- <show_in_store>1</show_in_store>
91
- </site_id>
92
-
93
- <store_id translate="label">
94
- <label>Store</label>
95
- <frontend_type>select</frontend_type>
96
- <source_model>RetentionScience_Waves_Helper_Storeselect</source_model>
97
- <sort_order>30</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
- </store_id>
102
- </fields>
103
- </retentionscience_settings>
104
-
105
-
106
- <rs_sync_settings translate="label">
107
- <label>Sync Settings</label>
108
- <sort_order>2</sort_order>
109
- <show_in_default>1</show_in_default>
110
- <show_in_website>1</show_in_website>
111
- <show_in_store>1</show_in_store>
112
- <fields>
113
-
114
- <sync_data_status translate="label">
115
- <label>Data Sync Status</label>
116
- <frontend_type>text</frontend_type>
117
- <sort_order>37</sort_order>
118
- <show_in_default>1</show_in_default>
119
- <show_in_website>1</show_in_website>
120
- <show_in_store>1</show_in_store>
121
- </sync_data_status>
122
-
123
- <sync_data_cron translate="label">
124
- <label>Data Sync Cron Entry</label>
125
- <rs_cron_job>retentionscience_waves_syncdata</rs_cron_job>
126
- <frontend_type>text</frontend_type>
127
- <sort_order>38</sort_order>
128
- <backend_model>waves/source_cronconfig</backend_model>
129
- <comment>Use Crontab Format (Eg. "0 10 * * *" for 10AM)</comment>
130
- <show_in_default>1</show_in_default>
131
- <show_in_website>1</show_in_website>
132
- <show_in_store>1</show_in_store>
133
- </sync_data_cron>
134
-
135
- <sync_data_run translate="label">
136
- <label></label>
137
- <rs_button_url>syncdata</rs_button_url>
138
- <frontend_type>button</frontend_type>
139
- <frontend_model>waves/adminhtml_syncbutton</frontend_model>
140
- <sort_order>39</sort_order>
141
- <show_in_default>1</show_in_default>
142
- <show_in_website>1</show_in_website>
143
- <show_in_store>1</show_in_store>
144
- </sync_data_run>
145
- </fields>
146
- </rs_sync_settings>
147
-
148
- <rs_sync_advanced>
149
- <label>Advanced Sync Settings</label>
150
- <sort_order>3</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
- <fields>
155
- <rs_php_bin translate="label">
156
- <label>Location of PHP bin</label>
157
- <frontend_type>text</frontend_type>
158
- <sort_order>95</sort_order>
159
- <show_in_default>1</show_in_default>
160
- <show_in_website>1</show_in_website>
161
- <show_in_store>1</show_in_store>
162
- </rs_php_bin>
163
-
164
- <rs_send_bulk_upload translate="label">
165
- <label>Use bulk upload</label>
166
- <frontend_type>select</frontend_type>
167
- <source_model>adminhtml/system_config_source_yesno</source_model>
168
- <sort_order>96</sort_order>
169
- <show_in_default>1</show_in_default>
170
- <show_in_website>1</show_in_website>
171
- <show_in_store>1</show_in_store>
172
- </rs_send_bulk_upload>
173
-
174
- <rs_use_bulk_compression translate="label">
175
- <label>Use bulk compression</label>
176
- <frontend_type>select</frontend_type>
177
- <source_model>adminhtml/system_config_source_yesno</source_model>
178
- <sort_order>97</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
- </rs_use_bulk_compression>
183
-
184
- <last_user_record_id translate="label">
185
- <label>Last sync'd user record id</label>
186
- <frontend_type>text</frontend_type>
187
- <sort_order>100</sort_order>
188
- <comment>New sync process will start with user record > value</comment>
189
- <show_in_default>1</show_in_default>
190
- <show_in_website>1</show_in_website>
191
- <show_in_store>1</show_in_store>
192
- </last_user_record_id>
193
-
194
- <last_order_record_id translate="label">
195
- <label>Last sync'd order record id</label>
196
- <frontend_type>text</frontend_type>
197
- <sort_order>110</sort_order>
198
- <comment>New sync process will start with order record > value</comment>
199
- <show_in_default>1</show_in_default>
200
- <show_in_website>1</show_in_website>
201
- <show_in_store>1</show_in_store>
202
- </last_order_record_id>
203
- </fields>
204
- </rs_sync_advanced>
205
- </groups>
206
- </waves>
207
- </sections>
208
-
209
-
210
  </config>
1
+ <?xml version="1.0"?>
2
+ <config>
3
+
4
+
5
+ <tabs>
6
+ <retentionsciencetab translate="label" module="waves">
7
+ <label>Retention Science</label>
8
+ <sort_order>400</sort_order>
9
+ </retentionsciencetab>
10
+ </tabs>
11
+
12
+ <sections>
13
+ <waves translate="label" module="waves">
14
+ <label>Retention Science</label>
15
+ <tab>retentionsciencetab</tab>
16
+ <frontend_type>text</frontend_type>
17
+ <sort_order>50</sort_order>
18
+ <show_in_default>1</show_in_default>
19
+ <show_in_website>1</show_in_website>
20
+ <show_in_store>1</show_in_store>
21
+ <groups>
22
+ <!--<rscore translate="label">-->
23
+ <!--<label>Retention Score</label>-->
24
+ <!--<sort_order>0</sort_order>-->
25
+ <!--<show_in_default>1</show_in_default>-->
26
+ <!--<show_in_website>1</show_in_website>-->
27
+ <!--<show_in_store>1</show_in_store>-->
28
+ <!--<frontend_type>text</frontend_type>-->
29
+ <!--<frontend_model>waves/adminhtml_rscore</frontend_model>-->
30
+ <!--</rscore>-->
31
+
32
+ <retentionscience_settings translate="label">
33
+ <label>Basic Settings</label>
34
+ <sort_order>1</sort_order>
35
+ <show_in_default>1</show_in_default>
36
+ <show_in_website>1</show_in_website>
37
+ <show_in_store>1</show_in_store>
38
+ <fields>
39
+ <enable translate="label">
40
+ <label>Retention Science enabled</label>
41
+ <frontend_type>select</frontend_type>
42
+ <source_model>adminhtml/system_config_source_yesno</source_model>
43
+ <sort_order>10</sort_order>
44
+ <show_in_default>1</show_in_default>
45
+ <show_in_website>1</show_in_website>
46
+ <show_in_store>1</show_in_store>
47
+ </enable>
48
+
49
+ <api_user translate="label">
50
+ <label>API User</label>
51
+ <frontend_type>text</frontend_type>
52
+ <sort_order>15</sort_order>
53
+ <show_in_default>1</show_in_default>
54
+ <show_in_website>1</show_in_website>
55
+ <show_in_store>1</show_in_store>
56
+ <validate>required-entry</validate>
57
+ <backend_model>waves/source_credentials</backend_model>
58
+ </api_user>
59
+ <api_pass translate="label">
60
+ <label>API Password</label>
61
+ <frontend_type>text</frontend_type>
62
+ <sort_order>16</sort_order>
63
+ <show_in_default>1</show_in_default>
64
+ <show_in_website>1</show_in_website>
65
+ <show_in_store>1</show_in_store>
66
+ <validate>required-entry</validate>
67
+ <backend_model>waves/source_credentials</backend_model>
68
+ </api_pass>
69
+ <site_id translate="label">
70
+ <label>Site ID</label>
71
+ <frontend_type>label</frontend_type>
72
+ <sort_order>17</sort_order>
73
+ <show_in_default>1</show_in_default>
74
+ <show_in_website>1</show_in_website>
75
+ <show_in_store>1</show_in_store>
76
+ <validate>required-entry</validate>
77
+ </site_id>
78
+ <testmode translate="label">
79
+ <label>Test Mode</label>
80
+ <frontend_type>select</frontend_type>
81
+ <source_model>adminhtml/system_config_source_yesno</source_model>
82
+ <sort_order>18</sort_order>
83
+ <show_in_default>1</show_in_default>
84
+ <show_in_website>1</show_in_website>
85
+ <show_in_store>1</show_in_store>
86
+ <backend_model>waves/source_credentials</backend_model>
87
+ </testmode>
88
+ <ajaxaddtocartenable translate="label">
89
+ <label>AJAX add-to-cart support enabled</label>
90
+ <frontend_type>select</frontend_type>
91
+ <source_model>adminhtml/system_config_source_yesno</source_model>
92
+ <sort_order>20</sort_order>
93
+ <show_in_default>1</show_in_default>
94
+ <show_in_website>1</show_in_website>
95
+ <show_in_store>1</show_in_store>
96
+ </ajaxaddtocartenable>
97
+
98
+ <store_id translate="label">
99
+ <label>Store</label>
100
+ <frontend_type>select</frontend_type>
101
+ <source_model>waves/source_stores</source_model>
102
+ <sort_order>30</sort_order>
103
+ <show_in_default>1</show_in_default>
104
+ <show_in_website>1</show_in_website>
105
+ <show_in_store>1</show_in_store>
106
+ <validate>required-entry</validate>
107
+ </store_id>
108
+ </fields>
109
+ </retentionscience_settings>
110
+
111
+
112
+ <rs_sync_settings translate="label">
113
+ <label>Sync Settings</label>
114
+ <sort_order>2</sort_order>
115
+ <show_in_default>1</show_in_default>
116
+ <show_in_website>1</show_in_website>
117
+ <show_in_store>1</show_in_store>
118
+ <fields>
119
+
120
+ <sync_data_cron translate="label">
121
+ <label>Data Sync Cron Entry</label>
122
+ <rs_cron_job>retentionscience_waves_syncdata</rs_cron_job>
123
+ <frontend_type>text</frontend_type>
124
+ <sort_order>38</sort_order>
125
+ <backend_model>waves/source_cronconfig</backend_model>
126
+ <comment>Use Crontab Format (Eg. "0 10 * * *" for 10AM)</comment>
127
+ <show_in_default>1</show_in_default>
128
+ <show_in_website>1</show_in_website>
129
+ <show_in_store>1</show_in_store>
130
+ <validate>required-entry</validate>
131
+ </sync_data_cron>
132
+
133
+ <sync_data_run translate="label">
134
+ <label></label>
135
+ <rs_button_url>syncdata</rs_button_url>
136
+ <frontend_type>button</frontend_type>
137
+ <frontend_model>waves/adminhtml_syncbutton</frontend_model>
138
+ <sort_order>39</sort_order>
139
+ <show_in_default>1</show_in_default>
140
+ <show_in_website>1</show_in_website>
141
+ <show_in_store>1</show_in_store>
142
+ </sync_data_run>
143
+ </fields>
144
+ </rs_sync_settings>
145
+
146
+ <rs_sync_advanced>
147
+ <label>Advanced Sync Settings</label>
148
+ <sort_order>3</sort_order>
149
+ <show_in_default>1</show_in_default>
150
+ <show_in_website>1</show_in_website>
151
+ <show_in_store>1</show_in_store>
152
+ <fields>
153
+ <rs_use_bulk_compression translate="label">
154
+ <label>Use bulk compression</label>
155
+ <frontend_type>select</frontend_type>
156
+ <source_model>adminhtml/system_config_source_yesno</source_model>
157
+ <sort_order>97</sort_order>
158
+ <show_in_default>1</show_in_default>
159
+ <show_in_website>1</show_in_website>
160
+ <show_in_store>1</show_in_store>
161
+ </rs_use_bulk_compression>
162
+ </fields>
163
+ </rs_sync_advanced>
164
+ </groups>
165
+ </waves>
166
+ </sections>
167
+
168
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  </config>
app/design/adminhtml/default/default/template/waves/rscore.phtml DELETED
@@ -1,101 +0,0 @@
1
- <?php
2
- $in_config = isset($in_config) && $in_config;
3
- $rscore_json = Mage::getStoreConfig('waves/calculated_rscore_json');
4
- $has_rscore = false;
5
- if (strlen($rscore_json) > 0) {
6
- $rscore_hash = json_decode($rscore_json, true);
7
- $has_rscore = true;
8
- } else { ?>
9
- <script type="text/javascript">
10
- document.observe("dom:loaded", function() {
11
- new Ajax.Request("<?php echo Mage::helper('adminhtml')->getUrl("waves/admin/updaterscore"); ?>", {
12
- onSuccess: function(response) {
13
- rscore_json = response.responseText.evalJSON();
14
- $('rscore-final').update(rscore_json["final"]);
15
- $('rscore-churn').update(rscore_json["churn"]);
16
- $('rscore-engagement').update(rscore_json["engagement"]);
17
- $('rscore-rpr').update(rscore_json["rpr"]);
18
- $('rscore-social-sentiment').update(rscore_json["social_sentiment"]);
19
- }
20
- });
21
- });
22
- </script>
23
- <?php } ?>
24
-
25
- <style>
26
- .rscore-letter {font-weight: bold;}
27
- .entry-rscore {clear: both; overflow: hidden;}
28
- .entry-rscore-left {float: left;}
29
- .entry-rscore-right {float: left; padding: 40px 25px 0;}
30
- </style>
31
-
32
- <?php if (!$in_config) { ?>
33
- </fieldset></div>
34
- <div class="entry-edit">
35
- <?php } else { ?>
36
- <div class="entry-rscore">
37
- <div class="entry-rscore-left">
38
- <?php } ?>
39
- <div class="entry-edit-head"><h4>Your Retention Score</h4></div>
40
- <fieldset class="np">
41
- <div class="grid np">
42
- <table cellspacing="0" style="border:0;">
43
- <colgroup>
44
- <col <?php echo ($in_config ? 'width="150"' : null) ?>/>
45
- <col width="50"/>
46
- <col width="100"/>
47
- </colgroup>
48
- <thead>
49
- <tr class="headings">
50
- <th class="no-link"><span class="nobr">Individual Metrics</span></th>
51
- <th class="no-link"><span class="nobr"></span></th>
52
- <th class="no-link last"><span class="nobr">Overall Grade</span></th>
53
- </tr>
54
- </thead>
55
- <tbody>
56
- <tr class="even">
57
- <td>Customer Churn</td>
58
- <td id="rscore-churn" class="a-center rscore-letter"><?php echo ($has_rscore ? $rscore_hash['churn'] : '?') ?></td>
59
- <td id="rscore-final" class="a-center rscore-letter" rowspan="4" style="background-color:#FFFFFF;color:#67767E;vertical-align:middle;font-size:60px;">
60
- <?php echo ($has_rscore ? $rscore_hash['final'] : '?') ?>
61
- </td>
62
- </tr>
63
- <tr>
64
- <td>Customer Engagement</td>
65
- <td id="rscore-engagement" class="a-center rscore-letter"><?php echo ($has_rscore ? $rscore_hash['engagement'] : '?') ?></td>
66
- </tr>
67
- <tr class="even">
68
- <td>Repeat Purchase Rate</td>
69
- <td id="rscore-rpr" class="a-center rscore-letter"><?php echo ($has_rscore ? $rscore_hash['rpr'] : '?') ?></td>
70
- </tr>
71
- <tr>
72
- <td>Social Sentiment</td>
73
- <td id="rscore-social-sentiment" class="a-center rscore-letter"><?php echo ($has_rscore ? $rscore_hash['social_sentiment'] : '?') ?></td>
74
- </tr>
75
- </tbody>
76
- </table>
77
- </div>
78
- </fieldset>
79
- <?php if ($in_config) { ?>
80
- </div>
81
- <div class="entry-rscore-right">
82
- <?php } ?>
83
- <div style="margin-top:-10px;padding:5px;text-align:center;">
84
- How much revenue are you missing out on?<br/>
85
- Find out how to maximize your customer retention.<br/>
86
- </div>
87
- <div style="text-align:center;">
88
- <?php echo $this->getLayout()->createBlock('adminhtml/widget_button')
89
- ->setType('button')
90
- ->setClass('rscore_signup')
91
- ->setLabel("FREE TRIAL")
92
- ->setOnClick("window.open('http://www.retentionscience.com/magento')")
93
- ->setDisabled(false)
94
- ->toHtml(); ?>
95
- </div>
96
- <?php if ($in_config) { ?>
97
- </div>
98
- </div>
99
- <?php } else { ?>
100
- <fieldset style="display:none;">
101
- <?php } ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/design/frontend/base/default/layout/waves.xml CHANGED
@@ -1,9 +1,8 @@
1
- <?xml version="1.0"?>
2
- <layout version="0.1.0">
3
-
4
- <default>
5
- <reference name="before_body_end">
6
- <block type="waves/waves" name="waves_waves" template="waves/waves.phtml"></block>
7
- </reference>
8
- </default>
9
- </layout>
1
+ <?xml version="1.0"?>
2
+ <layout>
3
+ <default>
4
+ <reference name="before_body_end">
5
+ <block type="waves/waves" name="waves_waves" template="waves/waves.phtml"></block>
6
+ </reference>
7
+ </default>
8
+ </layout>
 
app/design/frontend/base/default/template/waves/waves.phtml CHANGED
@@ -1,69 +1,66 @@
1
- <?php
2
- $status = $this->isEnable();
3
- if ($status && $this->getSiteid()) {
4
- $loggedIn = $this->customerLoggedIn();
5
- $moduleName = $this->getRequest()->getModuleName();
6
- $controllerName = $this->getRequest()->getControllerName();
7
- $actionName = $this->getRequest()->getActionName(); ?>
8
-
9
- <!-- lmca <?php echo $loggedIn ?> | <?php echo $moduleName ?> | <?php echo $controllerName ?> | <?php echo $actionName ?> -->
10
-
11
- <script type="text/javascript">
12
- var _rsq = _rsq || [];
13
- _rsq.push(['_setSiteId', '<?php echo $this->getSiteid();?>']);
14
-
15
- <?php if($loggedIn) {
16
- $user_id_set = $this->customerId(); ?>
17
- _rsq.push(['_setUserId', '<?php echo $user_id_set; ?>']);
18
- <?php }
19
-
20
- if ($moduleName == "catalog" && $controllerName == "product" && $actionName == "view") {
21
- $productId['id'] = $this->getRequest()->getParam('id'); ?>
22
-
23
- _rsq.push(['_addItem', <?php echo json_encode($productId)?>]);
24
- <?php }
25
-
26
- if (($moduleName == "checkout" && $controllerName == "cart" && $actionName == "index") || ($moduleName == "rangepricing" && $controllerName == "checkout_cart" && $actionName == "index")) {
27
- $allItems = Mage::getModel('checkout/cart')->getQuote()->getAllVisibleItems();
28
- foreach ($allItems as $item) {
29
- $itemArr['id'] = $item->getProductId();
30
- $itemArr['name'] = $item->getName();
31
- $itemArr['price'] = $item->getPrice(); ?>
32
- _rsq.push(['_addItem', <?php echo json_encode($itemArr) ?>]);
33
- <?php } ?>
34
- _rsq.push(['_setAction', 'shopping_cart']);
35
- <?php }
36
-
37
- if(($moduleName=="checkout" && $controllerName=="onepage" && $actionName=="success") || ($moduleName=="onestepcheckout" && $controllerName=="index" && $actionName=="success") || ($moduleName=="solecheckout" && $controllerName=="success" && $actionName=="index")){
38
- $order = $this->getOrder();
39
- if (empty($user_id_set)) {
40
- $user_record_id = md5(trim(strtolower($order->getCustomerEmail()))); ?>
41
- // guest
42
- _rsq.push(['_setUserId', '<?php echo $user_record_id; ?>']);
43
- <?php }
44
-
45
- // Use getAllVisibleItems for parent products
46
- // - getAllItems() will have all child products too
47
- $allitems = $order->getAllVisibleItems();
48
- foreach($allitems as $item){
49
- $itemArr['id'] = $item->getProductId();
50
- $itemArr['name'] = $item->getName();
51
- $itemArr['price'] = $item->getPrice(); ?>
52
-
53
- _rsq.push(['_addItem', <?php echo json_encode($itemArr); ?>]);
54
- <?php } ?>
55
-
56
- _rsq.push(['_addOrder', {id: '<?php echo $this->getOrderId();?>', total: '<?php echo $order->getBaseGrandTotal();?>'}]);
57
- _rsq.push(['_setAction', 'checkout_success']);
58
- <?php } ?>
59
-
60
- _rsq.push(['_track']);
61
- (function() { var rScix = document.createElement('script');; rScix.type = 'text/javascript';; rScix.async = true;; rScix.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'd1stxfv94hrhia.cloudfront.net/waves/v2/w.js';; (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(rScix);; })();
62
- </script>
63
- <?php if ($this->isAjaxAddToCartEnable()) { ?>
64
- <script src="<?php echo Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_JS)."RetentionScience/retention_science_wave.js";?>"></script>
65
- <script type="text/javascript">
66
- setAjaxSendCartUrl('<?php echo Mage::getUrl('waves/index/scriptRun') ?>');
67
- </script>
68
- <?php }
69
  }
1
+ <?php
2
+ if ($this->isEnabled()) {
3
+ $loggedIn = $this->customerLoggedIn();
4
+ $moduleName = $this->getRequest()->getModuleName();
5
+ $controllerName = $this->getRequest()->getControllerName();
6
+ $actionName = $this->getRequest()->getActionName();
7
+ $productId = $this->getProductId(); ?>
8
+
9
+ <!-- lmca <?php echo $loggedIn ?> | <?php echo $moduleName ?> | <?php echo $controllerName ?> | <?php echo $actionName ?> -->
10
+
11
+ <script type="text/javascript">
12
+ var _rsq = _rsq || [];
13
+ _rsq.push(['_setSiteId', '<?php echo $this->getSiteId();?>']);
14
+
15
+ <?php if($loggedIn) {
16
+ $user_id_set = $this->customerId(); ?>
17
+ _rsq.push(['_setUserId', '<?php echo $user_id_set; ?>']);
18
+ <?php }
19
+
20
+ if($productId): ?>
21
+ _rsq.push(['_addItem', <?php echo json_encode(array('id'=>$productId))?>]);
22
+ <?php endif;
23
+
24
+ if (($moduleName == "checkout" && $controllerName == "cart" && $actionName == "index") || ($moduleName == "rangepricing" && $controllerName == "checkout_cart" && $actionName == "index")) {
25
+ $allItems = Mage::getModel('checkout/cart')->getQuote()->getAllVisibleItems();
26
+ foreach ($allItems as $item) {
27
+ $itemArr['id'] = $item->getProductId();
28
+ $itemArr['name'] = $item->getName();
29
+ $itemArr['price'] = $item->getPrice(); ?>
30
+ _rsq.push(['_addItem', <?php echo json_encode($itemArr) ?>]);
31
+ <?php } ?>
32
+ _rsq.push(['_setAction', 'shopping_cart']);
33
+ <?php }
34
+
35
+ // If order success page
36
+ $orders = $this->getOrders();
37
+ if(! empty($orders) AND is_array($orders)) {
38
+ foreach($orders AS $order) {
39
+ if (empty($user_id_set)) {
40
+ $user_record_id = md5(trim(strtolower($order->getCustomerEmail()))); ?>
41
+ // guest
42
+ _rsq.push(['_setUserId', '<?php echo $user_record_id; ?>']);
43
+ <?php }
44
+ $allitems = $order->getAllVisibleItems();
45
+ foreach($allitems as $item){
46
+ $itemArr['id'] = $item->getProductId();
47
+ $itemArr['name'] = $item->getName();
48
+ $itemArr['price'] = $item->getPrice(); ?>
49
+
50
+ _rsq.push(['_addItem', <?php echo json_encode($itemArr); ?>]);
51
+ <?php } ?>
52
+ _rsq.push(['_addOrder', {id: '<?php echo $this->getOrderId();?>', total: '<?php echo $order->getBaseGrandTotal();?>'}]);
53
+ _rsq.push(['_setAction', 'checkout_success']); <?php
54
+ }
55
+ } ?>
56
+
57
+ _rsq.push(['_track']);
58
+ (function() { var rScix = document.createElement('script');; rScix.type = 'text/javascript';; rScix.async = true;; rScix.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'd1stxfv94hrhia.cloudfront.net/waves/v2/w.js';; (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(rScix);; })();
59
+ </script>
60
+ <?php if ($this->isAjaxAddToCartEnable()) { ?>
61
+ <script src="<?php echo Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_JS)."waves/waves.js";?>"></script>
62
+ <script type="text/javascript">
63
+ setAjaxSendCartUrl('<?php echo Mage::getUrl('waves') ?>');
64
+ </script>
65
+ <?php }
 
 
 
66
  }
app/etc/modules/RetentionScience_Waves.xml DELETED
@@ -1,9 +0,0 @@
1
- <?xml version="1.0"?>
2
- <config>
3
- <modules>
4
- <RetentionScience_Waves>
5
- <active>true</active>
6
- <codePool>community</codePool>
7
- </RetentionScience_Waves>
8
- </modules>
9
- </config>
 
 
 
 
 
 
 
 
 
js/RetentionScience/retention_science_wave.js DELETED
@@ -1,27 +0,0 @@
1
- var rSciUrl = "";
2
- function setAjaxSendCartUrl(ajax_send_cart_url){
3
- rSciUrl = ajax_send_cart_url;
4
- }
5
-
6
- function retention_science_send_cart(){
7
- if (rSciUrl != "") {
8
- new Ajax.Request(rSciUrl, {
9
- onSuccess: function(transport) {
10
- var json = transport.responseText.evalJSON();
11
-
12
- if (json.customerId != "") {
13
- _rsq.push(['_setUserId', json.customerId]);
14
- }
15
-
16
- items = json.items.evalJSON();
17
- items.each(function(item){
18
- _rsq.push(['_addItem', {id: item.id, name: item.name, price: item.price}]);
19
- });
20
-
21
- _rsq.push(['_setAction', 'shopping_cart']);
22
- _rsq.push(['_track']);
23
- },
24
- method: "get"
25
- });
26
- }
27
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
js/waves/waves.js ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var rSciUrl = "";
2
+ function setAjaxSendCartUrl(ajax_send_cart_url){
3
+ rSciUrl = ajax_send_cart_url;
4
+ }
5
+
6
+ function retention_science_send_cart(){
7
+ if (rSciUrl != "") {
8
+ new Ajax.Request(rSciUrl, {
9
+ onSuccess: function(transport) {
10
+ var json = transport.responseText.evalJSON();
11
+
12
+ if (json.customerId != "") {
13
+ _rsq.push(['_setUserId', json.customerId]);
14
+ }
15
+
16
+ items = json.items.evalJSON();
17
+ items.each(function(item){
18
+ _rsq.push(['_addItem', {id: item.id, name: item.name, price: item.price}]);
19
+ });
20
+
21
+ _rsq.push(['_setAction', 'shopping_cart']);
22
+ _rsq.push(['_track']);
23
+ },
24
+ method: "get"
25
+ });
26
+ }
27
+ }
28
+
29
+ (function() {
30
+ if('Ajax' in window && Ajax && 'Responders' in Ajax) {
31
+ Ajax.Responders.register({
32
+ onComplete: function(ajax) {
33
+ var url = ajax.url;
34
+ var cartAdd = false;
35
+ // Track Amasty
36
+ if(url.match(/amcart\/ajax\/index/)) {
37
+ cartAdd = true;
38
+ }
39
+ // Track AheadWorks
40
+ if(url.match(/checkout\/cart\/add/)) {
41
+ cartAdd = true;
42
+ }
43
+ // Track CmsIdeas
44
+ if(url.match(/ajaxcart/)) {
45
+ cartAdd = true;
46
+ }
47
+ if(cartAdd) {
48
+ retention_science_send_cart();
49
+ }
50
+ }
51
+ });
52
+ }
53
+ }) ();
package.xml CHANGED
@@ -1,26 +1,19 @@
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>RetentionScience_Waves</name>
4
- <version>2.3.0</version>
5
  <stability>stable</stability>
6
  <license uri="http://www.apache.org/licenses/LICENSE-2.0.html">Apache License 2.0</license>
7
  <channel>community</channel>
8
  <extends/>
9
- <summary>Leverage big data analytics and machine learning to optimally retain and re-engage your customers.</summary>
10
- <description>Retention Science helps your store drive sales and maximize customer lifetime value.&#xD;
11
- &#xD;
12
- We have created the first ever personalized retention marketing platform to help you understand and target each customer individually.&#xD;
13
- &#xD;
14
- We leverage big data analytics and machine learning to optimize retention strategies, provide product recommendations, and generate targeted discounts and promotional offers. &#xD;
15
- &#xD;
16
- Our technology enables your store to leverage massive social media, demographic, and behavioral datasets - powerful information sources to help you drive sales. &#xD;
17
- &#xD;
18
- Notes: This extension interfaces with Retention Science, and communicates through the Retention Science API. For more information, and to sign up for API access, please see http://retentionscience.com.</description>
19
- <notes>Default using compression, visible items, and using our new product collection model</notes>
20
- <authors><author><name>Retention Science</name><user>auto-converted</user><email>support@retentionscience.com</email></author></authors>
21
- <date>2013-07-30</date>
22
- <time>19:50:24</time>
23
- <contents><target name="magecommunity"><dir name="RetentionScience"><dir name="Waves"><dir name="Block"><dir name="Adminhtml"><file name="Rscore.php" hash="ddaa6fcc9b7c7448ca4546e28ded58f3"/><file name="Syncbutton.php" hash="f0e364d31e12bffd40a13e88bce3bc97"/></dir><file name="Waves.php" hash="e40dffc0ab52847e560182196a252291"/></dir><dir name="Helper"><file name="Data.php" hash="90490af254a670d4795b744c1ef4319e"/><file name="Storeselect.php" hash="dbfeb7a4e9e1f5c52fdbc2eac9370fcf"/></dir><dir name="Model"><dir name="Mysql4"><dir name="Product"><file name="Collection.php" hash="8015a634da59c97e797355abc44b8268"/></dir></dir><dir name="Source"><dir name="Cron"><file name="Frequency.php" hash="027feb7796f79b7cf811c4236ad7b87a"/><file name="Hours.php" hash="0ab9157003d5e7efed402ed401a46134"/></dir><file name="Categorytree.php" hash="8911fb34a76fed31b9e20a6a9fea0712"/><file name="Cronconfig.php" hash="f2dd3dcd572bd7407663576e250f9d23"/><file name="Rscoredata.php" hash="178f70a1f05415c86b6c5e959fb2fe50"/></dir><file name="Observer.php" hash="38539aafe8d9f52c55a9c4f65ed3ef38"/><file name="retention_science_api.php" hash="d9d5197492408502cf6084f19def5aa0"/><file name="rs_get_save_config.php" hash="9ff13acecc3cc89066e1476ee48459fb"/><file name="rs_send_categories.php" hash="1633b1c1b01a9c3666c0687586693102"/><file name="rs_send_orders.php" hash="1b4f0260e74fbe11436af16238ecd61b"/><file name="rs_send_products.php" hash="4430ecc6000698fc2fcd0c469ab97847"/><file name="rs_send_users.php" hash="0e27f4293d666c35e90ebb852ae83fb7"/><file name="rs_sync_data.php" hash="09185eab133aadf1142892372f698dfa"/></dir><dir name="controllers"><file name="AdminController.php" hash="25905c7233adde08763a74d8792e722f"/><file name="IndexController.php" hash="70e254ab63b9ea8c9d0cae2fe96d1f8b"/></dir><dir name="etc"><file name="adminhtml.xml" hash="1378650fdb7ecc596f9881d7eefca868"/><file name="config.xml" hash="0030d762fbe54dfa0558b952599ea273"/><file name="system.xml" hash="b2d00b02e576c1ee4049951577d74610"/></dir></dir><file name=".DS_Store" hash="128e595394427daa0503e6d824d6b4ef"/></dir></target><target name="mageweb"><dir name="js"><dir name="RetentionScience"><file name="retention_science_wave.js" hash="bbb32a179f6b6f7f8a19ee3e200b8178"/></dir></dir></target><target name="magedesign"><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><file name="waves.xml" hash="7f62bec7d87da48c0e554fc1cf3a9802"/></dir><dir name="template"><dir name="waves"><file name="waves.phtml" hash="0b9f206668a56c8da4cb7da6dc94850c"/></dir></dir></dir></dir></dir><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="template"><dir name="waves"><file name="rscore.phtml" hash="4f6af3dd918b23a009bb559e12f23c05"/></dir></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="RetentionScience_Waves.xml" hash="9dc27ff12e5834f576b22a72a60d02e7"/></dir></target></contents>
24
  <compatible/>
25
- <dependencies/>
26
  </package>
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>RetentionScience_Waves</name>
4
+ <version>3.0.1</version>
5
  <stability>stable</stability>
6
  <license uri="http://www.apache.org/licenses/LICENSE-2.0.html">Apache License 2.0</license>
7
  <channel>community</channel>
8
  <extends/>
9
+ <summary>Retention Science Integration</summary>
10
+ <description>Notes: This extension interfaces with Retention Science, and communicates through the Retention Science API. For more information, and to sign up for API access, please see http://retentionscience.com.&#xD;
11
+ </description>
12
+ <notes>Brand new API 3.0 Integration</notes>
13
+ <authors><author><name>Retention Science</name><user>retentionsci</user><email>support@retentionscience.com</email></author></authors>
14
+ <date>2016-04-05</date>
15
+ <time>23:00:15</time>
16
+ <contents><target name="magecommunity"><dir name="RetentionScience"><dir name="Waves"><dir name="Block"><dir name="Adminhtml"><file name="Rscore.php" hash="e8bc9ced354227cb3ba0f422230cc903"/><file name="Syncbutton.php" hash="a2c466f4ddb27ab28bf00b73d2358c0d"/></dir><file name="Waves.php" hash="2e6376311d74b5b7d164e6d1ba414be8"/></dir><dir name="Helper"><file name="Data.php" hash="adca88b4b8c7c245cddf147f337d3c13"/></dir><dir name="Model"><file name="Configfieldlistener.php" hash="d6e33f8d77edaa31c3c92994a77bfb40"/><dir name="Connection"><file name="AwsCloudWatch.php" hash="93b7341d33489fae5fa4ab624073d504"/><file name="RetentionScienceApi.php" hash="3d00d235bcddd72cc4f0fc504969b0fc"/></dir><dir name="Container"><file name="Waves.php" hash="2f806c5c1ed969bb30f4824e4a8bda5d"/></dir><file name="Cron.php" hash="aaaf7a1cc39c9c63e155d6ba63ea81f1"/><dir name="Export"><file name="Abstract.php" hash="879a1f98cefa2b5541f7b04f661bb0d2"/><file name="Category.php" hash="7c4a1ca9090b1380228f2501e82673ed"/><file name="Customer.php" hash="3c57c6dd1b5b766346ddee0a86e15abd"/><dir name="Order"><file name="Customer.php" hash="f1d992c41bbe1fe1d83aa267cabc77a2"/><file name="Items.php" hash="acef2135fa639e6152c6be45736947b0"/></dir><file name="Order.php" hash="10773bafb4e99b05913e65a0dc840916"/><file name="Product.php" hash="6ddd1e0b31249d16e612354e6730669f"/></dir><file name="Observer.php" hash="3b182e9c47b46f5ed0ad1288645b11c4"/><dir name="Source"><file name="Credentials.php" hash="cd130474463c736290805960c51de42c"/><file name="Cronconfig.php" hash="ba23b32971c18cad2dde9277d3ae283e"/><file name="Rscoredata.php" hash="7a4ebcc89436073a6a0b714511a7c7ea"/><file name="Stores.php" hash="a3a60fcd428aa2c7afa34f5d2f501f39"/></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="WavesController.php" hash="454409b7e1d1d5528495cc5527642a71"/></dir><dir name="Frontend"><file name="IndexController.php" hash="4546a381cb440987f2acbc75a6f3040e"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="a18529fc20edd574302d40cac61a1f87"/><file name="cache.xml" hash="1f43383e0399b6aad3afd134774beea6"/><file name="config.xml" hash="88bfe082ae333d8f6424272b21b71ef6"/><file name="system.xml" hash="c9ce31c0a9c7581f928866cd5da8ab0a"/></dir></dir></dir></target><target name="magedesign"><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><file name="waves.xml" hash="83bc698a8b92cedf523fa4c0ea6f2c9f"/></dir><dir name="template"><dir name="waves"><file name="waves.phtml" hash="eb7c68dedd644b9497fb30eb669e990d"/></dir></dir></dir></dir></dir></target><target name="mageweb"><dir name="js"><dir name="waves"><file name="waves.js" hash="992baa185644ac97d0c683b4934b32a0"/></dir></dir></target></contents>
 
 
 
 
 
 
 
17
  <compatible/>
18
+ <dependencies><required><php><min>5.0.0</min><max>6.0.0</max></php></required></dependencies>
19
  </package>