cartdefender_actions - Version 2.1.8

Version Notes

Compatibility updates in data gathering

Download this release

Release Info

Developer Radoslaw Gliniecki
Extension cartdefender_actions
Version 2.1.8
Comparing to
See all releases


Code changes from version 2.1.0 to 2.1.8

app/code/community/CartDefender/Actions/Helper/Data.php CHANGED
@@ -135,6 +135,47 @@ class CartDefender_Actions_Helper_Data extends Mage_Core_Helper_Abstract
135
  return $sendKey;
136
  }
137
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
  /**
139
  * Returns an array containing Cart Defender configuration settings.
140
  *
@@ -153,7 +194,9 @@ class CartDefender_Actions_Helper_Data extends Mage_Core_Helper_Abstract
153
  'test_server_url_start' => $this->getTestServerUrlStart(),
154
  'use_raw_test_url_for_biz_api' =>
155
  $this->getUseRawTestUrlForBizApi(),
156
- 'send_key' => $this->getSendKey()
 
 
157
  );
158
  }
159
  return $data;
135
  return $sendKey;
136
  }
137
 
138
+ /**
139
+ * Obtains the url to access the synchronous
140
+ * sender PHP script, used to send business events to Cart Defender
141
+ * servers.
142
+ *
143
+ * @return string URL needed to access the sender script.
144
+ */
145
+ public function getSenderControllerUrl()
146
+ {
147
+ $senderControllerUrl = Mage::getStoreConfig('actions/settings/sender_controller_url');
148
+ if (empty($senderControllerUrl)) {
149
+ $senderControllerUrl = Mage::getUrl(
150
+ 'cartdefender/CartDefenderSender/send',
151
+ array('_secure' => true)
152
+ );
153
+ Mage::getConfig()->saveConfig(
154
+ 'actions/settings/sender_controller_url',
155
+ $senderControllerUrl,
156
+ 'default',
157
+ 0
158
+ );
159
+ }
160
+ return $senderControllerUrl;
161
+ }
162
+
163
+ /**
164
+ * Obtains the selected transport method for store's data
165
+ *
166
+ * @return string code name of the selected transport method
167
+ */
168
+ public function getTransportMethod()
169
+ {
170
+ $transportMethod = Mage::getStoreConfig('actions/settings/transport_method');
171
+ if (empty($transportMethod)) {
172
+ $transportMethod = CartDefender_Actions_Model_System_Config_Source_Transport::CURL_PROCESS;
173
+ Mage::getConfig()->saveConfig('actions/settings/transport_method', $transportMethod, 'default', 0);
174
+ }
175
+ return $transportMethod;
176
+ }
177
+
178
+
179
  /**
180
  * Returns an array containing Cart Defender configuration settings.
181
  *
194
  'test_server_url_start' => $this->getTestServerUrlStart(),
195
  'use_raw_test_url_for_biz_api' =>
196
  $this->getUseRawTestUrlForBizApi(),
197
+ 'send_key' => $this->getSendKey(),
198
+ 'sender_controller_url' => $this->getSenderControllerUrl(),
199
+ 'transport_method' => $this->getTransportMethod()
200
  );
201
  }
202
  return $data;
app/code/community/CartDefender/Actions/Helper/Logger.php CHANGED
@@ -29,7 +29,7 @@ class CartDefender_Actions_Helper_Logger extends Mage_Core_Helper_Abstract
29
  $this->enabled = ($settings ? $settings['test'] : null);
30
  }
31
  if ($this->enabled) {
32
- Mage::log('[CD] [' . $function . '] ' . $message);
33
  }
34
  }
35
  }
29
  $this->enabled = ($settings ? $settings['test'] : null);
30
  }
31
  if ($this->enabled) {
32
+ Mage::log('[CD] [' . $function . '] ' . $message, null, 'cartdefender.log');
33
  }
34
  }
35
  }
app/code/community/CartDefender/Actions/Model/Api.php ADDED
@@ -0,0 +1,266 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class CartDefender_Actions_Model_Api extends Mage_Api_Model_Resource_Abstract
4
+ {
5
+
6
+ private $storeId;
7
+
8
+ private $itemStartIndex;
9
+
10
+ private $itemCount;
11
+
12
+ private $excludeOutOfStock;
13
+
14
+ private $excludeDisabled;
15
+
16
+ private $excludeInvisible;
17
+
18
+ private $productIds;
19
+
20
+ private $store;
21
+
22
+ public function getVersion ()
23
+ {
24
+ // Get path to config file
25
+ $filePath = realpath(dirname(__FILE__)) . '/../etc/config.xml';
26
+
27
+ // Open the config file -- ignore errors
28
+ $configFileContents = @file_get_contents($filePath);
29
+
30
+ // Return message if config file could not be opened
31
+ if (empty($configFileContents) == true) {
32
+ return 'Could not open config.xml';
33
+ }
34
+
35
+ // Get version from config file
36
+ $pattern = '|<version>([^<]+)|i';
37
+ if (preg_match($pattern, $configFileContents, $matches) !== 1) {
38
+ return 'Could not get version from config.xml';
39
+ }
40
+
41
+ // Return the version string
42
+ return $matches[1];
43
+ }
44
+
45
+ private function initialize () // TODO add logging and CD API exception
46
+ {
47
+ // Increase maximum execution time to 4 hours
48
+ ini_set('max_execution_time', 14400);
49
+
50
+ // Check format of the item start and count
51
+ if (0 == preg_match('|^\d+$|', $this->itemStartIndex)) {
52
+ Mage::throwException(
53
+ 'The specified item start index is not formatted correctly: ' .
54
+ $this->itemStartIndex);
55
+ }
56
+ if (0 == preg_match('|^\d+$|', $this->itemCount)) {
57
+ Mage::throwException(
58
+ 'The specified item count is not formatted correctly: ' .
59
+ $this->itemCount);
60
+ }
61
+ // Check range of the item start and ccount
62
+ $this->itemStartIndex = intval($this->itemStartIndex);
63
+ $this->itemCount = intval($this->itemCount);
64
+ if ($this->itemStartIndex < 0) {
65
+ Mage::throwException(
66
+ 'The specified item start index is less than zero: ' .
67
+ $this->itemStartIndex);
68
+ }
69
+ if ($this->itemCount <= 0) {
70
+ Mage::throwException(
71
+ 'The specified item count is less than or equal to zero: ' .
72
+ $this->itemCount);
73
+ }
74
+
75
+ // Check format of the storeId
76
+ if (0 == preg_match('|^\d+$|', $this->storeId)) {
77
+ Mage::throwException(
78
+ 'The specified Store is not formatted correctly: ' .
79
+ $this->storeId);
80
+ }
81
+ $this->storeId = intval($this->storeId);
82
+ try {
83
+ $this->store = Mage::app()->getStore($this->storeId);
84
+ } catch (Exception $e) {
85
+ Mage::throwException(
86
+ 'Error getting store with ID ' . $this->storeId .
87
+ ". The store probably does not exist. " .
88
+ get_class($e) . " " . $e->getMessage());
89
+ }
90
+
91
+ $this->excludeDisabled = (bool) $this->excludeDisabled;
92
+ $this->excludeInvisible = (bool) $this->excludeInvisible;
93
+
94
+ if (! is_array($this->productIds)) {
95
+ $this->productIds = null;
96
+ }
97
+ }
98
+
99
+ public function export ($storeId = 0, $itemStartIndex = 0, $itemCount = 100000,
100
+ $excludeDisabled = true, $excludeInvisible = true, $productIds = null)
101
+ {
102
+ $this->storeId = $storeId;
103
+ $this->itemStartIndex = $itemStartIndex;
104
+ $this->itemCount = $itemCount;
105
+ $this->excludeDisabled = $excludeDisabled;
106
+ $this->excludeInvisible = $excludeInvisible;
107
+ $this->productIds = $productIds;
108
+
109
+ $this->initialize();
110
+
111
+ // TODO Add FINAL price after rules applied
112
+ // TODO Check IMAGE URLS
113
+
114
+ try {
115
+ $collection = Mage::getResourceModel('catalog/product_collection')->setPage(
116
+ $itemStartIndex, $itemCount)
117
+ ->addAttributeToSelect('entity_id')
118
+ ->setOrder('entity_id', 'ASC')
119
+ ->addAttributeToSelect('sku')
120
+ ->addAttributeToSelect('status')
121
+ ->addAttributeToSelect('visibility')
122
+ ->addAttributeToSelect('created_at')
123
+ ->addAttributeToSelect('updated_at')
124
+ ->addAttributeToSelect('product_url')
125
+ ->addAttributeToSelect('type_id');
126
+
127
+ if ($this->excludeInvisible === true) {
128
+ $collection->addFieldToFilter('visibility',
129
+ array(
130
+ 'nlike' => Mage_Catalog_Model_Product_Visibility::VISIBILITY_NOT_VISIBLE
131
+ ));
132
+ }
133
+
134
+ if (is_array($this->productIds)) {
135
+ $collection->addFieldToFilter('entity_id',
136
+ array(
137
+ $this->productIds
138
+ ));
139
+ }
140
+
141
+ if ($this->excludeDisabled === true) {
142
+ $collection->addAttributeToFilter('status', 1); // enabled
143
+ }
144
+
145
+ if (Mage::helper('catalog')->isModuleEnabled(
146
+ 'Mage_CatalogInventory')) {
147
+ $collection->joinField('qty', 'cataloginventory/stock_item',
148
+ 'qty', 'product_id=entity_id', '{{table}}.stock_id=1',
149
+ 'left');
150
+ }
151
+
152
+ if ($this->store->getId()) {
153
+ $collection->addStoreFilter($this->store);
154
+ $collection->joinAttribute('name', 'catalog_product/name',
155
+ 'entity_id', null, 'inner', $this->store->getId());
156
+ $collection->joinAttribute('description',
157
+ 'catalog_product/description', 'entity_id', null,
158
+ 'inner', $this->store->getId());
159
+ $collection->joinAttribute('short_description',
160
+ 'catalog_product/short_description', 'entity_id', null,
161
+ 'inner', $this->store->getId());
162
+ $collection->joinAttribute('image', 'catalog_product/image',
163
+ 'entity_id', null, 'inner', $this->store->getId());
164
+ $collection->joinAttribute('price', 'catalog_product/price',
165
+ 'entity_id', null, 'left', $this->store->getId());
166
+ $collection->joinAttribute('special_price',
167
+ 'catalog_product/price', 'entity_id', null, 'left',
168
+ $this->store->getId());
169
+ } else {
170
+ $collection->addAttributeToSelect(
171
+ array(
172
+ 'name',
173
+ 'description',
174
+ 'short_description',
175
+ 'image',
176
+ 'price',
177
+ 'special_price'
178
+ ));
179
+ }
180
+ $mediaConfig = Mage::getModel('catalog/product_media_config');
181
+
182
+ $productArray = array(
183
+ 'entity_id' => '',
184
+ 'sku' => '',
185
+ 'status' => '',
186
+ 'visibility' => '',
187
+ 'created_at' => '',
188
+ 'updated_at' => '',
189
+ 'product_url' => '',
190
+ 'type_id' => '',
191
+ 'qty' => '',
192
+ 'name' => '',
193
+ 'description' => '',
194
+ 'short_description' => '',
195
+ 'base_image' => '',
196
+ 'small_image' => '',
197
+ 'thumbnail_image' => '',
198
+ 'price' => '',
199
+ 'special_price' => '',
200
+ 'parent_id' => ''
201
+ );
202
+
203
+ $content .= implode(',', array_keys($productArray));
204
+ $content .= "\n";
205
+
206
+ foreach ($collection as $product) {
207
+ if ("no_selection" == $product->getImage()) {
208
+ $productImage = "";
209
+ } else {
210
+ $productImage = $mediaConfig->getMediaUrl(
211
+ $product->getImage());
212
+ }
213
+
214
+ $parentIdsList = '';
215
+ if ($product->getTypeId() ==
216
+ Mage_Catalog_Model_Product_Type::TYPE_SIMPLE) {
217
+ $parentIds = Mage::getModel('catalog/product_type_grouped')->getParentIdsByChild(
218
+ $product->getId());
219
+ if (! $parentIds) {
220
+ $parentIds = Mage::getModel(
221
+ 'catalog/product_type_configurable')->getParentIdsByChild(
222
+ $product->getId());
223
+ }
224
+ if (isset($parentIds[0])) {
225
+ $parentIdsList = implode(',', $parentIds);
226
+ }
227
+ }
228
+ $productArray['entity_id'] = $product->getId();
229
+ $productArray['sku'] = $product->getSku();
230
+ $productArray['status'] = $product->getStatus();
231
+ $productArray['visibility'] = $product->getVisibility();
232
+ $productArray['created_at'] = $product->getCreatedAt();
233
+ $productArray['updated_at'] = $product->getUpdatedAt();
234
+ $productArray['product_url'] = $product->setStoreId(
235
+ $this->store->getId())
236
+ ->getProductUrl();
237
+ $productArray['type_id'] = $product->getTypeId();
238
+ $productArray['qty'] = $product->getQty();
239
+ $productArray['name'] = $product->getName();
240
+ $productArray['description'] = $product->getDescription();
241
+ $productArray['short_description'] = $product->getShortDescription();
242
+ $productArray['base_image'] = $productImage;
243
+ $productArray['small_image'] = $mediaConfig->getMediaUrl(
244
+ $product->getSmallImage());
245
+ $productArray['thumbnail_image'] = $mediaConfig->getMediaUrl(
246
+ $product->getThumbnail());
247
+ $productArray['price'] = $product->getPrice();
248
+ $productArray['special_price'] = $product->getSpecialPrice();
249
+ $productArray['parent_id'] = $parentIdsList; // get parent prod
250
+ // ids
251
+
252
+ // Escape double quotes
253
+ $escapedProductArray = str_replace('"', '""', $productArray);
254
+
255
+ // Write each product to the file
256
+ $content .= '"';
257
+ $content .= implode('","', $escapedProductArray);
258
+ $content .= "\"\n";
259
+ }
260
+ } catch (Exception $e) {
261
+ return 'The query resulted in an exception: ' . get_class($e) . ' ' .
262
+ $e->getMessage();
263
+ }
264
+ return $content;
265
+ }
266
+ }
app/code/community/CartDefender/Actions/Model/Api/V2.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class CartDefender_Actions_Model_Api_V2 extends CartDefender_Actions_Model_Api
4
+ {
5
+
6
+ }
app/code/community/CartDefender/Actions/Model/AsyncLocalSender.php CHANGED
@@ -1,5 +1,7 @@
1
  <?php
2
 
 
 
3
  /**
4
  * Asynchronous sender of text data to "synchronous remote sender" (another
5
  * Cart Defender PHP script available on localhost), which then sends the
@@ -26,6 +28,99 @@ class CartDefender_Actions_Model_AsyncLocalSender extends Varien_Object
26
  $this->logger = Mage::helper('actions/logger');
27
  }
28
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  /**
30
  * Asynchronously sends the data passed to "synchronous remote sender"
31
  * (another Cart Defender PHP script available on localhost),
@@ -49,31 +144,58 @@ class CartDefender_Actions_Model_AsyncLocalSender extends Varien_Object
49
  * by Cart Defender backend.
50
  * @return void
51
  */
