MaxicycleCom_Connector - Version 1.1.3

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 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 skku in reuqest
31
  return $this->_response(array('message' => 'No SKU provided'), 403);
 
 
 
 
 
32
  } else {
33
- // Check if product with given SKU exist
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
- // Check if product with given SKU exist
96
- $_product = Mage::getModel('catalog/product')->loadByAttribute('sku', $data['sku']);
97
- if (!$_product) {
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
- // Check if product with given SKU exist
141
- $_product = Mage::getModel('catalog/product')->loadByAttribute('sku', $data['sku']);
142
- if (!$_product) {
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
- $campaigns = Mage::getModel('maxicycle/results')->getCollection()->addFieldToFilter('campaign_id', $campaign_id)->addFieldToFilter('export_flag', 0);
223
  // Loop over all campaigns
224
- foreach ($campaigns as $campaign) {
225
  // For debug purpose
226
  if ($this->_debug) {
227
  // Simply return data without any check
228
  $results[] = array(
229
- 'campaign_id' => $campaign->getCampaignId(),
230
- 'order_id' => $campaign->getOrderId(),
231
- 'customer_id' => $campaign->getMaxicycleCustomerId(),
232
- 'campaign_order_type' => $campaign->getCampaignOrderType(),
233
- 'order_date' => $campaign->getCreatedAt(),
234
- 'response_to_order_id' => $campaign->getResponseToOrderId(),
235
- 'revenue' => $campaign->getGrandTotal(),
236
- 'gross_profit' => $campaign->getOrderProfit(),
237
- 'last_order_update' => $campaign->getLastOrderUpdateDate()
 
238
  );
239
- $campaign->setExportFlag(1)->save();
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 = '" . $campaign->getOrderId() . "'");
243
 
244
  if (in_array($order_status, $enable_statuses)) {
245
  $results[] = array(
246
- 'campaign_id' => $campaign->getCampaignId(),
247
- 'order_id' => $campaign->getOrderId(),
248
- 'customer_id' => $campaign->getMaxicycleCustomerId(),
249
- 'campaign_order_type' => $campaign->getCampaignOrderType(),
250
- 'order_date' => $campaign->getCreatedAt(),
251
- 'response_to_order_id' => $campaign->getResponseToOrderId(),
252
- 'revenue' => $campaign->getGrandTotal(),
253
- 'gross_profit' => $campaign->getOrderProfit(),
254
- 'last_order_update' => $campaign->getLastOrderUpdateDate()
 
255
  );
256
- $campaign->setExportFlag(1)->save();
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('controller_action_predispatch_checkout_onepage_index', null, 'maxicycle.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
- $this->setConfig($quote->getStoreId());
61
- if ($this->moduleEnabled() && $this->checkoutEnabled() && !$this->hasCampaignOrderTypeSet($quote)) {
62
- Mage::log('QUOTE: adding product to order', null, 'maxicycle.log');
63
- $active_campaigns = $this->getActiveCampaigns();
64
- // If there is some active campaign
65
- if (count($active_campaigns) > 0) {
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('QUOTE: Checkout adding disabled or product already added', null, 'maxicycle.log');
78
  }
79
  }
80
  catch(Exception $e) {
81
- Mage::log('QUOTE: Adding product to quote failed: ' .$e->getMessage(), null, 'maxicycle.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('adding product to order', null, 'maxicycle.log');
91
  try {
92
  $order = $observer->getOrder();
93
- $this->setConfig($order->getStoreId());
 
 
 
94
  if ($this->moduleEnabled()) {
95
- Mage::log('adding product to order', null, 'maxicycle.log');
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
- // no idea why we do this, but we check and set the customer id to the order
 
189
  $maxicycle_customer_id = $order->getMaxicycleCustomerId();
190
- //$maxicycle_customer_id = $order->getCustomerId();
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' => $order->getMaxicycleOrderType(),
206
- 'response_to_order_id' => $order->getMaxicycleResponseToOrderId()
 
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->hasCampaignOrderTypeSet($order);
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
- public function getCheckout()
513
- {
514
  return Mage::getSingleton('checkout/session');
515
  }
516
 
517
  // get quote from checkout
518
- public function getQuote()
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.0.7</version>
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.0.7</version>
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
  &#xD;
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.&#xD;
13
  </description>
14
- <notes>v1.0.7&#xD;
 
 
 
 
15
  Minor Refactoring&#xD;
16
  v1.0.6&#xD;
17
  New hooks for custom checkouts that do not use Magento's default hooks.&#xD;
@@ -42,9 +46,9 @@ Logging into separate logfile&#xD;
42
  v.1.0.0&#xD;
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>2015-10-20</date>
46
- <time>19:54:42</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="4236c80b8faa31e6cba5f184e0d45adc"/><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="260c1849fc5dba7b5698d5160f427d5d"/></dir><file name="Campaigns.php" hash="4e60821d8a19ea5391921e5b358257dc"/><file name="Cronlog.php" hash="dc5eec5445c6c703429992b749c8ef2c"/><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="03036e17fe2bd7b1c7294f5cee9ad7b0"/><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="9aeb95efe08ad5d9d72e653b5c4156fb"/></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="28f1d904f1dc1bebb1436bd93dca0122"/></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>
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
  &#xD;
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.&#xD;
13
  </description>
14
+ <notes>v1,1.3&#xD;
15
+ Big refactoring.&#xD;
16
+ Split testing functionality&#xD;
17
+ &#xD;
18
+ v1.0.7&#xD;
19
  Minor Refactoring&#xD;
20
  v1.0.6&#xD;
21
  New hooks for custom checkouts that do not use Magento's default hooks.&#xD;
46
  v.1.0.0&#xD;
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>