RetentionScience_Waves - Version 2.0.7

Version Notes

Bulk transfer of products is default

Download this release

Release Info

Developer Magento Core Team
Extension RetentionScience_Waves
Version 2.0.7
Comparing to
See all releases


Version 2.0.7

Files changed (25) hide show
  1. app/code/community/RetentionScience/.DS_Store +0 -0
  2. app/code/community/RetentionScience/Waves/Block/Adminhtml/Rscore.php +11 -0
  3. app/code/community/RetentionScience/Waves/Block/Adminhtml/Syncbutton.php +40 -0
  4. app/code/community/RetentionScience/Waves/Block/Waves.php +74 -0
  5. app/code/community/RetentionScience/Waves/Helper/Data.php +5 -0
  6. app/code/community/RetentionScience/Waves/Model/Observer.php +756 -0
  7. app/code/community/RetentionScience/Waves/Model/Source/Categorytree.php +62 -0
  8. app/code/community/RetentionScience/Waves/Model/Source/Cron/Frequency.php +29 -0
  9. app/code/community/RetentionScience/Waves/Model/Source/Cron/Hours.php +19 -0
  10. app/code/community/RetentionScience/Waves/Model/Source/Cronconfig.php +33 -0
  11. app/code/community/RetentionScience/Waves/Model/Source/Rscoredata.php +107 -0
  12. app/code/community/RetentionScience/Waves/Model/retention_science_api.php +254 -0
  13. app/code/community/RetentionScience/Waves/Model/rs_send_orders.php +43 -0
  14. app/code/community/RetentionScience/Waves/Model/rs_send_products.php +44 -0
  15. app/code/community/RetentionScience/Waves/Model/rs_send_users.php +43 -0
  16. app/code/community/RetentionScience/Waves/controllers/IndexController.php +73 -0
  17. app/code/community/RetentionScience/Waves/etc/adminhtml.xml +23 -0
  18. app/code/community/RetentionScience/Waves/etc/config.xml +106 -0
  19. app/code/community/RetentionScience/Waves/etc/system.xml +306 -0
  20. app/design/adminhtml/default/default/template/waves/rscore.phtml +101 -0
  21. app/design/frontend/base/default/layout/waves.xml +9 -0
  22. app/design/frontend/base/default/template/waves/waves.phtml +75 -0
  23. app/etc/modules/RetentionScience_Waves.xml +9 -0
  24. js/RetentionScience/RetentionScience/retention_science_wave.js +38 -0
  25. package.xml +26 -0
