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
- app/code/community/RetentionScience/.DS_Store +0 -0
- app/code/community/RetentionScience/Waves/Block/Adminhtml/Rscore.php +11 -0
- app/code/community/RetentionScience/Waves/Block/Adminhtml/Syncbutton.php +40 -0
- app/code/community/RetentionScience/Waves/Block/Waves.php +74 -0
- app/code/community/RetentionScience/Waves/Helper/Data.php +5 -0
- app/code/community/RetentionScience/Waves/Model/Observer.php +756 -0
- app/code/community/RetentionScience/Waves/Model/Source/Categorytree.php +62 -0
- app/code/community/RetentionScience/Waves/Model/Source/Cron/Frequency.php +29 -0
- app/code/community/RetentionScience/Waves/Model/Source/Cron/Hours.php +19 -0
- app/code/community/RetentionScience/Waves/Model/Source/Cronconfig.php +33 -0
- app/code/community/RetentionScience/Waves/Model/Source/Rscoredata.php +107 -0
- app/code/community/RetentionScience/Waves/Model/retention_science_api.php +254 -0
- app/code/community/RetentionScience/Waves/Model/rs_send_orders.php +43 -0
- app/code/community/RetentionScience/Waves/Model/rs_send_products.php +44 -0
- app/code/community/RetentionScience/Waves/Model/rs_send_users.php +43 -0
- app/code/community/RetentionScience/Waves/controllers/IndexController.php +73 -0
- app/code/community/RetentionScience/Waves/etc/adminhtml.xml +23 -0
- app/code/community/RetentionScience/Waves/etc/config.xml +106 -0
- app/code/community/RetentionScience/Waves/etc/system.xml +306 -0
- app/design/adminhtml/default/default/template/waves/rscore.phtml +101 -0
- app/design/frontend/base/default/layout/waves.xml +9 -0
- app/design/frontend/base/default/template/waves/waves.phtml +75 -0
- app/etc/modules/RetentionScience_Waves.xml +9 -0
- js/RetentionScience/RetentionScience/retention_science_wave.js +38 -0
- 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.
|
11 |
+

|
12 |
+
We have created the first ever personalized retention marketing platform to help you understand and target each customer individually.
|
13 |
+

|
14 |
+
We leverage big data analytics and machine learning to optimize retention strategies, provide product recommendations, and generate targeted discounts and promotional offers. 
|
15 |
+

|
16 |
+
Our technology enables your store to leverage massive social media, demographic, and behavioral datasets - powerful information sources to help you drive sales. 
|
17 |
+

|
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>
|