diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product.php b/app/code/Magento/Catalog/Model/ResourceModel/Product.php
index b72bd8c441588..c950b49348dc3 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Product.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product.php
@@ -656,11 +656,7 @@ public function getProductsIdsBySkus(array $productSkuList)
*/
private function getResultKey(string $sku, array $productSkuList): string
{
- $key = array_search(strtolower($sku), array_map('strtolower', $productSkuList));
- if ($key !== false) {
- $sku = $productSkuList[$key];
- }
- return $sku;
+ return in_array(strtolower($sku), array_map('strtolower', $productSkuList)) ? $sku : '';
}
/**
diff --git a/app/code/Magento/CatalogGraphQl/DataProvider/Product/SearchCriteriaBuilder.php b/app/code/Magento/CatalogGraphQl/DataProvider/Product/SearchCriteriaBuilder.php
index d4e049aedd9c2..d67a50875b81d 100644
--- a/app/code/Magento/CatalogGraphQl/DataProvider/Product/SearchCriteriaBuilder.php
+++ b/app/code/Magento/CatalogGraphQl/DataProvider/Product/SearchCriteriaBuilder.php
@@ -8,18 +8,23 @@
namespace Magento\CatalogGraphQl\DataProvider\Product;
use Magento\Catalog\Api\Data\EavAttributeInterface;
+use Magento\Catalog\Model\Product;
+use Magento\Catalog\Model\Product\Visibility;
+use Magento\Eav\Model\Config;
use Magento\Framework\Api\FilterBuilder;
use Magento\Framework\Api\Search\FilterGroupBuilder;
use Magento\Framework\Api\Search\SearchCriteriaInterface;
use Magento\Framework\Api\SortOrder;
+use Magento\Framework\Api\SortOrderBuilder;
use Magento\Framework\App\Config\ScopeConfigInterface;
+use Magento\Framework\App\ObjectManager;
use Magento\Framework\GraphQl\Query\Resolver\Argument\SearchCriteria\Builder;
-use Magento\Catalog\Model\Product\Visibility;
-use Magento\Framework\Api\SortOrderBuilder;
/**
* Build search criteria
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
+
class SearchCriteriaBuilder
{
/**
@@ -51,6 +56,11 @@ class SearchCriteriaBuilder
*/
private $sortOrderBuilder;
+ /**
+ * @var Config
+ */
+ private Config $eavConfig;
+
/**
* @param Builder $builder
* @param ScopeConfigInterface $scopeConfig
@@ -58,6 +68,7 @@ class SearchCriteriaBuilder
* @param FilterGroupBuilder $filterGroupBuilder
* @param Visibility $visibility
* @param SortOrderBuilder $sortOrderBuilder
+ * @param Config $eavConfig
*/
public function __construct(
Builder $builder,
@@ -65,14 +76,16 @@ public function __construct(
FilterBuilder $filterBuilder,
FilterGroupBuilder $filterGroupBuilder,
Visibility $visibility,
- SortOrderBuilder $sortOrderBuilder
+ SortOrderBuilder $sortOrderBuilder = null,
+ Config $eavConfig = null
) {
$this->scopeConfig = $scopeConfig;
$this->filterBuilder = $filterBuilder;
$this->filterGroupBuilder = $filterGroupBuilder;
$this->builder = $builder;
$this->visibility = $visibility;
- $this->sortOrderBuilder = $sortOrderBuilder;
+ $this->sortOrderBuilder = $sortOrderBuilder ?? ObjectManager::getInstance()->get(SortOrderBuilder::class);
+ $this->eavConfig = $eavConfig ?? ObjectManager::getInstance()->get(Config::class);
}
/**
@@ -87,9 +100,13 @@ public function build(array $args, bool $includeAggregation): SearchCriteriaInte
$searchCriteria = $this->builder->build('products', $args);
$isSearch = !empty($args['search']);
$this->updateRangeFilters($searchCriteria);
-
if ($includeAggregation) {
- $this->preparePriceAggregation($searchCriteria);
+ $attributeData = $this->eavConfig->getAttribute(Product::ENTITY, 'price');
+ $priceOptions = $attributeData->getData();
+
+ if ($priceOptions['is_filterable'] != 0) {
+ $this->preparePriceAggregation($searchCriteria);
+ }
$requestName = 'graphql_product_search_with_aggregation';
} else {
$requestName = 'graphql_product_search';
@@ -142,7 +159,7 @@ private function addEntityIdSort(SearchCriteriaInterface $searchCriteria): void
{
$sortOrderArray = $searchCriteria->getSortOrders();
$sortDir = SortOrder::SORT_DESC;
- if (count($sortOrderArray) > 0) {
+ if (is_array($sortOrderArray) && count($sortOrderArray) > 0) {
$sortOrder = end($sortOrderArray);
// in the case the last sort order is by position, sort IDs in descendent order
$sortDir = $sortOrder->getField() === EavAttributeInterface::POSITION
diff --git a/app/code/Magento/CatalogGraphQl/Test/Unit/DataProvider/Product/SearchCriteriaBuilderTest.php b/app/code/Magento/CatalogGraphQl/Test/Unit/DataProvider/Product/SearchCriteriaBuilderTest.php
new file mode 100644
index 0000000000000..59970335d3d10
--- /dev/null
+++ b/app/code/Magento/CatalogGraphQl/Test/Unit/DataProvider/Product/SearchCriteriaBuilderTest.php
@@ -0,0 +1,152 @@
+builder = $this->createMock(Builder::class);
+ $this->scopeConfig = $this->createMock(ScopeConfigInterface::class);
+ $this->filterBuilder = $this->createMock(FilterBuilder::class);
+ $this->filterGroupBuilder = $this->createMock(FilterGroupBuilder::class);
+ $this->sortOrderBuilder = $this->createMock(SortOrderBuilder::class);
+ $this->visibility = $this->createMock(Visibility::class);
+ $this->eavConfig = $this->createMock(Config::class);
+ $this->model = new SearchCriteriaBuilder(
+ $this->builder,
+ $this->scopeConfig,
+ $this->filterBuilder,
+ $this->filterGroupBuilder,
+ $this->visibility,
+ $this->sortOrderBuilder,
+ $this->eavConfig
+ );
+ }
+
+ public function testBuild(): void
+ {
+ $args = ['search' => '', 'pageSize' => 20, 'currentPage' => 1];
+
+ $filter = $this->createMock(Filter::class);
+
+ $searchCriteria = $this->getMockBuilder(SearchCriteriaInterface::class)
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
+ $attributeInterface = $this->getMockBuilder(Attribute::class)
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
+
+ $attributeInterface->setData(['is_filterable' => 0]);
+
+ $this->builder->expects($this->any())
+ ->method('build')
+ ->with('products', $args)
+ ->willReturn($searchCriteria);
+ $searchCriteria->expects($this->any())->method('getFilterGroups')->willReturn([]);
+ $this->eavConfig->expects($this->any())
+ ->method('getAttribute')
+ ->with(Product::ENTITY, 'price')
+ ->willReturn($attributeInterface);
+
+ $this->sortOrderBuilder->expects($this->once())
+ ->method('setField')
+ ->with('_id')
+ ->willReturnSelf();
+ $this->sortOrderBuilder->expects($this->once())
+ ->method('setDirection')
+ ->with('DESC')
+ ->willReturnSelf();
+ $this->sortOrderBuilder->expects($this->any())
+ ->method('create')
+ ->willReturn([]);
+
+ $this->filterBuilder->expects($this->once())
+ ->method('setField')
+ ->with('visibility')
+ ->willReturnSelf();
+ $this->filterBuilder->expects($this->once())
+ ->method('setValue')
+ ->with("")
+ ->willReturnSelf();
+ $this->filterBuilder->expects($this->once())
+ ->method('setConditionType')
+ ->with('in')
+ ->willReturnSelf();
+
+ $this->filterBuilder->expects($this->once())->method('create')->willReturn($filter);
+
+ $this->filterGroupBuilder->expects($this->any())
+ ->method('addFilter')
+ ->with($filter)
+ ->willReturnSelf();
+
+ $this->model->build($args, true);
+ }
+}
diff --git a/app/code/Magento/CatalogInventory/Test/Fixture/SourceItem.php b/app/code/Magento/CatalogInventory/Test/Fixture/SourceItem.php
new file mode 100644
index 0000000000000..68a887c580860
--- /dev/null
+++ b/app/code/Magento/CatalogInventory/Test/Fixture/SourceItem.php
@@ -0,0 +1,90 @@
+ 'SKU-%uniqid%',
+ 'source_code' => 'Source%uniqid%',
+ 'quantity' => 5,
+ 'status' => SourceItemInterface::STATUS_IN_STOCK,
+ ];
+
+ /**
+ * @var ServiceFactory
+ */
+ private ServiceFactory $serviceFactory;
+
+ /**
+ * @var ProcessorInterface
+ */
+ private ProcessorInterface $dataProcessor;
+
+ /**
+ * @var DataMerger
+ */
+ private DataMerger $dataMerger;
+
+ /**
+ * @param ServiceFactory $serviceFactory
+ * @param ProcessorInterface $dataProcessor
+ * @param DataMerger $dataMerger
+ */
+ public function __construct(
+ ServiceFactory $serviceFactory,
+ ProcessorInterface $dataProcessor,
+ DataMerger $dataMerger
+ ) {
+ $this->serviceFactory = $serviceFactory;
+ $this->dataProcessor = $dataProcessor;
+ $this->dataMerger = $dataMerger;
+ }
+
+ /**
+ * @param array $data
+ * @return DataObject|null
+ */
+ public function apply(array $data = []): ?DataObject
+ {
+ $service = $this->serviceFactory->create(SourceItemsSaveInterface::class, 'execute');
+
+ return $service->execute(['sourceItems' => [$this->prepareData($data)]]);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function revert(DataObject $data): void
+ {
+ $service = $this->serviceFactory->create(SourceItemsDeleteInterface::class, 'execute');
+ $service->execute(['sourceItems' => [$this->prepareData($data->getData())]]);
+ }
+
+ /**
+ * Prepare product data
+ *
+ * @param array $data
+ * @return array
+ */
+ private function prepareData(array $data): array
+ {
+ $data = $this->dataMerger->merge(self::DEFAULT_DATA, $data, false);
+
+ return $this->dataProcessor->process($this, $data);
+ }
+}
diff --git a/app/code/Magento/CatalogUrlRewrite/Model/Products/AdaptUrlRewritesToVisibilityAttribute.php b/app/code/Magento/CatalogUrlRewrite/Model/Products/AdaptUrlRewritesToVisibilityAttribute.php
index d329bdf0200a4..629fedde8caa1 100644
--- a/app/code/Magento/CatalogUrlRewrite/Model/Products/AdaptUrlRewritesToVisibilityAttribute.php
+++ b/app/code/Magento/CatalogUrlRewrite/Model/Products/AdaptUrlRewritesToVisibilityAttribute.php
@@ -79,6 +79,7 @@ public function execute(array $productIds, int $visibility, int $storeId): void
[
UrlRewrite::ENTITY_ID => $product->getId(),
UrlRewrite::ENTITY_TYPE => ProductUrlRewriteGenerator::ENTITY_TYPE,
+ UrlRewrite::STORE_ID => $storeId,
]
);
} elseif ($visibility !== Visibility::VISIBILITY_NOT_VISIBLE) {
diff --git a/app/code/Magento/OfflineShipping/Model/Carrier/Tablerate.php b/app/code/Magento/OfflineShipping/Model/Carrier/Tablerate.php
index b4351e6c5727d..e7a6203d8d15b 100644
--- a/app/code/Magento/OfflineShipping/Model/Carrier/Tablerate.php
+++ b/app/code/Magento/OfflineShipping/Model/Carrier/Tablerate.php
@@ -111,6 +111,9 @@ public function collectRates(RateRequest $request)
}
} elseif ($item->getProduct()->isVirtual()) {
$request->setPackageValue($request->getPackageValue() - $item->getBaseRowTotal());
+ $request->setPackageValueWithDiscount(
+ $request->getPackageValueWithDiscount() - $item->getBaseRowTotal()
+ );
}
}
}
@@ -133,8 +136,7 @@ public function collectRates(RateRequest $request)
$freeQty += $item->getQty() * ($child->getQty() - $freeShipping);
}
}
- } elseif (
- ($item->getFreeShipping() || $item->getAddress()->getFreeShipping()) &&
+ } elseif (($item->getFreeShipping() || $item->getAddress()->getFreeShipping()) &&
($item->getFreeShippingMethod() == null || $item->getFreeShippingMethod() &&
$item->getFreeShippingMethod() == 'tablerate_bestway')
) {
diff --git a/app/code/Magento/Quote/Model/Quote/Address/Total/Shipping.php b/app/code/Magento/Quote/Model/Quote/Address/Total/Shipping.php
index aef9fb04c19ae..64725d8d40a1c 100644
--- a/app/code/Magento/Quote/Model/Quote/Address/Total/Shipping.php
+++ b/app/code/Magento/Quote/Model/Quote/Address/Total/Shipping.php
@@ -73,7 +73,7 @@ public function collect(
$address->setFreeMethodWeight($data['freeMethodWeight']);
$isFreeShipping = $this->freeShipping->isFreeShipping($quote, $shippingAssignment->getItems());
- $address->setFreeShipping($isFreeShipping);
+ $address->setFreeShipping((int)$isFreeShipping);
// recalculate weights
$data = $this->getAssignmentWeightData($address, $shippingAssignment->getItems());
$address->setItemQty($data['addressQty']);
diff --git a/app/code/Magento/Quote/Test/Unit/Model/Quote/Address/Total/ShippingTest.php b/app/code/Magento/Quote/Test/Unit/Model/Quote/Address/Total/ShippingTest.php
index d889240de5b02..495a19c97b3ef 100644
--- a/app/code/Magento/Quote/Test/Unit/Model/Quote/Address/Total/ShippingTest.php
+++ b/app/code/Magento/Quote/Test/Unit/Model/Quote/Address/Total/ShippingTest.php
@@ -209,11 +209,16 @@ public function testCollect(): void
$this->shippingAssignment->expects($this->atLeastOnce())
->method('getItems')
->willReturn([$this->cartItem]);
- $this->freeShipping->method('isFreeShipping')
+ $isFreeShipping = true;
+ $this->freeShipping
+ ->expects($this->once())
+ ->method('isFreeShipping')
->with($this->quote, [$this->cartItem])
- ->willReturn(true);
- $this->address->method('setFreeShipping')
- ->with(true);
+ ->willReturn($isFreeShipping);
+ $this->address
+ ->expects($this->once())
+ ->method('setFreeShipping')
+ ->with((int)$isFreeShipping);
$this->total->expects($this->atLeastOnce())
->method('setTotalAmount');
$this->total->expects($this->atLeastOnce())
diff --git a/app/code/Magento/Sales/Test/Unit/Ui/Component/Listing/Column/PriceTest.php b/app/code/Magento/Sales/Test/Unit/Ui/Component/Listing/Column/PriceTest.php
index 449ab230b568d..c2639c8bb5664 100644
--- a/app/code/Magento/Sales/Test/Unit/Ui/Component/Listing/Column/PriceTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Ui/Component/Listing/Column/PriceTest.php
@@ -76,8 +76,7 @@ public function testPrepareDataSource(
array $dataSource,
string $currencyCode,
?int $expectedStoreId = null
- ): void
- {
+ ): void {
$itemName = 'itemName';
$oldItemValue = 'oldItemValue';
$newItemValue = 'newItemValue';
@@ -159,11 +158,24 @@ public function testPrepareDataSourceDataProvider(): array
]
]
];
+ $dataSource5 = [
+ 'data' => [
+ 'items' => [
+ [
+ 'itemName' => 'oldItemValue',
+ 'store_id' => '123Test',
+ 'base_currency_code' => '',
+ ]
+ ]
+ ]
+ ];
+
return [
[true, $dataSource1, 'US'],
[false, $dataSource2, 'SAR'],
[false, $dataSource3, 'SAR', 2],
[false, $dataSource4, 'SAR'],
+ [false, $dataSource5, 'INR'],
];
}
}
diff --git a/app/code/Magento/Sales/Ui/Component/Listing/Column/Price.php b/app/code/Magento/Sales/Ui/Component/Listing/Column/Price.php
index cc323730f14b4..38655cf4a69d8 100644
--- a/app/code/Magento/Sales/Ui/Component/Listing/Column/Price.php
+++ b/app/code/Magento/Sales/Ui/Component/Listing/Column/Price.php
@@ -76,13 +76,13 @@ public function prepareDataSource(array $dataSource)
{
if (isset($dataSource['data']['items'])) {
foreach ($dataSource['data']['items'] as & $item) {
- $currencyCode = isset($item['base_currency_code']) ? $item['base_currency_code'] : null;
+ $currencyCode = $item['base_currency_code'] ?? null;
+
if (!$currencyCode) {
- $storeId = isset($item['store_id']) && (int)$item['store_id'] !== 0 ? $item['store_id'] :
+ $itemStoreId = $item['store_id'] ?? '';
+ $storeId = $itemStoreId && is_numeric($itemStoreId) ? $itemStoreId :
$this->context->getFilterParam('store_id', Store::DEFAULT_STORE_ID);
- $store = $this->storeManager->getStore(
- $storeId
- );
+ $store = $this->storeManager->getStore($storeId);
$currencyCode = $store->getBaseCurrency()->getCurrencyCode();
}
$basePurchaseCurrency = $this->currency->load($currencyCode);
diff --git a/app/code/Magento/SalesRule/etc/extension_attributes.xml b/app/code/Magento/SalesRule/etc/extension_attributes.xml
index c69c309d8741b..8cdf0fd7cd39c 100644
--- a/app/code/Magento/SalesRule/etc/extension_attributes.xml
+++ b/app/code/Magento/SalesRule/etc/extension_attributes.xml
@@ -12,4 +12,7 @@
-
\ No newline at end of file
+
+
+
+
diff --git a/app/code/Magento/Wishlist/Block/Rss/Link.php b/app/code/Magento/Wishlist/Block/Rss/Link.php
index 28affa8d3372d..4f24d2d118fbd 100644
--- a/app/code/Magento/Wishlist/Block/Rss/Link.php
+++ b/app/code/Magento/Wishlist/Block/Rss/Link.php
@@ -9,42 +9,48 @@
*/
namespace Magento\Wishlist\Block\Rss;
+use Magento\Framework\App\Rss\UrlBuilderInterface;
+use Magento\Framework\Url\EncoderInterface;
+use Magento\Framework\View\Element\Template;
+use Magento\Framework\View\Element\Template\Context;
+use Magento\Wishlist\Helper\Data;
+
/**
* @api
* @since 100.0.2
*/
-class Link extends \Magento\Framework\View\Element\Template
+class Link extends Template
{
/**
- * @var \Magento\Wishlist\Helper\Data
+ * @var Data
*/
- protected $wishlistHelper;
+ protected Data $wishlistHelper;
/**
- * @var \Magento\Framework\App\Rss\UrlBuilderInterface
+ * @var UrlBuilderInterface
*/
- protected $rssUrlBuilder;
+ protected UrlBuilderInterface $rssUrlBuilder;
/**
- * @var \Magento\Framework\Url\EncoderInterface
+ * @var EncoderInterface
*/
- protected $urlEncoder;
+ protected EncoderInterface $urlEncoder;
/**
- * @param \Magento\Framework\View\Element\Template\Context $context
- * @param \Magento\Wishlist\Helper\Data $wishlistHelper
- * @param \Magento\Framework\App\Rss\UrlBuilderInterface $rssUrlBuilder
- * @param \Magento\Framework\Url\EncoderInterface $urlEncoder
+ * @param Context $context
+ * @param Data $wishlistHelper
+ * @param UrlBuilderInterface $rssUrlBuilder
+ * @param EncoderInterface $urlEncoder
* @param array $data
*/
public function __construct(
- \Magento\Framework\View\Element\Template\Context $context,
- \Magento\Wishlist\Helper\Data $wishlistHelper,
- \Magento\Framework\App\Rss\UrlBuilderInterface $rssUrlBuilder,
- \Magento\Framework\Url\EncoderInterface $urlEncoder,
+ Context $context,
+ Data $wishlistHelper,
+ UrlBuilderInterface $rssUrlBuilder,
+ EncoderInterface $urlEncoder,
array $data = []
) {
- $data['wishlistHelper'] = $this->wishlistHelper;
+ $data['wishlistHelper'] = $wishlistHelper;
parent::__construct($context, $data);
$this->wishlistHelper = $wishlistHelper;
$this->rssUrlBuilder = $rssUrlBuilder;
diff --git a/app/code/Magento/Wishlist/Test/Mftf/ActionGroup/StorefrontShareCustomerWishlistWithRssFeedLinkActionGroup.xml b/app/code/Magento/Wishlist/Test/Mftf/ActionGroup/StorefrontShareCustomerWishlistWithRssFeedLinkActionGroup.xml
new file mode 100644
index 0000000000000..6664242951e3d
--- /dev/null
+++ b/app/code/Magento/Wishlist/Test/Mftf/ActionGroup/StorefrontShareCustomerWishlistWithRssFeedLinkActionGroup.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Wishlist/Test/Mftf/Data/WishlistData.xml b/app/code/Magento/Wishlist/Test/Mftf/Data/WishlistData.xml
index cf87432b3ba79..cc6e9c489a652 100755
--- a/app/code/Magento/Wishlist/Test/Mftf/Data/WishlistData.xml
+++ b/app/code/Magento/Wishlist/Test/Mftf/Data/WishlistData.xml
@@ -45,4 +45,20 @@
wishlist/general/show_in_sidebar
0
+
+ rss/config/active
+ 0
+
+
+ rss/wishlist/active
+ 0
+
+
+ rss/config/active
+ 1
+
+
+ rss/wishlist/active
+ 1
+
diff --git a/app/code/Magento/Wishlist/Test/Mftf/Section/StorefrontCustomerWishlistShareSection.xml b/app/code/Magento/Wishlist/Test/Mftf/Section/StorefrontCustomerWishlistShareSection.xml
index 3f16133be96a9..1db9f5754638a 100644
--- a/app/code/Magento/Wishlist/Test/Mftf/Section/StorefrontCustomerWishlistShareSection.xml
+++ b/app/code/Magento/Wishlist/Test/Mftf/Section/StorefrontCustomerWishlistShareSection.xml
@@ -11,6 +11,7 @@
diff --git a/app/code/Magento/Wishlist/Test/Mftf/Test/StorefrontShareWishlistWithRssFeedLinkTest.xml b/app/code/Magento/Wishlist/Test/Mftf/Test/StorefrontShareWishlistWithRssFeedLinkTest.xml
new file mode 100644
index 0000000000000..75bc9263c199e
--- /dev/null
+++ b/app/code/Magento/Wishlist/Test/Mftf/Test/StorefrontShareWishlistWithRssFeedLinkTest.xml
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Observer/ProcessUrlRewriteOnChangeVisibilityObserverTest.php b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Observer/ProcessUrlRewriteOnChangeVisibilityObserverTest.php
index 7eb7400837f81..3554a6c72a77f 100644
--- a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Observer/ProcessUrlRewriteOnChangeVisibilityObserverTest.php
+++ b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Observer/ProcessUrlRewriteOnChangeVisibilityObserverTest.php
@@ -67,8 +67,7 @@ public function testMakeProductInvisibleViaMassAction()
/** @var StoreManagerInterface $storeManager */
$storeManager = $this->objectManager->get(StoreManagerInterface::class);
- $storeManager->setCurrentStore(0);
-
+ $firstStore = current($product->getStoreIds());
$testStore = $storeManager->getStore('test');
$productFilter = [
UrlRewrite::ENTITY_TYPE => 'product',
@@ -80,7 +79,7 @@ public function testMakeProductInvisibleViaMassAction()
'target_path' => "catalog/product/view/id/" . $product->getId(),
'is_auto_generated' => 1,
'redirect_type' => 0,
- 'store_id' => '1',
+ 'store_id' => $firstStore,
],
[
'request_path' => "product-1.html",
@@ -100,12 +99,14 @@ public function testMakeProductInvisibleViaMassAction()
'catalog_product_attribute_update_before',
[
'attributes_data' => [ ProductInterface::VISIBILITY => Visibility::VISIBILITY_NOT_VISIBLE ],
- 'product_ids' => [$product->getId()]
+ 'product_ids' => [$product->getId()],
+ 'store_id' => $firstStore,
]
);
$actual = $this->getActualResults($productFilter);
- $this->assertCount(0, $actual);
+ //Initially count was 2, when visibility of 1 store view is set to not visible individually, the new count is 1
+ $this->assertCount(1, $actual);
}
/**
diff --git a/dev/tests/integration/testsuite/Magento/Cookie/Model/Config/Backend/DomainTest.php b/dev/tests/integration/testsuite/Magento/Cookie/Model/Config/Backend/DomainTest.php
index 392bb9f7f1bad..8b56c9f94e733 100644
--- a/dev/tests/integration/testsuite/Magento/Cookie/Model/Config/Backend/DomainTest.php
+++ b/dev/tests/integration/testsuite/Magento/Cookie/Model/Config/Backend/DomainTest.php
@@ -6,13 +6,15 @@
namespace Magento\Cookie\Model\Config\Backend;
use Magento\Framework\Exception\LocalizedException;
+use Magento\TestFramework\Helper\Bootstrap;
+use PHPUnit\Framework\TestCase;
/**
* Test \Magento\Cookie\Model\Config\Backend\Domain
*
* @magentoAppArea adminhtml
*/
-class DomainTest extends \PHPUnit\Framework\TestCase
+class DomainTest extends TestCase
{
/**
* @param string $value
@@ -22,10 +24,8 @@ class DomainTest extends \PHPUnit\Framework\TestCase
*/
public function testBeforeSave($value, $exceptionMessage = null)
{
- /** @var $domain \Magento\Cookie\Model\Config\Backend\Domain */
- $domain = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
- \Magento\Cookie\Model\Config\Backend\Domain::class
- );
+ /** @var $domain Domain */
+ $domain = Bootstrap::getObjectManager()->create(Domain::class);
$domain->setValue($value);
$domain->setPath('path');
try {
@@ -45,18 +45,19 @@ public function testBeforeSave($value, $exceptionMessage = null)
/**
* @return array
*/
- public function beforeSaveDataProvider()
+ public function beforeSaveDataProvider(): array
{
return [
- 'not string' => [['array'], 'Invalid domain name: must be a string'],
- 'invalid hostname' => [
+ 'notString' => [['array'], 'Invalid domain name: must be a string'],
+ 'invalidHostname' => [
'http://',
'Invalid domain name: The input does not match the expected structure for a DNS hostname; '
. 'The input does not appear to be a valid URI hostname; '
. 'The input does not appear to be a valid local network name',
],
- 'valid hostname' => ['hostname.com'],
- 'empty string' => [''],
+ 'validHostname' => ['hostname.com'],
+ 'emptyString' => [''],
+ 'invalidCharacter' => ['hostname,com', 'Invalid domain name: invalid character in cookie domain'],
];
}
}
diff --git a/dev/tests/integration/testsuite/Magento/Quote/Model/ShippingMethodManagementTest.php b/dev/tests/integration/testsuite/Magento/Quote/Model/ShippingMethodManagementTest.php
index e938945f2c411..b88eccd69f2de 100644
--- a/dev/tests/integration/testsuite/Magento/Quote/Model/ShippingMethodManagementTest.php
+++ b/dev/tests/integration/testsuite/Magento/Quote/Model/ShippingMethodManagementTest.php
@@ -11,7 +11,6 @@
use Magento\Customer\Api\Data\GroupInterface;
use Magento\Customer\Api\GroupRepositoryInterface;
use Magento\Customer\Model\Vat;
-use Magento\Customer\Observer\AfterAddressSaveObserver;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\App\Config\MutableScopeConfigInterface;
use Magento\Framework\DataObject;
@@ -23,12 +22,13 @@
use Magento\Quote\Api\GuestShippingMethodManagementInterface;
use Magento\Quote\Api\ShippingMethodManagementInterface;
use Magento\Quote\Observer\Frontend\Quote\Address\CollectTotalsObserver;
-use Magento\Quote\Observer\Frontend\Quote\Address\VatValidator;
use Magento\Store\Model\ScopeInterface;
use Magento\Tax\Api\Data\TaxClassInterface;
use Magento\Tax\Api\TaxClassRepositoryInterface;
use Magento\Tax\Model\ClassModel;
use Magento\Tax\Model\Config as TaxConfig;
+use Magento\TestFramework\Fixture\DataFixtureStorage;
+use Magento\TestFramework\Fixture\DataFixtureStorageManager;
use Magento\TestFramework\Helper\Bootstrap;
use Magento\TestFramework\Quote\Model\GetQuoteByReservedOrderId;
use PHPUnit\Framework\TestCase;
@@ -50,6 +50,11 @@ class ShippingMethodManagementTest extends TestCase
/** @var TaxClassRepositoryInterface $taxClassRepository */
private $taxClassRepository;
+ /**
+ * @var DataFixtureStorage
+ */
+ private $fixtures;
+
/**
* @inheritdoc
*/
@@ -58,6 +63,7 @@ protected function setUp(): void
$this->objectManager = Bootstrap::getObjectManager();
$this->groupRepository = $this->objectManager->get(GroupRepositoryInterface::class);
$this->taxClassRepository = $this->objectManager->get(TaxClassRepositoryInterface::class);
+ $this->fixtures = $this->objectManager->get(DataFixtureStorageManager::class)->getStorage();
}
/**
@@ -127,6 +133,56 @@ public function testTableRateFreeShipping()
}
}
+ /**
+ * phpcs:disable Generic.Files.LineLength.TooLong
+ *
+ * @magentoConfigFixture default_store carriers/tablerate/active 1
+ * @magentoConfigFixture default_store carriers/flatrate/active 0
+ * @magentoConfigFixture current_store carriers/tablerate/condition_name package_value_with_discount
+ * @magentoConfigFixture default_store carriers/tablerate/include_virtual_price 0
+ * @magentoDataFixture Magento\Catalog\Test\Fixture\Product with:{"sku":"simple", "type_id":"simple"} as:p1
+ * @magentoDataFixture Magento\Catalog\Test\Fixture\Product with:{"sku":"virtual", "type_id":"virtual", "weight":0} as:p2
+ * @magentoDataFixture Magento\Quote\Test\Fixture\GuestCart as:cart
+ * @magentoDataFixture Magento\Quote\Test\Fixture\AddProductToCart with:{"cart_id":"$cart.id$", "product_id":"$p1.id$"}
+ * @magentoDataFixture Magento\Quote\Test\Fixture\AddProductToCart with:{"cart_id":"$cart.id$", "product_id":"$p2.id$"}
+ * @magentoDataFixture Magento\Quote\Test\Fixture\SetBillingAddress with:{"cart_id":"$cart.id$"}
+ * @magentoDataFixture Magento\Quote\Test\Fixture\SetShippingAddress with:{"cart_id":"$cart.id$"}
+ * @magentoDataFixture Magento/OfflineShipping/_files/tablerates_price.php
+ * @return void
+ * @throws NoSuchEntityException
+ */
+ public function testTableRateWithoutIncludingVirtualProduct()
+ {
+ $cartId = (int)$this->fixtures->get('cart')->getId();
+
+ if (!$cartId) {
+ $this->fail('quote fixture failed');
+ }
+
+ /** @var QuoteRepository $quoteRepository */
+ $quoteRepository = $this->objectManager->get(QuoteRepository::class);
+ $quote = $quoteRepository->get($cartId);
+
+ /** @var QuoteIdToMaskedQuoteIdInterface $maskedQuoteId */
+ $maskedQuoteId = $this->objectManager->get(QuoteIdToMaskedQuoteIdInterface::class)->execute($cartId);
+
+ /** @var GuestShippingMethodManagementInterface $shippingEstimation */
+ $shippingEstimation = $this->objectManager->get(GuestShippingMethodManagementInterface::class);
+ $result = $shippingEstimation->estimateByExtendedAddress(
+ $maskedQuoteId,
+ $quote->getShippingAddress()
+ );
+
+ $this->assertCount(1, $result);
+ $rate = reset($result);
+ $expectedResult = [
+ 'method_code' => 'bestway',
+ 'amount' => 15,
+ ];
+ $this->assertEquals($expectedResult['method_code'], $rate->getMethodCode());
+ $this->assertEquals($expectedResult['amount'], $rate->getAmount());
+ }
+
/**
* Test table rate amount for the cart that contains some items with free shipping applied.
*
diff --git a/dev/tests/integration/testsuite/Magento/SalesRule/_files/cart_rule_free_shipping_by_cart.php b/dev/tests/integration/testsuite/Magento/SalesRule/_files/cart_rule_free_shipping_by_cart.php
index 21dcae2c6de38..1c2c297fba4c0 100644
--- a/dev/tests/integration/testsuite/Magento/SalesRule/_files/cart_rule_free_shipping_by_cart.php
+++ b/dev/tests/integration/testsuite/Magento/SalesRule/_files/cart_rule_free_shipping_by_cart.php
@@ -64,7 +64,7 @@
'is_rss' => 1,
'use_auto_generation' => 0,
'uses_per_coupon' => 0,
- 'simple_free_shipping' => 2,
+ 'simple_free_shipping' => 1,
'website_ids' => [
$objectManager->get(StoreManagerInterface::class)->getWebsite()->getId()
diff --git a/lib/internal/Magento/Framework/Session/Config/Validator/CookieDomainValidator.php b/lib/internal/Magento/Framework/Session/Config/Validator/CookieDomainValidator.php
index e145484d22a43..5b794c26b2dda 100644
--- a/lib/internal/Magento/Framework/Session/Config/Validator/CookieDomainValidator.php
+++ b/lib/internal/Magento/Framework/Session/Config/Validator/CookieDomainValidator.php
@@ -6,10 +6,13 @@
namespace Magento\Framework\Session\Config\Validator;
+use Laminas\Validator\Hostname;
+use Magento\Framework\Validator\AbstractValidator;
+
/**
* Session cookie domain validator
*/
-class CookieDomainValidator extends \Magento\Framework\Validator\AbstractValidator
+class CookieDomainValidator extends AbstractValidator
{
/**
* @inheritDoc
@@ -17,17 +20,29 @@ class CookieDomainValidator extends \Magento\Framework\Validator\AbstractValidat
public function isValid($value)
{
$this->_clearMessages();
+
if (!is_string($value)) {
$this->_addMessages(['must be a string']);
+
return false;
}
- $validator = new \Laminas\Validator\Hostname(\Laminas\Validator\Hostname::ALLOW_ALL);
+ //Hostname validator allows [;,] and returns the validator as true but,
+ //these are unacceptable cookie domain characters hence need explicit validation for the same
+ if (preg_match('/[;,]/', $value)) {
+ $this->_addMessages(['invalid character in cookie domain']);
+
+ return false;
+ }
+
+ $validator = new Hostname(Hostname::ALLOW_ALL);
if (!empty($value) && !$validator->isValid($value)) {
$this->_addMessages($validator->getMessages());
+
return false;
}
+
return true;
}
}