Channelpilotsolutions_Channelpilot - Version 2.2.6

Version Notes

- general bugfixes
- added index for product feed export

Download this release

Release Info

Developer Magento Core Team
Extension Channelpilotsolutions_Channelpilot
Version 2.2.6
Comparing to
See all releases


Code changes from version 2.2.5 to 2.2.6

Files changed (41) hide show
  1. app/code/community/Channelpilotsolutions/Channelpilot/Block/Adminhtml/Feedexport.php +43 -0
  2. app/code/community/Channelpilotsolutions/Channelpilot/Block/Adminhtml/Feedexport/Grid.php +87 -0
  3. app/code/community/Channelpilotsolutions/Channelpilot/Block/Adminhtml/Feedexport/View.php +53 -0
  4. app/code/community/Channelpilotsolutions/Channelpilot/Block/Adminhtml/Feedexport/View/Form.php +61 -0
  5. app/code/community/Channelpilotsolutions/Channelpilot/Helper/Data.php +15 -4
  6. app/code/community/Channelpilotsolutions/Channelpilot/Helper/Export.php +759 -0
  7. app/code/community/Channelpilotsolutions/Channelpilot/Helper/api/1_0/ChannelPilotSellerAPI_v1_0.php +8 -2
  8. app/code/community/Channelpilotsolutions/Channelpilot/Helper/handler/CPAbstractHandler.php +33 -30
  9. app/code/community/Channelpilotsolutions/Channelpilot/Helper/handler/CPCancellationHandler.php +4 -5
  10. app/code/community/Channelpilotsolutions/Channelpilot/Helper/handler/CPDeliveryHandler.php +104 -25
  11. app/code/community/Channelpilotsolutions/Channelpilot/Helper/handler/CPExportHandler.php +48 -593
  12. app/code/community/Channelpilotsolutions/Channelpilot/Helper/handler/CPNewPriceHandler.php +89 -48
  13. app/code/community/Channelpilotsolutions/Channelpilot/Helper/handler/CPOrderHandler.php +152 -35
  14. app/code/community/Channelpilotsolutions/Channelpilot/Helper/handler/CPPaymentHandler.php +1 -1
  15. app/code/community/Channelpilotsolutions/Channelpilot/Helper/handler/CPRegisterHandler.php +0 -1
  16. app/code/community/Channelpilotsolutions/Channelpilot/Helper/handler/CPStatusHandler.php +4 -4
  17. app/code/community/Channelpilotsolutions/Channelpilot/Helper/responses/CPHookResponse.php +1 -1
  18. app/code/community/Channelpilotsolutions/Channelpilot/Model/Abstract.php +4 -4
  19. app/code/community/Channelpilotsolutions/Channelpilot/Model/Adminhtml/Source/Exportmethod.php +34 -0
  20. app/code/community/Channelpilotsolutions/Channelpilot/Model/Adminhtml/Source/Producturlgeneration.php +40 -0
  21. app/code/community/Channelpilotsolutions/Channelpilot/Model/Carrier/Cpshipping.php +2 -2
  22. app/code/community/Channelpilotsolutions/Channelpilot/Model/Feedexport/Indexer.php +150 -0
  23. app/code/community/Channelpilotsolutions/Channelpilot/Model/Observer.php +99 -0
  24. app/code/community/Channelpilotsolutions/Channelpilot/Model/Resource/Feedexport/Indexer.php +213 -0
  25. app/code/community/Channelpilotsolutions/Channelpilot/Model/Resource/Feedexport/Indexer/Collection.php +32 -0
  26. app/code/community/Channelpilotsolutions/Channelpilot/controllers/Adminhtml/Channelpilot/FeedexportController.php +55 -0
  27. app/code/community/Channelpilotsolutions/Channelpilot/etc/adminhtml.xml +24 -1
  28. app/code/community/Channelpilotsolutions/Channelpilot/etc/config.xml +43 -8
  29. app/code/community/Channelpilotsolutions/Channelpilot/etc/system.xml +34 -6
  30. app/code/community/Channelpilotsolutions/Channelpilot/sql/channelpilot_setup/mysql4-upgrade-2.1.0-2.1.6.php +51 -0
  31. app/code/community/Channelpilotsolutions/Channelpilot/sql/channelpilot_setup/mysql4-upgrade-2.2.5-2.2.6.php +37 -27
  32. app/locale/de_AT/Channelpilotsolutions_Channelpilot.csv +27 -1
  33. app/locale/de_CH/Channelpilotsolutions_Channelpilot.csv +27 -1
  34. app/locale/de_DE/Channelpilotsolutions_Channelpilot.csv +27 -1
  35. app/locale/en_AU/Channelpilotsolutions_Channelpilot.csv +27 -1
  36. app/locale/en_CA/Channelpilotsolutions_Channelpilot.csv +27 -1
  37. app/locale/en_GB/Channelpilotsolutions_Channelpilot.csv +27 -1
  38. app/locale/en_IE/Channelpilotsolutions_Channelpilot.csv +27 -1
  39. app/locale/en_NZ/Channelpilotsolutions_Channelpilot.csv +27 -1
  40. app/locale/en_US/Channelpilotsolutions_Channelpilot.csv +27 -1
  41. package.xml +5 -6