52
- public function send($data, $sequenceNo, $correlationId)
53
  {
54
- $remoteSenderConf = $this->getRemoteSenderConf();
55
  $request = $this->createRequest(
56
  $remoteSenderConf['path'],
57
  $remoteSenderConf['host'],
58
  $data,
59
  $sequenceNo,
60
- $correlationId
 
61
  );
62
  $socket = fsockopen(
63
  $remoteSenderConf['protocol'] . $remoteSenderConf['host'],
64
  $remoteSenderConf['port'],
65
  $errno,
66
  $errstr,
67
- 0.2 /*timeout*/
68
  );
69
- $success = fwrite($socket, $request);
70
- Mage::getSingleton('core/session')->setLastEventTime(time());
71
- $this->logger->log('AsyncLocalSender->send', ($success ? 'Success.'
72
- : ('Error (num: [' . $errno . '], msg: [' . $errstr . '])'))
73
- . ' Data: [' . $data . ']');
74
  fclose($socket);
 
 
 
 
 
 
 
 
75
  }
76
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  /**
78
  * Retrieves the configuration of synchronous remote sender,
79
  * specifically its URL parts.
@@ -81,15 +203,12 @@ class CartDefender_Actions_Model_AsyncLocalSender extends Varien_Object
81
  * @return array the configuration of synchronous remote sender, with
82
  * entries such as 'protocol', 'host', 'port', 'path'.
83
  */
