Version Notes
* Add "external_order_ref" to order tagging and API requests in order to better
track orders
* Add "order_statuses" to the order export to be able to better check up on order funnels
Download this release
Release Info
Developer | Nosto |
Extension | Nosto_Tagging |
Version | 2.6.5 |
Comparing to | |
See all releases |
Code changes from version 2.6.4 to 2.6.5
- app/code/community/Nosto/Tagging/Model/Export/Collection/Order.php +76 -0
- app/code/community/Nosto/Tagging/Model/Meta/Order.php +215 -25
- app/code/community/Nosto/Tagging/Model/Meta/Order/Buyer.php +24 -10
- app/code/community/Nosto/Tagging/Model/Meta/Order/Item.php +28 -142
- app/code/community/Nosto/Tagging/Model/Meta/Order/Status.php +43 -9
- app/code/community/Nosto/Tagging/Model/Observer.php +3 -1
- app/code/community/Nosto/Tagging/Model/Service/Order.php +112 -0
- app/code/community/Nosto/Tagging/controllers/ExportController.php +3 -2
- app/code/community/Nosto/Tagging/etc/config.xml +1 -1
- app/design/frontend/base/default/template/nostotagging/order.phtml +1 -0
- lib/nosto/php-sdk/LICENSE.txt +27 -0
- lib/nosto/php-sdk/README.md +416 -0
- package.xml +7 -5
app/code/community/Nosto/Tagging/Model/Export/Collection/Order.php
ADDED
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Magento
|
4 |
+
*
|
5 |
+
* NOTICE OF LICENSE
|
6 |
+
*
|
7 |
+
* This source file is subject to the Open Software License (OSL 3.0)
|
8 |
+
* that is bundled with this package in the file LICENSE.txt.
|
9 |
+
* It is also available through the world-wide-web at this URL:
|
10 |
+
* http://opensource.org/licenses/osl-3.0.php
|
11 |
+
* If you did not receive a copy of the license and are unable to
|
12 |
+
* obtain it through the world-wide-web, please send an email
|
13 |
+
* to license@magentocommerce.com so we can send you a copy immediately.
|
14 |
+
*
|
15 |
+
* DISCLAIMER
|
16 |
+
*
|
17 |
+
* Do not edit or add to this file if you wish to upgrade Magento to newer
|
18 |
+
* versions in the future. If you wish to customize Magento for your
|
19 |
+
* needs please refer to http://www.magentocommerce.com for more information.
|
20 |
+
*
|
21 |
+
* @category Nosto
|
22 |
+
* @package Nosto_Tagging
|
23 |
+
* @author Nosto Solutions Ltd <magento@nosto.com>
|
24 |
+
* @copyright Copyright (c) 2013-2015 Nosto Solutions Ltd (http://www.nosto.com)
|
25 |
+
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
|
26 |
+
*/
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Order collection for historical data exports.
|
30 |
+
*/
|
31 |
+
class Nosto_Tagging_Model_Export_Collection_Order extends NostoOrderCollection implements NostoExportCollectionInterface
|
32 |
+
{
|
33 |
+
/**
|
34 |
+
* @inheritdoc
|
35 |
+
*/
|
36 |
+
public function getJson()
|
37 |
+
{
|
38 |
+
$array = array();
|
39 |
+
/** @var Nosto_Tagging_Model_Meta_Order $item */
|
40 |
+
foreach ($this->getArrayCopy() as $item) {
|
41 |
+
$data = array(
|
42 |
+
'order_number' => $item->getOrderNumber(),
|
43 |
+
'external_order_ref' => $item->getExternalOrderRef(),
|
44 |
+
'order_status_code' => $item->getOrderStatus()->getCode(),
|
45 |
+
'order_status_label' => $item->getOrderStatus()->getLabel(),
|
46 |
+
'order_statuses' => array(),
|
47 |
+
'created_at' => Nosto::helper('date')->format($item->getCreatedDate()),
|
48 |
+
'buyer' => array(
|
49 |
+
'first_name' => $item->getBuyerInfo()->getFirstName(),
|
50 |
+
'last_name' => $item->getBuyerInfo()->getLastName(),
|
51 |
+
'email' => $item->getBuyerInfo()->getEmail(),
|
52 |
+
),
|
53 |
+
'payment_provider' => $item->getPaymentProvider(),
|
54 |
+
'purchased_items' => array(),
|
55 |
+
);
|
56 |
+
foreach ($item->getPurchasedItems() as $orderItem) {
|
57 |
+
$data['purchased_items'][] = array(
|
58 |
+
'product_id' => $orderItem->getProductId(),
|
59 |
+
'quantity' => (int)$orderItem->getQuantity(),
|
60 |
+
'name' => $orderItem->getName(),
|
61 |
+
'unit_price' => Nosto::helper('price')->format($orderItem->getUnitPrice()),
|
62 |
+
'price_currency_code' => strtoupper($orderItem->getCurrencyCode()),
|
63 |
+
);
|
64 |
+
}
|
65 |
+
foreach ($item->getOrderStatuses() as $status) {
|
66 |
+
if (!isset($data['order_statuses'][$status->getCode()])) {
|
67 |
+
$data['order_statuses'][$status->getCode()] = array();
|
68 |
+
}
|
69 |
+
$data['order_statuses'][$status->getCode()][] =
|
70 |
+
date('Y-m-d\TH:i:s\Z', strtotime($status->getCreatedAt()));
|
71 |
+
}
|
72 |
+
$array[] = $data;
|
73 |
+
}
|
74 |
+
return json_encode($array);
|
75 |
+
}
|
76 |
+
}
|
app/code/community/Nosto/Tagging/Model/Meta/Order.php
CHANGED
@@ -47,6 +47,11 @@ class Nosto_Tagging_Model_Meta_Order extends Mage_Core_Model_Abstract implements
|
|
47 |
*/
|
48 |
protected $_orderNumber;
|
49 |
|
|
|
|
|
|
|
|
|
|
|
50 |
/**
|
51 |
* @var string the date when the order was placed.
|
52 |
*/
|
@@ -74,6 +79,11 @@ class Nosto_Tagging_Model_Meta_Order extends Mage_Core_Model_Abstract implements
|
|
74 |
*/
|
75 |
protected $_orderStatus;
|
76 |
|
|
|
|
|
|
|
|
|
|
|
77 |
/**
|
78 |
* @inheritdoc
|
79 |
*/
|
@@ -90,52 +100,212 @@ class Nosto_Tagging_Model_Meta_Order extends Mage_Core_Model_Abstract implements
|
|
90 |
public function loadData(Mage_Sales_Model_Order $order)
|
91 |
{
|
92 |
$this->_orderNumber = $order->getId();
|
|
|
93 |
$this->_createdDate = $order->getCreatedAt();
|
94 |
$this->_paymentProvider = $order->getPayment()->getMethod();
|
95 |
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
100 |
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
|
|
|
|
|
|
|
|
105 |
|
106 |
-
/** @var $item Mage_Sales_Model_Order_Item */
|
107 |
foreach ($order->getAllVisibleItems() as $item) {
|
108 |
-
/** @var
|
109 |
-
$
|
110 |
-
$orderItem->loadData($item);
|
111 |
-
$this->_items[] = $orderItem;
|
112 |
}
|
113 |
|
114 |
if ($this->includeSpecialItems) {
|
115 |
if (($discount = $order->getDiscountAmount()) > 0) {
|
116 |
/** @var Nosto_Tagging_Model_Meta_Order_Item $orderItem */
|
117 |
-
$
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
|
|
|
|
|
|
|
|
122 |
);
|
123 |
-
$this->_items[] = $orderItem;
|
124 |
}
|
125 |
|
126 |
if (($shippingInclTax = $order->getShippingInclTax()) > 0) {
|
127 |
/** @var Nosto_Tagging_Model_Meta_Order_Item $orderItem */
|
128 |
-
$
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
|
|
|
|
|
|
|
|
133 |
);
|
134 |
-
$this->_items[] = $orderItem;
|
135 |
}
|
136 |
}
|
137 |
}
|
138 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
139 |
/**
|
140 |
* The unique order number identifying the order.
|
141 |
*
|
@@ -146,6 +316,16 @@ class Nosto_Tagging_Model_Meta_Order extends Mage_Core_Model_Abstract implements
|
|
146 |
return $this->_orderNumber;
|
147 |
}
|
148 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
149 |
/**
|
150 |
* The date when the order was placed.
|
151 |
*
|
@@ -196,4 +376,14 @@ class Nosto_Tagging_Model_Meta_Order extends Mage_Core_Model_Abstract implements
|
|
196 |
{
|
197 |
return $this->_orderStatus;
|
198 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
199 |
}
|
47 |
*/
|
48 |
protected $_orderNumber;
|
49 |
|
50 |
+
/**
|
51 |
+
* @var string the Magento order "real order ID" property.
|
52 |
+
*/
|
53 |
+
protected $_externalOrderRef;
|
54 |
+
|
55 |
/**
|
56 |
* @var string the date when the order was placed.
|
57 |
*/
|
79 |
*/
|
80 |
protected $_orderStatus;
|
81 |
|
82 |
+
/**
|
83 |
+
* @var Nosto_Tagging_Model_Meta_Order_Status[] list of order status history.
|
84 |
+
*/
|
85 |
+
protected $_orderStatuses = array();
|
86 |
+
|
87 |
/**
|
88 |
* @inheritdoc
|
89 |
*/
|
100 |
public function loadData(Mage_Sales_Model_Order $order)
|
101 |
{
|
102 |
$this->_orderNumber = $order->getId();
|
103 |
+
$this->_externalOrderRef = $order->getRealOrderId();
|
104 |
$this->_createdDate = $order->getCreatedAt();
|
105 |
$this->_paymentProvider = $order->getPayment()->getMethod();
|
106 |
|
107 |
+
$this->_orderStatus = Mage::getModel(
|
108 |
+
'nosto_tagging/meta_order_status',
|
109 |
+
array(
|
110 |
+
'code' => $order->getStatus(),
|
111 |
+
'label' => $order->getStatusLabel()
|
112 |
+
)
|
113 |
+
);
|
114 |
+
|
115 |
+
foreach ($order->getAllStatusHistory() as $item) {
|
116 |
+
/** @var Mage_Sales_Model_Order_Status_History $item */
|
117 |
+
$this->_orderStatuses[] = Mage::getModel(
|
118 |
+
'nosto_tagging/meta_order_status',
|
119 |
+
array(
|
120 |
+
'code' => $item->getStatus(),
|
121 |
+
'label' => $item->getStatusLabel(),
|
122 |
+
'createdAt' => $item->getCreatedAt()
|
123 |
+
)
|
124 |
+
);
|
125 |
+
}
|
126 |
|
127 |
+
$this->_buyer = Mage::getModel(
|
128 |
+
'nosto_tagging/meta_order_buyer',
|
129 |
+
array(
|
130 |
+
'firstName' => $order->getCustomerFirstname(),
|
131 |
+
'lastName' => $order->getCustomerLastname(),
|
132 |
+
'email' => $order->getCustomerEmail()
|
133 |
+
)
|
134 |
+
);
|
135 |
|
|
|
136 |
foreach ($order->getAllVisibleItems() as $item) {
|
137 |
+
/** @var $item Mage_Sales_Model_Order_Item */
|
138 |
+
$this->_items[] = $this->buildItem($item, $order);
|
|
|
|
|
139 |
}
|
140 |
|
141 |
if ($this->includeSpecialItems) {
|
142 |
if (($discount = $order->getDiscountAmount()) > 0) {
|
143 |
/** @var Nosto_Tagging_Model_Meta_Order_Item $orderItem */
|
144 |
+
$this->_items[] = Mage::getModel(
|
145 |
+
'nosto_tagging/meta_order_item',
|
146 |
+
array(
|
147 |
+
'productId' => -1,
|
148 |
+
'quantity' => 1,
|
149 |
+
'name' => 'Discount',
|
150 |
+
'unitPrice' => $discount,
|
151 |
+
'currencyCode' => $order->getOrderCurrencyCode()
|
152 |
+
)
|
153 |
);
|
|
|
154 |
}
|
155 |
|
156 |
if (($shippingInclTax = $order->getShippingInclTax()) > 0) {
|
157 |
/** @var Nosto_Tagging_Model_Meta_Order_Item $orderItem */
|
158 |
+
$this->_items[] = Mage::getModel(
|
159 |
+
'nosto_tagging/meta_order_item',
|
160 |
+
array(
|
161 |
+
'productId' => -1,
|
162 |
+
'quantity' => 1,
|
163 |
+
'name' => 'Shipping and handling',
|
164 |
+
'unitPrice' => $shippingInclTax,
|
165 |
+
'currencyCode' => $order->getOrderCurrencyCode()
|
166 |
+
)
|
167 |
);
|
|
|
168 |
}
|
169 |
}
|
170 |
}
|
171 |
|
172 |
+
/**
|
173 |
+
* Builds a order items object form the Magento sales item.
|
174 |
+
*
|
175 |
+
* @param Mage_Sales_Model_Order_Item $item the sales item model.
|
176 |
+
* @param Mage_Sales_Model_Order $order the order model.
|
177 |
+
*
|
178 |
+
* @return Nosto_Tagging_Model_Meta_Order_Item the built item.
|
179 |
+
*/
|
180 |
+
protected function buildItem(Mage_Sales_Model_Order_Item $item, Mage_Sales_Model_Order $order)
|
181 |
+
{
|
182 |
+
return Mage::getModel(
|
183 |
+
'nosto_tagging/meta_order_item',
|
184 |
+
array(
|
185 |
+
'productId' => (int)$this->buildItemProductId($item),
|
186 |
+
'quantity' => (int)$item->getQtyOrdered(),
|
187 |
+
'name' => $this->buildItemName($item),
|
188 |
+
'unitPrice' => $item->getPriceInclTax(),
|
189 |
+
'currencyCode' => $order->getOrderCurrencyCode()
|
190 |
+
)
|
191 |
+
);
|
192 |
+
}
|
193 |
+
|
194 |
+
/**
|
195 |
+
* Returns the product id for a quote item.
|
196 |
+
* Always try to find the "parent" product ID if the product is a child of
|
197 |
+
* another product type. We do this because it is the parent product that
|
198 |
+
* we tag on the product page, and the child does not always have it's own
|
199 |
+
* product page. This is important because it is the tagged info on the
|
200 |
+
* product page that is used to generate recommendations and email content.
|
201 |
+
*
|
202 |
+
* @param Mage_Sales_Model_Order_Item $item the sales item model.
|
203 |
+
*
|
204 |
+
* @return int
|
205 |
+
*/
|
206 |
+
protected function buildItemProductId(Mage_Sales_Model_Order_Item $item)
|
207 |
+
{
|
208 |
+
$parent = $item->getProductOptionByCode('super_product_config');
|
209 |
+
if (isset($parent['product_id'])) {
|
210 |
+
return $parent['product_id'];
|
211 |
+
} elseif ($item->getProductType() === Mage_Catalog_Model_Product_Type::TYPE_SIMPLE) {
|
212 |
+
/** @var Mage_Catalog_Model_Product_Type_Configurable $model */
|
213 |
+
$model = Mage::getModel('catalog/product_type_configurable');
|
214 |
+
$parentIds = $model->getParentIdsByChild($item->getProductId());
|
215 |
+
$attributes = $item->getBuyRequest()->getData('super_attribute');
|
216 |
+
// If the product has a configurable parent, we assume we should tag
|
217 |
+
// the parent. If there are many parent IDs, we are safer to tag the
|
218 |
+
// products own ID.
|
219 |
+
if (count($parentIds) === 1 && !empty($attributes)) {
|
220 |
+
return $parentIds[0];
|
221 |
+
}
|
222 |
+
}
|
223 |
+
return $item->getProductId();
|
224 |
+
}
|
225 |
+
|
226 |
+
/**
|
227 |
+
* Returns the name for a sales item.
|
228 |
+
* Configurable products will have their chosen options added to their name.
|
229 |
+
* Bundle products will have their chosen child product names added.
|
230 |
+
* Grouped products will have their parents name prepended.
|
231 |
+
* All others will have their own name only.
|
232 |
+
*
|
233 |
+
* @param Mage_Sales_Model_Order_Item $item the sales item model.
|
234 |
+
*
|
235 |
+
* @return string
|
236 |
+
*/
|
237 |
+
protected function buildItemName(Mage_Sales_Model_Order_Item $item)
|
238 |
+
{
|
239 |
+
$name = $item->getName();
|
240 |
+
$optNames = array();
|
241 |
+
|
242 |
+
if ($item->getProductType() === Mage_Catalog_Model_Product_Type::TYPE_SIMPLE) {
|
243 |
+
/** @var Mage_Catalog_Model_Product_Type_Configurable $model */
|
244 |
+
$model = Mage::getModel('catalog/product_type_configurable');
|
245 |
+
$parentIds = $model->getParentIdsByChild($item->getProductId());
|
246 |
+
// If the product has a configurable parent, we assume we should tag
|
247 |
+
// the parent. If there are many parent IDs, we are safer to tag the
|
248 |
+
// products own name alone.
|
249 |
+
if (count($parentIds) === 1) {
|
250 |
+
$attributes = $item->getBuyRequest()->getData('super_attribute');
|
251 |
+
if (is_array($attributes)) {
|
252 |
+
foreach ($attributes as $id => $value) {
|
253 |
+
/** @var Mage_Catalog_Model_Resource_Eav_Attribute $attribute */
|
254 |
+
$attribute = Mage::getModel('catalog/resource_eav_attribute')
|
255 |
+
->load($id);
|
256 |
+
$label = $attribute->getSource()->getOptionText($value);
|
257 |
+
if (!empty($label)) {
|
258 |
+
$optNames[] = $label;
|
259 |
+
}
|
260 |
+
}
|
261 |
+
}
|
262 |
+
}
|
263 |
+
} elseif ($item->getProductType() === Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE) {
|
264 |
+
$opts = $item->getProductOptionByCode('attributes_info');
|
265 |
+
if (is_array($opts)) {
|
266 |
+
foreach ($opts as $opt) {
|
267 |
+
if (isset($opt['value']) && is_string($opt['value'])) {
|
268 |
+
$optNames[] = $opt['value'];
|
269 |
+
}
|
270 |
+
}
|
271 |
+
}
|
272 |
+
} elseif ($item->getProductType() === Mage_Catalog_Model_Product_Type::TYPE_BUNDLE) {
|
273 |
+
$opts = $item->getProductOptionByCode('bundle_options');
|
274 |
+
if (is_array($opts)) {
|
275 |
+
foreach ($opts as $opt) {
|
276 |
+
if (isset($opt['value']) && is_array($opt['value'])) {
|
277 |
+
foreach ($opt['value'] as $val) {
|
278 |
+
$qty = '';
|
279 |
+
if (isset($val['qty']) && is_int($val['qty'])) {
|
280 |
+
$qty .= $val['qty'] . ' x ';
|
281 |
+
}
|
282 |
+
if (isset($val['title']) && is_string($val['title'])) {
|
283 |
+
$optNames[] = $qty . $val['title'];
|
284 |
+
}
|
285 |
+
}
|
286 |
+
}
|
287 |
+
}
|
288 |
+
}
|
289 |
+
} elseif ($item->getProductType() === Mage_Catalog_Model_Product_Type::TYPE_GROUPED) {
|
290 |
+
$config = $item->getProductOptionByCode('super_product_config');
|
291 |
+
if (isset($config['product_id'])) {
|
292 |
+
/** @var Mage_Catalog_Model_Product $parent */
|
293 |
+
$parent = Mage::getModel('catalog/product')
|
294 |
+
->load($config['product_id']);
|
295 |
+
$parentName = $parent->getName();
|
296 |
+
if (!empty($parentName)) {
|
297 |
+
$name = $parentName.' - '.$name;
|
298 |
+
}
|
299 |
+
}
|
300 |
+
}
|
301 |
+
|
302 |
+
if (!empty($optNames)) {
|
303 |
+
$name .= ' (' . implode(', ', $optNames) . ')';
|
304 |
+
}
|
305 |
+
|
306 |
+
return $name;
|
307 |
+
}
|
308 |
+
|
309 |
/**
|
310 |
* The unique order number identifying the order.
|
311 |
*
|
316 |
return $this->_orderNumber;
|
317 |
}
|
318 |
|
319 |
+
/**
|
320 |
+
* Returns the Magento order "real order ID" property.
|
321 |
+
*
|
322 |
+
* @return string the order ref.
|
323 |
+
*/
|
324 |
+
public function getExternalOrderRef()
|
325 |
+
{
|
326 |
+
return $this->_externalOrderRef;
|
327 |
+
}
|
328 |
+
|
329 |
/**
|
330 |
* The date when the order was placed.
|
331 |
*
|
376 |
{
|
377 |
return $this->_orderStatus;
|
378 |
}
|
379 |
+
|
380 |
+
/**
|
381 |
+
* Returns a list of order status history items.
|
382 |
+
*
|
383 |
+
* @return Nosto_Tagging_Model_Meta_Order_Status[] the list.
|
384 |
+
*/
|
385 |
+
public function getOrderStatuses()
|
386 |
+
{
|
387 |
+
return $this->_orderStatuses;
|
388 |
+
}
|
389 |
}
|
app/code/community/Nosto/Tagging/Model/Meta/Order/Buyer.php
CHANGED
@@ -52,23 +52,37 @@ class Nosto_Tagging_Model_Meta_Order_Buyer extends Mage_Core_Model_Abstract impl
|
|
52 |
protected $_email;
|
53 |
|
54 |
/**
|
55 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
*/
|
57 |
-
|
58 |
{
|
59 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
60 |
}
|
61 |
|
62 |
/**
|
63 |
-
*
|
64 |
-
*
|
65 |
-
* @param Mage_Sales_Model_Order $order the order model.
|
66 |
*/
|
67 |
-
|
68 |
{
|
69 |
-
$this->
|
70 |
-
$this->_lastName = $order->getCustomerLastname();
|
71 |
-
$this->_email = $order->getCustomerEmail();
|
72 |
}
|
73 |
|
74 |
/**
|
52 |
protected $_email;
|
53 |
|
54 |
/**
|
55 |
+
* Constructor.
|
56 |
+
*
|
57 |
+
* Sets up this Value Object.
|
58 |
+
*
|
59 |
+
* @param array $args the object data.
|
60 |
+
*
|
61 |
+
* @throws InvalidArgumentException
|
62 |
*/
|
63 |
+
public function __construct(array $args)
|
64 |
{
|
65 |
+
if (!isset($args['firstName']) || !is_string($args['firstName']) || empty($args['firstName'])) {
|
66 |
+
throw new InvalidArgumentException(sprintf('%s.firstName must be a non-empty string value.', __CLASS__));
|
67 |
+
}
|
68 |
+
if (!isset($args['lastName']) || !is_string($args['lastName']) || empty($args['lastName'])) {
|
69 |
+
throw new InvalidArgumentException(sprintf('%s.lastName must be a non-empty string value.', __CLASS__));
|
70 |
+
}
|
71 |
+
if (!isset($args['email']) || !is_string($args['email']) || empty($args['email'])) {
|
72 |
+
throw new InvalidArgumentException(sprintf('%s.email must be a non-empty string value.', __CLASS__));
|
73 |
+
}
|
74 |
+
|
75 |
+
$this->_firstName = $args['firstName'];
|
76 |
+
$this->_lastName = $args['lastName'];
|
77 |
+
$this->_email = $args['email'];
|
78 |
}
|
79 |
|
80 |
/**
|
81 |
+
* @inheritdoc
|
|
|
|
|
82 |
*/
|
83 |
+
protected function _construct()
|
84 |
{
|
85 |
+
$this->_init('nosto_tagging/meta_order_buyer');
|
|
|
|
|
86 |
}
|
87 |
|
88 |
/**
|
app/code/community/Nosto/Tagging/Model/Meta/Order/Item.php
CHANGED
@@ -63,159 +63,45 @@ class Nosto_Tagging_Model_Meta_Order_Item extends Mage_Core_Model_Abstract imple
|
|
63 |
protected $_currencyCode;
|
64 |
|
65 |
/**
|
66 |
-
*
|
67 |
-
*/
|
68 |
-
protected function _construct()
|
69 |
-
{
|
70 |
-
$this->_init('nosto_tagging/meta_order_item');
|
71 |
-
}
|
72 |
-
|
73 |
-
/**
|
74 |
-
* Loads the item info from the Magento order item model.
|
75 |
*
|
76 |
-
*
|
77 |
-
*/
|
78 |
-
public function loadData(Mage_Sales_Model_Order_Item $item)
|
79 |
-
{
|
80 |
-
$order = $item->getOrder();
|
81 |
-
$this->_productId = (int)$this->fetchProductId($item);
|
82 |
-
$this->_quantity = (int)$item->getQtyOrdered();
|
83 |
-
$this->_name = $this->fetchProductName($item);
|
84 |
-
$this->_unitPrice = $item->getPriceInclTax();
|
85 |
-
$this->_currencyCode = strtoupper($order->getOrderCurrencyCode());
|
86 |
-
}
|
87 |
-
|
88 |
-
/**
|
89 |
-
* Loads the "special item" info from provided data.
|
90 |
-
* A "special item" is an item that is included in an order but does not
|
91 |
-
* represent an item being bough, e.g. shipping fees, discounts etc.
|
92 |
-
*
|
93 |
-
* @param string $name the name of the item.
|
94 |
-
* @param float|int|string $unitPrice the unit price of the item.
|
95 |
-
* @param string $currencyCode the currency code for the item unit price.
|
96 |
-
*/
|
97 |
-
public function loadSpecialItemData($name, $unitPrice, $currencyCode)
|
98 |
-
{
|
99 |
-
$this->_productId = -1;
|
100 |
-
$this->_quantity = 1;
|
101 |
-
$this->_name = (string)$name;
|
102 |
-
$this->_unitPrice = $unitPrice;
|
103 |
-
$this->_currencyCode = strtoupper($currencyCode);
|
104 |
-
}
|
105 |
-
|
106 |
-
/**
|
107 |
-
* Returns the product id for a quote item.
|
108 |
-
* Always try to find the "parent" product ID if the product is a child of
|
109 |
-
* another product type. We do this because it is the parent product that
|
110 |
-
* we tag on the product page, and the child does not always have it's own
|
111 |
-
* product page. This is important because it is the tagged info on the
|
112 |
-
* product page that is used to generate recommendations and email content.
|
113 |
*
|
114 |
-
* @param
|
115 |
*
|
116 |
-
* @
|
117 |
*/
|
118 |
-
|
119 |
{
|
120 |
-
$
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
if (count($parentIds) === 1 && !empty($attributes)) {
|
132 |
-
return $parentIds[0];
|
133 |
-
}
|
134 |
}
|
135 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
136 |
}
|
137 |
|
138 |
/**
|
139 |
-
*
|
140 |
-
* Configurable products will have their chosen options added to their name.
|
141 |
-
* Bundle products will have their chosen child product names added.
|
142 |
-
* Grouped products will have their parents name prepended.
|
143 |
-
* All others will have their own name only.
|
144 |
-
*
|
145 |
-
* @param Mage_Sales_Model_Order_Item $item the sales item model.
|
146 |
-
*
|
147 |
-
* @return string
|
148 |
*/
|
149 |
-
protected function
|
150 |
{
|
151 |
-
$
|
152 |
-
$optNames = array();
|
153 |
-
|
154 |
-
if ($item->getProductType() === Mage_Catalog_Model_Product_Type::TYPE_SIMPLE) {
|
155 |
-
/** @var Mage_Catalog_Model_Product_Type_Configurable $model */
|
156 |
-
$model = Mage::getModel('catalog/product_type_configurable');
|
157 |
-
$parentIds = $model->getParentIdsByChild($item->getProductId());
|
158 |
-
// If the product has a configurable parent, we assume we should tag
|
159 |
-
// the parent. If there are many parent IDs, we are safer to tag the
|
160 |
-
// products own name alone.
|
161 |
-
if (count($parentIds) === 1) {
|
162 |
-
$attributes = $item->getBuyRequest()->getData('super_attribute');
|
163 |
-
if (is_array($attributes)) {
|
164 |
-
foreach ($attributes as $id => $value) {
|
165 |
-
/** @var Mage_Catalog_Model_Resource_Eav_Attribute $attribute */
|
166 |
-
$attribute = Mage::getModel('catalog/resource_eav_attribute')
|
167 |
-
->load($id);
|
168 |
-
$label = $attribute->getSource()->getOptionText($value);
|
169 |
-
if (!empty($label)) {
|
170 |
-
$optNames[] = $label;
|
171 |
-
}
|
172 |
-
}
|
173 |
-
}
|
174 |
-
}
|
175 |
-
} elseif ($item->getProductType() === Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE) {
|
176 |
-
$opts = $item->getProductOptionByCode('attributes_info');
|
177 |
-
if (is_array($opts)) {
|
178 |
-
foreach ($opts as $opt) {
|
179 |
-
if (isset($opt['value']) && is_string($opt['value'])) {
|
180 |
-
$optNames[] = $opt['value'];
|
181 |
-
}
|
182 |
-
}
|
183 |
-
}
|
184 |
-
} elseif ($item->getProductType() === Mage_Catalog_Model_Product_Type::TYPE_BUNDLE) {
|
185 |
-
$opts = $item->getProductOptionByCode('bundle_options');
|
186 |
-
if (is_array($opts)) {
|
187 |
-
foreach ($opts as $opt) {
|
188 |
-
if (isset($opt['value']) && is_array($opt['value'])) {
|
189 |
-
foreach ($opt['value'] as $val) {
|
190 |
-
$qty = '';
|
191 |
-
if (isset($val['qty']) && is_int($val['qty'])) {
|
192 |
-
$qty .= $val['qty'] . ' x ';
|
193 |
-
}
|
194 |
-
if (isset($val['title']) && is_string($val['title'])) {
|
195 |
-
$optNames[] = $qty . $val['title'];
|
196 |
-
}
|
197 |
-
}
|
198 |
-
}
|
199 |
-
}
|
200 |
-
}
|
201 |
-
} elseif ($item->getProductType() === Mage_Catalog_Model_Product_Type::TYPE_GROUPED) {
|
202 |
-
$config = $item->getProductOptionByCode('super_product_config');
|
203 |
-
if (isset($config['product_id'])) {
|
204 |
-
/** @var Mage_Catalog_Model_Product $parent */
|
205 |
-
$parent = Mage::getModel('catalog/product')
|
206 |
-
->load($config['product_id']);
|
207 |
-
$parentName = $parent->getName();
|
208 |
-
if (!empty($parentName)) {
|
209 |
-
$name = $parentName.' - '.$name;
|
210 |
-
}
|
211 |
-
}
|
212 |
-
}
|
213 |
-
|
214 |
-
if (!empty($optNames)) {
|
215 |
-
$name .= ' (' . implode(', ', $optNames) . ')';
|
216 |
-
}
|
217 |
-
|
218 |
-
return $name;
|
219 |
}
|
220 |
|
221 |
/**
|
63 |
protected $_currencyCode;
|
64 |
|
65 |
/**
|
66 |
+
* Constructor.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
*
|
68 |
+
* Sets up this Value Object.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
69 |
*
|
70 |
+
* @param array $args the object data.
|
71 |
*
|
72 |
+
* @throws InvalidArgumentException
|
73 |
*/
|
74 |
+
public function __construct(array $args)
|
75 |
{
|
76 |
+
if (!isset($args['productId']) || !is_int($args['productId'])) {
|
77 |
+
throw new InvalidArgumentException(sprintf('%s.productId must be a integer value.', __CLASS__));
|
78 |
+
}
|
79 |
+
if (!isset($args['quantity']) || !is_int($args['quantity']) || !($args['quantity'] > 0)) {
|
80 |
+
throw new InvalidArgumentException(sprintf('%s.quantity must be a integer value above zero.', __CLASS__));
|
81 |
+
}
|
82 |
+
if (!isset($args['name']) || !is_string($args['name']) || empty($args['name'])) {
|
83 |
+
throw new InvalidArgumentException(sprintf('%s.name must be a non-empty string value.', __CLASS__));
|
84 |
+
}
|
85 |
+
if (!isset($args['unitPrice']) || !is_numeric($args['unitPrice'])) {
|
86 |
+
throw new InvalidArgumentException(sprintf('%s.unitPrice must be a numeric value.', __CLASS__));
|
|
|
|
|
|
|
87 |
}
|
88 |
+
if (!isset($args['currencyCode']) || !is_string($args['currencyCode']) || empty($args['currencyCode'])) {
|
89 |
+
throw new InvalidArgumentException(sprintf('%s.currencyCode must be a non-empty string value.', __CLASS__));
|
90 |
+
}
|
91 |
+
|
92 |
+
$this->_productId = $args['productId'];
|
93 |
+
$this->_quantity = $args['quantity'];
|
94 |
+
$this->_name = $args['name'];
|
95 |
+
$this->_unitPrice = $args['unitPrice'];
|
96 |
+
$this->_currencyCode = $args['currencyCode'];
|
97 |
}
|
98 |
|
99 |
/**
|
100 |
+
* @inheritdoc
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
101 |
*/
|
102 |
+
protected function _construct()
|
103 |
{
|
104 |
+
$this->_init('nosto_tagging/meta_order_item');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
105 |
}
|
106 |
|
107 |
/**
|
app/code/community/Nosto/Tagging/Model/Meta/Order/Status.php
CHANGED
@@ -47,22 +47,46 @@ class Nosto_Tagging_Model_Meta_Order_Status extends Mage_Core_Model_Abstract imp
|
|
47 |
protected $_label;
|
48 |
|
49 |
/**
|
50 |
-
* @
|
51 |
*/
|
52 |
-
protected
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
{
|
54 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
}
|
56 |
|
57 |
/**
|
58 |
-
*
|
59 |
-
*
|
60 |
-
* @param Mage_Sales_Model_Order $order the order model.
|
61 |
*/
|
62 |
-
|
63 |
{
|
64 |
-
$this->
|
65 |
-
$this->_label = $order->getStatusLabel();
|
66 |
}
|
67 |
|
68 |
/**
|
@@ -84,4 +108,14 @@ class Nosto_Tagging_Model_Meta_Order_Status extends Mage_Core_Model_Abstract imp
|
|
84 |
{
|
85 |
return $this->_label;
|
86 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
87 |
}
|
47 |
protected $_label;
|
48 |
|
49 |
/**
|
50 |
+
* @var string the order status created at date.
|
51 |
*/
|
52 |
+
protected $_createdAt;
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Constructor.
|
56 |
+
*
|
57 |
+
* Sets up this Value Object.
|
58 |
+
*
|
59 |
+
* @param array $args the object data.
|
60 |
+
*
|
61 |
+
* @throws InvalidArgumentException
|
62 |
+
*/
|
63 |
+
public function __construct(array $args)
|
64 |
{
|
65 |
+
if (!isset($args['code']) || !is_string($args['code']) || empty($args['code'])) {
|
66 |
+
throw new InvalidArgumentException(sprintf('%s.code must be a non-empty string value.', __CLASS__));
|
67 |
+
}
|
68 |
+
if (!isset($args['label']) || !is_string($args['label']) || empty($args['label'])) {
|
69 |
+
throw new InvalidArgumentException(sprintf('%s.label must be a non-empty string value.', __CLASS__));
|
70 |
+
}
|
71 |
+
if (isset($args['createdAt'])) {
|
72 |
+
if (!is_string($args['createdAt']) || strtotime($args['createdAt']) === false) {
|
73 |
+
throw new InvalidArgumentException(sprintf('%s.createdAt must be a valid date.', __CLASS__));
|
74 |
+
}
|
75 |
+
}
|
76 |
+
|
77 |
+
$this->_code = $args['code'];
|
78 |
+
$this->_label = $args['label'];
|
79 |
+
if (isset($args['createdAt'])) {
|
80 |
+
$this->_createdAt = $args['createdAt'];
|
81 |
+
}
|
82 |
}
|
83 |
|
84 |
/**
|
85 |
+
* @inheritdoc
|
|
|
|
|
86 |
*/
|
87 |
+
protected function _construct()
|
88 |
{
|
89 |
+
$this->_init('nosto_tagging/meta_order_status');
|
|
|
90 |
}
|
91 |
|
92 |
/**
|
108 |
{
|
109 |
return $this->_label;
|
110 |
}
|
111 |
+
|
112 |
+
/**
|
113 |
+
* Returns the status created date.
|
114 |
+
*
|
115 |
+
* @return string the created date or null if not set.
|
116 |
+
*/
|
117 |
+
public function getCreatedAt()
|
118 |
+
{
|
119 |
+
return $this->_createdAt;
|
120 |
+
}
|
121 |
}
|
app/code/community/Nosto/Tagging/Model/Observer.php
CHANGED
@@ -188,7 +188,9 @@ class Nosto_Tagging_Model_Observer
|
|
188 |
$customerId = Mage::helper('nosto_tagging/customer')
|
189 |
->getNostoId($mageOrder);
|
190 |
if ($account !== null && $account->isConnectedToNosto()) {
|
191 |
-
|
|
|
|
|
192 |
}
|
193 |
} catch (NostoException $e) {
|
194 |
Mage::log("\n" . $e->__toString(), Zend_Log::ERR, 'nostotagging.log');
|
188 |
$customerId = Mage::helper('nosto_tagging/customer')
|
189 |
->getNostoId($mageOrder);
|
190 |
if ($account !== null && $account->isConnectedToNosto()) {
|
191 |
+
/** @var Nosto_Tagging_Model_Service_Order $service */
|
192 |
+
$service = Mage::getModel('nosto_tagging/service_order');
|
193 |
+
$service->confirm($order, $account, $customerId);
|
194 |
}
|
195 |
} catch (NostoException $e) {
|
196 |
Mage::log("\n" . $e->__toString(), Zend_Log::ERR, 'nostotagging.log');
|
app/code/community/Nosto/Tagging/Model/Service/Order.php
ADDED
@@ -0,0 +1,112 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Magento
|
4 |
+
*
|
5 |
+
* NOTICE OF LICENSE
|
6 |
+
*
|
7 |
+
* This source file is subject to the Open Software License (OSL 3.0)
|
8 |
+
* that is bundled with this package in the file LICENSE.txt.
|
9 |
+
* It is also available through the world-wide-web at this URL:
|
10 |
+
* http://opensource.org/licenses/osl-3.0.php
|
11 |
+
* If you did not receive a copy of the license and are unable to
|
12 |
+
* obtain it through the world-wide-web, please send an email
|
13 |
+
* to license@magentocommerce.com so we can send you a copy immediately.
|
14 |
+
*
|
15 |
+
* DISCLAIMER
|
16 |
+
*
|
17 |
+
* Do not edit or add to this file if you wish to upgrade Magento to newer
|
18 |
+
* versions in the future. If you wish to customize Magento for your
|
19 |
+
* needs please refer to http://www.magentocommerce.com for more information.
|
20 |
+
*
|
21 |
+
* @category Nosto
|
22 |
+
* @package Nosto_Tagging
|
23 |
+
* @author Nosto Solutions Ltd <magento@nosto.com>
|
24 |
+
* @copyright Copyright (c) 2013-2015 Nosto Solutions Ltd (http://www.nosto.com)
|
25 |
+
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
|
26 |
+
*/
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Handles sending the order confirmations to Nosto via the API.
|
30 |
+
*
|
31 |
+
* Order confirmations can be sent two different ways:
|
32 |
+
* - matched orders; where we know the Nosto customer ID of the user who placed the order
|
33 |
+
* - un-matched orders: where we do not know the Nosto customer ID of the user who placed the order
|
34 |
+
*
|
35 |
+
* The second option is a fallback and should be avoided as much as possible.
|
36 |
+
*/
|
37 |
+
class Nosto_Tagging_Model_Service_Order
|
38 |
+
{
|
39 |
+
/**
|
40 |
+
* Sends an order confirmation to Nosto.
|
41 |
+
*
|
42 |
+
* @param Nosto_Tagging_Model_Meta_Order $order the order to confirm.
|
43 |
+
* @param NostoAccount $account the Nosto account object.
|
44 |
+
* @param null $customerId the Nosto customer ID of the user who placed the order.
|
45 |
+
* @throws NostoException on failure.
|
46 |
+
* @return true on success.
|
47 |
+
*/
|
48 |
+
public function confirm(Nosto_Tagging_Model_Meta_Order $order, NostoAccount $account, $customerId = null)
|
49 |
+
{
|
50 |
+
$request = $this->initApiRequest($account, $customerId);
|
51 |
+
$response = $request->post($this->getOrderAsJson($order));
|
52 |
+
if ($response->getCode() !== 200) {
|
53 |
+
Nosto::throwHttpException('Failed to send order confirmation to Nosto.', $request, $response);
|
54 |
+
}
|
55 |
+
return true;
|
56 |
+
}
|
57 |
+
|
58 |
+
/**
|
59 |
+
* Builds the API request and returns it.
|
60 |
+
*
|
61 |
+
* @param NostoAccount $account the Nosto account object.
|
62 |
+
* @param string|null $customerId the Nosto customer ID of the user who placed the order.
|
63 |
+
* @return NostoApiRequest the request object.
|
64 |
+
*/
|
65 |
+
protected function initApiRequest(NostoAccount $account, $customerId)
|
66 |
+
{
|
67 |
+
$request = new NostoApiRequest();
|
68 |
+
$request->setContentType('application/json');
|
69 |
+
if (!empty($customerId)) {
|
70 |
+
$request->setPath(NostoApiRequest::PATH_ORDER_TAGGING);
|
71 |
+
$request->setReplaceParams(array('{m}' => $account->getName(), '{cid}' => $customerId));
|
72 |
+
} else {
|
73 |
+
$request->setPath(NostoApiRequest::PATH_UNMATCHED_ORDER_TAGGING);
|
74 |
+
$request->setReplaceParams(array('{m}' => $account->getName()));
|
75 |
+
}
|
76 |
+
return $request;
|
77 |
+
}
|
78 |
+
|
79 |
+
/**
|
80 |
+
* Turns an order object into a JSON structure.
|
81 |
+
*
|
82 |
+
* @param Nosto_Tagging_Model_Meta_Order $order the order object.
|
83 |
+
* @return string the JSON structure.
|
84 |
+
*/
|
85 |
+
protected function getOrderAsJson(Nosto_Tagging_Model_Meta_Order $order)
|
86 |
+
{
|
87 |
+
$data = array(
|
88 |
+
'order_number' => $order->getOrderNumber(),
|
89 |
+
'external_order_ref' => $order->getExternalOrderRef(),
|
90 |
+
'order_status_code' => $order->getOrderStatus()->getCode(),
|
91 |
+
'order_status_label' => $order->getOrderStatus()->getLabel(),
|
92 |
+
'buyer' => array(
|
93 |
+
'first_name' => $order->getBuyerInfo()->getFirstName(),
|
94 |
+
'last_name' => $order->getBuyerInfo()->getLastName(),
|
95 |
+
'email' => $order->getBuyerInfo()->getEmail(),
|
96 |
+
),
|
97 |
+
'created_at' => Nosto::helper('date')->format($order->getCreatedDate()),
|
98 |
+
'payment_provider' => $order->getPaymentProvider(),
|
99 |
+
'purchased_items' => array(),
|
100 |
+
);
|
101 |
+
foreach ($order->getPurchasedItems() as $item) {
|
102 |
+
$data['purchased_items'][] = array(
|
103 |
+
'product_id' => $item->getProductId(),
|
104 |
+
'quantity' => (int)$item->getQuantity(),
|
105 |
+
'name' => $item->getName(),
|
106 |
+
'unit_price' => Nosto::helper('price')->format($item->getUnitPrice()),
|
107 |
+
'price_currency_code' => strtoupper($item->getCurrencyCode()),
|
108 |
+
);
|
109 |
+
}
|
110 |
+
return json_encode($data);
|
111 |
+
}
|
112 |
+
}
|
app/code/community/Nosto/Tagging/controllers/ExportController.php
CHANGED
@@ -37,7 +37,7 @@ require_once Mage::getBaseDir('lib') . '/nosto/php-sdk/src/config.inc.php';
|
|
37 |
* @package Nosto_Tagging
|
38 |
* @author Nosto Solutions Ltd <magento@nosto.com>
|
39 |
*/
|
40 |
-
class
|
41 |
{
|
42 |
/**
|
43 |
* Exports completed orders from the current store.
|
@@ -58,7 +58,8 @@ class Nosto_tagging_ExportController extends Mage_Core_Controller_Front_Action
|
|
58 |
if ($currentPage > $orders->getLastPageNumber()) {
|
59 |
$orders = array();
|
60 |
}
|
61 |
-
$collection
|
|
|
62 |
foreach ($orders as $order) {
|
63 |
/** @var Nosto_Tagging_Model_Meta_Order $meta */
|
64 |
$meta = Mage::getModel('nosto_tagging/meta_order');
|
37 |
* @package Nosto_Tagging
|
38 |
* @author Nosto Solutions Ltd <magento@nosto.com>
|
39 |
*/
|
40 |
+
class Nosto_Tagging_ExportController extends Mage_Core_Controller_Front_Action
|
41 |
{
|
42 |
/**
|
43 |
* Exports completed orders from the current store.
|
58 |
if ($currentPage > $orders->getLastPageNumber()) {
|
59 |
$orders = array();
|
60 |
}
|
61 |
+
/** @var Nosto_Tagging_Model_Export_Collection_Order $collection */
|
62 |
+
$collection = Mage::getModel('nosto_tagging/export_collection_order');
|
63 |
foreach ($orders as $order) {
|
64 |
/** @var Nosto_Tagging_Model_Meta_Order $meta */
|
65 |
$meta = Mage::getModel('nosto_tagging/meta_order');
|
app/code/community/Nosto/Tagging/etc/config.xml
CHANGED
@@ -29,7 +29,7 @@
|
|
29 |
<config>
|
30 |
<modules>
|
31 |
<Nosto_Tagging>
|
32 |
-
<version>2.6.
|
33 |
</Nosto_Tagging>
|
34 |
</modules>
|
35 |
<global>
|
29 |
<config>
|
30 |
<modules>
|
31 |
<Nosto_Tagging>
|
32 |
+
<version>2.6.5</version>
|
33 |
</Nosto_Tagging>
|
34 |
</modules>
|
35 |
<global>
|
app/design/frontend/base/default/template/nostotagging/order.phtml
CHANGED
@@ -41,6 +41,7 @@ $priceHelper = Mage::helper('nosto_tagging/price');
|
|
41 |
<!-- Nosto Order Tagging -->
|
42 |
<div class="nosto_purchase_order" style="display:none">
|
43 |
<span class="order_number"><?php echo $order->getOrderNumber(); ?></span>
|
|
|
44 |
<span class="order_status_code"><?php echo $helper->escapeHtml($order->getOrderStatus()->getCode()); ?></span>
|
45 |
<span class="order_status_label"><?php echo $helper->escapeHtml($order->getOrderStatus()->getLabel()); ?></span>
|
46 |
<span class="payment_provider"><?php echo $helper->escapeHtml($order->getPaymentProvider()); ?></span>
|
41 |
<!-- Nosto Order Tagging -->
|
42 |
<div class="nosto_purchase_order" style="display:none">
|
43 |
<span class="order_number"><?php echo $order->getOrderNumber(); ?></span>
|
44 |
+
<span class="external_order_ref"><?php echo $helper->escapeHtml($order->getExternalOrderRef()); ?></span>
|
45 |
<span class="order_status_code"><?php echo $helper->escapeHtml($order->getOrderStatus()->getCode()); ?></span>
|
46 |
<span class="order_status_label"><?php echo $helper->escapeHtml($order->getOrderStatus()->getLabel()); ?></span>
|
47 |
<span class="payment_provider"><?php echo $helper->escapeHtml($order->getPaymentProvider()); ?></span>
|
lib/nosto/php-sdk/LICENSE.txt
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Copyright (c) 2015, Nosto Solutions Ltd
|
2 |
+
All rights reserved.
|
3 |
+
|
4 |
+
Redistribution and use in source and binary forms, with or without modification,
|
5 |
+
are permitted provided that the following conditions are met:
|
6 |
+
|
7 |
+
1. Redistributions of source code must retain the above copyright notice,
|
8 |
+
this list of conditions and the following disclaimer.
|
9 |
+
|
10 |
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
11 |
+
this list of conditions and the following disclaimer in the documentation
|
12 |
+
and/or other materials provided with the distribution.
|
13 |
+
|
14 |
+
3. Neither the name of the copyright holder nor the names of its contributors
|
15 |
+
may be used to endorse or promote products derived from this software without
|
16 |
+
specific prior written permission.
|
17 |
+
|
18 |
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
19 |
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
20 |
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
21 |
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
22 |
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
23 |
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
24 |
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
25 |
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
26 |
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
27 |
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
lib/nosto/php-sdk/README.md
ADDED
@@ -0,0 +1,416 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
php-sdk
|
2 |
+
=======
|
3 |
+
|
4 |
+
Provides tools for building modules that integrate Nosto into your e-commerce platform.
|
5 |
+
|
6 |
+
## Requirements
|
7 |
+
|
8 |
+
* PHP 5.2+
|
9 |
+
|
10 |
+
## What's included?
|
11 |
+
|
12 |
+
### Classes
|
13 |
+
|
14 |
+
* **NostoApiRequest** class for making API requests to the Nosto APIs
|
15 |
+
* **NostoApiToken** class that represents an API token which can be used whn making authenticated requests to the Nosto APIs
|
16 |
+
* **NostoCollection** collection base class
|
17 |
+
* **NostoProductCollection** collection class for nosto product objects
|
18 |
+
* **NostoOrderCollection** collection class for nosto order objects
|
19 |
+
* **NostoException** main exception class for all exceptions thrown by the SDK
|
20 |
+
* **NostoHttpException** HTTP request exceptions upon request failure
|
21 |
+
* **NostoExporter** class for exporting encrypted historical data from the shop
|
22 |
+
* **NostoExportOrderCollection** class for exporting historical order data
|
23 |
+
* **NostoExportProductCollection** class for exporting historical product data
|
24 |
+
* **NostoHelper** base class for all nosto helpers
|
25 |
+
* **NostoHelperDate** helper class for date related operations
|
26 |
+
* **NostoHelperIframe** helper class for iframe related operations
|
27 |
+
* **NostoHelperPrice** helper class for price related operations
|
28 |
+
* **NostoHttpRequest** class for making HTTP request, supports both curl and socket connections
|
29 |
+
* **NostoHttpRequestAdapter** base class for creating http request adapters
|
30 |
+
* **NostoHttpRequestAdapterCurl** http request adapter for making http requests using curl
|
31 |
+
* **NostoHttpRequestAdapterSocket** http request adapter for making http requests using sockets
|
32 |
+
* **NostoHttpResponse** class that represents a response for an http request made through the NostoHttpRequest class
|
33 |
+
* **NostoOAuthClient** class for authorizing the module to act on the Nosto account owners behalf using OAuth2 Authorization Code method
|
34 |
+
* **NostoOAuthToken** class that represents a token granted using the OAuth client
|
35 |
+
* **NostoOperationProduct** class for performing create/update/delete operations on product object
|
36 |
+
* **Nosto** main sdk class for common functionality
|
37 |
+
* **NostoAccount** class that represents a Nosto account which can be used to create new accounts and connect to existing accounts using OAuth2
|
38 |
+
* **NostoCipher** class for AES encrypting product/order information that can be exported for Nosto to improve recommendations from the get-go
|
39 |
+
* **NostoDotEnv** class for handling environment variables used while developing and testing
|
40 |
+
* **NostoMessage** util class for holding info about messages that can be forwarded to the account administration iframe to show to the user
|
41 |
+
* **NostoObject** base class for Nosto objects that need to share functionality
|
42 |
+
* **NostoOrderConfirmation** class for sending order confirmations through the API
|
43 |
+
* **NostoProductReCrawl** class for sending product re-crawl requests to Nosto over the API
|
44 |
+
* **NostoValidator** class for performing data validations on objects implementing NostoValidatableInterface
|
45 |
+
|
46 |
+
### Interfaces
|
47 |
+
|
48 |
+
* **NostoAccountInterface** interface defining methods needed to manage Nosto accounts
|
49 |
+
* **NostoAccountMetaDataBillingDetailsInterface** interface defining getters for billing information needed during Nosto account creation over the API
|
50 |
+
* **NostoAccountMetaDataIframeInterface** interface defining getters for information needed by the Nosto account configuration iframe
|
51 |
+
* **NostoAccountMetaDataInterface** interface defining getters for information needed during Nosto account creation over the API
|
52 |
+
* **NostoAccountMetaDataOwnerInterface** interface defining getters for account owner information needed during Nosto account creation over the API
|
53 |
+
* **NostoOrderBuyerInterface** interface defining getters for buyer information needed during order confirmation requests
|
54 |
+
* **NostoOrderInterface** interface defining getters for information needed during order confirmation requests
|
55 |
+
* **NostoOrderPurchasedItemInterface** interface defining getters for purchased item information needed during order confirmation requests
|
56 |
+
* **NostoOrderStatusInterface** interface defining getters for order status information needed during order confirmation requests
|
57 |
+
* **NostoExportCollectionInterface** interface defining getters for exportable data collections for the historical data
|
58 |
+
* **NostoOauthMetaDataInterface** interface defining getters for information needed during OAuth2 requests
|
59 |
+
* **NostoProductInterface** interface defining getters for product information needed during product re-crawl requests to Nosto over the API
|
60 |
+
* **NostoValidatableInterface** interface defining getters for validatable objects that can be used in conjunction with the NostoValidator class
|
61 |
+
|
62 |
+
### Libs
|
63 |
+
|
64 |
+
* **NostoCryptAES** class for aes encryption that uses mcrypt if available and an internal implementation otherwise
|
65 |
+
* **NostoCryptBase** base class for creating encryption classes
|
66 |
+
* **NostoCryptRijndael** class for rijndael encryption that uses mcrypt if available and an internal implementation otherwise
|
67 |
+
* **NostoCryptRandom** class for generating random strings
|
68 |
+
|
69 |
+
## Getting started
|
70 |
+
|
71 |
+
### Creating a new Nosto account
|
72 |
+
|
73 |
+
A Nosto account is needed for every shop and every language within each shop.
|
74 |
+
|
75 |
+
```php
|
76 |
+
.....
|
77 |
+
try {
|
78 |
+
/** @var NostoAccountMetaDataInterface $meta */
|
79 |
+
/** @var NostoAccount $account */
|
80 |
+
$account = NostoAccount::create($meta);
|
81 |
+
// save newly created account according to the platforms requirements
|
82 |
+
.....
|
83 |
+
} catch (NostoException $e) {
|
84 |
+
// handle failure
|
85 |
+
.....
|
86 |
+
}
|
87 |
+
.....
|
88 |
+
```
|
89 |
+
|
90 |
+
### Connecting with an existing Nosto account
|
91 |
+
|
92 |
+
This should be done in the shops back end when the admin user wants to connect an existing Nosto account to the shop.
|
93 |
+
|
94 |
+
First redirect to the Nosto OAuth2 server.
|
95 |
+
|
96 |
+
```php
|
97 |
+
.....
|
98 |
+
/** @var NostoOAuthClientMetaDataInterface $meta */
|
99 |
+
$client = new NostoOAuthClient($meta);
|
100 |
+
header('Location: ' . $client->getAuthorizationUrl());
|
101 |
+
```
|
102 |
+
|
103 |
+
Then have a public endpoint ready to handle the return request.
|
104 |
+
|
105 |
+
```php
|
106 |
+
if (isset($_GET['code'])) {
|
107 |
+
try {
|
108 |
+
/** @var NostoOAuthClientMetaDataInterface $meta */
|
109 |
+
$account = NostoAccount::syncFromNosto($meta, $_GET['code']);
|
110 |
+
// save the synced account according to the platforms requirements
|
111 |
+
} catch (NostoException $e) {
|
112 |
+
// handle failures
|
113 |
+
}
|
114 |
+
// redirect to the admin page where the user can see the account configuration iframe
|
115 |
+
.....
|
116 |
+
}
|
117 |
+
} elseif (isset($_GET['error'])) {
|
118 |
+
// handle errors; 3 parameter will be sent, 'error', 'error_reason' and 'error_description'
|
119 |
+
// redirect to the admin page where the user can see an error message
|
120 |
+
.....
|
121 |
+
} else {
|
122 |
+
// 404
|
123 |
+
.....
|
124 |
+
}
|
125 |
+
```
|
126 |
+
|
127 |
+
### Deleting a Nosto account
|
128 |
+
|
129 |
+
This should be used when you delete a Nosto account for a shop. It will notify Nosto that this account is no longer used.
|
130 |
+
|
131 |
+
```php
|
132 |
+
try {
|
133 |
+
/** @var NostoAccount $account */
|
134 |
+
$account->delete();
|
135 |
+
} catch (NostoException $e) {
|
136 |
+
// handle failure
|
137 |
+
}
|
138 |
+
```
|
139 |
+
|
140 |
+
### Get authenticated iframe URL for Nosto account configuration
|
141 |
+
|
142 |
+
The Nosto account can be created and managed through an iframe that should be accessible to the admin user in the shops
|
143 |
+
backend.
|
144 |
+
This iframe will load only content from nosto.com.
|
145 |
+
|
146 |
+
```php
|
147 |
+
.....
|
148 |
+
/**
|
149 |
+
* @var NostoAccount|null $account account with at least the 'SSO' token loaded or null if no account exists yet
|
150 |
+
* @var NostoAccountMetaDataIframeInterface $meta
|
151 |
+
* @var array $params (optional) extra params to add to the iframe url
|
152 |
+
*/
|
153 |
+
try
|
154 |
+
{
|
155 |
+
$url = Nosto::helper('iframe')->getUrl($meta, $account, $params);
|
156 |
+
}
|
157 |
+
catch (NostoException $e)
|
158 |
+
{
|
159 |
+
// handle failure
|
160 |
+
}
|
161 |
+
// show the iframe to the user with given url
|
162 |
+
.....
|
163 |
+
```
|
164 |
+
|
165 |
+
The iframe can communicate with your module through window.postMessage
|
166 |
+
(https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage). In order to set this up you can include the JS
|
167 |
+
file `src/js/NostoIframe.min.js` on the page where you show the iframe and just init the API.
|
168 |
+
|
169 |
+
```js
|
170 |
+
...
|
171 |
+
Nosto.iframe({
|
172 |
+
iframeId: "nosto_iframe",
|
173 |
+
urls: {
|
174 |
+
createAccount: "url_to_the_create_account_endpoint_for_current_shop",
|
175 |
+
connectAccount: "url_to_the_connect_account_endpoint_for_current_shop",
|
176 |
+
deleteAccount: "url_to_the_delete_account_endpoint_for_current_shop"
|
177 |
+
},
|
178 |
+
xhrParams: {} // additional xhr params to include in the requests
|
179 |
+
});
|
180 |
+
```
|
181 |
+
|
182 |
+
The iframe API makes POST requests to the specified endpoints with content-type `application/x-www-form-urlencoded`.
|
183 |
+
The response for these requests should always be JSON and include a `redirect_url` key. This url will be used to
|
184 |
+
redirect the iframe after the action has been performed. In case of the connect account, the url will be used to
|
185 |
+
redirect your browser to the Nosto OAuth server.
|
186 |
+
The redirect url also needs to include error/success message keys, if you want to show messages to the user after the
|
187 |
+
actions, e.g. when a new account has been created a success message can be shown with instructions. These messages are
|
188 |
+
hard-coded in Nosto.
|
189 |
+
You do NOT need to use this JS API, but instead set up your own postMessage handler in your application.
|
190 |
+
|
191 |
+
### Sending order confirmations using the Nosto API
|
192 |
+
|
193 |
+
Sending order confirmations to Nosto is a vital part of the functionality. Order confirmations should be sent when an
|
194 |
+
order has been completed in the shop. It is NOT recommended to do this when the "thank you" page is shown to the user,
|
195 |
+
as payment gateways work differently and you cannot rely on the user always being redirected back to the shop after a
|
196 |
+
payment has been made. Therefore, it is recommended to send the order conformation when the order is marked as payed
|
197 |
+
in the shop.
|
198 |
+
|
199 |
+
Order confirmations can be sent two different ways:
|
200 |
+
|
201 |
+
* matched orders; where we know the Nosto customer ID of the user who placed the order
|
202 |
+
* un-matched orders: where we do not know the Nosto customer ID of the user who placed the order
|
203 |
+
|
204 |
+
The Nosto customer ID is set in a cookie "2c.cId" by Nosto and it is up to the platform to keep a link between users
|
205 |
+
and the Nosto customer ID. It is recommended to tie the Nosto customer ID to the order or shopping cart instead of an
|
206 |
+
user ID, as the platform may support guest checkouts.
|
207 |
+
|
208 |
+
```php
|
209 |
+
.....
|
210 |
+
try {
|
211 |
+
/**
|
212 |
+
* @var NostoOrderInterface $order
|
213 |
+
* @var NostoAccountInterface $account
|
214 |
+
* @var string $customerId
|
215 |
+
*/
|
216 |
+
NostoOrderConfirmation::send($order, $account, $customerId);
|
217 |
+
} catch (NostoException $e) {
|
218 |
+
// handle error
|
219 |
+
}
|
220 |
+
.....
|
221 |
+
```
|
222 |
+
|
223 |
+
### Sending product re-crawl requests using the Nosto API
|
224 |
+
|
225 |
+
Note: this feature has been deprecated in favor of the create/update/delete method below.
|
226 |
+
|
227 |
+
When a product changes in the store, stock is reduced, price is updated etc. it is recommended to send an API request
|
228 |
+
to Nosto that initiates a product "re-crawl" event. This is done to update the recommendations including that product
|
229 |
+
so that the newest information can be shown to the users on the site.
|
230 |
+
|
231 |
+
Note: the $product model needs to include only `productId` and `url` properties, all others can be omitted.
|
232 |
+
|
233 |
+
```php
|
234 |
+
.....
|
235 |
+
try {
|
236 |
+
/**
|
237 |
+
* @var NostoProductInterface $product
|
238 |
+
* @var NostoAccountInterface $account
|
239 |
+
*/
|
240 |
+
NostoProductReCrawl::send($product, $account);
|
241 |
+
} catch (NostoException $e) {
|
242 |
+
// handle error
|
243 |
+
}
|
244 |
+
.....
|
245 |
+
```
|
246 |
+
|
247 |
+
Batch re-crawling is also possible by creating a collection of product models:
|
248 |
+
|
249 |
+
```php
|
250 |
+
.....
|
251 |
+
try {
|
252 |
+
/**
|
253 |
+
* @var NostoExportProductCollection $collection
|
254 |
+
* @var NostoProductInterface $product
|
255 |
+
* @var NostoAccountInterface $account
|
256 |
+
*/
|
257 |
+
$collection[] = $product;
|
258 |
+
NostoProductReCrawl::sendBatch($collection, $account);
|
259 |
+
} catch (NostoException $e) {
|
260 |
+
// handle error
|
261 |
+
}
|
262 |
+
.....
|
263 |
+
```
|
264 |
+
|
265 |
+
### Sending product create/update/delete requests using the Nosto API
|
266 |
+
|
267 |
+
When a product changes in the store, stock is reduced, price is updated etc. it is recommended to send an API request
|
268 |
+
to Nosto to handle the updated product info. This is also true when adding new products as well as deleting existing ones.
|
269 |
+
This is done to update the recommendations including that product so that the newest information can be shown to the users
|
270 |
+
on the site.
|
271 |
+
|
272 |
+
Creating new products:
|
273 |
+
|
274 |
+
```php
|
275 |
+
.....
|
276 |
+
try {
|
277 |
+
/**
|
278 |
+
* @var NostoProductInterface $product
|
279 |
+
* @var NostoAccountInterface $account
|
280 |
+
*/
|
281 |
+
$op = new NostoOperationProduct($account);
|
282 |
+
$op->addProduct($product);
|
283 |
+
$op->create();
|
284 |
+
} catch (NostoException $e) {
|
285 |
+
// handle error
|
286 |
+
}
|
287 |
+
.....
|
288 |
+
```
|
289 |
+
|
290 |
+
Note: you can call `addProduct` multiple times to add more products to the request. This way you can batch create products.
|
291 |
+
|
292 |
+
Updating existing products:
|
293 |
+
|
294 |
+
```php
|
295 |
+
.....
|
296 |
+
try {
|
297 |
+
/**
|
298 |
+
* @var NostoProductInterface $product
|
299 |
+
* @var NostoAccountInterface $account
|
300 |
+
*/
|
301 |
+
$op = new NostoOperationProduct($account);
|
302 |
+
$op->addProduct($product);
|
303 |
+
$op->update();
|
304 |
+
} catch (NostoException $e) {
|
305 |
+
// handle error
|
306 |
+
}
|
307 |
+
.....
|
308 |
+
```
|
309 |
+
|
310 |
+
Note: you can call `addProduct` multiple times to add more products to the request. This way you can batch update products.
|
311 |
+
|
312 |
+
Deleting existing products:
|
313 |
+
|
314 |
+
```php
|
315 |
+
.....
|
316 |
+
try {
|
317 |
+
/**
|
318 |
+
* @var NostoProductInterface $product
|
319 |
+
* @var NostoAccountInterface $account
|
320 |
+
*/
|
321 |
+
$op = new NostoOperationProduct($account);
|
322 |
+
$op->addProduct($product);
|
323 |
+
$op->delete();
|
324 |
+
} catch (NostoException $e) {
|
325 |
+
// handle error
|
326 |
+
}
|
327 |
+
.....
|
328 |
+
```
|
329 |
+
|
330 |
+
Note: you can call `addProduct` multiple times to add more products to the request. This way you can batch delete products.
|
331 |
+
|
332 |
+
### Exporting encrypted product/order information that Nosto can request
|
333 |
+
|
334 |
+
When new Nosto accounts are created for a shop, Nosto will try to fetch historical data about products and orders.
|
335 |
+
This information is used to bootstrap recommendations and decreases the time needed to get accurate recommendations
|
336 |
+
showing in the shop.
|
337 |
+
|
338 |
+
For this to work, Nosto requires 2 public endpoints that can be called once a new account has been created through
|
339 |
+
the API. These endpoints should serve the history data encrypted with AES. The SDK comes bundled with the ability to
|
340 |
+
encrypt the data with a pure PHP solution (http://phpseclib.sourceforge.net/), It is recommended, but not required, to
|
341 |
+
have mcrypt installed on the server.
|
342 |
+
|
343 |
+
Additionally, the endpoints need to support the ability to limit the amount of products/orders to export and an offset
|
344 |
+
for fetching batches of data. These must be implemented as GET parameters "limit" and "offset" which will be sent as
|
345 |
+
integer values and expected to be applied to the data set being exported.
|
346 |
+
|
347 |
+
```php
|
348 |
+
.....
|
349 |
+
/**
|
350 |
+
* @var NostoProductInterface[] $products
|
351 |
+
* @var NostoAccountInterface $account
|
352 |
+
*/
|
353 |
+
$collection = new NostoExportProductCollection();
|
354 |
+
foreach ($products as $product) {
|
355 |
+
$collection[] = $product;
|
356 |
+
}
|
357 |
+
// The exported will encrypt the collection and output the result.
|
358 |
+
$cipher_text = NostoExporter::export($account, $collection);
|
359 |
+
echo $cipher_text;
|
360 |
+
// It is important to stop the script execution after the export, in order to avoid any additional data being outputted.
|
361 |
+
die();
|
362 |
+
```
|
363 |
+
|
364 |
+
```php
|
365 |
+
.....
|
366 |
+
/**
|
367 |
+
* @var NostoOrderInterface[] $orders
|
368 |
+
* @var NostoAccountInterface $account
|
369 |
+
*/
|
370 |
+
$collection = new NostoExportOrderCollection();
|
371 |
+
foreach ($orders as $order) {
|
372 |
+
$collection[] = $order;
|
373 |
+
}
|
374 |
+
// The exported will encrypt the collection and output the result.
|
375 |
+
$cipher_text = NostoExporter::export($account, $collection);
|
376 |
+
echo $cipher_text;
|
377 |
+
// It is important to stop the script execution after the export, in order to avoid any additional data being outputted.
|
378 |
+
die();
|
379 |
+
```
|
380 |
+
|
381 |
+
## Testing
|
382 |
+
|
383 |
+
The SDK is unit tested with Codeception (http://codeception.com/).
|
384 |
+
API and OAuth2 requests are tested using api-mock server (https://www.npmjs.com/package/api-mock) running on Node.
|
385 |
+
|
386 |
+
### Install Codeception & api-mock
|
387 |
+
|
388 |
+
First cd into the root directory.
|
389 |
+
|
390 |
+
Then install Codeception via composer:
|
391 |
+
|
392 |
+
```bash
|
393 |
+
php composer.phar install
|
394 |
+
```
|
395 |
+
|
396 |
+
And then install Node (http://nodejs.org/) and the npm package manager (https://www.npmjs.com/). After that you can install the api-mock server via npm:
|
397 |
+
|
398 |
+
```bash
|
399 |
+
npm install -g api-mock
|
400 |
+
```
|
401 |
+
|
402 |
+
### Running tests
|
403 |
+
|
404 |
+
First cd into the root directory.
|
405 |
+
|
406 |
+
Then start the api-mock server with the API blueprint:
|
407 |
+
|
408 |
+
```bash
|
409 |
+
api-mock tests/api-blueprint.md
|
410 |
+
```
|
411 |
+
|
412 |
+
Then in another window run the tests:
|
413 |
+
|
414 |
+
```bash
|
415 |
+
vendor/bin/codecept run
|
416 |
+
```
|
package.xml
CHANGED
@@ -1,18 +1,20 @@
|
|
1 |
<?xml version="1.0"?>
|
2 |
<package>
|
3 |
<name>Nosto_Tagging</name>
|
4 |
-
<version>2.6.
|
5 |
<stability>stable</stability>
|
6 |
<license uri="http://opensource.org/licenses/osl-3.0.php">Open Software License (OSL)</license>
|
7 |
<channel>community</channel>
|
8 |
<extends/>
|
9 |
<summary>Personalization for Magento</summary>
|
10 |
<description>Increase your conversion rate and average order value by delivering your customers personalized product recommendations throughout their shopping journey.</description>
|
11 |
-
<notes>*
|
|
|
|
|
12 |
<authors><author><name>Nosto</name><user>nosto</user><email>magento@nosto.com</email></author></authors>
|
13 |
-
<date>2015-
|
14 |
-
<time>
|
15 |
-
<contents><target name="magecommunity"><dir name="Nosto"><dir name="Tagging"><dir name="Block"><file name="Addtocart.php" hash="61d645e5cc9e54a5170ae03797f0426a"/><dir name="Adminhtml"><file name="Iframe.php" hash="d60e2221e6689b2ab2da9263897f6a6b"/><file name="Wizard.php" hash="f98931a1a6e327c0d05e43b73063f672"/></dir><file name="Cart.php" hash="c1c707dad76c98d807d5160b90c06ac6"/><file name="Category.php" hash="177a5d8d9f1ba9e246d149c228c3aec8"/><file name="Customer.php" hash="d35777ca399244e4fb441456320f8ad7"/><file name="Element.php" hash="e5b12bb118b92eb7075ff7a6e16e0eba"/><file name="Embed.php" hash="e8b628b6bc49fb865697552300d08526"/><file name="Meta.php" hash="1f761e731214b7572ef139d9e0577ea1"/><file name="Order.php" hash="32115070d380e654f093da11dd6e4d85"/><file name="Product.php" hash="ac7b85e6d03d94d03c59416b622b0039"/></dir><dir name="Helper"><file name="Account.php" hash="40eb62dd1718741b2064d4a440f46b2f"/><file name="Customer.php" hash="92da4f0ae6c2aef635b837635cd74238"/><file name="Data.php" hash="c50b9b5a694fdd0401748741de97f6ab"/><file name="Date.php" hash="1a108a4ec8169b73411b6c11b86a1d80"/><file name="Oauth.php" hash="9ecbea9e8411501cabe780e0511a1d05"/><file name="Price.php" hash="b7fe656fad1182f5c2166e95a4b29204"/><file name="Url.php" hash="289294904d246c56e4de96798927a7f6"/></dir><dir name="Model"><file name="Base.php" hash="c0b3c4a6f68a0b707bf85ceff50e3c4b"/><dir name="Container"><file name="Cart.php" hash="20d2936693361999575f1e6ac56f2e40"/><file name="Customer.php" hash="b03bca89845b6c939521add8df1f7e9a"/></dir><file name="Customer.php" hash="6d992a43a75f29836ed1450e130df560"/><dir name="Meta"><dir name="Account"><file name="Billing.php" hash="353e807f832a37591bf7359857044ca1"/><file name="Iframe.php" hash="731e2bf424e1b9d4e00d403f55a87b54"/><file name="Owner.php" hash="6fd3228a2758d06f78729c0250f7fd30"/></dir><file name="Account.php" hash="8df7024533e1cf657b407c49fb19a3c5"/><file name="Oauth.php" hash="0863271d8a3db0de93525f0e64308f1c"/><dir name="Order"><file name="Buyer.php" hash="3b8e57e195e214ed3324967684614745"/><file name="Item.php" hash="90dbec8a0201ccd8fbca3e10f2c362ad"/><file name="Status.php" hash="37520c32630aa4bf14d8213f39e80a4b"/></dir><file name="Order.php" hash="7844be08fe7f3f5310c18f352a952a5e"/><file name="Product.php" hash="40cf899477bac2f9916b030af8885e5e"/></dir><file name="Observer.php" hash="58bf4eb430d8a74fbb1ac5c68750c30c"/><file name="Product.php" hash="3630a2a688f013b296d1865e6f32e1d2"/><dir name="Resource"><dir name="Customer"><file name="Collection.php" hash="0c99b46d5108a6fe31cad1190d8ef47c"/></dir><file name="Customer.php" hash="f92e4e5334b5e3493e8f04664b20f105"/><dir name="Product"><file name="Collection.php" hash="7566a7f4483a00c923bac2fbea173abd"/></dir><file name="Setup.php" hash="506b08bcb10cbe74e95812c5f646429f"/></dir><dir name="System"><dir name="Config"><dir name="Source"><file name="Image.php" hash="d1fcc96aab01342627b96edf6fad1dd1"/></dir></dir></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="NostoController.php" hash="fd43fd322ea1f8d6b7db6d716250f71e"/></dir><file name="ExportController.php" hash="e20f49db51535241ed1857c2a86e077e"/><file name="OauthController.php" hash="19927d6e9648d0f381b1c2f1b9684339"/></dir><dir name="etc"><file name="adminhtml.xml" hash="7ea210738a77630f299a14b442f3b8d0"/><file name="cache.xml" hash="e874fbbf2eb89b325deb1a62afbcfb4d"/><file name="config.xml" hash="a9f989480972018def6d777d9f8a85ca"/><file name="system.xml" hash="7deba6544a09d7af8c07e6b5edc0975a"/></dir><dir name="sql"><dir name="tagging_setup"><file name="mysql4-install-1.2.0.php" hash="3cbc52834c44870859562eec7969b9fd"/><file name="mysql4-upgrade-1.1.7-1.2.0.php" hash="0d8eb7990461a9d4b74b479120067aeb"/></dir></dir></dir></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="template"><dir name="nostotagging"><file name="iframe.phtml" hash="c81931adf855a4893e0cf2dc60c390cb"/><file name="wizard.phtml" hash="3f92e94e5ee3d3cd9906a6b0942a3a1b"/></dir></dir><dir name="layout"><file name="nostotagging.xml" hash="29eb82c1a28e9c4d398239c765a3f5fd"/></dir></dir></dir></dir><dir name="frontend"><dir name="base"><dir name="default"><dir name="template"><dir name="nostotagging"><file name="addtocart.phtml" hash="e8776f59ec4c7c7b6eea2fae9d56e2a4"/><file name="cart.phtml" hash="3c4e80cdcebf63c56dc14a6594e167b8"/><dir name="category"><file name="view.phtml" hash="fc09e2770ad6281ec96c8e92accc01f1"/></dir><file name="category.phtml" hash="81f36742cb4e3adbf9f692cc8f0ea8a8"/><file name="customer.phtml" hash="e9bc92bb7f7df989cc706c7eaee3614a"/><file name="element.phtml" hash="e1d38981789e632a3607ccf2e171f0cb"/><file name="embed.phtml" hash="9193ddd1ae373b68c53f8364f511b0a5"/><file name="meta.phtml" hash="c1b862a4993503fae420fb0eba194b00"/><file name="order.phtml" hash="e15b11ff1cb20aafaab0dc134ddd1a9b"/><file name="product.phtml" hash="9df3ff9f6e363e478d7fd68bd09827b1"/></dir></dir><dir name="layout"><file name="nostotagging.xml" hash="8adc3eecf5f90feffabee29d6308912b"/></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Nosto_Tagging.xml" hash="1705cb7e6db28388662ef52882d61701"/></dir></target><target name="magelib"><dir name="nosto"><dir name="php-sdk"><dir name="src"><dir name="classes"><file name="Nosto.php" hash="c595c5f646f6e513b6604848f8d10118"/><file name="NostoAccount.php" hash="c422a7f104c5ebc6eac9d83986280579"/><file name="NostoCipher.php" hash="a3d7d148311aa0319387c0918e5e26dc"/><file name="NostoDotEnv.php" hash="90b23c1b02095c9368372f1d5346c3f9"/><file name="NostoMessage.php" hash="5933eadd2ad08427010b0bf16657266b"/><file name="NostoObject.php" hash="187808f0c55d02294d41e9395f4c5d58"/><file name="NostoOrderConfirmation.php" hash="2a3fd5efb196bc0dcb7ad57fb61a81d0"/><file name="NostoProductReCrawl.php" hash="f370c539409dd74fc98b7aa1ea0f6387"/><file name="NostoValidator.php" hash="2096ddc9979ec77f8f0b1ec58b459329"/><dir name="api"><file name="NostoApiRequest.php" hash="37db50c0d35ff9a848afe6a4bb871b6f"/><file name="NostoApiToken.php" hash="2febdbec0fd3609162845aa678b36b38"/></dir><dir name="collection"><file name="NostoCollection.php" hash="35cea0282628354413f629062b58663a"/><file name="NostoOrderCollection.php" hash="db6f517948c1258e1521ceb1ce49d477"/><file name="NostoProductCollection.php" hash="3ae29dbbcb7effa234fa83461d3e6901"/></dir><dir name="exception"><file name="NostoException.php" hash="c4610fb70278d01bd85bc83b8e74df30"/><file name="NostoHttpException.php" hash="dabf4298746db898c8fe709ea9e25818"/></dir><dir name="export"><file name="NostoExportOrderCollection.php" hash="91bdd99a2be75be062fe5c7cde1803e4"/><file name="NostoExportProductCollection.php" hash="33986c8767922da98aa90f03759dbc0f"/><file name="NostoExporter.php" hash="72ad0af4bce8e57ada5a29e3634df94f"/></dir><dir name="helper"><file name="NostoHelper.php" hash="f4ca6c78e047fec93c32b7eb822b0692"/><file name="NostoHelperDate.php" hash="081a2d8bfec710f2baa52192a99a2658"/><file name="NostoHelperIframe.php" hash="303668f25103c245396b43811a15c28d"/><file name="NostoHelperPrice.php" hash="ee9f217dc1b8e0fc679fb56ca3fd3ca1"/></dir><dir name="http"><file name="NostoHttpRequest.php" hash="2c5b96a56d33b33e334d4d3772c2b14d"/><file name="NostoHttpRequestAdapter.php" hash="d8bf8e5db44ad982b655372529f4d88c"/><file name="NostoHttpRequestAdapterCurl.php" hash="945a4357578f91291d09f1e2850da580"/><file name="NostoHttpRequestAdapterSocket.php" hash="88f57e6d98de2ac652a235e2786f0be7"/><file name="NostoHttpResponse.php" hash="9982d3ed15bfcc8f0147b2b4cc400223"/></dir><dir name="oauth"><file name="NostoOAuthClient.php" hash="2672d9de80d23c91776d97b9803d01b4"/><file name="NostoOAuthToken.php" hash="f81c1c1e5c4fc2010162d8f69de2cb33"/></dir><dir name="operation"><file name="NostoOperationProduct.php" hash="37e24121df779ead75e028b15a3fe226"/></dir></dir><file name="config.inc.php" hash="b46a56f8d61ff2cf69cedb4281719e00"/><dir name="interfaces"><file name="NostoExportCollectionInterface.php" hash="63c833c17fe43ce48b45e0f552313a8b"/><file name="NostoOAuthClientMetaDataInterface.php" hash="75a82417bfc27cd82e41ea9810d31428"/><file name="NostoProductInterface.php" hash="64a9e110a97ebd8be690664ce5b8e371"/><file name="NostoValidatableInterface.php" hash="57ad8b28225344127843b97049f5868d"/><dir name="account"><file name="NostoAccountInterface.php" hash="063da0d25a5420f4e727938467c078f3"/><file name="NostoAccountMetaDataBillingDetailsInterface.php" hash="ef31f0c3b41591fd76f85a25021f0fe4"/><file name="NostoAccountMetaDataIframeInterface.php" hash="c739e6a3ef39a308df6852361f2fd1d7"/><file name="NostoAccountMetaDataInterface.php" hash="5adf0a5ed876348a05028a3ff111bf79"/><file name="NostoAccountMetaDataOwnerInterface.php" hash="4c037b8cb1b529c16c91f25cce2b0ed7"/></dir><dir name="order"><file name="NostoOrderBuyerInterface.php" hash="890884e45bcca61f96f0f98cda40b6c1"/><file name="NostoOrderInterface.php" hash="d341b4faf020bfca01336c5d60ca5e48"/><file name="NostoOrderPurchasedItemInterface.php" hash="e33b94290465eea80d614db35144b75a"/><file name="NostoOrderStatusInterface.php" hash="8c89cf4296629b635f52b53a9b800b1f"/></dir></dir><dir name="js"><file name="NostoIframe.min.js" hash="5fd9f5b418dd796c469aaa0c58b34aaa"/><dir name="src"><file name="NostoIframe.js" hash="ca03585215f846258d2dbb58724e48fa"/></dir></dir><dir name="libs"><dir name="phpseclib"><dir name="crypt"><file name="NostoCryptAES.php" hash="7f16ec6fa7eefa011a27acf4506a3b57"/><file name="NostoCryptBase.php" hash="c78432d428ad8a70be832f91261d4c42"/><file name="NostoCryptRandom.php" hash="eb21a56b9cf6e6ef0b220620dd4d0ebe"/><file name="NostoCryptRijndael.php" hash="9c728d06c0249f8bc24a7c61606ccc89"/></dir></dir></dir><file name=".env.example" hash="42aa9514d8b3f65e9df96b0df601f63c"/></dir></dir></dir></target><target name="mage"><dir name="js"><dir name="nosto"><file name="NostoAdmin.js" hash="0119fb333233f1f0fa70f4167fb014ef"/><file name="NostoIframe.min.js" hash="5fd9f5b418dd796c469aaa0c58b34aaa"/><file name="iframeresizer.min.js" hash="163b065c9dd702dc364913a951b81fee"/></dir></dir></target></contents>
|
16 |
<compatible/>
|
17 |
<dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php><package><name>Mage_Core_Modules</name><channel>community</channel><min>1.6.0.0</min><max>1.9.2.1</max></package></required></dependencies>
|
18 |
</package>
|
1 |
<?xml version="1.0"?>
|
2 |
<package>
|
3 |
<name>Nosto_Tagging</name>
|
4 |
+
<version>2.6.5</version>
|
5 |
<stability>stable</stability>
|
6 |
<license uri="http://opensource.org/licenses/osl-3.0.php">Open Software License (OSL)</license>
|
7 |
<channel>community</channel>
|
8 |
<extends/>
|
9 |
<summary>Personalization for Magento</summary>
|
10 |
<description>Increase your conversion rate and average order value by delivering your customers personalized product recommendations throughout their shopping journey.</description>
|
11 |
+
<notes>* Add "external_order_ref" to order tagging and API requests in order to better
|
12 |
+
track orders
|
13 |
+
* Add "order_statuses" to the order export to be able to better check up on order funnels</notes>
|
14 |
<authors><author><name>Nosto</name><user>nosto</user><email>magento@nosto.com</email></author></authors>
|
15 |
+
<date>2015-10-07</date>
|
16 |
+
<time>09:12:46</time>
|
17 |
+
<contents><target name="magecommunity"><dir name="Nosto"><dir name="Tagging"><dir name="Block"><file name="Addtocart.php" hash="61d645e5cc9e54a5170ae03797f0426a"/><dir name="Adminhtml"><file name="Iframe.php" hash="d60e2221e6689b2ab2da9263897f6a6b"/><file name="Wizard.php" hash="f98931a1a6e327c0d05e43b73063f672"/></dir><file name="Cart.php" hash="c1c707dad76c98d807d5160b90c06ac6"/><file name="Category.php" hash="177a5d8d9f1ba9e246d149c228c3aec8"/><file name="Customer.php" hash="d35777ca399244e4fb441456320f8ad7"/><file name="Element.php" hash="e5b12bb118b92eb7075ff7a6e16e0eba"/><file name="Embed.php" hash="e8b628b6bc49fb865697552300d08526"/><file name="Meta.php" hash="1f761e731214b7572ef139d9e0577ea1"/><file name="Order.php" hash="32115070d380e654f093da11dd6e4d85"/><file name="Product.php" hash="ac7b85e6d03d94d03c59416b622b0039"/></dir><dir name="Helper"><file name="Account.php" hash="40eb62dd1718741b2064d4a440f46b2f"/><file name="Customer.php" hash="92da4f0ae6c2aef635b837635cd74238"/><file name="Data.php" hash="c50b9b5a694fdd0401748741de97f6ab"/><file name="Date.php" hash="1a108a4ec8169b73411b6c11b86a1d80"/><file name="Oauth.php" hash="9ecbea9e8411501cabe780e0511a1d05"/><file name="Price.php" hash="b7fe656fad1182f5c2166e95a4b29204"/><file name="Url.php" hash="289294904d246c56e4de96798927a7f6"/></dir><dir name="Model"><file name="Base.php" hash="c0b3c4a6f68a0b707bf85ceff50e3c4b"/><dir name="Container"><file name="Cart.php" hash="20d2936693361999575f1e6ac56f2e40"/><file name="Customer.php" hash="b03bca89845b6c939521add8df1f7e9a"/></dir><file name="Customer.php" hash="6d992a43a75f29836ed1450e130df560"/><dir name="Export"><dir name="Collection"><file name="Order.php" hash="d30a5091514397ecf10d1bcac09dade9"/></dir></dir><dir name="Meta"><dir name="Account"><file name="Billing.php" hash="353e807f832a37591bf7359857044ca1"/><file name="Iframe.php" hash="731e2bf424e1b9d4e00d403f55a87b54"/><file name="Owner.php" hash="6fd3228a2758d06f78729c0250f7fd30"/></dir><file name="Account.php" hash="8df7024533e1cf657b407c49fb19a3c5"/><file name="Oauth.php" hash="0863271d8a3db0de93525f0e64308f1c"/><dir name="Order"><file name="Buyer.php" hash="fa231d30ae0d275ba820f05bfcd2f12e"/><file name="Item.php" hash="598aa5a2c713a59e9125976b48764488"/><file name="Status.php" hash="6d55ecde2ea856227b27b0f95c89a976"/></dir><file name="Order.php" hash="e8638ff582ac759a7e6d4c8d311e7d04"/><file name="Product.php" hash="40cf899477bac2f9916b030af8885e5e"/></dir><file name="Observer.php" hash="102b3e6d330e151a4595c54dc88a18a9"/><file name="Product.php" hash="3630a2a688f013b296d1865e6f32e1d2"/><dir name="Resource"><dir name="Customer"><file name="Collection.php" hash="0c99b46d5108a6fe31cad1190d8ef47c"/></dir><file name="Customer.php" hash="f92e4e5334b5e3493e8f04664b20f105"/><dir name="Product"><file name="Collection.php" hash="7566a7f4483a00c923bac2fbea173abd"/></dir><file name="Setup.php" hash="506b08bcb10cbe74e95812c5f646429f"/></dir><dir name="Service"><file name="Order.php" hash="6c6f74cc3d50101bbda13a21a19b5f3c"/></dir><dir name="System"><dir name="Config"><dir name="Source"><file name="Image.php" hash="d1fcc96aab01342627b96edf6fad1dd1"/></dir></dir></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="NostoController.php" hash="fd43fd322ea1f8d6b7db6d716250f71e"/></dir><file name="ExportController.php" hash="f22510a39256c0baca4fbcb9301c8ef5"/><file name="OauthController.php" hash="19927d6e9648d0f381b1c2f1b9684339"/></dir><dir name="etc"><file name="adminhtml.xml" hash="7ea210738a77630f299a14b442f3b8d0"/><file name="cache.xml" hash="e874fbbf2eb89b325deb1a62afbcfb4d"/><file name="config.xml" hash="56e427762b58625eb31ed2a9a07d2719"/><file name="system.xml" hash="7deba6544a09d7af8c07e6b5edc0975a"/></dir><dir name="sql"><dir name="tagging_setup"><file name="mysql4-install-1.2.0.php" hash="3cbc52834c44870859562eec7969b9fd"/><file name="mysql4-upgrade-1.1.7-1.2.0.php" hash="0d8eb7990461a9d4b74b479120067aeb"/></dir></dir></dir></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="template"><dir name="nostotagging"><file name="iframe.phtml" hash="c81931adf855a4893e0cf2dc60c390cb"/><file name="wizard.phtml" hash="3f92e94e5ee3d3cd9906a6b0942a3a1b"/></dir></dir><dir name="layout"><file name="nostotagging.xml" hash="29eb82c1a28e9c4d398239c765a3f5fd"/></dir></dir></dir></dir><dir name="frontend"><dir name="base"><dir name="default"><dir name="template"><dir name="nostotagging"><file name="addtocart.phtml" hash="e8776f59ec4c7c7b6eea2fae9d56e2a4"/><file name="cart.phtml" hash="3c4e80cdcebf63c56dc14a6594e167b8"/><dir name="category"><file name="view.phtml" hash="fc09e2770ad6281ec96c8e92accc01f1"/></dir><file name="category.phtml" hash="81f36742cb4e3adbf9f692cc8f0ea8a8"/><file name="customer.phtml" hash="e9bc92bb7f7df989cc706c7eaee3614a"/><file name="element.phtml" hash="e1d38981789e632a3607ccf2e171f0cb"/><file name="embed.phtml" hash="9193ddd1ae373b68c53f8364f511b0a5"/><file name="meta.phtml" hash="c1b862a4993503fae420fb0eba194b00"/><file name="order.phtml" hash="c176f10c5cc5a1c53fa6ed973a637f6c"/><file name="product.phtml" hash="9df3ff9f6e363e478d7fd68bd09827b1"/></dir></dir><dir name="layout"><file name="nostotagging.xml" hash="8adc3eecf5f90feffabee29d6308912b"/></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Nosto_Tagging.xml" hash="1705cb7e6db28388662ef52882d61701"/></dir></target><target name="magelib"><dir name="nosto"><dir name="php-sdk"><file name="LICENSE.txt" hash="309b355442cb85601216abd7a41909d2"/><file name="README.md" hash="0c4860a3dfe7bca30f3eb56c146b4166"/><dir name="src"><dir name="classes"><file name="Nosto.php" hash="c595c5f646f6e513b6604848f8d10118"/><file name="NostoAccount.php" hash="c422a7f104c5ebc6eac9d83986280579"/><file name="NostoCipher.php" hash="a3d7d148311aa0319387c0918e5e26dc"/><file name="NostoDotEnv.php" hash="90b23c1b02095c9368372f1d5346c3f9"/><file name="NostoMessage.php" hash="5933eadd2ad08427010b0bf16657266b"/><file name="NostoObject.php" hash="187808f0c55d02294d41e9395f4c5d58"/><file name="NostoOrderConfirmation.php" hash="2a3fd5efb196bc0dcb7ad57fb61a81d0"/><file name="NostoProductReCrawl.php" hash="f370c539409dd74fc98b7aa1ea0f6387"/><file name="NostoValidator.php" hash="2096ddc9979ec77f8f0b1ec58b459329"/><dir name="api"><file name="NostoApiRequest.php" hash="37db50c0d35ff9a848afe6a4bb871b6f"/><file name="NostoApiToken.php" hash="2febdbec0fd3609162845aa678b36b38"/></dir><dir name="collection"><file name="NostoCollection.php" hash="35cea0282628354413f629062b58663a"/><file name="NostoOrderCollection.php" hash="db6f517948c1258e1521ceb1ce49d477"/><file name="NostoProductCollection.php" hash="3ae29dbbcb7effa234fa83461d3e6901"/></dir><dir name="exception"><file name="NostoException.php" hash="c4610fb70278d01bd85bc83b8e74df30"/><file name="NostoHttpException.php" hash="dabf4298746db898c8fe709ea9e25818"/></dir><dir name="export"><file name="NostoExportOrderCollection.php" hash="91bdd99a2be75be062fe5c7cde1803e4"/><file name="NostoExportProductCollection.php" hash="33986c8767922da98aa90f03759dbc0f"/><file name="NostoExporter.php" hash="72ad0af4bce8e57ada5a29e3634df94f"/></dir><dir name="helper"><file name="NostoHelper.php" hash="f4ca6c78e047fec93c32b7eb822b0692"/><file name="NostoHelperDate.php" hash="081a2d8bfec710f2baa52192a99a2658"/><file name="NostoHelperIframe.php" hash="303668f25103c245396b43811a15c28d"/><file name="NostoHelperPrice.php" hash="ee9f217dc1b8e0fc679fb56ca3fd3ca1"/></dir><dir name="http"><file name="NostoHttpRequest.php" hash="2c5b96a56d33b33e334d4d3772c2b14d"/><file name="NostoHttpRequestAdapter.php" hash="d8bf8e5db44ad982b655372529f4d88c"/><file name="NostoHttpRequestAdapterCurl.php" hash="945a4357578f91291d09f1e2850da580"/><file name="NostoHttpRequestAdapterSocket.php" hash="88f57e6d98de2ac652a235e2786f0be7"/><file name="NostoHttpResponse.php" hash="9982d3ed15bfcc8f0147b2b4cc400223"/></dir><dir name="oauth"><file name="NostoOAuthClient.php" hash="2672d9de80d23c91776d97b9803d01b4"/><file name="NostoOAuthToken.php" hash="f81c1c1e5c4fc2010162d8f69de2cb33"/></dir><dir name="operation"><file name="NostoOperationProduct.php" hash="37e24121df779ead75e028b15a3fe226"/></dir></dir><file name="config.inc.php" hash="b46a56f8d61ff2cf69cedb4281719e00"/><dir name="interfaces"><file name="NostoExportCollectionInterface.php" hash="63c833c17fe43ce48b45e0f552313a8b"/><file name="NostoOAuthClientMetaDataInterface.php" hash="75a82417bfc27cd82e41ea9810d31428"/><file name="NostoProductInterface.php" hash="64a9e110a97ebd8be690664ce5b8e371"/><file name="NostoValidatableInterface.php" hash="57ad8b28225344127843b97049f5868d"/><dir name="account"><file name="NostoAccountInterface.php" hash="063da0d25a5420f4e727938467c078f3"/><file name="NostoAccountMetaDataBillingDetailsInterface.php" hash="ef31f0c3b41591fd76f85a25021f0fe4"/><file name="NostoAccountMetaDataIframeInterface.php" hash="c739e6a3ef39a308df6852361f2fd1d7"/><file name="NostoAccountMetaDataInterface.php" hash="5adf0a5ed876348a05028a3ff111bf79"/><file name="NostoAccountMetaDataOwnerInterface.php" hash="4c037b8cb1b529c16c91f25cce2b0ed7"/></dir><dir name="order"><file name="NostoOrderBuyerInterface.php" hash="890884e45bcca61f96f0f98cda40b6c1"/><file name="NostoOrderInterface.php" hash="d341b4faf020bfca01336c5d60ca5e48"/><file name="NostoOrderPurchasedItemInterface.php" hash="e33b94290465eea80d614db35144b75a"/><file name="NostoOrderStatusInterface.php" hash="8c89cf4296629b635f52b53a9b800b1f"/></dir></dir><dir name="js"><file name="NostoIframe.min.js" hash="5fd9f5b418dd796c469aaa0c58b34aaa"/><dir name="src"><file name="NostoIframe.js" hash="ca03585215f846258d2dbb58724e48fa"/></dir></dir><dir name="libs"><dir name="phpseclib"><dir name="crypt"><file name="NostoCryptAES.php" hash="7f16ec6fa7eefa011a27acf4506a3b57"/><file name="NostoCryptBase.php" hash="c78432d428ad8a70be832f91261d4c42"/><file name="NostoCryptRandom.php" hash="eb21a56b9cf6e6ef0b220620dd4d0ebe"/><file name="NostoCryptRijndael.php" hash="9c728d06c0249f8bc24a7c61606ccc89"/></dir></dir></dir><file name=".env.example" hash="42aa9514d8b3f65e9df96b0df601f63c"/></dir></dir></dir></target><target name="mage"><dir name="js"><dir name="nosto"><file name="NostoAdmin.js" hash="0119fb333233f1f0fa70f4167fb014ef"/><file name="NostoIframe.min.js" hash="5fd9f5b418dd796c469aaa0c58b34aaa"/><file name="iframeresizer.min.js" hash="163b065c9dd702dc364913a951b81fee"/></dir></dir></target></contents>
|
18 |
<compatible/>
|
19 |
<dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php><package><name>Mage_Core_Modules</name><channel>community</channel><min>1.6.0.0</min><max>1.9.2.1</max></package></required></dependencies>
|
20 |
</package>
|