app/code/community/Channelpilotsolutions/Channelpilot/Block/Adminhtml/Feedexport.php ADDED
@@ -0,0 +1,43 @@
1
+ <?php
2
+
3
+ /**
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the GNU General Public License (GPL 3)
8
+ * that is bundled with this package in the file LICENSE.txt
9
+ *
10
+ * DISCLAIMER
11
+ *
12
+ * Do not edit or add to this file if you wish to upgrade Channelpilotsolutions_Channelpilot to newer
13
+ * versions in the future. If you wish to customize Channelpilotsolutions_Channelpilot for your
14
+ * needs please refer to http://www.channelpilot.com for more information.
15
+ *
16
+ * @category Channelpilotsolutions
17
+ * @package Channelpilotsolutions_Channelpilot
18
+ * @copyright Copyright (c) 2012 <info@channelpilot.com> - www.channelpilot.com
19
+ * @author Björn Wehner <info@channelpilot.com>
20
+ * @license <http://www.gnu.org/licenses/> GNU General Public License (GPL 3)
21
+ * @link http://www.channelpilot.com
22
+ */
23
+ class Channelpilotsolutions_Channelpilot_Block_Adminhtml_Feedexport extends Mage_Adminhtml_Block_Widget_Grid_Container
24
+ {
25
+ public function __construct()
26
+ {
27
+ $this->_blockGroup = 'channelpilot_core';
28
+ $this->_controller = 'adminhtml_feedexport';
29
+ $this->_headerText = Mage::helper('channelpilot')->__('CP Channelpilot Product Feed Export');
30
+
31
+ parent::__construct();
32
+ $this->_removeButton('add');
33
+
34
+ $helper = Mage::helper('channelpilot');
35
+ $this->_addButton('truncate_index_table', array(
36
+ 'label' => $helper->__('CP Truncate Index Table'),
37
+ 'onclick' => "
38
+ if(confirm('{$helper->__('CP Warning, this will delete all entries and the data has to be reindexed. Proceed ?')}')) setLocation('{$this->getUrl('*/*/truncate')}')
39
+ ",
40
+ 'class' => 'delete'
41
+ ));
42
+ }
43
+ }
app/code/community/Channelpilotsolutions/Channelpilot/Block/Adminhtml/Feedexport/Grid.php ADDED
@@ -0,0 +1,87 @@
1
+ <?php
2
+
3
+ /**
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the GNU General Public License (GPL 3)
8
+ * that is bundled with this package in the file LICENSE.txt
9
+ *
10
+ * DISCLAIMER
11
+ *
12
+ * Do not edit or add to this file if you wish to upgrade Channelpilotsolutions_Channelpilot to newer
13
+ * versions in the future. If you wish to customize Channelpilotsolutions_Channelpilot for your
14
+ * needs please refer to http://www.channelpilot.com for more information.
15
+ *
16
+ * @category Channelpilotsolutions
17
+ * @package Channelpilotsolutions_Channelpilot
18
+ * @copyright Copyright (c) 2012 <info@channelpilot.com> - www.channelpilot.com
19
+ * @author Björn Wehner <info@channelpilot.com>
20
+ * @license <http://www.gnu.org/licenses/> GNU General Public License (GPL 3)
21
+ * @link http://www.channelpilot.com
22
+ */
23
+ class Channelpilotsolutions_Channelpilot_Block_Adminhtml_Feedexport_Grid extends Mage_Adminhtml_Block_Widget_Grid
24
+ {
25
+ public function __construct()
26
+ {
27
+ parent::__construct();
28
+ $this->setId('channelpilot_feed_export');
29
+ $this->setDefaultDir('product_id');
30
+ $this->setDefaultDir('ASC');
31
+ $this->setSaveParametersInSession(true);
32
+ $this->setUseAjax(false);
33
+ }
34
+
35
+ protected function _prepareCollection()
36
+ {
37
+ /** @var $storeSwitcherBlock Mage_Adminhtml_Block_Store_Switcher */
38
+ $storeSwitcherBlock = $this->getLayout()->getBlock('store_switcher');
39
+ $storeId = $storeSwitcherBlock->getStoreId();
40
+ $collection = Mage::getModel('channelpilot/feedexport_indexer')->getCollection()
41
+ ->addFieldToFilter('store_id', array('eq' => $storeId));
42
+
43
+ $this->setCollection($collection);
44
+ parent::_prepareCollection();
45
+
46
+ return $this;
47
+ }
48
+
49
+ protected function _prepareColumns()
50
+ {
51
+ $helper = Mage::helper('channelpilot');
52
+
53
+ $this->addColumn('product_id', array(
54
+ 'header' => $helper->__('CP Product ID'),
55
+ 'index' => 'product_id',
56
+ 'type' => 'text',
57
+ ));
58
+
59
+ $this->addColumn('sku', array(
60
+ 'header' => $helper->__('CP Product SKU'),
61
+ 'index' => 'sku',
62
+ 'type' => 'text',
63
+ ));
64
+
65
+ $this->addColumn('created_at', array(
66
+ 'header' => $helper->__('CP Created At'),
67
+ 'index' => 'created_at',
68
+ 'type' => 'datetime',
69
+ 'filter' => false,
70
+ ));
71
+
72
+ return parent::_prepareColumns();
73
+ }
74
+
75
+ public function getGridUrl()
76
+ {
77
+ return $this->getUrl('*/*/', array('_current' => true));
78
+ }
79
+
80
+ public function getRowUrl($row)
81
+ {
82
+ return $this->getUrl('*/*/view', array(
83
+ 'store'=>$this->getRequest()->getParam('store'),
84
+ 'product_id'=>$row->getProductId())
85
+ );
86
+ }
87
+ }
app/code/community/Channelpilotsolutions/Channelpilot/Block/Adminhtml/Feedexport/View.php ADDED
@@ -0,0 +1,53 @@
1
+ <?php
2
+
3
+ /**
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the GNU General Public License (GPL 3)
8
+ * that is bundled with this package in the file LICENSE.txt
9
+ *
10
+ * DISCLAIMER
11
+ *
12
+ * Do not edit or add to this file if you wish to upgrade Channelpilotsolutions_Channelpilot to newer
13
+ * versions in the future. If you wish to customize Channelpilotsolutions_Channelpilot for your
14
+ * needs please refer to http://www.channelpilot.com for more information.
15
+ *
16
+ * @category Channelpilotsolutions
17
+ * @package Channelpilotsolutions_Channelpilot
18
+ * @copyright Copyright (c) 2012 <info@channelpilot.com> - www.channelpilot.com
19
+ * @author Björn Wehner <info@channelpilot.com>
20
+ * @license <http://www.gnu.org/licenses/> GNU General Public License (GPL 3)
21
+ * @link http://www.channelpilot.com
22
+ */
23
+ class Channelpilotsolutions_Channelpilot_Block_Adminhtml_Feedexport_View extends Mage_Adminhtml_Block_Widget_Form_Container
24
+ {
25
+ public function __construct()
26
+ {
27
+ parent::__construct();
28
+
29
+ $this->_objectId = 'product_id';
30
+ $this->_blockGroup = 'channelpilot_core';
31
+ $this->_controller = 'adminhtml_feedexport';
32
+ $this->_mode = 'view';
33
+
34
+ $this->_removeButton('save');
35
+ $this->_removeButton('delete');
36
+ $this->_removeButton('reset');
37
+ }
38
+
39
+ public function getHeaderText()
40
+ {
41
+ $productId = $this->getRequest()->getParam('product_id');
42
+ $storeId = $this->getRequest()->getParam('store', 1);
43
+ $data = Mage::getResourceModel('channelpilot/feedexport_indexer')->getDataForProductIdAndStoreId($productId, $storeId);
44
+ Mage::register('cp_product_feed_data', $data);
45
+ return Mage::helper('channelpilot')->__('CP Showing feed export data for product %s and store %s - Created at: %s', $productId, $storeId, $data['created_at']);
46
+ }
47
+
48
+ public function getBackUrl()
49
+ {
50
+ $storeId = $this->getRequest()->getParam('store');
51
+ return $this->getUrl('*/*/', array('store' => $storeId));
52
+ }
53
+ }
app/code/community/Channelpilotsolutions/Channelpilot/Block/Adminhtml/Feedexport/View/Form.php ADDED
@@ -0,0 +1,61 @@
1
+ <?php
2
+
3
+ /**
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the GNU General Public License (GPL 3)
8
+ * that is bundled with this package in the file LICENSE.txt
9
+ *
10
+ * DISCLAIMER
11
+ *
12
+ * Do not edit or add to this file if you wish to upgrade Channelpilotsolutions_Channelpilot to newer
13
+ * versions in the future. If you wish to customize Channelpilotsolutions_Channelpilot for your
14
+ * needs please refer to http://www.channelpilot.com for more information.
15
+ *
16
+ * @category Channelpilotsolutions
17
+ * @package Channelpilotsolutions_Channelpilot
18
+ * @copyright Copyright (c) 2012 <info@channelpilot.com> - www.channelpilot.com
19
+ * @author Björn Wehner <info@channelpilot.com>
20
+ * @license <http://www.gnu.org/licenses/> GNU General Public License (GPL 3)
21
+ * @link http://www.channelpilot.com
22
+ */
23
+ class Channelpilotsolutions_Channelpilot_Block_Adminhtml_Feedexport_View_Form extends Mage_Adminhtml_Block_Widget_Form
24
+ {
25
+ protected function _prepareForm()
26
+ {
27
+ $form = new Varien_Data_Form(array(
28
+ 'id' => 'view_form',
29
+ 'action' => '',
30
+ 'method' => 'post',
31
+ ));
32
+ $form->setUseContainer(true);
33
+ $this->setForm($form);
34
+
35
+ $data = Mage::registry('cp_product_feed_data');
36
+
37
+ if(is_array($data) && isset($data['product_data'])) {
38
+ $productData = $data['product_data'];
39
+
40
+ $fieldset = $form->addFieldset('view_product_data', array(
41
+ ));
42
+
43
+ $xml = simplexml_load_string($productData);
44
+ $children = $xml->children();
45
+ $data = array();
46
+ foreach($children as $key => $value) {
47
+ $data[$key] = $value;
48
+ $fieldType = (strlen($value) > 50) ? 'textarea' : 'text';
49
+ $fieldset->addField($key, $fieldType, array(
50
+ 'label' => $key,
51
+ 'name' => $key,
52
+ 'disabled' => true,
53
+ ));
54
+ }
55
+
56
+ $form->setValues($data);
57
+ }
58
+
59
+ return parent::_prepareForm();
60
+ }
61
+ }
app/code/community/Channelpilotsolutions/Channelpilot/Helper/Data.php CHANGED
@@ -182,7 +182,7 @@ class Channelpilotsolutions_Channelpilot_Helper_Data extends Mage_Core_Helper_Ab
182
exit();
183
}
184
185
- private function checkSignature() {
186
$php = Mage::app()->getRequest()->getParam('php', false);
187
$shop = Mage::app()->getRequest()->getParam('shop', false);
188
$plugin = Mage::app()->getRequest()->getParam('plugin', false);
@@ -196,7 +196,7 @@ class Channelpilotsolutions_Channelpilot_Helper_Data extends Mage_Core_Helper_Ab
196
}
197
}
198
199
- private function checkActivation($configs, $function) {
200
foreach ($configs as $config) {
201
if ($config === true) {
202
return true;
@@ -205,12 +205,23 @@ class Channelpilotsolutions_Channelpilot_Helper_Data extends Mage_Core_Helper_Ab
205
CPErrorHandler::handle(CPErrors::RESULT_API_DEACTIVATED, "'$function' not activated", "'$function' not activated");
206
}
207
208
- private function checkIp() {
209
if (Mage::getStoreConfig('channelpilot_general/channelpilot_general/channelpilot_checkIp')) {
210
- return Mage::getModel('channelpilot/registration')->isIpAuthorized($_SERVER['REMOTE_ADDR']);
211
}
212
return true;
213
}
214
}
215
216
?>
182
exit();
183
}
184
185
+ protected function checkSignature() {
186
$php = Mage::app()->getRequest()->getParam('php', false);
187
$shop = Mage::app()->getRequest()->getParam('shop', false);
188
$plugin = Mage::app()->getRequest()->getParam('plugin', false);
196
}
197
}
198
199
+ protected function checkActivation($configs, $function) {
200
foreach ($configs as $config) {
201
if ($config === true) {
202
return true;
205
CPErrorHandler::handle(CPErrors::RESULT_API_DEACTIVATED, "'$function' not activated", "'$function' not activated");
206
}
207
208
+ protected function checkIp() {
209
if (Mage::getStoreConfig('channelpilot_general/channelpilot_general/channelpilot_checkIp')) {
210
+ return Mage::getModel('channelpilot/registration')->isIpAuthorized(Mage::app()->getRequest()->getClientIp());
211
}
212
return true;
213
}
214
+
215
+ public function getAllStoreIds() {
216
+ $storeIds = array();
217
+
218
+ /** @var $website Mage_Core_Model_Website */
219
+ foreach(Mage::app()->getWebsites() as $website) {
220
+ $storeIds = array_merge($storeIds, $website->getStoreIds());
221
+ }
222
+
223
+ return $storeIds;
224
+ }
225
}
226
227
?>
app/code/community/Channelpilotsolutions/Channelpilot/Helper/Export.php ADDED
@@ -0,0 +1,759 @@
1
+ <?php
2
+
3
+ /**
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the GNU General Public License (GPL 3)
8
+ * that is bundled with this package in the file LICENSE.txt
9
+ *
10
+ * DISCLAIMER
11
+ *
12
+ * Do not edit or add to this file if you wish to upgrade Channelpilotsolutions_Channelpilot to newer
13
+ * versions in the future. If you wish to customize Channelpilotsolutions_Channelpilot for your
14
+ * needs please refer to http://www.channelpilot.com for more information.
15
+ *
16
+ * @category Channelpilotsolutions
17
+ * @package Channelpilotsolutions_Channelpilot
18
+ * @copyright Copyright (c) 2012 <info@channelpilot.com> - www.channelpilot.com
19
+ * @author Björn Wehner <info@channelpilot.com>
20
+ * @license <http://www.gnu.org/licenses/> GNU General Public License (GPL 3)
21
+ * @link http://www.channelpilot.com
22
+ */
23
+ class Channelpilotsolutions_Channelpilot_Helper_Export extends Mage_Core_Helper_Abstract
24
+ {
25
+ const MAX_ATTRIBUTE_COUNT_FOR_LIVE_EXPORT = 40;
26
+
27
+ protected $_storeId;
28
+ protected $_siteId;
29
+ protected $_customerGroupId;
30
+ protected $_mediaUrl;
31
+ protected $_webUrl;
32
+ protected $_allCat;
33
+ protected $_limit;
34
+ protected $_last;
35
+ protected $_blankProduct;
36
+ protected $_configurableAttributes = array();
37
+ protected $_imageBaseUrl;
38
+ protected $_maxAdditionalImages;
39
+ protected $_exportFields;
40
+ protected $_currencyChange;
41
+ protected $_replaceFields;
42
+ protected $_parents;
43
+ protected $_backendModel;
44
+ protected $_chunkSize;
45
+ protected $_stockId;
46
+ /** @var $_eavEntity Mage_Eav_Model_Entity_Abstract */
47
+ protected $_eavEntity;
48
+
49
+ public function __construct() {
50
+ $this->_init();
51
+ }
52
+
53
+ /**
54
+ * Check if another currency (other than the base currency) should be used. Displays an error if the
55
+ * given currency could not be found.
56
+ */
57
+ protected function _initCurrencyChange() {
58
+ $this->_currencyChange = null;
59
+ $currencyCode = Mage::app()->getRequest()->getParam('currency', false);
60
+ if ($currencyCode && $currencyCode != '') {
61
+ $result = Mage::getModel('directory/currency')->getCurrencyRates(Mage::app()->getBaseCurrencyCode(), $currencyCode);
62
+ if(count($result) === 0){
63
+ $xml = new SimpleXMLElement('<root></root>');
64
+ $xml->addChild('error', 'wrong currency');
65
+ header('Content-Type: text/xml; charset=utf-8');
66
+ echo $xml->asXML();
67
+ exit();
68
+ }
69
+ $this->_currencyChange = $result[$currencyCode];
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Get PHP's memory limit in bytes.
75
+ * @return int|string
76
+ */
77
+ protected function getPhpMemoryLimitInBytes ()
78
+ {
79
+ $limit = ini_get('memory_limit');
80
+ switch (substr ($limit, -1))
81
+ {
82
+ case 'M': case 'm': return (int)$limit * 1048576; // 1024 * 1024
83
+ case 'K': case 'k': return (int)$limit * 1024;
84
+ case 'G': case 'g': return (int)$limit * 1073741824; // 1024 * 1024 * 1024
85
+ default: return $limit;
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Initialize the export.
91
+ *
92
+ * @param int $storeId
93
+ */
94
+ protected function _init() {
95
+ // Initialize the admin application
96
+ Mage::app('admin');
97
+
98
+ $this->_blankProduct = array();
99
+ $this->_blankProduct['entity_id'] = '';
100
+ $this->_blankProduct['sku'] = '';
101
+ $this->_blankProduct['parent_id'] = '';
102
+ $this->_blankProduct['variationTheme'] = '';
103
+ $this->_blankProduct['name'] = '';
104
+ $this->_blankProduct['description'] = '';
105
+ $this->_blankProduct['price'] = '';
106
+ $this->_blankProduct['categories'] = '';
107
+ $this->_blankProduct['manufacturer'] = '';
108
+ $this->_blankProduct['manufacturer_name'] = '';
109
+ $this->_blankProduct['cp_product_url'] = '';
110
+ $this->_blankProduct['cp_image_url'] = '';
111
+ $this->_blankProduct['color'] = '';
112
+ $this->_blankProduct['weight'] = '';
113
+ for($i = 1; $i <= Mage::getStoreConfig('channelpilot_export/channelpilot_productfeed/channelpilot_imagenumber'); $i++) {
114
+ $this->_blankProduct['cp_additional_image_'.$i] = '';
115
+ }
116
+
117
+ $specialExportFields = unserialize(Mage::getStoreConfig('channelpilot_export/channelpilot_productfeed/channelpilot_specialexportfields'));
118
+ if(!empty($specialExportFields)) {
119
+ foreach($specialExportFields as $field) {
120
+ if (!empty($field['name'])) {
121
+ $this->_blankProduct[preg_replace('/\W/', '', $field['name'])] = $field['value'];
122
+ }
123
+ }
124
+ }
125
+
126
+ $this->_customerGroupId = Mage_Customer_Model_Group::NOT_LOGGED_IN_ID;
127
+
128
+ $this->_buildCategoryTree();
129
+ $this->_initCurrencyChange();
130
+ $this->_initConfigurableAttributes();
131
+
132
+ /** @var $mediaConfig Mage_Catalog_Model_Product_Media_Config */
133
+ $mediaConfig = Mage::getSingleton('catalog/product_media_config');
134
+ $this->_imageBaseUrl = $mediaConfig->getBaseMediaUrl();
135
+
136
+ $this->_maxAdditionalImages = Mage::getStoreConfig('channelpilot_export/channelpilot_productfeed/channelpilot_imagenumber');
137
+ $this->_exportFields = unserialize(Mage::getStoreConfig('channelpilot_export/channelpilot_productfeed/channelpilot_exportfields'));
138
+ $this->_replaceFields = unserialize(Mage::getStoreConfig('channelpilot_export/channelpilot_productfeed/channelpilot_replacefields'));
139
+
140
+ $this->_initChunkSize();
141
+
142
+ $this->_parents = array();
143
+ }
144
+
145
+ /**
146
+ * Initialize the chunk size for the collection based on PHP's memory limit.
147
+ */
148
+ protected function _initChunkSize() {
149
+ $memoryLimit = $this->getPhpMemoryLimitInBytes();
150
+
151
+ switch($memoryLimit) {
152
+ case $memoryLimit <= 33554432: // 32M
153
+ $this->_chunkSize = 10;
154
+ break;
155
+ case $memoryLimit <= 67108864: // 64M
156
+ $this->_chunkSize = 25;
157
+ break;
158
+ case $memoryLimit <= 134217728: // 128M
159
+ $this->_chunkSize = 50;
160
+ break;
161
+ case $memoryLimit <= 268435456: // 256M
162
+ $this->_chunkSize = 75;
163
+ break;
164
+ default:
165
+ $this->_chunkSize = 100;
166
+ }
167
+ }
168
+
169
+ /**
170
+ * Build the category tree.
171
+ */
172
+ protected function _buildCategoryTree() {
173
+ $this->_allCat = array();
174
+
175
+ $categoryCollection = Mage::getModel('catalog/category')->getCollection()
176
+ ->addAttributeToSelect('name')
177
+ ->addAttributeToSort('path');
178
+
179
+ foreach($categoryCollection as $category) {
180
+ $path = $this->_getCategory($category->getPath());
181
+ if($path !== 0) {
182
+ $this->_allCat[$category->getPath()] = str_replace('Root Catalog', 'Home', $path . '>' . $category->getName());
183
+ } else {
184
+ $this->_allCat[$category->getPath()] = str_replace('Root Catalog', 'Home', $category->getName());
185
+ }
186
+ }
187
+ }
188
+
189
+ /**
190
+ * Get the category id from a path.
191
+ * @param $key
192
+ * @return int | string
193
+ */
194
+ protected function _getCategory($key) {
195
+ $return = 0;
196
+ if (strpos($key, '/') != false) {
197
+ $tmpKey = substr($key, 0, strpos($key, strrchr($key, '/')));
198
+ if (isset($this->_allCat[$tmpKey])) {
199
+ $return = $this->_allCat[$tmpKey];
200
+ } else {
201
+ $return = $this->_getCategory($tmpKey);
202
+ }
203
+ }
204
+ return $return;
205
+ }
206
+
207
+ /**
208
+ * Initialize the configurableAttributes array.
209
+ * Array(
210
+ * [PRODUCT_ID] => ARRAY(
211
+ * [ATTRIBUTE_CODE] => [FRONTEND_LABEL]
212
+ * )
213
+ * )
214
+ */
215
+ protected function _initConfigurableAttributes() {
216
+ $this->_configurableAttributes = array();
217
+
218
+ $connection = Mage::getSingleton('core/resource')->getConnection('core_read');
219
+
220
+ $select = $connection->select()
221
+ ->from(array('super_attribute' => Mage::getSingleton('core/resource')->getTableName('catalog/product_super_attribute')), array('attribute_id', 'product_id'))
222
+ ->join(array('attribute' => Mage::getSingleton('core/resource')->getTableName('eav/attribute')),
223
+ 'attribute.attribute_id = super_attribute.attribute_id',
224
+ array('attribute_code', 'frontend_label')
225
+ );
226
+
227
+ $result = $connection->fetchAll($select);
228
+
229
+ foreach($result as $attribute) {
230
+ if(!isset($this->_configurableAttributes[$attribute['product_id']])) {
231
+ $this->_configurableAttributes[$attribute['product_id']] = array();
232
+ }
233
+ $this->_configurableAttributes[$attribute['product_id']][$attribute['attribute_code']] = $attribute['frontend_label'];
234
+ }
235
+ }
236
+
237
+ /**
238
+ * Get an array of attribute codes for all configurable attributes of a product ID.
239
+ *
240
+ * @param int $productId
241
+ * @return array
242
+ */
243
+ protected function _getConfigurableAttributes($productId) {
244
+ $attributeOptions = array();
245
+ if(isset($this->_configurableAttributes[$productId])) {
246
+ foreach($this->_configurableAttributes[$productId] as $attributeCode => $label) {
247
+ $attributeOptions[] = $label;
248
+ }
249
+ }
250
+ return $attributeOptions;
251
+ }
252
+
253
+ /**
254
+ * Get all attributes that need to be selected from the database.
255
+ * @param $attributes array
256
+ * @return array
257
+ */
258
+ protected function _getAttributesForSelect($attributes) {
259
+ $attributesToSelect = array(
260
+ 'entity_id',
261
+ 'sku',
262
+ 'name',
263
+ 'description',
264
+ 'price',
265
+ 'manufacturer',
266
+ 'color',
267
+ 'weight',
268
+ 'media_gallery',
269
+ 'url_key',
270
+ 'url_path',
271
+ 'image',
272
+ 'type_id'
273
+ );
274
+
275
+ $attributeCodes = array();
276
+
277
+ // save all available attribute codes
278
+ foreach($attributes as $code => $attribute) {
279
+ $attributeCodes[] = $code;
280
+ }
281
+
282
+ // add all attributes from the config if the attribute is a Magento attribute and it has
283
+ // not already been added to the $attributesToSelect array
284
+ foreach($this->_exportFields as $field) {
285
+ $attrCode = $field['productattribute'];
286
+ if(in_array($attrCode, $attributeCodes) && !in_array($attrCode, $attributesToSelect)) {
287
+ $attributesToSelect[] = $attrCode;
288
+ }
289
+ }
290
+
291
+ return $attributesToSelect;
292
+
293
+ }
294
+
295
+ /**
296
+ * Sets store specific values for the export based on the parameter $storeId.
297
+ * Returns false if an error occured / the store with id $storeId does not exist.
298
+ * @param int $storeId
299
+ * @return bool
300
+ * @throws Mage_Core_Exception
301
+ */
302
+ protected function _setStoreValues($storeId) {
303
+ try {
304
+ $store = Mage::app()->getStore($storeId);
305
+ } catch(Exception $e) {
306
+ Mage::logException($e);
307
+ return false;;
308
+ }
309
+
310
+ $this->_storeId = $store->getId();
311
+ $this->_siteId = $store->getWebsiteId();
312
+ $this->_webUrl = $store->getBaseUrl(Mage_Core_Model_Store::URL_TYPE_WEB);
313
+ $this->_mediaUrl = $store->getBaseUrl(Mage_Core_Model_Store::URL_TYPE_MEDIA);
314
+
315
+ $stockId = $store->getWebsite()->getStockId();
316
+ $this->_stockId = (!empty($stockId)) ? $stockId : 1;
317
+
318
+ return true;
319
+ }
320
+
321
+ /**
322
+ * @param int $storeId
323
+ * @param array $filterIds
324
+ * @return Mage_Catalog_Model_Resource_Product_Collection|null
325
+ * @throws Mage_Core_Exception
326
+ */
327
+ public function getProductCollection($storeId, array $filterIds = array()) {
328
+ // Set the store values. If an error occurs, return null.
329
+ if(!$this->_setStoreValues($storeId)) {
330
+ return null;
331
+ }
332
+
333
+ /** @var $collection Mage_Catalog_Model_Resource_Product_Collection */
334
+ $collection = Mage::getModel('catalog/product')->getCollection();
335
+ $this->_eavEntity = $collection->getEntity();
336
+ $attributes = $collection->getEntity()->loadAllAttributes()->getAttributesByCode();
337
+
338
+ $connection = $collection->getConnection();
339
+
340
+ // addPriceData uses inner join to get the price data for a website_id and a customer_group id
341
+ // so all products that are not associated to $this->_siteId and the customerGroupId (NOT LOGGED IN (0) by default)
342
+ // are not included in this collection.
343
+ // addPriceData is needed for getting the minimal price for bundels
344
+ $collection
345
+ ->addAttributeToSelect('*')
346
+ ->addPriceData($this->_customerGroupId, $this->_siteId)
347
+ ->joinField('qty',
348
+ 'cataloginventory/stock_item',
349
+ 'qty',
350
+ 'product_id=entity_id',
351
+ $connection->quoteInto('{{table}}.stock_id=?', $this->_stockId),
352
+ 'left')
353
+ ->joinField('min_sale_qty',
354
+ 'cataloginventory/stock_item',
355
+ 'min_sale_qty',
356
+ 'product_id=entity_id',
357
+ $connection->quoteInto('{{table}}.stock_id=?', $this->_stockId),
358
+ 'left')
359
+ ->joinField('max_sale_qty',
360
+ 'cataloginventory/stock_item',
361
+ 'max_sale_qty',
362
+ 'product_id=entity_id',
363
+ $connection->quoteInto('{{table}}.stock_id=?', $this->_stockId),
364
+ 'left')
365
+ ->joinField('is_in_stock',
366
+ 'cataloginventory/stock_item',
367
+ 'is_in_stock',
368
+ 'product_id=entity_id',
369
+ $connection->quoteInto('{{table}}.stock_id=?', $this->_stockId),
370
+ 'left')
371
+ ->setStoreId($this->_storeId);
372
+
373
+ // add group price fields
374
+ foreach($this->_exportFields as $field) {
375
+ if(strpos($field['productattribute'], 'group_price') !== false) {
376
+ $groupId = substr($field['productattribute'], 12);
377
+ if(is_numeric($groupId)) {
378
+ $collection->joinField('group_price_'.$groupId,
379
+ 'catalog/product_index_price',
380
+ 'group_price',
381
+ 'entity_id=entity_id',
382
+ $connection->quoteInto('{{table}}.customer_group_id=?', $groupId),
383
+ 'left');
384
+ }
385
+ }
386
+ }
387
+
388
+ if(!empty($filterIds)) {
389
+ $collection->addFieldToFilter('entity_id', array('in' => $filterIds));
390
+ }
391
+
392
+ $this->_backendModel = $collection->getResource()->getAttribute('media_gallery')->getBackend();
393
+
394
+ return $collection;
395
+ }
396
+
397
+ /**
398
+ * Get the url for the product based on the selected method in the system config or from the param $method.
399
+ * @param Mage_Catalog_Model_Product $product
400
+ * @param null|int $method
401
+ * @return string
402
+ */
403
+ public function getProductUrl(Mage_Catalog_Model_Product $product, $method = null) {
404
+ if($method === null) {
405
+ $method = Mage::getStoreConfig('channelpilot_export/channelpilot_productfeed/product_url_generation_method');
406
+ }
407
+
408
+ switch($method) {
409
+ case Channelpilotsolutions_Channelpilot_Model_Adminhtml_Source_Producturlgeneration::METHOD_URL_PATH:
410
+ $url = $this->_webUrl . $product->getUrlPath();
411
+ break;
412
+ case Channelpilotsolutions_Channelpilot_Model_Adminhtml_Source_Producturlgeneration::METHOD_URL_KEY:
413
+ $url = $this->_webUrl . $product->getUrlKey();
414
+ break;
415
+ case Channelpilotsolutions_Channelpilot_Model_Adminhtml_Source_Producturlgeneration::METHOD_URL_KEY_HTML:
416
+ $url = $this->_webUrl . $product->getUrlKey() . '.html';
417
+ break;
418
+ case Channelpilotsolutions_Channelpilot_Model_Adminhtml_Source_Producturlgeneration::METHOD_GET_PRODUCT_URL:
419
+ $url = $product->getProductUrl();
420
+ break;
421
+ case Channelpilotsolutions_Channelpilot_Model_Adminhtml_Source_Producturlgeneration::METHOD_GET_URL_IN_STORE:
422
+ $url = $product->getUrlInStore($product, array('_store' => $this->_storeId));
423
+ break;
424
+ default:
425
+ $url = '';
426
+ }
427
+
428
+ return $url;
429
+ }
430
+
431
+ /**
432
+ * Get the current $item as array.
433
+ * Returns Array(
434
+ * [ATTRIBUTE_CODE] => [VALUE]
435
+ * )
436
+ * @param Mage_Catalog_Model_Product $item
437
+ * @return array
438
+ */
439
+ public function getFullProductData(Mage_Catalog_Model_Product $item) {
440
+ $imageUrl = $this->_imageBaseUrl . $item->getImage();
441
+
442
+ $isParent = 0;
443
+ if ($item->getTypeId() == Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE) {
444
+ $isParent = 1;
445
+ }
446
+
447
+ $parentId = null;
448
+ if ($item->getTypeId() == Mage_Catalog_Model_Product_Type::TYPE_SIMPLE) {
449
+ $parentId = Mage::getModel('catalog/product_type_configurable')->getParentIdsByChild($item->getId());
450
+ $parentId = (is_array($parentId) && !empty($parentId)) ? $parentId[0] : null;
451
+ }
452
+
453
+ $configurableAttributes = array();
454
+ if($parentId && isset($this->_variationThemes[$parentId])) {
455
+ $configurableAttributes = $this->_variationThemes[$parentId];
456
+ } else if($isParent && $parentId === null) {
457
+ $configurableAttributes = $this->_getConfigurableAttributes($item->getId());
458
+ $configurableAttributes = (!empty($configurableAttributes)) ? implode('|', $configurableAttributes) : '';
459
+ $this->_variationThemes[$item->getId()] = $configurableAttributes;
460
+ }
461
+
462
+ $colorText = ($this->_eavEntity->getAttribute('color')) ? $item->getAttributeText('color') : '';
463
+
464
+ // set the value to the minimal price if the current product is a bundle, otherwise the product's price
465
+ $calcPrice = ($item->getTypeId() == Mage_Catalog_Model_Product_Type::TYPE_BUNDLE) ? Mage::getModel('bundle/product_price')->getTotalPrices($item, 'min', true, false) : $item->getPrice();
466
+
467
+ $rulePrice = Mage::getModel('catalogrule/rule')->calcProductPriceRule($item->setStoreId($this->_storeId),$calcPrice);
468
+ $price = ($rulePrice) ? $rulePrice : $calcPrice;
469
+
470
+ $product = $this->_blankProduct;
471
+
472
+ $product['entity_id'] = $item->getId();
473
+ $product['sku'] = $item->getSku();
474
+ $product['parent_id'] = $parentId;
475
+ $product['variationTheme'] = $configurableAttributes;
476
+ $product['name'] = $this->_getCleanedStringForXml($item->getName());
477
+ $product['description'] = $this->_getCleanedStringForXml($item->getDescription());
478
+
479
+ $product['price'] = $price;
480
+ if($this->_currencyChange) {
481
+ $product['price'] = round($product['price']*$this->_currencyChange, 2);
482
+ }
483
+
484
+ $product['categories'] = $this->_getCategoryInformation($item);
485
+ if($this->_eavEntity->getAttribute('manufacturer')) {
486
+ $product['manufacturer'] = $this->_getCleanedStringForXml($item->getManufacturer());
487
+ $product['manufacturer_name'] = $this->_getCleanedStringForXml($item->getAttributeText('manufacturer'));
488
+ }
489
+ $product['cp_product_url'] = $this->getProductUrl($item);
490
+ $product['cp_image_url'] = $imageUrl;
491
+ $product['color'] = ($colorText) ? $this->_getCleanedStringForXml($colorText) : null;
492
+ $product['weight'] = $item->getWeight();
493
+
494
+ $product = array_merge($product, $this->_getAdditionalImages($item));
495
+
496
+ $product['is_parent'] = $isParent;
497
+
498
+ $this->_addExportFields($product, $item);
499
+
500
+ if(!empty($this->_replaceFields) && !$isParent && $parentId !== null) {
501
+ $this->_replaceFields($product, $parentId);
502
+ }
503
+
504
+ return $product;
505
+ }
506
+
507
+ /**
508
+ * Get the additional images for a product
509
+ * @param Mage_Catalog_Model_Product $product
510
+ * @return array
511
+ */
512
+ protected function _getAdditionalImages(Mage_Catalog_Model_Product $product) {
513
+ $counter = 1;
514
+ $productData = array();
515
+ $mediaGalleryImages = array();
516
+ if($product->getMediaGalleryImages()) {
517
+ $mediaGalleryImages = $product->getMediaGalleryImages();
518
+ }
519
+ foreach ($mediaGalleryImages as $image) {
520
+ // break if the maximum amount of additional images has been reached
521
+ if ($counter > $this->_maxAdditionalImages) {
522
+ break;
523
+ }
524
+
525
+ // ignore the base image; it has already been added
526
+ if ($image->getFile() == $product->getImage()) {
527
+ continue;
528
+ }
529
+
530
+ $productData['cp_additional_image_' . $counter] = $this->_imageBaseUrl . $image->getFile();
531
+ $counter++;
532
+ }
533
+
534
+ return $productData;
535
+ }
536
+
537
+ /**
538
+ * Add all fields to a product that need to be exported
539
+ * @param $product
540
+ * @param Mage_Catalog_Model_Product $item
541
+ */
542
+ protected function _addExportFields(&$product, Mage_Catalog_Model_Product $item) {
543
+ foreach($this->_exportFields as $field) {
544
+ $code = $field['productattribute'];
545
+ if(strpos($code, 'group_price') !== false) {
546
+ $groupId = substr($code, 12);
547
+ $customerGroup = Mage::getModel('customer/group')->load($groupId);
548
+ $groupCode = str_replace(' ', '_', $customerGroup->getCustomerGroupCode());
549
+ $product['group_price_'.$groupCode] = $item->getData('group_price_'.$customerGroup->getId());
550
+ } else {
551
+ switch($code) {
552
+ // ignore
553
+ case 'parent_id':
554
+ break;
555
+ case 'qty':
556
+ $product[$code] = $item->getQty();
557
+ break;
558
+ case 'stock_status':
559
+ $product[$code] = $item->getIsInStock();
560
+ break;
561
+ case 'min_sale_qty':
562
+ case 'max_sale_qty':
563
+ case 'tax_class_id':
564
+ $product[$code] = $item->getData($code);
565
+ break;
566
+ default:
567
+ $attributeText = ($item->getResource()->getAttribute($code)) ? $item->getAttributeText($code) : false;
568
+ if(is_array($attributeText)) {
569
+ $attributeText = implode(',',$attributeText);
570
+ }
571
+ $product[$code] = ($attributeText) ? $this->_getCleanedStringForXml($attributeText) : $this->_getCleanedStringForXml($item->getData($code));
572
+ }
573
+ }
574
+ }
575
+ }
576
+
577
+ /**
578
+ * Replace all selected fields with the parent's values.
579
+ * @param $product
580
+ * @param $parentId
581
+ */
582
+ protected function _replaceFields(&$product, $parentId) {
583
+ $parent = $this->_getParentById($parentId);
584
+ if($parent !== null && $parent->getId()) {
585
+ $parentImages = $this->_getAdditionalImages($parent);
586
+ foreach($this->_replaceFields as $field) {
587
+ $code = $field['productattribute'];
588
+ if(strpos($code, 'group_price') !== false) {
589
+ $groupId = substr($code, 12);
590
+ $customerGroup = Mage::getModel('customer/group')->load($groupId);
591
+ $groupPrices = $parent->getData('group_price');
592
+ foreach($groupPrices as $groupPrice) {
593
+ if($groupPrice['cust_group'] == $groupId) {
594
+ $groupCode = str_replace(' ', '_', $customerGroup->getCustomerGroupCode());
595
+ $product['group_price_'.$groupCode] = $groupPrice['price'];
596
+ }
597
+ }
598
+ } else if(strpos($code, 'cp_additional_image') !== false && isset($parentImages[$code])) {
599
+ $product[$code] = $parentImages[$code];
600
+ } else {
601
+ switch($code) {
602
+ case 'categories':
603
+ $product['categories'] = $this->_getCategoryInformation($parent);
604
+ break;
605
+ case 'cp_product_url':
606
+ $product[$code] = $this->getProductUrl($parent);
607
+ break;
608
+ case 'cp_image_url':
609
+ $product[$code] = $this->_imageBaseUrl . $parent->getImage();
610
+ break;
611
+ case 'qty':
612
+ $product[$code] = $parent->getStockItem()->getQty();
613
+ break;
614
+ case 'stock_status':
615
+ $product[$code] = $parent->getStockItem()->getIsInStock();
616
+ break;
617
+ case 'min_sale_qty':
618
+ $product[$code] = $parent->getStockItem()->getMinSaleQty();
619
+ break;
620
+ case 'max_sale_qty':
621
+ $product[$code] = $parent->getStockItem()->getMaxSaleQty();
622
+ break;
623
+ case 'tax_class_id':
624
+ $product[$code] = $parent->getData($code);
625
+ break;
626
+ default:
627
+ $attributeText = ($parent->getResource()->getAttribute($code)) ? $parent->getAttributeText($code) : false;
628
+ if(is_array($attributeText)) {
629
+ $attributeText = implode(',',$attributeText);
630
+ }
631
+ $product[$code] = ($attributeText) ? $this->_getCleanedStringForXml($attributeText) : $this->_getCleanedStringForXml($parent->getData($code));
632
+ }
633
+ }
634
+ }
635
+ }
636
+ }
637
+
638
+ /**
639
+ * Adds the values of the $product array to the $xml structure.
640
+ * @param array $product
641
+ * @param SimpleXMLElement $xml
642
+ */
643
+ public function productToXml(array $product, SimpleXMLElement $xml) {
644
+ foreach($product as $code => $value) {
645
+ if(is_array($value)) {
646
+ $node = $xml->addChild($code);
647
+ $this->productToXml($value, $node);
648
+ } else if (is_string($value) || is_numeric($value) || is_bool($value) || is_null($value)) {
649
+ $xml->addChild($code, htmlspecialchars($value));
650
+ }
651
+ }
652
+ }
653
+
654
+ /**
655
+ * Get the category information for a product.
656
+ * @param Mage_Catalog_Model_Product $product
657
+ * @return string
658
+ */
659
+ protected function _getCategoryInformation(Mage_Catalog_Model_Product $product) {
660
+ $arrPath = array();
661
+
662
+ /** @var $category Mage_Catalog_Model_Category */
663
+ foreach($product->getCategoryCollection() as $category) {
664
+ if(isset($this->_allCat[$category->getPath()])) {
665
+ $arrPath[] = $this->_allCat[$category->getPath()];
666
+ }
667
+ }
668
+
669
+ return ltrim(implode(',', $arrPath), '>');
670
+ }
671
+
672
+ /**
673
+ * Get a product by its id. Save the loaded product to an array to cache it.
674
+ * It is used for parent products only so these products do not need to be loaded by each
675
+ * of its child products.
676
+ * @param $parentId
677
+ * @return mixed
678
+ */
679
+ protected function _getParentById($parentId) {
680
+ if(!isset($this->_parents[$parentId])) {
681
+ $parent = Mage::getModel('catalog/product')->load($parentId);
682
+ $this->_parents[$parentId] = ($parent->getId()) ? $parent : null;
683
+ }
684
+ return $this->_parents[$parentId];
685
+ }
686
+
687
+ /**
688
+ * Clean a string for usage in XML.
689
+ * @param $string
690
+ * @return mixed
691
+ */
692
+ protected function _getCleanedStringForXml($string) {
693
+ return $this->_utf8ForXml(html_entity_decode($string));
694
+ }
695
+
696
+ /**
697
+ * Replace all UTF-8 characters that are not allowed in XML with a space.
698
+ * @param $string
699
+ * @return mixed
700
+ */
701
+ protected function _utf8ForXml($string) {
702
+ return preg_replace ('/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u', ' ', $string);
703
+ }
704
+
705
+ /**
706
+ * @return mixed
707
+ */
708
+ public function getStoreId()
709
+ {
710
+ return $this->_storeId;
711
+ }
712
+
713
+ public function setStoreVariables($storeId) {
714
+ try {
715
+ $store = Mage::app()->getStore($storeId);
716
+ $this->_storeId = $storeId;
717
+ $this->_siteId = $store->getWebsiteId();
718
+ $this->_webUrl = $store->getBaseUrl(Mage_Core_Model_Store::URL_TYPE_WEB);
719
+ $this->_mediaUrl = $store->getBaseUrl(Mage_Core_Model_Store::URL_TYPE_MEDIA);
720
+ } catch(Exception $e) {
721
+ Mage::logException($e);
722
+ }
723
+ }
724
+
725
+ /**
726
+ * @return mixed
727
+ */
728
+ public function getChunkSize()
729
+ {
730
+ if(empty($this->_chunkSize)) {
731
+ $this->_initChunkSize();
732
+ }
733
+ return $this->_chunkSize;
734
+ }
735
+
736
+ /**
737
+ * @param mixed $chunkSize
738
+ */
739
+ public function setChunkSize($chunkSize)
740
+ {
741
+ $this->_chunkSize = $chunkSize;
742
+ }
743
+
744
+ /**
745
+ * @return mixed
746
+ */
747
+ public function getAttributeCount()
748
+ {
749
+ return (!empty($this->_exportFields)) ? count($this->_exportFields) : 0;
750
+ }
751
+
752
+ /**
753
+ * @return mixed
754
+ */
755
+ public function getBackendModel()
756
+ {
757
+ return $this->_backendModel;
758
+ }
759
+ }
app/code/community/Channelpilotsolutions/Channelpilot/Helper/api/1_0/ChannelPilotSellerAPI_v1_0.php CHANGED
@@ -38,7 +38,6 @@ require_once 'responses/GetManagedArticlePricesResponse.php';
38
class ChannelPilotSellerAPI_v1_0 extends SoapClient {
39
40
private $auth;
41
- private $wsdlUrl = 'https://seller.api.channelpilot.com/1_0?wsdl';
42
private $soapOptions = array(
43
'connection_timeout' => 20,
44
'features' => SOAP_SINGLE_ELEMENT_ARRAYS
@@ -77,7 +76,7 @@ class ChannelPilotSellerAPI_v1_0 extends SoapClient {
77
$this->soapOptions['classmap'][$key] = $value;
78
}
79
}
80
- parent::__construct($this->wsdlUrl, $this->soapOptions);
81
}
82
83
/**
@@ -193,6 +192,13 @@ class ChannelPilotSellerAPI_v1_0 extends SoapClient {
193
);
194
}
195
196
}
197
198
?>
38
class ChannelPilotSellerAPI_v1_0 extends SoapClient {
39
40
private $auth;
41
private $soapOptions = array(
42
'connection_timeout' => 20,
43
'features' => SOAP_SINGLE_ELEMENT_ARRAYS
76
$this->soapOptions['classmap'][$key] = $value;
77
}
78
}
79
+ parent::__construct($this->getWsdlUrl(), $this->soapOptions);
80
}
81
82
/**
192
);
193
}
194
195
+ /**
196
+ * @return string
197
+ */
198
+ public function getWsdlUrl()
199
+ {
200
+ return Mage::getStoreConfig('channelpilot_general/channelpilot_general/seller_api_wsdl_url');
201
+ }
202
}
203
204
?>
app/code/community/Channelpilotsolutions/Channelpilot/Helper/handler/CPAbstractHandler.php CHANGED
@@ -22,24 +22,32 @@ class CPAbstractHandler {
22
* @return boolean
23
*/
24
public static function isIpAllowedViaShopId($shopId) {
25
- if (self::ChannelPilot_IP == $_SERVER['REMOTE_ADDR'] || !Mage::getStoreConfig('channelpilot_general/channelpilot_general/channelpilot_checkIp')) {
26
return true;
27
} else {
28
- return in_array($_SERVER['REMOTE_ADDR'], Mage::getModel('channelpilot/registration')->getAllowedIpsViaShopId($shopId));
29
}
30
}
31
32
/**
33
- * Is the IP allowed for this securityToken
34
*
35
- * @param type $token
36
* @return boolean
37
*/
38
- public static function isIpAllowedViaSecurityToken($token) {
39
- if (self::ChannelPilot_IP == $_SERVER['REMOTE_ADDR'] || !Mage::getStoreConfig('channelpilot_general/channelpilot_general/channelpilot_checkIp')) {
40
return true;
41
- } else {
42
- return in_array($_SERVER['REMOTE_ADDR'], Mage::getModel('channelpilot/registration')->getAllowedIpsViaSecurityToken($token));
43
}
44
}
45
@@ -59,25 +67,35 @@ class CPAbstractHandler {
59
60
/**
61
* Get the merchantId for a security token.
62
- * Returns NULL if record could not be found.
63
* @param string $token
64
* @return mixed
65
*/
66
public static function getMerchantId($token) {
67
- return Mage::getModel('channelpilot/registration')->load($token, 'securityToken')
68
->getData('merchantId');
69
}
70
71
/**
72
* Get shopId by token for registered shop.
73
- * Returns NULL if no record could be found.
74
*
75
* @param string $token
76
* @return mixed
77
*/
78
public static function getShopId($token) {
79
- return Mage::getModel('channelpilot/registration')->load($token, 'securityToken')
80
->getId();
81
}
82
83
public static function changeStatusOrders($apiOrders) {
@@ -87,7 +105,7 @@ class CPAbstractHandler {
87
self::changeStatusOrder($apiOrder->orderHeader);
88
} else {
89
$defectiveOrderIncrementIds[] = $apiOrder->orderHeader->orderId;
90
- self::logError("Cannot change orderstatus from order (id: '" . $apiOrder->orderHeader->orderId . "', status: '" . $apiOrder->orderHeader->status->identifier . "')");
91
}
92
}
93
return $defectiveOrderIncrementIds;
@@ -116,7 +134,8 @@ class CPAbstractHandler {
116
* @param string $msg
117
*/
118
public static function logError($msg) {
119
- $msg = "http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI] by IP: {$_SERVER['REMOTE_ADDR']}\n$msg";
120
121
Mage::log("$msg\n\n", null, 'cp_plugin.log');
122
Mage::getModel('channelpilot/logs')
@@ -124,22 +143,6 @@ class CPAbstractHandler {
124
->setData(array('created' => date('Y-m-d H:i:s'), 'content' => $msg))
125
->save();
126
}
127
-
128
- public static function checkConfig() {
129
- /* if(oxConfig::getInstance()->getShopConfVar('CPMARKETPLACE_ART_NUMBER')==2 && oxConfig::getInstance()->getShopConfVar('CPMARKETPLACE_ART_OTHERARTNUM')==''){
130
- CPErrorHandler::handle(CPErrors::RESULT_CONFIG_INVALID, "No column for other article number", "No column for other article number");
131
- }
132
- if(oxConfig::getInstance()->getShopConfVar('CPMARKETPLACE_IMPORT')==''){
133
- CPErrorHandler::handle(CPErrors::RESULT_CONFIG_INVALID, "No folder for unpaid orders", "No folder for unpaid orders");
134
- }
135
- if(oxConfig::getInstance()->getShopConfVar('CPMARKETPLACE_PAIDIMPORT')==''){
136
- CPErrorHandler::handle(CPErrors::RESULT_CONFIG_INVALID, "No folder for paid orders", "No folder for paid orders");
137
- }
138
- if(oxConfig::getInstance()->getShopConfVar('CPMARKETPLACE_CANCEL')==''){
139
- CPErrorHandler::handle(CPErrors::RESULT_CONFIG_INVALID, "No folder for cancelled orders", "No folder for cancelled orders");
140
- } */
141
- }
142
-
143
}
144
145
?>
22
* @return boolean
23
*/
24
public static function isIpAllowedViaShopId($shopId) {
25
+ $clientIp = Mage::app()->getRequest()->getClientIp();
26
+ if (self::ChannelPilot_IP == $clientIp || !Mage::getStoreConfig('channelpilot_general/channelpilot_general/channelpilot_checkIp')) {
27
return true;
28
} else {
29
+ return in_array($clientIp, Mage::getModel('channelpilot/registration')->getAllowedIpsViaShopId($shopId));
30
}
31
}
32
33
/**
34
+ * Is the IP allowed for this securityToken.
35
+ * The param $useConfigSettingCheckIp is currently use by the CpShipping carrier to prevent PayPal from
36
+ * using this shipping method if set to "backend_only". If the param is set to false the step to return true
37
+ * if the config setting to check the ip is set to false will be skipped.
38
*
39
+ * @param string $token
40
+ * @param bool $useConfigSettingCheckIp
41
* @return boolean
42
*/
43
+ public static function isIpAllowedViaSecurityToken($token, $useConfigSettingCheckIp = true) {
44
+ $clientIp = Mage::app()->getRequest()->getClientIp();
45
+ if (self::ChannelPilot_IP == $clientIp) {
46
return true;
47
+ } else if($useConfigSettingCheckIp && !Mage::getStoreConfig('channelpilot_general/channelpilot_general/channelpilot_checkIp')) {
48
+ return true;
49
+ } else {
50
+ return in_array($clientIp, Mage::getModel('channelpilot/registration')->getAllowedIpsViaSecurityToken($token));
51
}
52
}
53
67
68
/**
69
* Get the merchantId for a security token.
70
* @param string $token
71
* @return mixed
72
*/
73
public static function getMerchantId($token) {
74
+ $merchantId = Mage::getModel('channelpilot/registration')->load($token, 'securityToken')
75
->getData('merchantId');
76
+
77
+ if(empty($merchantId)) {
78
+ CPErrorHandler::handle(CPErrors::RESULT_FAILED,'No merchant id found for token.','No merchant id found for token.');
79
+ }
80
+
81
+ return $merchantId;
82
}
83
84
/**
85
* Get shopId by token for registered shop.
86
*
87
* @param string $token
88
* @return mixed
89
*/
90
public static function getShopId($token) {
91
+ $shopId = Mage::getModel('channelpilot/registration')->load($token, 'securityToken')
92
->getId();
93
+
94
+ if(empty($shopId)) {
95
+ CPErrorHandler::handle(CPErrors::RESULT_FAILED,'No shop id found for token.','No shop id found for token.');
96
+ }
97
+
98
+ return $shopId;
99
}
100
101
public static function changeStatusOrders($apiOrders) {
105
self::changeStatusOrder($apiOrder->orderHeader);
106
} else {
107
$defectiveOrderIncrementIds[] = $apiOrder->orderHeader->orderId;
108
+ self::logError("Cannot change orderstatus from order (id: '" . $apiOrder->orderHeader->orderId . "', status: '" . $apiOrder->orderHeader->status->identifier . ", msg: ". $apiOrder->header->resultMessage .")");
109
}
110
}
111
return $defectiveOrderIncrementIds;
134
* @param string $msg
135
*/
136
public static function logError($msg) {
137
+ $clientIp = Mage::app()->getRequest()->getClientIp();
138
+ $msg = "http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI] by IP: {$clientIp}\n$msg";
139
140
Mage::log("$msg\n\n", null, 'cp_plugin.log');
141
Mage::getModel('channelpilot/logs')
143
->setData(array('created' => date('Y-m-d H:i:s'), 'content' => $msg))
144
->save();
145
}
146
}
147
148
?>
app/code/community/Channelpilotsolutions/Channelpilot/Helper/handler/CPCancellationHandler.php CHANGED
@@ -15,7 +15,6 @@ class CPCancellationHandler extends CPAbstractHandler {
15
$token = Mage::app()->getRequest()->getParam('token', false);
16
$method = Mage::app()->getRequest()->getParam('method', '');
17
if ($token && self::isIpAllowedViaSecurityToken($token)) {
18
- self::checkConfig();
19
$cancelled = array();
20
21
$cancelledOrders = $this->getCancelledOrders();
@@ -66,7 +65,7 @@ class CPCancellationHandler extends CPAbstractHandler {
66
}
67
}
68
69
- private function hookResult($moreAvailable) {
70
$hook = new CPHookResponse();
71
$hook->resultCode = CPResultCodes::SUCCESS;
72
$hook->resultMessage = "CANCELLATION HOOK SUCCESS";
@@ -74,7 +73,7 @@ class CPCancellationHandler extends CPAbstractHandler {
74
$hook->writeResponse(self::defaultHeader, json_encode($hook));
75
}
76
77
- private function getCancelledItems() {
78
$sResult = Mage::getModel('channelpilot/order_item')->getCollection()
79
->addFieldToSelect(array('order_item_id', 'marketplace_order_item_id', 'time' => new Zend_Db_Expr('NOW()')))
80
->addCanceledSalesOrderItemsFilter()
@@ -110,7 +109,7 @@ class CPCancellationHandler extends CPAbstractHandler {
110
* Update the channelpilot/order_item table to set the cancelled column.
111
* @param array $orders
112
*/
113
- private function _updateMarketplaceOrderItems(array $orders = array()) {
114
foreach($orders as $order) {
115
foreach($order->cancelledItems as $cpOrderItem) {
116
if($cpOrderItem->quantityCancelled > 0) {
@@ -123,7 +122,7 @@ class CPCancellationHandler extends CPAbstractHandler {
123
}
124
}
125
126
- private function getCancelledOrders() {
127
try {
128
$result = Mage::getModel('channelpilot/order')->getCollection()
129
->addFieldToSelect(array('order_nr', 'marketplace', 'time' => new Zend_Db_Expr('NOW()'), 'status'))
15
$token = Mage::app()->getRequest()->getParam('token', false);
16
$method = Mage::app()->getRequest()->getParam('method', '');
17
if ($token && self::isIpAllowedViaSecurityToken($token)) {
18
$cancelled = array();
19
20
$cancelledOrders = $this->getCancelledOrders();
65
}
66
}
67
68
+ protected function hookResult($moreAvailable) {
69
$hook = new CPHookResponse();
70
$hook->resultCode = CPResultCodes::SUCCESS;
71
$hook->resultMessage = "CANCELLATION HOOK SUCCESS";
73
$hook->writeResponse(self::defaultHeader, json_encode($hook));
74
}
75
76
+ protected function getCancelledItems() {
77
$sResult = Mage::getModel('channelpilot/order_item')->getCollection()
78
->addFieldToSelect(array('order_item_id', 'marketplace_order_item_id', 'time' => new Zend_Db_Expr('NOW()')))
79
->addCanceledSalesOrderItemsFilter()
109
* Update the channelpilot/order_item table to set the cancelled column.
110
* @param array $orders
111
*/
112
+ protected function _updateMarketplaceOrderItems(array $orders = array()) {
113
foreach($orders as $order) {
114
foreach($order->cancelledItems as $cpOrderItem) {
115
if($cpOrderItem->quantityCancelled > 0) {
122
}
123
}
124
125
+ protected function getCancelledOrders() {
126
try {
127
$result = Mage::getModel('channelpilot/order')->getCollection()
128
->addFieldToSelect(array('order_nr', 'marketplace', 'time' => new Zend_Db_Expr('NOW()'), 'status'))
app/code/community/Channelpilotsolutions/Channelpilot/Helper/handler/CPDeliveryHandler.php CHANGED
@@ -15,43 +15,115 @@ class CPDeliveryHandler extends CPAbstractHandler {
15
$method = Mage::app()->getRequest()->getParam('method', false);
16
$token = Mage::app()->getRequest()->getParam('token', false);
17
if ($token && self::isIpAllowedViaSecurityToken($token)) {
18
- self::checkConfig();
19
$limit = Mage::app()->getRequest()->getParam('limit', 0);
20
if ($limit) {
21
try {
22
23
- $sResult = Mage::getModel('channelpilot/order')->getCollection()
24
->addFieldToSelect(array('order_nr', 'marketplace'))
25
->addHasShipmentFilter()
26
->addFieldToFilter('main_table.status', array(
27
array('eq' => CPOrderStatus::ID_IMPORTED),
28
array('eq' => CPOrderStatus::ID_PARTIALLY_DELIVERED)
29
- ))
30
- ->setPageSize($limit)
31
- ->getData();
32
33
$deliveries = array();
34
$shipments = array();
35
foreach ($sResult AS $order) {
36
$shipmentIds = explode(',',$order['shipment_ids']);
37
$salesOrder = Mage::getModel('sales/order')->unsetData()->load($order['order_id']);
38
$deliveryComplete = true;
39
- if($salesOrder && $salesOrder->getId()) {
40
- $deliveryComplete = (!$salesOrder->canShip());
41
- }
42
- foreach($shipmentIds as $shipmentId) {
43
- $delivered = new CPDelivery($order['order_nr'], $order['marketplace'], $deliveryComplete, $order['track_number'], date("Y-m-d", strtotime($order['shipment_created_at'])) . 'T' . date("H:i:s", strtotime($order['shipment_created_at'])));
44
- $delivered->carrierName = $order['title'];
45
- $delivered->shipping = new CPShipping();
46
- $delivered->shipping->typeId = $order['shipping_method'];
47
- $delivered->shipping->typeTitle = $order['title'];
48
- $deliveries[] = $delivered;
49
- $shipments[] = array(
50
- 'order_id' => $order['order_id'],
51
- 'order_nr' => $order['order_nr'], // this field is needed to be able to check for defective orders later
52
- 'shipment_id' => $shipmentId,
53
- );
54
}
55
}
56
if (sizeof($deliveries) == 0) {
57
self::hookResult(false);
@@ -67,11 +139,18 @@ class CPDeliveryHandler extends CPAbstractHandler {
67
foreach($shipments as $shipment) {
68
// if an error occured do not save this shipment
69
if(!in_array($shipment['order_nr'], $defectiveOrderIncrementIds)) {
70
- unset($shipment['order_nr']);
71
- $shipmentsToInsert[] = $shipment;
72
}
73
}
74
- $insertedRows = Mage::getModel('channelpilot/order_shipment')->addMultipleShipments($shipmentsToInsert);
75
76
} else {
77
// Result from registerDeliveries has no success
@@ -91,7 +170,7 @@ class CPDeliveryHandler extends CPAbstractHandler {
91
CPErrorHandler::handle(CPErrors::RESULT_MISSING_PARAMS, "no limit set for method: " . $method, "no limit set for method: " . $method);
92
}
93
} else {
94
- if (empty($_GET['token'])) {
95
CPErrorHandler::handle(CPErrors::RESULT_MISSING_PARAMS, "no token found", "no token found");
96
} else {
97
CPErrorHandler::handle(CPErrors::RESULT_FAILED, "ip not allowed by token: " . $token, "ip not allowed by token: " . $token);
@@ -100,7 +179,7 @@ class CPDeliveryHandler extends CPAbstractHandler {
100
return "Error during handle deliveryHook";
101
}
102
103
- private function hookResult($moreAvailable) {
104
$hook = new CPHookResponse();
105
$hook->resultCode = CPResultCodes::SUCCESS;
106
$hook->resultMessage = "DELIVERY HOOK SUCCESS";
15
$method = Mage::app()->getRequest()->getParam('method', false);
16
$token = Mage::app()->getRequest()->getParam('token', false);
17
if ($token && self::isIpAllowedViaSecurityToken($token)) {
18
$limit = Mage::app()->getRequest()->getParam('limit', 0);
19
if ($limit) {
20
try {
21
22
+ /** @var $collection Channelpilotsolutions_Channelpilot_Model_Resource_Order_Collection */
23
+ $collection = Mage::getModel('channelpilot/order')->getCollection()
24
->addFieldToSelect(array('order_nr', 'marketplace'))
25
->addHasShipmentFilter()
26
->addFieldToFilter('main_table.status', array(
27
array('eq' => CPOrderStatus::ID_IMPORTED),
28
array('eq' => CPOrderStatus::ID_PARTIALLY_DELIVERED)
29
+ ));
30
+
31
+ $sResult = array();
32
+ $incomplete = 0;
33
+
34
+ // loop through all orders with deliveries and add every order with
35
+ // a completed delivery until the limit has been reached
36
+ foreach($collection as $order) {
37
+ /** @var $salesOrder Mage_Sales_Model_Order */
38
+ $salesOrder = Mage::getModel('sales/order')->unsetData()->load($order['order_id']);
39
+
40
+ // For now the seller api does not allow partial deliveries.
41
+ // Therefore the variable $deliveryComplete will always be true.
42
+ if($salesOrder && $salesOrder->getId()) {
43
+ // order shipment is not complete yet, so skip this order
44
+ if($salesOrder->canShip()) {
45
+ $incomplete++;
46
+ continue;
47
+ }
48
+
49
+ $sResult[] = $order->getData();
50
+ $limit--;
51
+
52
+ if($limit == 0) {
53
+ break;
54
+ }
55
+ }
56
+ }
57
+
58
+ if($incomplete > 0) {
59
+ self::logError('Skipped '.$incomplete.' orders because the delivery is not completed yet.');
60
+ }
61
62
$deliveries = array();
63
$shipments = array();
64
foreach ($sResult AS $order) {
65
$shipmentIds = explode(',',$order['shipment_ids']);
66
+ /** @var $salesOrder Mage_Sales_Model_Order */
67
$salesOrder = Mage::getModel('sales/order')->unsetData()->load($order['order_id']);
68
+
69
+ // For now the seller api does not allow partial deliveries.
70
+ // Therefore the variable $deliveryComplete will always be true.
71
$deliveryComplete = true;
72
+
73
+ $delivered = new CPDelivery($order['order_nr'], $order['marketplace'], $deliveryComplete, $order['track_number'], date("Y-m-d", strtotime($order['shipment_created_at'])) . 'T' . date("H:i:s", strtotime($order['shipment_created_at'])));
74
+ $delivered->carrierName = $order['title'];
75
+ $delivered->shipping = new CPShipping();
76
+ $delivered->shipping->typeId = $order['shipping_method'];
77
+ $delivered->shipping->typeTitle = $order['title'];
78
+
79
+ $deliveredItems = array();
80
+ /** @var $orderItem Mage_Sales_Model_Order_Item */
81
+ foreach($salesOrder->getAllItems() as $orderItem) {
82
+ $cpMarketplaceOrderItem = Mage::getModel('channelpilot/order_item')->getCollection()
83
+ ->addFieldToFilter('order_id', array('eq' => $order['order_id']))
84
+ ->addFieldToFilter('order_item_id', array('eq' => $orderItem->getId()))
85
+ ->getFirstItem();
86
+
87
+ $item = new CPOrderItem();
88
+
89
+ $item->id = $orderItem->getId();
90
+ $item->idExternal = $cpMarketplaceOrderItem->getMarketplaceOrderItemId();
91
+
92
+ $item->article = new CPArticle();
93
+ $item->article->id = $orderItem->getId();
94
+ $item->article->idExternal = $cpMarketplaceOrderItem->getMarketplaceOrderItemId();
95
+ $item->article->title = $orderItem->getName();
96
+
97
+ $item->quantityOrdered = $orderItem->getQtyOrdered();
98
+ $item->quantityDelivered = $orderItem->getQtyShipped();
99
+ $item->quantityCancelled = $orderItem->getQtyCanceled();
100
+
101
+ $item->costsSingle = new CPMoney();
102
+ $item->costsSingle->gross = $orderItem->getPriceInclTax();
103
+ $item->costsSingle->net = $orderItem->getPrice();
104
+ $item->costsSingle->tax = ($orderItem->getPriceInclTax() - $orderItem->getPrice());
105
+ $item->costsSingle->taxRate = $orderItem->getTaxPercent();
106
+
107
+ $item->costsTotal = new CPMoney();
108
+ $item->costsTotal->gross = $orderItem->getRowTotalInclTax();
109
+ $item->costsTotal->net = $orderItem->getRowTotal();
110
+ $item->costsTotal->tax = $orderItem->getTaxAmount();
111
+ $item->costsTotal->taxRate = $orderItem->getTaxPercent();
112
+
113
+ $item->feeSingleNet = 0;
114
+ $item->feeTotalNet = 0;
115
+
116
+ $deliveredItems[] = $item;
117
}
118
+
119
+ $delivered->deliveredItems = $deliveredItems;
120
+
121
+ $deliveries[] = $delivered;
122
+ $shipments[] = array(
123
+ 'order_id' => $order['order_id'],
124
+ 'order_nr' => $order['order_nr'], // this field is needed to be able to check for defective orders later
125
+ 'shipment_id' => $order['shipment_ids'],
126
+ );
127
}
128
if (sizeof($deliveries) == 0) {
129
self::hookResult(false);
139
foreach($shipments as $shipment) {
140
// if an error occured do not save this shipment
141
if(!in_array($shipment['order_nr'], $defectiveOrderIncrementIds)) {
142
+ $shipmentIds = explode(',', $shipment['shipment_id']);
143
+ foreach($shipmentIds as $shipmentId) {
144
+ $shipmentsToInsert[] = array(
145
+ 'order_id' => $shipment['order_id'],
146
+ 'shipment_id' => $shipmentId,
147
+ );
148
+ }
149
}
150
}
151
+ if(count($shipmentsToInsert) > 0) {
152
+ $insertedRows = Mage::getModel('channelpilot/order_shipment')->addMultipleShipments($shipmentsToInsert);
153
+ }
154
155
} else {
156
// Result from registerDeliveries has no success
170
CPErrorHandler::handle(CPErrors::RESULT_MISSING_PARAMS, "no limit set for method: " . $method, "no limit set for method: " . $method);
171
}
172
} else {
173
+ if ($token) {
174
CPErrorHandler::handle(CPErrors::RESULT_MISSING_PARAMS, "no token found", "no token found");
175
} else {
176
CPErrorHandler::handle(CPErrors::RESULT_FAILED, "ip not allowed by token: " . $token, "ip not allowed by token: " . $token);
179
return "Error during handle deliveryHook";
180
}
181
182
+ protected function hookResult($moreAvailable) {
183
$hook = new CPHookResponse();
184
$hook->resultCode = CPResultCodes::SUCCESS;
185
$hook->resultMessage = "DELIVERY HOOK SUCCESS";
app/code/community/Channelpilotsolutions/Channelpilot/Helper/handler/CPExportHandler.php CHANGED
@@ -8,23 +8,6 @@
8
class CPExportHandler extends CPAbstractHandler {
9
10
private $_storeId;
11
- private $_siteId;
12
- private $_customerGroupId;
13
- private $_mediaUrl;
14
- private $_webUrl;
15
- private $_allCat;
16
- private $_limit;
17
- private $_last;
18
- private $_blankProduct;
19
- private $_configurableAttributes = array();
20
- private $_imageBaseUrl;
21
- private $_maxAdditionalImages;
22
- private $_exportFields;
23
- private $_currencyChange;
24
- private $_replaceFields;
25
- private $_parents;
26
- private $_onlyStockAndPriceData;
27
- private $_backendModel;
28
29
/**
30
* Handle status event
@@ -32,10 +15,7 @@ class CPExportHandler extends CPAbstractHandler {
32
*/
33
public function handle() {
34
ini_set('max_execution_time', 7200);
35
- $limit = Mage::app()->getRequest()->getParam('limit', null);
36
$store = Mage::app()->getRequest()->getParam('store', null);
37
- $this->_limit = $limit;
38
- $this->_last = Mage::app()->getRequest()->getParam('last', null);
39
try {
40
$this->_storeId = Mage::app()->getStore($store)->getId();
41
} catch(Exception $e) {
@@ -43,8 +23,6 @@ class CPExportHandler extends CPAbstractHandler {
43
return;
44
}
45
46
- $this->initExport();
47
-
48
// start the xml output right now to output the exported products as soon as
49
// each product has been processed
50
header('Content-Type: text/xml; charset=utf-8');
@@ -60,7 +38,7 @@ class CPExportHandler extends CPAbstractHandler {
60
* Display an error message based on current export (and therefore display) method
61
* if an exception has occured during Mage::app()->getStore().
62
*/
63
- private function _handleStoreException() {
64
// The exception thrown by Mage::app()->getStore() has an empty message ...
65
$xml = new SimpleXMLElement('<root></root>');
66
$xml->addChild('error', 'Error retrieving store.');
@@ -69,245 +47,22 @@ class CPExportHandler extends CPAbstractHandler {
69
exit();
70
}
71
72
- /**
73
- * Check if another currency (other than the base currency) should be used. Displays an error if the
74
- * given currency could not be found.
75
- */
76
- private function _initCurrencyChange() {
77
- $this->_currencyChange = null;
78
- $currencyCode = Mage::app()->getRequest()->getParam('currency', false);
79
- if ($currencyCode && $currencyCode != '') {
80
- $result = Mage::getModel('directory/currency')->getCurrencyRates(Mage::app()->getBaseCurrencyCode(), $currencyCode);
81
- if(count($result) === 0){
82
- $xml = new SimpleXMLElement('<root></root>');
83
- $xml->addChild('error', 'wrong currency');
84
- header('Content-Type: text/xml; charset=utf-8');
85
- echo $xml->asXML();
86
- exit();
87
- }
88
- $this->_currencyChange = $result[$currencyCode];
89
- }
90
- }
91
-
92
- /**
93
- * Initialize the export.
94
- */
95
- private function initExport() {
96
- // Initialize the admin application
97
- Mage::app('admin');
98
-
99
- $this->_blankProduct = array();
100
- $this->_blankProduct['entity_id'] = '';
101
- $this->_blankProduct['sku'] = '';
102
- $this->_blankProduct['parent_id'] = '';
103
- $this->_blankProduct['variationTheme'] = '';
104
- $this->_blankProduct['name'] = '';
105
- $this->_blankProduct['description'] = '';
106
- $this->_blankProduct['price'] = '';
107
- $this->_blankProduct['categories'] = '';
108
- $this->_blankProduct['manufacturer'] = '';
109
- $this->_blankProduct['manufacturer_name'] = '';
110
- $this->_blankProduct['cp_product_url'] = '';
111
- $this->_blankProduct['cp_image_url'] = '';
112
- $this->_blankProduct['color'] = '';
113
- $this->_blankProduct['weight'] = '';
114
- for($i = 1; $i <= Mage::getStoreConfig('channelpilot_export/channelpilot_productfeed/channelpilot_imagenumber'); $i++) {
115
- $this->_blankProduct['cp_additional_image_'.$i] = '';
116
- }
117
-
118
- $specialExportFields = unserialize(Mage::getStoreConfig('channelpilot_export/channelpilot_productfeed/channelpilot_specialexportfields'));
119
- if(!empty($specialExportFields)) {
120
- foreach($specialExportFields as $field) {
121
- if (!empty($field['name'])) {
122
- $this->_blankProduct[preg_replace('/\W/', '', $field['name'])] = $field['value'];
123
- }
124
- }
125
- }
126
-
127
- try {
128
- $store = Mage::app()->getStore($this->_storeId);
129
- $this->_siteId = $store->getWebsiteId();
130
- $this->_customerGroupId = Mage_Customer_Model_Group::NOT_LOGGED_IN_ID;
131
- $this->_webUrl = $store->getBaseUrl(Mage_Core_Model_Store::URL_TYPE_WEB);
132
- $this->_mediaUrl = $store->getBaseUrl(Mage_Core_Model_Store::URL_TYPE_MEDIA);
133
- } catch (Exception $e) {
134
- die('Store=' . $this->_storeId . " probably does not exist.");
135
- }
136
-
137
- $this->buildCategoryTree();
138
-
139
- $this->_initCurrencyChange();
140
-
141
- $this->_initConfigurableAttributes();
142
-
143
- /** @var $mediaConfig Mage_Catalog_Model_Product_Media_Config */
144
- $mediaConfig = Mage::getSingleton('catalog/product_media_config');
145
- $this->_imageBaseUrl = $mediaConfig->getBaseMediaUrl();
146
-
147
- $this->_maxAdditionalImages = Mage::getStoreConfig('channelpilot_export/channelpilot_productfeed/channelpilot_imagenumber');
148
- $this->_exportFields = unserialize(Mage::getStoreConfig('channelpilot_export/channelpilot_productfeed/channelpilot_exportfields'));
149
- $this->_replaceFields = unserialize(Mage::getStoreConfig('channelpilot_export/channelpilot_productfeed/channelpilot_replacefields'));
150
-
151
- $this->_parents = array();
152
- }
153
-
154
- /**
155
- * Build the category tree.
156
- */
157
- public function buildCategoryTree() {
158
- $this->_allCat = array();
159
-
160
- $categoryCollection = Mage::getModel('catalog/category')->getCollection()
161
- ->addAttributeToSelect('name')
162
- ->addAttributeToSort('path');
163
-
164
- foreach($categoryCollection as $category) {
165
- $path = $this->getCategory($category->getPath());
166
- if($path !== 0) {
167
- $this->_allCat[$category->getPath()] = str_replace('Root Catalog', 'Home', $path . '>' . $category->getName());
168
- } else {
169
- $this->_allCat[$category->getPath()] = str_replace('Root Catalog', 'Home', $category->getName());
170
- }
171
- }
172
- }
173
-
174
- /**
175
- * Get the category id from a path.
176
- * @param $key
177
- * @return int | string
178
- */
179
- private function getCategory($key) {
180
- $return = 0;
181
- if (strpos($key, '/') != false) {
182
- $tmpKey = substr($key, 0, strpos($key, strrchr($key, '/')));
183
- if (isset($this->_allCat[$tmpKey])) {
184
- $return = $this->_allCat[$tmpKey];
185
- } else {
186
- $return = $this->getCategory($tmpKey);
187
- }
188
- }
189
- return $return;
190
- }
191
-
192
- /**
193
- * Initialize the configurableAttributes array.
194
- * Array(
195
- * [PRODUCT_ID] => ARRAY(
196
- * [ATTRIBUTE_CODE] => [FRONTEND_LABEL]
197
- * )
198
- * )
199
- */
200
- private function _initConfigurableAttributes() {
201
- $this->_configurableAttributes = array();
202
-
203
- $connection = Mage::getSingleton('core/resource')->getConnection('core_read');
204
-
205
- $select = $connection->select()
206
- ->from(array('super_attribute' => Mage::getSingleton('core/resource')->getTableName('catalog/product_super_attribute')), array('attribute_id', 'product_id'))
207
- ->join(array('attribute' => Mage::getSingleton('core/resource')->getTableName('eav/attribute')),
208
- 'attribute.attribute_id = super_attribute.attribute_id',
209
- array('attribute_code', 'frontend_label')
210
- );
211
-
212
- $result = $connection->fetchAll($select);
213
-
214
- foreach($result as $attribute) {
215
- if(!isset($this->_configurableAttributes[$attribute['product_id']])) {
216
- $this->_configurableAttributes[$attribute['product_id']] = array();
217
- }
218
- $this->_configurableAttributes[$attribute['product_id']][$attribute['attribute_code']] = $attribute['frontend_label'];
219
- }
220
- }
221
-
222
- /**
223
- * Get an array of attribute codes for all configurable attributes of a product ID.
224
- *
225
- * @param int $productId
226
- * @return array
227
- */
228
- private function _getConfigurableAttributes($productId) {
229
- $attributeOptions = array();
230
- if(isset($this->_configurableAttributes[$productId])) {
231
- foreach($this->_configurableAttributes[$productId] as $attributeCode => $label) {
232
- $attributeOptions[] = $label;
233
- }
234
- }
235
- return $attributeOptions;
236
- }
237
-
238
/**
239
* Callback function used for the collection iterator.
240
* The function receives an array containing the fetched row from the database.
241
* Saves the product to export in the _productData array.
242
* @param $args array
243
*/
244
- public function productCallback($args)
245
{
246
- $product = Mage::getModel('catalog/product');
247
- $product->setData($args['row']);
248
-
249
- if($this->_onlyStockAndPriceData) {
250
- $result = $this->_getOnlyStockAndPriceData($product);
251
- } else {
252
- $this->_backendModel->afterLoad($product);
253
- $result = $this->_getFullProductData($product);
254
- }
255
-
256
- // instead of saving the result and creating the complete xml later,
257
- // the xml for the product is created and echoed right now to improve time and memory usage
258
- $productXml = new SimpleXMLElement('<product></product>');
259
- $this->_productToXml($result, $productXml);
260
- $dom = dom_import_simplexml($productXml);
261
- echo $dom->ownerDocument->saveXML($dom->ownerDocument->documentElement);
262
- }
263
-
264
- /**
265
- * Get all attributes that need to be selected from the database.
266
- * @param $attributes array
267
- * @return array
268
- */
269
- private function _getAttributesForSelect($attributes) {
270
- $attributesToSelect = array(
271
- 'entity_id',
272
- 'sku',
273
- 'name',
274
- 'description',
275
- 'price',
276
- 'manufacturer',
277
- 'color',
278
- 'weight',
279
- 'media_gallery',
280
- 'url_key',
281
- 'url_path',
282
- 'image',
283
- 'type_id'
284
- );
285
-
286
- $attributeCodes = array();
287
-
288
- // save all available attribute codes
289
- foreach($attributes as $code => $attribute) {
290
- $attributeCodes[] = $code;
291
- }
292
-
293
- // add all attributes from the config if the attribute is a Magento attribute and it has
294
- // not already been added to the $attributesToSelect array
295
- foreach($this->_exportFields as $field) {
296
- $attrCode = $field['productattribute'];
297
- if(in_array($attrCode, $attributeCodes) && !in_array($attrCode, $attributesToSelect)) {
298
- $attributesToSelect[] = $attrCode;
299
- }
300
- }
301
-
302
- return $attributesToSelect;
303
-
304
}
305
306
/**
307
* Export the products and return them as array.
308
- * @return array
309
*/
310
- private function _export() {
311
$flatEnabled = false;
312
if(class_exists('Mage_Core_Model_App_Emulation')) {
313
/* @var $flatHelper Mage_Catalog_Helper_Product_Flat */
@@ -324,365 +79,65 @@ class CPExportHandler extends CPAbstractHandler {
324
}
325
}
326
327
- /** @var $collection Mage_Catalog_Model_Resource_Product_Collection */
328
- $collection = Mage::getModel('catalog/product')->getCollection();
329
- $attributes = $collection->getEntity()->loadAllAttributes()->getAttributesByCode();
330
-
331
- // only use the needed attributes instead of every available
332
- $attributeCodes = $this->_getAttributesForSelect($attributes);
333
334
- // addPriceData uses inner join to get the price data for a website_id and a customer_group id
335
- // so all products that are not associated to $this->_siteId and the customerGroupId (NOT LOGGED IN (0) by default)
336
- // are not included in this collection.
337
- // addPriceData is needed for getting the minimal price for bundels
338
- $collection
339
- ->addAttributeToSelect($attributeCodes, 'left')
340
- ->addPriceData($this->_customerGroupId, $this->_siteId)
341
- ->joinField('qty',
342
- 'cataloginventory/stock_item',
343
- 'qty',
344
- 'product_id=entity_id',
345
- '{{table}}.stock_id=1',
346
- 'left')
347
- ->joinField('min_sale_qty',
348
- 'cataloginventory/stock_item',
349
- 'min_sale_qty',
350
- 'product_id=entity_id',
351
- '{{table}}.stock_id=1',
352
- 'left')
353
- ->joinField('max_sale_qty',
354
- 'cataloginventory/stock_item',
355
- 'max_sale_qty',
356
- 'product_id=entity_id',
357
- '{{table}}.stock_id=1',
358
- 'left')
359
- ->joinField('is_in_stock',
360
- 'cataloginventory/stock_item',
361
- 'is_in_stock',
362
- 'product_id=entity_id',
363
- '{{table}}.stock_id=1',
364
- 'left')
365
- ->addAttributeToSort('type_id')
366
- ->setStoreId($this->_storeId);
367
368
- // add group price fields
369
- foreach($this->_exportFields as $field) {
370
- if(strpos($field['productattribute'], 'group_price') !== false) {
371
- $groupId = substr($field['productattribute'], 12);
372
- if(is_numeric($groupId)) {
373
- $collection->joinField('group_price_'.$groupId,
374
- 'catalog/product_index_price',
375
- 'group_price',
376
- 'entity_id=entity_id',
377
- '{{table}}.customer_group_id='.$groupId,
378
- 'left');
379
- }
380
}
381
- }
382
383
- $this->_backendModel = $collection->getResource()->getAttribute('media_gallery')->getBackend();
384
- $this->_onlyStockAndPriceData = (Mage::app()->getRequest()->getParam('priceStock', '') === "true");
385
386
- /** @var $iterator Mage_Core_Model_Resource_Iterator */
387
- $iterator = Mage::getSingleton('core/resource_iterator');
388
- $iterator->walk($collection->getSelect(), array(array($this, 'productCallback')));
389
390
- // stop emulating admin store and set initial environment
391
- if ($flatEnabled) {
392
- $emulationModel->stopEnvironmentEmulation($initialEnvironmentInfo);
393
- }
394
- }
395
-
396
- /**
397
- * Get the current $item as array.
398
- * Returns Array(
399
- * [ATTRIBUTE_CODE] => [VALUE]
400
- * )
401
- * @param Mage_Catalog_Model_Product $item
402
- * @return array
403
- */
404
- private function _getFullProductData(Mage_Catalog_Model_Product $item) {
405
- $imageUrl = $this->_imageBaseUrl . $item->getImage();
406
-
407
- $isParent = 0;
408
- if ($item->getTypeId() == Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE) {
409
- $isParent = 1;
410
- }
411
-
412
- $parentId = null;
413
- if ($item->getTypeId() == Mage_Catalog_Model_Product_Type::TYPE_SIMPLE) {
414
- $parentId = Mage::getModel('catalog/product_type_configurable')->getParentIdsByChild($item->getId());
415
- $parentId = (is_array($parentId) && !empty($parentId)) ? $parentId[0] : null;
416
- }
417
-
418
- $configurableAttributes = array();
419
- if($parentId && isset($this->_variationThemes[$parentId])) {
420
- $configurableAttributes = $this->_variationThemes[$parentId];
421
- } else if($isParent && $parentId === null) {
422
- $configurableAttributes = $this->_getConfigurableAttributes($item->getId());
423
- $configurableAttributes = (!empty($configurableAttributes)) ? implode('|', $configurableAttributes) : '';
424
- $this->_variationThemes[$item->getId()] = $configurableAttributes;
425
- }
426
-
427
- // workaround... $item->getProductUrl() sometimes adds store code to url (e.g. <url>?___store=default)
428
- $productUrl = $this->_webUrl . $item->getUrlPath();
429
- $colorText = $item->getAttributeText('color');
430
-
431
- // set the value to the minimal price if the current product is a bundle, otherwise the product's price
432
- $calcPrice = ($item->getTypeId() == Mage_Catalog_Model_Product_Type::TYPE_BUNDLE) ? Mage::getModel('bundle/product_price')->getTotalPrices($item, 'min', true, false) : $item->getPrice();
433
-
434
- $rulePrice = Mage::getModel('catalogrule/rule')->calcProductPriceRule($item->setStoreId($this->_storeId),$calcPrice);
435
- $price = ($rulePrice) ? $rulePrice : $calcPrice;
436
-
437
- $product = $this->_blankProduct;
438
-
439
- $product['entity_id'] = $item->getId();
440
- $product['sku'] = $item->getSku();
441
- $product['parent_id'] = $parentId;
442
- $product['variationTheme'] = $configurableAttributes;
443
- $product['name'] = $this->_getCleanedStringForXml($item->getName());
444
- $product['description'] = $this->_getCleanedStringForXml($item->getDescription());
445
-
446
- $product['price'] = $price;
447
- if($this->_currencyChange) {
448
- $product['price'] = round($product['price']*$this->_currencyChange, 2);
449
- }
450
-
451
- $product['categories'] = $this->_getCategoryInformation($item);
452
- $product['manufacturer'] = $this->_getCleanedStringForXml($item->getManufacturer());
453
- $product['manufacturer_name'] = $this->_getCleanedStringForXml($item->getAttributeText('manufacturer'));
454
- $product['cp_product_url'] = $productUrl;
455
- $product['cp_image_url'] = $imageUrl;
456
- $product['color'] = ($colorText) ? $this->_getCleanedStringForXml($colorText) : null;
457
- $product['weight'] = $item->getWeight();
458
-
459
- $product = array_merge($product, $this->_getAdditionalImages($item));
460
461
- $product['is_parent'] = $isParent;
462
463
- $this->_addExportFields($product, $item);
464
465
- if(!empty($this->_replaceFields) && !$isParent && $parentId !== null) {
466
- $this->_replaceFields($product, $parentId);
467
- }
468
-
469
- return $product;
470
- }
471
-
472
- /**
473
- * Get the additional images for a product
474
- * @param Mage_Catalog_Model_Product $product
475
- * @return array
476
- */
477
- private function _getAdditionalImages(Mage_Catalog_Model_Product $product) {
478
- $counter = 1;
479
- $productData = array();
480
- foreach ($product->getMediaGalleryImages() as $image) {
481
- // break if the maximum amount of additional images has been reached
482
- if ($counter > $this->_maxAdditionalImages) {
483
- break;
484
- }
485
-
486
- // ignore the base image; it has already been added
487
- if ($image->getFile() == $product->getImage()) {
488
- continue;
489
- }
490
-
491
- $productData['cp_additional_image_' . $counter] = $this->_imageBaseUrl . $image->getFile();
492
- $counter++;
493
- }
494
-
495
- return $productData;
496
- }
497
-
498
- /**
499
- * Add all fields to a product that need to be exported
500
- * @param $product
501
- * @param Mage_Catalog_Model_Product $item
502
- */
503
- private function _addExportFields(&$product, Mage_Catalog_Model_Product $item) {
504
- foreach($this->_exportFields as $field) {
505
- $code = $field['productattribute'];
506
- if(strpos($code, 'group_price') !== false) {
507
- $groupId = substr($code, 12);
508
- $customerGroup = Mage::getModel('customer/group')->load($groupId);
509
- $groupCode = str_replace(' ', '_', $customerGroup->getCustomerGroupCode());
510
- $product['group_price_'.$groupCode] = $item->getData('group_price_'.$customerGroup->getId());
511
- } else {
512
- switch($code) {
513
- // ignore
514
- case 'parent_id':
515
- break;
516
- case 'qty':
517
- $product[$code] = $item->getQty();
518
- break;
519
- case 'stock_status':
520
- $product[$code] = $item->getIsInStock();
521
- break;
522
- case 'min_sale_qty':
523
- case 'max_sale_qty':
524
- case 'tax_class_id':
525
- $product[$code] = $item->getData($code);
526
- break;
527
- default:
528
- $attributeText = ($item->getResource()->getAttribute($code)) ? $item->getAttributeText($code) : false;
529
- if(is_array($attributeText)) {
530
- $attributeText = implode(',',$attributeText);
531
- }
532
- $product[$code] = ($attributeText) ? $this->_getCleanedStringForXml($attributeText) : $this->_getCleanedStringForXml($item->getData($code));
533
}
534
}
535
- }
536
- }
537
-
538
- /**
539
- * Replace all selected fields with the parent's values.
540
- * @param $product
541
- * @param $parentId
542
- */
543
- private function _replaceFields(&$product, $parentId) {
544
- $parent = $this->_getParentById($parentId);
545
- if($parent !== null && $parent->getId()) {
546
- $parentImages = $this->_getAdditionalImages($parent);
547
- foreach($this->_replaceFields as $field) {
548
- $code = $field['productattribute'];
549
- if(strpos($code, 'group_price') !== false) {
550
- $groupId = substr($code, 12);
551
- $customerGroup = Mage::getModel('customer/group')->load($groupId);
552
- $groupPrices = $parent->getData('group_price');
553
- foreach($groupPrices as $groupPrice) {
554
- if($groupPrice['cust_group'] == $groupId) {
555
- $groupCode = str_replace(' ', '_', $customerGroup->getCustomerGroupCode());
556
- $product['group_price_'.$groupCode] = $groupPrice['price'];
557
- }
558
- }
559
- } else if(strpos($code, 'cp_additional_image') !== false && isset($parentImages[$code])) {
560
- $product[$code] = $parentImages[$code];
561
- } else {
562
- switch($code) {
563
- case 'categories':
564
- $product['categories'] = $this->_getCategoryInformation($parent);
565
- break;
566
- case 'cp_product_url':
567
- $product[$code] = $this->_webUrl . $parent->getUrlPath();
568
- break;
569
- case 'cp_image_url':
570
- $product[$code] = $this->_imageBaseUrl . $parent->getImage();
571
- break;
572
- case 'qty':
573
- $product[$code] = $parent->getStockItem()->getQty();
574
- break;
575
- case 'stock_status':
576
- $product[$code] = $parent->getStockItem()->getIsInStock();
577
- break;
578
- case 'min_sale_qty':
579
- $product[$code] = $parent->getStockItem()->getMinSaleQty();
580
- break;
581
- case 'max_sale_qty':
582
- $product[$code] = $parent->getStockItem()->getMaxSaleQty();
583
- break;
584
- case 'tax_class_id':
585
- $product[$code] = $parent->getData($code);
586
- break;
587
- default:
588
- $attributeText = ($parent->getResource()->getAttribute($code)) ? $parent->getAttributeText($code) : false;
589
- if(is_array($attributeText)) {
590
- $attributeText = implode(',',$attributeText);
591
- }
592
- $product[$code] = ($attributeText) ? $this->_getCleanedStringForXml($attributeText) : $this->_getCleanedStringForXml($parent->getData($code));
593
- }
594
- }
595
}
596
- }
597
- }
598
599
- /**
600
- * Get only the stock and price data for a product as array. Attributes: entity_id, sku, price, qty.
601
- * Array(
602
- * [ATTRIBUTE_CODE] => [VALUE]
603
- * )
604
- * @param Mage_Catalog_Model_Product $item
605
- * @return array
606
- */
607
- private function _getOnlyStockAndPriceData(Mage_Catalog_Model_Product $item) {
608
- $rulePrice = Mage::getModel('catalogrule/rule')->calcProductPriceRule($item->setStoreId($this->_storeId),$item->getPrice());
609
- $price = ($rulePrice) ? $rulePrice : $item->getPrice();
610
-
611
- $product['entity_id'] = $item->getId();
612
- $product['sku'] = $item->getSku();
613
- $product['price'] = $price;
614
- if($this->_currencyChange) {
615
- $product['price'] = round($product['price']*$this->_currencyChange, 2);
616
}
617
618
- $product['qty'] = $item->getQty();
619
-
620
- return $product;
621
- }
622
-
623
- /**
624
- * Adds the values of the $product array to the $xml structure.
625
- * @param array $product
626
- * @param SimpleXMLElement $xml
627
- */
628
- private function _productToXml(array $product, SimpleXMLElement $xml) {
629
- foreach($product as $code => $value) {
630
- if(is_array($value)) {
631
- $node = $xml->addChild($code);
632
- $this->_productToXml($value, $node);
633
- } else if (is_string($value) || is_numeric($value) || is_bool($value) || is_null($value)) {
634
- $xml->addChild($code, htmlspecialchars($value));
635
- }
636
- }
637
- }
638
-
639
- /**
640
- * Get the category information for a product.
641
- * @param Mage_Catalog_Model_Product $product
642
- * @return string
643
- */
644
- private function _getCategoryInformation(Mage_Catalog_Model_Product $product) {
645
- $arrPath = array();
646
-
647
- /** @var $category Mage_Catalog_Model_Category */
648
- foreach($product->getCategoryCollection() as $category) {
649
- $arrPath[] = $this->_allCat[$category->getPath()];
650
- }
651
-
652
- return ltrim(implode(',', $arrPath), '>');
653
- }
654
-
655
- /**
656
- * Get a product by its id. Save the loaded product to an array to cache it.
657
- * It is used for parent products only so these products do not need to be loaded by each
658
- * of its child products.
659
- * @param $parentId
660
- * @return mixed
661
- */
662
- private function _getParentById($parentId) {
663
- if(!isset($this->_parents[$parentId])) {
664
- $parent = Mage::getModel('catalog/product')->load($parentId);
665
- $this->_parents[$parentId] = ($parent->getId()) ? $parent : null;
666
}
667
- return $this->_parents[$parentId];
668
- }
669
-
670
- /**
671
- * Clean a string for usage in XML.
672
- * @param $string
673
- * @return mixed
674
- */
675
- private function _getCleanedStringForXml($string) {
676
- return $this->_utf8ForXml(html_entity_decode($string));
677
- }
678
-
679
- /**
680
- * Replace all UTF-8 characters that are not allowed in XML with a space.
681
- * @param $string
682
- * @return mixed
683
- */
684
- private function _utf8ForXml($string) {
685
- return preg_replace ('/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u', ' ', $string);
686
}
687
}
688
8
class CPExportHandler extends CPAbstractHandler {
9
10
private $_storeId;
11
12
/**
13
* Handle status event
15
*/
16
public function handle() {
17
ini_set('max_execution_time', 7200);
18
$store = Mage::app()->getRequest()->getParam('store', null);
19
try {
20
$this->_storeId = Mage::app()->getStore($store)->getId();
21
} catch(Exception $e) {
23
return;
24
}
25
26
// start the xml output right now to output the exported products as soon as
27
// each product has been processed
28
header('Content-Type: text/xml; charset=utf-8');
38
* Display an error message based on current export (and therefore display) method
39
* if an exception has occured during Mage::app()->getStore().
40
*/
41
+ protected function _handleStoreException() {
42
// The exception thrown by Mage::app()->getStore() has an empty message ...
43
$xml = new SimpleXMLElement('<root></root>');
44
$xml->addChild('error', 'Error retrieving store.');
47
exit();
48
}
49