Skip to content

Commit

Permalink
Merge pull request #4799 from magento-trigger/MC-16650
Browse files Browse the repository at this point in the history
- fixed Product Attribute Type Price Not Displaying
  • Loading branch information
irenelagno authored Sep 19, 2019
2 parents 3ee05a4 + bdfc864 commit 52f9fd4
Show file tree
Hide file tree
Showing 17 changed files with 344 additions and 15 deletions.
8 changes: 6 additions & 2 deletions app/code/Magento/Catalog/Model/Layer/FilterList.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\Catalog\Model\Layer;

/**
* Layer navigation filters
*/
class FilterList
{
const CATEGORY_FILTER = 'category';
Expand Down Expand Up @@ -106,9 +110,9 @@ protected function getAttributeFilterClass(\Magento\Catalog\Model\ResourceModel\
{
$filterClassName = $this->filterTypes[self::ATTRIBUTE_FILTER];

if ($attribute->getAttributeCode() == 'price') {
if ($attribute->getFrontendInput() === 'price') {
$filterClassName = $this->filterTypes[self::PRICE_FILTER];
} elseif ($attribute->getBackendType() == 'decimal') {
} elseif ($attribute->getBackendType() === 'decimal') {
$filterClassName = $this->filterTypes[self::DECIMAL_FILTER];
}

Expand Down
22 changes: 22 additions & 0 deletions app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeData.xml
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,28 @@
<data key="used_for_sort_by">false</data>
<requiredEntity type="FrontendLabel">ProductAttributeFrontendLabel</requiredEntity>
</entity>
<entity name="productAttributeTypeOfPrice" type="ProductAttribute">
<data key="attribute_code" unique="suffix">attribute</data>
<data key="frontend_input">price</data>
<data key="scope">global</data>
<data key="is_required">false</data>
<data key="is_unique">false</data>
<data key="is_searchable">false</data>
<data key="is_visible">true</data>
<data key="is_wysiwyg_enabled">false</data>
<data key="is_visible_in_advanced_search">false</data>
<data key="is_visible_on_front">true</data>
<data key="is_filterable">true</data>
<data key="is_filterable_in_search">false</data>
<data key="used_in_product_listing">false</data>
<data key="is_used_for_promo_rules">false</data>
<data key="is_comparable">true</data>
<data key="is_used_in_grid">false</data>
<data key="is_visible_in_grid">false</data>
<data key="is_filterable_in_grid">false</data>
<data key="used_for_sort_by">false</data>
<requiredEntity type="FrontendLabel">ProductAttributeFrontendLabel</requiredEntity>
</entity>
<entity name="textProductAttribute" extends="productAttributeWysiwyg" type="ProductAttribute">
<data key="frontend_input">text</data>
<data key="default_value" unique="suffix">defaultValue</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@
<element name="textAttributeByName" type="text" selector="//div[@data-index='attributes']//fieldset[contains(@class, 'admin__field') and .//*[contains(.,'{{var}}')]]//input" parameterized="true"/>
<element name="dropDownAttribute" type="select" selector="//select[@name='product[{{arg}}]']" parameterized="true" timeout="30"/>
<element name="attributeSection" type="block" selector="//div[@data-index='attributes']/div[contains(@class, 'admin__collapsible-content _show')]" timeout="30"/>
<element name="customAttribute" type="text" selector="product[{{attributecode}}]" timeout="30" parameterized="true"/>
<element name="attributeGroupByName" type="button" selector="//div[@class='fieldset-wrapper-title']//span[text()='{{group}}']" parameterized="true"/>
<element name="attributeByGroupAndName" type="text" selector="//div[@class='fieldset-wrapper-title']//span[text()='{{group}}']/../../following-sibling::div//span[contains(text(),'attribute')]" parameterized="true"/>
</section>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@
<section name="StorefrontCategoryFilterSection">
<element name="CategoryFilter" type="button" selector="//main//div[@class='filter-options']//div[contains(text(), 'Category')]"/>
<element name="CategoryByName" type="button" selector="//main//div[@class='filter-options']//li[@class='item']//a[contains(text(), '{{var1}}')]" parameterized="true"/>
<element name="CustomPriceAttribute" type="button" selector="div.filter-options-title"/>
</section>
</sections>
19 changes: 12 additions & 7 deletions app/code/Magento/Catalog/Test/Unit/Model/Layer/FilterListTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\Catalog\Test\Unit\Model\Layer;

Expand Down Expand Up @@ -72,9 +73,13 @@ public function testGetFilters($method, $value, $expectedClass)

$this->objectManagerMock->expects($this->at(1))
->method('create')
->with($expectedClass, [
'data' => ['attribute_model' => $this->attributeMock],
'layer' => $this->layerMock])
->with(
$expectedClass,
[
'data' => ['attribute_model' => $this->attributeMock],
'layer' => $this->layerMock
]
)
->will($this->returnValue('filter'));

$this->attributeMock->expects($this->once())
Expand All @@ -95,8 +100,8 @@ public function getFiltersDataProvider()
{
return [
[
'method' => 'getAttributeCode',
'value' => FilterList::PRICE_FILTER,
'method' => 'getFrontendInput',
'value' => 'price',
'expectedClass' => 'PriceFilterClass',
],
[
Expand All @@ -105,8 +110,8 @@ public function getFiltersDataProvider()
'expectedClass' => 'DecimalFilterClass',
],
[
'method' => 'getAttributeCode',
'value' => null,
'method' => 'getFrontendInput',
'value' => 'text',
'expectedClass' => 'AttributeFilterClass',
]
];
Expand Down
17 changes: 14 additions & 3 deletions app/code/Magento/CatalogSearch/Model/Layer/Filter/Decimal.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\CatalogSearch\Model\Layer\Filter;

use Magento\Catalog\Model\Layer\Filter\AbstractFilter;
Expand All @@ -12,6 +14,9 @@
*/
class Decimal extends AbstractFilter
{
/** Decimal delta for filter */
private const DECIMAL_DELTA = 0.001;

/**
* @var \Magento\Framework\Pricing\PriceCurrencyInterface
*/
Expand Down Expand Up @@ -70,11 +75,17 @@ public function apply(\Magento\Framework\App\RequestInterface $request)

list($from, $to) = explode('-', $filter);

// When the range is 10-20 we only need to get products that are in the 10-19.99 range.
$toValue = $to;
if (!empty($toValue) && $from !== $toValue) {
$toValue -= self::DECIMAL_DELTA;
}

$this->getLayer()
->getProductCollection()
->addFieldToFilter(
$this->getAttributeModel()->getAttributeCode(),
['from' => $from, 'to' => $to]
['from' => $from, 'to' => $toValue]
);

$this->getLayer()->getState()->addFilter(
Expand Down Expand Up @@ -111,7 +122,7 @@ protected function _getItemsData()
$from = '';
}
if ($to == '*') {
$to = null;
$to = '';
}
$label = $this->renderRangeLabel(empty($from) ? 0 : $from, $to);
$value = $from . '-' . $to;
Expand All @@ -138,7 +149,7 @@ protected function _getItemsData()
protected function renderRangeLabel($fromPrice, $toPrice)
{
$formattedFromPrice = $this->priceCurrency->format($fromPrice);
if ($toPrice === null) {
if ($toPrice === '') {
return __('%1 and above', $formattedFromPrice);
} else {
if ($fromPrice != $toPrice) {
Expand Down
5 changes: 4 additions & 1 deletion app/code/Magento/CatalogSearch/Model/Layer/Filter/Price.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\CatalogSearch\Model\Layer\Filter;

use Magento\Catalog\Model\Layer\Filter\AbstractFilter;
Expand All @@ -11,6 +13,7 @@
* Layer price filter based on Search API
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
*/
class Price extends AbstractFilter
{
Expand Down Expand Up @@ -138,7 +141,7 @@ public function apply(\Magento\Framework\App\RequestInterface $request)
list($from, $to) = $filter;

$this->getLayer()->getProductCollection()->addFieldToFilter(
'price',
$this->getAttributeModel()->getAttributeCode(),
['from' => $from, 'to' => empty($to) || $from == $to ? $to : $to - self::PRICE_DELTA]
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\CatalogSearch\Model\Search;

use Magento\Catalog\Api\Data\EavAttributeInterface;
Expand Down Expand Up @@ -78,6 +80,7 @@ private function generateRequest($attributeType, $container, $useFulltext)
{
$request = [];
foreach ($this->getSearchableAttributes() as $attribute) {
/** @var $attribute Attribute */
if ($attribute->getData($attributeType)) {
if (!in_array($attribute->getAttributeCode(), ['price', 'category_ids'], true)) {
$queryName = $attribute->getAttributeCode() . '_query';
Expand All @@ -97,12 +100,14 @@ private function generateRequest($attributeType, $container, $useFulltext)
],
];
$bucketName = $attribute->getAttributeCode() . self::BUCKET_SUFFIX;
$generator = $this->generatorResolver->getGeneratorForType($attribute->getBackendType());
$generatorType = $attribute->getFrontendInput() === 'price'
? $attribute->getFrontendInput()
: $attribute->getBackendType();
$generator = $this->generatorResolver->getGeneratorForType($generatorType);
$request['filters'][$filterName] = $generator->getFilterData($attribute, $filterName);
$request['aggregations'][$bucketName] = $generator->getAggregationData($attribute, $bucketName);
}
}
/** @var $attribute Attribute */
if (!$attribute->getIsSearchable() || in_array($attribute->getAttributeCode(), ['price'], true)) {
// Some fields have their own specific handlers
continue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\CatalogSearch\Model\Search\RequestGenerator;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\CatalogSearch\Model\Search\RequestGenerator;

use Magento\Catalog\Model\ResourceModel\Eav\Attribute;
use Magento\Framework\Search\Request\BucketInterface;
use Magento\Framework\Search\Request\FilterInterface;

/**
* Catalog search range request generator.
*/
class Price implements GeneratorInterface
{
/**
* @inheritdoc
*/
public function getFilterData(Attribute $attribute, $filterName): array
{
return [
'type' => FilterInterface::TYPE_RANGE,
'name' => $filterName,
'field' => $attribute->getAttributeCode(),
'from' => '$' . $attribute->getAttributeCode() . '.from$',
'to' => '$' . $attribute->getAttributeCode() . '.to$',
];
}

/**
* @inheritdoc
*/
public function getAggregationData(Attribute $attribute, $bucketName): array
{
return [
'type' => BucketInterface::TYPE_DYNAMIC,
'name' => $bucketName,
'field' => $attribute->getAttributeCode(),
'method' => '$price_dynamic_algorithm$',
'metric' => [['type' => 'count']],
];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->

<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
<test name="LayerNavigationOfCatalogSearchTest">
<annotations>
<stories value="Search terms"/>
<title value="Layer Navigation of Catalog Search Should Equalize Price Range As Default Configuration"/>
<description value="Make sure filter of custom attribute with type of price displays on storefront Catalog page and price range should respect the configuration in Admin site"/>
<testCaseId value="MC-16979"/>
<useCaseId value="MC-16650"/>
<severity value="MAJOR"/>
<group value="CatalogSearch"/>
</annotations>
<before>
<magentoCLI command="config:set catalog/layered_navigation/price_range_calculation auto" stepKey="setAutoPriceRange"/>
<createData stepKey="createPriceAttribute" entity="productAttributeTypeOfPrice"/>
<createData stepKey="assignPriceAttributeGroup" entity="AddToDefaultSet">
<requiredEntity createDataKey="createPriceAttribute"/>
</createData>
<createData entity="SimpleSubCategory" stepKey="subCategory"/>
<createData entity="SimpleProduct" stepKey="simpleProduct1">
<requiredEntity createDataKey="subCategory"/>
</createData>
<createData entity="SimpleProduct" stepKey="simpleProduct2">
<requiredEntity createDataKey="subCategory"/>
</createData>
<actionGroup ref = "LoginAsAdmin" stepKey="loginAsAdmin"/>
</before>
<after>
<deleteData stepKey="deleteSimpleSubCategory" createDataKey="subCategory"/>
<deleteData stepKey="deleteSimpleProduct1" createDataKey="simpleProduct1"/>
<deleteData stepKey="deleteSimpleProduct2" createDataKey="simpleProduct2"/>
<deleteData createDataKey="createPriceAttribute" stepKey="deleteAttribute"/>
<actionGroup ref="logout" stepKey="logout"/>
</after>
<!--Update value for price attribute of Product 1-->
<comment userInput="Update value for price attribute of Product 1" stepKey="comment1"/>
<actionGroup ref="navigateToCreatedProductEditPage" stepKey="navigateToCreatedProductEditPage1">
<argument name="product" value="$$simpleProduct1$$"/>
</actionGroup>
<grabTextFrom selector="{{AdminProductFormSection.attributeLabelByText($$createPriceAttribute.attribute[frontend_labels][0][label]$$)}}" stepKey="grabAttributeLabel"/>
<fillField selector="{{AdminProductAttributeSection.customAttribute($$createPriceAttribute.attribute_code$$)}}" userInput="30" stepKey="fillCustomPrice1"/>
<click selector="{{AdminProductFormSection.save}}" stepKey="clickSaveButton1"/>
<waitForPageLoad stepKey="waitForSimpleProductSaved1"/>
<!--Update value for price attribute of Product 2-->
<comment userInput="Update value for price attribute of Product 1" stepKey="comment2"/>
<actionGroup ref="navigateToCreatedProductEditPage" stepKey="navigateToCreatedProductEditPage2">
<argument name="product" value="$$simpleProduct2$$"/>
</actionGroup>
<fillField selector="{{AdminProductAttributeSection.customAttribute($$createPriceAttribute.attribute_code$$)}}" userInput="70" stepKey="fillCustomPrice2"/>
<click selector="{{AdminProductFormSection.save}}" stepKey="clickSaveButton2"/>
<waitForPageLoad stepKey="waitForSimpleProductSaved2"/>
<!--Navigate to category on Storefront-->
<comment userInput="Navigate to category on Storefront" stepKey="comment3"/>
<amOnPage url="{{StorefrontCategoryPage.url($$subCategory.name$$)}}" stepKey="goToCategoryStorefront"/>
<waitForPageLoad stepKey="waitForPageLoad"/>
<see userInput="{$grabAttributeLabel}" selector="{{StorefrontCategoryFilterSection.CustomPriceAttribute}}" stepKey="seePriceLayerNavigationOnStorefront"/>
</test>
</tests>






















Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\CatalogSearch\Test\Unit\Model\Layer\Filter;

Expand Down Expand Up @@ -208,6 +209,12 @@ public function testApply()
$priceId = '15-50';
$requestVar = 'test_request_var';

$this->target->setAttributeModel($this->attribute);
$attributeCode = 'price';
$this->attribute->expects($this->any())
->method('getAttributeCode')
->will($this->returnValue($attributeCode));

$this->target->setRequestVar($requestVar);
$this->request->expects($this->exactly(1))
->method('getParam')
Expand Down
Loading

0 comments on commit 52f9fd4

Please sign in to comment.