diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/StatusBaseSelectProcessor.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/StatusBaseSelectProcessor.php
index 656998113fdb9..b4293a3989585 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Product/StatusBaseSelectProcessor.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/StatusBaseSelectProcessor.php
@@ -11,6 +11,8 @@
use Magento\Eav\Model\Config;
use Magento\Framework\DB\Select;
use Magento\Framework\EntityManager\MetadataPool;
+use Magento\Store\Api\StoreResolverInterface;
+use Magento\Store\Model\Store;
/**
* Class StatusBaseSelectProcessor
@@ -27,16 +29,24 @@ class StatusBaseSelectProcessor implements BaseSelectProcessorInterface
*/
private $metadataPool;
+ /**
+ * @var StoreResolverInterface
+ */
+ private $storeResolver;
+
/**
* @param Config $eavConfig
* @param MetadataPool $metadataPool
+ * @param StoreResolverInterface $storeResolver
*/
public function __construct(
Config $eavConfig,
- MetadataPool $metadataPool
+ MetadataPool $metadataPool,
+ StoreResolverInterface $storeResolver
) {
$this->eavConfig = $eavConfig;
$this->metadataPool = $metadataPool;
+ $this->storeResolver = $storeResolver;
}
/**
@@ -48,13 +58,23 @@ public function process(Select $select)
$linkField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField();
$statusAttribute = $this->eavConfig->getAttribute(Product::ENTITY, ProductInterface::STATUS);
- $select->join(
+ $select->joinLeft(
+ ['status_global_attr' => $statusAttribute->getBackendTable()],
+ "status_global_attr.{$linkField} = " . self::PRODUCT_TABLE_ALIAS . ".{$linkField}"
+ . ' AND status_global_attr.attribute_id = ' . (int)$statusAttribute->getAttributeId()
+ . ' AND status_global_attr.store_id = ' . Store::DEFAULT_STORE_ID,
+ []
+ );
+
+ $select->joinLeft(
['status_attr' => $statusAttribute->getBackendTable()],
- sprintf('status_attr.%s = %s.%1$s', $linkField, self::PRODUCT_TABLE_ALIAS),
+ "status_attr.{$linkField} = " . self::PRODUCT_TABLE_ALIAS . ".{$linkField}"
+ . ' AND status_attr.attribute_id = ' . (int)$statusAttribute->getAttributeId()
+ . ' AND status_attr.store_id = ' . $this->storeResolver->getCurrentStoreId(),
[]
- )
- ->where('status_attr.attribute_id = ?', $statusAttribute->getAttributeId())
- ->where('status_attr.value = ?', Status::STATUS_ENABLED);
+ );
+
+ $select->where('IFNULL(status_attr.value, status_global_attr.value) = ?', Status::STATUS_ENABLED);
return $select;
}
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/StatusBaseSelectProcessorTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/StatusBaseSelectProcessorTest.php
index 0909f754a01c2..1fada997913b6 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/StatusBaseSelectProcessorTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/StatusBaseSelectProcessorTest.php
@@ -16,7 +16,12 @@
use Magento\Framework\EntityManager\EntityMetadataInterface;
use Magento\Framework\EntityManager\MetadataPool;
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+use Magento\Store\Api\StoreResolverInterface;
+use Magento\Store\Model\Store;
+/**
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
class StatusBaseSelectProcessorTest extends \PHPUnit_Framework_TestCase
{
/**
@@ -29,6 +34,11 @@ class StatusBaseSelectProcessorTest extends \PHPUnit_Framework_TestCase
*/
private $metadataPool;
+ /**
+ * @var StoreResolverInterface|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $storeResolver;
+
/**
* @var Select|\PHPUnit_Framework_MockObject_MockObject
*/
@@ -43,11 +53,13 @@ protected function setUp()
{
$this->eavConfig = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock();
$this->metadataPool = $this->getMockBuilder(MetadataPool::class)->disableOriginalConstructor()->getMock();
+ $this->storeResolver = $this->getMockBuilder(StoreResolverInterface::class)->getMock();
$this->select = $this->getMockBuilder(Select::class)->disableOriginalConstructor()->getMock();
$this->statusBaseSelectProcessor = (new ObjectManager($this))->getObject(StatusBaseSelectProcessor::class, [
'eavConfig' => $this->eavConfig,
'metadataPool' => $this->metadataPool,
+ 'storeResolver' => $this->storeResolver,
]);
}
@@ -55,7 +67,8 @@ public function testProcess()
{
$linkField = 'link_field';
$backendTable = 'backend_table';
- $attributeId = 'attribute_id';
+ $attributeId = 2;
+ $currentStoreId = 1;
$metadata = $this->getMock(EntityMetadataInterface::class);
$metadata->expects($this->once())
@@ -66,13 +79,14 @@ public function testProcess()
->with(ProductInterface::class)
->willReturn($metadata);
+ /** @var AttributeInterface|\PHPUnit_Framework_MockObject_MockObject $statusAttribute */
$statusAttribute = $this->getMockBuilder(AttributeInterface::class)
->setMethods(['getBackendTable', 'getAttributeId'])
->getMock();
- $statusAttribute->expects($this->once())
+ $statusAttribute->expects($this->atLeastOnce())
->method('getBackendTable')
->willReturn($backendTable);
- $statusAttribute->expects($this->once())
+ $statusAttribute->expects($this->atLeastOnce())
->method('getAttributeId')
->willReturn($attributeId);
$this->eavConfig->expects($this->once())
@@ -80,21 +94,34 @@ public function testProcess()
->with(Product::ENTITY, ProductInterface::STATUS)
->willReturn($statusAttribute);
- $this->select->expects($this->once())
- ->method('join')
+ $this->storeResolver->expects($this->once())
+ ->method('getCurrentStoreId')
+ ->willReturn($currentStoreId);
+
+ $this->select->expects($this->at(0))
+ ->method('joinLeft')
->with(
- ['status_attr' => $backendTable],
- sprintf('status_attr.%s = %s.%1$s', $linkField, BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS),
+ ['status_global_attr' => $backendTable],
+ "status_global_attr.{$linkField} = "
+ . BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS . ".{$linkField}"
+ . " AND status_global_attr.attribute_id = {$attributeId}"
+ . ' AND status_global_attr.store_id = ' . Store::DEFAULT_STORE_ID,
[]
)
->willReturnSelf();
$this->select->expects($this->at(1))
- ->method('where')
- ->with('status_attr.attribute_id = ?', $attributeId)
+ ->method('joinLeft')
+ ->with(
+ ['status_attr' => $backendTable],
+ "status_attr.{$linkField} = " . BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS . ".{$linkField}"
+ . " AND status_attr.attribute_id = {$attributeId}"
+ . " AND status_attr.store_id = {$currentStoreId}",
+ []
+ )
->willReturnSelf();
$this->select->expects($this->at(2))
->method('where')
- ->with('status_attr.value = ?', Status::STATUS_ENABLED)
+ ->with('IFNULL(status_attr.value, status_global_attr.value) = ?', Status::STATUS_ENABLED)
->willReturnSelf();
$this->assertEquals($this->select, $this->statusBaseSelectProcessor->process($this->select));
diff --git a/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/Configurable.php b/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/Configurable.php
index fbb69798ff94f..ed4863342a967 100644
--- a/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/Configurable.php
+++ b/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/Configurable.php
@@ -9,9 +9,45 @@
use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Catalog\Model\Product\Attribute\Source\Status as ProductStatus;
+use Magento\Catalog\Model\Product\Attribute\Source\Status;
+use Magento\Store\Api\StoreResolverInterface;
+use Magento\Store\Model\Store;
+/**
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
class Configurable extends \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\DefaultPrice
{
+ /**
+ * @var StoreResolverInterface
+ */
+ private $storeResolver;
+
+ /**
+ * Class constructor
+ *
+ * @param \Magento\Framework\Model\ResourceModel\Db\Context $context
+ * @param \Magento\Framework\Indexer\Table\StrategyInterface $tableStrategy
+ * @param \Magento\Eav\Model\Config $eavConfig
+ * @param \Magento\Framework\Event\ManagerInterface $eventManager
+ * @param \Magento\Framework\Module\Manager $moduleManager
+ * @param string $connectionName
+ * @param StoreResolverInterface $storeResolver
+ */
+ public function __construct(
+ \Magento\Framework\Model\ResourceModel\Db\Context $context,
+ \Magento\Framework\Indexer\Table\StrategyInterface $tableStrategy,
+ \Magento\Eav\Model\Config $eavConfig,
+ \Magento\Framework\Event\ManagerInterface $eventManager,
+ \Magento\Framework\Module\Manager $moduleManager,
+ $connectionName = null,
+ StoreResolverInterface $storeResolver = null
+ ) {
+ parent::__construct($context, $tableStrategy, $eavConfig, $eventManager, $moduleManager, $connectionName);
+ $this->storeResolver = $storeResolver ?:
+ \Magento\Framework\App\ObjectManager::getInstance()->get(StoreResolverInterface::class);
+ }
+
/**
* Reindex temporary (price result data) for all products
*
@@ -190,16 +226,21 @@ protected function _applyConfigurableOption()
[]
)->where(
'le.required_options=0'
- )->join(
- ['product_status' => $this->getTable($statusAttribute->getBackend()->getTable())],
- sprintf(
- 'le.%1$s = product_status.%1$s AND product_status.attribute_id = %2$s',
- $linkField,
- $statusAttribute->getAttributeId()
- ),
+ )->joinLeft(
+ ['status_global_attr' => $statusAttribute->getBackendTable()],
+ "status_global_attr.{$linkField} = le.{$linkField}"
+ . ' AND status_global_attr.attribute_id = ' . (int)$statusAttribute->getAttributeId()
+ . ' AND status_global_attr.store_id = ' . Store::DEFAULT_STORE_ID,
+ []
+ )->joinLeft(
+ ['status_attr' => $statusAttribute->getBackendTable()],
+ "status_attr.{$linkField} = le.{$linkField}"
+ . ' AND status_attr.attribute_id = ' . (int)$statusAttribute->getAttributeId()
+ . ' AND status_attr.store_id = ' . $this->storeResolver->getCurrentStoreId(),
[]
)->where(
- 'product_status.value=' . ProductStatus::STATUS_ENABLED
+ 'IFNULL(status_attr.value, status_global_attr.value) = ?',
+ Status::STATUS_ENABLED
)->group(
['e.entity_id', 'i.customer_group_id', 'i.website_id', 'l.product_id']
);
diff --git a/app/code/Magento/Customer/Model/Address/AbstractAddress.php b/app/code/Magento/Customer/Model/Address/AbstractAddress.php
index 7b32da94ddedb..786c5f9770a2e 100644
--- a/app/code/Magento/Customer/Model/Address/AbstractAddress.php
+++ b/app/code/Magento/Customer/Model/Address/AbstractAddress.php
@@ -554,6 +554,8 @@ public function getDataModel($defaultBillingAddressId = null, $defaultShippingAd
/**
* Validate address attribute values
*
+ *
+ *
* @return bool|array
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
@@ -562,23 +564,24 @@ public function validate()
{
$errors = [];
if (!\Zend_Validate::is($this->getFirstname(), 'NotEmpty')) {
- $errors[] = __('Please enter the first name.');
+ $errors[] = __('%fieldName is a required field.', ['fieldName' => 'firstname']);
}
if (!\Zend_Validate::is($this->getLastname(), 'NotEmpty')) {
- $errors[] = __('Please enter the last name.');
+ $errors[] = __('%fieldName is a required field.', ['fieldName' => 'lastname']);
}
if (!\Zend_Validate::is($this->getStreetLine(1), 'NotEmpty')) {
- $errors[] = __('Please enter the street.');
+ $errors[] = __('%fieldName is a required field.', ['fieldName' => 'street']);
}
if (!\Zend_Validate::is($this->getCity(), 'NotEmpty')) {
- $errors[] = __('Please enter the city.');
+ $errors[] = __('%fieldName is a required field.', ['fieldName' => 'city']);
}
if (!\Zend_Validate::is($this->getTelephone(), 'NotEmpty')) {
- $errors[] = __('Please enter the phone number.');
+ $errors[] = __('%fieldName is a required field.', ['fieldName' => 'telephone']);
+
}
$_havingOptionalZip = $this->_directoryData->getCountriesWithOptionalZip();
@@ -590,11 +593,11 @@ public function validate()
'NotEmpty'
)
) {
- $errors[] = __('Please enter the zip/postal code.');
+ $errors[] = __('%fieldName is a required field.', ['fieldName' => 'postcode']);
}
if (!\Zend_Validate::is($this->getCountryId(), 'NotEmpty')) {
- $errors[] = __('Please enter the country.');
+ $errors[] = __('%fieldName is a required field.', ['fieldName' => 'countryId']);
}
if ($this->getCountryModel()->getRegionCollection()->getSize() && !\Zend_Validate::is(
@@ -604,7 +607,7 @@ public function validate()
$this->getCountryId()
)
) {
- $errors[] = __('Please enter the state/province.');
+ $errors[] = __('%fieldName is a required field.', ['fieldName' => 'regionId']);
}
if (empty($errors) || $this->getShouldIgnoreValidation()) {
diff --git a/app/code/Magento/Customer/Model/ResourceModel/AddressRepository.php b/app/code/Magento/Customer/Model/ResourceModel/AddressRepository.php
index 67d4ea32369ba..24df57e07e848 100644
--- a/app/code/Magento/Customer/Model/ResourceModel/AddressRepository.php
+++ b/app/code/Magento/Customer/Model/ResourceModel/AddressRepository.php
@@ -124,8 +124,12 @@ public function save(\Magento\Customer\Api\Data\AddressInterface $address)
$addressModel->updateData($address);
}
- $inputException = $this->_validate($addressModel);
- if ($inputException->wasErrorAdded()) {
+ $errors = $addressModel->validate();
+ if ($errors !== true) {
+ $inputException = new InputException();
+ foreach ($errors as $error) {
+ $inputException->addError($error);
+ }
throw $inputException;
}
$addressModel->save();
@@ -255,70 +259,6 @@ public function deleteById($addressId)
return true;
}
- /**
- * Validate Customer Addresses attribute values.
- *
- * @param CustomerAddressModel $customerAddressModel the model to validate
- * @return InputException
- *
- * @SuppressWarnings(PHPMD.NPathComplexity)
- * @SuppressWarnings(PHPMD.CyclomaticComplexity)
- */
- private function _validate(CustomerAddressModel $customerAddressModel)
- {
- $exception = new InputException();
- if ($customerAddressModel->getShouldIgnoreValidation()) {
- return $exception;
- }
-
- if (!\Zend_Validate::is($customerAddressModel->getFirstname(), 'NotEmpty')) {
- $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'firstname']));
- }
-
- if (!\Zend_Validate::is($customerAddressModel->getLastname(), 'NotEmpty')) {
- $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'lastname']));
- }
-
- if (!\Zend_Validate::is($customerAddressModel->getStreetLine(1), 'NotEmpty')) {
- $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'street']));
- }
-
- if (!\Zend_Validate::is($customerAddressModel->getCity(), 'NotEmpty')) {
- $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'city']));
- }
-
- if (!\Zend_Validate::is($customerAddressModel->getTelephone(), 'NotEmpty')) {
- $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'telephone']));
- }
-
- $havingOptionalZip = $this->directoryData->getCountriesWithOptionalZip();
- if (!in_array($customerAddressModel->getCountryId(), $havingOptionalZip)
- && !\Zend_Validate::is($customerAddressModel->getPostcode(), 'NotEmpty')
- ) {
- $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'postcode']));
- }
-
- if (!\Zend_Validate::is($customerAddressModel->getCountryId(), 'NotEmpty')) {
- $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'countryId']));
- }
-
- if ($this->directoryData->isRegionRequired($customerAddressModel->getCountryId())) {
- $regionCollection = $customerAddressModel->getCountryModel()->getRegionCollection();
- if (!$regionCollection->count() && empty($customerAddressModel->getRegion())) {
- $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'region']));
- } elseif (
- $regionCollection->count()
- && !in_array(
- $customerAddressModel->getRegionId(),
- array_column($regionCollection->getData(), 'region_id')
- )
- ) {
- $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'regionId']));
- }
- }
- return $exception;
- }
-
/**
* Retrieve collection processor
*
diff --git a/app/code/Magento/Customer/Test/Unit/Model/Address/AbstractAddressTest.php b/app/code/Magento/Customer/Test/Unit/Model/Address/AbstractAddressTest.php
index 32112ccdeb1ae..ba833221aba18 100644
--- a/app/code/Magento/Customer/Test/Unit/Model/Address/AbstractAddressTest.php
+++ b/app/code/Magento/Customer/Test/Unit/Model/Address/AbstractAddressTest.php
@@ -336,31 +336,31 @@ public function validateDataProvider()
return [
'firstname' => [
array_merge(array_diff_key($data, ['firstname' => '']), ['country_id' => $countryId++]),
- ['Please enter the first name.'],
+ ['firstname is a required field.'],
],
'lastname' => [
array_merge(array_diff_key($data, ['lastname' => '']), ['country_id' => $countryId++]),
- ['Please enter the last name.'],
+ ['lastname is a required field.'],
],
'street' => [
array_merge(array_diff_key($data, ['street' => '']), ['country_id' => $countryId++]),
- ['Please enter the street.'],
+ ['street is a required field.'],
],
'city' => [
array_merge(array_diff_key($data, ['city' => '']), ['country_id' => $countryId++]),
- ['Please enter the city.'],
+ ['city is a required field.'],
],
'telephone' => [
array_merge(array_diff_key($data, ['telephone' => '']), ['country_id' => $countryId++]),
- ['Please enter the phone number.'],
+ ['telephone is a required field.'],
],
'postcode' => [
array_merge(array_diff_key($data, ['postcode' => '']), ['country_id' => $countryId++]),
- ['Please enter the zip/postal code.'],
+ ['postcode is a required field.'],
],
'country_id' => [
array_diff_key($data, ['country_id' => '']),
- ['Please enter the country.'],
+ ['countryId is a required field.'],
],
'validated' => [array_merge($data, ['country_id' => $countryId++]), true],
];
diff --git a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/AddressRepositoryTest.php b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/AddressRepositoryTest.php
index b72a5f6a417d4..5f6bc315acd16 100644
--- a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/AddressRepositoryTest.php
+++ b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/AddressRepositoryTest.php
@@ -128,6 +128,7 @@ protected function setUp()
'setCustomer',
'getCountryModel',
'getShouldIgnoreValidation',
+ 'validate',
'save',
'getDataModel',
'getCustomerId',
@@ -191,6 +192,9 @@ public function testSave()
$this->address->expects($this->once())
->method('setCustomer')
->with($this->customer);
+ $this->address->expects($this->once())
+ ->method('validate')
+ ->willReturn(true);
$this->address->expects($this->once())
->method('save');
$this->addressRegistry->expects($this->once())
@@ -208,9 +212,6 @@ public function testSave()
$this->address->expects($this->once())
->method('getDataModel')
->willReturn($customerAddress);
- $this->address->expects($this->once())
- ->method('getShouldIgnoreValidation')
- ->willReturn(true);
$this->repository->save($customerAddress);
}
@@ -222,6 +223,7 @@ public function testSaveWithException()
{
$customerId = 34;
$addressId = 53;
+ $errors[] = __('Please enter the state/province.');
$customerAddress = $this->getMockForAbstractClass(
\Magento\Customer\Api\Data\AddressInterface::class,
[],
@@ -245,7 +247,9 @@ public function testSaveWithException()
$this->address->expects($this->once())
->method('updateData')
->with($customerAddress);
- $this->prepareMocksForInvalidAddressValidation();
+ $this->address->expects($this->once())
+ ->method('validate')
+ ->willReturn($errors);
$this->repository->save($customerAddress);
}
@@ -258,6 +262,7 @@ public function testSaveWithInvalidRegion()
{
$customerId = 34;
$addressId = 53;
+ $errors[] = __('region is a required field.');
$customerAddress = $this->getMockForAbstractClass(
\Magento\Customer\Api\Data\AddressInterface::class,
[],
@@ -281,60 +286,13 @@ public function testSaveWithInvalidRegion()
$this->address->expects($this->once())
->method('updateData')
->with($customerAddress);
- $countryModel = $this->getMock(\Magento\Directory\Model\Country::class, [], [], '', false);
- $regionCollection = $this->getMock(
- \Magento\Directory\Model\ResourceModel\Region\Collection::class,
- [],
- [],
- '',
- false
- );
- $this->address->expects($this->once())
- ->method('getShouldIgnoreValidation')
- ->willReturn(false);
- $this->address->expects($this->atLeastOnce())
- ->method('getCountryId')
- ->willReturn(1);
- $this->address->expects($this->once())
- ->method('getFirstname')
- ->willReturn('firstname');
- $this->address->expects($this->once())
- ->method('getLastname')
- ->willReturn('lastname');
- $this->address->expects($this->once())
- ->method('getStreetLine')
- ->with(1)
- ->willReturn('street line');
- $this->address->expects($this->once())
- ->method('getCity')
- ->willReturn('city');
- $this->address->expects($this->once())
- ->method('getTelephone')
- ->willReturn('23423423423');
$this->address->expects($this->never())
->method('getRegionId')
->willReturn(null);
-
- $this->directoryData->expects($this->once())
- ->method('getCountriesWithOptionalZip')
- ->willReturn([1]);
- $this->address->expects($this->once())
- ->method('getCountryModel')
- ->willReturn($countryModel);
- $countryModel->expects($this->once())
- ->method('getRegionCollection')
- ->willReturn($regionCollection);
- $regionCollection->expects($this->once())
- ->method('count')
- ->willReturn(0);
- $this->directoryData->expects($this->once())
- ->method('isRegionRequired')
- ->with(1)
- ->willReturn(true);
$this->address->expects($this->once())
- ->method('getRegion')
- ->willReturn('');
+ ->method('validate')
+ ->willReturn($errors);
$this->repository->save($customerAddress);
}
@@ -347,6 +305,7 @@ public function testSaveWithInvalidRegionId()
{
$customerId = 34;
$addressId = 53;
+ $errors[] = __('regionId is a required field.');
$customerAddress = $this->getMockForAbstractClass(
\Magento\Customer\Api\Data\AddressInterface::class,
[],
@@ -370,114 +329,14 @@ public function testSaveWithInvalidRegionId()
$this->address->expects($this->once())
->method('updateData')
->with($customerAddress);
- $countryModel = $this->getMock(\Magento\Directory\Model\Country::class, [], [], '', false);
- $regionCollection = $this->getMock(
- \Magento\Directory\Model\ResourceModel\Region\Collection::class,
- [],
- [],
- '',
- false
- );
-
- $this->address->expects($this->once())
- ->method('getShouldIgnoreValidation')
- ->willReturn(false);
- $this->address->expects($this->atLeastOnce())
- ->method('getCountryId')
- ->willReturn(1);
- $this->address->expects($this->once())
- ->method('getFirstname')
- ->willReturn('firstname');
- $this->address->expects($this->once())
- ->method('getLastname')
- ->willReturn('lastname');
- $this->address->expects($this->once())
- ->method('getStreetLine')
- ->with(1)
- ->willReturn('street line');
- $this->address->expects($this->once())
- ->method('getCity')
- ->willReturn('city');
- $this->address->expects($this->once())
- ->method('getTelephone')
- ->willReturn('23423423423');
- $this->address->expects($this->once())
- ->method('getRegionId')
- ->willReturn(2);
-
- $this->directoryData->expects($this->once())
- ->method('getCountriesWithOptionalZip')
- ->willReturn([1]);
- $this->address->expects($this->once())
- ->method('getCountryModel')
- ->willReturn($countryModel);
- $countryModel->expects($this->once())
- ->method('getRegionCollection')
- ->willReturn($regionCollection);
- $regionCollection->expects($this->atLeastOnce())
- ->method('count')
- ->willReturn(2);
- $regionCollection->expects($this->once())
- ->method('getData')
- ->willReturn([5, 6, 7, 8, 9]);
- $this->directoryData->expects($this->once())
- ->method('isRegionRequired')
- ->with(1)
- ->willReturn(true);
$this->address->expects($this->never())
->method('getRegion')
->willReturn('');
-
- $this->repository->save($customerAddress);
- }
-
- protected function prepareMocksForInvalidAddressValidation()
- {
- $countryModel = $this->getMock(\Magento\Directory\Model\Country::class, [], [], '', false);
- $regionCollection = $this->getMock(
- \Magento\Directory\Model\ResourceModel\Region\Collection::class,
- [],
- [],
- '',
- false
- );
-
- $this->address->expects($this->once())
- ->method('getShouldIgnoreValidation')
- ->willReturn(false);
- $this->address->expects($this->atLeastOnce())
- ->method('getCountryId');
- $this->address->expects($this->once())
- ->method('getFirstname');
- $this->address->expects($this->once())
- ->method('getLastname');
- $this->address->expects($this->once())
- ->method('getStreetLine')
- ->with(1);
$this->address->expects($this->once())
- ->method('getCity');
- $this->address->expects($this->once())
- ->method('getTelephone');
- $this->address->expects($this->never())
- ->method('getRegionId')
- ->willReturn(null);
+ ->method('validate')
+ ->willReturn($errors);
- $this->directoryData->expects($this->once())
- ->method('getCountriesWithOptionalZip')
- ->willReturn([]);
- $this->address->expects($this->once())
- ->method('getCountryModel')
- ->willReturn($countryModel);
- $countryModel->expects($this->once())
- ->method('getRegionCollection')
- ->willReturn($regionCollection);
- $regionCollection->expects($this->once())
- ->method('count')
- ->willReturn(0);
- $this->directoryData->expects($this->once())
- ->method('isRegionRequired')
- ->with(null)
- ->willReturn(true);
+ $this->repository->save($customerAddress);
}
public function testGetById()
diff --git a/app/code/Magento/Review/etc/di.xml b/app/code/Magento/Review/etc/di.xml
index d42d3e3330c67..13f7d0b84bc50 100644
--- a/app/code/Magento/Review/etc/di.xml
+++ b/app/code/Magento/Review/etc/di.xml
@@ -26,4 +26,9 @@
Magento\Framework\Url
+
+
+ Magento\Customer\Model\Session\Proxy
+
+
diff --git a/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js b/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js
index c1d2fd3f91051..cd9794dc1757d 100644
--- a/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js
+++ b/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js
@@ -259,6 +259,9 @@ define([
// whether swatches are rendered in product list or on product page
inProductList: false,
+ // sly-old-price block selector
+ slyOldPriceSelector: '.sly-old-price',
+
// tier prise selectors start
tierPriceTemplateSelector: '#tier-prices-template',
tierPriceBlockSelector: '[data-role="tier-price-block"]',
@@ -837,6 +840,12 @@ define([
}
);
+ if (result.oldPrice.amount !== result.finalPrice.amount) {
+ $(this.options.slyOldPriceSelector).show();
+ } else {
+ $(this.options.slyOldPriceSelector).hide();
+ }
+
if (result.tierPrices.length) {
if (this.options.tierPriceTemplate) {
tierPriceHtml = mageTemplate(
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/CustomAttribute.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/CustomAttribute.php
index 53fe49b759c64..3c324de0cabab 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/CustomAttribute.php
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/CustomAttribute.php
@@ -102,7 +102,7 @@ private function getElementByClass($class)
{
$element = null;
foreach (array_keys($this->classReferences) as $key) {
- if (strpos($class, $key) !== false) {
+ if ($class == $key) {
return $this->classReferences[$class];
}
}
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/di.xml
index 82a7c263b1ca9..fee6efedff2e2 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/di.xml
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/di.xml
@@ -167,7 +167,7 @@
- [name="product[%code%]"]
- null
- -
+
-
- [name="product[%code%]"]
- datepicker
diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/ConfigurableTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/ConfigurableTest.php
index 5db97cc366149..2e339e4347cf6 100644
--- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/ConfigurableTest.php
+++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/ConfigurableTest.php
@@ -67,4 +67,40 @@ public function testGetProductFinalPriceIfOneOfChildIsDisabled()
->getFirstItem();
$this->assertEquals(20, $configurableProduct->getMinimalPrice());
}
+
+ /**
+ * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable.php
+ */
+ public function testGetProductFinalPriceIfOneOfChildIsDisabledPerStore()
+ {
+ /** @var Collection $collection */
+ $collection = Bootstrap::getObjectManager()->get(CollectionFactory::class)
+ ->create();
+ $configurableProduct = $collection
+ ->addIdFilter([1])
+ ->addMinimalPrice()
+ ->load()
+ ->getFirstItem();
+ $this->assertEquals(10, $configurableProduct->getMinimalPrice());
+
+ $childProduct = $this->productRepository->getById(10, false, null, true);
+ $childProduct->setStatus(Status::STATUS_DISABLED);
+
+ // update in default store scope
+ $currentStoreId = $this->storeManager->getStore()->getId();
+ $defaultStore = $this->storeManager->getDefaultStoreView();
+ $this->storeManager->setCurrentStore($defaultStore->getId());
+ $this->productRepository->save($childProduct);
+ $this->storeManager->setCurrentStore($currentStoreId);
+
+ /** @var Collection $collection */
+ $collection = Bootstrap::getObjectManager()->get(CollectionFactory::class)
+ ->create();
+ $configurableProduct = $collection
+ ->addIdFilter([1])
+ ->addMinimalPrice()
+ ->load()
+ ->getFirstItem();
+ $this->assertEquals(20, $configurableProduct->getMinimalPrice());
+ }
}
diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Pricing/Price/LowestPriceOptionProviderTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Pricing/Price/LowestPriceOptionProviderTest.php
index 50787c7962412..58df9f50f7f0c 100644
--- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Pricing/Price/LowestPriceOptionProviderTest.php
+++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Pricing/Price/LowestPriceOptionProviderTest.php
@@ -68,6 +68,38 @@ public function testGetProductsIfOneOfChildIsDisabled()
$this->assertEquals(20, $lowestPriceChildrenProduct->getPrice());
}
+ /**
+ * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable.php
+ */
+ public function testGetProductsIfOneOfChildIsDisabledPerStore()
+ {
+ $configurableProduct = $this->productRepository->getById(1, false, null, true);
+ $lowestPriceChildrenProducts = $this->lowestPriceOptionsProvider->getProducts($configurableProduct);
+ $this->assertCount(1, $lowestPriceChildrenProducts);
+ $lowestPriceChildrenProduct = reset($lowestPriceChildrenProducts);
+ $this->assertEquals(10, $lowestPriceChildrenProduct->getPrice());
+
+ // load full aggregation root
+ $lowestPriceChildProduct = $this->productRepository->get(
+ $lowestPriceChildrenProduct->getSku(),
+ false,
+ null,
+ true
+ );
+ $lowestPriceChildProduct->setStatus(Status::STATUS_DISABLED);
+ // update in default store scope
+ $currentStoreId = $this->storeManager->getStore()->getId();
+ $defaultStore = $this->storeManager->getDefaultStoreView();
+ $this->storeManager->setCurrentStore($defaultStore->getId());
+ $this->productRepository->save($lowestPriceChildProduct);
+ $this->storeManager->setCurrentStore($currentStoreId);
+
+ $lowestPriceChildrenProducts = $this->lowestPriceOptionsProvider->getProducts($configurableProduct);
+ $this->assertCount(1, $lowestPriceChildrenProducts);
+ $lowestPriceChildrenProduct = reset($lowestPriceChildrenProducts);
+ $this->assertEquals(20, $lowestPriceChildrenProduct->getPrice());
+ }
+
/**
* @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable.php
*/