84
- private function getRemoteSenderConf()
85
  {
86
  // "static" to compute only once and return cached value later.
87
  static $remoteSenderConf = null;
88
  if ($remoteSenderConf === null) {
89
- $remoteSenderConf = parse_url(Mage::getUrl(
90
- 'cartdefender/CartDefenderSender/send',
91
- array('_secure' => true)
92
- ));
93
  if (empty($remoteSenderConf['port'])) {
94
  $remoteSenderConf['port'] =
95
  ($remoteSenderConf['scheme'] == 'http') ? 80 : 443;
@@ -126,31 +245,47 @@ class CartDefender_Actions_Model_AsyncLocalSender extends Varien_Object
126
  $remoteSenderHost,
127
  $data,
128
  $sequenceNo,
129
- $correlationId
 
130
  ) {
131
- $settings = Mage::helper('actions')->getSettings();
132
  $queryParams = array(
133
  'sequence_no' => $sequenceNo,
134
- 'data' => $data,
135
  'is_local_request' => true, // PHP to PHP call within current server
136
  'correlation_id' => $correlationId,
137
- 'send_key' => $settings['send_key']
 
138
  );
139
  $postdata = http_build_query($queryParams);
140
 
141
  // Note that Carriage Return (\r) characters below are in accordance
142
  // with RFC 2616. See http://stackoverflow.com/questions/5757290 Also,
143
  // note that double quotes let \r & \n be interpreted correctly.
144
-
145
  $request = "";
146
  $request.= "POST " . $remoteSenderUrlPath . " HTTP/1.1\r\n";
147
  $request.= "Host: " . $remoteSenderHost . "\r\n";
148
- $request.= "Content-type: application/x-www-form-urlencoded\r\n";
149
- $request.= "Content-length: " . strlen($postdata) . "\r\n";
150
  $request.= "\r\n";
151
  $request.= $postdata;
152
  $request.= "\r\n\r\n";
153
 
154
  return $request;
155
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
  }
1
  <?php
2
 
3
+ use CartDefender_Actions_Helper_Data as CDData;
4
+
5
  /**
6
  * Asynchronous sender of text data to "synchronous remote sender" (another
7
  * Cart Defender PHP script available on localhost), which then sends the
28
  $this->logger = Mage::helper('actions/logger');
29
  }
30
 
31
+ /**
32
+ * Sends the data passed to this function using one of the possible
33
+ * transport methods.
34
+ *
35
+ * @param string $data
36
+ * the data to send.
37
+ * @param int $sequenceNo
38
+ * sequence number of the data being sent,
39
+ * used for logging purposes.
40
+ * @param string $correlationId
41
+ * the correlation identifier needed
42
+ * by Cart Defender backend.
43
+ * @return void
44
+ */
45
+ public function send($data, $sequenceNo, $correlationId)
46
+ {
47
+ $settings = Mage::helper('actions')->getSettings();
48
+ $localControllerUrl = $settings['sender_controller_url'];
49
+ if ($settings['transport_method'] ===
50
+ CartDefender_Actions_Model_System_Config_Source_Transport::ASYNC_SOCKET) {
51
+ $this->sendAsyncSocket($data, $sequenceNo, $correlationId,
52
+ $settings['send_key'], $localControllerUrl);
53
+ } elseif ($settings['transport_method'] ===
54
+ CartDefender_Actions_Model_System_Config_Source_Transport::CURL_PROCESS) {
55
+ $this->sendCurl($data, $sequenceNo, $correlationId, //TODO check
56
+ $settings, $this->getUrl($correlationId, $settings));
57
+ } elseif ($settings['transport_method'] ===
58
+ CartDefender_Actions_Model_System_Config_Source_Transport::SYNC_HTTP) {
59
+ $this->sendSyncHttpClient($data, $sequenceNo, $correlationId,
60
+ $settings['send_key'], $localControllerUrl);
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Executes an async cURL process to send the data to the Cart Defender servers
66
+ *
67
+ */
68
+ private function sendCurl($data, $sequenceNo, $correlationId, $settings, $targetUrl)
69
+ {
70
+ $apiKey = $settings['api'];
71
+ $cmd = "curl -u $apiKey: -X POST -H 'Content-Type: application/json'";
72
+ $cmd .= " -d '$data' " . " -L --post301 --post302 --post303 '$targetUrl'";
73
+ if ( ! $settings['test']) { // Async when in normal mode (not test)
74
+ $cmd .= " > /dev/null 2>&1 &";
75
+ }
76
+ exec($cmd, $output, $exit);
77
+
78
+ Mage::getSingleton('core/session')->setLastEventTime(time());
79
+
80
+ $this->logger->log(
81
+ 'AsyncLocalSender->sendCurl', ' Correlation ID: '. $correlationId
82
+ . ' PHP Session ID: '. session_id()
83
+ . ' Sequence No: ' . $sequenceNo
84
+ . ' Executed curl request. '
85
+ . ' Command:' . $cmd
86
+ . ' Exec output: ' . print_r($output,true)
87
+ . ' Return Var: ' . $exit
88
+ );
89
+ }
90
+
91
+ /**
92
+ * Mainly for connection and controller testing purposes.
93
+ * Synchronously sends the data passed to "synchronous remote sender"
94
+ * (another Cart Defender PHP script available on localhost),
95
+ * which then sends the data synchronously to Cart Defender servers.
96
+ *
97
+ */
98
+ private function sendSyncHttpClient($data, $sequenceNo, $correlationId, $sendKey, $localControllerUrl)
99
+ {
100
+ $client = new Varien_Http_Client($localControllerUrl);
101
+ $client->setMethod(Varien_Http_Client::POST);
102
+ $client->setCookie('CartDefenderCorrelationId', $correlationId);
103
+ $client->setConfig(array('strictredirects' => true));
104
+ $client->setEncType();
105
+ $client->setParameterPost('sequence_no', $sequenceNo);
106
+ $client->setParameterPost('is_local_request', true);
107
+ $client->setParameterPost('correlation_id', $correlationId);
108
+ $client->setParameterPost('send_key', $sendKey);
109
+ $client->setParameterPost('data', $data);
110
+ $response = $client->request('POST');
111
+ $lastRequest = $client->getLastRequest();
112
+
113
+ Mage::getSingleton('core/session')->setLastEventTime(time());
114
+
115
+ $this->logger->log(
116
+ 'AsyncLocalSender->sendSyncHttpClient', ' Correlation ID: '. $correlationId
117
+ . ' PHP Session ID: '. session_id() . 'Request: ' . $lastRequest
118
+ . ' Response: '. (($response->getStatus() == 200) ? 'Success ' : 'Error ')
119
+ . 'Response Status Code: ' . $response->getStatus()
120
+ . 'Entire Response string: ' . $response->asString()
121
+ );
122
+ }
123
+
124
  /**
125
  * Asynchronously sends the data passed to "synchronous remote sender"
126
  * (another Cart Defender PHP script available on localhost),
144
  * by Cart Defender backend.
145
  * @return void
146
  */
147
+ private function sendAsyncSocket($data, $sequenceNo, $correlationId, $sendKey, $localControllerUrl)
148
  {
149
+ $remoteSenderConf = $this->getRemoteSenderConf($localControllerUrl);
150
  $request = $this->createRequest(
151
  $remoteSenderConf['path'],
152
  $remoteSenderConf['host'],
153
  $data,
154
  $sequenceNo,
155
+ $correlationId,
156
+ $sendKey
157
  );
158
  $socket = fsockopen(
159
  $remoteSenderConf['protocol'] . $remoteSenderConf['host'],
160
  $remoteSenderConf['port'],
161
  $errno,
162
  $errstr,
163
+ 0.3 /*timeout*/
164
  );
165
+ $strLen = strlen($request);
166
+ $writeResult = $this->fwriteStream($socket, $request, $strLen, 6);
 
 
 
167
  fclose($socket);
168
+ $success = ($writeResult === $strLen);
169
+
170
+ Mage::getSingleton('core/session')->setLastEventTime(time());
171
+
172
+ $this->logger->log('AsyncLocalSender->sendAsyncSocket', ' Correlation ID: '. $correlationId
173
+ . ' PHP Session ID: '. session_id()
174
+ . ($success ? ' Success. ' : ('Error (num: [' . $errno . '], msg: [' . $errstr . '])'))
175
+ . ' Request: [' . $request . ']');
176
  }
177
+
178
+ /**
179
+ * Writes stream data over network sockets and expects the number of zero bytes written to be
180
+ * smaller than the set parameter.
181
+ *
182
+ * @return int the number of bytes written
183
+ */
184
+ private function fwriteStream($fp, $string, $strLen, $maxZeros = 3)
185
+ {
186
+ $numZeros = 0;
187
+ for ($written = 0; $written < $strLen; $written += $fwrite) {
188
+ $fwrite = fwrite($fp, substr($string, $written));
189
+ if ($fwrite === false || $numZeros >= $maxZeros) {
190
+ return $written;
191
+ }
192
+ if ($fwrite === 0) {
193
+ $numZeros += 1;
194
+ }
195
+ }
196
+ return $written;
197
+ }
198
+
199
  /**
200
  * Retrieves the configuration of synchronous remote sender,
201
  * specifically its URL parts.
203
  * @return array the configuration of synchronous remote sender, with
204
  * entries such as 'protocol', 'host', 'port', 'path'.
205
  */
206
+ private function getRemoteSenderConf($localControllerUrl)
207
  {
208
  // "static" to compute only once and return cached value later.
209
  static $remoteSenderConf = null;
210
  if ($remoteSenderConf === null) {
211
+ $remoteSenderConf = parse_url($localControllerUrl);
 
 
 
212
  if (empty($remoteSenderConf['port'])) {
213
  $remoteSenderConf['port'] =
214
  ($remoteSenderConf['scheme'] == 'http') ? 80 : 443;
245
  $remoteSenderHost,
246
  $data,
247
  $sequenceNo,
248
+ $correlationId,
249
+ $sendKey
250
  ) {
 
251
  $queryParams = array(
252
  'sequence_no' => $sequenceNo,
 
253
  'is_local_request' => true, // PHP to PHP call within current server
254
  'correlation_id' => $correlationId,
255
+ 'send_key' => $sendKey,
256
+ 'data' => $data
257
  );
258
  $postdata = http_build_query($queryParams);
259
 
260
  // Note that Carriage Return (\r) characters below are in accordance
261
  // with RFC 2616. See http://stackoverflow.com/questions/5757290 Also,
262
  // note that double quotes let \r & \n be interpreted correctly.
 
263
  $request = "";
264
  $request.= "POST " . $remoteSenderUrlPath . " HTTP/1.1\r\n";
265
  $request.= "Host: " . $remoteSenderHost . "\r\n";
266
+ $request.= "Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n";
267
+ $request.= "Content-Length: " . strlen($postdata) . "\r\n";
268
  $request.= "\r\n";
269
  $request.= $postdata;
270
  $request.= "\r\n\r\n";
271
 
272
  return $request;
273
  }
274
+
275
+ /**
276
+ * Returns the URL to which the data should be sent by this script.
277
+ *
278
+ * @param array $settings Cart Defender configuration settings.
279
+ * @return string URL to which the data should be sent by this script.
280
+ */
281
+ private function getUrl($correlationId, $settings)
282
+ {
283
+ $path = CDData::CD_PLUGIN_BIZ_API_PATH_START
284
+ . '/' . $correlationId . '/'
285
+ . CDData::CD_PLUGIN_BIZ_API_VERSION
286
+ . CDData::CD_PLUGIN_BIZ_API_PATH_END;
287
+ $useRawTestUrl = $settings['use_raw_test_url_for_biz_api'];
288
+ return $settings['test'] ? ($settings['test_server_url_start']
289
+ . ($useRawTestUrl ? '' : $path)) : (CDData::CD_HOST . $path);
290
+ }
291
  }
app/code/community/CartDefender/Actions/Model/CorrelationIdManager.php CHANGED
@@ -110,12 +110,22 @@ class CartDefender_Actions_Model_CorrelationIdManager extends Varien_Object
110
  if (!$corrIdExternal) {
111
  // Take id from header if not present on cookie
112
  $corrIdExternal = Mage::app()->getRequest()->getHeader(self::CD_CORRELATION_HEADER_NAME);
 
 
 
 
 
113
  }
114
  // If Correlation ID was not provided, generate it.
115
  $this->correlationId = $corrIdExternal ?: $this->generateCorrelationId();
116
  $phpSessionId = session_id();
117
  if (!$corrIdExternal && !empty($phpSessionId)) {
118
  $this->setCorrelationIdCookie();
 
 
 
 
 
119
  // Notify CD servers of new correlation id.
120
  $this->sender->sendEvent(
121
  CDData::START_OF_SESSION,
110
  if (!$corrIdExternal) {
111
  // Take id from header if not present on cookie
112
  $corrIdExternal = Mage::app()->getRequest()->getHeader(self::CD_CORRELATION_HEADER_NAME);
113
+ $this->logger->log(
114
+ 'CorrelationIdManager->ensureCorrelationIdSet', 'Taken from header, not from cookie'
115
+ . ' Correlation ID: '. $this->correlationId
116
+ . ' PHP Session ID: '. session_id()
117
+ );
118
  }
119
  // If Correlation ID was not provided, generate it.
120
  $this->correlationId = $corrIdExternal ?: $this->generateCorrelationId();
121
  $phpSessionId = session_id();
122
  if (!$corrIdExternal && !empty($phpSessionId)) {
123
  $this->setCorrelationIdCookie();
124
+ $this->logger->log(
125
+ 'CorrelationIdManager->ensureCorrelationIdSet', 'Generated and set on cookie'
126
+ . ' Correlation ID: '. $this->correlationId
127
+ . ' PHP Session ID: '. session_id()
128
+ );
129
  // Notify CD servers of new correlation id.
130
  $this->sender->sendEvent(
131
  CDData::START_OF_SESSION,
app/code/community/CartDefender/Actions/Model/EventAsyncLocalSender.php CHANGED
@@ -42,10 +42,16 @@ class CartDefender_Actions_Model_EventAsyncLocalSender
42
  $data,
43
  $sequenceNo
44
  );
 
45
  $this->send($event, $sequenceNo, $correlationId);
 
 
46
  $this->logger->log(
47
- 'EventAsyncLocalSender->sendEvent',
48
- 'Sent event: ' . $eventName
 
 
 
49
  );
50
  }
51
  }
42
  $data,
43
  $sequenceNo
44
  );
45
+ $millisBefore = round(microtime(true) * 1000);
46
  $this->send($event, $sequenceNo, $correlationId);
47
+ $millisAfter = round(microtime(true) * 1000);
48
+
49
  $this->logger->log(
50
+ 'EventAsyncLocalSender->sendEvent', ' Correlation ID: '. $correlationId
51
+ . ' PHP Session ID: '. session_id()
52
+ . ' Sent event: ' . $eventName
53
+ . ' Request time: ' . $millisBefore
54
+ . ' Request latency: ' . ($millisAfter - $millisBefore)
55
  );
56
  }
57
  }
app/code/community/CartDefender/Actions/Model/EventBuilder.php CHANGED
@@ -66,6 +66,11 @@ class CartDefender_Actions_Model_EventBuilder
66
  );
67
  $done = array();
68
  $utf8izedEvent = Mage::helper('actions')->utf8ize($event, $done);
 
 
 
 
 
69
  return Zend_Json::encode($utf8izedEvent, true);
70
  }
71
 
@@ -133,17 +138,46 @@ class CartDefender_Actions_Model_EventBuilder
133
  $cartData = $this->removePersonalData($quote->getData());
134
  $productMediaConfig = Mage::getModel('catalog/product_media_config');
135
  $items = $quote->getAllVisibleItems();
 
136
  foreach ($items as $item) {
137
  $itemData = $item->getData();
138
  $productFromData = $itemData['product'];
139
- $productUrl = Mage::getUrl($productFromData->getUrlPath(), array('_secure' => true, '_type' => 'direct_link'));
140
- $itemData['product_url'] = $productUrl;
141
- $itemData['base_image_url'] = $productMediaConfig->getMediaUrl($productFromData->getImage());
142
- $itemData['small_image_url'] = $productMediaConfig->getMediaUrl($productFromData->getSmallImage());
143
- $itemData['thumbnail_url'] = $productMediaConfig->getMediaUrl($productFromData->getThumbnail());
144
- $itemData['product_data'] = $productFromData->getData();
145
  $cartItems[] = $itemData;
146
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
  } else {
148
  $quote = CDData::MISSING_VALUE;
149
  $cartData[] = CDData::MISSING_VALUE;
66
  );
67
  $done = array();
68
  $utf8izedEvent = Mage::helper('actions')->utf8ize($event, $done);
69
+ $logger = Mage::helper('actions/logger');
70
+ $logger->log(
71
+ 'EventBuilder->buildEvent',
72
+ 'Built event: ' . $eventName
73
+ );
74
  return Zend_Json::encode($utf8izedEvent, true);
75
  }
