Version Notes
Submit async orders to Metrilo to handle drops on external payment pages.
Download this release
Release Info
| Developer | Murry Ivanoff |
| Extension | Metrilo_Analytics |
| Version | 1.1.0 |
| Comparing to | |
| See all releases | |
Code changes from version 1.0.8 to 1.1.0
- app/code/community/Metrilo/Analytics/Block/Adminhtml/System/Config/Form/Button.php +2 -1
- app/code/community/Metrilo/Analytics/Helper/AsyncHttpClient.php +80 -0
- app/code/community/Metrilo/Analytics/Helper/Data.php +153 -78
- app/code/community/Metrilo/Analytics/Model/Observer.php +49 -71
- app/code/community/Metrilo/Analytics/controllers/Adminhtml/AjaxController.php +3 -35
- app/code/community/Metrilo/Analytics/etc/config.xml +1 -1
- app/design/adminhtml/default/default/template/metrilo/system/config/button.phtml +1 -1
- app/design/frontend/base/default/template/metrilo/head.phtml +1 -1
- package.xml +5 -5
app/code/community/Metrilo/Analytics/Block/Adminhtml/System/Config/Form/Button.php
CHANGED
|
@@ -37,6 +37,7 @@ class Metrilo_Analytics_Block_Adminhtml_System_Config_Form_Button extends Mage_A
|
|
| 37 |
{
|
| 38 |
$html = parent::_toHtml();
|
| 39 |
$helper = Mage::helper('metrilo_analytics');
|
|
|
|
| 40 |
if($helper->isEnabled() && $helper->getApiToken() && $helper->getApiSecret())
|
| 41 |
return $html;
|
| 42 |
}
|
|
@@ -78,4 +79,4 @@ class Metrilo_Analytics_Block_Adminhtml_System_Config_Form_Button extends Mage_A
|
|
| 78 |
|
| 79 |
return $button->toHtml();
|
| 80 |
}
|
| 81 |
-
}
|
| 37 |
{
|
| 38 |
$html = parent::_toHtml();
|
| 39 |
$helper = Mage::helper('metrilo_analytics');
|
| 40 |
+
|
| 41 |
if($helper->isEnabled() && $helper->getApiToken() && $helper->getApiSecret())
|
| 42 |
return $html;
|
| 43 |
}
|
| 79 |
|
| 80 |
return $button->toHtml();
|
| 81 |
}
|
| 82 |
+
}
|
app/code/community/Metrilo/Analytics/Helper/AsyncHttpClient.php
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
/**
|
| 3 |
+
* Helper class for metrilo properties
|
| 4 |
+
*
|
| 5 |
+
* @author Zhivko Draganov <zhivko@metrilo.com>
|
| 6 |
+
*/
|
| 7 |
+
class Metrilo_Analytics_Helper_AsyncHttpClient extends Mage_Core_Helper_Abstract
|
| 8 |
+
{
|
| 9 |
+
/**
|
| 10 |
+
* Create HTTP GET async request to URL
|
| 11 |
+
*
|
| 12 |
+
* @param String $url
|
| 13 |
+
* @return void
|
| 14 |
+
*/
|
| 15 |
+
public function get($url)
|
| 16 |
+
{
|
| 17 |
+
$parsedUrl = parse_url($url);
|
| 18 |
+
$raw = $this->_buildRawGet($parsedUrl['host'], $parsedUrl['path']);
|
| 19 |
+
|
| 20 |
+
$fp = fsockopen(
|
| 21 |
+
$parsedUrl['host'],
|
| 22 |
+
isset($parsedUrl['port']) ? $parsedUrl['port'] : 80,
|
| 23 |
+
$errno, $errstr, 30);
|
| 24 |
+
|
| 25 |
+
if ($fp) {
|
| 26 |
+
fwrite($fp, $raw);
|
| 27 |
+
fclose($fp);
|
| 28 |
+
}
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
/**
|
| 32 |
+
* Create HTTP POSTasync request to URL
|
| 33 |
+
*
|
| 34 |
+
* @param String $url
|
| 35 |
+
* @param Array $bodyArray
|
| 36 |
+
* @return void
|
| 37 |
+
*/
|
| 38 |
+
public function post($url, $bodyArray = false)
|
| 39 |
+
{
|
| 40 |
+
$parsedUrl = parse_url($url);
|
| 41 |
+
$encodedBody = $bodyArray ? json_encode($bodyArray) : '';
|
| 42 |
+
|
| 43 |
+
$raw = $this->_buildRawPost($parsedUrl['host'], $parsedUrl['path'], $encodedBody);
|
| 44 |
+
|
| 45 |
+
$fp = fsockopen(
|
| 46 |
+
$parsedUrl['host'],
|
| 47 |
+
isset($parsedUrl['port']) ? $parsedUrl['port'] : 80,
|
| 48 |
+
$errno, $errstr, 30);
|
| 49 |
+
|
| 50 |
+
if ($fp) {
|
| 51 |
+
fwrite($fp, $raw);
|
| 52 |
+
fclose($fp);
|
| 53 |
+
}
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
private function _buildRawGet($host, $path)
|
| 57 |
+
{
|
| 58 |
+
$out = "GET ".$path." HTTP/1.1\r\n";
|
| 59 |
+
$out .= "Host: ".$host."\r\n";
|
| 60 |
+
// $out .= "Accept: application/json\r\n";
|
| 61 |
+
$out .= "Connection: Close\r\n\r\n";
|
| 62 |
+
|
| 63 |
+
return $out;
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
private function _buildRawPost($host, $path, $encodedCall)
|
| 67 |
+
{
|
| 68 |
+
$out = "POST ".$path." HTTP/1.1\r\n";
|
| 69 |
+
$out .= "Host: ".$host."\r\n";
|
| 70 |
+
$out .= "Content-Type: application/json\r\n";
|
| 71 |
+
$out .= "Content-Length: ".strlen($encodedCall)."\r\n";
|
| 72 |
+
$out .= "Accept: */*\r\n";
|
| 73 |
+
$out .= "User-Agent: AsyncHttpClient/1.0.0\r\n";
|
| 74 |
+
$out .= "Connection: Close\r\n\r\n";
|
| 75 |
+
|
| 76 |
+
$out .= $encodedCall;
|
| 77 |
+
|
| 78 |
+
return $out;
|
| 79 |
+
}
|
| 80 |
+
}
|
app/code/community/Metrilo/Analytics/Helper/Data.php
CHANGED
|
@@ -50,7 +50,7 @@ class Metrilo_Analytics_Helper_Data extends Mage_Core_Helper_Abstract
|
|
| 50 |
/**
|
| 51 |
* Add event to queue
|
| 52 |
*
|
| 53 |
-
* @param string $method Can be
|
| 54 |
* @param string $type
|
| 55 |
* @param string|array $data
|
| 56 |
*/
|
|
@@ -100,6 +100,8 @@ class Metrilo_Analytics_Helper_Data extends Mage_Core_Helper_Abstract
|
|
| 100 |
'payment_method' => $order->getPayment()->getMethodInstance()->getTitle(),
|
| 101 |
);
|
| 102 |
|
|
|
|
|
|
|
| 103 |
if ($order->getCouponCode()) {
|
| 104 |
$data['coupons'] = array($order->getCouponCode());
|
| 105 |
}
|
|
@@ -132,81 +134,99 @@ class Metrilo_Analytics_Helper_Data extends Mage_Core_Helper_Abstract
|
|
| 132 |
}
|
| 133 |
$data['items'][] = $dataItem;
|
| 134 |
}
|
|
|
|
| 135 |
return $data;
|
| 136 |
}
|
| 137 |
|
| 138 |
/**
|
| 139 |
-
* Create HTTP request to
|
| 140 |
*
|
| 141 |
-
* @param
|
| 142 |
-
* @param string $event
|
| 143 |
-
* @param array $params
|
| 144 |
-
* @param boolean|array $identityData
|
| 145 |
-
* @param boolean|int $time
|
| 146 |
-
* @param boolean|array $callParameters
|
| 147 |
* @return void
|
| 148 |
*/
|
| 149 |
-
public function callApi($
|
| 150 |
{
|
| 151 |
try {
|
| 152 |
-
$
|
| 153 |
-
// We should handle the setting of token parameter, as it's part of the request
|
| 154 |
-
$call['token'] = $this->getApiToken();
|
| 155 |
-
|
| 156 |
-
// Additional ksort here because of adding token param
|
| 157 |
-
ksort($call);
|
| 158 |
-
$basedCall = base64_encode(Mage::helper('core')->jsonEncode($call));
|
| 159 |
-
$signature = md5($basedCall.$this->getApiSecret());
|
| 160 |
-
// Use Varien_Http_Client
|
| 161 |
-
// to generate API call end point and call it
|
| 162 |
-
$url = 'http://p.metrilo.com/t?s='.$signature.'&hs='.$basedCall;
|
| 163 |
-
$client = new Varien_Http_Client($url);
|
| 164 |
-
$response = $client->request();
|
| 165 |
-
$result = Mage::helper('core')->jsonDecode($response->getBody());
|
| 166 |
-
if (!$result['status']) {
|
| 167 |
-
Mage::log($result['error'], null, 'Metrilo_Analytics.log');
|
| 168 |
-
}
|
| 169 |
} catch (Exception $e){
|
| 170 |
Mage::log($e->getMessage(), null, 'Metrilo_Analytics.log');
|
| 171 |
}
|
| 172 |
}
|
| 173 |
|
| 174 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 175 |
{
|
| 176 |
try {
|
| 177 |
-
|
| 178 |
-
$
|
| 179 |
-
$
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
);
|
|
|
|
|
|
|
| 186 |
|
| 187 |
-
|
| 188 |
-
ksort($call);
|
| 189 |
|
| 190 |
-
|
| 191 |
-
|
|
|
|
|
|
|
| 192 |
|
| 193 |
-
|
| 194 |
-
|
|
|
|
|
|
|
| 195 |
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 203 |
|
| 204 |
-
|
| 205 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 206 |
}
|
| 207 |
-
} catch (Exception $e) {
|
| 208 |
-
Mage::log($e->getMessage(), null, 'Metrilo_Analytics.log');
|
| 209 |
}
|
|
|
|
|
|
|
| 210 |
}
|
| 211 |
|
| 212 |
/**
|
|
@@ -220,31 +240,86 @@ class Metrilo_Analytics_Helper_Data extends Mage_Core_Helper_Abstract
|
|
| 220 |
* @param boolean|array $callParameters
|
| 221 |
* @return void
|
| 222 |
*/
|
| 223 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 224 |
{
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
|
| 233 |
-
|
| 234 |
-
// check for special parameters to include in the API call
|
| 235 |
-
if($callParameters) {
|
| 236 |
-
if($callParameters['use_ip']) {
|
| 237 |
-
$call['use_ip'] = $callParameters['use_ip'];
|
| 238 |
-
}
|
| 239 |
-
}
|
| 240 |
-
// put identity data in call if available
|
| 241 |
-
if($identityData) {
|
| 242 |
-
$call['identity'] = $identityData;
|
| 243 |
-
}
|
| 244 |
-
|
| 245 |
-
// Prepare keys is alphabetical order
|
| 246 |
-
ksort($call);
|
| 247 |
-
|
| 248 |
-
return $call;
|
| 249 |
}
|
| 250 |
}
|
| 50 |
/**
|
| 51 |
* Add event to queue
|
| 52 |
*
|
| 53 |
+
* @param string $method Can be identify|track
|
| 54 |
* @param string $type
|
| 55 |
* @param string|array $data
|
| 56 |
*/
|
| 100 |
'payment_method' => $order->getPayment()->getMethodInstance()->getTitle(),
|
| 101 |
);
|
| 102 |
|
| 103 |
+
$this->_assignBillingInfo($data, $order);
|
| 104 |
+
|
| 105 |
if ($order->getCouponCode()) {
|
| 106 |
$data['coupons'] = array($order->getCouponCode());
|
| 107 |
}
|
| 134 |
}
|
| 135 |
$data['items'][] = $dataItem;
|
| 136 |
}
|
| 137 |
+
|
| 138 |
return $data;
|
| 139 |
}
|
| 140 |
|
| 141 |
/**
|
| 142 |
+
* Create HTTP request to Metrilo API to sync single order
|
| 143 |
*
|
| 144 |
+
* @param Mage_Sales_Model_Order $order
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 145 |
* @return void
|
| 146 |
*/
|
| 147 |
+
public function callApi($order, $async = false)
|
| 148 |
{
|
| 149 |
try {
|
| 150 |
+
$this->callBatchApi(array($order), $async);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 151 |
} catch (Exception $e){
|
| 152 |
Mage::log($e->getMessage(), null, 'Metrilo_Analytics.log');
|
| 153 |
}
|
| 154 |
}
|
| 155 |
|
| 156 |
+
/**
|
| 157 |
+
* Create HTTP request to Metrilo API to sync multiple orders
|
| 158 |
+
*
|
| 159 |
+
* @param Array(Mage_Sales_Model_Order) $orders
|
| 160 |
+
* @return void
|
| 161 |
+
*/
|
| 162 |
+
public function callBatchApi($orders, $async = false)
|
| 163 |
{
|
| 164 |
try {
|
| 165 |
+
$ordersForSubmition = $this->_buildOrdersForSubmition($orders);
|
| 166 |
+
$call = $this->_buildCall($ordersForSubmition);
|
| 167 |
+
if ($async) {
|
| 168 |
+
$this->_callMetriloApiAsync($call);
|
| 169 |
+
} else {
|
| 170 |
+
$this->_callMetriloApi($call);
|
| 171 |
+
}
|
| 172 |
+
} catch (Exception $e) {
|
| 173 |
+
Mage::log($e->getMessage(), null, 'Metrilo_Analytics.log');
|
| 174 |
+
}
|
| 175 |
+
}
|
| 176 |
|
| 177 |
+
// Private functions start here
|
|
|
|
| 178 |
|
| 179 |
+
private function _callMetriloApiAsync($call) {
|
| 180 |
+
ksort($call);
|
| 181 |
+
$basedCall = base64_encode(Mage::helper('core')->jsonEncode($call));
|
| 182 |
+
$signature = md5($basedCall.$this->getApiSecret());
|
| 183 |
|
| 184 |
+
$requestBody = array(
|
| 185 |
+
's' => $signature,
|
| 186 |
+
'hs' => $basedCall
|
| 187 |
+
);
|
| 188 |
|
| 189 |
+
$asyncHttpHelper = Mage::helper('metrilo_analytics/asynchttpclient');
|
| 190 |
+
$asyncHttpHelper->post('http://p.metrilo.com/bt', $requestBody);
|
| 191 |
+
}
|
| 192 |
+
|
| 193 |
+
private function _callMetriloApi($call) {
|
| 194 |
+
// Prepare call for submition
|
| 195 |
+
ksort($call);
|
| 196 |
+
$basedCall = base64_encode(Mage::helper('core')->jsonEncode($call));
|
| 197 |
+
$signature = md5($basedCall.$this->getApiSecret());
|
| 198 |
+
|
| 199 |
+
$requestBody = array(
|
| 200 |
+
's' => $signature,
|
| 201 |
+
'hs' => $basedCall
|
| 202 |
+
);
|
| 203 |
+
|
| 204 |
+
$client = new Varien_Http_Client('http://p.metrilo.com/bt');
|
| 205 |
+
|
| 206 |
+
// This method supports passing named array as well as key, value
|
| 207 |
+
$client->setParameterPost($requestBody);
|
| 208 |
+
$response = $client->request('POST');
|
| 209 |
+
|
| 210 |
+
if ($response->isError()) {
|
| 211 |
+
Mage::log($response->getBody(), null, 'Metrilo_Analytics.log');
|
| 212 |
+
}
|
| 213 |
+
}
|
| 214 |
|
| 215 |
+
/**
|
| 216 |
+
* Create submition ready arrays from Array of Mage_Sales_Model_Order
|
| 217 |
+
* @param Array(Mage_Sales_Model_Order) $orders
|
| 218 |
+
* @return Array of Arrays
|
| 219 |
+
*/
|
| 220 |
+
private function _buildOrdersForSubmition($orders) {
|
| 221 |
+
$ordersForSubmition = array();
|
| 222 |
+
|
| 223 |
+
foreach ($orders as $order) {
|
| 224 |
+
if ($order->getId()) {
|
| 225 |
+
array_push($ordersForSubmition, $this->_buildOrderForSubmition($order));
|
| 226 |
}
|
|
|
|
|
|
|
| 227 |
}
|
| 228 |
+
|
| 229 |
+
return $ordersForSubmition;
|
| 230 |
}
|
| 231 |
|
| 232 |
/**
|
| 240 |
* @param boolean|array $callParameters
|
| 241 |
* @return void
|
| 242 |
*/
|
| 243 |
+
private function _buildEventArray($ident, $event, $params, $identityData = false, $time = false, $callParameters = false)
|
| 244 |
+
{
|
| 245 |
+
$call = array(
|
| 246 |
+
'event_type' => $event,
|
| 247 |
+
'params' => $params,
|
| 248 |
+
'uid' => $ident
|
| 249 |
+
);
|
| 250 |
+
if($time) {
|
| 251 |
+
$call['time'] = $time;
|
| 252 |
+
}
|
| 253 |
+
|
| 254 |
+
// check for special parameters to include in the API call
|
| 255 |
+
if($callParameters) {
|
| 256 |
+
if($callParameters['use_ip']) {
|
| 257 |
+
$call['use_ip'] = $callParameters['use_ip'];
|
| 258 |
+
}
|
| 259 |
+
}
|
| 260 |
+
// put identity data in call if available
|
| 261 |
+
if($identityData) {
|
| 262 |
+
$call['identity'] = $identityData;
|
| 263 |
+
}
|
| 264 |
+
|
| 265 |
+
// Prepare keys is alphabetical order
|
| 266 |
+
ksort($call);
|
| 267 |
+
|
| 268 |
+
return $call;
|
| 269 |
+
}
|
| 270 |
+
|
| 271 |
+
private function _buildOrderForSubmition($order) {
|
| 272 |
+
$orderDetails = $this->prepareOrderDetails($order);
|
| 273 |
+
// initialize additional params
|
| 274 |
+
$callParameters = false;
|
| 275 |
+
// check if order has customer IP in it
|
| 276 |
+
$ip = $order->getRemoteIp();
|
| 277 |
+
if ($ip) {
|
| 278 |
+
$callParameters = array('use_ip' => $ip);
|
| 279 |
+
}
|
| 280 |
+
// initialize time
|
| 281 |
+
$time = false;
|
| 282 |
+
if ($order->getCreatedAtStoreDate()) {
|
| 283 |
+
$time = $order->getCreatedAtStoreDate()->getTimestamp() * 1000;
|
| 284 |
+
}
|
| 285 |
+
|
| 286 |
+
$identityData = $this->_orderIdentityData($order);
|
| 287 |
+
|
| 288 |
+
return $this->_buildEventArray(
|
| 289 |
+
$identityData['email'], 'order', $orderDetails, $identityData, $time, $callParameters
|
| 290 |
+
);
|
| 291 |
+
}
|
| 292 |
+
|
| 293 |
+
|
| 294 |
+
private function _orderIdentityData($order) {
|
| 295 |
+
return array(
|
| 296 |
+
'email' => $order->getCustomerEmail(),
|
| 297 |
+
'first_name' => $order->getBillingAddress()->getFirstname(),
|
| 298 |
+
'last_name' => $order->getBillingAddress()->getLastname(),
|
| 299 |
+
'name' => $order->getBillingAddress()->getName(),
|
| 300 |
+
);
|
| 301 |
+
}
|
| 302 |
+
|
| 303 |
+
private function _buildCall($ordersForSubmition) {
|
| 304 |
+
return array(
|
| 305 |
+
'token' => $this->getApiToken(),
|
| 306 |
+
'events' => $ordersForSubmition,
|
| 307 |
+
// for debugging/support purposes
|
| 308 |
+
'platform' => 'Magento ' . Mage::getEdition() . ' ' . Mage::getVersion(),
|
| 309 |
+
'version' => (string)Mage::getConfig()->getModuleConfig("Metrilo_Analytics")->version
|
| 310 |
+
);
|
| 311 |
+
}
|
| 312 |
+
|
| 313 |
+
private function _assignBillingInfo(&$data, $order)
|
| 314 |
{
|
| 315 |
+
$billingAddress = $order->getBillingAddress();
|
| 316 |
+
# Assign billing data to order data array
|
| 317 |
+
$data['billing_phone'] = $billingAddress->getTelephone();
|
| 318 |
+
$data['billing_country'] = $billingAddress->getCountryId();
|
| 319 |
+
$data['billing_region'] = $billingAddress->getRegion();
|
| 320 |
+
$data['billing_city'] = $billingAddress->getCity();
|
| 321 |
+
$data['billing_postcode'] = $billingAddress->getPostcode();
|
| 322 |
+
$data['billing_address'] = $billingAddress->getStreetFull();
|
| 323 |
+
$data['billing_company'] = $billingAddress->getCompany();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 324 |
}
|
| 325 |
}
|
app/code/community/Metrilo/Analytics/Model/Observer.php
CHANGED
|
@@ -1,8 +1,9 @@
|
|
| 1 |
<?php
|
| 2 |
/**
|
| 3 |
-
* Catch events and track them to
|
| 4 |
*
|
| 5 |
* @author Miroslav Petrov <miro91tn@gmail.com>
|
|
|
|
| 6 |
*/
|
| 7 |
class Metrilo_Analytics_Model_Observer
|
| 8 |
{
|
|
@@ -74,7 +75,7 @@ class Metrilo_Analytics_Model_Observer
|
|
| 74 |
return;
|
| 75 |
}
|
| 76 |
// category view pages
|
| 77 |
-
if($action == 'catalog_category_view') {
|
| 78 |
$category = Mage::registry('current_category');
|
| 79 |
$data = array(
|
| 80 |
'id' => $category->getId(),
|
|
@@ -93,10 +94,10 @@ class Metrilo_Analytics_Model_Observer
|
|
| 93 |
'url' => $product->getProductUrl()
|
| 94 |
);
|
| 95 |
// Additional information ( image and categories )
|
| 96 |
-
if($product->getImage())
|
| 97 |
$data['image_url'] = (string)Mage::helper('catalog/image')->init($product, 'image');
|
| 98 |
|
| 99 |
-
if(count($product->getCategoryIds())) {
|
| 100 |
$categories = array();
|
| 101 |
$collection = $product->getCategoryCollection()->addAttributeToSelect('*');
|
| 102 |
foreach ($collection as $category) {
|
|
@@ -111,7 +112,7 @@ class Metrilo_Analytics_Model_Observer
|
|
| 111 |
return;
|
| 112 |
}
|
| 113 |
// cart view
|
| 114 |
-
if($action == 'checkout_cart_index') {
|
| 115 |
$helper->addEvent('track', 'view_cart', array());
|
| 116 |
return;
|
| 117 |
}
|
|
@@ -122,19 +123,6 @@ class Metrilo_Analytics_Model_Observer
|
|
| 122 |
}
|
| 123 |
}
|
| 124 |
|
| 125 |
-
/**
|
| 126 |
-
* Events that we don't want to track
|
| 127 |
-
*
|
| 128 |
-
* @param string event
|
| 129 |
-
*/
|
| 130 |
-
private function _isRejected($event)
|
| 131 |
-
{
|
| 132 |
-
return in_array(
|
| 133 |
-
$event,
|
| 134 |
-
array('catalogsearch_advanced_result', 'catalogsearch_advanced_index')
|
| 135 |
-
);
|
| 136 |
-
}
|
| 137 |
-
|
| 138 |
/**
|
| 139 |
* Event for adding product to cart
|
| 140 |
* "checkout_cart_product_add_after"
|
|
@@ -165,39 +153,6 @@ class Metrilo_Analytics_Model_Observer
|
|
| 165 |
|
| 166 |
}
|
| 167 |
|
| 168 |
-
/**
|
| 169 |
-
* Add to cart event
|
| 170 |
-
*
|
| 171 |
-
* @param integer $productId
|
| 172 |
-
* @param Mage_Catalog_Model_Product $item
|
| 173 |
-
* @param integer $qty
|
| 174 |
-
*/
|
| 175 |
-
private function _addToCart($productId, $item, $qty) {
|
| 176 |
-
$helper = Mage::helper('metrilo_analytics');
|
| 177 |
-
$product = Mage::getModel('catalog/product')->load($productId);
|
| 178 |
-
|
| 179 |
-
$data = array(
|
| 180 |
-
'id' => (int)$product->getId(),
|
| 181 |
-
'price' => (float)$product->getFinalPrice(),
|
| 182 |
-
'name' => $product->getName(),
|
| 183 |
-
'url' => $product->getProductUrl(),
|
| 184 |
-
'quantity' => $qty
|
| 185 |
-
);
|
| 186 |
-
|
| 187 |
-
// Add options for grouped or configurable products
|
| 188 |
-
if ($item->isGrouped() || $item->isConfigurable()) {
|
| 189 |
-
$data['id'] = $item->getId();
|
| 190 |
-
$data['name'] = $item->getName();
|
| 191 |
-
$data['url'] = $item->getProductUrl();
|
| 192 |
-
// Options
|
| 193 |
-
$data['option_id'] = $product->getSku();
|
| 194 |
-
$data['option_name'] = trim(str_replace("-", " ", $product->getName()));
|
| 195 |
-
$data['option_price'] = (float)$product->getFinalPrice();
|
| 196 |
-
}
|
| 197 |
-
|
| 198 |
-
$helper->addEvent('track', 'add_to_cart', $data);
|
| 199 |
-
}
|
| 200 |
-
|
| 201 |
/**
|
| 202 |
* Event for removing item from shopping bag
|
| 203 |
*
|
|
@@ -270,30 +225,53 @@ class Metrilo_Analytics_Model_Observer
|
|
| 270 |
public function updateOrder(Varien_Event_Observer $observer)
|
| 271 |
{
|
| 272 |
$helper = Mage::helper('metrilo_analytics');
|
| 273 |
-
$
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
$callParameters = false;
|
| 277 |
|
| 278 |
-
|
| 279 |
-
|
| 280 |
-
|
| 281 |
-
|
| 282 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 283 |
|
| 284 |
-
|
| 285 |
-
|
| 286 |
-
|
| 287 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 288 |
|
| 289 |
-
$
|
| 290 |
-
'
|
| 291 |
-
'
|
| 292 |
-
'
|
| 293 |
-
'
|
|
|
|
| 294 |
);
|
| 295 |
|
| 296 |
-
|
| 297 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 298 |
|
|
|
|
|
|
|
| 299 |
}
|
| 1 |
<?php
|
| 2 |
/**
|
| 3 |
+
* Catch events and track them to Metrilo API
|
| 4 |
*
|
| 5 |
* @author Miroslav Petrov <miro91tn@gmail.com>
|
| 6 |
+
* @author Zhivko Draganov <zhivko@metrilo.com>
|
| 7 |
*/
|
| 8 |
class Metrilo_Analytics_Model_Observer
|
| 9 |
{
|
| 75 |
return;
|
| 76 |
}
|
| 77 |
// category view pages
|
| 78 |
+
if ($action == 'catalog_category_view') {
|
| 79 |
$category = Mage::registry('current_category');
|
| 80 |
$data = array(
|
| 81 |
'id' => $category->getId(),
|
| 94 |
'url' => $product->getProductUrl()
|
| 95 |
);
|
| 96 |
// Additional information ( image and categories )
|
| 97 |
+
if ($product->getImage())
|
| 98 |
$data['image_url'] = (string)Mage::helper('catalog/image')->init($product, 'image');
|
| 99 |
|
| 100 |
+
if (count($product->getCategoryIds())) {
|
| 101 |
$categories = array();
|
| 102 |
$collection = $product->getCategoryCollection()->addAttributeToSelect('*');
|
| 103 |
foreach ($collection as $category) {
|
| 112 |
return;
|
| 113 |
}
|
| 114 |
// cart view
|
| 115 |
+
if ($action == 'checkout_cart_index') {
|
| 116 |
$helper->addEvent('track', 'view_cart', array());
|
| 117 |
return;
|
| 118 |
}
|
| 123 |
}
|
| 124 |
}
|
| 125 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 126 |
/**
|
| 127 |
* Event for adding product to cart
|
| 128 |
* "checkout_cart_product_add_after"
|
| 153 |
|
| 154 |
}
|
| 155 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 156 |
/**
|
| 157 |
* Event for removing item from shopping bag
|
| 158 |
*
|
| 225 |
public function updateOrder(Varien_Event_Observer $observer)
|
| 226 |
{
|
| 227 |
$helper = Mage::helper('metrilo_analytics');
|
| 228 |
+
$helper->callApi($observer->getOrder(), true);
|
| 229 |
+
}
|
|
|
|
|
|
|
| 230 |
|
| 231 |
+
/**
|
| 232 |
+
* Events that we don't want to track
|
| 233 |
+
*
|
| 234 |
+
* @param string event
|
| 235 |
+
*/
|
| 236 |
+
private function _isRejected($event)
|
| 237 |
+
{
|
| 238 |
+
return in_array(
|
| 239 |
+
$event,
|
| 240 |
+
array('catalogsearch_advanced_result', 'catalogsearch_advanced_index')
|
| 241 |
+
);
|
| 242 |
+
}
|
| 243 |
|
| 244 |
+
/**
|
| 245 |
+
* Add to cart event
|
| 246 |
+
*
|
| 247 |
+
* @param integer $productId
|
| 248 |
+
* @param Mage_Catalog_Model_Product $item
|
| 249 |
+
* @param integer $qty
|
| 250 |
+
*/
|
| 251 |
+
private function _addToCart($productId, $item, $qty)
|
| 252 |
+
{
|
| 253 |
+
$helper = Mage::helper('metrilo_analytics');
|
| 254 |
+
$product = Mage::getModel('catalog/product')->load($productId);
|
| 255 |
|
| 256 |
+
$data = array(
|
| 257 |
+
'id' => (int)$product->getId(),
|
| 258 |
+
'price' => (float)$product->getFinalPrice(),
|
| 259 |
+
'name' => $product->getName(),
|
| 260 |
+
'url' => $product->getProductUrl(),
|
| 261 |
+
'quantity' => $qty
|
| 262 |
);
|
| 263 |
|
| 264 |
+
// Add options for grouped or configurable products
|
| 265 |
+
if ($item->isGrouped() || $item->isConfigurable()) {
|
| 266 |
+
$data['id'] = $item->getId();
|
| 267 |
+
$data['name'] = $item->getName();
|
| 268 |
+
$data['url'] = $item->getProductUrl();
|
| 269 |
+
// Options
|
| 270 |
+
$data['option_id'] = $product->getSku();
|
| 271 |
+
$data['option_name'] = trim(str_replace("-", " ", $product->getName()));
|
| 272 |
+
$data['option_price'] = (float)$product->getFinalPrice();
|
| 273 |
+
}
|
| 274 |
|
| 275 |
+
$helper->addEvent('track', 'add_to_cart', $data);
|
| 276 |
+
}
|
| 277 |
}
|
app/code/community/Metrilo/Analytics/controllers/Adminhtml/AjaxController.php
CHANGED
|
@@ -19,42 +19,10 @@ class Metrilo_Analytics_Adminhtml_AjaxController extends Mage_Adminhtml_Controll
|
|
| 19 |
try {
|
| 20 |
$import = Mage::getSingleton('metrilo_analytics/import');
|
| 21 |
$chunkId = (int)$this->getRequest()->getParam('chunk_id');
|
|
|
|
| 22 |
$orders = $import->getOrders($chunkId);
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
foreach ($orders as $order) {
|
| 26 |
-
if ($order->getId()) {
|
| 27 |
-
$orderDetails = $helper->prepareOrderDetails($order);
|
| 28 |
-
|
| 29 |
-
$callParameters = false;
|
| 30 |
-
|
| 31 |
-
// check if order has customer IP in it
|
| 32 |
-
$ip = $order->getRemoteIp();
|
| 33 |
-
if($ip){
|
| 34 |
-
$callParameters = array('use_ip' => $ip);
|
| 35 |
-
}
|
| 36 |
-
|
| 37 |
-
$time = false;
|
| 38 |
-
if ($order->getCreatedAtStoreDate()) {
|
| 39 |
-
$time = $order->getCreatedAtStoreDate()->getTimestamp() * 1000;
|
| 40 |
-
}
|
| 41 |
-
|
| 42 |
-
$identityData = array(
|
| 43 |
-
'email' => $order->getCustomerEmail(),
|
| 44 |
-
'first_name' => $order->getBillingAddress()->getFirstname(),
|
| 45 |
-
'last_name' => $order->getBillingAddress()->getLastname(),
|
| 46 |
-
'name' => $order->getBillingAddress()->getName(),
|
| 47 |
-
);
|
| 48 |
-
|
| 49 |
-
$builtEventArray = $helper->buildEventArray(
|
| 50 |
-
$identityData['email'], 'order', $orderDetails, $identityData, $time, $callParameters
|
| 51 |
-
);
|
| 52 |
-
|
| 53 |
-
array_push($ordersForSubmition, $builtEventArray);
|
| 54 |
-
}
|
| 55 |
-
}
|
| 56 |
-
|
| 57 |
-
$helper->callBatchApi($ordersForSubmition);
|
| 58 |
$result['success'] = true;
|
| 59 |
} catch (Exception $e) {
|
| 60 |
Mage::logException($e);
|
| 19 |
try {
|
| 20 |
$import = Mage::getSingleton('metrilo_analytics/import');
|
| 21 |
$chunkId = (int)$this->getRequest()->getParam('chunk_id');
|
| 22 |
+
// Get orders from the Database
|
| 23 |
$orders = $import->getOrders($chunkId);
|
| 24 |
+
// Send orders via API helper method
|
| 25 |
+
$helper->callBatchApi($orders);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
$result['success'] = true;
|
| 27 |
} catch (Exception $e) {
|
| 28 |
Mage::logException($e);
|
app/code/community/Metrilo/Analytics/etc/config.xml
CHANGED
|
@@ -8,7 +8,7 @@
|
|
| 8 |
<config>
|
| 9 |
<modules>
|
| 10 |
<Metrilo_Analytics>
|
| 11 |
-
<version>1.0
|
| 12 |
</Metrilo_Analytics>
|
| 13 |
</modules>
|
| 14 |
<frontend>
|
| 8 |
<config>
|
| 9 |
<modules>
|
| 10 |
<Metrilo_Analytics>
|
| 11 |
+
<version>1.1.0</version>
|
| 12 |
</Metrilo_Analytics>
|
| 13 |
</modules>
|
| 14 |
<frontend>
|
app/design/adminhtml/default/default/template/metrilo/system/config/button.phtml
CHANGED
|
@@ -21,7 +21,7 @@
|
|
| 21 |
jQuery.post('<?php echo $this->getAjaxUrl(); ?>', data, function(response) {
|
| 22 |
new_chunk_id = chunk_id + 1;
|
| 23 |
if(new_chunk_id < total_chunks){
|
| 24 |
-
setTimeout(function(){
|
| 25 |
sync_chunk(new_chunk_id);
|
| 26 |
}, 100);
|
| 27 |
}else{
|
| 21 |
jQuery.post('<?php echo $this->getAjaxUrl(); ?>', data, function(response) {
|
| 22 |
new_chunk_id = chunk_id + 1;
|
| 23 |
if(new_chunk_id < total_chunks){
|
| 24 |
+
setTimeout(function() {
|
| 25 |
sync_chunk(new_chunk_id);
|
| 26 |
}, 100);
|
| 27 |
}else{
|
app/design/frontend/base/default/template/metrilo/head.phtml
CHANGED
|
@@ -5,7 +5,7 @@ window.metrilo||(window.metrilo=[]),window.metrilo.queue=[],window.metrilo.metho
|
|
| 5 |
window.metrilo.skelet=function(e){return function(){a=Array.prototype.slice.call(arguments);a.unshift(e);window.metrilo.queue.push(a)}};
|
| 6 |
for(var i=0;window.metrilo.methods.length>i;i++){var mthd=window.metrilo.methods[i];window.metrilo[mthd]=window.metrilo.skelet(mthd)}
|
| 7 |
window.metrilo.load=function(e){var t=document,n=t.getElementsByTagName("script")[0],r=t.createElement("script");
|
| 8 |
-
r.type="text/javascript";r.async=true;r.src="//
|
| 9 |
metrilo.load("<?php echo $helper->getApiToken(); ?>");
|
| 10 |
|
| 11 |
<?php foreach ($events as $event) : ?>
|
| 5 |
window.metrilo.skelet=function(e){return function(){a=Array.prototype.slice.call(arguments);a.unshift(e);window.metrilo.queue.push(a)}};
|
| 6 |
for(var i=0;window.metrilo.methods.length>i;i++){var mthd=window.metrilo.methods[i];window.metrilo[mthd]=window.metrilo.skelet(mthd)}
|
| 7 |
window.metrilo.load=function(e){var t=document,n=t.getElementsByTagName("script")[0],r=t.createElement("script");
|
| 8 |
+
r.type="text/javascript";r.async=true;r.src="//t.metrilo.com/j/"+e+".js";n.parentNode.insertBefore(r,n)};
|
| 9 |
metrilo.load("<?php echo $helper->getApiToken(); ?>");
|
| 10 |
|
| 11 |
<?php foreach ($events as $event) : ?>
|
package.xml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
<?xml version="1.0"?>
|
| 2 |
<package>
|
| 3 |
<name>Metrilo_Analytics</name>
|
| 4 |
-
<version>1.0
|
| 5 |
<stability>stable</stability>
|
| 6 |
<license>Apache Software License (ASL)</license>
|
| 7 |
<channel>community</channel>
|
|
@@ -18,11 +18,11 @@
|
|
| 18 |
* Powerful intelligence for your sales team&#xD;
|
| 19 |
* With Metrilo, you have an amazing real-time overview of who's doing what on your eCommerce store.&#xD;
|
| 20 |
* Metrilo automatically collects and analyzes your eCommerce data to use for your email campaigns.</description>
|
| 21 |
-
<notes>
|
| 22 |
<authors><author><name>Murry Ivanoff</name><user>Metrilo</user><email>murry@metrilo.com</email></author><author><name>Zhivko Draganov</name><user>zhivko</user><email>zhivko@metirlo.com</email></author><author><name>Miroslav Petrov</name><user>miro</user><email>miro91tn@gmail.com</email></author></authors>
|
| 23 |
-
<date>2016-
|
| 24 |
-
<time>
|
| 25 |
-
<contents><target name="magecommunity"><dir name="Metrilo"><dir name="Analytics"><dir name="Block"><dir name="Adminhtml"><dir name="System"><dir name="Config"><dir name="Form"><file name="Button.php" hash="
|
| 26 |
<compatible/>
|
| 27 |
<dependencies><required><php><min>5.2.1</min><max>5.6.22</max></php></required></dependencies>
|
| 28 |
</package>
|
| 1 |
<?xml version="1.0"?>
|
| 2 |
<package>
|
| 3 |
<name>Metrilo_Analytics</name>
|
| 4 |
+
<version>1.1.0</version>
|
| 5 |
<stability>stable</stability>
|
| 6 |
<license>Apache Software License (ASL)</license>
|
| 7 |
<channel>community</channel>
|
| 18 |
* Powerful intelligence for your sales team&#xD;
|
| 19 |
* With Metrilo, you have an amazing real-time overview of who's doing what on your eCommerce store.&#xD;
|
| 20 |
* Metrilo automatically collects and analyzes your eCommerce data to use for your email campaigns.</description>
|
| 21 |
+
<notes>Submit async orders to Metrilo to handle drops on external payment pages.</notes>
|
| 22 |
<authors><author><name>Murry Ivanoff</name><user>Metrilo</user><email>murry@metrilo.com</email></author><author><name>Zhivko Draganov</name><user>zhivko</user><email>zhivko@metirlo.com</email></author><author><name>Miroslav Petrov</name><user>miro</user><email>miro91tn@gmail.com</email></author></authors>
|
| 23 |
+
<date>2016-03-28</date>
|
| 24 |
+
<time>08:01:26</time>
|
| 25 |
+
<contents><target name="magecommunity"><dir name="Metrilo"><dir name="Analytics"><dir name="Block"><dir name="Adminhtml"><dir name="System"><dir name="Config"><dir name="Form"><file name="Button.php" hash="056b366e98b9a61a5594679ae4b15cdd"/></dir></dir></dir></dir><file name="Head.php" hash="7fc6870506f8882520b4e2b9596600d7"/></dir><dir name="Helper"><file name="AsyncHttpClient.php" hash="1a4a85f68808e3eee8651a82f86093c5"/><file name="Data.php" hash="9430df17c85bc59687f46cdcaa7cbb28"/></dir><dir name="Model"><file name="Import.php" hash="1eb20cd00c210ee378039edb8d0515dc"/><file name="Observer.php" hash="3a1a7ad40a6d385c7acfe39844660b7c"/></dir><dir name="controllers"><dir name="Adminhtml"><file name="AjaxController.php" hash="e99c1af2e7c9cb18dc2b5ee61022f87b"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="00c90fdba5e48bb35367c16c83abd6a7"/><file name="config.xml" hash="c85a9993d7046eb8e6a52f7684268ff3"/><file name="system.xml" hash="7564c68e51df23d7975bc1c9ead7be8f"/></dir></dir></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><file name="metrilo_analytics.xml" hash="0e6911e2e883992f2182969286d929b1"/></dir><dir name="template"><dir name="metrilo"><dir name="system"><dir name="config"><file name="button.phtml" hash="c69dd7d8286cdff217c8c18c8ef5e2e9"/></dir></dir></dir></dir></dir></dir></dir><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><file name="metrilo_analytics.xml" hash="c7dcf4057bc31d906865e82159ac5eca"/></dir><dir name="template"><dir name="metrilo"><file name="head.phtml" hash="c32d5255058eefcc623c51a1dc51c23e"/></dir></dir></dir></dir></dir></target><target name="mageskin"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="metrilo"><file name="favicon-metrilo.png" hash="743558f1e49a730be9d515197a36567b"/><file name="loader.gif" hash="e05e6bb35d035cac4f3e0c8af213e9ab"/><file name="logo.png" hash="e9e54afd81384e12f77aca4eaebf5be8"/><file name="styles.css" hash="da0c07513d917e4ad08ff50814b536e1"/></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Metrilo_Analytics.xml" hash="3a4dbecc4e093537f11dd4c8fa2756e7"/></dir></target></contents>
|
| 26 |
<compatible/>
|
| 27 |
<dependencies><required><php><min>5.2.1</min><max>5.6.22</max></php></required></dependencies>
|
| 28 |
</package>
|
