FarApp_Connector - Version 1.5.6

Version Notes

Added support for special values FARAPPOMIT and FARAPPIGNORE.

Download this release

Release Info

Developer FarApp
Extension FarApp_Connector
Version 1.5.6
Comparing to
See all releases


Code changes from version 1.5.5 to 1.5.6

app/code/community/FarApp/Connector/Model/Import/Entity/Product.php CHANGED
@@ -268,6 +268,125 @@ class FarApp_Connector_Model_Import_Entity_Product extends Mage_ImportExport_Mod
268
  return $this;
269
  }
270
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
271
  protected function _saveStockItem()
272
  {
273
  $defaultStockData = array(
@@ -352,9 +471,22 @@ class FarApp_Connector_Model_Import_Entity_Product extends Mage_ImportExport_Mod
352
  return $this;
353
  }
354
 
 
 
 
 
355
  protected function _filterRowData(&$rowData)
356
  {
357
  $rowData = array_filter($rowData, 'strlen');
 
 
 
 
 
 
 
 
 
358
  // Exceptions - for sku - put them back in
359
  if (!isset($rowData[self::COL_SKU])) {
360
  $rowData[self::COL_SKU] = null;
268
  return $this;
269
  }
270
 
271
+ /**
272
+ * Prepare attributes data
273
+ *
274
+ * @param array $rowData Row data
275
+ * @param int $rowScope Row scope
276
+ * @param array $attributes Attributes
277
+ * @param string|null $rowSku Row sku
278
+ * @param int $rowStore Row store
279
+ * @return array
280
+ */
281
+ protected function _prepareAttributes($rowData, $rowScope, $attributes, $rowSku, $rowStore)
282
+ {
283
+ if (method_exists($this, '_prepareUrlKey')) {
284
+ $rowData = $this->_prepareUrlKey($rowData, $rowScope, $rowSku);
285
+ }
286
+ $product = Mage::getModel('importexport/import_proxy_product', $rowData);
287
+ foreach ($rowData as $attrCode => $attrValue) {
288
+ $attribute = $this->_getAttribute($attrCode);
289
+ if ('multiselect' != $attribute->getFrontendInput()
290
+ && self::SCOPE_NULL == $rowScope
291
+ ) {
292
+ continue; // skip attribute processing for SCOPE_NULL rows
293
+ }
294
+ $attrId = $attribute->getId();
295
+ $backModel = $attribute->getBackendModel();
296
+ $attrTable = $attribute->getBackend()->getTable();
297
+ $storeIds = array($rowStore);
298
+ if (!is_null($attrValue)) {
299
+ if ('datetime' == $attribute->getBackendType() && strtotime($attrValue)) {
300
+ $attrValue = gmstrftime($this->_getStrftimeFormat(), strtotime($attrValue));
301
+ } elseif ($backModel) {
302
+ $attribute->getBackend()->beforeSave($product);
303
+ $attrValue = $product->getData($attribute->getAttributeCode());
304
+ }
305
+ }
306
+ if (self::SCOPE_STORE == $rowScope) {
307
+ if (self::SCOPE_WEBSITE == $attribute->getIsGlobal()) {
308
+ // check website defaults already set
309
+ if (!isset($attributes[$attrTable][$rowSku][$attrId][$rowStore])) {
310
+ $storeIds = $this->_storeIdToWebsiteStoreIds[$rowStore];
311
+ }
312
+ } elseif (self::SCOPE_STORE == $attribute->getIsGlobal()) {
313
+ $storeIds = array($rowStore);
314
+ }
315
+ }
316
+ foreach ($storeIds as $storeId) {
317
+ if ('multiselect' == $attribute->getFrontendInput()) {
318
+ if (!isset($attributes[$attrTable][$rowSku][$attrId][$storeId])) {
319
+ $attributes[$attrTable][$rowSku][$attrId][$storeId] = '';
320
+ } else {
321
+ $attributes[$attrTable][$rowSku][$attrId][$storeId] .= ',';
322
+ }
323
+ $attributes[$attrTable][$rowSku][$attrId][$storeId] .= $attrValue;
324
+ } else {
325
+ $attributes[$attrTable][$rowSku][$attrId][$storeId] = $attrValue;
326
+ }
327
+ }
328
+ $attribute->setBackendModel($backModel); // restore 'backend_model' to avoid 'default' setting
329
+ }
330
+ return $attributes;
331
+ }
332
+
333
+ /**
334
+ * Save product attributes.
335
+ *
336
+ * @param array $attributesData Attribute data
337
+ * @return Mage_ImportExport_Model_Import_Entity_Product
338
+ */
339
+ protected function _saveProductAttributes(array $attributesData)
340
+ {
341
+ foreach ($attributesData as $tableName => $skuData) {
342
+ $tableData = array();
343
+ foreach ($skuData as $sku => $attributes) {
344
+ $productId = $this->_newSku[$sku]['entity_id'];
345
+ foreach ($attributes as $attributeId => $storeValues) {
346
+ foreach ($storeValues as $storeId => $storeValue) {
347
+ // For storeId 0 we *must* save the NULL value into DB otherwise product collections can not load the store specific values
348
+ if ($storeId == 0 || ! is_null($storeValue)) {
349
+ $tableData[] = array(
350
+ 'entity_id' => $productId,
351
+ 'entity_type_id' => $this->_entityTypeId,
352
+ 'attribute_id' => $attributeId,
353
+ 'store_id' => $storeId,
354
+ 'value' => $storeValue
355
+ );
356
+ } else {
357
+ /** @var Magento_Db_Adapter_Pdo_Mysql $connection */
358
+ $connection = $this->_connection;
359
+ $connection->delete($tableName, array(
360
+ 'entity_id=?' => (int) $productId,
361
+ 'entity_type_id=?' => (int) $this->_entityTypeId,
362
+ 'attribute_id=?' => (int) $attributeId,
363
+ 'store_id=?' => (int) $storeId,
364
+ ));
365
+ }
366
+ }
367
+ if (Mage_ImportExport_Model_Import::BEHAVIOR_APPEND != $this->getBehavior()) {
368
+ /**
369
+ * If the store based values are not provided for a particular store,
370
+ * we default to the default scope values.
371
+ * In this case, remove all the existing store based values stored in the table.
372
+ **/
373
+ $where = $this->_connection->quoteInto('store_id NOT IN (?)', array_keys($storeValues)) .
374
+ $this->_connection->quoteInto(' AND attribute_id = ?', $attributeId) .
375
+ $this->_connection->quoteInto(' AND entity_id = ?', $productId) .
376
+ $this->_connection->quoteInto(' AND entity_type_id = ?', $this->_entityTypeId);
377
+ $this->_connection->delete(
378
+ $tableName, $where
379
+ );
380
+ }
381
+ }
382
+ }
383
+ if (count($tableData)) {
384
+ $this->_connection->insertOnDuplicate($tableName, $tableData, array('value'));
385
+ }
386
+ }
387
+ return $this;
388
+ }
389
+
390
  protected function _saveStockItem()
391
  {
392
  $defaultStockData = array(
471
  return $this;
472
  }
473
 
474
+ public function filterRowData(&$rowData) {
475
+ $this->_filterRowData($rowData);
476
+ }
477
+
478
  protected function _filterRowData(&$rowData)
479
  {
480
  $rowData = array_filter($rowData, 'strlen');
481
+
482
+ foreach($rowData as $key => $fieldValue) {
483
+ if (trim($fieldValue) == 'FARAPPOMIT') {
484
+ $rowData[$key] = NULL;
485
+ } else if (trim($fieldValue) == 'FARAPPIGNORE') {
486
+ unset($rowData[$key]);
487
+ }
488
+ }
489
+
490
  // Exceptions - for sku - put them back in
491
  if (!isset($rowData[self::COL_SKU])) {
492
  $rowData[self::COL_SKU] = null;
app/code/community/FarApp/Connector/Model/Import/Entity/Product/Type/Bundle.php ADDED
@@ -0,0 +1,350 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class FarApp_Connector_Model_Import_Entity_Product_Type_Bundle
4
+ extends Mage_ImportExport_Model_Import_Entity_Product_Type_Abstract
5
+ {
6
+
7
+ const DEFAULT_OPTION_TYPE = 'select';
8
+ const ERROR_INVALID_BUNDLE_PRODUCT_SKU = 'invalidBundleProductSku';
9
+
10
+ protected $_particularAttributes = array(
11
+ '_bundle_option_required',
12
+ '_bundle_option_position',
13
+ '_bundle_option_type',
14
+ '_bundle_option_title',
15
+ '_bundle_option_store',
16
+ '_bundle_option_store_title',
17
+ '_bundle_product_sku',
18
+ '_bundle_product_position',
19
+ '_bundle_product_is_default',
20
+ '_bundle_product_price_type',
21
+ '_bundle_product_price_value',
22
+ '_bundle_product_qty',
23
+ '_bundle_product_can_change_qty'
24
+ );
25
+
26
+ protected $_bundleOptionTypes = array(
27
+ 'select',
28
+ 'radio',
29
+ 'checkbox',
30
+ 'multi'
31
+ );
32
+
33
+ public function _initAttributes()
34
+ {
35
+ parent::_initAttributes();
36
+
37
+ /*
38
+ * Price type and Sku type does not live in an attribute set, so it is not picked up
39
+ * by abstract _initAttributes method. We add it here manually.
40
+ */
41
+
42
+ $typeAttributes = array('price_type', 'sku_type');
43
+ foreach ($this->_attributes as $attrSetName => $attributes) {
44
+ foreach ($typeAttributes as $attributeCode) {
45
+ $attribute = Mage::getResourceModel('catalog/eav_attribute')->load($attributeCode, 'attribute_code');
46
+ $this->_addAttributeParams(
47
+ $attrSetName,
48
+ array(
49
+ 'id' => $attribute->getId(),
50
+ 'code' => $attribute->getAttributeCode(),
51
+ 'for_configurable' => $attribute->getIsConfigurable(),
52
+ 'is_global' => $attribute->getIsGlobal(),
53
+ 'is_required' => false,
54
+ 'is_unique' => $attribute->getIsUnique(),
55
+ 'frontend_label' => $attribute->getFrontendLabel(),
56
+ 'is_static' => $attribute->isStatic(),
57
+ 'apply_to' => $attribute->getApplyTo(),
58
+ 'type' => Mage_ImportExport_Model_Import::getAttributeType($attribute),
59
+ 'default_value' => strlen($attribute->getDefaultValue()) ? $attribute->getDefaultValue() : null,
60
+ 'options' => $this->_entityModel->getAttributeOptions($attribute, $this->_indexValueAttributes)
61
+ )
62
+ );
63
+ }
64
+
65
+ }
66
+ }
67
+
68
+ public function saveData()
69
+ {
70
+ if(!$this->isSuitable())
71
+ {
72
+ return $this;
73
+ }
74
+ $connection = $this->_entityModel->getConnection();
75
+ $newSku = $this->_entityModel->getNewSku();
76
+ $oldSku = $this->_entityModel->getOldSku();
77
+ $optionTable = Mage::getSingleton('core/resource')->getTableName('bundle/option');
78
+ $optionValueTable = Mage::getSingleton('core/resource')->getTableName('bundle/option_value');
79
+ $selectionTable = Mage::getSingleton('core/resource')->getTableName('bundle/selection');
80
+ $relationTable = Mage::getSingleton('core/resource')->getTableName('catalog/product_relation');
81
+ $productData = null;
82
+ $productId = null;
83
+
84
+ while ($bunch = $this->_entityModel->getNextBunch()) {
85
+ $bundleOptions = array();
86
+ $bundleSelections = array();
87
+ $bundleTitles = array();
88
+ foreach ($bunch as $rowNum => $rowData) {
89
+ if (!$this->_entityModel->isRowAllowedToImport($rowData, $rowNum)) {
90
+ continue;
91
+ }
92
+ $this->_entityModel->filterRowData($rowData);
93
+ $scope = $this->_entityModel->getRowScope($rowData);
94
+ if (Mage_ImportExport_Model_Import_Entity_Product::SCOPE_DEFAULT == $scope) {
95
+ $productData = $newSku[$rowData[Mage_ImportExport_Model_Import_Entity_Product::COL_SKU]];
96
+
97
+ if ($this->_type != $productData['type_id']) {
98
+ $productData = null;
99
+ continue;
100
+ }
101
+ $productId = $productData['entity_id'];
102
+ } elseif (null === $productData) {
103
+ continue;
104
+ }
105
+
106
+ if (empty($rowData['_bundle_option_title'])) {
107
+ continue;
108
+ } else {
109
+ $bundleTitles[$rowData['_bundle_option_title']][Mage_Catalog_Model_Abstract::DEFAULT_STORE_ID] = $rowData['_bundle_option_title'];
110
+ }
111
+ if (!empty($rowData['_bundle_option_store']) && !empty($rowData['_bundle_option_store_title'])) {
112
+ $optionStore = $rowData['_bundle_option_store'];
113
+ $storeId = Mage::app()->getStore($optionStore)->getId();
114
+ $bundleTitles[$rowData['_bundle_option_title']][$storeId] = $rowData['_bundle_option_store_title'];
115
+ }
116
+ if (isset($rowData['_bundle_option_type']) && !empty($rowData['_bundle_option_type'])) {
117
+ if (!in_array($rowData['_bundle_option_type'], $this->_bundleOptionTypes)) {
118
+ continue;
119
+ }
120
+
121
+ $bundleOptions[$productId][$rowData['_bundle_option_title']] = array(
122
+ 'parent_id' => $productId,
123
+ 'required' => !empty($rowData['_bundle_option_required']) ? $rowData['_bundle_option_required'] : '0',
124
+ 'position' => !empty($rowData['_bundle_option_position']) ? $rowData['_bundle_option_position'] : '0',
125
+ 'type' => !empty($rowData['_bundle_option_type']) ? $rowData['_bundle_option_type'] : self::DEFAULT_OPTION_TYPE
126
+ );
127
+ }
128
+ if (isset($rowData['_bundle_product_sku']) && !empty($rowData['_bundle_product_sku'])) {
129
+ $selectionEntityId = false;
130
+ if (isset($newSku[$rowData['_bundle_product_sku']])) {
131
+ $selectionEntityId = $newSku[$rowData['_bundle_product_sku']]['entity_id'];
132
+ } elseif (isset($oldSku[$rowData['_bundle_product_sku']])) {
133
+ $selectionEntityId = $oldSku[$rowData['_bundle_product_sku']]['entity_id'];
134
+ } else {
135
+ /*
136
+ * TODO: We should move this to _isParticularAttributeValid, but
137
+ * entity model is not filled with newSku / oldSku there.
138
+ */
139
+ $this->_entityModel->addRowError(self::ERROR_INVALID_BUNDLE_PRODUCT_SKU, $rowNum);
140
+ }
141
+
142
+ if ($selectionEntityId) {
143
+ $bundleSelections[$productId][$rowData['_bundle_option_title']][] = array(
144
+ 'parent_product_id' => $productId,
145
+ 'product_id' => $selectionEntityId,
146
+ 'position' => !empty($rowData['_bundle_product_position']) ? $rowData['_bundle_product_position'] : '0',
147
+ 'is_default' => !empty($rowData['_bundle_product_is_default']) ? $rowData['_bundle_product_is_default'] : '0',
148
+ 'selection_price_type' => !empty($rowData['_bundle_product_price_type']) ? $rowData['_bundle_product_price_type'] : '0',
149
+ 'selection_price_value' => !empty($rowData['_bundle_product_price_value']) ? $rowData['_bundle_product_price_value'] : '0',
150
+ 'selection_qty' => !empty($rowData['_bundle_product_qty']) ? $rowData['_bundle_product_qty'] : '1',
151
+ 'selection_can_change_qty' => !empty($rowData['_bundle_product_can_change_qty']) ? $rowData['_bundle_product_can_change_qty'] : '0'
152
+ );
153
+ }
154
+ }
155
+ }
156
+
157
+ if (count($bundleOptions)) {
158
+ // if ($this->_entityModel->getBehavior() != Mage_ImportExport_Model_Import::BEHAVIOR_APPEND) {
159
+ $quoted = $connection->quoteInto('IN (?)', array_keys($bundleOptions));
160
+ $connection->delete($optionTable, "parent_id {$quoted}");
161
+ $connection->delete($selectionTable, "parent_product_id {$quoted}");
162
+ $connection->delete($relationTable, "parent_id {$quoted}");
163
+ // }
164
+
165
+ /*
166
+ * Insert options.
167
+ */
168
+ $optionData = array();
169
+ foreach ($bundleOptions as $productId => $options) {
170
+ foreach ($options as $title => $option) {
171
+ $optionData[] = $option;
172
+ }
173
+ }
174
+ $connection->insertOnDuplicate($optionTable, $optionData);
175
+
176
+ /*
177
+ * Insert option titles.
178
+ */
179
+ $optionId = $connection->lastInsertId();
180
+ $titleOptionId = $optionId;
181
+ $optionValues = array();
182
+ foreach ($bundleOptions as $productId => $options) {
183
+ foreach ($options as $title => $option) {
184
+ $titles = $bundleTitles[$title];
185
+ foreach ($titles as $storeId => $storeTitle) {
186
+ $optionValues[] = array(
187
+ 'option_id' => $titleOptionId,
188
+ 'store_id' => $storeId,
189
+ 'title' => $storeTitle
190
+ );
191
+ }
192
+ $titleOptionId++;
193
+ }
194
+ }
195
+ $connection->insertOnDuplicate($optionValueTable, $optionValues);
196
+ if (count($bundleSelections)) {
197
+ $optionSelections = array();
198
+ $productRelations = array();
199
+ $selectionOptionId = $optionId;
200
+ foreach ($bundleSelections as $productId => $selections) {
201
+ foreach ($selections as $title => $selection) {
202
+ foreach ($selection as &$sel) {
203
+ $productRelations[] = array(
204
+ 'parent_id' => $sel['parent_product_id'],
205
+ 'child_id' => $sel['product_id']
206
+ );
207
+ $sel['option_id'] = $selectionOptionId;
208
+ }
209
+ $selectionOptionId++;
210
+ $optionSelections = array_merge($optionSelections, $selection);
211
+ }
212
+ }
213
+
214
+ /*
215
+ * Insert option selections.
216
+ */
217
+ $connection->insertOnDuplicate($selectionTable, $optionSelections);
218
+
219
+ /*
220
+ * Insert product relations.
221
+ */
222
+ $connection->insertOnDuplicate($relationTable, $productRelations);
223
+ }
224
+ }
225
+ }
226
+
227
+ return $this;
228
+ }
229
+
230
+ /**
231
+ * Prepare attributes values for save: remove non-existent, remove empty values, remove static.
232
+ *
233
+ * @param array $rowData
234
+ * @param bool $withDefaultValue
235
+ * @return array
236
+ */
237
+ public function prepareAttributesForSave(array $rowData, $withDefaultValue = true)
238
+ {
239
+ $resultAttrs = array();
240
+
241
+ foreach ($this->_getProductAttributes($rowData) as $attrCode => $attrParams) {
242
+ if (!$attrParams['is_static']) {
243
+ if (isset($rowData[$attrCode]) && strlen($rowData[$attrCode])) {
244
+ $resultAttrs[$attrCode] =
245
+ ('select' == $attrParams['type'] || 'multiselect' == $attrParams['type'])
246
+ ? $attrParams['options'][Mage::helper('fastsimpleimport')->strtolower($rowData[$attrCode])]
247
+ : $rowData[$attrCode];
248
+ } elseif (array_key_exists($attrCode, $rowData)) {
249
+ $resultAttrs[$attrCode] = $rowData[$attrCode];
250
+ } elseif ($this->_isSkuNew($rowData['sku'])) {
251
+ $defaultValue = $this->_getDefaultValue($attrParams);
252
+ if (null !== $defaultValue) {
253
+ $resultAttrs[$attrCode] = $defaultValue;
254
+ }
255
+ }
256
+ }
257
+ }
258
+ return $resultAttrs;
259
+ }
260
+
261
+ /**
262
+ * Validate row attributes. Pass VALID row data ONLY as argument.
263
+ *
264
+ * @param array $rowData
265
+ * @param int $rowNum
266
+ * @param boolean $checkRequiredAttributes OPTIONAL Flag which can disable validation required values.
267
+ * @return boolean
268
+ */
269
+ public function isRowValid(array $rowData, $rowNum, $checkRequiredAttributes = true)
270
+ {
271
+ $error = false;
272
+ $rowScope = $this->_entityModel->getRowScope($rowData);
273
+
274
+ if (Mage_ImportExport_Model_Import_Entity_Product::SCOPE_NULL != $rowScope) {
275
+ foreach ($this->_getProductAttributes($rowData) as $attrCode => $attrParams) {
276
+ // check value for non-empty in the case of required attribute?
277
+ if (isset($rowData[$attrCode]) && strlen($rowData[$attrCode])) {
278
+ $error |= !$this->_entityModel->isAttributeValid($attrCode, $attrParams, $rowData, $rowNum);
279
+ } elseif (
280
+ $this->_isAttributeRequiredCheckNeeded($attrCode)
281
+ && $checkRequiredAttributes
282
+ && Mage_ImportExport_Model_Import_Entity_Product::SCOPE_DEFAULT == $rowScope
283
+ && $attrParams['is_required']
284
+ && is_null($this->_getDefaultValue($attrParams))
285
+ ) {
286
+ $this->_entityModel->addRowError(
287
+ Mage_ImportExport_Model_Import_Entity_Product::ERROR_VALUE_IS_REQUIRED, $rowNum, $attrCode
288
+ );
289
+ $error = true;
290
+ }
291
+ }
292
+ }
293
+ $error |= !$this->_isParticularAttributesValid($rowData, $rowNum);
294
+
295
+ return !$error;
296
+ }
297
+
298
+ /**
299
+ * Get configured default value for attribute
300
+ *
301
+ * @param array $attrParams
302
+ * @return mixed|null
303
+ */
304
+ protected function _getDefaultValue($attrParams)
305
+ {
306
+ switch ($attrParams['code']) {
307
+
308
+ case 'tax_class_id':
309
+ case 'status':
310
+ case 'visibility':
311
+ case 'weight':
312
+ $defaultValue = Mage::getStoreConfig('fastsimpleimport/product/' . $attrParams['code']);
313
+ if (strlen($defaultValue)) {
314
+ return $defaultValue;
315
+ }
316
+ break;
317
+ }
318
+
319
+ if (null !== $attrParams['default_value']) {
320
+ return $attrParams['default_value'];
321
+ }
322
+
323
+ return null;
324
+ }
325
+
326
+ /**
327
+ * Check if the given sku belongs to a new product or an existing one
328
+ *
329
+ * @param $sku
330
+ * @return bool
331
+ */
332
+ protected function _isSkuNew($sku)
333
+ {
334
+ if ($sku == '') {
335
+ return false;
336
+ }
337
+ $oldSkus = $this->_entityModel->getOldSku();
338
+ return !isset($oldSkus[$sku]);
339
+ }
340
+
341
+ /**
342
+ * check if Mage_Bundle module is enabled
343
+ *
344
+ * @return boolean
345
+ */
346
+ public function isSuitable()
347
+ {
348
+ return Mage::getConfig()->getModuleConfig('Mage_Bundle')->is('active', 'true');
349
+ }
350
+ }
app/code/community/FarApp/Connector/Model/Import/Entity/Product/Type/Configurable.php ADDED
@@ -0,0 +1,344 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class FarApp_Connector_Model_Import_Entity_Product_Type_Configurable
4
+ extends Mage_ImportExport_Model_Import_Entity_Product_Type_Configurable
5
+ {
6
+
7
+ /**
8
+ * All stores code-ID pairs.
9
+ *
10
+ * @var array
11
+ */
12
+ protected $_storeCodeToId = array();
13
+
14
+ /**
15
+ * Initialize stores hash.
16
+ *
17
+ * @return Mage_ImportExport_Model_Import_Entity_Product
18
+ */
19
+ protected function _initStores()
20
+ {
21
+ foreach (Mage::app()->getStores() as $store) {
22
+ $this->_storeCodeToId[$store->getCode()] = $store->getId();
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Prepare attributes values for save: remove non-existent, remove empty values, remove static.
28
+ *
29
+ * @param array $rowData
30
+ * @param bool $withDefaultValue
31
+ * @return array
32
+ */
33
+ public function prepareAttributesForSave(array $rowData, $withDefaultValue = true)
34
+ {
35
+ $resultAttrs = array();
36
+
37
+ foreach ($this->_getProductAttributes($rowData) as $attrCode => $attrParams) {
38
+ if (!$attrParams['is_static']) {
39
+ if (isset($rowData[$attrCode]) && strlen($rowData[$attrCode])) {
40
+ $resultAttrs[$attrCode] =
41
+ ('select' == $attrParams['type'] || 'multiselect' == $attrParams['type'])
42
+ ? $attrParams['options'][Mage::helper('fastsimpleimport')->strtolower($rowData[$attrCode])]
43
+ : $rowData[$attrCode];
44
+ } elseif (array_key_exists($attrCode, $rowData)) {
45
+ $resultAttrs[$attrCode] = $rowData[$attrCode];
46
+ } elseif ($this->_isSkuNew($rowData['sku'])) {
47
+ $defaultValue = $this->_getDefaultValue($attrParams);
48
+ if (null !== $defaultValue) {
49
+ $resultAttrs[$attrCode] = $defaultValue;
50
+ }
51
+ }
52
+ }
53
+ }
54
+ return $resultAttrs;
55
+ }
56
+
57
+ /**
58
+ * Validate row attributes. Pass VALID row data ONLY as argument.
59
+ *
60
+ * @param array $rowData
61
+ * @param int $rowNum
62
+ * @param boolean $checkRequiredAttributes OPTIONAL Flag which can disable validation required values.
63
+ * @return boolean
64
+ */
65
+ public function isRowValid(array $rowData, $rowNum, $checkRequiredAttributes = true)
66
+ {
67
+ $error = false;
68
+ $rowScope = $this->_entityModel->getRowScope($rowData);
69
+
70
+ if (Mage_ImportExport_Model_Import_Entity_Product::SCOPE_NULL != $rowScope) {
71
+ foreach ($this->_getProductAttributes($rowData) as $attrCode => $attrParams) {
72
+ // check value for non-empty in the case of required attribute?
73
+ if (isset($rowData[$attrCode]) && strlen($rowData[$attrCode])) {
74
+ $error |= !$this->_entityModel->isAttributeValid($attrCode, $attrParams, $rowData, $rowNum);
75
+ } elseif (
76
+ $this->_isAttributeRequiredCheckNeeded($attrCode)
77
+ && $checkRequiredAttributes
78
+ && Mage_ImportExport_Model_Import_Entity_Product::SCOPE_DEFAULT == $rowScope
79
+ && $attrParams['is_required']
80
+ && is_null($this->_getDefaultValue($attrParams))
81
+ ) {
82
+ $this->_entityModel->addRowError(
83
+ Mage_ImportExport_Model_Import_Entity_Product::ERROR_VALUE_IS_REQUIRED, $rowNum, $attrCode
84
+ );
85
+ $error = true;
86
+ }
87
+ }
88
+ }
89
+ $error |= !$this->_isParticularAttributesValid($rowData, $rowNum);
90
+
91
+ return !$error;
92
+ }
93
+
94
+ /**
95
+ * Get configured default value for attribute
96
+ *
97
+ * @param array $attrParams
98
+ * @return mixed|null
99
+ */
100
+ protected function _getDefaultValue($attrParams)
101
+ {
102
+ switch ($attrParams['code']) {
103
+
104
+ case 'tax_class_id':
105
+ case 'status':
106
+ case 'visibility':
107
+ case 'weight':
108
+ $defaultValue = Mage::getStoreConfig('fastsimpleimport/product/' . $attrParams['code']);
109
+ if (strlen($defaultValue)) {
110
+ return $defaultValue;
111
+ }
112
+ break;
113
+ }
114
+
115
+ if (null !== $attrParams['default_value']) {
116
+ return $attrParams['default_value'];
117
+ }
118
+
119
+ return null;
120
+ }
121
+
122
+ /**
123
+ * Check if the given sku belongs to a new product or an existing one
124
+ *
125
+ * @param $sku
126
+ * @return bool
127
+ */
128
+ protected function _isSkuNew($sku)
129
+ {
130
+ if ($sku == '') {
131
+ return false;
132
+ }
133
+ $oldSkus = $this->_entityModel->getOldSku();
134
+ return !isset($oldSkus[$sku]);
135
+ }
136
+
137
+
138
+ /**
139
+ * Save product type specific data.
140
+ *
141
+ * @throws Exception
142
+ * @return Mage_ImportExport_Model_Import_Entity_Product_Type_Abstract
143
+ */
144
+ public function saveData()
145
+ {
146
+ $this->_initStores();
147
+ $connection = $this->_entityModel->getConnection();
148
+ $mainTable = Mage::getSingleton('core/resource')->getTableName('catalog/product_super_attribute');
149
+ $labelTable = Mage::getSingleton('core/resource')->getTableName('catalog/product_super_attribute_label');
150
+ $priceTable = Mage::getSingleton('core/resource')->getTableName('catalog/product_super_attribute_pricing');
151
+ $linkTable = Mage::getSingleton('core/resource')->getTableName('catalog/product_super_link');
152
+ $relationTable = Mage::getSingleton('core/resource')->getTableName('catalog/product_relation');
153
+ $newSku = $this->_entityModel->getNewSku();
154
+ $oldSku = $this->_entityModel->getOldSku();
155
+ $productSuperData = array();
156
+ $productData = null;
157
+ $nextAttrId = Mage::getResourceHelper('importexport')->getNextAutoincrement($mainTable);
158
+
159
+ if ($this->_entityModel->getBehavior() == Mage_ImportExport_Model_Import::BEHAVIOR_APPEND) {
160
+ $this->_loadSkuSuperData();
161
+ }
162
+ $this->_loadSkuSuperAttributeValues();
163
+
164
+ while ($bunch = $this->_entityModel->getNextBunch()) {
165
+ $superAttributes = array(
166
+ 'attributes' => array(),
167
+ 'labels' => array(),
168
+ 'pricing' => array(),
169
+ 'super_link' => array(),
170
+ 'relation' => array()
171
+ );
172
+ $superAttributePosition = 0;
173
+ foreach ($bunch as $rowNum => $rowData) {
174
+ if (!$this->_entityModel->isRowAllowedToImport($rowData, $rowNum)) {
175
+ continue;
176
+ }
177
+ $this->_entityModel->filterRowData($rowData);
178
+ // remember SCOPE_DEFAULT row data
179
+ $scope = $this->_entityModel->getRowScope($rowData);
180
+ if (Mage_ImportExport_Model_Import_Entity_Product::SCOPE_DEFAULT == $scope) {
181
+ $productData = $newSku[$rowData[Mage_ImportExport_Model_Import_Entity_Product::COL_SKU]];
182
+
183
+ if ($this->_type != $productData['type_id']) {
184
+ $productData = null;
185
+ continue;
186
+ }
187
+ $productId = $productData['entity_id'];
188
+
189
+ $this->_processSuperData($productSuperData, $superAttributes);
190
+
191
+ $productSuperData = array(
192
+ 'product_id' => $productId,
193
+ 'attr_set_code' => $productData['attr_set_code'],
194
+ 'used_attributes' => empty($this->_skuSuperData[$productId])
195
+ ? array() : $this->_skuSuperData[$productId],
196
+ 'assoc_ids' => array()
197
+ );
198
+ } elseif (null === $productData) {
199
+ continue;
200
+ }
201
+ if (!empty($rowData['_super_products_sku'])) {
202
+ if (isset($newSku[$rowData['_super_products_sku']])) {
203
+ $productSuperData['assoc_ids'][$newSku[$rowData['_super_products_sku']]['entity_id']] = true;
204
+ } elseif (isset($oldSku[$rowData['_super_products_sku']])) {
205
+ $productSuperData['assoc_ids'][$oldSku[$rowData['_super_products_sku']]['entity_id']] = true;
206
+ }
207
+ }
208
+
209
+ if (empty($rowData['_super_attribute_code'])) {
210
+ continue;
211
+ }
212
+ $attrParams = $this->_superAttributes[$rowData['_super_attribute_code']];
213
+
214
+ if ($this->_getSuperAttributeId($productId, $attrParams['id'])) {
215
+ $productSuperAttrId = $this->_getSuperAttributeId($productId, $attrParams['id']);
216
+ } elseif (!isset($superAttributes['attributes'][$productId][$attrParams['id']])) {
217
+ $productSuperAttrId = $nextAttrId++;
218
+
219
+ if(($rowData['sku'] !== NULL) && ($rowData['_type'] == 'configurable')) {
220
+ /*
221
+ Positioning of super attribute will be reset if a new configurable product is detected
222
+ */
223
+ $superAttributePosition = 0;
224
+ }
225
+
226
+ $superAttributes['attributes'][$productId][$attrParams['id']] = array(
227
+ 'product_super_attribute_id' => $productSuperAttrId, 'position' => $superAttributePosition++
228
+ );
229
+ $superAttributes['labels'][] = array(
230
+ 'product_super_attribute_id' => $productSuperAttrId,
231
+ 'store_id' => 0,
232
+ 'use_default' => 1,
233
+ 'value' => $attrParams['frontend_label']
234
+ );
235
+ }
236
+ if (isset($rowData['_super_attribute_option']) && strlen($rowData['_super_attribute_option'])) {
237
+ $optionId = $attrParams['options'][Mage::helper('fastsimpleimport')->strtolower($rowData['_super_attribute_option'])];
238
+
239
+ if (!isset($productSuperData['used_attributes'][$attrParams['id']][$optionId])) {
240
+ $productSuperData['used_attributes'][$attrParams['id']][$optionId] = false;
241
+ }
242
+
243
+ if (!empty($rowData['_super_attribute_price_corr'])) {
244
+ $rowScope = $this->_entityModel->getRowScope($rowData);
245
+ $rowStore = Mage_ImportExport_Model_Import_Entity_Product::SCOPE_STORE == $rowScope ? $this->_storeCodeToId[$rowData[Mage_ImportExport_Model_Import_Entity_Product::COL_STORE]] : 0;
246
+ $rowWebsite = $rowStore > 0 ? Mage::getModel('core/store')->load($rowStore)->getWebsiteId() : 0;
247
+ $superAttributes['pricing'][] = array(
248
+ 'product_super_attribute_id' => $productSuperAttrId,
249
+ 'value_index' => $optionId,
250
+ 'is_percent' => '%' == substr($rowData['_super_attribute_price_corr'], -1),
251
+ 'pricing_value' => (float) rtrim($rowData['_super_attribute_price_corr'], '%'),
252
+ 'website_id' => $rowWebsite
253
+ );
254
+ }
255
+ }
256
+ }
257
+
258
+ $this->_processSuperData($productSuperData, $superAttributes);
259
+
260
+ // remove old data if needed
261
+ if ($this->_entityModel->getBehavior() != Mage_ImportExport_Model_Import::BEHAVIOR_APPEND
262
+ && $superAttributes['attributes']) {
263
+ $quoted = $connection->quoteInto('IN (?)', array_keys($superAttributes['attributes']));
264
+ $connection->delete($mainTable, "product_id {$quoted}");
265
+ $connection->delete($linkTable, "parent_id {$quoted}");
266
+ $connection->delete($relationTable, "parent_id {$quoted}");
267
+ }
268
+ $mainData = array();
269
+
270
+ foreach ($superAttributes['attributes'] as $productId => $attributesData) {
271
+ foreach ($attributesData as $attrId => $row) {
272
+ $row['product_id'] = $productId;
273
+ $row['attribute_id'] = $attrId;
274
+ $mainData[] = $row;
275
+ }
276
+ }
277
+ if ($mainData) {
278
+ $connection->insertOnDuplicate($mainTable, $mainData);
279
+ }
280
+ if ($superAttributes['labels']) {
281
+ $connection->insertOnDuplicate($labelTable, $superAttributes['labels']);
282
+ }
283
+ if ($superAttributes['pricing']) {
284
+ $connection->insertOnDuplicate(
285
+ $priceTable,
286
+ $superAttributes['pricing'],
287
+ array('is_percent', 'pricing_value')
288
+ );
289
+ }
290
+ if ($superAttributes['super_link']) {
291
+ $connection->insertOnDuplicate($linkTable, $superAttributes['super_link']);
292
+ }
293
+ if ($superAttributes['relation']) {
294
+ $connection->insertOnDuplicate($relationTable, $superAttributes['relation']);
295
+ }
296
+ }
297
+ return $this;
298
+ }
299
+
300
+ /**
301
+ * Array of SKU to array of super attribute values for all products.
302
+ *
303
+ * @return Mage_ImportExport_Model_Import_Entity_Product_Type_Configurable
304
+ */
305
+ protected function _loadSkuSuperAttributeValues()
306
+ {
307
+ if ($this->_superAttributes) {
308
+ $attrSetIdToName = $this->_entityModel->getAttrSetIdToName();
309
+ $allowProductTypes = array();
310
+
311
+ foreach (Mage::getConfig()
312
+ ->getNode('global/catalog/product/type/configurable/allow_product_types')->children() as $type) {
313
+ $allowProductTypes[] = $type->getName();
314
+ }
315
+
316
+ $collection = Mage::getResourceModel('catalog/product_collection')
317
+ ->addFieldToFilter('type_id', $allowProductTypes)
318
+ ->addAttributeToSelect(array_keys($this->_superAttributes));
319
+
320
+ $collection->setPageSize(200);
321
+ $pages = $collection->getLastPageNumber();
322
+
323
+ for ($currentPage = 1; $currentPage <= $pages; $currentPage++) {
324
+
325
+ $collection->setCurPage($currentPage);
326
+
327
+ foreach ($collection as $product) {
328
+ $attrSetName = $attrSetIdToName[$product->getAttributeSetId()];
329
+
330
+ $data = array_intersect_key(
331
+ $product->getData(),
332
+ $this->_superAttributes
333
+ );
334
+ foreach ($data as $attrCode => $value) {
335
+ $attrId = $this->_superAttributes[$attrCode]['id'];
336
+ $this->_skuSuperAttributeValues[$attrSetName][$product->getId()][$attrId] = $value;
337
+ }
338
+ }
339
+ $collection->clear();
340
+ }
341
+ }
342
+ return $this;
343
+ }
344
+ }
app/code/community/FarApp/Connector/Model/Import/Entity/Product/Type/Grouped.php ADDED
@@ -0,0 +1,259 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class FarApp_Connector_Model_Import_Entity_Product_Type_Grouped
4
+ extends Mage_ImportExport_Model_Import_Entity_Product_Type_Grouped
5
+ {
6
+ /**
7
+ * Prepare attributes values for save: remove non-existent, remove empty values, remove static.
8
+ *
9
+ * @param array $rowData
10
+ * @param bool $withDefaultValue
11
+ * @return array
12
+ */
13
+ public function prepareAttributesForSave(array $rowData, $withDefaultValue = true)
14
+ {
15
+ $resultAttrs = array();
16
+
17
+ foreach ($this->_getProductAttributes($rowData) as $attrCode => $attrParams) {
18
+ if (!$attrParams['is_static']) {
19
+ if (isset($rowData[$attrCode]) && strlen($rowData[$attrCode])) {
20
+ $resultAttrs[$attrCode] =
21
+ ('select' == $attrParams['type'] || 'multiselect' == $attrParams['type'])
22
+ ? $attrParams['options'][Mage::helper('fastsimpleimport')->strtolower($rowData[$attrCode])]
23
+ : $rowData[$attrCode];
24
+ } elseif (array_key_exists($attrCode, $rowData)) {
25
+ $resultAttrs[$attrCode] = $rowData[$attrCode];
26
+ } elseif ($this->_isSkuNew($rowData['sku'])) {
27
+ $defaultValue = $this->_getDefaultValue($attrParams);
28
+ if (null !== $defaultValue) {
29
+ $resultAttrs[$attrCode] = $defaultValue;
30
+ }
31
+ }
32
+ }
33
+ }
34
+ return $resultAttrs;
35
+ }
36
+
37
+ /**
38
+ * Validate row attributes. Pass VALID row data ONLY as argument.
39
+ *
40
+ * @param array $rowData
41
+ * @param int $rowNum
42
+ * @param boolean $checkRequiredAttributes OPTIONAL Flag which can disable validation required values.
43
+ * @return boolean
44
+ */
45
+ public function isRowValid(array $rowData, $rowNum, $checkRequiredAttributes = true)
46
+ {
47
+ $error = false;
48
+ $rowScope = $this->_entityModel->getRowScope($rowData);
49
+
50
+ if (Mage_ImportExport_Model_Import_Entity_Product::SCOPE_NULL != $rowScope) {
51
+ foreach ($this->_getProductAttributes($rowData) as $attrCode => $attrParams) {
52
+ // check value for non-empty in the case of required attribute?
53
+ if (isset($rowData[$attrCode]) && strlen($rowData[$attrCode])) {
54
+ $error |= !$this->_entityModel->isAttributeValid($attrCode, $attrParams, $rowData, $rowNum);
55
+ } elseif (
56
+ $this->_isAttributeRequiredCheckNeeded($attrCode)
57
+ && $checkRequiredAttributes
58
+ && Mage_ImportExport_Model_Import_Entity_Product::SCOPE_DEFAULT == $rowScope
59
+ && $attrParams['is_required']
60
+ && is_null($this->_getDefaultValue($attrParams))
61
+ ) {
62
+ $this->_entityModel->addRowError(
63
+ Mage_ImportExport_Model_Import_Entity_Product::ERROR_VALUE_IS_REQUIRED, $rowNum, $attrCode
64
+ );
65
+ $error = true;
66
+ }
67
+ }
68
+ }
69
+ $error |= !$this->_isParticularAttributesValid($rowData, $rowNum);
70
+
71
+ return !$error;
72
+ }
73
+
74
+ /**
75
+ * Get configured default value for attribute
76
+ *
77
+ * @param array $attrParams
78
+ * @return mixed|null
79
+ */
80
+ protected function _getDefaultValue($attrParams)
81
+ {
82
+ switch ($attrParams['code']) {
83
+
84
+ case 'tax_class_id':
85
+ case 'status':
86
+ case 'visibility':
87
+ case 'weight':
88
+ $defaultValue = Mage::getStoreConfig('fastsimpleimport/product/' . $attrParams['code']);
89
+ if (strlen($defaultValue)) {
90
+ return $defaultValue;
91
+ }
92
+ break;
93
+ }
94
+
95
+ if (null !== $attrParams['default_value']) {
96
+ return $attrParams['default_value'];
97
+ }
98
+
99
+ return null;
100
+ }
101
+
102
+ /**
103
+ * Check if the given sku belongs to a new product or an existing one
104
+ *
105
+ * @param $sku
106
+ * @return bool
107
+ */
108
+ protected function _isSkuNew($sku)
109
+ {
110
+ if ($sku == '') {
111
+ return false;
112
+ }
113
+ $oldSkus = $this->_entityModel->getOldSku();
114
+ return !isset($oldSkus[$sku]);
115
+ }
116
+
117
+
118
+ /**
119
+ * Save product type specific data.
120
+ *
121
+ * @return Mage_ImportExport_Model_Import_Entity_Product_Type_Abstract
122
+ */
123
+ public function saveData()
124
+ {
125
+ $groupedLinkId = Mage_Catalog_Model_Product_Link::LINK_TYPE_GROUPED;
126
+ $connection = Mage::getSingleton('core/resource')->getConnection('write');
127
+ $resource = Mage::getResourceModel('catalog/product_link');
128
+ $mainTable = $resource->getMainTable();
129
+ $relationTable = $resource->getTable('catalog/product_relation');
130
+ $newSku = $this->_entityModel->getNewSku();
131
+ $oldSku = $this->_entityModel->getOldSku();
132
+ $attributes = array();
133
+
134
+ // pre-load attributes parameters
135
+ $select = $connection->select()
136
+ ->from($resource->getTable('catalog/product_link_attribute'), array(
137
+ 'id' => 'product_link_attribute_id',
138
+ 'code' => 'product_link_attribute_code',
139
+ 'type' => 'data_type'
140
+ ))->where('link_type_id = ?', $groupedLinkId);
141
+ foreach ($connection->fetchAll($select) as $row) {
142
+ $attributes[$row['code']] = array(
143
+ 'id' => $row['id'],
144
+ 'table' => $resource->getAttributeTypeTable($row['type'])
145
+ );
146
+ }
147
+ while ($bunch = $this->_entityModel->getNextBunch()) {
148
+ $linksData = array(
149
+ 'product_ids' => array(),
150
+ 'links' => array(),
151
+ 'attr_product_ids' => array(),
152
+ 'position' => array(),
153
+ 'qty' => array(),
154
+ 'relation' => array()
155
+ );
156
+ foreach ($bunch as $rowNum => $rowData) {
157
+ $this->_entityModel->filterRowData($rowData);
158
+ if (!$this->_entityModel->isRowAllowedToImport($rowData, $rowNum)
159
+ || empty($rowData['_associated_sku'])
160
+ ) {
161
+ continue;
162
+ }
163
+ if (isset($newSku[$rowData['_associated_sku']])) {
164
+ $linkedProductId = $newSku[$rowData['_associated_sku']]['entity_id'];
165
+ } elseif (isset($oldSku[$rowData['_associated_sku']])) {
166
+ $linkedProductId = $oldSku[$rowData['_associated_sku']]['entity_id'];
167
+ } else {
168
+ continue;
169
+ }
170
+ $scope = $this->_entityModel->getRowScope($rowData);
171
+ if (Mage_ImportExport_Model_Import_Entity_Product::SCOPE_DEFAULT == $scope) {
172
+ $productData = $newSku[$rowData[Mage_ImportExport_Model_Import_Entity_Product::COL_SKU]];
173
+ } else {
174
+ $colAttrSet = Mage_ImportExport_Model_Import_Entity_Product::COL_ATTR_SET;
175
+ $rowData[$colAttrSet] = $productData['attr_set_code'];
176
+ $rowData[Mage_ImportExport_Model_Import_Entity_Product::COL_TYPE] = $productData['type_id'];
177
+ }
178
+ $productId = $productData['entity_id'];
179
+
180
+ if ($this->_type != $rowData[Mage_ImportExport_Model_Import_Entity_Product::COL_TYPE]) {
181
+ continue;
182
+ }
183
+ $linksData['product_ids'][$productId] = true;
184
+ $linksData['links'][$productId][$linkedProductId] = $groupedLinkId;
185
+ $linksData['relation'][] = array('parent_id' => $productId, 'child_id' => $linkedProductId);
186
+ $qty = empty($rowData['_associated_default_qty']) ? 0 : $rowData['_associated_default_qty'];
187
+ $pos = empty($rowData['_associated_position']) ? 0 : $rowData['_associated_position'];
188
+
189
+ if ($qty || $pos) {
190
+ $linksData['attr_product_ids'][$productId] = true;
191
+ if ($pos) {
192
+ $linksData['position']["{$productId} {$linkedProductId}"] = array(
193
+ 'product_link_attribute_id' => $attributes['position']['id'],
194
+ 'value' => $pos
195
+ );
196
+ }
197
+ if ($qty) {
198
+ $linksData['qty']["{$productId} {$linkedProductId}"] = array(
199
+ 'product_link_attribute_id' => $attributes['qty']['id'],
200
+ 'value' => $qty
201
+ );
202
+ }
203
+ }
204
+ }
205
+ // save links and relations
206
+ if ($linksData['product_ids'] && $this->getBehavior() != Mage_ImportExport_Model_Import::BEHAVIOR_APPEND) {
207
+ $connection->delete(
208
+ $mainTable,
209
+ $connection->quoteInto(
210
+ 'product_id IN (?) AND link_type_id = ' . $groupedLinkId,
211
+ array_keys($linksData['product_ids'])
212
+ )
213
+ );
214
+ }
215
+ if ($linksData['links']) {
216
+ $mainData = array();
217
+
218
+ foreach ($linksData['links'] as $productId => $linkedData) {
219
+ foreach ($linkedData as $linkedId => $linkType) {
220
+ $mainData[] = array(
221
+ 'product_id' => $productId,
222
+ 'linked_product_id' => $linkedId,
223
+ 'link_type_id' => $linkType
224
+ );
225
+ }
226
+ }
227
+ $connection->insertOnDuplicate($mainTable, $mainData);
228
+ $connection->insertOnDuplicate($relationTable, $linksData['relation']);
229
+ }
230
+ // save positions and default quantity
231
+ if ($linksData['attr_product_ids']) {
232
+ $savedData = $connection->fetchPairs($connection->select()
233
+ ->from($mainTable, array(
234
+ new Zend_Db_Expr('CONCAT_WS(" ", product_id, linked_product_id)'), 'link_id'
235
+ ))
236
+ ->where(
237
+ 'product_id IN (?) AND link_type_id = ' . $groupedLinkId,
238
+ array_keys($linksData['attr_product_ids'])
239
+ )
240
+ );
241
+ foreach ($savedData as $pseudoKey => $linkId) {
242
+ if (isset($linksData['position'][$pseudoKey])) {
243
+ $linksData['position'][$pseudoKey]['link_id'] = $linkId;
244
+ }
245
+ if (isset($linksData['qty'][$pseudoKey])) {
246
+ $linksData['qty'][$pseudoKey]['link_id'] = $linkId;
247
+ }
248
+ }
249
+ if ($linksData['position']) {
250
+ $connection->insertOnDuplicate($attributes['position']['table'], $linksData['position']);
251
+ }
252
+ if ($linksData['qty']) {
253
+ $connection->insertOnDuplicate($attributes['qty']['table'], $linksData['qty']);
254
+ }
255
+ }
256
+ }
257
+ return $this;
258
+ }
259
+ }
app/code/community/FarApp/Connector/Model/Import/Entity/Product/Type/Simple.php ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class FarApp_Connector_Model_Import_Entity_Product_Type_Simple
3
+ extends Mage_ImportExport_Model_Import_Entity_Product_Type_Simple
4
+ {
5
+ /**
6
+ * Prepare attributes values for save: remove non-existent, remove empty values, remove static.
7
+ *
8
+ * @param array $rowData
9
+ * @param bool $withDefaultValue
10
+ * @return array
11
+ */
12
+ public function prepareAttributesForSave(array $rowData, $withDefaultValue = true)
13
+ {
14
+ $resultAttrs = array();
15
+ foreach ($this->_getProductAttributes($rowData) as $attrCode => $attrParams) {
16
+ if (!$attrParams['is_static']) {
17
+ if (isset($rowData[$attrCode]) && strlen($rowData[$attrCode])) {
18
+ $resultAttrs[$attrCode] =
19
+ ('select' == $attrParams['type'] || 'multiselect' == $attrParams['type'])
20
+ ? $attrParams['options'][Mage::helper('fastsimpleimport')->strtolower($rowData[$attrCode])]
21
+ : $rowData[$attrCode];
22
+ } elseif (array_key_exists($attrCode, $rowData)) {
23
+ $resultAttrs[$attrCode] = $rowData[$attrCode];
24
+ } elseif ($this->_isSkuNew($rowData['sku'])) {
25
+ $defaultValue = $this->_getDefaultValue($attrParams);
26
+ if (null !== $defaultValue) {
27
+ $resultAttrs[$attrCode] = $defaultValue;
28
+ }
29
+ }
30
+ }
31
+ }
32
+ return $resultAttrs;
33
+ }
34
+ /**
35
+ * Validate row attributes. Pass VALID row data ONLY as argument.
36
+ *
37
+ * @param array $rowData
38
+ * @param int $rowNum
39
+ * @param boolean $checkRequiredAttributes OPTIONAL Flag which can disable validation required values.
40
+ * @return boolean
41
+ */
42
+ public function isRowValid(array $rowData, $rowNum, $checkRequiredAttributes = true)
43
+ {
44
+ $error = false;
45
+ $rowScope = $this->_entityModel->getRowScope($rowData);
46
+ if (Mage_ImportExport_Model_Import_Entity_Product::SCOPE_NULL != $rowScope) {
47
+ foreach ($this->_getProductAttributes($rowData) as $attrCode => $attrParams) {
48
+ // check value for non-empty in the case of required attribute?
49
+ if (isset($rowData[$attrCode]) && strlen($rowData[$attrCode])) {
50
+ $error |= !$this->_entityModel->isAttributeValid($attrCode, $attrParams, $rowData, $rowNum);
51
+ } elseif (
52
+ $this->_isAttributeRequiredCheckNeeded($attrCode)
53
+ && $checkRequiredAttributes
54
+ && Mage_ImportExport_Model_Import_Entity_Product::SCOPE_DEFAULT == $rowScope
55
+ && $attrParams['is_required']
56
+ && is_null($this->_getDefaultValue($attrParams))
57
+ ) {
58
+ $this->_entityModel->addRowError(
59
+ Mage_ImportExport_Model_Import_Entity_Product::ERROR_VALUE_IS_REQUIRED, $rowNum, $attrCode
60
+ );
61
+ $error = true;
62
+ }
63
+ }
64
+ }
65
+ $error |= !$this->_isParticularAttributesValid($rowData, $rowNum);
66
+ return !$error;
67
+ }
68
+ /**
69
+ * Get configured default value for attribute
70
+ *
71
+ * @param array $attrParams
72
+ * @return mixed|null
73
+ */
74
+ protected function _getDefaultValue($attrParams)
75
+ {
76
+ switch ($attrParams['code']) {
77
+ case 'tax_class_id':
78
+ case 'status':
79
+ case 'visibility':
80
+ case 'weight':
81
+ $defaultValue = Mage::getStoreConfig('fastsimpleimport/product/' . $attrParams['code']);
82
+ if (strlen($defaultValue)) {
83
+ return $defaultValue;
84
+ }
85
+ break;
86
+ }
87
+ if (null !== $attrParams['default_value']) {
88
+ return $attrParams['default_value'];
89
+ }
90
+ return null;
91
+ }
92
+ /**
93
+ * Check if the given sku belongs to a new product or an existing one
94
+ *
95
+ * @param $sku
96
+ * @return bool
97
+ */
98
+ protected function _isSkuNew($sku)
99
+ {
100
+ if ($sku == '') {
101
+ return false;
102
+ }
103
+ $oldSkus = $this->_entityModel->getOldSku();
104
+ return !isset($oldSkus[$sku]);
105
+ }
106
+ }
app/code/community/FarApp/Connector/Model/Import/Entity/Product/Type/Virtual.php ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ <?php
2
+
3
+ class FarApp_Connector_Model_Import_Entity_Product_Type_Virtual extends FarApp_Connector_Model_Import_Entity_Product_Type_Simple {
4
+
5
+ }
app/code/community/FarApp/Connector/etc/config.xml CHANGED
@@ -9,7 +9,7 @@
9
  <config>
10
  <modules>
11
  <FarApp_Connector>
12
- <version>1.5.5</version>
13
  </FarApp_Connector>
14
  </modules>
15
  <global>
@@ -28,6 +28,11 @@
28
  <product_api>FarApp_Connector_Model_Product_Api</product_api>
29
  </rewrite>
30
  </catalog>
 
 
 
 
 
31
  </models>
32
  <events>
33
  <sales_order_save_after>
@@ -59,6 +64,13 @@
59
  <label>Orders</label>
60
  </order>
61
  </import_entities>
 
 
 
 
 
 
 
62
  <export_entities>
63
  <order translate="label">
64
  <model_token>farapp_connector/export_entity_order</model_token>
@@ -81,6 +93,13 @@
81
  <label>Orders</label>
82
  </order>
83
  </import_entities>
 
 
 
 
 
 
 
84
  </importexport>
85
  </global>
86
  <frontend>
9
  <config>
10
  <modules>
11
  <FarApp_Connector>
12
+ <version>1.5.6</version>
13
  </FarApp_Connector>
14
  </modules>
15
  <global>
28
  <product_api>FarApp_Connector_Model_Product_Api</product_api>
29
  </rewrite>
30
  </catalog>
31
+ <importexport>
32
+ <rewrite>
33
+ <import_entity_product>FarApp_Connector_Model_Import_Entity_Product</import_entity_product>
34
+ </rewrite>
35
+ </importexport>
36
  </models>
37
  <events>
38
  <sales_order_save_after>
64
  <label>Orders</label>
65
  </order>
66
  </import_entities>
67
+ <import_product_types>
68
+ <simple>farapp_connector/import_entity_product_type_simple</simple>
69
+ <configurable>farapp_connector/import_entity_product_type_configurable</configurable>
70
+ <virtual>farapp_connector/import_entity_product_type_virtual</virtual>
71
+ <grouped>farapp_connector/import_entity_product_type_grouped</grouped>
72
+ <bundle>farapp_connector/import_entity_product_type_bundle</bundle>
73
+ </import_product_types>
74
  <export_entities>
75
  <order translate="label">
76
  <model_token>farapp_connector/export_entity_order</model_token>
93
  <label>Orders</label>
94
  </order>
95
  </import_entities>
96
+ <import_product_types>
97
+ <simple>farapp_connector/import_entity_product_type_simple</simple>
98
+ <configurable>farapp_connector/import_entity_product_type_configurable</configurable>
99
+ <virtual>farapp_connector/import_entity_product_type_virtual</virtual>
100
+ <grouped>farapp_connector/import_entity_product_type_grouped</grouped>
101
+ <bundle>farapp_connector/import_entity_product_type_bundle</bundle>
102
+ </import_product_types>
103
  </importexport>
104
  </global>
105
  <frontend>
package.xml CHANGED
@@ -1,18 +1,18 @@
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>FarApp_Connector</name>
4
- <version>1.5.5</version>
5
  <stability>stable</stability>
6
  <license uri="https://www.farapp.com/signup/">Commercial</license>
7
  <channel>community</channel>
8
  <extends/>
9
  <summary>Connector to sync product data from FarApp to Magento. FarApp currently supports NetSuite and other backends.</summary>
10
  <description>FarApp is a cloud-based solution for posting product data to storefronts, retrieving orders from storefront and posting fulfillments to storefronts. We support various backends including NetSuite, X-Cart, 3D-Cart, and more. This connector allows full product data posting to Magento from FarApp. It has the the extra benefits of allowing FarApp to dynamically push new product data, automatically creating new attribute options and importing external images (features not provided by Magento).</description>
11
- <notes>Fixed permissions so configurable products get linked properly on first import.</notes>
12
  <authors><author><name>FarApp</name><user>FarApp</user><email>support@farapp.com</email></author></authors>
13
- <date>2017-05-01</date>
14
- <time>10:04:56</time>
15
- <contents><target name="magecommunity"><dir name="FarApp"><dir name="Connector"><dir name="Helper"><file name="Data.php" hash="60ea63e7acbcdd006c05d3f8528d6b91"/></dir><dir name="Model"><dir name="Export"><dir name="Adapter"><file name="Abstract.php" hash="765dc8fbab996f17b9f049cc8aa906a0"/><file name="Array.php" hash="6ca62c702dcb9512ec429563ac1ce1a2"/></dir><dir name="Entity"><file name="Order.php" hash="14a2f735cf8fc5e8f2bcd6682a1e56b1"/></dir></dir><file name="Export.php" hash="01643ef101731c6d98bbc523642f95a0"/><dir name="Import"><dir name="Entity"><file name="Customer.php" hash="376978f635c73605d428037cca8cf594"/><file name="Order.php" hash="38579396825a1bd3ad59de84278085f6"/><file name="Product.php" hash="61fb4cfe7c47ba3f99dec526cc534ada"/><file name="minVersion2.php" hash="8df670fd68516ba1629304ae8ab6c812"/></dir></dir><file name="Import.php" hash="deb96f4867780788413d96be1c2b9ff9"/><file name="Observer.php" hash="4bc864815ea234f1b0ae064477bdff45"/><dir name="Order"><dir name="Creditmemo"><file name="Api.php" hash="edb85d34679eab92e8990a0dd065632e"/></dir><dir name="Invoice"><file name="Api.php" hash="f133255dae51ab9c44c71ca9cc702d0a"/></dir></dir><dir name="Product"><file name="Api.php" hash="60539725273ed3ce03adef8e90198cc3"/></dir></dir><dir name="controllers"><file name="ExportController.php" hash="83a48feea4dc3d601b2cef7df2d27110"/><file name="ImportController.php" hash="03922ffac029110e4739497c69ba45f5"/><file name="IndexController.php" hash="93918848d3ce7f6ad05688f89a730e75"/></dir><dir name="etc"><file name="api.xml" hash="6178269d7dc6cb7aa1188f059e75a4fc"/><file name="config.xml" hash="73ef5016ba330568af36e5cf3f4d8619"/><file name="system.xml" hash="395c2670f5132a4e617310345185c200"/><file name="wsdl.xml" hash="bab71f49a1053f87094da12d1060d1d5"/></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="FarApp_Connector.xml" hash="ff3fe315c70239229cb5ff3a49d40967"/></dir></target></contents>
16
  <compatible/>
17
  <dependencies><required><php><min>5.0.0</min><max>5.7.0</max></php></required></dependencies>
18
  </package>
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>FarApp_Connector</name>
4
+ <version>1.5.6</version>
5
  <stability>stable</stability>
6
  <license uri="https://www.farapp.com/signup/">Commercial</license>
7
  <channel>community</channel>
8
  <extends/>
9
  <summary>Connector to sync product data from FarApp to Magento. FarApp currently supports NetSuite and other backends.</summary>
10
  <description>FarApp is a cloud-based solution for posting product data to storefronts, retrieving orders from storefront and posting fulfillments to storefronts. We support various backends including NetSuite, X-Cart, 3D-Cart, and more. This connector allows full product data posting to Magento from FarApp. It has the the extra benefits of allowing FarApp to dynamically push new product data, automatically creating new attribute options and importing external images (features not provided by Magento).</description>
11
+ <notes>Added support for special values FARAPPOMIT and FARAPPIGNORE.</notes>
12
  <authors><author><name>FarApp</name><user>FarApp</user><email>support@farapp.com</email></author></authors>
13
+ <date>2017-05-17</date>
14
+ <time>17:41:15</time>
15
+ <contents><target name="magecommunity"><dir name="FarApp"><dir name="Connector"><dir name="Helper"><file name="Data.php" hash="60ea63e7acbcdd006c05d3f8528d6b91"/></dir><dir name="Model"><dir name="Export"><dir name="Adapter"><file name="Abstract.php" hash="765dc8fbab996f17b9f049cc8aa906a0"/><file name="Array.php" hash="6ca62c702dcb9512ec429563ac1ce1a2"/></dir><dir name="Entity"><file name="Order.php" hash="14a2f735cf8fc5e8f2bcd6682a1e56b1"/></dir></dir><file name="Export.php" hash="01643ef101731c6d98bbc523642f95a0"/><dir name="Import"><dir name="Entity"><file name="Customer.php" hash="376978f635c73605d428037cca8cf594"/><file name="Order.php" hash="38579396825a1bd3ad59de84278085f6"/><dir name="Product"><dir name="Type"><file name="Bundle.php" hash="50acbc00136c53b77e99595b4d42ecd5"/><file name="Configurable.php" hash="1929ec7ef35dece6ccb45ee2f2e9f948"/><file name="Grouped.php" hash="a0e76e8df865369afea7e08cb5b8a0a6"/><file name="Simple.php" hash="8e391fa46ee657a55a68fb1667b945ce"/><file name="Virtual.php" hash="68a0ee5d2af8269d16f56416988e90aa"/></dir></dir><file name="Product.php" hash="95776e1ea7f2bcf2265afdfe7116d22d"/><file name="minVersion2.php" hash="8df670fd68516ba1629304ae8ab6c812"/></dir></dir><file name="Import.php" hash="deb96f4867780788413d96be1c2b9ff9"/><file name="Observer.php" hash="4bc864815ea234f1b0ae064477bdff45"/><dir name="Order"><dir name="Creditmemo"><file name="Api.php" hash="edb85d34679eab92e8990a0dd065632e"/></dir><dir name="Invoice"><file name="Api.php" hash="f133255dae51ab9c44c71ca9cc702d0a"/></dir></dir><dir name="Product"><file name="Api.php" hash="60539725273ed3ce03adef8e90198cc3"/></dir></dir><dir name="controllers"><file name="ExportController.php" hash="83a48feea4dc3d601b2cef7df2d27110"/><file name="ImportController.php" hash="03922ffac029110e4739497c69ba45f5"/><file name="IndexController.php" hash="93918848d3ce7f6ad05688f89a730e75"/></dir><dir name="etc"><file name="api.xml" hash="6178269d7dc6cb7aa1188f059e75a4fc"/><file name="config.xml" hash="b9eb77160df386d06f95346b6c78930b"/><file name="system.xml" hash="395c2670f5132a4e617310345185c200"/><file name="wsdl.xml" hash="bab71f49a1053f87094da12d1060d1d5"/></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="FarApp_Connector.xml" hash="ff3fe315c70239229cb5ff3a49d40967"/></dir></target></contents>
16
  <compatible/>
17
  <dependencies><required><php><min>5.0.0</min><max>5.7.0</max></php></required></dependencies>
18
  </package>