Version Notes
v1,1.3
Big refactoring.
Split testing functionality
v1.0.7
Minor Refactoring
v1.0.6
New hooks for custom checkouts that do not use Magento's default hooks.
If the sku needs to be added at the beginn of the checkout, some payment providers like Klarna require that the following hook need need to be triggered
* maxicycle_add_product_to_quote
If the sales_order_place_after hook is not triggered the following hook needs to be triggered
* maxicycle_add_product_to_order
v1.0.5
Added compatibility with Klarna
v1.0.4
Fixed bug in PHP 5.4
v1.0.3
Refresh caching
Fix bug when having a multi store setup for SKU check
v1.0.2
Bug fix release
v1.0.1
Stability improvements
Logging into separate logfile
v.1.0.0
* Initial official release
Download this release
Release Info
Developer | Maxicycle Software GmbH |
Extension | MaxicycleCom_Connector |
Version | 1.1.3 |
Comparing to | |
See all releases |
Code changes from version 1.0.7 to 1.1.3
- app/code/community/Maxicycle/Connector/Block/Adminhtml/Results/Grid.php +6 -0
- app/code/community/Maxicycle/Connector/Model/Api/Rest.php +65 -39
- app/code/community/Maxicycle/Connector/Model/Insert.php +367 -0
- app/code/community/Maxicycle/Connector/Model/Observer.php +97 -302
- app/code/community/Maxicycle/Connector/etc/config.xml +3 -3
- app/code/community/Maxicycle/Connector/sql/maxicycle_setup/upgrade-1.0.4-1.0.5.php +1 -1
- app/code/community/Maxicycle/Connector/sql/maxicycle_setup/upgrade-1.0.7-1.1.1.php +32 -0
- app/code/community/Maxicycle/Connector/sql/maxicycle_setup/upgrade-1.1.1-1.1.2.php +23 -0
- app/code/community/Maxicycle/Connector/sql/maxicycle_setup/upgrade-1.1.2-1.1.3.php +22 -0
- package.xml +9 -5
app/code/community/Maxicycle/Connector/Block/Adminhtml/Results/Grid.php
CHANGED
@@ -53,6 +53,12 @@ class Maxicycle_Connector_Block_Adminhtml_Results_Grid extends Mage_Adminhtml_Bl
|
|
53 |
'index' => 'campaign_order_type',
|
54 |
));
|
55 |
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
$this->addColumn('response_to_order_id', array(
|
57 |
'header' => Mage::helper('maxicycle')->__('Response To Order ID'),
|
58 |
'align' => 'left',
|
53 |
'index' => 'campaign_order_type',
|
54 |
));
|
55 |
|
56 |
+
$this->addColumn('sku', array(
|
57 |
+
'header' => Mage::helper('maxicycle')->__('SKU'),
|
58 |
+
'align' => 'left',
|
59 |
+
'index' => 'sku',
|
60 |
+
));
|
61 |
+
|
62 |
$this->addColumn('response_to_order_id', array(
|
63 |
'header' => Mage::helper('maxicycle')->__('Response To Order ID'),
|
64 |
'align' => 'left',
|
app/code/community/Maxicycle/Connector/Model/Api/Rest.php
CHANGED
@@ -27,17 +27,17 @@ class Maxicycle_Connector_Model_Api_Rest extends Maxicycle_Connector_Model_Api_A
|
|
27 |
|
28 |
// Check if API key param exist between data
|
29 |
if (!array_key_exists('sku', $data)) {
|
30 |
-
// There is no
|
31 |
return $this->_response(array('message' => 'No SKU provided'), 403);
|
|
|
|
|
|
|
|
|
|
|
32 |
} else {
|
33 |
-
|
34 |
-
$_product = Mage::getModel('catalog/product')->getIdBySku($data['sku']);
|
35 |
-
if (!$_product) {
|
36 |
-
return $this->_response(array('message' => 'Product with SKU: ' . $data['sku'] . ' not exist'), 404);
|
37 |
-
} else {
|
38 |
-
return $this->_response(array('message' => 'Product with SKU: exist'), 200);
|
39 |
-
}
|
40 |
}
|
|
|
41 |
} else {
|
42 |
// Default answer for all other HTTP methods
|
43 |
return $this->_response(array('message' => 'Method: ' . $this->method . ' is not supported.'), 500);
|
@@ -92,10 +92,9 @@ class Maxicycle_Connector_Model_Api_Rest extends Maxicycle_Connector_Model_Api_A
|
|
92 |
if ($this->method == 'POST') {
|
93 |
// Check if all params exist
|
94 |
if (array_key_exists('name', $data) && array_key_exists('sku', $data) && array_key_exists('campaign_start', $data) && array_key_exists('campaign_end', $data) && array_key_exists('response_enddate', $data) && array_key_exists('treatment_group_size', $data)) {
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
return $this->_response(array('message' => 'Product with SKU: ' . $data['sku'] . ' not exist'), 404);
|
99 |
}
|
100 |
|
101 |
// Check if store with given ID exist
|
@@ -137,10 +136,9 @@ class Maxicycle_Connector_Model_Api_Rest extends Maxicycle_Connector_Model_Api_A
|
|
137 |
return $this->_response(array('message' => 'Campaign with ID: ' . $data['campaign_id'] . ' not exist'), 404);
|
138 |
}
|
139 |
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
return $this->_response(array('message' => 'Product with SKU: ' . $data['sku'] . ' not exist'), 404);
|
144 |
}
|
145 |
|
146 |
// Check if store with given ID exist
|
@@ -198,6 +196,31 @@ class Maxicycle_Connector_Model_Api_Rest extends Maxicycle_Connector_Model_Api_A
|
|
198 |
return $this->_response(array('message' => 'Method: ' . $this->method . ' is not supported.'), 500);
|
199 |
}
|
200 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
201 |
|
202 |
public function results($campaign_id, $store_id) {
|
203 |
if ($this->method == 'GET') {
|
@@ -219,41 +242,43 @@ class Maxicycle_Connector_Model_Api_Rest extends Maxicycle_Connector_Model_Api_A
|
|
219 |
$results = array();
|
220 |
|
221 |
// Load all campaigns
|
222 |
-
$
|
223 |
// Loop over all campaigns
|
224 |
-
foreach ($
|
225 |
// For debug purpose
|
226 |
if ($this->_debug) {
|
227 |
// Simply return data without any check
|
228 |
$results[] = array(
|
229 |
-
'campaign_id' => $
|
230 |
-
'order_id' => $
|
231 |
-
'customer_id' => $
|
232 |
-
'campaign_order_type' => $
|
233 |
-
'order_date' => $
|
234 |
-
'response_to_order_id' => $
|
235 |
-
'revenue' => $
|
236 |
-
'gross_profit' => $
|
237 |
-
'last_order_update' => $
|
|
|
238 |
);
|
239 |
-
$
|
240 |
} else {
|
241 |
// Order status check
|
242 |
-
$order_status = $this->_db->fetchOne("SELECT status FROM " . $this->_resource->getTableName("sales_flat_order_grid") . " WHERE increment_id = '" . $
|
243 |
|
244 |
if (in_array($order_status, $enable_statuses)) {
|
245 |
$results[] = array(
|
246 |
-
'campaign_id' => $
|
247 |
-
'order_id' => $
|
248 |
-
'customer_id' => $
|
249 |
-
'campaign_order_type' => $
|
250 |
-
'order_date' => $
|
251 |
-
'response_to_order_id' => $
|
252 |
-
'revenue' => $
|
253 |
-
'gross_profit' => $
|
254 |
-
'last_order_update' => $
|
|
|
255 |
);
|
256 |
-
$
|
257 |
}
|
258 |
}
|
259 |
}
|
@@ -378,6 +403,7 @@ class Maxicycle_Connector_Model_Api_Rest extends Maxicycle_Connector_Model_Api_A
|
|
378 |
'order_profit' => $gross_profit,
|
379 |
'last_order_update_date' => $order->getUpdatedAt(),
|
380 |
'campaign_order_type' => $order->getMaxicycleOrderType(),
|
|
|
381 |
'export_flag' => 0
|
382 |
);
|
383 |
|
27 |
|
28 |
// Check if API key param exist between data
|
29 |
if (!array_key_exists('sku', $data)) {
|
30 |
+
// There is no sku in reuqest
|
31 |
return $this->_response(array('message' => 'No SKU provided'), 403);
|
32 |
+
}
|
33 |
+
|
34 |
+
$missing_skus = $this->checkSkus($data['sku']);
|
35 |
+
if (!empty($missing_skus)) {
|
36 |
+
return $this->_response(array('message' => 'Product with SKU: ' . join(', ', $missing_skus) . ' does not exist'), 404);
|
37 |
} else {
|
38 |
+
return $this->_response(array('message' => 'Product with SKU: exist'), 200);
|
|
|
|
|
|
|
|
|
|
|
|
|
39 |
}
|
40 |
+
|
41 |
} else {
|
42 |
// Default answer for all other HTTP methods
|
43 |
return $this->_response(array('message' => 'Method: ' . $this->method . ' is not supported.'), 500);
|
92 |
if ($this->method == 'POST') {
|
93 |
// Check if all params exist
|
94 |
if (array_key_exists('name', $data) && array_key_exists('sku', $data) && array_key_exists('campaign_start', $data) && array_key_exists('campaign_end', $data) && array_key_exists('response_enddate', $data) && array_key_exists('treatment_group_size', $data)) {
|
95 |
+
$missing_skus = $this->checkSkus($data['sku']);
|
96 |
+
if (!empty($missing_skus)) {
|
97 |
+
return $this->_response(array('message' => 'Product with SKU: ' . join(', ', $missing_skus) . ' does not exist'), 404);
|
|
|
98 |
}
|
99 |
|
100 |
// Check if store with given ID exist
|
136 |
return $this->_response(array('message' => 'Campaign with ID: ' . $data['campaign_id'] . ' not exist'), 404);
|
137 |
}
|
138 |
|
139 |
+
$missing_skus = $this->checkSkus($data['sku']);
|
140 |
+
if (!empty($missing_skus)) {
|
141 |
+
return $this->_response(array('message' => 'Product with SKU: ' . join(', ', $missing_skus) . ' does not exist'), 404);
|
|
|
142 |
}
|
143 |
|
144 |
// Check if store with given ID exist
|
196 |
return $this->_response(array('message' => 'Method: ' . $this->method . ' is not supported.'), 500);
|
197 |
}
|
198 |
}
|
199 |
+
|
200 |
+
// Check skus if they exist in the shop
|
201 |
+
// sku_string 'sku1:30;sku2:40;sku3:30'
|
202 |
+
private function checkSkus($sku_string) {
|
203 |
+
$skus = explode(';', $sku_string);
|
204 |
+
// $skus == ['sku1:30', 'sku2:40', 'sku3:30']
|
205 |
+
$not_found_sku = array();
|
206 |
+
|
207 |
+
foreach($skus as $sku_percentage) {
|
208 |
+
Mage::log('Checking sku percentage: ' . $sku_percentage , null, 'maxicycle.log');
|
209 |
+
$sku_p_ary = explode(':', $sku_percentage);
|
210 |
+
$sku = $sku_p_ary[0];
|
211 |
+
// if not found
|
212 |
+
if (!$this->checkProduct($sku)) {
|
213 |
+
Mage::log('Sku not found: ' . $sku , null, 'maxicycle.log');
|
214 |
+
array_push($not_found_sku, $sku);
|
215 |
+
}
|
216 |
+
}
|
217 |
+
return $not_found_sku;
|
218 |
+
}
|
219 |
+
|
220 |
+
private function checkProduct($sku) {
|
221 |
+
$_product = Mage::getModel('catalog/product')->loadByAttribute('sku', $sku);
|
222 |
+
return ($_product ? true : false );
|
223 |
+
}
|
224 |
|
225 |
public function results($campaign_id, $store_id) {
|
226 |
if ($this->method == 'GET') {
|
242 |
$results = array();
|
243 |
|
244 |
// Load all campaigns
|
245 |
+
$orders = Mage::getModel('maxicycle/results')->getCollection()->addFieldToFilter('campaign_id', $campaign_id)->addFieldToFilter('export_flag', 0);
|
246 |
// Loop over all campaigns
|
247 |
+
foreach ($orders as $order) {
|
248 |
// For debug purpose
|
249 |
if ($this->_debug) {
|
250 |
// Simply return data without any check
|
251 |
$results[] = array(
|
252 |
+
'campaign_id' => $order->getCampaignId(),
|
253 |
+
'order_id' => $order->getOrderId(),
|
254 |
+
'customer_id' => $order->getMaxicycleCustomerId(),
|
255 |
+
'campaign_order_type' => $order->getCampaignOrderType(),
|
256 |
+
'order_date' => $order->getCreatedAt(),
|
257 |
+
'response_to_order_id' => $order->getResponseToOrderId(),
|
258 |
+
'revenue' => $order->getGrandTotal(),
|
259 |
+
'gross_profit' => $order->getOrderProfit(),
|
260 |
+
'last_order_update' => $order->getLastOrderUpdateDate(),
|
261 |
+
'sku' => $order->getSku()
|
262 |
);
|
263 |
+
$order->setExportFlag(1)->save();
|
264 |
} else {
|
265 |
// Order status check
|
266 |
+
$order_status = $this->_db->fetchOne("SELECT status FROM " . $this->_resource->getTableName("sales_flat_order_grid") . " WHERE increment_id = '" . $order->getOrderId() . "'");
|
267 |
|
268 |
if (in_array($order_status, $enable_statuses)) {
|
269 |
$results[] = array(
|
270 |
+
'campaign_id' => $order->getCampaignId(),
|
271 |
+
'order_id' => $order->getOrderId(),
|
272 |
+
'customer_id' => $order->getMaxicycleCustomerId(),
|
273 |
+
'campaign_order_type' => $order->getCampaignOrderType(),
|
274 |
+
'order_date' => $order->getCreatedAt(),
|
275 |
+
'response_to_order_id' => $order->getResponseToOrderId(),
|
276 |
+
'revenue' => $order->getGrandTotal(),
|
277 |
+
'gross_profit' => $order->getOrderProfit(),
|
278 |
+
'last_order_update' => $order->getLastOrderUpdateDate(),
|
279 |
+
'sku' => $order->getSku()
|
280 |
);
|
281 |
+
$order->setExportFlag(1)->save();
|
282 |
}
|
283 |
}
|
284 |
}
|
403 |
'order_profit' => $gross_profit,
|
404 |
'last_order_update_date' => $order->getUpdatedAt(),
|
405 |
'campaign_order_type' => $order->getMaxicycleOrderType(),
|
406 |
+
'sku' => $campaign->getSku(),
|
407 |
'export_flag' => 0
|
408 |
);
|
409 |
|
app/code/community/Maxicycle/Connector/Model/Insert.php
ADDED
@@ -0,0 +1,367 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Copyright (c) 2009-2014 Vaimo AB
|
5 |
+
*
|
6 |
+
* Vaimo reserves all rights in the Program as delivered. The Program
|
7 |
+
* or any portion thereof may not be reproduced in any form whatsoever without
|
8 |
+
* the written consent of Vaimo, except as provided by licence. A licence
|
9 |
+
* under Vaimo's rights in the Program may be available directly from
|
10 |
+
* Vaimo.
|
11 |
+
*
|
12 |
+
* Disclaimer:
|
13 |
+
* THIS NOTICE MAY NOT BE REMOVED FROM THE PROGRAM BY ANY USER THEREOF.
|
14 |
+
* THE PROGRAM IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
15 |
+
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
17 |
+
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19 |
+
* OUT OF OR IN CONNECTION WITH THE PROGRAM OR THE USE OR OTHER DEALINGS
|
20 |
+
* IN THE PROGRAM.
|
21 |
+
*
|
22 |
+
* @category Maxicycle
|
23 |
+
* @package Maxicycle_Connector
|
24 |
+
* @copyright Copyright (c) 2015-2016 Maxicycle Software GmbH
|
25 |
+
*/
|
26 |
+
|
27 |
+
class Maxicycle_Connector_Model_Insert extends Mage_Core_Model_Abstract {
|
28 |
+
|
29 |
+
var $_db = null;
|
30 |
+
var $_dbResource = null;
|
31 |
+
var $_enabled = NULL;
|
32 |
+
var $_config = array();
|
33 |
+
var $_quote_or_order = NULL;
|
34 |
+
var $_campaign = NULL;
|
35 |
+
var $_now = NULL;
|
36 |
+
var $_is_type = NULL; // order or quote
|
37 |
+
var $_store_id = NULL;
|
38 |
+
|
39 |
+
public function __construct($params) {
|
40 |
+
Mage::log('Maxicycle Campaign initialized for store ' . $params['store_id'], null, 'maxicycle.log');
|
41 |
+
$this->_db = Mage::getSingleton('core/resource')->getConnection('core_write');
|
42 |
+
$this->_dbResource = Mage::getSingleton('core/resource');
|
43 |
+
$this->setConfig($params['store_id']);
|
44 |
+
$this->_store_id = $params['store_id'];
|
45 |
+
$this->_quote_or_order = $params['quote_or_order'];
|
46 |
+
$this->_now = date("Y-m-d H:i:s");
|
47 |
+
$this->_is_type = $params['is_type'];
|
48 |
+
}
|
49 |
+
|
50 |
+
// get and set module configuration
|
51 |
+
private function setConfig($store_id) {
|
52 |
+
$this->_config = Mage::helper('maxicycle')->getConfiguration($store_id);
|
53 |
+
}
|
54 |
+
|
55 |
+
public function addInsert() {
|
56 |
+
Mage::log('Checking for active campaigns', null, 'maxicycle.log');
|
57 |
+
$active_campaigns = $this->_getActiveCampaigns();
|
58 |
+
// If there is some active campaign
|
59 |
+
if (count($active_campaigns) > 0) {
|
60 |
+
$order = $this->_quote_or_order;
|
61 |
+
Mage::log('Active campaigns, checking for product to add', null, 'maxicycle.log');
|
62 |
+
// Loop over active campaings
|
63 |
+
foreach ($active_campaigns as $campaign) {
|
64 |
+
$this->_campaign = $campaign;
|
65 |
+
$order->setMaxicycleCampaignId($campaign['campaign_id']);
|
66 |
+
$this->_setCustomerIdToOrder();
|
67 |
+
// Process condition - ADD PRODUCT - only if campaign is still in CP and not already in RT
|
68 |
+
if (!$this->_inResponsePeriod($campaign)) {
|
69 |
+
$this->_addProduct();
|
70 |
+
} else {
|
71 |
+
Mage::log('Not adding product, campaign in response period', null, 'maxicycle.log');
|
72 |
+
}
|
73 |
+
}
|
74 |
+
} else {
|
75 |
+
Mage::log('No active campaigns, not adding a product', null, 'maxicycle.log');
|
76 |
+
}
|
77 |
+
Mage::log('adding insert done!', null, 'maxicycle.log');
|
78 |
+
}
|
79 |
+
|
80 |
+
private function _addProduct() {
|
81 |
+
// if treatment -> insert SKU
|
82 |
+
if ($this->_isTreatment()) {
|
83 |
+
Mage::log('Treament order', null, 'maxicycle.log');
|
84 |
+
$this->checkAndAddProduct();
|
85 |
+
} else {
|
86 |
+
Mage::log('OrderType: control', null, 'maxicycle.log');
|
87 |
+
// Set it into order to be used when exporting the results
|
88 |
+
$this->_quote_or_order->setMaxicycleOrderType('control');
|
89 |
+
}
|
90 |
+
}
|
91 |
+
|
92 |
+
// Takes the product skus stored in campaigns and checks if they were already added
|
93 |
+
// product_sku 'sku1:30;sku2:40;sku3:30'
|
94 |
+
private function checkAndAddProduct() {
|
95 |
+
// if quote we want to check if sku is already on order to not add it twice
|
96 |
+
// like on log in on checkout
|
97 |
+
$already_added = false;
|
98 |
+
// Check if we have already added the sku
|
99 |
+
// Either quote has added sku or a reload/log in on checkout
|
100 |
+
if ($this->checkIfSKUAlreadyAdded()) {
|
101 |
+
Mage::log('Product was already added to order', null, 'maxicycle.log');
|
102 |
+
return;
|
103 |
+
}
|
104 |
+
$product = $this->pickProduct();
|
105 |
+
if ($product) {
|
106 |
+
if ($this->_isOrder()) {
|
107 |
+
$this->addOrderItem();
|
108 |
+
} else {
|
109 |
+
$this->_addQuoteItem($product);
|
110 |
+
}
|
111 |
+
// Mark order
|
112 |
+
$this->_quote_or_order->setMaxicycleOrderType('treatment');
|
113 |
+
Mage::log('OrderType: treatment', null, 'maxicycle.log');
|
114 |
+
}
|
115 |
+
else {
|
116 |
+
Mage::log('OrderType: error, SKU not found', null, 'maxicycle.log');
|
117 |
+
$this->_quote_or_order->setMaxicycleOrderType('error');
|
118 |
+
}
|
119 |
+
|
120 |
+
}
|
121 |
+
|
122 |
+
// Checks if Quote is already a Maxicycle order
|
123 |
+
// if so, copies the order type and campaign id
|
124 |
+
// returns campaign type or nil
|
125 |
+
private function _alreadyMaxicycleOrder($order) {
|
126 |
+
Mage::log('Check if quote is already maxicycle order', null, 'maxicycle.log');
|
127 |
+
$quote_id = $order->getQuoteId();
|
128 |
+
$quote = Mage::getModel('sales/quote')->load($quote_id);
|
129 |
+
$campaignType = $quote->getMaxicycleOrderType();
|
130 |
+
|
131 |
+
// if type already set, copy values
|
132 |
+
if (isset($campaignType)) {
|
133 |
+
$order->setMaxicycleOrderType($quote->getMaxicycleOrderType());
|
134 |
+
$order->setMaxicycleCampaignId($quote->getMaxicycleCampaignId());
|
135 |
+
$order->setMaxicycleSku($quote->getMaxicycleSku());
|
136 |
+
}
|
137 |
+
return $campaignType;
|
138 |
+
}
|
139 |
+
|
140 |
+
// This method loops through all items and checks if one of them is on of the skus
|
141 |
+
// Array(
|
142 |
+
// [0] => voucher:30
|
143 |
+
// [1] => gimmik:50
|
144 |
+
// [2] => treat:20)
|
145 |
+
private function checkIfSKUAlreadyAdded() {
|
146 |
+
// $skus == ['sku1', 'sku2', 'sku3']
|
147 |
+
$skus_array = explode(';', $this->_campaign['product_sku']);
|
148 |
+
$items = $this->_quote_or_order->getAllItems();
|
149 |
+
|
150 |
+
$skus = $this->getSkus($skus_array);
|
151 |
+
$added = FALSE;
|
152 |
+
Foreach($items as $item){
|
153 |
+
if (in_array($item->getSku(), $skus)) {
|
154 |
+
$added = TRUE;
|
155 |
+
}
|
156 |
+
}
|
157 |
+
Mage::log('SKU already added?:' . $added, null, 'maxicycle.log');
|
158 |
+
return $added;
|
159 |
+
}
|
160 |
+
|
161 |
+
// create and add order item to quote
|
162 |
+
private function addOrderItem() {
|
163 |
+
Mage::log('Adding product to order', null, 'maxicycle.log');
|
164 |
+
$product = $this->pickProduct();
|
165 |
+
$order = $this->_quote_or_order;
|
166 |
+
if ($product) {
|
167 |
+
try {
|
168 |
+
// Save product into order
|
169 |
+
$rowTotal = 0.00;
|
170 |
+
$order_item = Mage::getModel('sales/order_item')
|
171 |
+
->setStoreId($this->_store_id)
|
172 |
+
->setQuoteItemId(null)
|
173 |
+
->setQuoteParentItemId(null)
|
174 |
+
->setProductId($product->getId())
|
175 |
+
->setProductType($product->getTypeId())
|
176 |
+
->setQtyBackordered(null)
|
177 |
+
->setTotalQtyOrdered(1)
|
178 |
+
->setQtyOrdered(1)
|
179 |
+
->setName($product->getName())
|
180 |
+
->setSku($product->getSku())
|
181 |
+
->setPrice(0)
|
182 |
+
->setBasePrice(0)
|
183 |
+
->setOriginalPrice(0)
|
184 |
+
->setRowTotal($rowTotal)
|
185 |
+
->setBaseRowTotal($rowTotal)
|
186 |
+
->setOrder($order);
|
187 |
+
$order_item->save();
|
188 |
+
Mage::log('Product successfully added to quote', null, 'maxicycle.log');
|
189 |
+
} catch (Exception $e) {
|
190 |
+
Mage::log('Adding product to order failed: ' .$e->getMessage(), null, 'maxicycle.log');
|
191 |
+
throw $e;
|
192 |
+
}
|
193 |
+
}
|
194 |
+
}
|
195 |
+
// create and add order item to quote
|
196 |
+
private function _addQuoteItem($product) {
|
197 |
+
$quote = $this->_quote_or_order;
|
198 |
+
if ($product->getId()) {
|
199 |
+
try {
|
200 |
+
// Save product into quote
|
201 |
+
$rowTotal = 0.00;
|
202 |
+
$order_item = Mage::getModel('sales/quote_item')
|
203 |
+
->setStoreId($this->_store_id)
|
204 |
+
->setQuoteId($quote->getId())
|
205 |
+
->setProduct($product)
|
206 |
+
->setQty(1)
|
207 |
+
->setPrice(0)
|
208 |
+
->setBasePrice(0)
|
209 |
+
->setCustomPrice(0)
|
210 |
+
->setOriginalCustomPrice(0)
|
211 |
+
->setRowTotal($rowTotal)
|
212 |
+
->setBaseRowTotal($rowTotal)
|
213 |
+
->setRowTotalWithDiscount($rowTotal)
|
214 |
+
->setRowTotalInclTax($rowTotal)
|
215 |
+
->setBaseRowTotalInclTax($rowTotal)
|
216 |
+
->setQuote($quote);
|
217 |
+
$order_item->save();
|
218 |
+
Mage::log('Product successfully added to quote', null, 'maxicycle.log');
|
219 |
+
} catch (Exception $e) {
|
220 |
+
Mage::log('Adding product to quote failed: ' .$e->getMessage(), null, 'maxicycle.log');
|
221 |
+
throw $e;
|
222 |
+
}
|
223 |
+
return true;
|
224 |
+
}
|
225 |
+
}
|
226 |
+
|
227 |
+
// returns sha1 for email
|
228 |
+
private function customerId($email) {
|
229 |
+
return sha1($email);
|
230 |
+
}
|
231 |
+
|
232 |
+
// get customer id and set it to order
|
233 |
+
private function _setCustomerIdToOrder() {
|
234 |
+
$order = $this->_quote_or_order;
|
235 |
+
$campaign = $this->_campaign;
|
236 |
+
// Customer email
|
237 |
+
$customer_email = $order->getCustomerEmail();
|
238 |
+
|
239 |
+
//Check if order exist with same customer email and already with Maxicycle Customer ID
|
240 |
+
$maxicycle_customer_id_exist = $this->_db->fetchAll("SELECT maxicycle_customer_id FROM "
|
241 |
+
. $this->_dbResource->getTableName('sales/order')
|
242 |
+
. " WHERE customer_email = '$customer_email' AND store_id = "
|
243 |
+
. $campaign['store_id'] . " AND maxicycle_customer_id IS NOT NULL LIMIT 1");
|
244 |
+
|
245 |
+
$maxicycle_customer_id = 0;
|
246 |
+
|
247 |
+
// If not then assign maxicycle customer as order entity ID is, if yes then use maxicycle_customer_id from the past
|
248 |
+
if (count($maxicycle_customer_id_exist) > 0) {
|
249 |
+
$maxicycle_customer_id = intval($maxicycle_customer_id_exist[0]['maxicycle_customer_id']);
|
250 |
+
Mage::log('existing customer id found: ' . $maxicycle_customer_id, null, 'maxicycle.log');
|
251 |
+
} else {
|
252 |
+
$maxicycle_customer_id = $order->getEntityId();
|
253 |
+
Mage::log('new customer id: ' . $maxicycle_customer_id, null, 'maxicycle.log');
|
254 |
+
}
|
255 |
+
$order->setMaxicycleCustomerId($maxicycle_customer_id);
|
256 |
+
|
257 |
+
return $maxicycle_customer_id;
|
258 |
+
}
|
259 |
+
|
260 |
+
// This method gets the campaign skus and loops through the array and randomly chooses the SKU
|
261 |
+
//
|
262 |
+
// Array(
|
263 |
+
// [0] => voucher:30
|
264 |
+
// [1] => gimmik:50
|
265 |
+
// [2] => treat:20)
|
266 |
+
// For backwards compatibility the entry can look also like
|
267 |
+
// [0] => voucher
|
268 |
+
private function pickProduct() {
|
269 |
+
$campaign = $this->_campaign;
|
270 |
+
$skus = explode(';', $campaign['product_sku']);
|
271 |
+
// product_sku 'sku1:30;sku2:40;sku3:30'
|
272 |
+
// $skus == ['sku1:30', 'sku2:40', 'sku3:30']
|
273 |
+
// Generate random number
|
274 |
+
$random_number = rand(0, 100);
|
275 |
+
$percentage_section = 0;
|
276 |
+
$sku = NULL;
|
277 |
+
//Mage::log('Picking product: random number ' .$random_number, null, 'maxicycle.log');
|
278 |
+
foreach($skus as $sku_percentage) {
|
279 |
+
$sku_p_ary = explode(':', $sku_percentage);
|
280 |
+
// check if ary is a single SKU
|
281 |
+
if (count($sku_p_ary) == 1) {
|
282 |
+
Mage::log('Single SKU', null, 'maxicycle.log');
|
283 |
+
$sku = $sku_p_ary[0]; // single sku like 'voucher', no percentage, return SKU straight away
|
284 |
+
} else {
|
285 |
+
// split test, multiple
|
286 |
+
list($chosen, $percentage) = $sku_p_ary;
|
287 |
+
$percentage_section += intval($percentage);
|
288 |
+
if ($random_number <= $percentage_section) {
|
289 |
+
Mage::log('Picking product: in percentile ' .$percentage_section, null, 'maxicycle.log');
|
290 |
+
$sku = $chosen;
|
291 |
+
$this->_quote_or_order->setMaxicycleSku($sku);
|
292 |
+
break;
|
293 |
+
} else {
|
294 |
+
Mage::log('Picking product: not in percentile ' .$percentage_section, null, 'maxicycle.log');
|
295 |
+
}
|
296 |
+
}
|
297 |
+
}
|
298 |
+
$product = Mage::getModel('catalog/product')->loadByAttribute('sku', $sku);
|
299 |
+
if (!$product) { Mage::log('WARNING: Product ' . $sku . ' not found for control order', null, 'maxicycle.log');}
|
300 |
+
return $product;
|
301 |
+
}
|
302 |
+
|
303 |
+
// Collect all skus in an array, skus is an array like below
|
304 |
+
//
|
305 |
+
// Array(
|
306 |
+
// [0] => voucher:30
|
307 |
+
// [1] => gimmik:50
|
308 |
+
// [2] => treat:20)
|
309 |
+
// For backwards compatibility the entry can look also like
|
310 |
+
// [0] => voucher
|
311 |
+
private function getSkus($sku_array) {
|
312 |
+
$skus = array();
|
313 |
+
foreach($sku_array as $sku_percentage) {
|
314 |
+
$sku_p_ary = explode(':', $sku_percentage);
|
315 |
+
$skus[] = $sku_p_ary[0];
|
316 |
+
}
|
317 |
+
Mage::log('Campaign skus: ' . join(', ', $skus), null, 'maxicycle.log');
|
318 |
+
return $skus;
|
319 |
+
}
|
320 |
+
|
321 |
+
// gets the treatment group size out of the condition coloumn
|
322 |
+
private function _getTreatmentGroupSize() {
|
323 |
+
// condition = treatment_group_size:90
|
324 |
+
$condition = explode(":", $this->_campaign['condition']);
|
325 |
+
return $condition[1];
|
326 |
+
}
|
327 |
+
|
328 |
+
// get all active campaigns running or in response time
|
329 |
+
private function _getActiveCampaigns() {
|
330 |
+
$camps = $this->_db->fetchAll("SELECT * FROM " . $this->_dbResource->getTableName('maxicycle/campaigns')
|
331 |
+
. " WHERE campaign_start <= '$this->_now' AND response_time_end >= '$this->_now' AND store_id = " . $this->_store_id);
|
332 |
+
return $camps;
|
333 |
+
}
|
334 |
+
|
335 |
+
// check if campaign is in response period
|
336 |
+
private function _inResponsePeriod($campaign) {
|
337 |
+
$campaign_time_end = strtotime($campaign['campaign_end']);
|
338 |
+
return ($campaign_time_end <= time());
|
339 |
+
}
|
340 |
+
|
341 |
+
// Generates random number and checks if treatment or not
|
342 |
+
private function _isTreatment() {
|
343 |
+
// check if order type was already set
|
344 |
+
// for order we need to check against quote
|
345 |
+
if ($this->_isOrder()) {
|
346 |
+
$orderType = $this->_alreadyMaxicycleOrder($this->_quote_or_order);
|
347 |
+
}
|
348 |
+
// for quote we simply check if set or not
|
349 |
+
else {
|
350 |
+
$orderType = $this->_quote_or_order->getMaxicycleOrderType();
|
351 |
+
}
|
352 |
+
|
353 |
+
if (isset($orderType)) {
|
354 |
+
Mage::log('OrderType was already set! OrderType: ' . $orderType, null, 'maxicycle.log');
|
355 |
+
return $orderType == 'treatment';
|
356 |
+
}
|
357 |
+
// calculate if treatment or control
|
358 |
+
$treatment_group_size = $this->_getTreatmentGroupSize();
|
359 |
+
return (rand(0, 100) <= $treatment_group_size ? true : false);
|
360 |
+
}
|
361 |
+
|
362 |
+
// Check if we insert for Order or Quote
|
363 |
+
private function _isOrder() {
|
364 |
+
return get_class($this->_quote_or_order) == 'Mage_Sales_Model_Order';
|
365 |
+
}
|
366 |
+
|
367 |
+
}
|
app/code/community/Maxicycle/Connector/Model/Observer.php
CHANGED
@@ -24,92 +24,63 @@ class Maxicycle_Connector_Model_Observer{
|
|
24 |
$this->_config = Mage::helper('maxicycle')->getConfiguration($store_id);
|
25 |
}
|
26 |
|
27 |
-
// get all active campaigns running or in response time
|
28 |
-
private function getActiveCampaigns() {
|
29 |
-
return $this->_db->fetchAll("SELECT * FROM " . $this->_dbResource->getTableName('maxicycle/campaigns') . " WHERE campaign_start <= '$this->_now' AND response_time_end >= '$this->_now' AND store_id = " . Mage::app()->getStore()->getId());
|
30 |
-
}
|
31 |
-
|
32 |
// manually triggered event for quote
|
33 |
public function maxicycle_add_product_to_quote_hook($observer) {
|
34 |
-
Mage::log('Event hook maxicycle_add_product_to_quote', null, 'maxicycle.log');
|
35 |
try {
|
36 |
$quote = $observer->getQuote();
|
37 |
$this->add_product_to_quote($quote);
|
38 |
}
|
39 |
catch(Exception $e) {
|
40 |
-
Mage::log('QUOTE: maxicycle_add_product_to_quote hook failed: ' .$e->getMessage(), null, 'maxicycle.log');
|
41 |
}
|
42 |
}
|
43 |
|
44 |
// triggered by event observer
|
45 |
public function one_page_checkout_hook($observer) {
|
46 |
-
Mage::log('
|
47 |
try {
|
48 |
$quote = $this->getQuote();
|
49 |
$this->add_product_to_quote($quote);
|
50 |
}
|
51 |
catch(Exception $e) {
|
52 |
Mage::log('QUOTE: one_page_checkout hook failed: ' .$e->getMessage(), null, 'maxicycle.log');
|
53 |
-
}
|
|
|
54 |
}
|
55 |
|
56 |
// will add product to quote table to have product ready for payment methods
|
57 |
// like Klarna which sends the cart items before the actual order creation
|
58 |
-
public function add_product_to_quote($quote) {
|
59 |
try {
|
60 |
-
$
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
Mage::log('QUOTE: active campaigns, checking for product to add', null, 'maxicycle.log');
|
67 |
-
// Loop over active campaings
|
68 |
-
foreach ($active_campaigns as $campaign) {
|
69 |
-
// add product to Quote
|
70 |
-
$this->_addProductToCart($quote, $campaign);
|
71 |
-
$quote->setMaxicycleCampaignId($campaign['campaign_id']);
|
72 |
-
}
|
73 |
-
} else {
|
74 |
-
Mage::log('QUOTE: No active campaigns, not adding a product', null, 'maxicycle.log');
|
75 |
-
}
|
76 |
} else {
|
77 |
-
Mage::log('
|
78 |
}
|
79 |
}
|
80 |
catch(Exception $e) {
|
81 |
-
Mage::log('
|
82 |
}
|
83 |
}
|
84 |
|
85 |
-
|
86 |
// add PRODUCT after order placement
|
87 |
// This needs to run for all payment methods that skip the checkout like
|
88 |
// Paypal express
|
89 |
public function add_product_to_order($observer) {
|
90 |
-
Mage::log('
|
91 |
try {
|
92 |
$order = $observer->getOrder();
|
93 |
-
$
|
|
|
|
|
|
|
94 |
if ($this->moduleEnabled()) {
|
95 |
-
|
96 |
-
$active_campaigns = $this->getActiveCampaigns();
|
97 |
-
// If there is some active campaign
|
98 |
-
if (count($active_campaigns) > 0) {
|
99 |
-
Mage::log('ORDER: active campaigns, checking for product to add', null, 'maxicycle.log');
|
100 |
-
// Loop over active campaings
|
101 |
-
foreach ($active_campaigns as $campaign) {
|
102 |
-
// add product to Order
|
103 |
-
$this->_addProductToOrder($order, $campaign);
|
104 |
-
// Set campaign_id to order
|
105 |
-
$order->setMaxicycleCampaignId($campaign['campaign_id']);
|
106 |
-
$maxicycle_customer_id = $this->setCustomerIdToOrder($order, $campaign);
|
107 |
-
// check and mark if order is response order
|
108 |
-
$this->checkIfResponseOrder($order, $maxicycle_customer_id, $campaign);
|
109 |
-
}
|
110 |
-
} else {
|
111 |
-
Mage::log('No active campaigns, not adding a product', null, 'maxicycle.log');
|
112 |
-
}
|
113 |
} else {
|
114 |
Mage::log('module disabled', null, 'maxicycle.log');
|
115 |
}
|
@@ -117,6 +88,7 @@ class Maxicycle_Connector_Model_Observer{
|
|
117 |
catch(Exception $e) {
|
118 |
Mage::log('Order Place After Exception: ' .$e->getMessage(), null, 'maxicycle.log');
|
119 |
}
|
|
|
120 |
}
|
121 |
|
122 |
|
@@ -125,53 +97,42 @@ class Maxicycle_Connector_Model_Observer{
|
|
125 |
try {
|
126 |
$order = $observer->getOrder();
|
127 |
$this->setConfig($order->getStoreId());
|
128 |
-
Mage::log('after save hook for order:' . $order->getEntityId(), null, 'maxicycle.log');
|
129 |
//Mage::log(json_encode($this->_config), null, 'maxicycle.log');
|
130 |
//Mage::log($this->_config['valid_statuses'], null, 'maxicycle.log');
|
131 |
// Check if Maxicycle is active and a valid status
|
132 |
if ($this->shouldExport($order)) {
|
133 |
-
Mage::log('valid status: ' . $order->getStatus(), null, 'maxicycle.log');
|
134 |
// Load order info
|
135 |
-
Mage::log('Order ID ' . $order->getEntityId(), null, 'maxicycle.log');
|
136 |
-
Mage::log('valid status: ' . $order->getStatus(), null, 'maxicycle.log');
|
137 |
// Get all active campaigns
|
138 |
-
// Mage::log('Current Store ' . $order->getStoreId(), null, 'maxicycle.log');
|
139 |
// TODO: refactor this, order has campaign id already
|
140 |
$active_campaigns = $this->_db->fetchAll("SELECT * FROM " . $this->_dbResource->getTableName('maxicycle/campaigns') .
|
141 |
" WHERE campaign_start <= '$this->_now' AND response_time_end >= '$this->_now' AND store_id = " . $order->getStoreId());
|
142 |
// If there are some active campaigns
|
143 |
if (count($active_campaigns) > 0) {
|
144 |
-
Mage::log('active campaigns', null, 'maxicycle.log');
|
145 |
// Loop over active campaings
|
146 |
foreach ($active_campaigns as $campaign) {
|
147 |
$this->exportToResults($order, $campaign);
|
148 |
}
|
149 |
} else {
|
150 |
-
Mage::log('No active campaigns', null, 'maxicycle.log');
|
151 |
}
|
152 |
} else {
|
153 |
# do nothing
|
154 |
-
Mage::log('module disabled or invalid status', null, 'maxicycle.log');
|
155 |
}
|
156 |
}
|
157 |
catch(Exception $e) {
|
158 |
-
Mage::log('Order Save After Exception: ' .$e->getMessage(), null, 'maxicycle.log');
|
159 |
}
|
160 |
}
|
161 |
|
162 |
-
private function _isTreatment($treatment_size) {
|
163 |
-
// Generate random number
|
164 |
-
$random_number = rand(0, 100);
|
165 |
-
// Log random number for overview
|
166 |
-
if ($random_number <= $treatment_size) {
|
167 |
-
return true;
|
168 |
-
} else {
|
169 |
-
return false;
|
170 |
-
}
|
171 |
-
}
|
172 |
-
|
173 |
private function exportToResults($order, $campaign) {
|
174 |
-
Mage::log('Starting Export', null, 'maxicycle.log');
|
175 |
$order_id = $order->getIncrementId();
|
176 |
// check if already exported
|
177 |
$previous_order_exists = $this->_db->fetchAll("SELECT order_id FROM " .
|
@@ -180,15 +141,25 @@ class Maxicycle_Connector_Model_Observer{
|
|
180 |
" AND order_id = ". $order_id ." LIMIT 1");
|
181 |
|
182 |
if (count($previous_order_exists) == 1) {
|
183 |
-
Mage::log('Order already exported: ' . $order->getIncrementId(), null, 'maxicycle.log');
|
184 |
} else {
|
185 |
|
186 |
-
Mage::log('exporting status: ' . $order->getStatus(), null, 'maxicycle.log');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
187 |
|
188 |
-
//
|
|
|
189 |
$maxicycle_customer_id = $order->getMaxicycleCustomerId();
|
190 |
-
|
191 |
-
|
192 |
// calculate gross profit
|
193 |
$gross_profit = $this->calculateGrossProfit($order);
|
194 |
|
@@ -202,43 +173,21 @@ class Maxicycle_Connector_Model_Observer{
|
|
202 |
'order_profit' => $gross_profit,
|
203 |
'last_order_update_date' => $order->getCreatedAt(),
|
204 |
'export_flag' => 0,
|
205 |
-
'campaign_order_type' => $
|
206 |
-
'response_to_order_id' => $
|
|
|
207 |
);
|
208 |
|
209 |
// Save order data into Maxicycle orders table
|
210 |
try {
|
211 |
$result = Mage::getModel('maxicycle/results')->setData($data)->save();
|
212 |
-
Mage::log('Result: ' . $result->getId(), null, 'maxicycle.log');
|
213 |
} catch (Exception $e) {
|
214 |
-
Mage::log('ERROR: ' . $e->getMessage(), null, 'maxicycle.log');
|
215 |
}
|
216 |
}
|
217 |
}
|
218 |
|
219 |
-
private function setCustomerIdToOrder($order, $campaign) {
|
220 |
-
// Customer email
|
221 |
-
$customer_email = $order->getCustomerEmail();
|
222 |
-
// Check if order exist with same customer email and already with Maxicycle Customer ID
|
223 |
-
$maxicycle_customer_id_exist = $this->_db->fetchAll("SELECT maxicycle_customer_id FROM "
|
224 |
-
. $this->_dbResource->getTableName('sales/order')
|
225 |
-
. " WHERE customer_email = '$customer_email' AND store_id = "
|
226 |
-
. $campaign['store_id'] . " AND maxicycle_customer_id IS NOT NULL LIMIT 1");
|
227 |
-
|
228 |
-
$maxicycle_customer_id = 0;
|
229 |
-
|
230 |
-
// If not then assign maxicycle customer as order entity ID is, if yes then use maxicycle_customer_id from the past
|
231 |
-
if (count($maxicycle_customer_id_exist) > 0) {
|
232 |
-
$maxicycle_customer_id = intval($maxicycle_customer_id_exist[0]['maxicycle_customer_id']);
|
233 |
-
Mage::log('existing customer id found: ' . $maxicycle_customer_id, null, 'maxicycle.log');
|
234 |
-
} else {
|
235 |
-
$maxicycle_customer_id = $order->getEntityId();
|
236 |
-
Mage::log('new customer id: ' . $maxicycle_customer_id, null, 'maxicycle.log');
|
237 |
-
}
|
238 |
-
$order->setMaxicycleCustomerId($maxicycle_customer_id);
|
239 |
-
return $maxicycle_customer_id;
|
240 |
-
}
|
241 |
-
|
242 |
private function calculateGrossProfit($order) {
|
243 |
|
244 |
// Recount gross_profit according to module configuration
|
@@ -262,21 +211,21 @@ class Maxicycle_Connector_Model_Observer{
|
|
262 |
if ($product_costs_type == '1') {
|
263 |
// get product price from specified attribute
|
264 |
$bp = floatval($product->getData($product_costs_attribute));
|
265 |
-
// Mage::log('Gross profit: attribute', null, 'maxicycle.log');
|
266 |
if ($bp != 0) {
|
267 |
-
// Mage::log('Gross profit: attribute value: ' . $bp, null, 'maxicycle.log');
|
268 |
$item_costs += ($item_quantity * $bp);
|
269 |
} else {
|
270 |
-
// Mage::log('Gross profit: attribute value empty ' . $bp, null, 'maxicycle.log');
|
271 |
$item_costs += ($item_quantity * $item_price);
|
272 |
}
|
273 |
} else {
|
274 |
-
// Mage::log('Gross profit: fixed product price - percentage', null, 'maxicycle.log');
|
275 |
if (floatval($product_costs_fixed) != 0) {
|
276 |
// deduct percentage
|
277 |
$fixed_percentage = floatval($product_costs_fixed) / 100.00;
|
278 |
$item_costs += ($item_quantity * $item_price * $fixed_percentage);
|
279 |
-
// Mage::log('Gross profit: item costs ' . $item_costs, null, 'maxicycle.log');
|
280 |
} else {
|
281 |
$item_costs += ($item_quantity * $item_price);
|
282 |
}
|
@@ -285,10 +234,10 @@ class Maxicycle_Connector_Model_Observer{
|
|
285 |
|
286 |
// deduct specified average order costs
|
287 |
$gross_profit = ($grand_total - floatval($avg_order_costs));
|
288 |
-
Mage::log('Gross profit: Grand total - avg order costs' . $gross_profit, null, 'maxicycle.log');
|
289 |
// deduct tax
|
290 |
if ($use_tax) {
|
291 |
-
Mage::log('Gross profit, deducting tax', null, 'maxicycle.log');
|
292 |
$gross_profit -= floatval($order->getTaxAmount());
|
293 |
}
|
294 |
// deduct order item costs
|
@@ -296,127 +245,22 @@ class Maxicycle_Connector_Model_Observer{
|
|
296 |
return $gross_profit;
|
297 |
}
|
298 |
|
299 |
-
private function _alreadyMaxicycleOrder($order) {
|
300 |
-
Mage::log('Check if quote is already maxicycle order', null, 'maxicycle.log');
|
301 |
-
$quote_id = $order->getQuoteId();
|
302 |
-
$quote = Mage::getModel('sales/quote')->load($quote_id);
|
303 |
-
$campaign_type_set = $this->hasCampaignOrderTypeSet($quote);
|
304 |
-
// copy values
|
305 |
-
if ($campaign_type_set) {
|
306 |
-
$order->setMaxicycleOrderType($quote->getMaxicycleOrderType());
|
307 |
-
$order->setMaxicycleCampaignId($quote->getMaxicycleCampaignId());
|
308 |
-
}
|
309 |
-
return $campaign_type_set;
|
310 |
-
}
|
311 |
-
|
312 |
-
private function _addProductToOrder($order, $campaign) {
|
313 |
-
Mage::log('Place order -> check adding order', null, 'maxicycle.log');
|
314 |
-
// exit if product was already added in quote
|
315 |
-
$already_added = $this->_alreadyMaxicycleOrder($order);
|
316 |
-
if ($already_added) {
|
317 |
-
Mage::log('Product was already added to order', null, 'maxicycle.log');
|
318 |
-
} else {
|
319 |
-
// Process condition - ADD PRODUCT - only if campaign is still in CP and not already in RT
|
320 |
-
if ($this->_campaignActive($campaign)) {
|
321 |
-
// conditiond = treatment_group_size:90
|
322 |
-
$condition = explode(":", $campaign['condition']);
|
323 |
-
// Get code and value of condition
|
324 |
-
$treatment_group_size = $condition[1];
|
325 |
-
// Test condition
|
326 |
-
// if treatment condition true -> insert SKU
|
327 |
-
if ($this->_isTreatment($treatment_group_size)) {
|
328 |
-
Mage::log('Product was NOT already added to order', null, 'maxicycle.log');
|
329 |
-
$this->addOrderItem($order, $campaign);
|
330 |
-
// Set it into order
|
331 |
-
$order->setMaxicycleOrderType('treatment');
|
332 |
-
Mage::log('OrderType: treatment', null, 'maxicycle.log');
|
333 |
-
} else {
|
334 |
-
// Set it into order to be used when exporting the results
|
335 |
-
$order->setMaxicycleOrderType('control');
|
336 |
-
Mage::log('OrderType: control', null, 'maxicycle.log');
|
337 |
-
}
|
338 |
-
|
339 |
-
} else {
|
340 |
-
Mage::log('Not adding product, campaign in response period', null, 'maxicycle.log');
|
341 |
-
}
|
342 |
-
}
|
343 |
-
}
|
344 |
-
|
345 |
-
private function checkIfSKUAlreadyAdded($items, $sku) {
|
346 |
-
$added = FALSE;
|
347 |
-
Foreach($items as $item){
|
348 |
-
if ($sku == $item->getSku()) {
|
349 |
-
$added = TRUE;
|
350 |
-
}
|
351 |
-
}
|
352 |
-
return $added;
|
353 |
-
}
|
354 |
-
|
355 |
-
// create and order item to product
|
356 |
-
private function addOrderItem($order, $campaign) {
|
357 |
-
Mage::log('Adding product to order', null, 'maxicycle.log');
|
358 |
-
$product = Mage::getModel('catalog/product')->loadByAttribute('sku', $campaign['product_sku']);
|
359 |
-
if ($product) {
|
360 |
-
// Save product into order
|
361 |
-
$rowTotal = 0.00;
|
362 |
-
$order_item = Mage::getModel('sales/order_item')
|
363 |
-
->setStoreId($order->getStore()->getStoreId())
|
364 |
-
->setQuoteItemId(null)
|
365 |
-
->setQuoteParentItemId(null)
|
366 |
-
->setProductId($product->getId())
|
367 |
-
->setProductType($product->getTypeId())
|
368 |
-
->setQtyBackordered(null)
|
369 |
-
->setTotalQtyOrdered(1)
|
370 |
-
->setQtyOrdered(1)
|
371 |
-
->setName($product->getName())
|
372 |
-
->setSku($product->getSku())
|
373 |
-
->setPrice(0)
|
374 |
-
->setBasePrice(0)
|
375 |
-
->setOriginalPrice(0)
|
376 |
-
->setRowTotal($rowTotal)
|
377 |
-
->setBaseRowTotal($rowTotal)
|
378 |
-
->setOrder($order);
|
379 |
-
$order_item->save();
|
380 |
-
} else {
|
381 |
-
Mage::log('WARNING: Product ' . $campaign['product_sku'] . ' not found for control order', null, 'maxicycle.log');
|
382 |
-
}
|
383 |
-
}
|
384 |
-
|
385 |
-
private function checkIfResponseOrder($order, $maxicycle_customer_id, $campaign) {
|
386 |
-
Mage::log('campaign: ' . $campaign['campaign_id'], null, 'maxicycle.log');
|
387 |
-
Mage::log('customer id: ' . $maxicycle_customer_id, null, 'maxicycle.log');
|
388 |
-
$response_to_order_id = NULL;
|
389 |
-
// Identify if it is response order
|
390 |
-
$previous_order_exists = $this->_db->fetchAll("SELECT order_id FROM " . $this->_dbResource->getTableName('maxicycle/results') .
|
391 |
-
" WHERE campaign_id = " . $campaign['campaign_id'] .
|
392 |
-
" AND maxicycle_customer_id = $maxicycle_customer_id AND campaign_order_type IS NOT NULL ORDER BY created_at DESC LIMIT 1");
|
393 |
-
if (count($previous_order_exists) == 1) {
|
394 |
-
Mage::log('response order', null, 'maxicycle.log');
|
395 |
-
$response_to_order_id = $previous_order_exists[0]['order_id'];
|
396 |
-
// Set it into order
|
397 |
-
$order->setMaxicycleResponseToOrderId($response_to_order_id);
|
398 |
-
}
|
399 |
-
return $response_to_order_id;
|
400 |
-
}
|
401 |
-
|
402 |
private function shouldExport($order) {
|
403 |
-
$this->
|
404 |
-
return $this->moduleEnabled() && $this->validStatus($order) && $this->hasCampaignOrderTypeSet($order);
|
405 |
}
|
406 |
|
407 |
// requires config to be set
|
408 |
private function validStatus($order) {
|
409 |
$status = $order->getStatus();
|
410 |
-
Mage::log('order status: ' . $status, null, 'maxicycle.log');
|
411 |
$valid_status = in_array($order->getStatus(), $this->_config['valid_statuses']);
|
412 |
-
Mage::log('has valid status: ' . $valid_status, null, 'maxicycle.log');
|
413 |
return $valid_status;
|
414 |
}
|
415 |
|
416 |
// requires _config to be set
|
417 |
private function moduleEnabled() {
|
418 |
$enabled = intval($this->_config['is_enable']);
|
419 |
-
Mage::log('Module enabled true/false: ' . $enabled, null, 'maxicycle.log');
|
420 |
return $enabled;
|
421 |
}
|
422 |
|
@@ -424,99 +268,50 @@ class Maxicycle_Connector_Model_Observer{
|
|
424 |
// checks if product should be added during checkout
|
425 |
private function checkoutEnabled() {
|
426 |
$enabled = intval($this->_config['add_during_checkout']);
|
427 |
-
Mage::log('Checkout enabled true/false: ' . $enabled, null, 'maxicycle.log');
|
428 |
return $enabled;
|
429 |
}
|
430 |
|
431 |
-
// should have type set - fixes bug when exported before order_place_after_ran
|
432 |
-
private function hasCampaignOrderTypeSet($quote) {
|
433 |
-
$order_type = $quote->getMaxicycleOrderType();
|
434 |
-
$has_type_set = isset($order_type);
|
435 |
-
Mage::log('Campaign order type is set true/false: ' . $has_type_set, null, 'maxicycle.log');
|
436 |
-
return $has_type_set;
|
437 |
-
}
|
438 |
-
|
439 |
-
private function _campaignActive($campaign) {
|
440 |
-
$campaign_time_end = strtotime($campaign['campaign_end']);
|
441 |
-
// condition is treatment group size > 0
|
442 |
-
return ($campaign_time_end >= time());
|
443 |
-
}
|
444 |
-
|
445 |
-
protected function _addProductToCart($quote, $campaign) {
|
446 |
-
Mage::log('Checkout: adding order', null, 'maxicycle.log');
|
447 |
-
$product = Mage::getModel('catalog/product')->loadByAttribute('sku', $campaign['product_sku']);
|
448 |
-
// Process condition - ADD PRODUCT - only if campaign is still in CP and not already in RT
|
449 |
-
if ($this->_campaignActive($campaign)) {
|
450 |
-
// conditiond = treatment_group_size:90
|
451 |
-
$condition = explode(":", $campaign['condition']);
|
452 |
-
// Get code and value of condition
|
453 |
-
$treatment_group_size = $condition[1];
|
454 |
-
// Test condition
|
455 |
-
// if treatment condition true -> insert SKU
|
456 |
-
if ($this->_isTreatment($treatment_group_size)) {
|
457 |
-
// exit if product was already added in quote
|
458 |
-
$already_added = $this->checkIfSKUAlreadyAdded($quote->getAllItems(), $campaign['product_sku']);
|
459 |
-
if ($already_added) {
|
460 |
-
Mage::log('Product was already added to order', null, 'maxicycle.log');
|
461 |
-
} else {
|
462 |
-
Mage::log('Product was NOT already added to order', null, 'maxicycle.log');
|
463 |
-
$this->_addQuoteItem($product, $quote);
|
464 |
-
}
|
465 |
-
// Set it into order
|
466 |
-
$quote->setMaxicycleOrderType('treatment');
|
467 |
-
Mage::log('OrderType: treatment', null, 'maxicycle.log');
|
468 |
-
} else {
|
469 |
-
// Set it into order to be used when exporting the results
|
470 |
-
$quote->setMaxicycleOrderType('control');
|
471 |
-
Mage::log('OrderType: control', null, 'maxicycle.log');
|
472 |
-
}
|
473 |
-
|
474 |
-
} else {
|
475 |
-
Mage::log('Not adding product, campaign in response period', null, 'maxicycle.log');
|
476 |
-
}
|
477 |
-
|
478 |
-
}
|
479 |
-
|
480 |
-
protected function _addQuoteItem($product, $quote) {
|
481 |
-
if ($product->getId()) {
|
482 |
-
try {
|
483 |
-
// Save product into quote
|
484 |
-
$rowTotal = 0.00;
|
485 |
-
$order_item = Mage::getModel('sales/quote_item')
|
486 |
-
->setStoreId($quote->getStore()->getStoreId())
|
487 |
-
->setQuoteId($quote->getId())
|
488 |
-
->setProduct($product)
|
489 |
-
->setQty(1)
|
490 |
-
->setPrice(0)
|
491 |
-
->setBasePrice(0)
|
492 |
-
->setCustomPrice(0)
|
493 |
-
->setOriginalCustomPrice(0)
|
494 |
-
->setRowTotal($rowTotal)
|
495 |
-
->setBaseRowTotal($rowTotal)
|
496 |
-
->setRowTotalWithDiscount($rowTotal)
|
497 |
-
->setRowTotalInclTax($rowTotal)
|
498 |
-
->setBaseRowTotalInclTax($rowTotal)
|
499 |
-
->setQuote($quote);
|
500 |
-
$order_item->save();
|
501 |
-
Mage::log('Saving product to quote', null, 'maxicycle.log');
|
502 |
-
|
503 |
-
} catch (Exception $e) {
|
504 |
-
Mage::log('Adding product to quote failed: ' .$e->getMessage(), null, 'maxicycle.log');
|
505 |
-
throw $e;
|
506 |
-
}
|
507 |
-
return true;
|
508 |
-
}
|
509 |
-
}
|
510 |
-
|
511 |
// get checkout from controller
|
512 |
-
|
513 |
-
{
|
514 |
return Mage::getSingleton('checkout/session');
|
515 |
}
|
516 |
|
517 |
// get quote from checkout
|
518 |
-
|
519 |
-
{
|
520 |
return $this->getCheckout()->getQuote();
|
521 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
522 |
}
|
24 |
$this->_config = Mage::helper('maxicycle')->getConfiguration($store_id);
|
25 |
}
|
26 |
|
|
|
|
|
|
|
|
|
|
|
27 |
// manually triggered event for quote
|
28 |
public function maxicycle_add_product_to_quote_hook($observer) {
|
29 |
+
Mage::log('EXPORT: Event hook maxicycle_add_product_to_quote', null, 'maxicycle.log');
|
30 |
try {
|
31 |
$quote = $observer->getQuote();
|
32 |
$this->add_product_to_quote($quote);
|
33 |
}
|
34 |
catch(Exception $e) {
|
35 |
+
Mage::log('EXPORT: QUOTE: maxicycle_add_product_to_quote hook failed: ' .$e->getMessage(), null, 'maxicycle.log');
|
36 |
}
|
37 |
}
|
38 |
|
39 |
// triggered by event observer
|
40 |
public function one_page_checkout_hook($observer) {
|
41 |
+
Mage::log('### One page checkout start', null, 'maxicycle.log');
|
42 |
try {
|
43 |
$quote = $this->getQuote();
|
44 |
$this->add_product_to_quote($quote);
|
45 |
}
|
46 |
catch(Exception $e) {
|
47 |
Mage::log('QUOTE: one_page_checkout hook failed: ' .$e->getMessage(), null, 'maxicycle.log');
|
48 |
+
}
|
49 |
+
Mage::log('### One page checkout end', null, 'maxicycle.log');
|
50 |
}
|
51 |
|
52 |
// will add product to quote table to have product ready for payment methods
|
53 |
// like Klarna which sends the cart items before the actual order creation
|
54 |
+
public function add_product_to_quote($quote) {
|
55 |
try {
|
56 |
+
$store_id = $quote->getStoreId();
|
57 |
+
$maxicycle = Mage::getModel('maxicycle/insert', array('store_id' => $store_id, 'quote_or_order' => $quote, 'is_type' => 'quote'));
|
58 |
+
$this->setConfig($store_id);
|
59 |
+
|
60 |
+
if ($this->checkoutEnabled() && $this->moduleEnabled()) {
|
61 |
+
$maxicycle->addInsert();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
62 |
} else {
|
63 |
+
Mage::log('Checkout adding disabled', null, 'maxicycle.log');
|
64 |
}
|
65 |
}
|
66 |
catch(Exception $e) {
|
67 |
+
Mage::log('Adding product to quote failed: ' .$e->getMessage(), null, 'maxicycle.log');
|
68 |
}
|
69 |
}
|
70 |
|
|
|
71 |
// add PRODUCT after order placement
|
72 |
// This needs to run for all payment methods that skip the checkout like
|
73 |
// Paypal express
|
74 |
public function add_product_to_order($observer) {
|
75 |
+
Mage::log('### Order observer start', null, 'maxicycle.log');
|
76 |
try {
|
77 |
$order = $observer->getOrder();
|
78 |
+
$store_id = $order->getStoreId();
|
79 |
+
$this->setConfig($store_id);
|
80 |
+
$maxicycle = Mage::getModel('maxicycle/insert', array('store_id' => $store_id, 'quote_or_order' => $order, 'is_type' => 'order'));
|
81 |
+
|
82 |
if ($this->moduleEnabled()) {
|
83 |
+
$maxicycle->addInsert();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
84 |
} else {
|
85 |
Mage::log('module disabled', null, 'maxicycle.log');
|
86 |
}
|
88 |
catch(Exception $e) {
|
89 |
Mage::log('Order Place After Exception: ' .$e->getMessage(), null, 'maxicycle.log');
|
90 |
}
|
91 |
+
Mage::log('### Order observer end', null, 'maxicycle.log');
|
92 |
}
|
93 |
|
94 |
|
97 |
try {
|
98 |
$order = $observer->getOrder();
|
99 |
$this->setConfig($order->getStoreId());
|
100 |
+
Mage::log('EXPORT: after save hook for order:' . $order->getEntityId(), null, 'maxicycle.log');
|
101 |
//Mage::log(json_encode($this->_config), null, 'maxicycle.log');
|
102 |
//Mage::log($this->_config['valid_statuses'], null, 'maxicycle.log');
|
103 |
// Check if Maxicycle is active and a valid status
|
104 |
if ($this->shouldExport($order)) {
|
105 |
+
Mage::log('EXPORT: valid status: ' . $order->getStatus(), null, 'maxicycle.log');
|
106 |
// Load order info
|
107 |
+
Mage::log('EXPORT: Order ID ' . $order->getEntityId(), null, 'maxicycle.log');
|
108 |
+
Mage::log('EXPORT: valid status: ' . $order->getStatus(), null, 'maxicycle.log');
|
109 |
// Get all active campaigns
|
110 |
+
// Mage::log('EXPORT: Current Store ' . $order->getStoreId(), null, 'maxicycle.log');
|
111 |
// TODO: refactor this, order has campaign id already
|
112 |
$active_campaigns = $this->_db->fetchAll("SELECT * FROM " . $this->_dbResource->getTableName('maxicycle/campaigns') .
|
113 |
" WHERE campaign_start <= '$this->_now' AND response_time_end >= '$this->_now' AND store_id = " . $order->getStoreId());
|
114 |
// If there are some active campaigns
|
115 |
if (count($active_campaigns) > 0) {
|
116 |
+
Mage::log('EXPORT: active campaigns', null, 'maxicycle.log');
|
117 |
// Loop over active campaings
|
118 |
foreach ($active_campaigns as $campaign) {
|
119 |
$this->exportToResults($order, $campaign);
|
120 |
}
|
121 |
} else {
|
122 |
+
Mage::log('EXPORT: No active campaigns', null, 'maxicycle.log');
|
123 |
}
|
124 |
} else {
|
125 |
# do nothing
|
126 |
+
Mage::log('EXPORT: module disabled or invalid status', null, 'maxicycle.log');
|
127 |
}
|
128 |
}
|
129 |
catch(Exception $e) {
|
130 |
+
Mage::log('EXPORT: Order Save After Exception: ' .$e->getMessage(), null, 'maxicycle.log');
|
131 |
}
|
132 |
}
|
133 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
134 |
private function exportToResults($order, $campaign) {
|
135 |
+
Mage::log('EXPORT: Starting Export', null, 'maxicycle.log');
|
136 |
$order_id = $order->getIncrementId();
|
137 |
// check if already exported
|
138 |
$previous_order_exists = $this->_db->fetchAll("SELECT order_id FROM " .
|
141 |
" AND order_id = ". $order_id ." LIMIT 1");
|
142 |
|
143 |
if (count($previous_order_exists) == 1) {
|
144 |
+
Mage::log('EXPORT: Order already exported: ' . $order->getIncrementId(), null, 'maxicycle.log');
|
145 |
} else {
|
146 |
|
147 |
+
Mage::log('EXPORT: exporting status: ' . $order->getStatus(), null, 'maxicycle.log');
|
148 |
+
|
149 |
+
$response_to_order_id = $this->getResponseOrderId($order, $campaign);
|
150 |
+
|
151 |
+
// do not export orders that are in response period and are not a response to a previous order
|
152 |
+
if ($this->_inResponsePeriod($campaign) && is_null($response_to_order_id) ) {
|
153 |
+
Mage::log('EXPORT: not exporting, no response order id found', null, 'maxicycle.log');
|
154 |
+
return;
|
155 |
+
} else {
|
156 |
+
Mage::log('EXPORT: Response to order id: ' . $response_to_order_id, null, 'maxicycle.log');
|
157 |
+
}
|
158 |
|
159 |
+
// We query the results table for the customer id to check if it is a response order
|
160 |
+
// therefore we need to set it
|
161 |
$maxicycle_customer_id = $order->getMaxicycleCustomerId();
|
162 |
+
|
|
|
163 |
// calculate gross profit
|
164 |
$gross_profit = $this->calculateGrossProfit($order);
|
165 |
|
173 |
'order_profit' => $gross_profit,
|
174 |
'last_order_update_date' => $order->getCreatedAt(),
|
175 |
'export_flag' => 0,
|
176 |
+
'campaign_order_type' => $this->campaignOrderType($order, $campaign),
|
177 |
+
'response_to_order_id' => $response_to_order_id,
|
178 |
+
'sku' => $this->sku($order, $campaign)
|
179 |
);
|
180 |
|
181 |
// Save order data into Maxicycle orders table
|
182 |
try {
|
183 |
$result = Mage::getModel('maxicycle/results')->setData($data)->save();
|
184 |
+
Mage::log('EXPORT: Result: ' . $result->getId(), null, 'maxicycle.log');
|
185 |
} catch (Exception $e) {
|
186 |
+
Mage::log('EXPORT: ERROR: ' . $e->getMessage(), null, 'maxicycle.log');
|
187 |
}
|
188 |
}
|
189 |
}
|
190 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
191 |
private function calculateGrossProfit($order) {
|
192 |
|
193 |
// Recount gross_profit according to module configuration
|
211 |
if ($product_costs_type == '1') {
|
212 |
// get product price from specified attribute
|
213 |
$bp = floatval($product->getData($product_costs_attribute));
|
214 |
+
// Mage::log('EXPORT: Gross profit: attribute', null, 'maxicycle.log');
|
215 |
if ($bp != 0) {
|
216 |
+
// Mage::log('EXPORT: Gross profit: attribute value: ' . $bp, null, 'maxicycle.log');
|
217 |
$item_costs += ($item_quantity * $bp);
|
218 |
} else {
|
219 |
+
// Mage::log('EXPORT: Gross profit: attribute value empty ' . $bp, null, 'maxicycle.log');
|
220 |
$item_costs += ($item_quantity * $item_price);
|
221 |
}
|
222 |
} else {
|
223 |
+
// Mage::log('EXPORT: Gross profit: fixed product price - percentage', null, 'maxicycle.log');
|
224 |
if (floatval($product_costs_fixed) != 0) {
|
225 |
// deduct percentage
|
226 |
$fixed_percentage = floatval($product_costs_fixed) / 100.00;
|
227 |
$item_costs += ($item_quantity * $item_price * $fixed_percentage);
|
228 |
+
// Mage::log('EXPORT: Gross profit: item costs ' . $item_costs, null, 'maxicycle.log');
|
229 |
} else {
|
230 |
$item_costs += ($item_quantity * $item_price);
|
231 |
}
|
234 |
|
235 |
// deduct specified average order costs
|
236 |
$gross_profit = ($grand_total - floatval($avg_order_costs));
|
237 |
+
//Mage::log('EXPORT: Gross profit: Grand total - avg order costs' . $gross_profit, null, 'maxicycle.log');
|
238 |
// deduct tax
|
239 |
if ($use_tax) {
|
240 |
+
Mage::log('EXPORT: Gross profit, deducting tax', null, 'maxicycle.log');
|
241 |
$gross_profit -= floatval($order->getTaxAmount());
|
242 |
}
|
243 |
// deduct order item costs
|
245 |
return $gross_profit;
|
246 |
}
|
247 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
248 |
private function shouldExport($order) {
|
249 |
+
return $this->moduleEnabled() && $this->validStatus($order);
|
|
|
250 |
}
|
251 |
|
252 |
// requires config to be set
|
253 |
private function validStatus($order) {
|
254 |
$status = $order->getStatus();
|
255 |
+
Mage::log('EXPORT: order status: ' . $status, null, 'maxicycle.log');
|
256 |
$valid_status = in_array($order->getStatus(), $this->_config['valid_statuses']);
|
257 |
+
Mage::log('EXPORT: has valid status: ' . $valid_status, null, 'maxicycle.log');
|
258 |
return $valid_status;
|
259 |
}
|
260 |
|
261 |
// requires _config to be set
|
262 |
private function moduleEnabled() {
|
263 |
$enabled = intval($this->_config['is_enable']);
|
|
|
264 |
return $enabled;
|
265 |
}
|
266 |
|
268 |
// checks if product should be added during checkout
|
269 |
private function checkoutEnabled() {
|
270 |
$enabled = intval($this->_config['add_during_checkout']);
|
271 |
+
Mage::log('EXPORT: Checkout enabled true/false: ' . $enabled, null, 'maxicycle.log');
|
272 |
return $enabled;
|
273 |
}
|
274 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
275 |
// get checkout from controller
|
276 |
+
private function getCheckout() {
|
|
|
277 |
return Mage::getSingleton('checkout/session');
|
278 |
}
|
279 |
|
280 |
// get quote from checkout
|
281 |
+
private function getQuote() {
|
|
|
282 |
return $this->getCheckout()->getQuote();
|
283 |
}
|
284 |
+
|
285 |
+
// check if campaign is in response period
|
286 |
+
private function _inResponsePeriod($campaign) {
|
287 |
+
$campaign_time_end = strtotime($campaign['campaign_end']);
|
288 |
+
return ($campaign_time_end <= time());
|
289 |
+
}
|
290 |
+
|
291 |
+
// get order type depending on if campaign is in response period
|
292 |
+
private function campaignOrderType($order, $campaign) {
|
293 |
+
return ($this->_inResponsePeriod($campaign)) ? new Zend_Db_Expr('NULL') : $order->getMaxicycleOrderType();
|
294 |
+
}
|
295 |
+
|
296 |
+
// get sku type depending on if campaign is in response period
|
297 |
+
private function sku($order, $campaign) {
|
298 |
+
return ($this->_inResponsePeriod($campaign)) ? new Zend_Db_Expr('NULL') : $order->getMaxicycleSku();
|
299 |
+
}
|
300 |
+
|
301 |
+
// Check if order is a response order and get id
|
302 |
+
// Is queried against the results table if there is already an order for that campaign and customer id
|
303 |
+
private function getResponseOrderId($order, $campaign) {
|
304 |
+
Mage::log('Checking if response order', null, 'maxicycle.log');
|
305 |
+
$maxicycle_customer_id = $order->getMaxicycleCustomerId();
|
306 |
+
$response_to_order_id = NULL;
|
307 |
+
// Identify if it is response order
|
308 |
+
$previous_order_exists = $this->_db->fetchAll("SELECT order_id FROM " . $this->_dbResource->getTableName('maxicycle/results') .
|
309 |
+
" WHERE campaign_id = " . $campaign['campaign_id'] .
|
310 |
+
" AND maxicycle_customer_id = $maxicycle_customer_id AND campaign_order_type IS NOT NULL ORDER BY created_at DESC LIMIT 1");
|
311 |
+
if (count($previous_order_exists) == 1) {
|
312 |
+
Mage::log('Response order!', null, 'maxicycle.log');
|
313 |
+
$response_to_order_id = $previous_order_exists[0]['order_id'];
|
314 |
+
}
|
315 |
+
return $response_to_order_id;
|
316 |
+
}
|
317 |
}
|
app/code/community/Maxicycle/Connector/etc/config.xml
CHANGED
@@ -12,7 +12,7 @@
|
|
12 |
<config>
|
13 |
<modules>
|
14 |
<Maxicycle_Connector>
|
15 |
-
<version>1.
|
16 |
</Maxicycle_Connector>
|
17 |
</modules>
|
18 |
|
@@ -43,7 +43,7 @@
|
|
43 |
<maxicycle>
|
44 |
<class>Maxicycle_Connector_Model</class>
|
45 |
<resourceModel>maxicycle_mysql4</resourceModel>
|
46 |
-
</maxicycle>
|
47 |
<maxicycle_mysql4>
|
48 |
<class>Maxicycle_Connector_Model_Mysql4</class>
|
49 |
<entities>
|
@@ -57,7 +57,7 @@
|
|
57 |
<table>maxicycle_results</table>
|
58 |
</results>
|
59 |
</entities>
|
60 |
-
</maxicycle_mysql4>
|
61 |
</models>
|
62 |
<resources>
|
63 |
<maxicycle_setup>
|
12 |
<config>
|
13 |
<modules>
|
14 |
<Maxicycle_Connector>
|
15 |
+
<version>1.1.3</version>
|
16 |
</Maxicycle_Connector>
|
17 |
</modules>
|
18 |
|
43 |
<maxicycle>
|
44 |
<class>Maxicycle_Connector_Model</class>
|
45 |
<resourceModel>maxicycle_mysql4</resourceModel>
|
46 |
+
</maxicycle>
|
47 |
<maxicycle_mysql4>
|
48 |
<class>Maxicycle_Connector_Model_Mysql4</class>
|
49 |
<entities>
|
57 |
<table>maxicycle_results</table>
|
58 |
</results>
|
59 |
</entities>
|
60 |
+
</maxicycle_mysql4>
|
61 |
</models>
|
62 |
<resources>
|
63 |
<maxicycle_setup>
|
app/code/community/Maxicycle/Connector/sql/maxicycle_setup/upgrade-1.0.4-1.0.5.php
CHANGED
@@ -33,4 +33,4 @@ $installer->getConnection()->addColumn($installer->getTable('sales_flat_quote'),
|
|
33 |
'default' => null,
|
34 |
'comment' => 'Maxicycle campaign ID for order'
|
35 |
));
|
36 |
-
$installer->endSetup();
|
33 |
'default' => null,
|
34 |
'comment' => 'Maxicycle campaign ID for order'
|
35 |
));
|
36 |
+
$installer->endSetup();
|
app/code/community/Maxicycle/Connector/sql/maxicycle_setup/upgrade-1.0.7-1.1.1.php
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Maxicycle
|
5 |
+
*
|
6 |
+
* @category Maxicycle
|
7 |
+
* @package Maxicycle_Connector
|
8 |
+
* @copyright Copyright (c) 2015 (http://www.maxicycle.com)
|
9 |
+
*/
|
10 |
+
$installer = $this;
|
11 |
+
$installer->startSetup();
|
12 |
+
|
13 |
+
// Add sku attribute
|
14 |
+
$installer->getConnection()->addColumn($installer->getTable('sales_flat_quote'), 'maxicycle_sku',
|
15 |
+
Varien_Db_Ddl_Table::TYPE_TEXT, null, array(
|
16 |
+
'nullable' => true,
|
17 |
+
'default' => null,
|
18 |
+
'comment' => 'Maxicycle chosen sku',
|
19 |
+
'length' => 100
|
20 |
+
));
|
21 |
+
|
22 |
+
// Add sku attribute
|
23 |
+
$installer->getConnection()->addColumn($installer->getTable('sales_flat_order'), 'maxicycle_sku',
|
24 |
+
Varien_Db_Ddl_Table::TYPE_TEXT, null, array(
|
25 |
+
'nullable' => true,
|
26 |
+
'default' => null,
|
27 |
+
'comment' => 'Maxicycle chosen sku',
|
28 |
+
'length' => 100
|
29 |
+
));
|
30 |
+
|
31 |
+
|
32 |
+
$installer->endSetup();
|
app/code/community/Maxicycle/Connector/sql/maxicycle_setup/upgrade-1.1.1-1.1.2.php
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Maxicycle
|
5 |
+
*
|
6 |
+
* @category Maxicycle
|
7 |
+
* @package Maxicycle_Connector
|
8 |
+
* @copyright Copyright (c) 2015 (http://www.maxicycle.com)
|
9 |
+
*/
|
10 |
+
$installer = $this;
|
11 |
+
$installer->startSetup();
|
12 |
+
|
13 |
+
// Add sku attribute
|
14 |
+
$installer->getConnection()->addColumn($installer->getTable('maxicycle/results'), 'sku',
|
15 |
+
Varien_Db_Ddl_Table::TYPE_TEXT, null, array(
|
16 |
+
'nullable' => true,
|
17 |
+
'default' => null,
|
18 |
+
'comment' => 'Maxicycle chosen sku',
|
19 |
+
'length' => 100
|
20 |
+
));
|
21 |
+
|
22 |
+
|
23 |
+
$installer->endSetup();
|
app/code/community/Maxicycle/Connector/sql/maxicycle_setup/upgrade-1.1.2-1.1.3.php
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Maxicycle
|
5 |
+
*
|
6 |
+
* @category Maxicycle
|
7 |
+
* @package Maxicycle_Connector
|
8 |
+
* @copyright Copyright (c) 2015 (http://www.maxicycle.com)
|
9 |
+
*/
|
10 |
+
$installer = $this;
|
11 |
+
$installer->startSetup();
|
12 |
+
|
13 |
+
$installer->run("
|
14 |
+
ALTER TABLE `{$installer->getTable('maxicycle/results')}` CHANGE `campaign_order_type` `campaign_order_type` TEXT NULL DEFAULT NULL
|
15 |
+
");
|
16 |
+
|
17 |
+
//// Add sku attribute
|
18 |
+
//$installer->getConnection()->modifyColumn($installer->getTable('maxicycle/results'), 'campaign_order_type',
|
19 |
+
// Varien_Db_Ddl_Table::TYPE_VARCHAR, array('nullable' => true), 'Campaign Order Type' );
|
20 |
+
|
21 |
+
|
22 |
+
$installer->endSetup();
|
package.xml
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
<?xml version="1.0"?>
|
2 |
<package>
|
3 |
<name>MaxicycleCom_Connector</name>
|
4 |
-
<version>1.
|
5 |
<stability>stable</stability>
|
6 |
<license uri="http://www.maxicycle/license">Copyright Maxicycle Software GmbH 2015</license>
|
7 |
<channel>community</channel>
|
@@ -11,7 +11,11 @@
|
|
11 |

|
12 |
Did you know that enclosing package inserts (coupons, catalogs, freebies, product samples, etc.) are extremely effective in driving follow-up orders from your existing customer base? Maxicycle is the solution that turns your packages into a real performance-based retention marketing channel with an amazing ROI: Create, manage, measure and optimise package inserts in a similar way than you are used from your AdWords or Facebook ads.
|
13 |
</description>
|
14 |
-
<notes>v1.
|
|
|
|
|
|
|
|
|
15 |
Minor Refactoring
|
16 |
v1.0.6
|
17 |
New hooks for custom checkouts that do not use Magento's default hooks.
|
@@ -42,9 +46,9 @@ Logging into separate logfile
|
|
42 |
v.1.0.0
|
43 |
* Initial official release</notes>
|
44 |
<authors><author><name>Maxicycle Software GmbH</name><user>maxicycle</user><email>support@maxicycle.com</email></author></authors>
|
45 |
-
<date>
|
46 |
-
<time>
|
47 |
-
<contents><target name="mageetc"><dir name="modules"><file name="Maxicycle_Connector.xml" hash="0d64b2d2ad66099e225460c349125557"/></dir></target><target name="magecommunity"><dir name="Maxicycle"><dir name="Connector"><dir name="Block"><dir name="Adminhtml"><dir name="Campaigns"><file name="Grid.php" hash="c350b3b4e428bf5f11027a97e38167ae"/></dir><file name="Campaigns.php" hash="b09c985fc4215ecd937024e0364f319b"/><dir name="Cronlog"><file name="Grid.php" hash="256284d0455dbb136baf8e00d2a71a89"/></dir><file name="Cronlog.php" hash="577f5e50a80fbac7b83cf8d5727bbb5f"/><dir name="Results"><file name="Grid.php" hash="
|
48 |
<compatible/>
|
49 |
<dependencies><required><php><min>5.3.0</min><max>6.0.0</max></php></required></dependencies>
|
50 |
</package>
|
1 |
<?xml version="1.0"?>
|
2 |
<package>
|
3 |
<name>MaxicycleCom_Connector</name>
|
4 |
+
<version>1.1.3</version>
|
5 |
<stability>stable</stability>
|
6 |
<license uri="http://www.maxicycle/license">Copyright Maxicycle Software GmbH 2015</license>
|
7 |
<channel>community</channel>
|
11 |

|
12 |
Did you know that enclosing package inserts (coupons, catalogs, freebies, product samples, etc.) are extremely effective in driving follow-up orders from your existing customer base? Maxicycle is the solution that turns your packages into a real performance-based retention marketing channel with an amazing ROI: Create, manage, measure and optimise package inserts in a similar way than you are used from your AdWords or Facebook ads.
|
13 |
</description>
|
14 |
+
<notes>v1,1.3
|
15 |
+
Big refactoring.
|
16 |
+
Split testing functionality
|
17 |
+

|
18 |
+
v1.0.7
|
19 |
Minor Refactoring
|
20 |
v1.0.6
|
21 |
New hooks for custom checkouts that do not use Magento's default hooks.
|
46 |
v.1.0.0
|
47 |
* Initial official release</notes>
|
48 |
<authors><author><name>Maxicycle Software GmbH</name><user>maxicycle</user><email>support@maxicycle.com</email></author></authors>
|
49 |
+
<date>2016-02-04</date>
|
50 |
+
<time>05:50:45</time>
|
51 |
+
<contents><target name="mageetc"><dir name="modules"><file name="Maxicycle_Connector.xml" hash="0d64b2d2ad66099e225460c349125557"/></dir></target><target name="magecommunity"><dir name="Maxicycle"><dir name="Connector"><dir name="Block"><dir name="Adminhtml"><dir name="Campaigns"><file name="Grid.php" hash="c350b3b4e428bf5f11027a97e38167ae"/></dir><file name="Campaigns.php" hash="b09c985fc4215ecd937024e0364f319b"/><dir name="Cronlog"><file name="Grid.php" hash="256284d0455dbb136baf8e00d2a71a89"/></dir><file name="Cronlog.php" hash="577f5e50a80fbac7b83cf8d5727bbb5f"/><dir name="Results"><file name="Grid.php" hash="ba4b97a5137098ae21826f3ff4ed7a09"/><dir name="Renderer"><file name="Campaign.php" hash="ef4d3f0cd6c3558367f82e07853414e6"/><file name="Flag2.php" hash="d8779254a77e19da81c91e81452a7e43"/><file name="Order.php" hash="aecdc4cb460c558773660778060cde0f"/></dir></dir><file name="Results.php" hash="4d32a5f15b1f3a18434e3b2754030659"/></dir></dir><dir name="Helper"><file name="Data.php" hash="a7df4cd21dc681b1887b21276e099c53"/></dir><dir name="Model"><dir name="Api"><file name="Abstract.php" hash="71be3bc47c32463bc8f6f84e901719ef"/><file name="Rest.php" hash="1a3c5413761e27c88e6c3cbe940d2be0"/></dir><file name="Campaigns.php" hash="4e60821d8a19ea5391921e5b358257dc"/><file name="Cronlog.php" hash="dc5eec5445c6c703429992b749c8ef2c"/><file name="Insert.php" hash="5b31e189cac060f0d1a0f4801d82480f"/><dir name="Mysql4"><dir name="Campaigns"><file name="Collection.php" hash="880cbcd1ab65efb9096965c267ad35cc"/></dir><file name="Campaigns.php" hash="98143aae26423260cccb496aac9d28f2"/><dir name="Cronlog"><file name="Collection.php" hash="44d321c218f66619fbbf14271fca361f"/></dir><file name="Cronlog.php" hash="299749238a435407cce37b5dc524c466"/><dir name="Results"><file name="Collection.php" hash="8b046e56516f2f1893b6f3d1e6e2b228"/><dir name="Renderer"><file name="Actions.php" hash="da76e0352436e0570c8e6506a121d031"/><file name="Status.php" hash="37878ac8231edee56041b714077f7aec"/></dir></dir><file name="Results.php" hash="8898f253c8dce9ebe3a6b289e26945a6"/></dir><file name="Observer.php" hash="e130e8ddb458559a06d58523d6586fc6"/><dir name="Resource"><dir name="Mysql4"><file name="Setup.php" hash="ccae8f6fc1d48cb5ef6b761211e75bd9"/></dir></dir><file name="Results.php" hash="246fff1018a0b03f521ba96ec61b8a8e"/></dir><dir name="controllers"><dir name="Adminhtml"><file name="CampaignsController.php" hash="420557976cfeda32353ce0b5f435a252"/><file name="CronlogController.php" hash="eb58983412dec2890d22138adecb95a7"/><file name="InstallationController.php" hash="8f338320862fc72b7f2eaaf5a918e293"/><file name="ResultsController.php" hash="78633bbdd767350c56deef829c7b4a62"/></dir><file name="TestConnectionController.php" hash="ddb67e441e3478d45632905b78e5c362"/><file name="V1Controller.php" hash="8cf992ec3ab988d3b11f8428ea98d501"/></dir><dir name="data"><file name="data_sample.sql" hash="c02ad04dc9c1b43814ac7877970ab1ae"/></dir><dir name="etc"><file name="adminhtml.xml" hash="363126b0e935810dd07d42426ce9f766"/><file name="config.xml" hash="a1adf400fe884d258339210f8df04c43"/></dir><dir name="sql"><dir name="maxicycle_setup"><file name="mysql4-install-1.0.0.php" hash="ac322e77f8b08beb2d326426f2c23121"/><file name="upgrade-1.0.0-1.0.1.php" hash="dba0e0a874a87c101b379de988646b1f"/><file name="upgrade-1.0.3-1.0.4.php" hash="dba0e0a874a87c101b379de988646b1f"/><file name="upgrade-1.0.4-1.0.5.php" hash="5ab6b381bfe60a5d2d2b0b8476fa687c"/><file name="upgrade-1.0.7-1.1.1.php" hash="71ac5eb71b7401d3cbd976b413f88860"/><file name="upgrade-1.1.1-1.1.2.php" hash="025f1aea7c6432175c27c6d898ea8d09"/><file name="upgrade-1.1.2-1.1.3.php" hash="dac70cbef34f2c9a892cdce3a2c568cf"/></dir></dir></dir></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="template"><dir name="maxicycle"><dir name="connector"><dir name="installation"><file name="step1.phtml" hash="498b5417c51c5b7d92bb46a17caeb9fa"/></dir></dir></dir></dir><dir name="layout"><dir name="maxicycle"><dir name="connector"><file name="layout.xml" hash="b4c388d059df42d365c945f972e8cfca"/></dir></dir></dir></dir></dir></dir></target><target name="mageskin"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="maxicycle"><dir name="connector"><dir name="css"><file name="css.css" hash="6cb4c9ca0ce1288f028ea80284d368ae"/></dir></dir></dir></dir></dir></dir></target></contents>
|
52 |
<compatible/>
|
53 |
<dependencies><required><php><min>5.3.0</min><max>6.0.0</max></php></required></dependencies>
|
54 |
</package>
|