Skip to content

Commit

Permalink
Merge pull request #634 from magento-dragons/MAGETWO-54704
Browse files Browse the repository at this point in the history
MAGETWO-54704: [Backport] [GITHUB] Product prices not scoped to Website
  • Loading branch information
Yaroslav Onischenko authored Nov 30, 2016
2 parents b9c9449 + 95daeec commit 673217a
Show file tree
Hide file tree
Showing 17 changed files with 812 additions and 83 deletions.
74 changes: 74 additions & 0 deletions app/code/Magento/Catalog/Cron/DeleteOutdatedPriceValues.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?php
/**
* Copyright © 2016 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Catalog\Cron;

use Magento\Framework\App\ResourceConnection;
use Magento\Eav\Api\AttributeRepositoryInterface as AttributeRepository;
use Magento\Framework\App\Config\MutableScopeConfigInterface as ScopeConfig;
use Magento\Catalog\Api\Data\ProductAttributeInterface;
use Magento\Store\Model\Store;

/**
* Cron operation is responsible for deleting all product prices on WEBSITE level
* in case 'Catalog Price Scope' configuratoin parameter is set to GLOBAL.
*/
class DeleteOutdatedPriceValues
{
/**
* @var ResourceConnection
*/
private $resource;

/**
* @var AttributeRepository
*/
private $attributeRepository;

/**
* @var ScopeConfig
*/
private $scopeConfig;

/**
* @param ResourceConnection $resource
* @param AttributeRepository $attributeRepository
* @param ScopeConfig $scopeConfig
*/
public function __construct(
ResourceConnection $resource,
AttributeRepository $attributeRepository,
ScopeConfig $scopeConfig
) {
$this->resource = $resource;
$this->attributeRepository = $attributeRepository;
$this->scopeConfig = $scopeConfig;
}

/**
* Delete all price values for non-admin stores if PRICE_SCOPE is global
*
* @return void
*/
public function execute()
{
$priceScope = $this->scopeConfig->getValue(Store::XML_PATH_PRICE_SCOPE);
if ($priceScope == Store::PRICE_SCOPE_GLOBAL) {
/** @var \Magento\Catalog\Model\ResourceModel\Eav\Attribute $priceAttribute */
$priceAttribute = $this->attributeRepository
->get(ProductAttributeInterface::ENTITY_TYPE_CODE, ProductAttributeInterface::CODE_PRICE);
$connection = $this->resource->getConnection();
$conditions = [
$connection->quoteInto('attribute_id = ?', $priceAttribute->getId()),
$connection->quoteInto('store_id != ?', Store::DEFAULT_STORE_ID),
];

$connection->delete(
$priceAttribute->getBackend()->getTable(),
$conditions
);
}
}
}
48 changes: 16 additions & 32 deletions app/code/Magento/Catalog/Model/Product/Attribute/Backend/Price.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/
namespace Magento\Catalog\Model\Product\Attribute\Backend;

use \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface;
use Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface;

/**
* Catalog product price attribute backend model
Expand Down Expand Up @@ -102,43 +102,27 @@ public function setScope($attribute)
}

/**
* After Save Attribute manipulation
* After Save Price Attribute manipulation
* Processes product price attributes if price scoped to website and updates data when:
* * Price changed for non-default store view - will update price for all stores assigned to current website.
* * Price will be changed according to store currency even if price changed in product with default store id.
* * In a case when price was removed for non-default store (use default option checked) the default store price
* * will be used instead
*
* @param \Magento\Catalog\Model\Product $object
* @return $this
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function afterSave($object)
{
$value = $object->getData($this->getAttribute()->getAttributeCode());
/**
* Orig value is only for existing objects
*/
$oridData = $object->getOrigData();
$origValueExist = $oridData && array_key_exists($this->getAttribute()->getAttributeCode(), $oridData);
if ($object->getStoreId() != 0 || !$value || $origValueExist) {
return $this;
}

