cancel
Showing results for 
Search instead for 
Did you mean: 

Фильтры и управление наличием

SOLVED

Фильтры и управление наличием

Добрый день! У меня на сайте используются настраиваемые товары. Соответственно используется фильтр мадженты по атрибутам. Проблема заключается в следующем. Я хочу показывать на сайте товары которых нет в наличии, но при этом чтобы корректно работал фильтр по атрибутам. Поясню.

 

Есть товары: майка №1 (в наличии все цвета), товар майка №2 (в наличии только красный цвет) и товар майка №3 (вообще нет в наличии).

Захожу в категорию майки и вижу там три товара. У товаров майка №1 и №2 написано "В наличии", у товара майка №3 написано "Нет в наличии". Затем выбираю в фильтре "красный цвет" и в результатах должен увидеть только майку №1 и майку №2. А если выбрать зеленый цвет, то должен увидеть только майку №1. Сейчас же если в настройках склада отмечено "Display Out of Stock Products", то при использовании фильтров отображаются все товары, что не удобно (и не верно).

 

Подскажите, где искать проблему? 

1 ACCEPTED SOLUTION

Accepted Solutions

Re: Фильтры и управление наличием

Вобщем нашел я для себя такое решение, может быть кому-нибудь пригодится.

 

1. Добавляем поле "in_stock" в таблицы 

$installer = $this;
$installer->startSetup();

$fieldName = "in_stock";
$tableNames = [
'catalog_product_index_eav',
'catalog_product_index_eav_idx',
'catalog_product_index_eav_tmp',
'catalog_product_index_eav_decimal',
'catalog_product_index_eav_decimal_idx',
'catalog_product_index_eav_decimal_tmp',
];

foreach ($tableNames as $tableName) {
$indexName = "IDX_" . mb_strtoupper($tableName) . "_" . mb_strtoupper($fieldName);
$installer->getConnection()->addColumn($tableName, $fieldName, 'tinyint(1) not null');
$installer->getConnection()->addIndex($tableName, $indexName, [$fieldName], Varien_Db_Adapter_Interface::INDEX_TYPE_INDEX);
}


$installer->endSetup();

2. Меняем  

Mage_Catalog_Model_Resource_Product_Indexer_Eav_Abstract

