diff --git a/src/app/code/community/AvS/FastSimpleImport/Model/Import/Entity/Product.php b/src/app/code/community/AvS/FastSimpleImport/Model/Import/Entity/Product.php index d28a666c..51f5ac68 100644 --- a/src/app/code/community/AvS/FastSimpleImport/Model/Import/Entity/Product.php +++ b/src/app/code/community/AvS/FastSimpleImport/Model/Import/Entity/Product.php @@ -9,6 +9,7 @@ */ class AvS_FastSimpleImport_Model_Import_Entity_Product extends Mage_ImportExport_Model_Import_Entity_Product { + CONST COL_CATEGORY_POSITION = 'position'; /** @var array */ protected $_dropdownAttributes = array(); @@ -28,6 +29,8 @@ public function getAllowRenameFiles() return $this->_allowRenameFiles; } + + /** * Source model setter. * @@ -605,4 +608,239 @@ protected function _saveStockItem() } return $this; } + /** + * Gather and save information about product entities. + * Overwritten to allow correct product positions within a category + * + * @return Mage_ImportExport_Model_Import_Entity_Product + */ + protected function _saveProducts() + { + /** @var $resource Mage_ImportExport_Model_Import_Proxy_Product_Resource */ + $resource = Mage::getModel('importexport/import_proxy_product_resource'); + $priceIsGlobal = Mage::helper('catalog')->isPriceGlobal(); + $strftimeFormat = Varien_Date::convertZendToStrftime(Varien_Date::DATETIME_INTERNAL_FORMAT, true, true); + $productLimit = null; + $productsQty = null; + + while ($bunch = $this->_dataSourceModel->getNextBunch()) { + $entityRowsIn = array(); + $entityRowsUp = array(); + $attributes = array(); + $websites = array(); + $categories = array(); + $tierPrices = array(); + $groupPrices = array(); + $mediaGallery = array(); + $uploadedGalleryFiles = array(); + $previousType = null; + $previousAttributeSet = null; + + foreach ($bunch as $rowNum => $rowData) { + if (!$this->validateRow($rowData, $rowNum)) { + continue; + } + $rowScope = $this->getRowScope($rowData); + + if (self::SCOPE_DEFAULT == $rowScope) { + $rowSku = $rowData[self::COL_SKU]; + + // 1. Entity phase + if (isset($this->_oldSku[$rowSku])) { // existing row + $entityRowsUp[] = array( + 'updated_at' => now(), + 'entity_id' => $this->_oldSku[$rowSku]['entity_id'] + ); + } else { // new row + if (!$productLimit || $productsQty < $productLimit) { + $entityRowsIn[$rowSku] = array( + 'entity_type_id' => $this->_entityTypeId, + 'attribute_set_id' => $this->_newSku[$rowSku]['attr_set_id'], + 'type_id' => $this->_newSku[$rowSku]['type_id'], + 'sku' => $rowSku, + 'created_at' => now(), + 'updated_at' => now() + ); + $productsQty++; + } else { + $rowSku = null; // sign for child rows to be skipped + $this->_rowsToSkip[$rowNum] = true; + continue; + } + } + } elseif (null === $rowSku) { + $this->_rowsToSkip[$rowNum] = true; + continue; // skip rows when SKU is NULL + } elseif (self::SCOPE_STORE == $rowScope) { // set necessary data from SCOPE_DEFAULT row + $rowData[self::COL_TYPE] = $this->_newSku[$rowSku]['type_id']; + $rowData['attribute_set_id'] = $this->_newSku[$rowSku]['attr_set_id']; + $rowData[self::COL_ATTR_SET] = $this->_newSku[$rowSku]['attr_set_code']; + } + if (!empty($rowData['_product_websites'])) { // 2. Product-to-Website phase + $websites[$rowSku][$this->_websiteCodeToId[$rowData['_product_websites']]] = true; + } + + // 3. Categories phase + // nhp: added +1 to the actual position to avoid problems with true/false casting if they + // occur at any point (not found any) + $categoryPath = empty($rowData[self::COL_CATEGORY]) ? '' : $rowData[self::COL_CATEGORY]; + if (!empty($rowData[self::COL_ROOT_CATEGORY])) { + $categoryId = $this->_categoriesWithRoots[$rowData[self::COL_ROOT_CATEGORY]][$categoryPath]; + $categories[$rowSku][$categoryId] = true; + } elseif (!empty($categoryPath)) { + $categories[$rowSku][$this->_categories[$categoryPath]] = $rowData[self::COL_CATEGORY_POSITION] + 1; + } + + if (!empty($rowData['_tier_price_website'])) { // 4.1. Tier prices phase + $tierPrices[$rowSku][] = array( + 'all_groups' => $rowData['_tier_price_customer_group'] == self::VALUE_ALL, + 'customer_group_id' => ($rowData['_tier_price_customer_group'] == self::VALUE_ALL) + ? 0 : $rowData['_tier_price_customer_group'], + 'qty' => $rowData['_tier_price_qty'], + 'value' => $rowData['_tier_price_price'], + 'website_id' => (self::VALUE_ALL == $rowData['_tier_price_website'] || $priceIsGlobal) + ? 0 : $this->_websiteCodeToId[$rowData['_tier_price_website']] + ); + } + if (!empty($rowData['_group_price_website'])) { // 4.2. Group prices phase + $groupPrices[$rowSku][] = array( + 'all_groups' => $rowData['_group_price_customer_group'] == self::VALUE_ALL, + 'customer_group_id' => ($rowData['_group_price_customer_group'] == self::VALUE_ALL) + ? 0 : $rowData['_group_price_customer_group'], + 'value' => $rowData['_group_price_price'], + 'website_id' => (self::VALUE_ALL == $rowData['_group_price_website'] || $priceIsGlobal) + ? 0 : $this->_websiteCodeToId[$rowData['_group_price_website']] + ); + } + foreach ($this->_imagesArrayKeys as $imageCol) { + if (!empty($rowData[$imageCol])) { // 5. Media gallery phase + if (!array_key_exists($rowData[$imageCol], $uploadedGalleryFiles)) { + $uploadedGalleryFiles[$rowData[$imageCol]] = $this->_uploadMediaFiles($rowData[$imageCol]); + } + $rowData[$imageCol] = $uploadedGalleryFiles[$rowData[$imageCol]]; + } + } + if (!empty($rowData['_media_image'])) { + $mediaGallery[$rowSku][] = array( + 'attribute_id' => $rowData['_media_attribute_id'], + 'label' => $rowData['_media_lable'], + 'position' => $rowData['_media_position'], + 'disabled' => $rowData['_media_is_disabled'], + 'value' => $rowData['_media_image'] + ); + } + // 6. Attributes phase + $rowStore = self::SCOPE_STORE == $rowScope ? $this->_storeCodeToId[$rowData[self::COL_STORE]] : 0; + $productType = $rowData[self::COL_TYPE]; + if(!is_null($rowData[self::COL_TYPE])) { + $previousType = $rowData[self::COL_TYPE]; + } + if(!is_null($rowData[self::COL_ATTR_SET])) { + $previousAttributeSet = $rowData[Mage_ImportExport_Model_Import_Entity_Product::COL_ATTR_SET]; + } + if (self::SCOPE_NULL == $rowScope) { + // for multiselect attributes only + if(!is_null($previousAttributeSet)) { + $rowData[Mage_ImportExport_Model_Import_Entity_Product::COL_ATTR_SET] = $previousAttributeSet; + } + if(is_null($productType) && !is_null($previousType)) { + $productType = $previousType; + } + if(is_null($productType)) { + continue; + } + } + $rowData = $this->_productTypeModels[$productType]->prepareAttributesForSave($rowData); + $product = Mage::getModel('importexport/import_proxy_product', $rowData); + + foreach ($rowData as $attrCode => $attrValue) { + $attribute = $resource->getAttribute($attrCode); + if('multiselect' != $attribute->getFrontendInput() + && self::SCOPE_NULL == $rowScope) { + continue; // skip attribute processing for SCOPE_NULL rows + } + $attrId = $attribute->getId(); + $backModel = $attribute->getBackendModel(); + $attrTable = $attribute->getBackend()->getTable(); + $storeIds = array(0); + + if ('datetime' == $attribute->getBackendType() && strtotime($attrValue)) { + $attrValue = gmstrftime($strftimeFormat, strtotime($attrValue)); + } elseif ($backModel) { + $attribute->getBackend()->beforeSave($product); + $attrValue = $product->getData($attribute->getAttributeCode()); + } + if (self::SCOPE_STORE == $rowScope) { + if (self::SCOPE_WEBSITE == $attribute->getIsGlobal()) { + // check website defaults already set + if (!isset($attributes[$attrTable][$rowSku][$attrId][$rowStore])) { + $storeIds = $this->_storeIdToWebsiteStoreIds[$rowStore]; + } + } elseif (self::SCOPE_STORE == $attribute->getIsGlobal()) { + $storeIds = array($rowStore); + } + } + foreach ($storeIds as $storeId) { + if('multiselect' == $attribute->getFrontendInput()) { + if(!isset($attributes[$attrTable][$rowSku][$attrId][$storeId])) { + $attributes[$attrTable][$rowSku][$attrId][$storeId] = ''; + } else { + $attributes[$attrTable][$rowSku][$attrId][$storeId] .= ','; + } + $attributes[$attrTable][$rowSku][$attrId][$storeId] .= $attrValue; + } else { + $attributes[$attrTable][$rowSku][$attrId][$storeId] = $attrValue; + } + } + $attribute->setBackendModel($backModel); // restore 'backend_model' to avoid 'default' setting + } + } + $this->_saveProductEntity($entityRowsIn, $entityRowsUp) + ->_saveProductWebsites($websites) + ->_saveProductCategories($categories) + ->_saveProductTierPrices($tierPrices) + ->_saveProductGroupPrices($groupPrices) + ->_saveMediaGallery($mediaGallery) + ->_saveProductAttributes($attributes); + } + return $this; + } + + /** + * Save product categories. Adapted to allow positioning within a category instead of always supplying 1 as position + * + * @param array $categoriesData + * @return Mage_ImportExport_Model_Import_Entity_Product + */ + protected function _saveProductCategories(array $categoriesData) + { + static $tableName = null; + + if (!$tableName) { + $tableName = Mage::getModel('importexport/import_proxy_product_resource')->getProductCategoryTable(); + } + if ($categoriesData) { + $categoriesIn = array(); + $delProductId = array(); + + foreach ($categoriesData as $delSku => $categories) { + $productId = $this->_newSku[$delSku]['entity_id']; + $delProductId[] = $productId; + + foreach ($categories as $categoryId => $position) { + $categoriesIn[] = array('product_id' => $productId, 'category_id' => $categoryId, 'position' => ($position-1 > 0) ? $position - 1 : 1); + } + } + if (Mage_ImportExport_Model_Import::BEHAVIOR_APPEND != $this->getBehavior()) { + $this->_connection->delete( + $tableName, + $this->_connection->quoteInto('product_id IN (?)', $delProductId) + ); + } + if ($categoriesIn) { + $this->_connection->insertOnDuplicate($tableName, $categoriesIn, array('position')); + } + } + return $this; + } } \ No newline at end of file