Metrilo_Analytics - Version 1.0.0

Version Notes

The first stable version of Metrilo's integration with Magento

Download this release

Release Info

Developer Murry Ivanoff
Extension Metrilo_Analytics
Version 1.0.0
Comparing to
See all releases


Version 1.0.0

app/code/community/Metrilo/Analytics/Block/Adminhtml/System/Config/Form/Button.php ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Button widget class
4
+ * Add import model and render button view
5
+ *
6
+ * @author Miroslav Petrov <miro91tn@gmail.com>
7
+ */
8
+ class Metrilo_Analytics_Block_Adminhtml_System_Config_Form_Button extends Mage_Adminhtml_Block_System_Config_Form_Field
9
+ {
10
+ /**
11
+ * Set template
12
+ *
13
+ * @return void
14
+ */
15
+ protected function _construct()
16
+ {
17
+ parent::_construct();
18
+ $this->setTemplate('metrilo/system/config/button.phtml');
19
+ }
20
+
21
+ /**
22
+ * Get import instance
23
+ *
24
+ * @return Metrilo_Analytics_Model_Import
25
+ */
26
+ public function getImport()
27
+ {
28
+ return Mage::getSingleton('metrilo_analytics/import');
29
+ }
30
+
31
+ /**
32
+ * Render metrilo js if module is enabled
33
+ *
34
+ * @return string
35
+ */
36
+ protected function _toHtml()
37
+ {
38
+ $html = parent::_toHtml();
39
+ $helper = Mage::helper('metrilo_analytics');
40
+ if($helper->isEnabled() && $helper->getApiToken() && $helper->getApiSecret())
41
+ return $html;
42
+ }
43
+
44
+ /**
45
+ * Return element html
46
+ *
47
+ * @param Varien_Data_Form_Element_Abstract $element
48
+ * @return string
49
+ */
50
+ protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
51
+ {
52
+ return $this->_toHtml();
53
+ }
54
+
55
+ /**
56
+ * Return ajax url for button
57
+ *
58
+ * @return string
59
+ */
60
+ public function getAjaxUrl()
61
+ {
62
+ return Mage::helper('adminhtml')->getUrl("metrilo_analytics/adminhtml_ajax", array('isAjax'=> true));
63
+ }
64
+
65
+ /**
66
+ * Generate button html
67
+ *
68
+ * @return string
69
+ */
70
+ public function getButtonHtml()
71
+ {
72
+ $button = $this->getLayout()->createBlock('adminhtml/widget_button')
73
+ ->setData(array(
74
+ 'id' => 'metrilo_button',
75
+ 'label' => $this->helper('adminhtml')->__('Import orders'),
76
+ 'onclick' => 'javascript:import_metrilo(); return false;'
77
+ ));
78
+
79
+ return $button->toHtml();
80
+ }
81
+ }
app/code/community/Metrilo/Analytics/Block/Head.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Block for head part who render all js lines
4
+ *
5
+ * @author Miroslav Petrov <miro91tn@gmail.com>
6
+ */
7
+ class Metrilo_Analytics_Block_Head extends Mage_Core_Block_Template
8
+ {
9
+ /**
10
+ * key in session storage
11
+ */
12
+ const DATA_TAG = "metrilo_events";
13
+
14
+ /**
15
+ * Get events to track them to metrilo js api
16
+ *
17
+ * @return array
18
+ */
19
+ public function getEvents()
20
+ {
21
+ $helper = Mage::helper('metrilo_analytics');
22
+ $events = (array)Mage::getSingleton('core/session')->getData(self::DATA_TAG);
23
+ // clear events from session ater get events once
24
+ Mage::getSingleton('core/session')->setData(self::DATA_TAG,'');
25
+ return array_filter($events);
26
+ }
27
+
28
+ /**
29
+ * Render metrilo js if module is enabled
30
+ *
31
+ * @return string
32
+ */
33
+ protected function _toHtml()
34
+ {
35
+ $html = parent::_toHtml();
36
+ if(Mage::helper('metrilo_analytics')->isEnabled())
37
+ return $html;
38
+ }
39
+ }
app/code/community/Metrilo/Analytics/Helper/Data.php ADDED
@@ -0,0 +1,230 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Helper class for metrilo properties
4
+ *
5
+ * @author Miroslav Petrov <miro91tn@gmail.com>
6
+ */
7
+ class Metrilo_Analytics_Helper_Data extends Mage_Core_Helper_Abstract
8
+ {
9
+
10
+ /**
11
+ * Get session instance
12
+ *
13
+ * @return Mage_Core_Model_Session
14
+ */
15
+ public function getSession()
16
+ {
17
+ return Mage::getSingleton('core/session');
18
+ }
19
+
20
+ /**
21
+ * Check if metrilo module is enabled
22
+ *
23
+ * @return boolean
24
+ */
25
+ public function isEnabled()
26
+ {
27
+ return Mage::getStoreConfig('metrilo_analytics_settings/settings/enable');
28
+ }
29
+
30
+ /**
31
+ * Get API Token from system configuration
32
+ *
33
+ * @return string
34
+ */
35
+ public function getApiToken()
36
+ {
37
+ return Mage::getStoreConfig('metrilo_analytics_settings/settings/api_key');
38
+ }
39
+
40
+ /**
41
+ * Get API Secret from system configuration
42
+ *
43
+ * @return string
44
+ */
45
+ public function getApiSecret()
46
+ {
47
+ return Mage::getStoreConfig('metrilo_analytics_settings/settings/api_secret');
48
+ }
49
+
50
+ /**
51
+ * Add event to queue
52
+ *
53
+ * @param string $method Can be identiy|track
54
+ * @param string $type
55
+ * @param string|array $data
56
+ */
57
+ public function addEvent($method, $type, $data)
58
+ {
59
+ $events = (array)$this->getSession()->getData(Metrilo_Analytics_Block_Head::DATA_TAG);
60
+ $events[] = array(
61
+ 'method' => $method,
62
+ 'type' => $type,
63
+ 'data' => $data
64
+ );
65
+ $this->getSession()->setData(Metrilo_Analytics_Block_Head::DATA_TAG, $events);
66
+ }
67
+
68
+ /**
69
+ * Get order details and sort them for metrilo
70
+ *
71
+ * @param Mage_Sales_Model_Order $order
72
+ * @return array
73
+ */
74
+ public function prepareOrderDetails($order)
75
+ {
76
+ $data = array(
77
+ 'order_id' => $order->getIncrementId(),
78
+ 'order_status' => $order->getStatus(),
79
+ 'amount' => (float)$order->getGrandTotal(),
80
+ 'shipping_amount' => (float)$order->getShippingAmount(),
81
+ 'tax_amount' => $order->getTaxAmount(),
82
+ 'items' => array(),
83
+ 'shipping_method' => $order->getShippingDescription(),
84
+ 'payment_method' => $order->getPayment()->getMethodInstance()->getTitle(),
85
+ );
86
+
87
+ if ($order->getCouponCode()) {
88
+ $data['coupons'] = $order->getCouponCode();
89
+ }
90
+ $skusAdded = array();
91
+ foreach ($order->getAllItems() as $item) {
92
+ if (in_array($item->getSku(), $skusAdded)) continue;
93
+
94
+ $skusAdded[] = $item->getSku();
95
+ $dataItem = array(
96
+ 'id' => $item->getProductId(),
97
+ 'price' => (float)$item->getPrice() ? $item->getPrice() : $item->getProduct()->getFinalPrice(),
98
+ 'name' => $item->getName(),
99
+ 'url' => $item->getProduct()->getProductUrl(),
100
+ 'quantity' => (int)$item->getQtyOrdered()
101
+ );
102
+ if ($item->getProductType() == 'configurable' || $item->getProductType() == 'grouped') {
103
+ if ($item->getProductType() == 'grouped') {
104
+ $parentIds = Mage::getModel('catalog/product_type_grouped')->getParentIdsByChild($item->getProductId());
105
+ $parentId = $parentIds[0];
106
+ } else {
107
+ $parentId = $item->getProductId();
108
+ }
109
+ $mainProduct = Mage::getModel('catalog/product')->load($parentId);
110
+ $dataItem['id'] = $mainProduct->getId();
111
+ $dataItem['name'] = $mainProduct->getName();
112
+ $dataItem['url'] = $mainProduct->getProductUrl();
113
+ $dataItem['option_id'] = $item->getSku();
114
+ $dataItem['option_name'] = trim(str_replace("-", " ", $item->getName()));
115
+ $dataItem['option_price'] = (float)$item->getPrice();
116
+ }
117
+ $data['items'][] = $dataItem;
118
+ }
119
+ return $data;
120
+ }
121
+
122
+ /**
123
+ * Create HTTP request to metrilo server
124
+ *
125
+ * @param string $ident
126
+ * @param string $event
127
+ * @param array $params
128
+ * @param boolean|array $identityData
129
+ * @param boolean|int $time
130
+ * @param boolean|array $callParameters
131
+ * @return void
132
+ */
133
+ public function callApi($ident, $event, $params, $identityData = false, $time = false, $callParameters = false)
134
+ {
135
+ try {
136
+ $call = $this->buildEventArray($ident, $event, $params, $identityData, $time, $callParameters);
137
+ // We should handle the setting of token parameter, as it's part of the request
138
+ $call['token'] = $this->getApiToken();
139
+
140
+ // Additional ksort here because of adding token param
141
+ ksort($call);
142
+ $basedCall = base64_encode(Mage::helper('core')->jsonEncode($call));
143
+ $signature = md5($basedCall.$this->getApiSecret());
144
+ // Use Varien_Http_Client
145
+ // to generate API call end point and call it
146
+ $url = 'http://p.metrilo.com/t?s='.$signature.'&hs='.$basedCall;
147
+ $client = new Varien_Http_Client($url);
148
+ $response = $client->request();
149
+ $result = Mage::helper('core')->jsonDecode($response->getBody());
150
+ if (!$result['status']) {
151
+ Mage::log($result['error'], null, 'Metrilo_Analytics.log');
152
+ }
153
+ } catch (Exception $e){
154
+ Mage::log($e->getMessage(), null, 'Metrilo_Analytics.log');
155
+ }
156
+ }
157
+
158
+ public function callBatchApi($ordersForSubmition)
159
+ {
160
+ try {
161
+ // Consider token is in the first level in the hashed json
162
+ $call = array(
163
+ 'token' => $this->getApiToken(),
164
+ 'events' => $ordersForSubmition
165
+ );
166
+
167
+ // Additional ksort here because of adding token param
168
+ ksort($call);
169
+
170
+ $basedCall = base64_encode(Mage::helper('core')->jsonEncode($call));
171
+ $signature = md5($basedCall.$this->getApiSecret());
172
+
173
+ $url = 'http://p.metrilo.com/bt';
174
+ $client = new Varien_Http_Client($url);
175
+
176
+ $requestBody = array(
177
+ 's' => $signature,
178
+ 'hs' => $basedCall
179
+ );
180
+ // This method supports passing named array as well as key, value
181
+ $client->setParameterPost($requestBody);
182
+ $response = $client->request('POST');
183
+
184
+ if ($response->isError()) {
185
+ Mage::log($response->getBody(), null, 'Metrilo_Analytics.log');
186
+ }
187
+ } catch (Exception $e) {
188
+ Mage::log($e->getMessage(), null, 'Metrilo_Analytics.log');
189
+ }
190
+ }
191
+
192
+ /**
193
+ * Build event array ready for encoding and encrypting. Built array is returned using ksort.
194
+ *
195
+ * @param string $ident
196
+ * @param string $event
197
+ * @param array $params
198
+ * @param boolean|array $identityData
199
+ * @param boolean|int $time
200
+ * @param boolean|array $callParameters
201
+ * @return void
202
+ */
203
+ public function buildEventArray($ident, $event, $params, $identityData = false, $time = false, $callParameters = false)
204
+ {
205
+ $call = array(
206
+ 'event_type' => $event,
207
+ 'params' => $params,
208
+ 'uid' => $ident
209
+ );
210
+ if($time) {
211
+ $call['time'] = $time;
212
+ }
213
+
214
+ // check for special parameters to include in the API call
215
+ if($callParameters) {
216
+ if($callParameters['use_ip']) {
217
+ $call['use_ip'] = $callParameters['use_ip'];
218
+ }
219
+ }
220
+ // put identity data in call if available
221
+ if($identityData) {
222
+ $call['identity'] = $identityData;
223
+ }
224
+
225
+ // Prepare keys is alphabetical order
226
+ ksort($call);
227
+
228
+ return $call;
229
+ }
230
+ }
app/code/community/Metrilo/Analytics/Model/Import.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Import model which collect all previous orders
4
+ *
5
+ * @author Miroslav Petrov <miro91tn@gmail.com>
6
+ */
7
+ class Metrilo_Analytics_Model_Import extends Mage_Core_Model_Abstract
8
+ {
9
+ private $_ordersTotal = 0;
10
+ private $_totalChunks = 0;
11
+ private $_chunkItems = 15;
12
+
13
+ /**
14
+ * Prepare all order ids
15
+ *
16
+ * @return void
17
+ */
18
+ public function _construct()
19
+ {
20
+ // prepare to fetch all orders
21
+ $this->_ordersTotal = Mage::getModel('sales/order')->getCollection()->getSize();
22
+ $this->_totalChunks = (int)ceil($this->_ordersTotal / $this->_chunkItems);
23
+ }
24
+
25
+ /**
26
+ * Get chunk orders
27
+ *
28
+ * @param int
29
+ * @return Varien_Data_Collection
30
+ */
31
+ public function getOrders($chunkId)
32
+ {
33
+ return Mage::getModel('sales/order')
34
+ ->getCollection()
35
+ ->setPageSize($this->_chunkItems)
36
+ ->setCurPage($chunkId + 1);
37
+ }
38
+
39
+ /**
40
+ * Chenks array
41
+ *
42
+ * @return array
43
+ */
44
+ public function getChunks()
45
+ {
46
+ return $this->_totalChunks;
47
+ }
48
+ }
app/code/community/Metrilo/Analytics/Model/Observer.php ADDED
@@ -0,0 +1,257 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Catch events and track them to metrilo api
4
+ *
5
+ * @author Miroslav Petrov <miro91tn@gmail.com>
6
+ */
7
+ class Metrilo_Analytics_Model_Observer
8
+ {
9
+ /**
10
+ * Identify customer after login
11
+ *
12
+ * @param Varien_Event_Observer $observer
13
+ * @return void
14
+ */
15
+ public function customerLogin(Varien_Event_Observer $observer)
16
+ {
17
+ $helper = Mage::helper('metrilo_analytics');
18
+ $customer = $observer->getEvent()->getCustomer();
19
+ $data = array(
20
+ 'id' => $customer->getId(),
21
+ 'params' => array(
22
+ 'email' => $customer->getEmail(),
23
+ 'name' => $customer->getName(),
24
+ 'first_name' => $customer->getFirstname(),
25
+ 'last_name' => $customer->getLastname(),
26
+ )
27
+ );
28
+ $helper->addEvent('identify', 'identify', $data);
29
+ }
30
+
31
+ /**
32
+ * Track page views
33
+ * - homepage & CMS pages
34
+ * - product view pages
35
+ * - category view pages
36
+ * - cart view
37
+ * - checkout
38
+ * - any other pages (get title from head)
39
+ *
40
+ * @param Varien_Event_Observer $observer
41
+ * @return void
42
+ */
43
+ public function trackPageView(Varien_Event_Observer $observer)
44
+ {
45
+ $helper = Mage::helper('metrilo_analytics');
46
+ $action = $observer->getEvent()->getAction()->getFullActionName();
47
+ $pageTracked = false;
48
+ // homepage & CMS pages
49
+ if ($action == 'cms_index_index' || $action == 'cms_page_view') {
50
+ $title = Mage::getSingleton('cms/page')->getTitle();
51
+ $helper->addEvent('track', 'pageview', $title);
52
+ $pageTracked = true;
53
+ }
54
+ // category view pages
55
+ if($action == 'catalog_category_view') {
56
+ $category = Mage::registry('current_category');
57
+ $data = array(
58
+ 'id' => $category->getId(),
59
+ 'name' => $category->getName()
60
+ );
61
+ $helper->addEvent('track', 'view_category', $data);
62
+ $pageTracked = true;
63
+ }
64
+ // product view pages
65
+ if ($action == 'catalog_product_view') {
66
+ $product = Mage::registry('current_product');
67
+ $data = array(
68
+ 'id' => $product->getId(),
69
+ 'name' => $product->getName(),
70
+ 'price' => $product->getFinalPrice(),
71
+ 'url' => $product->getProductUrl()
72
+ );
73
+ // Additional information ( image and categories )
74
+ if($product->getImage())
75
+ $data['image_url'] = (string)Mage::helper('catalog/image')->init($product, 'image');
76
+
77
+ if(count($product->getCategoryIds())) {
78
+ $categories = array();
79
+ $collection = $product->getCategoryCollection()->addAttributeToSelect('*');
80
+ foreach ($collection as $category) {
81
+ $categories[] = array(
82
+ 'id' => $category->getId(),
83
+ 'name' => $category->getName()
84
+ );
85
+ }
86
+ $data['categories'] = $categories;
87
+ }
88
+ $helper->addEvent('track', 'view_product', $data);
89
+ $pageTracked = true;
90
+ }
91
+ // cart view
92
+ if($action == 'checkout_cart_index') {
93
+ $helper->addEvent('track', 'view_cart', array());
94
+ $pageTracked = true;
95
+ }
96
+ // checkout
97
+ if ($action != 'checkout_cart_index' && strpos($action, 'checkout') !== false && strpos($action, 'success') === false) {
98
+ $helper->addEvent('track', 'checkout_start', array());
99
+ $pageTracked = true;
100
+ }
101
+ // Any other pages
102
+ if(!$pageTracked) {
103
+ $title = $observer->getEvent()->getLayout()->getBlock('head')->getTitle();
104
+ $helper->addEvent('track', 'pageview', $title);
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Event for adding product to cart
110
+ * "checkout_cart_product_add_after"
111
+ *
112
+ * @param Varien_Event_Observer $observer [description]
113
+ */
114
+ public function addToCart(Varien_Event_Observer $observer)
115
+ {
116
+ /**
117
+ * @var Mage_Sales_Model_Quote_Item
118
+ */
119
+ $item = $observer->getQuoteItem();
120
+ $product = $item->getProduct();
121
+ $cartProduct = $observer->getProduct();
122
+
123
+ if ($cartProduct->isGrouped()) {
124
+ $options = Mage::app()->getRequest()->getParam('super_group');
125
+ if (is_array($options)) {
126
+ foreach ($options as $productId => $qty) {
127
+ $this->_addToCart((int)$productId, $cartProduct, (int)$qty);
128
+ }
129
+ }
130
+ } elseif($cartProduct->isConfigurable()) {
131
+ $this->_addToCart($product->getId(), $cartProduct, $item->getQty());
132
+ } else {
133
+ $this->_addToCart($cartProduct->getId(), $cartProduct, $item->getQty());
134
+ }
135
+
136
+ }
137
+
138
+ /**
139
+ * Add to cart event
140
+ *
141
+ * @param integer $productId
142
+ * @param Mage_Catalog_Model_Product $item
143
+ * @param integer $qty
144
+ */
145
+ private function _addToCart($productId, $item, $qty) {
146
+ $helper = Mage::helper('metrilo_analytics');
147
+ $product = Mage::getModel('catalog/product')->load($productId);
148
+
149
+ $data = array(
150
+ 'id' => (int)$product->getId(),
151
+ 'price' => (float)$product->getFinalPrice(),
152
+ 'name' => $product->getName(),
153
+ 'url' => $product->getProductUrl(),
154
+ 'quantity' => $qty
155
+ );
156
+
157
+ // Add options for grouped or configurable products
158
+ if ($item->isGrouped() || $item->isConfigurable()) {
159
+ $data['id'] = $item->getId();
160
+ $data['name'] = $item->getName();
161
+ $data['url'] = $item->getProductUrl();
162
+ // Options
163
+ $data['option_id'] = $product->getSku();
164
+ $data['option_name'] = trim(str_replace("-", " ", $product->getName()));
165
+ $data['option_price'] = (float)$product->getFinalPrice();
166
+ }
167
+
168
+ $helper->addEvent('track', 'add_to_cart', $data);
169
+ }
170
+
171
+ /**
172
+ * Event for removing item from shopping bag
173
+ *
174
+ * @param Varien_Event_Observer $observer
175
+ * @return void
176
+ */
177
+ public function removeFromCart(Varien_Event_Observer $observer)
178
+ {
179
+ $helper = Mage::helper('metrilo_analytics');
180
+ $item = $observer->getQuoteItem();
181
+ $product = $item->getProduct();
182
+
183
+ $data = array(
184
+ 'id' => $product->getId()
185
+ );
186
+
187
+ $helper->addEvent('track', 'remove_from_cart', $data);
188
+ }
189
+
190
+ /**
191
+ * Track placing a new order from customer
192
+ *
193
+ * @param Varien_Event_Observer $observer
194
+ * @return void
195
+ */
196
+ public function trackNewOrder(Varien_Event_Observer $observer)
197
+ {
198
+ $helper = Mage::helper('metrilo_analytics');
199
+ $data = array();
200
+ $order = $observer->getOrder();
201
+ if ($order->getId()) {
202
+ $data = $helper->prepareOrderDetails($order);
203
+ $helper->addEvent('track', 'order', $data);
204
+ }
205
+ }
206
+
207
+ /**
208
+ * Track adding discount codes in shopping bag
209
+ *
210
+ * @param Varien_Event_Observer $observer
211
+ * @return void
212
+ */
213
+ public function trackCoupon(Varien_Event_Observer $observer)
214
+ {
215
+ $helper = Mage::helper('metrilo_analytics');
216
+ $code = Mage::getSingleton('checkout/cart')->getQuote()->getCouponCode();
217
+ if (strlen($code)) {
218
+ $helper->addEvent('track', 'applied_coupon', $code);
219
+ }
220
+ }
221
+
222
+ /**
223
+ * Send order information after save
224
+ *
225
+ * @param Varien_Event_Observer $observer
226
+ * @return void
227
+ */
228
+ public function updateOrder(Varien_Event_Observer $observer)
229
+ {
230
+ $helper = Mage::helper('metrilo_analytics');
231
+ $order = $observer->getOrder();
232
+ $orderDetails = $helper->prepareOrderDetails($order);
233
+
234
+ $callParameters = false;
235
+
236
+ // check if order has customer IP in it
237
+ $ip = $order->getRemoteIp();
238
+ if ($ip){
239
+ $callParameters = array('use_ip' => $ip);
240
+ }
241
+
242
+ $time = false;
243
+ if ($order->getCreatedAtStoreDate()) {
244
+ $time = $order->getCreatedAtStoreDate()->getTimestamp() * 1000;
245
+ }
246
+
247
+ $identityData = array(
248
+ 'email' => $order->getCustomerEmail(),
249
+ 'first_name' => $order->getBillingAddress()->getFirstname(),
250
+ 'last_name' => $order->getBillingAddress()->getLastname(),
251
+ 'name' => $order->getBillingAddress()->getName(),
252
+ );
253
+
254
+ $helper->callApi($identityData['email'], 'order', $orderDetails, $identityData, $time, $callParameters);
255
+ }
256
+
257
+ }
app/code/community/Metrilo/Analytics/controllers/Adminhtml/AjaxController.php ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Ajax controller for sending orders to metrilo
4
+ *
5
+ * @author Miroslav Petrov <miro91tn@gmail.com>
6
+ */
7
+ class Metrilo_Analytics_Adminhtml_AjaxController extends Mage_Adminhtml_Controller_Action
8
+ {
9
+ /**
10
+ * Import order chunks
11
+ *
12
+ * @return void
13
+ */
14
+ public function indexAction()
15
+ {
16
+ $result = array();
17
+ $result['success'] = false;
18
+ $helper = Mage::helper('metrilo_analytics');
19
+ try {
20
+ $import = Mage::getSingleton('metrilo_analytics/import');
21
+ $chunkId = (int)$this->getRequest()->getParam('chunk_id');
22
+ $orders = $import->getOrders($chunkId);
23
+ $ordersForSubmition = array();
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);
61
+ }
62
+ $this->getResponse()->setBody(Mage::helper('core')->jsonEncode($result));
63
+ }
64
+ }
app/code/community/Metrilo/Analytics/etc/adminhtml.xml ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+
3
+ <config>
4
+ <acl>
5
+ <resources>
6
+ <admin>
7
+ <children>
8
+ <system>
9
+ <children>
10
+ <config>
11
+ <children>
12
+ <metrilo_analytics_settings>
13
+ <title>Metrilo Settings Tab</title>
14
+ </metrilo_analytics_settings>
15
+ </children>
16
+ </config>
17
+ </children>
18
+ </system>
19
+ </children>
20
+ </admin>
21
+ </resources>
22
+ </acl>
23
+ </config>
app/code/community/Metrilo/Analytics/etc/config.xml ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!--
3
+ /**
4
+ * @package Metrilo_Analytics
5
+ * @author Miroslav Petrov <miro91tn@gmail.com>
6
+ */
7
+ -->
8
+ <config>
9
+ <modules>
10
+ <Metrilo_Analytics>
11
+ <version>1.0.0</version>
12
+ </Metrilo_Analytics>
13
+ </modules>
14
+ <frontend>
15
+ <layout>
16
+ <updates>
17
+ <metrilo_analytics>
18
+ <file>metrilo_analytics.xml</file>
19
+ </metrilo_analytics>
20
+ </updates>
21
+ </layout>
22
+ <events>
23
+ <customer_login>
24
+ <observers>
25
+ <metrilo_login>
26
+ <type>singleton</type>
27
+ <class>Metrilo_Analytics_Model_Observer</class>
28
+ <method>customerLogin</method>
29
+ </metrilo_login>
30
+ </observers>
31
+ </customer_login>
32
+ <controller_action_layout_generate_blocks_after>
33
+ <observers>
34
+ <page_view>
35
+ <type>singleton</type>
36
+ <class>Metrilo_Analytics_Model_Observer</class>
37
+ <method>trackPageView</method>
38
+ </page_view>
39
+ </observers>
40
+ </controller_action_layout_generate_blocks_after>
41
+ <checkout_cart_product_add_after>
42
+ <observers>
43
+ <add_to_cart>
44
+ <type>singleton</type>
45
+ <class>Metrilo_Analytics_Model_Observer</class>
46
+ <method>addToCart</method>
47
+ </add_to_cart>
48
+ </observers>
49
+ </checkout_cart_product_add_after>
50
+ <sales_quote_remove_item>
51
+ <observers>
52
+ <remove_from_cart>
53
+ <type>singleton</type>
54
+ <class>Metrilo_Analytics_Model_Observer</class>
55
+ <method>removeFromCart</method>
56
+ </remove_from_cart>
57
+ </observers>
58
+ </sales_quote_remove_item>
59
+ <sales_order_place_after>
60
+ <observers>
61
+ <place_order>
62
+ <type>singleton</type>
63
+ <class>Metrilo_Analytics_Model_Observer</class>
64
+ <method>trackNewOrder</method>
65
+ </place_order>
66
+ </observers>
67
+ </sales_order_place_after>
68
+ <controller_action_postdispatch_checkout_cart_couponPost>
69
+ <observers>
70
+ <applied_coupon>
71
+ <type>singleton</type>
72
+ <class>Metrilo_Analytics_Model_Observer</class>
73
+ <method>trackCoupon</method>
74
+ </applied_coupon>
75
+ </observers>
76
+ </controller_action_postdispatch_checkout_cart_couponPost>
77
+ </events>
78
+ </frontend>
79
+ <global>
80
+ <events>
81
+ <sales_order_save_after>
82
+ <observers>
83
+ <update_order>
84
+ <type>singleton</type>
85
+ <class>Metrilo_Analytics_Model_Observer</class>
86
+ <method>updateOrder</method>
87
+ </update_order>
88
+ </observers>
89
+ </sales_order_save_after>
90
+ </events>
91
+ <models>
92
+ <metrilo_analytics>
93
+ <class>Metrilo_Analytics_Model</class>
94
+ </metrilo_analytics>
95
+ </models>
96
+ <blocks>
97
+ <metrilo_analytics>
98
+ <class>Metrilo_Analytics_Block</class>
99
+ </metrilo_analytics>
100
+ </blocks>
101
+ <helpers>
102
+ <metrilo_analytics>
103
+ <class>Metrilo_Analytics_Helper</class>
104
+ </metrilo_analytics>
105
+ </helpers>
106
+ </global>
107
+ <admin>
108
+ <routers>
109
+ <metrilo_analytics>
110
+ <use>admin</use>
111
+ <args>
112
+ <module>Metrilo_Analytics</module>
113
+ <frontName>metrilo_analytics</frontName>
114
+ </args>
115
+ </metrilo_analytics>
116
+ </routers>
117
+ </admin>
118
+ <adminhtml>
119
+ <layout>
120
+ <updates>
121
+ <metrilo_analytics>
122
+ <file>metrilo_analytics.xml</file>
123
+ </metrilo_analytics>
124
+ </updates>
125
+ </layout>
126
+ </adminhtml>
127
+ <default>
128
+ <metrilo_analytics_settings>
129
+ <settings>
130
+ <enable>0</enable>
131
+ </settings>
132
+ </metrilo_analytics_settings>
133
+ </default>
134
+ </config>
app/code/community/Metrilo/Analytics/etc/system.xml ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <config>
3
+ <tabs>
4
+ <metrilo_analytics translate="label" module="metrilo_analytics">
5
+ <label>Metrilo Analytics</label>
6
+ <sort_order>100</sort_order>
7
+ </metrilo_analytics>
8
+ </tabs>
9
+ <sections>
10
+ <metrilo_analytics_settings module="metrilo_analytics">
11
+ <label>General Settings</label>
12
+ <class>metrilo-section</class>
13
+ <header_css>metrilo-header</header_css>
14
+ <sort_order>10</sort_order>
15
+ <show_in_default>1</show_in_default>
16
+ <show_in_website>1</show_in_website>
17
+ <show_in_store>1</show_in_store>
18
+ <tab>metrilo_analytics</tab>
19
+ <groups>
20
+ <settings>
21
+ <label>General settings</label>
22
+ <sort_order>10</sort_order>
23
+ <show_in_default>1</show_in_default>
24
+ <show_in_website>1</show_in_website>
25
+ <show_in_store>1</show_in_store>
26
+ <comment>
27
+ <![CDATA[
28
+ <div id="metrilo-info">
29
+ <img src="/skin/adminhtml/default/default/metrilo/favicon-metrilo.png" alt="Metrilo" />
30
+ <div class="text">
31
+ This module was developed by <a href="http://metrilo.com" target="_blank">Metrilo.com</a><br />
32
+ If you encounter any issues, let us know at <a href="mailto:support@metrilo.com">support@metrilo.com</a>. We'll be happy to assist you!
33
+ </div>
34
+ </div>
35
+ <div style="clear:both;"></div>
36
+ ]]>
37
+ </comment>
38
+ <fields>
39
+ <enable>
40
+ <label>Enabled</label>
41
+ <frontend_type>select</frontend_type>
42
+ <source_model>adminhtml/system_config_source_yesno</source_model>
43
+ <sort_order>0</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
+ <api_key>
49
+ <label>API Token</label>
50
+ <frontend_type>text</frontend_type>
51
+ <sort_order>10</sort_order>
52
+ <show_in_default>1</show_in_default>
53
+ <show_in_website>1</show_in_website>
54
+ <show_in_store>1</show_in_store>
55
+ <depends><enable>1</enable></depends>
56
+ </api_key>
57
+ <api_secret>
58
+ <label>API Secret</label>
59
+ <frontend_type>text</frontend_type>
60
+ <sort_order>20</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
+ <depends><enable>1</enable></depends>
65
+ </api_secret>
66
+ <import translate="label">
67
+ <label>Import orders</label>
68
+ <frontend_type>button</frontend_type>
69
+ <frontend_model>metrilo_analytics/adminhtml_system_config_form_button</frontend_model>
70
+ <sort_order>40</sort_order>
71
+ <comment>First set API token and secret before import orders</comment>
72
+ <show_in_default>1</show_in_default>
73
+ <show_in_website>1</show_in_website>
74
+ <show_in_store>1</show_in_store>
75
+ <depends><enable>1</enable></depends>
76
+ </import>
77
+ </fields>
78
+ </settings>
79
+ </groups>
80
+ </metrilo_analytics_settings>
81
+ </sections>
82
+ </config>
app/design/adminhtml/default/default/layout/metrilo_analytics.xml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <layout>
3
+
4
+ <adminhtml_system_config_edit>
5
+ <reference name="head">
6
+ <action method="addCss"><stylesheet>metrilo/styles.css</stylesheet></action>
7
+ </reference>
8
+ </adminhtml_system_config_edit>
9
+
10
+ </layout>
app/design/adminhtml/default/default/template/metrilo/system/config/button.phtml ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php $import = $this->getImport(); ?>
2
+ <script type="text/javascript" src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
3
+ <script type="text/javascript">
4
+ jQuery.noConflict();
5
+
6
+ function import_metrilo() {
7
+ var total_chunks = <?php echo $import->getChunks(); ?>;
8
+ var chunk_percentage = 100;
9
+ if(total_chunks > 0){
10
+ var chunk_percentage = (100 / total_chunks);
11
+ }
12
+ // Update button state and text
13
+ jQuery('#metrilo_button').addClass('disabled').attr('disabled', 'disabled').text('Importing orders');
14
+
15
+ var sync_chunk = function(chunk_id){
16
+ progress_percents = Math.round(chunk_id * chunk_percentage);
17
+ update_importing_message('Please wait... '+progress_percents+'% done', true);
18
+
19
+ // add form_key for magento controller check
20
+ data = {'chunk_id': chunk_id, 'form_key': window.FORM_KEY};
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{
28
+ update_importing_message("<span style='color: green;'>Done! Please expect up to 30 minutes for your historical data to appear in Metrilo.</span>", false);
29
+ jQuery('#metrilo_button').removeClass('disabled').addClass('success').text('Orders imported');
30
+ }
31
+
32
+ });
33
+
34
+ }
35
+
36
+ var update_importing_message = function(message, show_loader){
37
+ if (show_loader)
38
+ message = '<img src="<?php echo $this->getSkinUrl("metrilo/loader.gif"); ?>" />' + message;
39
+ jQuery('#metrilo_import_status').html(message);
40
+ }
41
+ sync_chunk(0);
42
+ }
43
+ </script>
44
+
45
+ <div style="float: left;">
46
+ <h3>Importing your orders and customers</h3>
47
+ <p>
48
+ This tool helps you sync all your orders and customers to Metrilo and can take <strong>up to 20 minutes</strong> to complete. <br />
49
+ It will not affect your website's performance at all since it sends your orders to your Metrilo account in small chunks. <br /><br />
50
+ Make sure to <strong>not close this page</strong> while importing. Coffee, maybe?
51
+ </p>
52
+ </div>
53
+ <div style="clear:both"></div>
54
+ <?php echo $this->getButtonHtml() ?>
55
+ <div style="clear:both"></div>
56
+ <div id="metrilo_import_status"></div>
57
+ <div style="clear:both"></div>
app/etc/modules/Metrilo_Analytics.xml ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8" standalone="no"?>
2
+ <config>
3
+ <modules>
4
+ <Metrilo_Analytics>
5
+ <active>true</active>
6
+ <codePool>community</codePool>
7
+ </Metrilo_Analytics>
8
+ </modules>
9
+ </config>
package.xml ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <package>
3
+ <name>Metrilo_Analytics</name>
4
+ <version>1.0.0</version>
5
+ <stability>stable</stability>
6
+ <license>Apache Software License (ASL)</license>
7
+ <channel>community</channel>
8
+ <extends/>
9
+ <summary>Metrilo is simple, yet extremely powerful Customer Insights, CRM and Email Marketing product that turns your Magento data into insights to grow your business. Metrilo helps you know everything about your customers from their first touch with your Magento store to their latest purchase.</summary>
10
+ <description>Metrilo is simple, yet extremely powerful Customer Insights, CRM and Email Marketing product that turns your Magento data into insights to grow your business. Metrilo helps you know everything about your customers from their first touch with your Magento store to their latest purchase.&#xD;
11
+ &#xD;
12
+ * Have all your customer data in one place.&#xD;
13
+ * Identify cohorts of customers, cart abandoners or high-value spenders. Metrilo gets all your customer data in one place and makes it easy for you to get to know your biggest asset - your customers.&#xD;
14
+ * More repeat purchases, just a few clicks away. Send targeted email messages in 3 easy steps.&#xD;
15
+ * Metrilo tracks all important eCommerce metrics for you. Automatically.&#xD;
16
+ * Optimize your acquisition channels&#xD;
17
+ * Track product performance&#xD;
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>The first stable version of Metrilo's integration with Magento</notes>
22
+ <authors><author><name>Murry Ivanoff</name><user>Metrilo</user><email>murry@metrilo.com</email></author><author><name>Miroslav Petrov</name><user>miro</user><email>miro91tn@gmail.com</email></author><author><name>Zhivko Draganov</name><user>zhivko</user><email>zhivko@metrilo.com</email></author></authors>
23
+ <date>2015-09-03</date>
24
+ <time>08:26:32</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="70aadb3d62d998a3076bd4f9209db560"/></dir></dir></dir></dir><file name="Head.php" hash="7fc6870506f8882520b4e2b9596600d7"/></dir><dir name="Helper"><file name="Data.php" hash="3b3d5f6796d7370863ce116107a90f1c"/></dir><dir name="Model"><file name="Import.php" hash="1eb20cd00c210ee378039edb8d0515dc"/><file name="Observer.php" hash="ca427229dd8f754efd4b3cf511c25cf6"/></dir><dir name="controllers"><dir name="Adminhtml"><file name="AjaxController.php" hash="0a16196c1c62b3359508b0b688a36e04"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="00c90fdba5e48bb35367c16c83abd6a7"/><file name="config.xml" hash="4708aed8284ec5c1457ca08a5ae079f6"/><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="528d7eb52bf996b7b2a31e8c6a4d7d86"/></dir></dir></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>
skin/adminhtml/default/default/metrilo/favicon-metrilo.png ADDED
Binary file
skin/adminhtml/default/default/metrilo/loader.gif ADDED
Binary file
skin/adminhtml/default/default/metrilo/logo.png ADDED
Binary file
skin/adminhtml/default/default/metrilo/styles.css ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ul.tabs a.metrilo-section span {
2
+ background: url(favicon-metrilo.png) no-repeat 18px 3px;
3
+ background-size: 23px;
4
+ overflow: hidden;
5
+ padding: 5px 0 5px 50px;
6
+ }
7
+ ul.tabs a.metrilo-section:hover span {
8
+ background: #D8E6E6 url(favicon-metrilo.png) no-repeat 18px 3px;
9
+ background-size: 23px;
10
+ padding: 5px 0 5px 50px;
11
+ }
12
+ #metrilo-info {
13
+ float:left;
14
+ width: calc(100% - 20px);
15
+ padding: 10px;
16
+ background-color: #fff;
17
+ border: 1px solid #ddd;
18
+ margin-bottom: 7px;
19
+ }
20
+ #metrilo-info img {
21
+ float:left;
22
+ width:50px;
23
+ }
24
+ #metrilo-info a {
25
+ color:#378FE2!important;
26
+ margin: 0;
27
+ }
28
+ #metrilo-info .text {
29
+ float:left;
30
+ margin-left: 10px;
31
+ padding-top: 5px;
32
+ }
33
+ #metrilo_import_status {
34
+ font-weight: bold;
35
+ vertical-align: middle;
36
+ display: flex;
37
+ padding: 10px 0;
38
+ }
39
+ #metrilo_import_status img {
40
+ margin-right: 5px;
41
+ }