if ($this->getAttribute()->getIsGlobal() == ScopedAttributeInterface::SCOPE_WEBSITE) {
$baseCurrency = $this->_config->getValue(
\Magento\Directory\Model\Currency::XML_PATH_CURRENCY_BASE,
'default'
);

$storeIds = $object->getStoreIds();
if (is_array($storeIds)) {
foreach ($storeIds as $storeId) {
$storeCurrency = $this->_storeManager->getStore($storeId)->getBaseCurrencyCode();
if ($storeCurrency == $baseCurrency) {
continue;
}
$rate = $this->_currencyFactory->create()->load($baseCurrency)->getRate($storeCurrency);
if (!$rate) {
$rate = 1;
}
$newValue = $value * $rate;
$object->addAttributeUpdate($this->getAttribute()->getAttributeCode(), $newValue, $storeId);
/** @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */
$attribute = $this->getAttribute();
$attributeCode = $attribute->getAttributeCode();
$value = $object->getData($attributeCode);
if ($value && $value != $object->getOrigData($attributeCode)) {
if ($attribute->isScopeWebsite()) {
foreach ((array)$object->getWebsiteStoreIds() as $storeId) {
/** @var $object \Magento\Catalog\Model\Product */
$object->addAttributeUpdate($attributeCode, $value, $storeId);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,6 @@ public function save(\Magento\Catalog\Api\Data\ProductAttributeInterface $attrib
}
$attribute->setDefaultFrontendLabel($frontendLabel);
}
if (!$attribute->getIsUserDefined()) {
// Unset attribute field for system attributes
$attribute->setApplyTo(null);
}
} else {
$attribute->setAttributeId(null);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php
/**
* Copyright © 2016 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Catalog\Observer;

use Magento\Framework\Event\Observer as EventObserver;
use Magento\Framework\Event\ObserverInterface;
use Magento\Catalog\Api\Data\ProductAttributeInterface;
use Magento\Catalog\Api\ProductAttributeRepositoryInterface;
use Magento\Store\Model\Store;
use Magento\Framework\App\Config\ReinitableConfigInterface;
use Magento\Framework\Api\SearchCriteriaBuilder;

/**
* Observer is responsible for changing scope for all price attributes in system
* depending on 'Catalog Price Scope' configuration parameter
*/
class SwitchPriceAttributeScopeOnConfigChange implements ObserverInterface
{
/**
* @var ReinitableConfigInterface
*/
private $config;

/**
* @var ProductAttributeRepositoryInterface
*/
private $productAttributeRepository;

/**
* @var SearchCriteriaBuilder
*/
private $searchCriteriaBuilder;

/**
* @param ReinitableConfigInterface $config
* @param ProductAttributeRepositoryInterface $productAttributeRepository
* @param SearchCriteriaBuilder $searchCriteriaBuilder
*/
public function __construct(
ReinitableConfigInterface $config,
ProductAttributeRepositoryInterface $productAttributeRepository,
SearchCriteriaBuilder $searchCriteriaBuilder
){
$this->config = $config;
$this->productAttributeRepository = $productAttributeRepository;
$this->searchCriteriaBuilder = $searchCriteriaBuilder;
}

/**
* Change scope for all price attributes according to
* 'Catalog Price Scope' configuration parameter value
*
* @param EventObserver $observer
* @return void
*/
public function execute(EventObserver $observer)
{
$this->searchCriteriaBuilder->addFilter('frontend_input', 'price');
$criteria = $this->searchCriteriaBuilder->create();

$scope = $this->config->getValue(Store::XML_PATH_PRICE_SCOPE);
$scope = ($scope == Store::PRICE_SCOPE_WEBSITE)
? ProductAttributeInterface::SCOPE_WEBSITE_TEXT
: ProductAttributeInterface::SCOPE_GLOBAL_TEXT;

$priceAttributes = $this->productAttributeRepository->getList($criteria)->getItems();

/** @var ProductAttributeInterface $priceAttribute */
foreach ($priceAttributes as $priceAttribute) {
$priceAttribute->setScope($scope);
$this->productAttributeRepository->save($priceAttribute);
}
}
}
29 changes: 27 additions & 2 deletions app/code/Magento/Catalog/Setup/UpgradeData.php
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface
}

if (version_compare($context->getVersion(), '2.0.7') < 0) {
/** @var EavSetup $eavSetupF */
/** @var EavSetup $eavSetup */
$eavSetup= $this->eavSetupFactory->create(['setup' => $setup]);

$eavSetup->updateAttribute(
Expand All @@ -351,7 +351,32 @@ public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface
]
);
}


if (version_compare($context->getVersion(), '2.1.3') < 0) {
/** @var \Magento\Catalog\Setup\CategorySetup $categorySetup */
$categorySetup = $this->categorySetupFactory->create(['setup' => $setup]);
$this->changePriceAttributeDefaultScope($categorySetup);
}

$setup->endSetup();
}

/**
* @param \Magento\Catalog\Setup\CategorySetup $categorySetup
* @return void
*/
private function changePriceAttributeDefaultScope($categorySetup)
{
$entityTypeId = $categorySetup->getEntityTypeId(\Magento\Catalog\Model\Product::ENTITY);
foreach (['price', 'cost', 'special_price'] as $attributeCode) {
$attribute = $categorySetup->getAttribute($entityTypeId, $attributeCode);
$categorySetup->updateAttribute(
$entityTypeId,
$attribute['attribute_id'],
'is_global',
\Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL
);

}
}
}
Loading

0 comments on commit 673217a

Please sign in to comment.