76
 
138
  $cartData = $this->removePersonalData($quote->getData());
139
  $productMediaConfig = Mage::getModel('catalog/product_media_config');
140
  $items = $quote->getAllVisibleItems();
141
+ $productIds = array();
142
  foreach ($items as $item) {
143
  $itemData = $item->getData();
144
  $productFromData = $itemData['product'];
145
+ $productIds[] = $productFromData->getId();
 
 
 
 
 
146
  $cartItems[] = $itemData;
147
  }
148
+ if (! empty($productIds)) {
149
+ Mage::getResourceModel('catalog/product_collection')->setStore($storeId);
150
+ $collection = Mage::getResourceModel('catalog/product_collection');
151
+
152
+ $prodCollection = Mage::getModel('catalog/product')->getCollection()
153
+ ->setStore(Mage::app()->getStore()->getStoreId())
154
+ ->addAttributeToSelect('entity_id')
155
+ ->addAttributeToSelect('meta_title')
156
+ ->addAttributeToSelect('name')
157
+ ->addAttributeToSelect('short_description')
158
+ ->addAttributeToSelect('price')
159
+ ->addAttributeToSelect('final_price')
160
+ ->addAttributeToSelect('image')
161
+ ->addAttributeToSelect('small_image')
162
+ ->addAttributeToSelect('thumbnail')
163
+ ->addAttributeToSelect('product_url')
164
+ ->addFieldToFilter('entity_id', array('in' => array(array_unique($productIds))
165
+ ));
166
+
167
+ $prodInfo = array();
168
+
169
+ foreach ($prodCollection as $prodData) {
170
+ $prodData->setStoreId(Mage::app()->getStore()->getStoreId());
171
+ $productUrl = $prodData->getProductUrl();
172
+ $prodArray = $prodData->getData();
173
+ $prodArray['cd_product_url'] = $productUrl;
174
+ $prodArray['cd_base_image_url'] = $productMediaConfig->getMediaUrl($prodData->getImage());
175
+ $prodArray['cd_small_image_url'] = $productMediaConfig->getMediaUrl($prodData->getSmallImage());
176
+ $prodArray['cd_thumbnail_url'] = $productMediaConfig->getMediaUrl($prodData->getThumbnail());
177
+ $prodInfo[] = $prodArray;
178
+ }
179
+ $cartData['cd_all_products_info'] = $prodInfo;
180
+ }
181
  } else {
182
  $quote = CDData::MISSING_VALUE;
183
  $cartData[] = CDData::MISSING_VALUE;
app/code/community/CartDefender/Actions/Model/Observer.php CHANGED
@@ -50,9 +50,9 @@ class CartDefender_Actions_Model_Observer extends Varien_Event_Observer
50
  }