app/code/community/RetentionScience/.DS_Store ADDED
Binary file
app/code/community/RetentionScience/Waves/Block/Adminhtml/Rscore.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class RetentionScience_Waves_Block_Adminhtml_Rscore extends Mage_Adminhtml_Block_Abstract
4
+ {
5
+ public function render(Varien_Data_Form_Element_Abstract $fieldset)
6
+ {
7
+ if (Mage::getStoreConfig('waves/retentionscience_settings/enable') == 0) {
8
+ return $this->getLayout()->createBlock('waves/adminhtml_rscore')->setTemplate('waves/rscore.phtml')->assign('in_config', true)->toHtml();
9
+ }
10
+ }
11
+ }
app/code/community/RetentionScience/Waves/Block/Adminhtml/Syncbutton.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
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
+
13
+ $action = $originalData['rs_button_url'];
14
+
15
+ $link_url = $this->_getLink($action);
16
+ return $this->_getAddRowButtonHtml($link_url);
17
+ }
18
+
19
+
20
+ protected function _getAddRowButtonHtml($link_url)
21
+ {
22
+ $title = "Run Now";
23
+ return $this->getLayout()->createBlock('adminhtml/widget_button')
24
+ ->setType('button')
25
+ ->setClass('run_now_button')
26
+ ->setLabel($title)
27
+ //$this->__('Add')
28
+ ->setOnClick("window.open('$link_url')")
29
+ ->setDisabled(false)
30
+ ->toHtml();
31
+
32
+ }
33
+
34
+ protected function _getLink($action){
35
+ $baseurl = Mage::app()->getStore()->getBaseUrl();
36
+ $link_url = $baseurl . 'waves/index/' . $action;
37
+ return $link_url;
38
+ }
39
+
40
+ }
app/code/community/RetentionScience/Waves/Block/Waves.php ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ //$customerId = Mage::getSingleton('customer/session')->getCustomerId();
62
+ $email = Mage::getSingleton('customer/session')->getCustomer()->getEmail();
63
+ $user_record_id = md5(trim(strtolower($email)));
64
+ return $user_record_id;
65
+ }
66
+ public function getOrderId(){
67
+ $lastOrderId = Mage::getSingleton('checkout/session')->getLastOrderId();
68
+ return $lastOrderId;
69
+ }
70
+ public function getOrder(){
71
+ $order = Mage::getSingleton('sales/order')->load($this->getOrderId());
72
+ return $order;
73
+ }
74
+ }
app/code/community/RetentionScience/Waves/Helper/Data.php ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ <?php
2
+
3
+ class RetentionScience_Waves_Helper_Data extends Mage_Core_Helper_Abstract{
4
+
5
+ }
app/code/community/RetentionScience/Waves/Model/Observer.php ADDED
@@ -0,0 +1,756 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // ini_set('display_errors', '1');
3
+ include('retention_science_api.php');
4
+ $last_processed_order_record_id;
5
+ $last_processed_user_entity_id;
6
+ $last_processed_product_entity_id;
7
+
8
+ class RetentionScience_Waves_Model_Observer
9
+ {
10
+ // if sendBulkUpload, do not access the RS API at all, just ouput all entities to a file
11
+ protected $phpBin = 'php'; // only used if useExec==true
12
+ // can use sendBulkUpload with or without useExec
13
+ // or can just use API by setting sendBulkUpload=false
14
+ protected $sendBulkUpload = true;
15
+ protected $useBulkCompression = true; // only used if sendBulkUpload==true
16
+ protected $useExec = false;
17
+ protected $removeFileAfterSend = true; // only used if sendBulkUpload==true
18
+ protected $logToFile = false;
19
+ protected $elementsPerPage = 2000;
20
+ protected $apiClient;
21
+ public function sendCategory(){
22
+ $categoryProcessStatus = Mage::getStoreConfig('waves/rs_sync_settings/category_process_status');
23
+ if(stristr($categoryProcessStatus, "running")){
24
+ return false;
25
+ }
26
+ try {
27
+ $timestamp = date("YmdHis");
28
+ Mage::getModel('core/config')->saveConfig('waves/rs_sync_settings/category_process_status', '[running] started at: ' . date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(time())) );
29
+ $categorytree = Mage::getModel('waves/source_categorytree')->getAllOptions();
30
+
31
+ foreach($categorytree as $category){
32
+ $parentId = ($category->getParentId())?$category->getParentId():null;
33
+ $categoryId = $category->getEntityId();
34
+ $categoryName = $category->getName();
35
+ $categoryDescription = $category->getDescripton();
36
+ $category_array = array('name' => $categoryName, 'description' => $categoryDescription, 'parent_record_id' => $parentId);
37
+ if ($this->sendBulkUpload()){
38
+ $this->writeBulkUploadFile(array($categoryId => $category_array), 'categories', $timestamp);
39
+ } else {
40
+ $this->getRetentionScienceApiClient()->update_category($categoryId, $category_array);
41
+ }
42
+ }
43
+ if ($this->sendBulkUpload()){
44
+ $this->sendBulkUploadFile('categories', $timestamp);
45
+ }
46
+ } catch (Exception $e){
47
+ Mage::logException($e);
48
+ Mage::getModel('core/config')->saveConfig('waves/rs_sync_settings/category_process_status', '[stopped] last run at: ' . date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(time())) );
49
+ }
50
+ Mage::getModel('core/config')->saveConfig('waves/rs_sync_settings/category_process_status', '[stopped] last run at: ' . date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(time())) );
51
+ }
52
+
53
+ public function sendProduct(){
54
+ global $last_processed_product_entity_id;
55
+ $timestamp = date("YmdHis");
56
+ $productProcessStatus = Mage::getStoreConfig('waves/rs_sync_settings/product_process_status');
57
+ if(stristr($productProcessStatus, "running")){
58
+ return false;
59
+ }
60
+ try{
61
+ Mage::getModel('core/config')->saveConfig('waves/rs_sync_settings/product_process_status', '[running] started at: ' . date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(time())) );
62
+ $productCollection = Mage::getModel('catalog/product')->getCollection()->addAttributeToSelect('*');
63
+
64
+ # How many do we have to send? - Don't use count()
65
+ $num_products_to_send = $productCollection->getSize();
66
+
67
+ if ($this->sendBulkUpload()){
68
+ if ($this->useExec()){
69
+ $phpbin = $this->getPhpBin();
70
+ $store_id = Mage::app()->getStore()->getCode();
71
+ $send_products_script = dirname(__FILE__) . "/rs_send_products.php";
72
+ $send_products_script = escapeshellarg($send_products_script);
73
+
74
+
75
+ $pages = ceil($num_products_to_send / $this->elementsPerPage());
76
+ echo "Pages: $pages \n";
77
+
78
+ $page_counter = 1;
79
+ while($page_counter <= $pages){
80
+ $cmd = "$phpbin $send_products_script $store_id $timestamp $page_counter $last_processed_product_entity_id";
81
+ $output = array();
82
+ $return_val = null;
83
+ exec($cmd, $output, $return_val);
84
+ $last_processed_user_entity_id = $output[0];
85
+
86
+ if ($return_val != 0){
87
+ var_dump($output);
88
+ throw new Exception('Send products script returned with non-zero return code.');
89
+ }
90
+ $page_counter = $page_counter + 1;
91
+ }
92
+ } else {
93
+ // bulk upload but do not use exec
94
+ foreach($productCollection as $product){
95
+ $this->productCallback(array('product_id' => $product->getId(), 'timestamp' => $timestamp));
96
+ }
97
+ }
98
+ $this->sendBulkUploadFile('items', $timestamp);
99
+ // end if($this->sendBulkUpload())
100
+
101
+ } else {
102
+ // send one at a time - not using sendBulkUpload()
103
+ foreach($productCollection as $product){
104
+ $this->productCallback(array('product_id' => $product->getId(), 'timestamp' => $timestamp));
105
+ }
106
+ }
107
+ }
108
+ catch (Exception $e){
109
+ Mage::logException($e);
110
+ Mage::getModel('core/config')->saveConfig('waves/rs_sync_settings/product_process_status', '[stopped] last run at: ' . date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(time())) );
111
+ }
112
+ Mage::getModel('core/config')->saveConfig('waves/rs_sync_settings/product_process_status', '[stopped] last run at: ' . date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(time())) );
113
+ }
114
+
115
+ public function sendUser(){
116
+ $timestamp = date("YmdHis");
117
+ $phpbin = $this->getPhpBin();
118
+
119
+ $userProcessStatus = Mage::getStoreConfig('waves/rs_sync_settings/user_process_status');
120
+ if(stristr($userProcessStatus, "running") ){
121
+ return false;
122
+ }
123
+ try {
124
+ $last_user_record_id = Mage::getStoreConfig('waves/rs_sync_advanced/last_user_record_id');
125
+ Mage::getModel('core/config')->saveConfig('waves/rs_sync_settings/user_process_status', '[running] started at: ' . date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(time())) );
126
+ $userCollection = Mage::getModel('customer/customer')
127
+ ->getCollection()
128
+ ->addAttributeToSelect('name')
129
+ ->addAttributeToSelect('*')
130
+
131
+ ;
132
+ $last_user_record_id = (int) $last_user_record_id;
133
+ global $last_processed_user_entity_id;
134
+ $last_processed_user_entity_id = $last_user_record_id;
135
+
136
+ if($last_user_record_id>0){
137
+ $userCollection->addFieldToFilter('entity_id', array('gt'=>$last_user_record_id));
138
+ }
139
+
140
+ # How many do we have to send? - Don't use count()
141
+ $num_users_to_send = $userCollection->getSize();
142
+ // echo "Number of users to send: $num_users_to_send \n";
143
+
144
+ if ($this->sendBulkUpload()){
145
+ if ($this->useExec()){
146
+ $store_id = Mage::app()->getStore()->getCode();
147
+ $pages = ceil($num_users_to_send / $this->elementsPerPage());
148
+ // echo "Pages: $pages \n";
149
+
150
+ $page_counter = 1;
151
+ while($page_counter <= $pages){
152
+ // CALL SCRIPT - saves memory
153
+ $send_users_script = dirname(__FILE__) . "/rs_send_users.php";
154
+ $send_users_script = escapeshellarg($send_users_script);
155
+ $cmd = "$phpbin $send_users_script $store_id $timestamp $page_counter $last_user_record_id";
156
+ $output = array();
157
+ $return_val = null;
158
+ exec($cmd, $output, $return_val);
159
+ $last_processed_user_entity_id = $output[0];
160
+ # Store back to config
161
+ Mage::getModel('core/config')->saveConfig('waves/rs_sync_advanced/last_user_record_id', $last_processed_user_entity_id);
162
+ if ($return_val != 0){
163
+ var_dump($output);
164
+ throw new Exception('Send users script returned with non-zero return code.');
165
+ }
166
+ $page_counter = $page_counter + 1;
167
+ }
168
+ } else {
169
+ // bulk upload but do not use exec
170
+ foreach($userCollection as $user){
171
+ $this->userCallback(array('user_record_id' => $user->getEntityId(), 'timestamp' => $timestamp));
172
+ $last_processed_user_entity_id = $this->get_last_processed_user_entity_id();
173
+ Mage::getModel('core/config')->saveConfig('waves/rs_sync_advanced/last_user_record_id', $last_processed_user_entity_id);
174
+ }
175
+ }
176
+ $this->sendBulkUploadFile('users', $timestamp);
177
+
178
+ } else {
179
+ // send one at a time - not using sendBulkUpload()
180
+ foreach($userCollection as $user){
181
+ $this->userCallback(array('user_record_id' => $user->getEntityId(), 'timestamp' => $timestamp));
182
+ $last_processed_user_entity_id = $this->get_last_processed_user_entity_id();
183
+ # Store back to config
184
+ Mage::getModel('core/config')->saveConfig('waves/rs_sync_advanced/last_user_record_id', $last_processed_user_entity_id);
185
+ }
186
+ }
187
+ } catch (Exception $e){
188
+ Mage::logException($e);
189
+ Mage::getModel('core/config')->saveConfig('waves/rs_sync_settings/user_process_status', '[stopped] last run at: ' . date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(time())) );
190
+ Mage::getModel('core/config')->saveConfig('waves/rs_sync_advanced/last_user_record_id', $last_processed_user_entity_id);
191
+ }
192
+
193
+ Mage::getModel('core/config')->saveConfig('waves/rs_sync_settings/user_process_status', '[stopped] last run at: ' . date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(time())) );
194
+ }
195
+
196
+ public function sendOrder(){
197
+ $timestamp = date("YmdHis");
198
+ $phpbin = $this->getPhpBin();
199
+
200
+ $orderProcessStatus = Mage::getStoreConfig('waves/rs_sync_settings/order_process_status');
201
+ if(stristr($orderProcessStatus, "running")){
202
+ return false;
203
+ }
204
+ try{
205
+ $last_order_record_id = Mage::getStoreConfig('waves/rs_sync_advanced/last_order_record_id');
206
+
207
+ Mage::getModel('core/config')->saveConfig('waves/rs_sync_settings/order_process_status', '[running] started at: ' . date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(time())) );
208
+ $orderCollection = Mage::getModel('sales/order')->getCollection();
209
+
210
+ $last_order_record_id = (int) $last_order_record_id;
211
+ if($last_order_record_id>0){
212
+ $orderCollection->addFieldToFilter('entity_id', array('gt'=>$last_order_record_id));
213
+ }
214
+
215
+ # this will be updated as we iterate
216
+ global $last_processed_order_record_id;
217
+ $last_processed_order_record_id = $last_order_record_id;
218
+
219
+ # How many do we have to send?
220
+ // Don't use count()
221
+ $num_orders_to_send = $orderCollection->getSize();
222
+ // echo "Number of orders to send: $num_orders_to_send \n";
223
+
224
+ if ($this->sendBulkUpload()){
225
+ if ($this->useExec()){
226
+ $store_id = Mage::app()->getStore()->getCode();
227
+ $pages = ceil($num_orders_to_send / $this->elementsPerPage());
228
+ echo "Pages: $pages \n";
229
+ $send_orders_script = dirname(__FILE__) . "/rs_send_orders.php";
230
+ $send_orders_script = escapeshellarg($send_orders_script);
231
+
232
+ ##### SEND ORDER
233
+ $page_counter = 1;
234
+ while($page_counter <= $pages){
235
+ // $orderCollectionWalker = Mage::getSingleton('core/resource_iterator')->walk($orderCollection->getSelect(),
236
+ // array(array($this, 'orderCallback')),
237
+ // array('timestamp' => $timestamp));
238
+
239
+ // CALL SCRIPT - saves memory
240
+
241
+ $cmd = "$phpbin $send_orders_script $store_id $timestamp $page_counter $last_order_record_id";
242
+ $output = array();
243
+ $return_val = null;
244
+ exec($cmd, $output, $return_val);
245
+ $last_processed_order_record_id = $output[0];
246
+ # Store back to config
247
+ Mage::getModel('core/config')->saveConfig('waves/rs_sync_advanced/last_order_record_id', $last_processed_order_record_id);
248
+ if ($return_val != 0){
249
+ var_dump($output);
250
+ throw new Exception('Send orders script returned with non-zero return code.');
251
+ }
252
+ $page_counter = $page_counter + 1;
253
+ }
254
+ } else {
255
+ // bulk upload but do not use exec
256
+ foreach($orderCollection as $order){
257
+ $this->orderCallback(array('order_record_id' => $order->getEntityId(), 'timestamp' => $timestamp));
258
+ $last_processed_order_record_id = $this->get_last_processed_order_record_id();
259
+ Mage::getModel('core/config')->saveConfig('waves/rs_sync_advanced/last_order_record_id', $last_processed_order_record_id);
260
+ }
261
+ }
262
+ $this->sendBulkUploadFile('orders_users', $timestamp);
263
+ $this->sendBulkUploadFile('orders', $timestamp);
264
+
265
+ } else {
266
+ // send one at a time - not using sendBulkUpload()
267
+ foreach($orderCollection as $order){
268
+ $this->orderCallback(array('order_record_id' => $order->getEntityId(), 'timestamp' => $timestamp));
269
+ $last_processed_order_record_id = $this->get_last_processed_order_record_id();
270
+ # Store back to config
271
+ Mage::getModel('core/config')->saveConfig('waves/rs_sync_advanced/last_order_record_id', $last_processed_order_record_id);
272
+ }
273
+ }
274
+
275
+
276
+
277
+ } catch(Exception $e) {
278
+ Mage::logException($e);
279
+ Mage::getModel('core/config')->saveConfig('waves/rs_sync_settings/order_process_status', '[stopped] last run at: ' . date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(time())) );
280
+ Mage::getModel('core/config')->saveConfig('waves/rs_sync_advanced/last_order_record_id', $last_processed_order_record_id);
281
+ }
282
+ Mage::getModel('core/config')->saveConfig('waves/rs_sync_settings/order_process_status', '[stopped] last run at: '. date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(time())) );
283
+ }
284
+
285
+ public function getRetentionScienceApiClient(){
286
+ if(!$this->apiClient){
287
+ $api_user = Mage::getStoreConfig('waves/retentionscience_settings/api_user');
288
+ $api_pass = Mage::getStoreConfig('waves/retentionscience_settings/api_pass');
289
+ $testmode = Mage::getStoreConfig('waves/retentionscience_settings/testmode');
290
+ // $client = new RetentionScienceApi($api_user, $api_pass, $testmode);
291
+ $this->apiClient = new RetentionScienceApi($api_user, $api_pass, $testmode);
292
+ }
293
+ return $this->apiClient;
294
+ }
295
+ public function getPhpBin(){
296
+ $php_bin = Mage::getStoreConfig('waves/rs_sync_advanced/rs_php_bin');
297
+ if ($php_bin == NULL){
298
+ $php_bin = $this->phpBin;
299
+ }
300
+ // echo "PHP_BIN is [ $php_bin ] \n";
301
+ return $php_bin;
302
+ }
303
+ public function logToFile(){
304
+ return $this->logToFile;
305
+ }
306
+ public function sendBulkUpload(){
307
+ $send_bulk_upload = Mage::getStoreConfig('waves/rs_sync_advanced/rs_send_bulk_upload');
308
+ if ($send_bulk_upload == NULL){
309
+ $send_bulk_upload = $this->sendBulkUpload;
310
+ }
311
+ // echo "send_bulk_upload is [ $send_bulk_upload ] \n";
312
+ return $send_bulk_upload;
313
+ }
314
+ public function useBulkCompression(){
315
+ $use_bulk_compression = Mage::getStoreConfig('waves/rs_sync_advanced/rs_use_bulk_compression');
316
+ if ($use_bulk_compression == NULL){
317
+ $use_bulk_compression = $this->useBulkCompression;
318
+ }
319
+ return $use_bulk_compression;
320
+ }
321
+ public function elementsPerPage(){
322
+ return $this->elementsPerPage;
323
+ }
324
+ public function useExec(){
325
+ $use_exec = Mage::getStoreConfig('waves/rs_sync_advanced/rs_bulk_use_exec');
326
+ if ($use_exec == NULL){
327
+ $use_exec = $this->useExec;
328
+ }
329
+ //echo "use_exec is [ $use_exec ] \n";
330
+ return $use_exec;
331
+ }
332
+ public function writeToLog($msg, $category){
333
+ $msg = $msg . "\n";
334
+ $file = dirname(__FILE__) . '/retention_science_'. $category.'.log';
335
+ file_put_contents($file, $msg, FILE_APPEND);
336
+ }
337
+ public function get_last_processed_order_record_id(){
338
+ global $last_processed_order_record_id;
339
+ return $last_processed_order_record_id;
340
+ }
341
+ public function get_last_processed_user_entity_id(){
342
+ global $last_processed_user_entity_id;
343
+ return $last_processed_user_entity_id;
344
+ }
345
+ public function get_last_processed_product_entity_id(){
346
+ global $last_processed_product_entity_id;
347
+ return $last_processed_product_entity_id;
348
+ }
349
+ public function writeBulkUploadFile($entity_hash, $category, $timestamp){
350
+ $tmp_base = Mage::getBaseDir('tmp');
351
+
352
+ $msg = json_encode($entity_hash) . "\n";
353
+ // $file = dirname(__FILE__) . '/rs_bulk_'. $category.'_'.$timestamp.'.log';
354
+ $file = $tmp_base . '/rs_bulk_'. $category.'_'.$timestamp.'.log';
355
+ file_put_contents($file, $msg, FILE_APPEND);
356
+ }
357
+ public function sendBulkUploadFile($category, $timestamp){
358
+ $tmp_base = Mage::getBaseDir('tmp');
359
+ //$file = dirname(__FILE__) . '/rs_bulk_'. $category.'_'.$timestamp.'.log';
360
+ $file = $tmp_base . '/rs_bulk_'. $category.'_'.$timestamp.'.log';
361
+
362
+ // Use Compression if useBulkCompression()
363
+ $gzfile = null;
364
+ if ($this->useBulkCompression()){
365
+ $gzfile = $file . ".gz";
366
+ $fp = gzopen ($gzfile, 'wb');
367
+ gzwrite ($fp, file_get_contents($file));
368
+ gzclose($fp);
369
+ }
370
+ $file_to_send = ($gzfile == null) ? $file : $gzfile;
371
+
372
+ if (file_exists($file_to_send)){
373
+ if ($category == 'orders'){
374
+ $this->getRetentionScienceApiClient()->upload_orders_bulk_file($file_to_send);
375
+ } else if ($category == 'categories'){
376
+ $this->getRetentionScienceApiClient()->upload_categories_bulk_file($file_to_send);
377
+ } else if ($category == 'items'){
378
+ $this->getRetentionScienceApiClient()->upload_items_bulk_file($file_to_send);
379
+ } else if ($category == 'orders_users' || $category == "users"){
380
+ $this->getRetentionScienceApiClient()->upload_users_bulk_file($file_to_send);
381
+ }
382
+ // delete the file after sending
383
+ if($this->removeFileAfterSend){
384
+ unlink($file);
385
+ if ($gzfile != null){
386
+ unlink($gzfile);
387
+ }
388
+ }
389
+ }
390
+ }
391
+ public function productCallback($args){
392
+
393
+ global $last_processed_product_entity_id;
394
+
395
+ $timestamp = $args['timestamp'];
396
+
397
+ $product_id = $args['product_id'];
398
+ $product = Mage::getModel('catalog/product')->load($product_id);
399
+ $product_name = $product->getName();
400
+
401
+ // OLDER VERSIONS OF MAGENTO HAVE A FATAL ERROR for this bug in magento: http://www.magentocommerce.com/boards/viewthread/53871/#t215589
402
+ // MUST PATCH app/code/core/Mage/Catalog/Model/Product.php
403
+ $manufacturer = $product->getAttributeText('manufacturer');
404
+ $manufacturer = $manufacturer ? $manufacturer : null;
405
+ $model = $product->getSku();
406
+ $qty_stock = (int) Mage::getModel('cataloginventory/stock_item')->loadByProduct($product)->getQty();
407
+ $price = $product->getPrice();
408
+ if($product->getSpecialPrice()){
409
+ $price = $product->getSpecialPrice();
410
+ }
411
+ $price = number_format($price, 2, '.', '');
412
+ // TODO: THIS returns false when called from the PHPscript
413
+ $active = ($product->isSalable()) ? true : false;
414
+ $images_url = array($product->getImageUrl());
415
+ $media_images = $product->getMediaGalleryImages();
416
+ foreach($media_images as $media_image){
417
+ $images_url[] = $media_image->getUrl();
418
+ }
419
+ $categories = $product->getCategoryIds();
420
+ $item_url = $product->getProductUrl();
421
+ // $item_url = Mage::helper('catalog/product')->getProductUrl($product_id);
422
+ // $item_url = $product->getUrlPath();
423
+ //$_category = Mage::getModel('catalog/category')->load($categories[0]);
424
+ //$item_url = Mage::getUrl($_category->getUrlPath()).basename($product->getProductUrl());
425
+ //$item_url = $product->getUrlInStore();
426
+
427
+ $product_array = array(
428
+ 'name'=> $product_name,
429
+ 'manufacturer' => $manufacturer,
430
+ 'model' => $model,
431
+ 'quantity' => $qty_stock,
432
+ 'price' => $price,
433
+ 'active' => $active,
434
+ 'image_list' => $images_url,
435
+ 'item_url' => $item_url,
436
+ 'categories' => $categories
437
+ );
438
+
439
+ if ($this->sendBulkUpload()){
440
+ $this->writeBulkUploadFile(array($product_id => $product_array), 'items', $timestamp);
441
+ } else {
442
+ try{
443
+ $this->getRetentionScienceApiClient()->update_item($product_id, $product_array);
444
+ } catch (Exception $e){
445
+ // do nothing
446
+ }
447
+ }
448
+
449
+ # Update this as we iterate
450
+ $last_processed_product_entity_id = $product_id;
451
+ }
452
+
453
+ public function userCallback($args){
454
+ global $last_processed_user_entity_id;
455
+
456
+ $timestamp = $args['timestamp'];
457
+ $user = Mage::getModel('customer/customer')->load($args['user_record_id']);
458
+ $email = $user->getEmail();
459
+ $user_entity_id = $user->getEntityId();
460
+ $user_record_id = md5(trim(strtolower($email)));
461
+ $fullName = $user->getName();
462
+ $address = Mage::getModel('customer/address')->load($user->getdefault_billing());
463
+ $address1 = $address->getStreetFull();
464
+ $address1 = str_replace("\n"," ",$address1);
465
+ $city = $address->getCity();
466
+ $regionModel = Mage::getModel('directory/region')->load($address->getRegionId());
467
+ $region = $regionModel->getName();
468
+ $zip = $address->getPostcode();
469
+ $country = $address->getCountryId();
470
+ $phone = $address->getTelephone();
471
+ $birthDate = $user->getDob();
472
+ $birthDate = explode('-',$birthDate);
473
+ $birth_year = $birthDate[0];
474
+ $gender = $user->getGender();
475
+ // $ipAddress = '117.196.42.219';
476
+ // $numberLogons = '2';
477
+ $accountCreatedAt = $user->getCreatedAt();
478
+ $accountCreatedAt = date("Y-m-d", Mage::getModel('core/date')->timestamp(strtotime($accountCreatedAt)));
479
+
480
+ $accountUpdatedDate = $user->getUpdatedAt();
481
+ $accountUpdatedAt = date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(strtotime($accountUpdatedDate)));
482
+
483
+ if (!$this->sendBulkUpload()){
484
+ // only update some fields (like created_at) if this is a new user.
485
+ $user_exists_already = $this->getRetentionScienceApiClient()->user_exists($user_record_id);
486
+ $existing_user = ($user_exists_already) ? $this->getRetentionScienceApiClient()->show_user($user_record_id) : null;
487
+ }
488
+
489
+ $user_array = array();
490
+ if($email){
491
+ $user_array['email'] = $email;
492
+ }
493
+ if($fullName){
494
+ $user_array['full_name'] = $fullName;
495
+ }
496
+ if($address1){
497
+ $user_array['address1'] = $address1;
498
+ }
499
+ if($city){
500
+ $user_array['city'] = $city;
501
+ }
502
+ if($region){
503
+ $user_array['state'] = $region;
504
+ }
505
+ if($zip){
506
+ $user_array['zip'] = $zip;
507
+ }
508
+ if($country){
509
+ $user_array['country'] = $country;
510
+ }
511
+ if($phone){
512
+ $user_array['phone'] = $phone;
513
+ }
514
+ if($birth_year){
515
+ $user_array['birth_year'] = $birth_year;
516
+ }
517
+ if($gender){
518
+ $user_array['gender'] = $gender;
519
+ }
520
+ if($accountCreatedAt){
521
+ if ($this->sendBulkUpload()){
522
+ $user_array['account_created_on'] = $accountCreatedAt;
523
+
524
+ } else {
525
+ // Only send this if user has not already been created
526
+ if (!($user_exists_already) || ($existing_user && (strtotime($existing_user['account_created_on']) > strtotime($accountCreatedAt))) ){
527
+ $user_array['account_created_on'] = $accountCreatedAt;
528
+ }
529
+ }
530
+ }
531
+ if($accountUpdatedAt){
532
+ $user_array['last_logon_at'] = $accountUpdatedAt;
533
+ }
534
+ if ($this->logToFile()){
535
+ $this->writeToLog($user_record_id, 'users');
536
+ $this->writeToLog(http_build_query($user_array), 'users');
537
+ }
538
+
539
+ if ($this->sendBulkUpload()){
540
+ $this->writeBulkUploadFile(array($user_record_id => $user_array), 'users', $timestamp);
541
+ } else {
542
+ try{
543
+ $this->getRetentionScienceApiClient()->update_user($user_record_id, $user_array);
544
+ } catch (Exception $e){
545
+ // do nothing
546
+ }
547
+ }
548
+
549
+ # Update this as we iterate
550
+ $last_processed_user_entity_id = $user_entity_id;
551
+
552
+ }
553
+
554
+ public function orderCallback($args){
555
+ #echo "before: " . memory_get_usage() . "\n";
556
+ $timestamp = $args['timestamp'];
557
+ global $last_processed_order_record_id;
558
+ //$order = Mage::getModel('sales/order');
559
+ //$order->setData($args['row']);
560
+ //echo "Loading order with record_id " . $args['order_record_id'] . " \n";
561
+ $order = Mage::getModel('sales/order')->load($args['order_record_id']);
562
+ $order_array = array();
563
+ $order_record_id = $order->getEntityId();
564
+ //$orderAllItems = $order->getAllItems();
565
+ $orderAllItems = $order->getAllVisibleItems();
566
+ $order_item_array = array();
567
+ foreach($orderAllItems as $orderAllItem){
568
+ $item_record_id = $orderAllItem->getProductId();
569
+ $name = $orderAllItem->getName();
570
+ $quantity = (int) $orderAllItem->getQtyOrdered();
571
+ $price = $orderAllItem->getPrice();
572
+ $price = number_format($price, 2, '.', '');
573
+ $final_price = $price * $quantity;
574
+ $sku = $orderAllItem->getSku();
575
+ $productId = $orderAllItem->getProductId();
576
+ $product = Mage::getModel('catalog/product')->load($productId);
577
+ $categoryIds = $product->getCategoryIds();
578
+ $order_item_array[] = array(
579
+ 'item_record_id' => $item_record_id,
580
+ 'name' => $name,
581
+ 'quantity' => $quantity,
582
+ 'price' => $price,
583
+ 'final_price' => $final_price,
584
+ 'attribute_1' => $sku,
585
+ 'categories' => $categoryIds
586
+ );
587
+ // save memory
588
+ // $product->clearInstance(); // doesnt work on older magento installs
589
+ unset($product);
590
+ }
591
+ // Save memory ?
592
+ unset($orderAllItems);
593
+
594
+ $user_record_id = md5(trim(strtolower($order->getCustomerEmail())));
595
+ if($order->getCustomerIsGuest()){
596
+ $email = $order->getCustomerEmail();
597
+ $user_record_id = md5(trim(strtolower($email)));
598
+
599
+ // get billing address
600
+ $address = $order->getBillingAddress();
601
+ $fullName = $order->getCustomerFirstname()." ".$order->getCustomerLastname();
602
+
603
+ $address1 = $address->getStreetFull();
604
+ $address1 = str_replace("\n"," ",$address1);
605
+ $city = $address->getCity();
606
+ $regionModel = Mage::getModel('directory/region')->load($address->getRegionId());
607
+ $region = $regionModel->getName();
608
+ $zip = $address->getPostcode();
609
+ $country = $address->getCountryId();
610
+ $phone = $address->getTelephone();
611
+ $accountCreatedAt = $order->getCreatedAt();
612
+ $accountUpdatedAt = date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(strtotime($accountCreatedAt)));
613
+ $accountCreatedAt = date("Y-m-d", Mage::getModel('core/date')->timestamp(strtotime($accountCreatedAt)));
614
+
615
+ if (!$this->sendBulkUpload()){
616
+ // only update some fields (like created_at) if this is a new user.
617
+ $user_exists_already = $this->getRetentionScienceApiClient()->user_exists($user_record_id);
618
+ $existing_user = ($user_exists_already) ? $this->getRetentionScienceApiClient()->show_user($user_record_id) : null;
619
+ }
620
+
621
+
622
+ // send this user to api as well...
623
+ $user_array = array();
624
+ if($email){
625
+ $user_array['email'] = $email;
626
+ }
627
+ if($fullName){
628
+ $user_array['full_name'] = $fullName;
629
+ }
630
+ if($address1){
631
+ $user_array['address1'] = $address1;
632
+ }
633
+ if($city){
634
+ $user_array['city'] = $city;
635
+ }
636
+ if($region){
637
+ $user_array['state'] = $region;
638
+ }
639
+ if($zip){
640
+ $user_array['zip'] = $zip;
641
+ }
642
+ if($country){
643
+ $user_array['country'] = $country;
644
+ }
645
+ if($phone){
646
+ $user_array['phone'] = $phone;
647
+ }
648
+ if($accountCreatedAt){
649
+ if ($this->sendBulkUpload()){
650
+ $user_array['account_created_on'] = $accountCreatedAt;
651
+
652
+ } else {
653
+ if (!($user_exists_already)){
654
+ $this->writeToLog("User does not exist yet ***** - creating with account_created_on as [" . $accountCreatedAt . ']', 'order_users');
655
+ } else if ($existing_user) {
656
+ $this->writeToLog(http_build_query($existing_user), 'existing_users');
657
+ $themsg = "Existing user is PRESENT. His account_created_on is [" . $existing_user['account_created_on'] . "]. My accountCreatedAt is [" . $accountCreatedAt . "]";
658
+ $this->writeToLog($themsg, 'order_users');
659
+ }
660
+
661
+ if (!($user_exists_already) || ($existing_user && (strtotime($existing_user['account_created_on']) > strtotime($accountCreatedAt))) ){
662
+ $user_array['account_created_on'] = $accountCreatedAt;
663
+ }
664
+ }
665
+ }
666
+ if($accountUpdatedAt){
667
+ $user_array['last_logon_at'] = $accountUpdatedAt;
668
+ }
669
+
670
+ if ($this->logToFile()){
671
+ $this->writeToLog($user_record_id, 'order_users');
672
+ $this->writeToLog(http_build_query($user_array), 'order_users');
673
+ }
674
+ try{
675
+ if ($this->sendBulkUpload()){
676
+ $this->writeBulkUploadFile(array($user_record_id => $user_array), 'orders_users', $timestamp);
677
+ } else {
678
+ $this->getRetentionScienceApiClient()->update_user($user_record_id, $user_array);
679
+ }
680
+ } catch (Exception $e){
681
+ // do nothing
682
+ }
683
+ }
684
+
685
+ $total_price = $order->getBaseSubtotal();
686
+ $total_price = number_format($total_price, 2, '.', '');
687
+ $discount_amount = $order->getBaseDiscountAmount();
688
+ $shipping_amount = $order->getShippingAmount();
689
+ $tax_amount = $order->getBaseTaxAmount();
690
+ $date = $order->getCreatedAt();
691
+ $ordered_at = date("Y-m-d H:i:s", Mage::getModel('core/date')->timestamp(strtotime($date)));
692
+ $payment_method = $order->getPayment()->getMethodInstance()->getTitle();
693
+ $order_array = array(
694
+ 'user_record_id' => $user_record_id,
695
+ 'total_price' => $total_price,
696
+ 'discount_amount' => $discount_amount,
697
+ 'shipping_amount' => $shipping_amount,
698
+ 'tax_amount' => $tax_amount,
699
+ 'ordered_at' => $ordered_at,
700
+ 'payment_method' => $payment_method,
701
+ 'order_items'=> $order_item_array
702
+ );
703
+ if ($this->sendBulkUpload()){
704
+ $this->writeBulkUploadFile(array($order_record_id => $order_array), 'orders', $timestamp);
705
+ } else {
706
+ try {
707
+ $this->getRetentionScienceApiClient()->update_order($order_record_id, $order_array);
708
+ } catch (Exception $e){
709
+ // do nothing
710
+ }
711
+ }
712
+
713
+ // Update this as we iterate
714
+ $last_processed_order_record_id = $order_record_id;
715
+ // Release memory?
716
+ unset($order_array);
717
+ // $order->clearInstance(); //doesnt work on older magento ver
718
+ unset($order);
719
+ //echo "after: " . memory_get_usage() . "\n";
720
+ }
721
+
722
+ public function coreBlockAbstractPrepareLayoutAfter(Varien_Event_Observer $observer)
723
+ {
724
+ if (Mage::app()->getFrontController()->getAction()->getFullActionName() === 'adminhtml_dashboard_index')
725
+ {
726
+ $block = $observer->getBlock();
727
+ if ($block->getNameInLayout() === 'dashboard')
728
+ {
729
+ $block->getChild('topSearches')->setUseAsDashboardHook(true);
730
+ }
731
+ }
732
+ }
733
+
734
+ public function coreBlockAbstractToHtmlAfter(Varien_Event_Observer $observer)
735
+ {
736
+ if (Mage::app()->getFrontController()->getAction()->getFullActionName() === 'adminhtml_dashboard_index')
737
+ {
738
+ if ($observer->getBlock()->getUseAsDashboardHook())
739
+ {
740
+ $transport = $observer->getTransport();
741
+ $html = $transport->getHtml();
742
+ $myBlock = $observer->getBlock()->getLayout()->createBlock('waves/adminhtml_rscore')->setTemplate('waves/rscore.phtml');
743
+ $html .= $myBlock->toHtml();
744
+ $transport->setHtml($html);
745
+ }
746
+ }
747
+ }
748
+
749
+ public function updateRScore()
750
+ {
751
+ $rscore_data = Mage::getModel('waves/source_rscoredata')->getDataArray();
752
+ $rscore_json = $this->getRetentionScienceApiClient()->calculate_rscore($rscore_data);
753
+ Mage::getModel('core/config')->saveConfig('waves/calculated_rscore_json', $rscore_json);
754
+ return $rscore_json;
755
+ }
756
+ }
app/code/community/RetentionScience/Waves/Model/Source/Categorytree.php ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+
38
+ // $categories = Mage::getModel('catalog/category')->getCollection()
39
+ //
40
+ // ->addAttributeToSelect('name')
41
+ // ->addAttributeToSelect('url_key')
42
+ // ->addAttributeToSelect('my_attribute')
43
+ // ->setLoadProductCount(true)
44
+ // ->addAttributeToSort('parent_record_id', 'ASC')
45
+ // ->addAttributeToSort('entity_id', 'ASC')
46
+ // //->addAttributeToFilter('is_active',array('eq'=>true))
47
+ // ->load();
48
+ $this->_options['categories'] = $categories;
49
+ }
50
+ /**
51
+ * Retrieve all options array
52
+ *
53
+ * @return array
54
+ */
55
+ public function getAllOptions()
56
+ {
57
+ if (!$this->_options) {
58
+ $this->getAllCategories();
59
+ }
60
+ return $this->_options['categories'];
61
+ }
62
+ }
app/code/community/RetentionScience/Waves/Model/Source/Cron/Frequency.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class RetentionScience_Waves_Model_Source_Cronconfig extends Mage_Core_Model_Config_Data
4
+ {
5
+
6
+ protected function _afterSave()
7
+ {
8
+ // category, product, user, order
9
+ $rs_cron_job = $this->getFieldConfig()->rs_cron_job;
10
+
11
+ $cron_string_path = 'crontab/jobs/' . $rs_cron_job . '/schedule/cron_expr';
12
+ $cron_model_path = 'crontab/jobs/' . $rs_cron_job . '/run/model';
13
+
14
+ $cron_expr_string = $this->getValue();
15
+
16
+
17
+ try {
18
+ Mage::getModel('core/config_data')
19
+ ->load($cron_string_path, 'path')
20
+ ->setValue($cron_expr_string)
21
+ ->setPath($cron_string_path)
22
+ ->save();
23
+ Mage::getModel('core/config_data')
24
+ ->load($cron_model_path, 'path')
25
+ ->setValue((string) Mage::getConfig()->getNode($cron_model_path))
26
+ ->setPath($cron_model_path)
27
+ ->save();
28
+ } catch (Exception $e) {
29
+ throw new Exception(Mage::helper('cron')->__('Unable to save the cron expression.'));
30
+ }
31
+ }
32
+
33
+ }
app/code/community/RetentionScience/Waves/Model/Source/Rscoredata.php ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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');
31
+ $order_table = $this->resource->getTableName('sales_flat_order');
32
+ $query = " SELECT days, COUNT(DISTINCT customer_id) AS c
33
+ FROM (
34
+ SELECT o.customer_id, DATEDIFF(MAX(o.created_at), MIN(c.created_at)) AS days, COUNT(o.entity_id) AS ct
35
+ FROM $order_table o INNER JOIN $customer_table c ON o.customer_id = c.entity_id
36
+ GROUP BY c.entity_id) a
37
+ WHERE ct > 1 AND days >= 0 AND days < 365
38
+ GROUP BY days
39
+ ORDER BY days ASC;";
40
+ return array_map("array_values", $this->readConnection->fetchAll($query));
41
+ }
42
+
43
+ private function getEngagementRate()
44
+ {
45
+ // orders.select("distinct user_id").count.to_f/users.count.to_f
46
+ $customer_table = $this->resource->getTableName('customer_entity');
47
+ $order_table = $this->resource->getTableName('sales_flat_order');
48
+ $query = "SELECT
49
+ (SELECT COUNT(DISTINCT customer_email) FROM $order_table) /
50
+ (SELECT count(*) FROM ((SELECT email FROM $customer_table) UNION (SELECT customer_email FROM $order_table WHERE customer_is_guest IS TRUE)) a);";
51
+ return $this->readConnection->fetchOne($query);
52
+ }
53
+
54
+ private function getRprRate()
55
+ {
56
+ $writeConnection = $this->resource->getConnection();
57
+ $customer_table = $this->resource->getTableName('customer_entity');
58
+ $order_table = $this->resource->getTableName('sales_flat_order');
59
+ $writeConnection->query("DROP TEMPORARY TABLE IF EXISTS _temp_orders_1;");
60
+ $writeConnection->query("DROP TEMPORARY TABLE IF EXISTS _temp_orders_2;");
61
+ $writeConnection->query(" CREATE TEMPORARY TABLE _temp_orders_1
62
+ (
63
+ customer_email varchar(255),
64
+ created_at datetime,
65
+ key(customer_email)
66
+ ) AS
67
+ (
68
+ SELECT customer_email, created_at FROM $order_table
69
+ );");
70
+ $writeConnection->query(" CREATE TEMPORARY TABLE _temp_orders_2
71
+ (
72
+ customer_email varchar(255),
73
+ created_at datetime,
74
+ key(customer_email)
75
+ ) AS
76
+ (
77
+ SELECT customer_email, created_at FROM _temp_orders_1
78
+ );");
79
+ $query = " SELECT yearmonth, SUM(repeat_purchase) AS repeat_users, COUNT(*) AS total_users
80
+ FROM (
81
+ SELECT o.customer_email, DATE_FORMAT(o.created_at, '%Y%m') AS yearmonth, (first_orders.first_order_date < MAX(o.created_at)) AS repeat_purchase
82
+ FROM _temp_orders_1 o
83
+ INNER JOIN (
84
+ SELECT customer_email, MIN(created_at) AS first_order_date
85
+ FROM _temp_orders_2
86
+ WHERE customer_email IS NOT NULL
87
+ GROUP BY customer_email) first_orders
88
+ ON o.customer_email = first_orders.customer_email
89
+ GROUP BY o.customer_email, yearmonth) order_users
90
+ GROUP BY yearmonth;";
91
+ $results = $writeConnection->fetchAll($query);
92
+ array_shift($results); // ignore first month
93
+
94
+ if (count($results) == 0) {
95
+ return null;
96
+ } else {
97
+ $rates = array();
98
+ foreach ($results as $row)
99
+ {
100
+ $repeat_count = (float) $row['repeat_users'];
101
+ $one_time_count = (float) $row['total_users'] - $repeat_count;
102
+ array_push($rates, ($one_time_count > 0) ? $repeat_count/$one_time_count : 1);
103
+ }
104
+ return array_sum($rates) / count($rates);
105
+ }
106
+ }
107
+ }
app/code/community/RetentionScience/Waves/Model/retention_science_api.php ADDED
@@ -0,0 +1,254 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ // user_array is an assoc. array:
157
+ // email, full_name, address1, address2, city, state
158
+ // zip, country, phone, birth_year, gender, ip_address,
159
+ // number_logons, account_created_on, last_logon_at
160
+ public function update_user($record_id, $user_array) {
161
+ $url = 'users/update/' . urlencode($record_id);
162
+ $response = $this->perform_call($url, array('user' => json_encode($user_array)), true, true);
163
+ return $this->handle_response($response);
164
+ }
165
+ public function upload_users_bulk_file($filename){
166
+ $url = 'users/upload_bulk_file';
167
+ $response = $this->perform_call($url, array('file_name' => basename($filename),
168
+ 'file' => "@".$filename), true, true);
169
+ return $this->handle_response($response);
170
+ }
171
+
172
+
173
+ /* Orders resource */
174
+ public function get_last_order_record_id() {
175
+ $url = 'orders/last_record_id';
176
+ $response = $this->perform_call($url, array(), true, false);
177
+ return $this->handle_response($response);
178
+ }
179
+
180
+ public function show_order($record_id) {
181
+ $url = 'orders/show/' . urlencode($record_id);
182
+ $response = $this->perform_call($url, array(), true, false);
183
+ return json_decode($this->handle_response($response), true);
184
+ }
185
+
186
+ // order_array is an assoc. array:
187
+ // user_record_id, total_price, discount_amount, ordered_at, payment_method, order_items
188
+ public function update_order($record_id, $order_array) {
189
+ $url = 'orders/update/' . urlencode($record_id);
190
+ $response = $this->perform_call($url, array('order' => json_encode($order_array)), true, true);
191
+ return $this->handle_response($response);
192
+ }
193
+ public function upload_orders_bulk_file($filename){
194
+ $url = 'orders/upload_bulk_file';
195
+ $response = $this->perform_call($url, array('file_name' => basename($filename),
196
+ 'file' => "@".$filename), true, true);
197
+ return $this->handle_response($response);
198
+ }
199
+
200
+ /* Items resource */
201
+ public function show_item($record_id) {
202
+ $url = 'items/show/' . urlencode($record_id);
203
+ $response = $this->perform_call($url, array(), true, false);
204
+ return json_decode($this->handle_response($response), true);
205
+ }
206
+ // item_array is an assoc. array:
207
+ // name, manufacturer, model, quantity, price,
208
+ // active, image_list, categories
209
+ public function update_item($record_id, $item_array) {
210
+ $url = 'items/update/' . urlencode($record_id);
211
+ $response = $this->perform_call($url, array('item' => json_encode($item_array)), true, true);
212
+ return $this->handle_response($response);
213
+ }
214
+ public function upload_items_bulk_file($filename){
215
+ $url = 'items/upload_bulk_file';
216
+ $response = $this->perform_call($url, array('file_name' => basename($filename),
217
+ 'file' => "@".$filename), true, true);
218
+ return $this->handle_response($response);
219
+ }
220
+
221
+
222
+ /* Categories resource */
223
+ public function show_category($record_id) {
224
+ $url = 'categories/show/' . urlencode($record_id);
225
+ $response = $this->perform_call($url, array(), true, false);
226
+ return json_decode($this->handle_response($response), true);
227
+ }
228
+ // category_array is an assoc. array:
229
+ // name, description, parent_record_id
230
+ public function update_category($record_id, $category_array) {
231
+ $url = 'categories/update/' . urlencode($record_id);
232
+ $response = $this->perform_call($url, array('category' => json_encode($category_array)), true, true);
233
+ return $this->handle_response($response);
234
+ }
235
+ public function upload_categories_bulk_file($filename){
236
+ $url = 'categories/upload_bulk_file';
237
+ $response = $this->perform_call($url, array('file_name' => basename($filename),
238
+ 'file' => "@".$filename), true, true);
239
+ return $this->handle_response($response);
240
+ }
241
+
242
+
243
+ /* RScore resource */
244
+ public function calculate_rscore($rscore_data_array) {
245
+ $url = 'r_scores/calculate';
246
+ $response = $this->perform_call($url, array('data' => json_encode($rscore_data_array)), false, true);
247
+ return $this->handle_response($response);
248
+ }
249
+
250
+
251
+ }
252
+
253
+
254
+ class RetentionScienceException extends Exception { }
app/code/community/RetentionScience/Waves/Model/rs_send_orders.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ define('MAGENTO', realpath(dirname(__FILE__)));
4
+ require_once MAGENTO . '/../../../../../../app/Mage.php';
5
+ // require_once '/Users/--/Sites/magento/app/Mage.php';
6
+
7
+
8
+ //umask(0);
9
+ $store_id = $argv[1];
10
+ $timestamp = $argv[2];
11
+ $page_counter = $argv[3];
12
+ $last_order_record_id = $argv[4];
13
+
14
+ // Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);
15
+ Mage::app()->setCurrentStore($store_id);
16
+
17
+
18
+ #echo "Running rs_send_orders.php with arguments $store_id $timestamp $page_counter $last_order_record_id \n";
19
+
20
+ $observer = new RetentionScience_Waves_Model_Observer();
21
+ $elements_per_page = $observer->elementsPerPage();
22
+
23
+ $orderCollection = Mage::getModel('sales/order')->getCollection();
24
+ $orderCollection->addAttributeToSelect('entity_id');
25
+ if($last_order_record_id>0){
26
+ $orderCollection->addFieldToFilter('entity_id', array('gt'=>$last_order_record_id));
27
+ }
28
+
29
+ $orderCollection->setPage($page_counter, $elements_per_page);
30
+
31
+ try {
32
+ foreach($orderCollection as $order){
33
+ $observer->orderCallback(array('order_record_id' => $order->getEntityId(), 'timestamp' => $timestamp));
34
+ }
35
+ echo $observer->get_last_processed_order_record_id();
36
+ die(0);
37
+
38
+ } catch (Exception $e){
39
+ Mage::logException($e);
40
+ echo $observer->get_last_processed_order_record_id();
41
+ die(1);
42
+ }
43
+
app/code/community/RetentionScience/Waves/Model/rs_send_products.php ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ define('MAGENTO', dirname(__FILE__));
4
+ require_once MAGENTO . '/../../../../../../app/Mage.php';
5
+ // require_once '/Users/--/Sites/magento/app/Mage.php';
6
+
7
+ //umask(0);
8
+
9
+
10
+ $store_id = $argv[1];
11
+ $timestamp = $argv[2];
12
+ $page_counter = $argv[3];
13
+ $last_product_record_id = $argv[4];
14
+
15
+ // Mage_Core_Model_App::ADMIN_STORE_ID
16
+ Mage::app()->setCurrentStore($store_id);
17
+
18
+ $msg = "Running rs_send_orders.php with arguments $store_id $timestamp $page_counter $last_order_record_id \n";
19
+
20
+ $observer = new RetentionScience_Waves_Model_Observer();
21
+ $elements_per_page = $observer->elementsPerPage();
22
+
23
+ $productCollection = Mage::getModel('catalog/product')->getCollection();
24
+ $productCollection->addAttributeToSelect('entity_id')->addAttributeToSelect('*');
25
+
26
+ if($last_product_record_id>0){
27
+ $productCollection->addFieldToFilter('entity_id', array('gt'=>$last_product_record_id));
28
+ }
29
+
30
+ $productCollection->setPage($page_counter, $elements_per_page);
31
+
32
+ try {
33
+ foreach($productCollection as $product){
34
+ $observer->productCallback(array('product_id' => $product->getId(), 'timestamp' => $timestamp));
35
+ }
36
+ echo $observer->get_last_processed_product_entity_id();
37
+ die(0);
38
+
39
+ } catch (Exception $e){
40
+ Mage::logException($e);
41
+ echo $observer->get_last_processed_product_entity_id();
42
+ die(1);
43
+ }
44
+
app/code/community/RetentionScience/Waves/Model/rs_send_users.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ define('MAGENTO', realpath(dirname(__FILE__)));
4
+ require_once MAGENTO . '/../../../../../../app/Mage.php';
5
+ // require_once '/Users/--/Sites/magento/app/Mage.php';
6
+
7
+
8
+ //umask(0);
9
+ $store_id = $argv[1];
10
+ $timestamp = $argv[2];
11
+ $page_counter = $argv[3];
12
+ $last_user_record_id = $argv[4];
13
+
14
+ // Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);
15
+ Mage::app()->setCurrentStore($store_id);
16
+
17
+
18
+ #echo "Running rs_send_orders.php with arguments $store_id $timestamp $page_counter $last_order_record_id \n";
19
+
20
+ $observer = new RetentionScience_Waves_Model_Observer();
21
+ $elements_per_page = $observer->elementsPerPage();
22
+
23
+ $userCollection = Mage::getModel('customer/customer')->getCollection();
24
+ $userCollection->addAttributeToSelect('entity_id');
25
+ if($last_user_record_id>0){
26
+ $userCollection->addFieldToFilter('entity_id', array('gt'=>$last_user_record_id));
27
+ }
28
+
29
+ $userCollection->setPage($page_counter, $elements_per_page);
30
+
31
+ try {
32
+ foreach($userCollection as $user){
33
+ $observer->userCallback(array('user_record_id' => $user->getEntityId(), 'timestamp' => $timestamp));
34
+ }
35
+ echo $observer->get_last_processed_user_entity_id();
36
+ die(0);
37
+
38
+ } catch (Exception $e){
39
+ Mage::logException($e);
40
+ echo $observer->get_last_processed_user_entity_id();
41
+ die(1);
42
+ }
43
+
app/code/community/RetentionScience/Waves/controllers/IndexController.php ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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()->getAllItems();
18
+ $items = array();
19
+ $count = 0;
20
+ foreach ($allItems as $item){
21
+ $items[$count]['id'] = $item->getProductId();
22
+ $items[$count]['name'] = $item->getName();
23
+ $items[$count]['price'] = $item->getPrice();
24
+ $count++;
25
+ }
26
+ $result['items'] = json_encode($items);
27
+ echo json_encode($result);
28
+ die();
29
+ }
30
+ }
31
+
32
+ public function sendCategoryAction(){
33
+ $t1 = time();
34
+ $obj = new RetentionScience_Waves_Model_Observer();
35
+ $obj->sendCategory();
36
+ $length = time() - $t1;
37
+ echo "Finished in $length seconds";
38
+ //$parentId = Mage::app()->getStore('admin')->getRootCategoryId();
39
+ //echo "Parent id: " . $parentId . "<br>";
40
+ die();
41
+ }
42
+
43
+ public function sendProductAction(){
44
+ $t1 = time();
45
+ $obj = new RetentionScience_Waves_Model_Observer();
46
+ $obj->sendProduct();
47
+ $length = time() - $t1;
48
+ echo "Finished in $length seconds";
49
+ die();
50
+ }
51
+ public function sendUserAction(){
52
+ $t1 = time();
53
+ $obj = new RetentionScience_Waves_Model_Observer();
54
+ $obj->sendUser();
55
+ $length = time() - $t1;
56
+ echo "Finished in $length seconds";
57
+ die();
58
+ }
59
+ public function sendOrderAction(){
60
+ $t1 = time();
61
+ $obj = new RetentionScience_Waves_Model_Observer();
62
+ $obj->sendOrder();
63
+ $length = time() - $t1;
64
+ echo "Finished in $length seconds";
65
+ die();
66
+ }
67
+
68
+ public function updateRScoreAction() {
69
+ $obj = new RetentionScience_Waves_Model_Observer();
70
+ $rscore_json = $obj->updateRScore();
71
+ die($rscore_json);
72
+ }
73
+ }
app/code/community/RetentionScience/Waves/etc/adminhtml.xml ADDED
@@ -0,0 +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>
app/code/community/RetentionScience/Waves/etc/config.xml ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <RetentionScience_Waves>
5
+ <version>2.0.7</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
+
38
+ <crontab>
39
+ <jobs>
40
+ <retentionscience_waves_sendcategory>
41
+ <run>
42
+ <model>waves/observer::sendCategory</model>
43
+ </run>
44
+ </retentionscience_waves_sendcategory>
45
+
46
+ <retentionscience_waves_sendproduct>
47
+ <run>
48
+ <model>waves/observer::sendProduct</model>
49
+ </run>
50
+ </retentionscience_waves_sendproduct>
51
+
52
+ <retentionscience_waves_senduser>
53
+ <run>
54
+ <model>waves/observer::sendUser</model>
55
+ </run>
56
+ </retentionscience_waves_senduser>
57
+
58
+ <retentionscience_waves_sendorder>
59
+ <run>
60
+ <model>waves/observer::sendOrder</model>
61
+ </run>
62
+ </retentionscience_waves_sendorder>
63
+ </jobs>
64
+ </crontab>
65
+
66
+ <default>
67
+ <waves>
68
+ <rs_sync_settings>
69
+ <category_process_cron>0 1 * * *</category_process_cron>
70
+ <product_process_cron>0 2 * * *</product_process_cron>
71
+ <user_process_cron>0 3 * * *</user_process_cron>
72
+ <order_process_cron>0 4 * * *</order_process_cron>
73
+ </rs_sync_settings>
74
+
75
+ <rs_sync_advanced>
76
+ <rs_php_bin>php</rs_php_bin>
77
+ <rs_send_bulk_upload>1</rs_send_bulk_upload>
78
+ <rs_use_bulk_compression>1</rs_use_bulk_compression>
79
+ <rs_bulk_use_exec>1</rs_bulk_use_exec>
80
+ <last_user_record_id>0</last_user_record_id>
81
+ <last_order_record_id>0</last_order_record_id>
82
+ </rs_sync_advanced>
83
+ </waves>
84
+ </default>
85
+
86
+ <adminhtml>
87
+ <events>
88
+ <core_block_abstract_prepare_layout_after>
89
+ <observers>
90
+ <retentionscience_waves>
91
+ <class>RetentionScience_Waves_Model_Observer</class>
92
+ <method>coreBlockAbstractPrepareLayoutAfter</method>
93
+ </retentionscience_waves>
94
+ </observers>
95
+ </core_block_abstract_prepare_layout_after>
96
+ <core_block_abstract_to_html_after>
97
+ <observers>
98
+ <retentionscience_waves>
99
+ <class>RetentionScience_Waves_Model_Observer</class>
100
+ <method>coreBlockAbstractToHtmlAfter</method>
101
+ </retentionscience_waves>
102
+ </observers>
103
+ </core_block_abstract_to_html_after>
104
+ </events>
105
+ </adminhtml>
106
+ </config>
app/code/community/RetentionScience/Waves/etc/system.xml ADDED
@@ -0,0 +1,306 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>30</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
+ </fields>
93
+ </retentionscience_settings>
94
+
95
+
96
+ <rs_sync_settings translate="label">
97
+ <label>Sync Settings</label>
98
+ <sort_order>2</sort_order>
99
+ <show_in_default>1</show_in_default>
100
+ <show_in_website>1</show_in_website>
101
+ <show_in_store>1</show_in_store>
102
+ <fields>
103
+
104
+ <category_process_status translate="label">
105
+ <label>Categories Sync Status</label>
106
+ <frontend_type>text</frontend_type>
107
+ <sort_order>40</sort_order>
108
+ <show_in_default>1</show_in_default>
109
+ <show_in_website>1</show_in_website>
110
+ <show_in_store>1</show_in_store>
111
+ </category_process_status>
112
+
113
+ <category_process_cron translate="label">
114
+ <label>Categories Sync Cron Entry</label>
115
+ <rs_cron_job>retentionscience_waves_sendcategory</rs_cron_job>
116
+ <frontend_type>text</frontend_type>
117
+ <sort_order>41</sort_order>
118
+ <backend_model>waves/source_cronconfig</backend_model>
119
+ <comment>Use Crontab Format (Eg. "0 10 * * *" for 10AM)</comment>
120
+ <show_in_default>1</show_in_default>
121
+ <show_in_website>1</show_in_website>
122
+ <show_in_store>1</show_in_store>
123
+ </category_process_cron>
124
+
125
+ <category_process_run translate="label">
126
+ <label></label>
127
+ <rs_button_url>sendcategory</rs_button_url>
128
+ <frontend_type>button</frontend_type>
129
+ <frontend_model>waves/adminhtml_syncbutton</frontend_model>
130
+ <sort_order>42</sort_order>
131
+ <show_in_default>1</show_in_default>
132
+ <show_in_website>1</show_in_website>
133
+ <show_in_store>1</show_in_store>
134
+ </category_process_run>
135
+
136
+ <product_process_status translate="label">
137
+ <label>Products Sync Status</label>
138
+ <frontend_type>text</frontend_type>
139
+ <sort_order>50</sort_order>
140
+ <show_in_default>1</show_in_default>
141
+ <show_in_website>1</show_in_website>
142
+ <show_in_store>1</show_in_store>
143
+ </product_process_status>
144
+
145
+ <product_process_cron translate="label">
146
+ <label>Products Sync Cron Entry</label>
147
+ <rs_cron_job>retentionscience_waves_sendproduct</rs_cron_job>
148
+ <frontend_type>text</frontend_type>
149
+ <backend_model>waves/source_cronconfig</backend_model>
150
+ <comment>Use Crontab Format (Eg. "0 10 * * *" for 10AM)</comment>
151
+ <sort_order>51</sort_order>
152
+ <show_in_default>1</show_in_default>
153
+ <show_in_website>1</show_in_website>
154
+ <show_in_store>1</show_in_store>
155
+ </product_process_cron>
156
+
157
+ <product_process_run translate="label">
158
+ <label></label>
159
+ <rs_button_url>sendproduct</rs_button_url>
160
+ <frontend_type>button</frontend_type>
161
+ <frontend_model>waves/adminhtml_syncbutton</frontend_model>
162
+ <sort_order>52</sort_order>
163
+ <show_in_default>1</show_in_default>
164
+ <show_in_website>1</show_in_website>
165
+ <show_in_store>1</show_in_store>
166
+ </product_process_run>
167
+
168
+ <user_process_status translate="label">
169
+ <label>Users Sync Status</label>
170
+ <frontend_type>text</frontend_type>
171
+ <sort_order>60</sort_order>
172
+ <show_in_default>1</show_in_default>
173
+ <show_in_website>1</show_in_website>
174
+ <show_in_store>1</show_in_store>
175
+ </user_process_status>
176
+
177
+ <user_process_cron translate="label">
178
+ <label>Users Sync Cron Entry</label>
179
+ <rs_cron_job>retentionscience_waves_senduser</rs_cron_job>
180
+ <frontend_type>text</frontend_type>
181
+ <backend_model>waves/source_cronconfig</backend_model>
182
+ <comment>Use Crontab Format (Eg. "0 10 * * *" for 10AM)</comment>
183
+ <sort_order>61</sort_order>
184
+ <show_in_default>1</show_in_default>
185
+ <show_in_website>1</show_in_website>
186
+ <show_in_store>1</show_in_store>
187
+ </user_process_cron>
188
+
189
+ <user_process_run translate="label">
190
+ <label></label>
191
+ <rs_button_url>senduser</rs_button_url>
192
+ <frontend_type>button</frontend_type>
193
+ <frontend_model>waves/adminhtml_syncbutton</frontend_model>
194
+ <sort_order>62</sort_order>
195
+ <show_in_default>1</show_in_default>
196
+ <show_in_website>1</show_in_website>
197
+ <show_in_store>1</show_in_store>
198
+ </user_process_run>
199
+
200
+ <order_process_status translate="label">
201
+ <label>Orders Sync Status</label>
202
+ <frontend_type>text</frontend_type>
203
+ <sort_order>70</sort_order>
204
+ <show_in_default>1</show_in_default>
205
+ <show_in_website>1</show_in_website>
206
+ <show_in_store>1</show_in_store>
207
+ </order_process_status>
208
+
209
+ <order_process_cron translate="label">
210
+ <label>Orders Sync Cron Entry</label>
211
+ <rs_cron_job>retentionscience_waves_sendorder</rs_cron_job>
212
+ <frontend_type>text</frontend_type>
213
+ <backend_model>waves/source_cronconfig</backend_model>
214
+ <comment>Use Crontab Format (Eg. "0 10 * * *" for 10AM)</comment>
215
+ <sort_order>71</sort_order>
216
+ <show_in_default>1</show_in_default>
217
+ <show_in_website>1</show_in_website>
218
+ <show_in_store>1</show_in_store>
219
+ </order_process_cron>
220
+
221
+ <order_process_run translate="label">
222
+ <label></label>
223
+ <rs_button_url>sendorder</rs_button_url>
224
+ <frontend_type>button</frontend_type>
225
+ <frontend_model>waves/adminhtml_syncbutton</frontend_model>
226
+ <sort_order>72</sort_order>
227
+ <show_in_default>1</show_in_default>
228
+ <show_in_website>1</show_in_website>
229
+ <show_in_store>1</show_in_store>
230
+ </order_process_run>
231
+ </fields>
232
+ </rs_sync_settings>
233
+
234
+ <rs_sync_advanced>
235
+ <label>Advanced Sync Settings</label>
236
+ <sort_order>3</sort_order>
237
+ <show_in_default>1</show_in_default>
238
+ <show_in_website>1</show_in_website>
239
+ <show_in_store>1</show_in_store>
240
+ <fields>
241
+ <rs_php_bin translate="label">
242
+ <label>Location of PHP bin</label>
243
+ <frontend_type>text</frontend_type>
244
+ <sort_order>95</sort_order>
245
+ <show_in_default>1</show_in_default>
246
+ <show_in_website>1</show_in_website>
247
+ <show_in_store>1</show_in_store>
248
+ </rs_php_bin>
249
+
250
+ <rs_send_bulk_upload translate="label">
251
+ <label>Use bulk upload</label>
252
+ <frontend_type>select</frontend_type>
253
+ <source_model>adminhtml/system_config_source_yesno</source_model>
254
+ <sort_order>96</sort_order>
255
+ <show_in_default>1</show_in_default>
256
+ <show_in_website>1</show_in_website>
257
+ <show_in_store>1</show_in_store>
258
+ </rs_send_bulk_upload>
259
+
260
+ <rs_use_bulk_compression translate="label">
261
+ <label>Use bulk compression</label>
262
+ <frontend_type>select</frontend_type>
263
+ <source_model>adminhtml/system_config_source_yesno</source_model>
264
+ <sort_order>97</sort_order>
265
+ <show_in_default>1</show_in_default>
266
+ <show_in_website>1</show_in_website>
267
+ <show_in_store>1</show_in_store>
268
+ </rs_use_bulk_compression>
269
+
270
+ <rs_bulk_use_exec translate="label">
271
+ <label>Use PHP exec() to save memory</label>
272
+ <frontend_type>select</frontend_type>
273
+ <source_model>adminhtml/system_config_source_yesno</source_model>
274
+ <sort_order>98</sort_order>
275
+ <show_in_default>1</show_in_default>
276
+ <show_in_website>1</show_in_website>
277
+ <show_in_store>1</show_in_store>
278
+ </rs_bulk_use_exec>
279
+
280
+ <last_user_record_id translate="label">
281
+ <label>Last sync'd user record id</label>
282
+ <frontend_type>text</frontend_type>
283
+ <sort_order>100</sort_order>
284
+ <comment>New sync process will start with user record > value</comment>
285
+ <show_in_default>1</show_in_default>
286
+ <show_in_website>1</show_in_website>
287
+ <show_in_store>1</show_in_store>
288
+ </last_user_record_id>
289
+
290
+ <last_order_record_id translate="label">
291
+ <label>Last sync'd order record id</label>
292
+ <frontend_type>text</frontend_type>
293
+ <sort_order>110</sort_order>
294
+ <comment>New sync process will start with order record > value</comment>
295
+ <show_in_default>1</show_in_default>
296
+ <show_in_website>1</show_in_website>
297
+ <show_in_store>1</show_in_store>
298
+ </last_order_record_id>
299
+ </fields>
300
+ </rs_sync_advanced>
301
+ </groups>
302
+ </waves>
303
+ </sections>
304
+
305
+
306
+ </config>
app/design/adminhtml/default/default/template/waves/rscore.phtml ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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::getUrl('waves/index/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 ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
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>
app/design/frontend/base/default/template/waves/waves.phtml ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ ?>
10
+ <script type='text/javascript'> (function() { var iBx = document.createElement('script'); iBx.type = 'text/javascript'; iBx.async =
11
+ true; iBx.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'waves.retentionscience.com/w.js';
12
+ (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(iBx); })();
13
+ </script>
14
+ <script type="text/javascript">
15
+ var rsci_init = function(){
16
+ rsci_wave.set_site_id('<?php echo $this->getSiteid();?>');
17
+ <?php if($loggedIn) { ?>
18
+ <?php $user_id_set = $this->customerId(); ?>
19
+ rsci_wave.set_user_id('<?php echo $this->customerId();?>');
20
+ <?php }
21
+
22
+ if($moduleName=="catalog" && $controllerName=="product" && $actionName=="view"){
23
+ $productId['id'] = $this->getRequest()->getParam('id');
24
+ ?>
25
+ rsci_wave.add_item(<?php echo json_encode($productId)?>);
26
+ <?php }
27
+
28
+ if($moduleName=="checkout" && $controllerName=="cart" && $actionName=="index"){ ?>
29
+ rsci_wave.set_action('shopping_cart');
30
+ // has 1 or more items in shopping cart
31
+ <?php
32
+ $allItems = Mage::getModel('checkout/cart')->getQuote()->getAllItems();
33
+ foreach ($allItems as $item){
34
+ $itemArr['id'] = $item->getProductId();
35
+ $itemArr['name'] = $item->getName();
36
+ $itemArr['price'] = $item->getPrice();
37
+ ?>
38
+ rsci_wave.add_item(<?php echo json_encode($itemArr) ?>);
39
+ <?php }
40
+ }
41
+
42
+ if($moduleName=="checkout" && $controllerName=="onepage" && $actionName=="success"){
43
+ $lastOrderId = Mage::getSingleton('checkout/session')->getLastOrderId();
44
+ $order = $this->getOrder(); ?>
45
+
46
+ rsci_wave.set_action('checkout_success');
47
+ // Order info consists of order_id, and total_price
48
+ rsci_wave.add_order_info('<?php echo $this->getOrderId();?>', '<?php echo $order->getBaseGrandTotal();?>');
49
+ // purchased and checked out successfully with 1 or more items
50
+ <?php
51
+ if (empty($user_id_set)) {
52
+ $user_record_id = md5(trim(strtolower($order->getCustomerEmail())));
53
+ echo "\n // guest \n";
54
+ echo "\n rsci_wave.set_user_id('" . $user_record_id . "'); \n";
55
+ }
56
+ $allitems = $order->getAllItems();
57
+ foreach($allitems as $item){
58
+ $itemArr['id'] = $item->getProductId();
59
+ $itemArr['name'] = $item->getName();
60
+ $itemArr['price'] = $item->getPrice();
61
+ ?>
62
+ rsci_wave.add_item(<?php echo json_encode($itemArr) ?>);
63
+ <?php }
64
+ }
65
+
66
+ ?> } // rsci_init end
67
+ </script>
68
+ <?php if($this->isAjaxAddToCartEnable()) { ?>
69
+ <script src="<?php echo Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_JS)."RetentionScience/retention_science_wave.js";?>"></script>
70
+ <script type="text/javascript">
71
+ setAjaxSendCartUrl('<?php echo Mage::getUrl('waves/index/scriptRun') ?>');
72
+ </script>
73
+ <?php }
74
+ }
75
+ ?>
app/etc/modules/RetentionScience_Waves.xml ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
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/RetentionScience/retention_science_wave.js ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+
11
+ var json = transport.responseText.evalJSON();
12
+ siteID = json.siteID;
13
+
14
+ rsci_init = function(){
15
+ rsci_wave.set_site_id(siteID);
16
+ rsci_wave.set_action('shopping_cart');
17
+
18
+ if(json.customerId!=""){
19
+ rsci_wave.set_user_id(json.customerId);
20
+ }
21
+
22
+ items = json.items.evalJSON();
23
+ items.each(function(item){
24
+ var data = {id:item.id, name:item.name, price:item.price };
25
+ //var jsonItem = Object.toJSON(data);
26
+ rsci_wave.add_item(data);
27
+ });
28
+ };
29
+
30
+ (function() { var iBx = document.createElement('script'); iBx.type = 'text/javascript'; iBx.async =
31
+ true; iBx.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'waves.retentionscience.com/w.js';
32
+ (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(iBx); })();
33
+
34
+ //rsci_init();
35
+ }, method: "get"
36
+ });
37
+ }
38
+ }
package.xml ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <package>
3
+ <name>RetentionScience_Waves</name>
4
+ <version>2.0.7</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>Bulk transfer of products is default</notes>
20
+ <authors><author><name>Retention Science</name><user>auto-converted</user><email>support@retentionscience.com</email></author></authors>
21
+ <date>2013-01-26</date>
22
+ <time>11:18:41</time>
23
+ <contents><target name="magecommunity"><dir name="RetentionScience"><dir name="Waves"><dir name="Block"><dir name="Adminhtml"><file name="Rscore.php" hash="93919181411e46af838c6cfb872d3f31"/><file name="Syncbutton.php" hash="fc52a166cc3d020818797bced63d7ae5"/></dir><file name="Waves.php" hash="a2c0c64d0dbbb9d458f6d0a8ec854f75"/></dir><dir name="Helper"><file name="Data.php" hash="90490af254a670d4795b744c1ef4319e"/></dir><dir name="Model"><dir name="Source"><dir name="Cron"><file name="Frequency.php" hash="027feb7796f79b7cf811c4236ad7b87a"/><file name="Hours.php" hash="0ab9157003d5e7efed402ed401a46134"/></dir><file name="Categorytree.php" hash="58ca152ea2a34c7992460ece01b12bd8"/><file name="Cronconfig.php" hash="d8ae966b08bad48e68618343f7a27569"/><file name="Rscoredata.php" hash="a60f52a76b6097cdc0fb64e7218939dc"/></dir><file name="Observer.php" hash="0faf165015a943c51ba383521302cb21"/><file name="retention_science_api.php" hash="d0d6944d90fc91f8b4c8a9595619c580"/><file name="rs_send_orders.php" hash="b79f12c9e6039320c239048685057b8f"/><file name="rs_send_products.php" hash="53c3b2494746021d9eebfec13fefe59a"/><file name="rs_send_users.php" hash="12752511aa1f8e413ded28b7e4a95936"/></dir><dir name="controllers"><file name="IndexController.php" hash="de70b24b32acaf6989329f6be0385fe0"/></dir><dir name="etc"><file name="adminhtml.xml" hash="1378650fdb7ecc596f9881d7eefca868"/><file name="config.xml" hash="6125393b50c24a5662347b1a9fdc6764"/><file name="system.xml" hash="9ec62a9230e4c070fb797c3a0d80bdd1"/></dir></dir><file name=".DS_Store" hash="128e595394427daa0503e6d824d6b4ef"/></dir></target><target name="mageweb"><dir name="js"><dir name="RetentionScience"><dir name="RetentionScience"><file name="retention_science_wave.js" hash="2a2584125f96c48c061a6fed5d1e0653"/></dir></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="04828984bbd986cbe098bca2a6d30bb1"/></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="bec902beb86d449dceef39bddf179943"/></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>