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