51
 
52
  /**
53
- * Main event observer function.
54
  *
55
- * List of events: http://www.nicksays.co.uk/magento-events-cheat-sheet-1-7/
56
  *
57
  * @param object $observer event data.
58
  * @return void
@@ -150,7 +150,10 @@ class CartDefender_Actions_Model_Observer extends Varien_Event_Observer
150
  $result = empty($lastEventAt)
151
  || (($now - $lastEventAt) > self::EVENT_TIME_THRESHOLD);
152
 
153
- $this->logger->log('Observer->isLongSinceLastEvent', 'Result: '
 
 
 
154
  . ($result ? 'Y' : 'N') . ' Time diff: '
155
  . ($lastEventAt ? ($now - $lastEventAt): 'N/A'));
156
  return $result;
50
  }
51
 
52
  /**
53
+ * Main event observer function for selected Magento events.
54
  *
55
+ * FYI, full list of events: http://www.nicksays.co.uk/magento-events-cheat-sheet-1-7/
56
  *
57
  * @param object $observer event data.
58
  * @return void
150
  $result = empty($lastEventAt)
151
  || (($now - $lastEventAt) > self::EVENT_TIME_THRESHOLD);
152
 
153
+ $this->logger->log('Observer->isLongSinceLastEvent', ' Correlation ID: '
154
+ . $this->correlationIdMgr->getCorrelationId()
155
+ . ' PHP Session ID: '. session_id()
156
+ . 'Result: '
157
  . ($result ? 'Y' : 'N') . ' Time diff: '
158
  . ($lastEventAt ? ($now - $lastEventAt): 'N/A'));
159
  return $result;
app/code/community/CartDefender/Actions/Model/System/Config/Source/Transport.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class CartDefender_Actions_Model_System_Config_Source_Transport
4
+ {
5
+ const ASYNC_SOCKET = 'Async PHP script';
6
+ const CURL_PROCESS = 'Async CURL process';
7
+ const SYNC_HTTP = 'Sync HTTP client';
8
+
9
+ /**
10
+ * Returns the value for transport mode selection in the admin config panel.
11
+ */
12
+ public function toOptionArray()
13
+ {
14
+ return array(
15
+ array('value'=>self::ASYNC_SOCKET, 'label'=>self::ASYNC_SOCKET),
16
+ array('value'=>self::CURL_PROCESS, 'label'=>self::CURL_PROCESS),
17
+ array('value'=>self::SYNC_HTTP, 'label'=>self::SYNC_HTTP)
18
+ );
19
+ }
20
+ }
app/code/community/CartDefender/Actions/controllers/CartDefenderSenderController.php CHANGED
@@ -64,6 +64,11 @@ class CartDefender_Actions_CartDefenderSenderController
64
  {
65
  $settings = Mage::helper('actions')->getSettings();
66
  $request = $this->getRequest();
 
 
 
 
 
67
  if ($this->isRequestAllowed($request, $settings)) {
68
  $millisBefore = round(microtime(true) * 1000);
69
 
@@ -79,15 +84,23 @@ class CartDefender_Actions_CartDefenderSenderController
79
  . ' Url: ' . $this->getUrl($settings)
80
  . ' Request time: ' . $millisBefore
81
  . ' Request latency: ' . ($millisAfter - $millisBefore)
 
 
 
82
  );
83
  } else {
84
  $this->logger->log(
85
  'CartDefenderSenderController->sendAction',
86
- 'Error - request not allowed.'
 
 
87
  );
88
  exit;
89
  }
