/** * Redefine Attribute scope * * @param \Magento\Catalog\Model\ResourceModel\Eav\Attribute $attribute * @return $this */ public function setScope($attribute) { if ($this->_helper->isPriceGlobal()) { $attribute->setIsGlobal(ScopedAttributeInterface::SCOPE_GLOBAL); } else { $attribute->setIsGlobal(ScopedAttributeInterface::SCOPE_WEBSITE); } return $this; }
/** * Redefine Attribute scope * * @param \Magento\Catalog\Model\Resource\Eav\Attribute $attribute * @return $this */ public function setScope($attribute) { if ($this->_helper->isPriceGlobal()) { $attribute->setIsGlobal(\Magento\Catalog\Model\Resource\Eav\Attribute::SCOPE_GLOBAL); } else { $attribute->setIsGlobal(\Magento\Catalog\Model\Resource\Eav\Attribute::SCOPE_WEBSITE); } return $this; }
/** * Processing object before save data * * @return $this */ public function afterSave() { if (!$this->_catalogData->isPriceGlobal() && $this->getWebsiteId()) { $this->getResource()->saveSelectionPrice($this); if (!$this->getDefaultPriceScope()) { $this->unsSelectionPriceValue(); $this->unsSelectionPriceType(); } } parent::afterSave(); }
/** * {@inheritdoc} */ public function build($productId) { $linkField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField(); $productTable = $this->resource->getTableName('catalog_product_entity'); $priceSelect = $this->resource->getConnection()->select()->from(['parent' => $productTable], '')->joinInner(['link' => $this->resource->getTableName('catalog_product_relation')], "link.parent_id = parent.{$linkField}", [])->joinInner(['child' => $productTable], "child.entity_id = link.child_id", ['entity_id'])->joinInner(['t' => $this->resource->getTableName('catalog_product_entity_tier_price')], "t.{$linkField} = child.{$linkField}", [])->where('parent.entity_id = ? ', $productId)->where('t.all_groups = 1 OR customer_group_id = ?', $this->customerSession->getCustomerGroupId())->where('t.qty = ?', 1)->order('t.value ' . Select::SQL_ASC)->limit(1); $priceSelectDefault = clone $priceSelect; $priceSelectDefault->where('t.website_id = ?', self::DEFAULT_WEBSITE_ID); $select[] = $priceSelectDefault; if (!$this->catalogHelper->isPriceGlobal()) { $priceSelect->where('t.website_id = ?', $this->storeManager->getStore()->getWebsiteId()); $select[] = $priceSelect; } return $select; }
/** * {@inheritdoc} */ public function build($productId) { $linkField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField(); $priceAttribute = $this->eavConfig->getAttribute(Product::ENTITY, 'price'); $productTable = $this->resource->getTableName('catalog_product_entity'); $priceSelect = $this->resource->getConnection()->select()->from(['parent' => $productTable], '')->joinInner(['link' => $this->resource->getTableName('catalog_product_relation')], "link.parent_id = parent.{$linkField}", [])->joinInner(['child' => $productTable], "child.entity_id = link.child_id", ['entity_id'])->joinInner(['t' => $priceAttribute->getBackendTable()], "t.{$linkField} = child.{$linkField}", [])->where('parent.entity_id = ? ', $productId)->where('t.attribute_id = ?', $priceAttribute->getAttributeId())->where('t.value IS NOT NULL')->order('t.value ' . Select::SQL_ASC)->limit(1); $priceSelectDefault = clone $priceSelect; $priceSelectDefault->where('t.store_id = ?', Store::DEFAULT_STORE_ID); $select[] = $priceSelectDefault; if (!$this->catalogHelper->isPriceGlobal()) { $priceSelect->where('t.store_id = ?', $this->storeManager->getStore()->getId()); $select[] = $priceSelect; } return $select; }
/** * Save title and price of link item * * @param \Magento\Downloadable\Model\Link $linkObject * @return $this * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function saveItemTitleAndPrice($linkObject) { $connection = $this->getConnection(); $linkTitleTable = $this->getTable('downloadable_link_title'); $linkPriceTable = $this->getTable('downloadable_link_price'); $select = $connection->select()->from($this->getTable('downloadable_link_title'))->where('link_id=:link_id AND store_id=:store_id'); $bind = [':link_id' => $linkObject->getId(), ':store_id' => (int) $linkObject->getStoreId()]; if ($connection->fetchOne($select, $bind)) { $where = ['link_id = ?' => $linkObject->getId(), 'store_id = ?' => (int) $linkObject->getStoreId()]; if ($linkObject->getUseDefaultTitle()) { $connection->delete($linkTitleTable, $where); } else { $insertData = ['title' => $linkObject->getTitle()]; $connection->update($linkTitleTable, $insertData, $where); } } else { if (!$linkObject->getUseDefaultTitle()) { $connection->insert($linkTitleTable, ['link_id' => $linkObject->getId(), 'store_id' => (int) $linkObject->getStoreId(), 'title' => $linkObject->getTitle()]); } } $select = $connection->select()->from($linkPriceTable)->where('link_id=:link_id AND website_id=:website_id'); $bind = [':link_id' => $linkObject->getId(), ':website_id' => (int) $linkObject->getWebsiteId()]; if ($connection->fetchOne($select, $bind)) { $where = ['link_id = ?' => $linkObject->getId(), 'website_id = ?' => $linkObject->getWebsiteId()]; if ($linkObject->getUseDefaultPrice()) { $connection->delete($linkPriceTable, $where); } else { $connection->update($linkPriceTable, ['price' => $linkObject->getPrice()], $where); } } else { if (!$linkObject->getUseDefaultPrice()) { $dataToInsert[] = ['link_id' => $linkObject->getId(), 'website_id' => (int) $linkObject->getWebsiteId(), 'price' => (double) $linkObject->getPrice()]; if ($linkObject->getOrigData('link_id') != $linkObject->getLinkId()) { $_isNew = true; } else { $_isNew = false; } if ($linkObject->getWebsiteId() == 0 && $_isNew && !$this->_catalogData->isPriceGlobal()) { $websiteIds = $linkObject->getProductWebsiteIds(); foreach ($websiteIds as $websiteId) { $baseCurrency = $this->_configuration->getValue(\Magento\Directory\Model\Currency::XML_PATH_CURRENCY_BASE, 'default'); $websiteCurrency = $this->_storeManager->getWebsite($websiteId)->getBaseCurrencyCode(); if ($websiteCurrency == $baseCurrency) { continue; } $rate = $this->_createCurrency()->load($baseCurrency)->getRate($websiteCurrency); if (!$rate) { $rate = 1; } $newPrice = $linkObject->getPrice() * $rate; $dataToInsert[] = ['link_id' => $linkObject->getId(), 'website_id' => (int) $websiteId, 'price' => $newPrice]; } } $connection->insertMultiple($linkPriceTable, $dataToInsert); } } return $this; }
/** * Load prices for configurable attribute * * @param ConfigurableAttribute $object * @return $this */ protected function loadPrices(ConfigurableAttribute $object) { $websiteId = $this->_catalogData->isPriceGlobal() ? 0 : (int) $this->_storeManager->getStore()->getWebsiteId(); $select = $this->_getReadAdapter()->select()->from($this->_priceTable)->where('product_super_attribute_id = ?', $object->getId())->where('website_id = ?', $websiteId); foreach ($select->query() as $row) { $data = ['value_index' => $row['value_index'], 'is_percent' => $row['is_percent'], 'pricing_value' => $row['pricing_value']]; $object->addPrice($data); } return $this; }
/** * {@inheritdoc} */ public function build($productId) { $linkField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField(); $connection = $this->resource->getConnection(); $specialPriceAttribute = $this->eavConfig->getAttribute(Product::ENTITY, 'special_price'); $specialPriceFromDate = $this->eavConfig->getAttribute(Product::ENTITY, 'special_from_date'); $specialPriceToDate = $this->eavConfig->getAttribute(Product::ENTITY, 'special_to_date'); $timestamp = $this->localeDate->scopeTimeStamp($this->storeManager->getStore()); $currentDate = $this->dateTime->formatDate($timestamp, false); $productTable = $this->resource->getTableName('catalog_product_entity'); $specialPrice = $this->resource->getConnection()->select()->from(['parent' => $productTable], '')->joinInner(['link' => $this->resource->getTableName('catalog_product_relation')], "link.parent_id = parent.{$linkField}", [])->joinInner(['child' => $productTable], "child.entity_id = link.child_id", ['entity_id'])->joinInner(['t' => $specialPriceAttribute->getBackendTable()], "t.{$linkField} = child.{$linkField}", [])->joinLeft(['special_from' => $specialPriceFromDate->getBackendTable()], $connection->quoteInto("t.{$linkField} = special_from.{$linkField} AND special_from.attribute_id = ?", $specialPriceFromDate->getAttributeId()), '')->joinLeft(['special_to' => $specialPriceToDate->getBackendTable()], $connection->quoteInto("t.{$linkField} = special_to.{$linkField} AND special_to.attribute_id = ?", $specialPriceToDate->getAttributeId()), '')->where('parent.entity_id = ? ', $productId)->where('t.attribute_id = ?', $specialPriceAttribute->getAttributeId())->where('t.value IS NOT NULL')->where('special_from.value IS NULL OR ' . $connection->getDatePartSql('special_from.value') . ' <= ?', $currentDate)->where('special_to.value IS NULL OR ' . $connection->getDatePartSql('special_to.value') . ' >= ?', $currentDate)->order('t.value ' . Select::SQL_ASC)->limit(1); $specialPriceDefault = clone $specialPrice; $specialPriceDefault->where('t.store_id = ?', Store::DEFAULT_STORE_ID); $select[] = $specialPriceDefault; if (!$this->catalogHelper->isPriceGlobal()) { $specialPrice->where('t.store_id = ?', $this->storeManager->getStore()->getId()); $select[] = $specialPrice; } return $select; }
/** * Retrieve bundle selections collection based on ids * * @param array $selectionIds * @param \Magento\Catalog\Model\Product $product * @return \Magento\Bundle\Model\ResourceModel\Selection\Collection */ public function getSelectionsByIds($selectionIds, $product) { sort($selectionIds); $usedSelections = $product->getData($this->_keyUsedSelections); $usedSelectionsIds = $product->getData($this->_keyUsedSelectionsIds); if (!$usedSelections || $usedSelectionsIds !== $selectionIds) { $storeId = $product->getStoreId(); $usedSelections = $this->_bundleCollection->create()->addAttributeToSelect('*')->setFlag('require_stock_items', true)->setFlag('product_children', true)->addStoreFilter($this->getStoreFilter($product))->setStoreId($storeId)->setPositionOrder()->addFilterByRequiredOptions()->setSelectionIdsFilter($selectionIds); if (!$this->_catalogData->isPriceGlobal() && $storeId) { $websiteId = $this->_storeManager->getStore($storeId)->getWebsiteId(); $usedSelections->joinPrices($websiteId); } $product->setData($this->_keyUsedSelections, $usedSelections); $product->setData($this->_keyUsedSelectionsIds, $selectionIds); } return $usedSelections; }
/** * Retrieve bundle selections collection based on ids * * @param array $selectionIds * @param \Magento\Catalog\Model\Product $product * @return \Magento\Bundle\Model\ResourceModel\Selection\Collection */ public function getSelectionsByIds($selectionIds, $product) { sort($selectionIds); $usedSelections = $product->getData($this->_keyUsedSelections); $usedSelectionsIds = $product->getData($this->_keyUsedSelectionsIds); if (!$usedSelections || $usedSelectionsIds !== $selectionIds) { $storeId = $product->getStoreId(); $usedSelections = $this->_bundleCollection->create()->addAttributeToSelect('*')->setFlag('require_stock_items', true)->setFlag('product_children', true)->addStoreFilter($this->getStoreFilter($product))->setStoreId($storeId)->setPositionOrder()->addFilterByRequiredOptions()->setSelectionIdsFilter($selectionIds); if (count($usedSelections->getItems()) !== count($selectionIds)) { throw new \Magento\Framework\Exception\LocalizedException(__('The options you selected are not available.')); } if (!$this->_catalogData->isPriceGlobal() && $storeId) { $websiteId = $this->_storeManager->getStore($storeId)->getWebsiteId(); $usedSelections->joinPrices($websiteId); } $product->setData($this->_keyUsedSelections, $usedSelections); $product->setData($this->_keyUsedSelectionsIds, $selectionIds); } return $usedSelections; }
/** * Get website id by code * * @param string $websiteCode * @return array|int|string */ protected function getWebSiteId($websiteCode) { $result = $websiteCode == $this->_getValidator(self::VALIDATOR_WEBSITE)->getAllWebsitesValue() || $this->_catalogData->isPriceGlobal() ? 0 : $this->_storeResolver->getWebsiteCodeToId($websiteCode); return $result; }
/** * Gather and save information about product entities. * * @return $this * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) * @SuppressWarnings(PHPMD.ExcessiveMethodLength) * @SuppressWarnings(PHPMD.UnusedLocalVariable) */ protected function _saveProducts() { /** @var $resource \Magento\CatalogImportExport\Model\Import\Proxy\Product\ResourceModel */ $resource = $this->_resourceFactory->create(); $priceIsGlobal = $this->_catalogData->isPriceGlobal(); $productLimit = null; $productsQty = null; while ($bunch = $this->_dataSourceModel->getNextBunch()) { $entityRowsIn = []; $entityRowsUp = []; $attributes = []; $this->websitesCache = []; $this->categoriesCache = []; $tierPrices = []; $mediaGallery = []; $uploadedGalleryFiles = []; $previousType = null; $prevAttributeSet = null; $allImagesFromBunch = $this->_getAllBunchImages($bunch); $existingImages = $this->_prepareAllMediaFiles($allImagesFromBunch); foreach ($bunch as $rowNum => $rowData) { if (!$this->validateRow($rowData, $rowNum)) { continue; } if ($this->getErrorAggregator()->hasToBeTerminated()) { $this->getErrorAggregator()->addRowToSkip($rowNum); continue; } $rowScope = $this->getRowScope($rowData); $rowSku = $rowData[self::COL_SKU]; if (null === $rowSku) { $this->getErrorAggregator()->addRowToSkip($rowNum); continue; } elseif (self::SCOPE_STORE == $rowScope) { // set necessary data from SCOPE_DEFAULT row $rowData[self::COL_TYPE] = $this->skuProcessor->getNewSku($rowSku)['type_id']; $rowData['attribute_set_id'] = $this->skuProcessor->getNewSku($rowSku)['attr_set_id']; $rowData[self::COL_ATTR_SET] = $this->skuProcessor->getNewSku($rowSku)['attr_set_code']; } // 1. Entity phase if (isset($this->_oldSku[$rowSku])) { // existing row $entityRowsUp[] = ['updated_at' => (new \DateTime())->format(DateTime::DATETIME_PHP_FORMAT), 'entity_id' => $this->_oldSku[$rowSku]['entity_id']]; } else { if (!$productLimit || $productsQty < $productLimit) { $entityRowsIn[$rowSku] = ['attribute_set_id' => $this->skuProcessor->getNewSku($rowSku)['attr_set_id'], 'type_id' => $this->skuProcessor->getNewSku($rowSku)['type_id'], 'sku' => $rowSku, 'has_options' => isset($rowData['has_options']) ? $rowData['has_options'] : 0, 'created_at' => (new \DateTime())->format(DateTime::DATETIME_PHP_FORMAT), 'updated_at' => (new \DateTime())->format(DateTime::DATETIME_PHP_FORMAT)]; $productsQty++; } else { $rowSku = null; // sign for child rows to be skipped $this->getErrorAggregator()->addRowToSkip($rowNum); continue; } } $this->websitesCache[$rowSku] = []; // 2. Product-to-Website phase if (!empty($rowData[self::COL_PRODUCT_WEBSITES])) { $websiteCodes = explode($this->getMultipleValueSeparator(), $rowData[self::COL_PRODUCT_WEBSITES]); foreach ($websiteCodes as $websiteCode) { $websiteId = $this->storeResolver->getWebsiteCodeToId($websiteCode); $this->websitesCache[$rowSku][$websiteId] = true; } } // 3. Categories phase $categoriesString = empty($rowData[self::COL_CATEGORY]) ? '' : $rowData[self::COL_CATEGORY]; $this->categoriesCache[$rowSku] = []; if (!empty($categoriesString)) { foreach ($this->categoryProcessor->upsertCategories($categoriesString) as $categoryId) { $this->categoriesCache[$rowSku][$categoryId] = true; } } // 4.1. Tier prices phase if (!empty($rowData['_tier_price_website'])) { $tierPrices[$rowSku][] = ['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->storeResolver->getWebsiteCodeToId($rowData['_tier_price_website'])]; } if (!$this->validateRow($rowData, $rowNum)) { continue; } // 5. Media gallery phase $mediaGalleryImages = array(); $mediaGalleryLabels = array(); if (!empty($rowData[self::COL_MEDIA_IMAGE])) { $mediaGalleryImages = explode($this->getMultipleValueSeparator(), $rowData[self::COL_MEDIA_IMAGE]); if (isset($rowData['_media_image_label'])) { $mediaGalleryLabels = explode($this->getMultipleValueSeparator(), $rowData['_media_image_label']); } else { $mediaGalleryLabels = []; } if (count($mediaGalleryLabels) > count($mediaGalleryImages)) { $mediaGalleryLabels = array_slice($mediaGalleryLabels, 0, count($mediaGalleryImages)); } elseif (count($mediaGalleryLabels) < count($mediaGalleryImages)) { $mediaGalleryLabels = array_pad($mediaGalleryLabels, count($mediaGalleryImages), ''); } } foreach ($this->_imagesArrayKeys as $imageCol) { if (!empty($rowData[$imageCol]) && $imageCol != self::COL_MEDIA_IMAGE && !in_array($rowData[$imageCol], $mediaGalleryImages)) { $mediaGalleryImages[] = $rowData[$imageCol]; if (isset($mediaGalleryLabels)) { $mediaGalleryLabels[] = isset($rowData[$imageCol . '_label']) ? $rowData[$imageCol . '_label'] : ''; } else { $mediaGalleryLabels[] = ''; } } } $rowData[self::COL_MEDIA_IMAGE] = array(); foreach ($mediaGalleryImages as $mediaImage) { $imagePath = $allImagesFromBunch[$mediaImage]; if (isset($existingImages[$imagePath]) && in_array($rowSku, $existingImages[$imagePath])) { if (!array_key_exists($mediaImage, $uploadedGalleryFiles)) { $uploadedFile = $this->_uploadMediaFiles(trim($mediaImage), true); if ($uploadedFile) { $uploadedGalleryFiles[$mediaImage] = $uploadedFile; } else { $this->addRowError(ValidatorInterface::ERROR_MEDIA_URL_NOT_ACCESSIBLE, $rowNum, null, null, ProcessingError::ERROR_LEVEL_NOT_CRITICAL); } } } elseif (!isset($existingImages[$imagePath])) { if (!array_key_exists($mediaImage, $uploadedGalleryFiles)) { $uploadedFile = $this->_uploadMediaFiles(trim($mediaImage), true); if ($uploadedFile) { $uploadedGalleryFiles[$mediaImage] = $uploadedFile; $newImagePath = $uploadedGalleryFiles[$mediaImage]; $existingImages[$newImagePath][] = $rowSku; } else { $this->addRowError(ValidatorInterface::ERROR_MEDIA_URL_NOT_ACCESSIBLE, $rowNum, null, null, ProcessingError::ERROR_LEVEL_NOT_CRITICAL); } } if (isset($uploadedGalleryFiles[$mediaImage])) { $rowData[self::COL_MEDIA_IMAGE][] = $uploadedGalleryFiles[$mediaImage]; if (!empty($rowData[self::COL_MEDIA_IMAGE]) && is_array($rowData[self::COL_MEDIA_IMAGE])) { $position = array_search($mediaImage, $mediaGalleryImages); foreach ($rowData[self::COL_MEDIA_IMAGE] as $mediaImage) { $mediaGallery[$rowSku][] = ['attribute_id' => $this->getMediaGalleryAttributeId(), 'label' => isset($mediaGalleryLabels[$position]) ? $mediaGalleryLabels[$position] : '', 'position' => $position, 'disabled' => '', 'value' => $mediaImage]; } } } } foreach ($this->_imagesArrayKeys as $imageCol) { if (empty($rowData[$imageCol]) || $imageCol == self::COL_MEDIA_IMAGE) { continue; } if (isset($existingImages[$imagePath]) && !in_array($rowSku, $existingImages[$imagePath]) && ($rowData[$imageCol] == $imagePath || $rowData[$imageCol] == $mediaImage)) { unset($rowData[$imageCol]); } elseif (isset($uploadedGalleryFiles[$rowData[$imageCol]])) { $rowData[$imageCol] = $uploadedGalleryFiles[$rowData[$imageCol]]; } } } // 6. Attributes phase $rowStore = self::SCOPE_STORE == $rowScope ? $this->storeResolver->getStoreCodeToId($rowData[self::COL_STORE]) : 0; $productType = isset($rowData[self::COL_TYPE]) ? $rowData[self::COL_TYPE] : null; if (!is_null($productType)) { $previousType = $productType; } if (isset($rowData[self::COL_ATTR_SET])) { $prevAttributeSet = $rowData[self::COL_ATTR_SET]; } if (self::SCOPE_NULL == $rowScope) { // for multiselect attributes only if (!is_null($prevAttributeSet)) { $rowData[self::COL_ATTR_SET] = $prevAttributeSet; } if (is_null($productType) && !is_null($previousType)) { $productType = $previousType; } if (is_null($productType)) { continue; } } $productTypeModel = $this->_productTypeModels[$productType]; if (!empty($rowData['tax_class_name'])) { $rowData['tax_class_id'] = $this->taxClassProcessor->upsertTaxClass($rowData['tax_class_name'], $productTypeModel); } if ($this->getBehavior() == \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND || empty($rowData[self::COL_SKU])) { $rowData = $productTypeModel->clearEmptyData($rowData); } $rowData = $productTypeModel->prepareAttributesWithDefaultValueForSave($rowData, !isset($this->_oldSku[$rowSku])); $product = $this->_proxyProdFactory->create(['data' => $rowData]); foreach ($rowData as $attrCode => $attrValue) { $attribute = $this->retrieveAttributeByCode($attrCode); if ('multiselect' != $attribute->getFrontendInput() && self::SCOPE_NULL == $rowScope) { // skip attribute processing for SCOPE_NULL rows continue; } $attrId = $attribute->getId(); $backModel = $attribute->getBackendModel(); $attrTable = $attribute->getBackend()->getTable(); $storeIds = [0]; if ('datetime' == $attribute->getBackendType() && strtotime($attrValue)) { $attrValue = (new \DateTime())->setTimestamp(strtotime($attrValue)); $attrValue = $attrValue->format(DateTime::DATETIME_PHP_FORMAT); } 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->storeResolver->getStoreIdToWebsiteStoreIds($rowStore); } } elseif (self::SCOPE_STORE == $attribute->getIsGlobal()) { $storeIds = [$rowStore]; } if (!isset($this->_oldSku[$rowSku])) { $storeIds[] = 0; } } foreach ($storeIds as $storeId) { $attributes[$attrTable][$rowSku][$attrId][$storeId] = $attrValue; } // restore 'backend_model' to avoid 'default' setting $attribute->setBackendModel($backModel); } } $this->_saveProductEntity($entityRowsIn, $entityRowsUp)->_saveProductWebsites($this->websitesCache)->_saveProductCategories($this->categoriesCache)->_saveProductTierPrices($tierPrices)->_saveMediaGallery($mediaGallery)->_saveProductAttributes($attributes); $this->_eventManager->dispatch('catalog_product_import_bunch_save_after', ['adapter' => $this, 'bunch' => $bunch]); } return $this; }
/** * Load attribute prices information * * @return $this * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) */ protected function _loadPrices() { if ($this->count()) { $pricings = array(0 => array()); if ($this->_catalogData->isPriceGlobal()) { $websiteId = 0; } else { $websiteId = (int) $this->_storeManager->getStore($this->getStoreId())->getWebsiteId(); $pricing[$websiteId] = array(); } $select = $this->getConnection()->select()->from(array('price' => $this->_priceTable))->where('price.product_super_attribute_id IN (?)', array_keys($this->_items)); if ($websiteId > 0) { $select->where('price.website_id IN(?)', array(0, $websiteId)); } else { $select->where('price.website_id = ?', 0); } $query = $this->getConnection()->query($select); while ($row = $query->fetch()) { $pricings[(int) $row['website_id']][] = $row; } $values = array(); $usedProducts = $this->getProductType()->getUsedProducts($this->getProduct()); if ($usedProducts) { foreach ($this->_items as $item) { $productAttribute = $item->getProductAttribute(); if (!$productAttribute instanceof \Magento\Eav\Model\Entity\Attribute\AbstractAttribute) { continue; } $itemId = $item->getId(); $options = $productAttribute->getFrontend()->getSelectOptions(); foreach ($options as $option) { foreach ($usedProducts as $associatedProduct) { $attributeCodeValue = $associatedProduct->getData($productAttribute->getAttributeCode()); if (!empty($option['value']) && $option['value'] == $attributeCodeValue) { // If option available in associated product if (!isset($values[$item->getId() . ':' . $option['value']])) { $values[$itemId . ':' . $option['value']] = array('product_super_attribute_id' => $itemId, 'value_index' => $option['value'], 'label' => $option['label'], 'default_label' => $option['label'], 'store_label' => $option['label'], 'is_percent' => 0, 'pricing_value' => null, 'use_default_value' => true); } } } } } } foreach ($pricings[0] as $pricing) { // Addding pricing to options $valueKey = $pricing['product_super_attribute_id'] . ':' . $pricing['value_index']; if (isset($values[$valueKey])) { $values[$valueKey]['pricing_value'] = $pricing['pricing_value']; $values[$valueKey]['is_percent'] = $pricing['is_percent']; $values[$valueKey]['value_id'] = $pricing['value_id']; $values[$valueKey]['use_default_value'] = true; } } if ($websiteId && isset($pricings[$websiteId])) { foreach ($pricings[$websiteId] as $pricing) { $valueKey = $pricing['product_super_attribute_id'] . ':' . $pricing['value_index']; if (isset($values[$valueKey])) { $values[$valueKey]['pricing_value'] = $pricing['pricing_value']; $values[$valueKey]['is_percent'] = $pricing['is_percent']; $values[$valueKey]['value_id'] = $pricing['value_id']; $values[$valueKey]['use_default_value'] = false; } } } foreach ($values as $data) { $this->getItemById($data['product_super_attribute_id'])->addPrice($data); } } return $this; }
/** * Gather and save information about product entities. * * @return $this */ protected function _saveProducts() { /** @var $resource \Magento\CatalogImportExport\Model\Import\Proxy\Product\Resource */ $resource = $this->_resourceFactory->create(); $priceIsGlobal = $this->_catalogData->isPriceGlobal(); $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; $prevAttributeSet = 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' => $this->dateTime->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, 'has_options' => isset($rowData['has_options']) ? $rowData['has_options'] : 0, 'created_at' => $this->dateTime->now(), 'updated_at' => $this->dateTime->now()); $productsQty++; } else { $rowSku = null; // sign for child rows to be skipped $this->_rowsToSkip[$rowNum] = true; continue; } } } elseif (null === $rowSku) { $this->_rowsToSkip[$rowNum] = true; // skip rows when SKU is NULL continue; } 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']; } // 2. Product-to-Website phase if (!empty($rowData['_product_websites'])) { $websites[$rowSku][$this->_websiteCodeToId[$rowData['_product_websites']]] = true; } // 3. Categories phase $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]] = true; } // 4.1. Tier prices phase if (!empty($rowData['_tier_price_website'])) { $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']]); } // 4.2. Group prices phase if (!empty($rowData['_group_price_website'])) { $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']]); } // 5. Media gallery phase foreach ($this->_imagesArrayKeys as $imageCol) { if (!empty($rowData[$imageCol])) { 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_label'], '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 = isset($rowData[self::COL_TYPE]) ? $rowData[self::COL_TYPE] : null; if (!is_null($productType)) { $previousType = $productType; } if (isset($rowData[self::COL_ATTR_SET])) { $prevAttributeSet = $rowData[self::COL_ATTR_SET]; } if (self::SCOPE_NULL == $rowScope) { // for multiselect attributes only if (!is_null($prevAttributeSet)) { $rowData[self::COL_ATTR_SET] = $prevAttributeSet; } if (is_null($productType) && !is_null($previousType)) { $productType = $previousType; } if (is_null($productType)) { continue; } } if ($this->getBehavior() == \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND || empty($rowData[self::COL_SKU])) { $rowData = $this->_productTypeModels[$productType]->clearEmptyData($rowData); } $rowData = $this->_productTypeModels[$productType]->prepareAttributesWithDefaultValueForSave($rowData, !isset($this->_oldSku[$rowSku])); $product = $this->_proxyProdFactory->create(array('data' => $rowData)); foreach ($rowData as $attrCode => $attrValue) { $attribute = $resource->getAttribute($attrCode); if ('multiselect' != $attribute->getFrontendInput() && self::SCOPE_NULL == $rowScope) { // skip attribute processing for SCOPE_NULL rows continue; } $attrId = $attribute->getId(); $backModel = $attribute->getBackendModel(); $attrTable = $attribute->getBackend()->getTable(); $storeIds = array(0); if ('datetime' == $attribute->getBackendType() && strtotime($attrValue)) { $attrValue = new \DateTime('@' . strtotime($attrValue)); $attrValue = $attrValue->format(\Magento\Framework\Stdlib\DateTime::DATETIME_PHP_FORMAT); } 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; } } // restore 'backend_model' to avoid 'default' setting $attribute->setBackendModel($backModel); } } $this->_saveProductEntity($entityRowsIn, $entityRowsUp)->_saveProductWebsites($websites)->_saveProductCategories($categories)->_saveProductTierPrices($tierPrices)->_saveProductGroupPrices($groupPrices)->_saveMediaGallery($mediaGallery)->_saveProductAttributes($attributes); } return $this; }
/** * Check whether prices of configurable products can be editable * * @return bool */ public function isAttributesPricesReadonly() { return $this->getProduct()->getAttributesConfigurationReadonly() || $this->_catalogData->isPriceGlobal() && $this->isReadonly(); }
/** * Retrieve price values * * @return array * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) */ protected function getPriceValues() { $cachedPriceData = $this->priceData->getProductPrice($this->getProduct()->getId()); if (false !== $cachedPriceData) { return $cachedPriceData; } $pricings = [0 => []]; if ($this->_catalogData->isPriceGlobal()) { $websiteId = 0; } else { $websiteId = (int) $this->_storeManager->getStore($this->getStoreId())->getWebsiteId(); $pricing[$websiteId] = []; } $select = $this->getConnection()->select()->from(['price' => $this->_priceTable])->where('price.product_super_attribute_id IN (?)', array_keys($this->_items)); if ($websiteId > 0) { $select->where('price.website_id IN(?)', [0, $websiteId]); } else { $select->where('price.website_id = ?', 0); } $query = $this->getConnection()->query($select); while ($row = $query->fetch()) { $pricings[(int) $row['website_id']][] = $row; } $values = []; $usedProducts = $this->getProductType()->getUsedProducts($this->getProduct()); if ($usedProducts) { foreach ($this->_items as $item) { $productAttribute = $item->getProductAttribute(); if (!$productAttribute instanceof AbstractAttribute) { continue; } $itemId = $item->getId(); $options = $this->getIncludedOptions($usedProducts, $productAttribute); foreach ($options as $option) { foreach ($usedProducts as $associatedProduct) { $attributeCodeValue = $associatedProduct->getData($productAttribute->getAttributeCode()); if (!empty($option['value']) && $option['value'] == $attributeCodeValue) { // If option available in associated product if (!isset($values[$item->getId() . ':' . $option['value']])) { $values[$itemId . ':' . $option['value']] = ['product_super_attribute_id' => $itemId, 'value_index' => $option['value'], 'label' => $option['label'], 'default_label' => $option['label'], 'store_label' => $option['label'], 'is_percent' => 0, 'pricing_value' => null, 'use_default_value' => true]; } } } } } } foreach ($pricings[0] as $pricing) { // Addding pricing to options $valueKey = $pricing['product_super_attribute_id'] . ':' . $pricing['value_index']; if (isset($values[$valueKey])) { $values[$valueKey]['pricing_value'] = $pricing['pricing_value']; $values[$valueKey]['is_percent'] = $pricing['is_percent']; $values[$valueKey]['value_id'] = $pricing['value_id']; $values[$valueKey]['use_default_value'] = true; } } if ($websiteId && isset($pricings[$websiteId])) { foreach ($pricings[$websiteId] as $pricing) { $valueKey = $pricing['product_super_attribute_id'] . ':' . $pricing['value_index']; if (isset($values[$valueKey])) { $values[$valueKey]['pricing_value'] = $pricing['pricing_value']; $values[$valueKey]['is_percent'] = $pricing['is_percent']; $values[$valueKey]['value_id'] = $pricing['value_id']; $values[$valueKey]['use_default_value'] = false; } } } $this->priceData->setProductPrice($this->getProduct()->getId(), $values); return $values; }
/** * @magentoConfigFixture current_store catalog/price/scope 1 */ public function testIsPriceGlobal() { $this->assertFalse($this->helper->isPriceGlobal()); }
/** * @param \Magento\ImportExport\Model\Resource\Import\Data $importData * @param \Magento\Framework\App\Resource $resource * @param \Magento\ImportExport\Model\Resource\Helper $resourceHelper * @param \Magento\Store\Model\StoreManagerInterface $_storeManager * @param \Magento\Catalog\Model\ProductFactory $productFactory * @param \Magento\Catalog\Model\Resource\Product\Option\CollectionFactory $optionColFactory * @param \Magento\ImportExport\Model\Resource\CollectionByPagesIteratorFactory $colIteratorFactory * @param \Magento\Catalog\Helper\Data $catalogData * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig * @param \Magento\Framework\Stdlib\DateTime $dateTime * @param array $data * * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct(\Magento\ImportExport\Model\Resource\Import\Data $importData, \Magento\Framework\App\Resource $resource, \Magento\ImportExport\Model\Resource\Helper $resourceHelper, \Magento\Store\Model\StoreManagerInterface $_storeManager, \Magento\Catalog\Model\ProductFactory $productFactory, \Magento\Catalog\Model\Resource\Product\Option\CollectionFactory $optionColFactory, \Magento\ImportExport\Model\Resource\CollectionByPagesIteratorFactory $colIteratorFactory, \Magento\Catalog\Helper\Data $catalogData, \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, \Magento\Framework\Stdlib\DateTime $dateTime, array $data = array()) { $this->_resource = $resource; $this->_catalogData = $catalogData; $this->_storeManager = $_storeManager; $this->_productFactory = $productFactory; $this->_dataSourceModel = $importData; $this->_optionColFactory = $optionColFactory; $this->_colIteratorFactory = $colIteratorFactory; $this->_scopeConfig = $scopeConfig; $this->dateTime = $dateTime; if (isset($data['connection'])) { $this->_connection = $data['connection']; } else { $this->_connection = $resource->getConnection('write'); } if (isset($data['resource_helper'])) { $this->_resourceHelper = $data['resource_helper']; } else { $this->_resourceHelper = $resourceHelper; } if (isset($data['is_price_global'])) { $this->_isPriceGlobal = $data['is_price_global']; } else { $this->_isPriceGlobal = $this->_catalogData->isPriceGlobal(); } $this->_initSourceEntities($data)->_initTables($data)->_initStores($data); $this->_initMessageTemplates(); $this->_initProductsSku()->_initOldCustomOptions(); }
/** * Check if used website scope price * * @return string */ public function isUsedWebsitePrice() { $product = $this->_coreRegistry->registry('product'); return !$this->_catalogData->isPriceGlobal() && $product->getStoreId(); }
/** * @param \Magento\ImportExport\Model\ResourceModel\Import\Data $importData * @param ResourceConnection $resource * @param \Magento\ImportExport\Model\ResourceModel\Helper $resourceHelper * @param \Magento\Store\Model\StoreManagerInterface $_storeManager * @param \Magento\Catalog\Model\ProductFactory $productFactory * @param \Magento\Catalog\Model\ResourceModel\Product\Option\CollectionFactory $optionColFactory * @param \Magento\ImportExport\Model\ResourceModel\CollectionByPagesIteratorFactory $colIteratorFactory * @param \Magento\Catalog\Helper\Data $catalogData * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig * @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $dateTime * @param ProcessingErrorAggregatorInterface $errorAggregator * @param array $data * @throws \Magento\Framework\Exception\LocalizedException * * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct(\Magento\ImportExport\Model\ResourceModel\Import\Data $importData, \Magento\Framework\App\ResourceConnection $resource, \Magento\ImportExport\Model\ResourceModel\Helper $resourceHelper, \Magento\Store\Model\StoreManagerInterface $_storeManager, \Magento\Catalog\Model\ProductFactory $productFactory, \Magento\Catalog\Model\ResourceModel\Product\Option\CollectionFactory $optionColFactory, \Magento\ImportExport\Model\ResourceModel\CollectionByPagesIteratorFactory $colIteratorFactory, \Magento\Catalog\Helper\Data $catalogData, \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, \Magento\Framework\Stdlib\DateTime\TimezoneInterface $dateTime, ProcessingErrorAggregatorInterface $errorAggregator, array $data = []) { $this->_resource = $resource; $this->_catalogData = $catalogData; $this->_storeManager = $_storeManager; $this->_productFactory = $productFactory; $this->_dataSourceModel = $importData; $this->_optionColFactory = $optionColFactory; $this->_colIteratorFactory = $colIteratorFactory; $this->_scopeConfig = $scopeConfig; $this->dateTime = $dateTime; if (isset($data['connection'])) { $this->_connection = $data['connection']; } else { $this->_connection = $resource->getConnection(); } if (isset($data['resource_helper'])) { $this->_resourceHelper = $data['resource_helper']; } else { $this->_resourceHelper = $resourceHelper; } if (isset($data['is_price_global'])) { $this->_isPriceGlobal = $data['is_price_global']; } else { $this->_isPriceGlobal = $this->_catalogData->isPriceGlobal(); } /** * TODO: Make metadataPool a direct constructor dependency, and eliminate its setter & getter */ if (isset($data['metadata_pool'])) { $this->metadataPool = $data['metadata_pool']; } $this->errorAggregator = $errorAggregator; $this->_initSourceEntities($data)->_initTables($data)->_initStores($data); $this->_initMessageTemplates(); $this->_initProductsSku()->_initOldCustomOptions(); }