protected function _prepareRelationIndex($parentIds = null)
{ ... ->join(
array('i' => $idxTable),
'l.child_id = i.entity_id AND cs.store_id = i.store_id',
array('attribute_id', 'store_id', 'value', 'in_stock'))
->group(array(
'l.parent_id', 'i.attribute_id', 'i.store_id', 'i.value', 'i.in_stock' ... }

 

Mage_Catalog_Model_Resource_Product_Indexer_Eav_Source
protected function _prepareSelectIndex($entityIds = null, $attributeId = null)
{ ... $select = $adapter->select()
->from(
array('pid' => new Zend_Db_Expr(sprintf('(%s)',$subSelect->assemble()))),
array()
)
->joinLeft(
array('pis' => $this->getValueTable('catalog/product', 'int')),
'pis.entity_id = pid.entity_id AND pis.attribute_id = pid.attribute_id AND pis.store_id = pid.store_id',
array()
)
->joinLeft(
array('csi' => $this->getValueTable('cataloginventory/stock', 'item')),
'csi.product_id = pid.entity_id',
array()
)
->columns(
array(
'pid.entity_id',
'pid.attribute_id',
'pid.store_id',
'is_in_stock' => $adapter->getIfNullSql('csi.is_in_stock', 0),
'value' => $adapter->getIfNullSql('pis.value', 'pid.value')
)
)
->where('pid.attribute_id IN(?)', $attrIds); ... } protected function _prepareMultiselectIndex($entityIds = null, $attributeId = null)
{ ... $select = $adapter->select()
->from(
array('pvd' => $this->getValueTable('catalog/product', 'varchar')),
array('entity_id', 'attribute_id'))
->join(
array('cs' => $this->getTable('core/store')),
'',
array('store_id'))
->joinLeft(
array('csi' => $this->getValueTable('cataloginventory/stock', 'item')),
'csi.product_id = pvd.entity_id',
array('is_in_stock' => $adapter->getIfNullSql('csi.is_in_stock', 0))
)
->joinLeft(
array('pvs' => $this->getValueTable('catalog/product', 'varchar')),
'pvs.entity_id = pvd.entity_id AND pvs.attribute_id = pvd.attribute_id'
. ' AND pvs.store_id=cs.store_id',
array('value' => $productValueExpression))
->where('pvd.store_id=?',
$adapter->getIfNullSql('pvs.store_id', Mage_Catalog_Model_Abstract::DEFAULT_STORE_ID))
->where('cs.store_id!=?', Mage_Catalog_Model_Abstract::DEFAULT_STORE_ID)
->where('pvd.attribute_id IN(?)', $attrIds); ... $data[] = array(
$row['entity_id'],
$row['attribute_id'],
$row['store_id'],
$row['is_in_stock'],
$valueId,
); ... protected function _saveIndexData(array $data)
{
if (!$data) {
return $this;
}
$adapter = $this->_getWriteAdapter();
$adapter->insertArray($this->getIdxTable(), array('entity_id', 'attribute_id', 'store_id', 'in_stock', 'value'), $data);
return $this;
} }

 

3. 

Mage_Catalog_Model_Resource_Layer_Filter_Attribute

function applyFilterToCollection($filter, $values)
{ ... $connection->quoteInto("{$tableAlias}.in_stock = ?", 1 ... }

 

Суть в том, что при переиндексации magento формирует таблицу catalog_product_index_eav, в которую попадают значения атрибутов для товаров.
а)  Если товары "не в наличии" не показываются. В таблицу catalog_product_index_eav  не попадают значения атрибутов простых товаров, которые не в наличии. Таким образом при использовании фильтра (многоуровневой навигации) всё отображается корректно. В данном случае мои изменения не меняют этот кейс.

б) Если товары "не в наличии" должны отображаться. В таблицу попадают все атрибуты простых товаров, даже если они не в наличии. А проверка по наличию происходит по configurable-товару. После исправления, мы проверяем наличие также по конкретному простому товару, чей атрибут учавствует в фильтре. 

ps. Надеюсь понятно объяснил. 
pps. Конечно, не обязательно вносить изменения в Core. Можно/нужно написать модуль, который переопределит нужные методы.

 

 

Ну и возможно есть другое решение, буду признателен если кто поделится. 

View solution in original post

3 REPLIES 3

Re: Фильтры и управление наличием

Смотреть в сторону модулей фильтрации, которые умеют фильтровать по наличию товара. Стандартный модуль фильтрует все видимые товары, а не только те, что в наличии.


ET Web Solutions
extensions, custom work, support

Re: Фильтры и управление наличием

Да, стандартный наличием никак не управляет. Я нашел готовый модуль и переделываю его под себя. Использую для фильтрации по наличию:

 

/** @var Mage_CatalogInventory_Model_Stock $model */
$model = Mage::getsingleton('cataloginventory/stock');
$model->addInStockFilterToCollection($collection); 

Все работает прекрасно при фильтрации простых товаров. А с настраиваемыми такой фокус не проходит, видимо т.к. сам конфигурируемый товар в наличии, а вот простой товар с нужным атрибутом - нет. Есть возможность сделать так, чтобы фильтр работал правильно и с настраиваемыми товарами?

Re: Фильтры и управление наличием

Вобщем нашел я для себя такое решение, может быть кому-нибудь пригодится.

 

1. Добавляем поле "in_stock" в таблицы 

$installer = $this;
$installer->startSetup();

$fieldName = "in_stock";
$tableNames = [
'catalog_product_index_eav',
'catalog_product_index_eav_idx',
'catalog_product_index_eav_tmp',
'catalog_product_index_eav_decimal',
'catalog_product_index_eav_decimal_idx',
'catalog_product_index_eav_decimal_tmp',
];

foreach ($tableNames as $tableName) {
$indexName = "IDX_" . mb_strtoupper($tableName) . "_" . mb_strtoupper($fieldName);
$installer->getConnection()->addColumn($tableName, $fieldName, 'tinyint(1) not null');
$installer->getConnection()->addIndex($tableName, $indexName, [$fieldName], Varien_Db_Adapter_Interface::INDEX_TYPE_INDEX);
}


$installer->endSetup();

2. Меняем  

Mage_Catalog_Model_Resource_Product_Indexer_Eav_Abstract

protected function _prepareRelationIndex($parentIds = null)
{ ... ->join(
array('i' => $idxTable),
'l.child_id = i.entity_id AND cs.store_id = i.store_id',
array('attribute_id', 'store_id', 'value', 'in_stock'))
->group(array(
'l.parent_id', 'i.attribute_id', 'i.store_id', 'i.value', 'i.in_stock' ... }

 

Mage_Catalog_Model_Resource_Product_Indexer_Eav_Source
protected function _prepareSelectIndex($entityIds = null, $attributeId = null)
{ ... $select = $adapter->select()
->from(
array('pid' => new Zend_Db_Expr(sprintf('(%s)',$subSelect->assemble()))),
array()
)
->joinLeft(
array('pis' => $this->getValueTable('catalog/product', 'int')),
'pis.entity_id = pid.entity_id AND pis.attribute_id = pid.attribute_id AND pis.store_id = pid.store_id',
array()
)
->joinLeft(
array('csi' => $this->getValueTable('cataloginventory/stock', 'item')),
'csi.product_id = pid.entity_id',
array()
)
->columns(
array(
'pid.entity_id',
'pid.attribute_id',
'pid.store_id',
'is_in_stock' => $adapter->getIfNullSql('csi.is_in_stock', 0),
'value' => $adapter->getIfNullSql('pis.value', 'pid.value')
)
)
->where('pid.attribute_id IN(?)', $attrIds); ... } protected function _prepareMultiselectIndex($entityIds = null, $attributeId = null)
{ ... $select = $adapter->select()
->from(
array('pvd' => $this->getValueTable('catalog/product', 'varchar')),
array('entity_id', 'attribute_id'))
->join(
array('cs' => $this->getTable('core/store')),
'',
array('store_id'))
->joinLeft(
array('csi' => $this->getValueTable('cataloginventory/stock', 'item')),
'csi.product_id = pvd.entity_id',
array('is_in_stock' => $adapter->getIfNullSql('csi.is_in_stock', 0))
)
->joinLeft(
array('pvs' => $this->getValueTable('catalog/product', 'varchar')),
'pvs.entity_id = pvd.entity_id AND pvs.attribute_id = pvd.attribute_id'
. ' AND pvs.store_id=cs.store_id',
array('value' => $productValueExpression))
->where('pvd.store_id=?',
$adapter->getIfNullSql('pvs.store_id', Mage_Catalog_Model_Abstract::DEFAULT_STORE_ID))
->where('cs.store_id!=?', Mage_Catalog_Model_Abstract::DEFAULT_STORE_ID)
->where('pvd.attribute_id IN(?)', $attrIds); ... $data[] = array(
$row['entity_id'],
$row['attribute_id'],
$row['store_id'],
$row['is_in_stock'],
$valueId,
); ... protected function _saveIndexData(array $data)
{
if (!$data) {
return $this;
}
$adapter = $this->_getWriteAdapter();
$adapter->insertArray($this->getIdxTable(), array('entity_id', 'attribute_id', 'store_id', 'in_stock', 'value'), $data);
return $this;
} }

 

3. 

Mage_Catalog_Model_Resource_Layer_Filter_Attribute

function applyFilterToCollection($filter, $values)
{ ... $connection->quoteInto("{$tableAlias}.in_stock = ?", 1 ... }

 

Суть в том, что при переиндексации magento формирует таблицу catalog_product_index_eav, в которую попадают значения атрибутов для товаров.
а)  Если товары "не в наличии" не показываются. В таблицу catalog_product_index_eav  не попадают значения атрибутов простых товаров, которые не в наличии. Таким образом при использовании фильтра (многоуровневой навигации) всё отображается корректно. В данном случае мои изменения не меняют этот кейс.

б) Если товары "не в наличии" должны отображаться. В таблицу попадают все атрибуты простых товаров, даже если они не в наличии. А проверка по наличию происходит по configurable-товару. После исправления, мы проверяем наличие также по конкретному простому товару, чей атрибут учавствует в фильтре. 

ps. Надеюсь понятно объяснил. 
pps. Конечно, не обязательно вносить изменения в Core. Можно/нужно написать модуль, который переопределит нужные методы.

 

 

Ну и возможно есть другое решение, буду признателен если кто поделится.