90
- $this->logger->log('CartDefenderSenderController->sendAction', 'Done');
 
 
 
91
  echo 'Done';
92
  exit;
93
  }
@@ -137,10 +150,11 @@ class CartDefender_Actions_CartDefenderSenderController
137
  private function sendRequest($request, $settings)
138
  {
139
  $client = new Varien_Http_Client($this->getUrl($settings));
 
140
  $client->setMethod(Varien_Http_Client::POST);
141
  $client->setAuth($settings['api'], '', Zend_Http_Client::AUTH_BASIC);
142
  $client->setRawData($request->getPost('data'));
143
  $client->setEncType('application/json');
144
- return $client->request();
145
  }
146
  }
64
  {
65
  $settings = Mage::helper('actions')->getSettings();
66
  $request = $this->getRequest();
67
+ $this->logger->log(
68
+ 'CartDefenderSenderController->sendAction',
69
+ 'Received request with Correlation ID: ' . $request->getPost('correlation_id')
70
+ . ' PHP Session ID: ' . session_id()
71
+ );
72
  if ($this->isRequestAllowed($request, $settings)) {
73
  $millisBefore = round(microtime(true) * 1000);
74
 
84
  . ' Url: ' . $this->getUrl($settings)
85
  . ' Request time: ' . $millisBefore
86
  . ' Request latency: ' . ($millisAfter - $millisBefore)
87
+ . ' Status code: ' . $response->getStatus()
88
+ . ' Correlation ID: ' . $request->getPost('correlation_id')
89
+ . ' PHP Session ID: ' . session_id()
90
  );
91
  } else {
92
  $this->logger->log(
93
  'CartDefenderSenderController->sendAction',
94
+ 'Error - request not allowed. '
95
+ . 'Correlation ID: ' . $request->getPost('correlation_id')
96
+ . 'PHP Session ID: ' . session_id()
97
  );
98
  exit;
99
  }
100
+ $this->logger->log('CartDefenderSenderController->sendAction', 'Done'
101
+ . 'Correlation ID: ' . $request->getPost('correlation_id')
102
+ . 'PHP Session ID: ' . session_id()
103
+ );
104
  echo 'Done';
105
  exit;
106
  }
150
  private function sendRequest($request, $settings)
151
  {
152
  $client = new Varien_Http_Client($this->getUrl($settings));
153
+ $client->setConfig(array('strictredirects' => true));
154
  $client->setMethod(Varien_Http_Client::POST);
155
  $client->setAuth($settings['api'], '', Zend_Http_Client::AUTH_BASIC);
156
  $client->setRawData($request->getPost('data'));
157
  $client->setEncType('application/json');
158
+ return $client->request('POST');
159
  }
160
  }
app/code/community/CartDefender/Actions/etc/api.xml ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <api>
4
+ <resources>
5
+ <cartdefender_product_feed>
6
+ <model>actions/api</model>
7
+ <title>Cart Defender's product feed API</title>
8
+ <acl>cartdefender</acl>
9
+ <methods>
10
+ <export translate="title" module="actions">
11
+ <title>Retrieve store's products</title>
12
+ <method>export</method>
13
+ </export>
14
+ <getVersion translate="title" module="actions">
15
+ <title>Retrieve store's products</title>
16
+ <method>getVersion</method>
17
+ </getVersion>
18
+ </methods>
19
+ </cartdefender_product_feed>
20
+
21
+ </resources>
22
+ <v2>
23
+ <resources_function_prefix>
24
+ <cartdefender_product_feed>cartdefender_productFeed</cartdefender_product_feed>
25
+ </resources_function_prefix>
26
+ </v2>
27
+ <acl>
28
+ <resources>
29
+ <cartdefender translate="title" module="actions">
30
+ <title>Cart Defender product feed data</title>
31
+ <product_export translate="title" module="actions">
32
+ <title>Product export</title>
33
+ </product_export>
34
+ </cartdefender>
35
+ </resources>
36
+ </acl>
37
+ </api>
38
+ </config>
app/code/community/CartDefender/Actions/etc/config.xml CHANGED
@@ -12,7 +12,7 @@
12
  <config>
13
  <modules>
14
  <CartDefender_Actions>
15
- <version>2.0.2</version>
16
  </CartDefender_Actions>
17
  </modules>
18
 
@@ -54,24 +54,6 @@
54
  </cartdefender_checkout_cart_save_after>
55
  </observers>
56
  </checkout_cart_save_after>
57
- <checkout_controller_multishipping_shipping_post>
58
- <observers>
59
- <cartdefender_checkout_controller_multishipping_shipping_post>
60
- <type>singleton</type>
61
- <class>CartDefender_Actions_Model_Observer</class>
62
- <method>captureEvent</method>
63
- </cartdefender_checkout_controller_multishipping_shipping_post>
64
- </observers>
65
- </checkout_controller_multishipping_shipping_post>
66
- <checkout_controller_onepage_save_shipping_method>
67
- <observers>
68
- <cartdefender_checkout_controller_onepage_save_shipping_method>
69
- <type>singleton</type>
70
- <class>CartDefender_Actions_Model_Observer</class>
71
- <method>captureEvent</method>
72
- </cartdefender_checkout_controller_onepage_save_shipping_method>
73
- </observers>
74
- </checkout_controller_onepage_save_shipping_method>
75
  <checkout_multishipping_controller_success_action>
76
  <observers>
77
  <cartdefender_checkout_multishipping_controller_success_action>
@@ -135,69 +117,15 @@
135
  </cartdefender_order_cancel_after>
136
  </observers>
137
  </order_cancel_after>
138
- <sales_order_payment_cancel>
139
- <observers>
140
- <cartdefender_sales_order_payment_cancel>
141
- <type>singleton</type>
142
- <class>CartDefender_Actions_Model_Observer</class>
143
- <method>captureEvent</method>
144
- </cartdefender_sales_order_payment_cancel>
145
- </observers>
146
- </sales_order_payment_cancel>
147
- <sales_order_payment_capture>
148
- <observers>
149
- <cartdefender_sales_order_payment_capture>
150
- <type>singleton</type>
151
- <class>CartDefender_Actions_Model_Observer</class>
152
- <method>captureEvent</method>
153
- </cartdefender_sales_order_payment_capture>
154
- </observers>
155
- </sales_order_payment_capture>
156
- <sales_order_payment_pay>
157
- <observers>
158
- <cartdefender_sales_order_payment_pay>
159
- <type>singleton</type>
160
- <class>CartDefender_Actions_Model_Observer</class>
161
- <method>captureEvent</method>
162
- </cartdefender_sales_order_payment_pay>
163
- </observers>
164
- </sales_order_payment_pay>
165
- <sales_order_payment_place_end>
166
- <observers>
167
- <cartdefender_sales_order_payment_place_end>
168
- <type>singleton</type>
169
- <class>CartDefender_Actions_Model_Observer</class>
170
- <method>captureEvent</method>
171
- </cartdefender_sales_order_payment_place_end>
172
- </observers>
173
- </sales_order_payment_place_end>
174
- <sales_order_payment_place_start>
175
- <observers>
176
- <cartdefender_sales_order_payment_place_start>
177
- <type>singleton</type>
178
- <class>CartDefender_Actions_Model_Observer</class>
179
- <method>captureEvent</method>
180
- </cartdefender_sales_order_payment_place_start>
181
- </observers>
182
- </sales_order_payment_place_start>
183
- <sales_order_payment_refund>
184
- <observers>
185
- <cartdefender_sales_order_payment_refund>
186
- <type>singleton</type>
187
- <class>CartDefender_Actions_Model_Observer</class>
188
- <method>captureEvent</method>
189
- </cartdefender_sales_order_payment_refund>
190
- </observers>
191
- </sales_order_payment_refund>
192
- <sales_order_payment_void>
193
  <observers>
194
- <cartdefender_sales_order_payment_void>
195
  <type>singleton</type>
196
  <class>CartDefender_Actions_Model_Observer</class>
197
  <method>captureEvent</method>
198
- </cartdefender_sales_order_payment_void>
199
  </observers>
200
- </sales_order_payment_void>
201
  <controller_action_predispatch_checkout_onepage_index>
202
  <observers>
203
  <cartdefender_controller_action_predispatch_checkout_onepage_index>
12
  <config>
13
  <modules>
14
  <CartDefender_Actions>
15
+ <version>2.1.8</version>
16
  </CartDefender_Actions>
17
  </modules>
18
 
54
  </cartdefender_checkout_cart_save_after>
55
  </observers>
56
  </checkout_cart_save_after>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  <checkout_multishipping_controller_success_action>
58
  <observers>
59
  <cartdefender_checkout_multishipping_controller_success_action>
117
  </cartdefender_order_cancel_after>
118
  </observers>
119
  </order_cancel_after>
120
+ <sales_order_place_after>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  <observers>
122
+ <cartdefender_sales_order_place_after>
123
  <type>singleton</type>
124
  <class>CartDefender_Actions_Model_Observer</class>
125
  <method>captureEvent</method>
126
+ </cartdefender_sales_order_place_after>
127
  </observers>
128
+ </sales_order_place_after>
129
  <controller_action_predispatch_checkout_onepage_index>
130
  <observers>
131
  <cartdefender_controller_action_predispatch_checkout_onepage_index>
app/code/community/CartDefender/Actions/etc/system.xml CHANGED
@@ -44,7 +44,7 @@
44
  <sort_order>1</sort_order>
45
  <show_in_default>1</show_in_default>
46
  <show_in_website>1</show_in_website>
47
- <show_in_store>1</show_in_store>
48
  </enabled>
49
  <api translate="label">
50
  <label>API key</label>
@@ -52,33 +52,65 @@
52
  <sort_order>2</sort_order>
53
  <show_in_default>1</show_in_default>
54
  <show_in_website>1</show_in_website>
55
- <show_in_store>1</show_in_store>
56
  </api>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  <send_key translate="label">
58
- <label>Generated internal request key</label>
59
  <frontend_type>text</frontend_type>
60
- <sort_order>3</sort_order>
61
  <show_in_default>1</show_in_default>
62
- <show_in_website>0</show_in_website>
63
  <show_in_store>0</show_in_store>
64
  </send_key>
65
  <test translate="label">
66
  <label>Test mode</label>
67
  <frontend_type>select</frontend_type>
68
  <source_model>adminhtml/system_config_source_yesno</source_model>
69
- <sort_order>4</sort_order>
70
  <show_in_default>1</show_in_default>
71
  <show_in_website>1</show_in_website>
72
- <show_in_store>1</show_in_store>
 
 
 
 
73
  </test>
74
  <!-- Don't use a trailing slash in test server URL.-->
75
  <test_server_url_start>
76
- <label>Send data to this URL: protocol, domain, and path prefix if any (e.g. http://localhost)</label>
77
  <frontend_type>text</frontend_type>
78
- <sort_order>5</sort_order>
79
  <show_in_default>1</show_in_default>
80
  <show_in_website>1</show_in_website>
81
- <show_in_store>1</show_in_store>
82
  <depends><test>1</test></depends>
83
  </test_server_url_start>
84
  <!-- This setting controls if the "Test server URL" value is used exactly
@@ -89,10 +121,10 @@
89
  <label>Use unadorned target server URL for JSON API</label>
90
  <frontend_type>select</frontend_type>
91
  <source_model>adminhtml/system_config_source_yesno</source_model>
92
- <sort_order>6</sort_order>
93
  <show_in_default>1</show_in_default>
94
  <show_in_website>1</show_in_website>
95
- <show_in_store>1</show_in_store>
96
  <depends><test>1</test></depends>
97
  </use_raw_test_url_for_biz_api>
98
  </fields>
44
  <sort_order>1</sort_order>
45
  <show_in_default>1</show_in_default>
46
  <show_in_website>1</show_in_website>
47
+ <show_in_store>0</show_in_store>
48
  </enabled>
49
  <api translate="label">
50
  <label>API key</label>
52
  <sort_order>2</sort_order>
53
  <show_in_default>1</show_in_default>
54
  <show_in_website>1</show_in_website>
55
+ <show_in_store>0</show_in_store>
56
  </api>
57
+ <transport_method translate="label">
58
+ <label>Select how data is sent to Cart Defender</label>
59
+ <frontend_type>select</frontend_type>
60
+ <source_model>actions/system_config_source_transport</source_model>
61
+ <sort_order>3</sort_order>
62
+ <show_in_default>1</show_in_default>
63
+ <show_in_website>1</show_in_website>
64
+ <show_in_store>0</show_in_store>
65
+ <comment><![CDATA[ <p>Please select the method that will work best in your system:</p>
66
+ <p>CURL requires access to the exec() function to fork a separate process.</p>
67
+ <p>Async PHP script relies on a separate Controller which sends data to Cart Defender.</p>
68
+ <p>Synchronous PHP is encouraged when testing the connection.</p>
69
+ ]]>
70
+ </comment>
71
+ </transport_method>
72
+ <sender_controller_url translate="label">
73
+ <label>Cart Defender Sender Controller URL (auto-populated)</label>
74
+ <frontend_type>text</frontend_type>
75
+ <sort_order>4</sort_order>
76
+ <show_in_default>1</show_in_default>
77
+ <show_in_website>1</show_in_website>
78
+ <show_in_store>0</show_in_store>
79
+ <depends><transport_method>Async PHP script</transport_method></depends>
80
+ <comment><![CDATA[ <p>This is the URL of the internal Async PHP controller. It is populated automatically if left blank.
81
+ Afterwards, changes might be required to tweak the URL according to your website setup.</p>
82
+ ]]>
83
+ </comment>
84
+ </sender_controller_url>
85
  <send_key translate="label">
86
+ <label>Internal request key (generated)</label>
87
  <frontend_type>text</frontend_type>
88
+ <sort_order>5</sort_order>
89
  <show_in_default>1</show_in_default>
90
+ <show_in_website>1</show_in_website>
91
  <show_in_store>0</show_in_store>
92
  </send_key>
93
  <test translate="label">
94
  <label>Test mode</label>
95
  <frontend_type>select</frontend_type>
96
  <source_model>adminhtml/system_config_source_yesno</source_model>
97
+ <sort_order>6</sort_order>
98
  <show_in_default>1</show_in_default>
99
  <show_in_website>1</show_in_website>
100
+ <show_in_store>0</show_in_store>
101
+ <comment><![CDATA[ <p>Test mode enables logging (into a separate file: cartdefender.log)
102
+ and allows to configure the URL where the data is send to.</p>
103
+ ]]>
104
+ </comment>
105
  </test>
106
  <!-- Don't use a trailing slash in test server URL.-->
107
  <test_server_url_start>
108
+ <label>Send data to this target URL: protocol, domain, and path prefix if any (e.g. http://localhost)</label>
109
  <frontend_type>text</frontend_type>
110
+ <sort_order>7</sort_order>
111
  <show_in_default>1</show_in_default>
112
  <show_in_website>1</show_in_website>
113
+ <show_in_store>0</show_in_store>
114
  <depends><test>1</test></depends>
115
  </test_server_url_start>
116
  <!-- This setting controls if the "Test server URL" value is used exactly
121
  <label>Use unadorned target server URL for JSON API</label>
122
  <frontend_type>select</frontend_type>
123
  <source_model>adminhtml/system_config_source_yesno</source_model>
124
+ <sort_order>8</sort_order>
125
  <show_in_default>1</show_in_default>
126
  <show_in_website>1</show_in_website>
127
+ <show_in_store>0</show_in_store>
128
  <depends><test>1</test></depends>
129
  </use_raw_test_url_for_biz_api>
130
  </fields>
app/design/frontend/base/default/template/actions/script.phtml CHANGED
@@ -11,7 +11,7 @@
11
 
12
  <?php if ($this->getSetting('enabled')) { ?>
13
  <?php if ($this->getSetting('test')) { ?>
14
- <p> Cart Defender Actions module is running in TEST MODE. </p>
15
  <?php } ?>
16
  <script type='text/javascript'>
17
  /* <![CDATA[ */
11
 
12
  <?php if ($this->getSetting('enabled')) { ?>
13
  <?php if ($this->getSetting('test')) { ?>
14
+ <p hidden> Cart Defender Actions module is running in TEST MODE. </p>
15
  <?php } ?>
16
  <script type='text/javascript'>
17
  /* <![CDATA[ */
package.xml CHANGED
@@ -1,19 +1,19 @@
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>cartdefender_actions</name>
4
- <version>2.1.0</version>
5
  <stability>stable</stability>
6
  <license uri="http://opensource.org/licenses/osl-3.0.php">Open Software License (OSL)</license>
7
  <channel>community</channel>
8
  <extends/>
9
  <summary>Increase sales with this state-of-the-art product recommendations and targeted popups, including a FREE exit intent message. Engage your visitors in real time or later via email!</summary>
10
  <description>You can instantly use product recommendations, messages and offers which convert your visitors into customers. Start with FREE exit intent messages. Do it without A/B tests, because Cart Defender learns which messages convert the best and adjusts itself automatically.</description>
11
- <notes>Product recommendation included. Plugin sends more data about products to Cart Defender.&#xD;
12
  </notes>
13
  <authors><author><name>Radoslaw Gliniecki</name><user>Cart_Defender</user><email>radek@cartdefender.com</email></author><author><name>Jan Zankowski</name><user>janzankowski</user><email>jan@cartdefender.com</email></author><author><name>Przemyslaw Gliniecki</name><user>psgliniecki</user><email>psg@cartdefender.com</email></author></authors>
14
- <date>2017-03-13</date>
15
- <time>20:14:21</time>
16
- <contents><target name="magecommunity"><dir name="CartDefender"><dir name="Actions"><dir name="Block"><file name="Script.php" hash="247305c63594b6442e94122b226e3bb2"/></dir><dir name="Helper"><file name="Data.php" hash="dd4057deaaa8b0bdcfcc3e6f7c31091c"/><file name="Logger.php" hash="f21b3aed521b3761a890b22ba0f247a9"/></dir><dir name="Model"><file name="AsyncLocalSender.php" hash="f92a25257a8262840019eaff9eb0a387"/><file name="CorrelationIdManager.php" hash="7215fd45ca052d5bde16e93d278565be"/><file name="EventAsyncLocalSender.php" hash="cd9a25e21225cb1966da47fbbc8f9854"/><file name="EventBuilder.php" hash="fb4642447e925748ec47f4620d26b4c0"/><file name="Observer.php" hash="f34856aad9bf7aeb870317f6548eb349"/></dir><dir name="controllers"><file name="CartDefenderSenderController.php" hash="f35bb2528ccab59c3e2df3efa8172fd2"/></dir><dir name="etc"><file name="config.xml" hash="b9d1b6f7bb362aa490d2f13f38695867"/><file name="system.xml" hash="3b03c1e1412712cbba28a999dd52514c"/></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="CartDefender_Actions.xml" hash="f9e77235e41f79ac086160ef2e494837"/></dir></target><target name="magedesign"><dir name="frontend"><dir name="base"><dir name="default"><dir name="template"><dir name="actions"><file name="script.phtml" hash="aa322fad9cd04ae7c910936e043fa8f1"/></dir></dir><dir name="layout"><file name="actions.xml" hash="e6a4b2f6d8132a833a1b5f8b9fce7166"/></dir></dir></dir></dir></target></contents>
17
  <compatible/>
18
  <dependencies><required><php><min>5.3.0</min><max>6.0.0</max></php><package><name>Mage_Core_Modules</name><channel>community</channel><min>1.7.0.2</min><max>1.9.3.2</max></package><extension><name>openssl</name><min>0.9.6</min><max>1.1.0</max></extension></required></dependencies>
19
  </package>
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>cartdefender_actions</name>
4
+ <version>2.1.8</version>
5
  <stability>stable</stability>
6
  <license uri="http://opensource.org/licenses/osl-3.0.php">Open Software License (OSL)</license>
7
  <channel>community</channel>
8
  <extends/>
9
  <summary>Increase sales with this state-of-the-art product recommendations and targeted popups, including a FREE exit intent message. Engage your visitors in real time or later via email!</summary>
10
  <description>You can instantly use product recommendations, messages and offers which convert your visitors into customers. Start with FREE exit intent messages. Do it without A/B tests, because Cart Defender learns which messages convert the best and adjusts itself automatically.</description>
11
+ <notes>Compatibility updates in data gathering&#xD;
12
  </notes>
13
  <authors><author><name>Radoslaw Gliniecki</name><user>Cart_Defender</user><email>radek@cartdefender.com</email></author><author><name>Jan Zankowski</name><user>janzankowski</user><email>jan@cartdefender.com</email></author><author><name>Przemyslaw Gliniecki</name><user>psgliniecki</user><email>psg@cartdefender.com</email></author></authors>
14
+ <date>2017-05-04</date>
15
+ <time>13:59:52</time>
16
+ <contents><target name="magecommunity"><dir name="CartDefender"><dir name="Actions"><dir name="Block"><file name="Script.php" hash="247305c63594b6442e94122b226e3bb2"/></dir><dir name="Helper"><file name="Data.php" hash="f6da7288d3b111b4e9d82aeee64aebb6"/><file name="Logger.php" hash="aca3233298074d3cf8f436e668969bb9"/></dir><dir name="Model"><dir name="Api"><file name="V2.php" hash="64b8b03a84578a6f9a1fbf1321e109f2"/></dir><file name="Api.php" hash="a2d9ede9d01bb14ff31ebd792c9bbc51"/><file name="AsyncLocalSender.php" hash="2e22d4c07c7f983d98687d6faa6fe413"/><file name="CorrelationIdManager.php" hash="56f619241fdec54bcc4457937af893b8"/><file name="EventAsyncLocalSender.php" hash="4bcc43959212d0610e3e4b653d01c6cc"/><file name="EventBuilder.php" hash="18f0e4637a03fb6ea767fcab375a0984"/><file name="Observer.php" hash="44922ecc47fdf4a60fa86b929c5877c8"/><dir name="System"><dir name="Config"><dir name="Source"><file name="Transport.php" hash="f63ca41ae1242de7bb18854d0f450b00"/></dir></dir></dir></dir><dir name="controllers"><file name="CartDefenderSenderController.php" hash="c3fb495d4ad88ac658867c77447d2b2b"/></dir><dir name="etc"><file name="api.xml" hash="3d9558fa5df621470460d4c9d62ba7f3"/><file name="config.xml" hash="ec73ff2a9115f7150b034f3e6eacd163"/><file name="system.xml" hash="3bc66fa6869648811f2283f54abac2f5"/></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="CartDefender_Actions.xml" hash="f9e77235e41f79ac086160ef2e494837"/></dir></target><target name="magedesign"><dir name="frontend"><dir name="base"><dir name="default"><dir name="template"><dir name="actions"><file name="script.phtml" hash="4de68c84b01a9532595d2d13c494ef6c"/></dir></dir><dir name="layout"><file name="actions.xml" hash="e6a4b2f6d8132a833a1b5f8b9fce7166"/></dir></dir></dir></dir></target></contents>
17
  <compatible/>
18
  <dependencies><required><php><min>5.3.0</min><max>6.0.0</max></php><package><name>Mage_Core_Modules</name><channel>community</channel><min>1.7.0.2</min><max>1.9.3.2</max></package><extension><name>openssl</name><min>0.9.6</min><max>1.1.0</max></extension></required></dependencies>
19
  </package>