3

I use a module to display out of stock products last in the category view. That worked fine, but now I enabled the Magento option to purchase products that are out of stock. (The default Magento backorder method)

In that case I need to set all products to status "In Stock", so this code does not work anymore.

How can I edit this code, so that it will check if qty is 0, instead of status is "Out of stock"?

Default code, that works fine when set product to "Out of Stock" status:

class Outofstock_Model_Observer extends Mage_Core_Model_Abstract
{
    public function catalogProductCollectionLoadBefore(Varien_Event_Observer $observer)
    {
        $prefix = '_inventory_table'.rand(0, 10000);
        $collection = $observer->getCollection();
        $collection->getSelect()->joinLeft(
            array($prefix=>$collection->getTable('cataloginventory/stock_item')),
            "$prefix.product_id = e.entity_id",
            array('is_in_stock', 'manage_stock')
        );
        // $collection->addExpressionAttributeToSelect(
        //     'on_top',
        //     '(CASE WHEN (((_inventory_table.use_config_manage_stock = 1) AND (_inventory_table.is_in_stock = 1)) OR  ((_inventory_table.use_config_manage_stock = 0) AND (1 - _inventory_table.manage_stock + _inventory_table.is_in_stock >= 1))) THEN 1 ELSE 0 END)',
        //     array()
        // );
        $collection->getSelect()->order('(CASE WHEN ((('.$prefix.'.use_config_manage_stock = 1) AND ('.$prefix.'.is_in_stock = 1)) OR  (('.$prefix.'.use_config_manage_stock = 0) AND (1 - '.$prefix.'.manage_stock + '.$prefix.'.is_in_stock >= 1))) THEN 1 ELSE 0 END) DESC');
        $order = $collection->getSelect()->getPart('order');
        array_unshift($order, array_pop($order));
        $collection->getSelect()->setPart('order', $order);


    }
}

I already tried the code below, but that does not work perfectly. It does work, except that it does not overrule the catagory sort listing. So the sort listing is first displayed and then all products with the same sort listing are separated from stock and out of stock. I need to edit the code, so that it overrule the sort listing. So first list on stock and than on the sort listing number. How can I fix this?

class Outofstock_Model_Observer extends Mage_Core_Model_Abstract
{
    public function catalogProductCollectionLoadBefore(Varien_Event_Observer $observer)
    {
        $prefix = '_inventory_table'.rand(0, 10000);
        $collection = $observer->getCollection();
        $collection->getSelect()->joinLeft(
            array($prefix=>$collection->getTable('cataloginventory/stock_item')),
            "$prefix.product_id = e.entity_id",
            array('is_in_stock', 'manage_stock')
        );
        $collection->joinField(
                        'inventory_qty',
                        'cataloginventory_stock_item',
                        'qty',
                        'product_id=entity_id')
                    ->setOrder('inventory_qty','desc');

    }
}
1
  • Do my answer helped you in solving your problem? Or leading you towards that what you want? Apr 25, 2018 at 4:33

3 Answers 3

1

Not sure if this works, I haven't tested, but I used a similar approach to sort by custom attributes. So watch out for syntax errors.

You can rewrite the method Mage_Catalog_Model_Resource_Product_Collection::addAttributeToSort() and make it look like this:

public function addAttributeToSort($attribute, $dir = self::SORT_ORDER_ASC)
{
    //don't screw up the admin sorting.
    if (Mage::app()->getStore()->getId() == Mage_Core_Model_App::ADMIN_STORE_ID) {
        return parent::addAttributeToSort($attribute, $dir);
    }
    $website = Mage::app()->getWebsite();
    $select = $this->getSelect();
    //check if the correlation was already added
    $from = $select->getPart(Zend_Db_Select::FROM);
    //join the current collection with the stock status index table
    if (!isset($from['stock_status'])) {
        /** @var Mage_CatalogInventory_Model_Stock_Status $stockStatusModel */
        $stockStatusModel = Mage::getModel('cataloginventory/stock_status');
        $stockStatusModel->addStockStatusToSelect($select, $website);
    }
    //show first products that are in stock
    $select->order('stock_status.stock_status DESC');
    return parent::addAttributeToSort($attribute, $dir);
}
2
  • Thanks a lot for your reply. I tried the given code, but that does not seem to work. It does not effect the category page and out of stock products are not moved to the back.
    – JGeer
    Mar 23, 2018 at 11:47
  • sorry for that. As I said it's not tested. I will try again when I have some time and come back if I find something.
    – Marius
    Mar 23, 2018 at 11:58
0

I found the answer

Try this :

.../Mage/Catalog/Model/Layer.php at line #102

$collection->joinField('inventory_in_stock', 'cataloginventory_stock_item', 'is_in_stock', 'product_id=entity_id','is_in_stock>=0', 'left')->setOrder('inventory_in_stock', 'desc');

This will effect both the listing as well as the results page.

Another thing is to remember to copy this file from core to code/local/Mage/Catalog/Model/Layer.php so that the core files remain as it is.

4
  • Thanks for reply. Do I need to overwrite line 102? Because than I get a Fatal error: Uncaught Error: Call to a member function joinField() on 102
    – JGeer
    Sep 14, 2017 at 11:51
  • Search For $collection = $this->getCurrentCategory()->getProductCollection(); after this line add below code Category List : $collection->joinFieldCa('inventory_in_stock', 'cataloginventory_stock_item', 'is_in_stock', 'product_id=entity_id','is_in_stock>=0', 'left')->setOrder('inventory_in_stock', 'desc');
    – Raghav
    Sep 14, 2017 at 11:56
  • For Category Search : search for $collection = Mage::getResourceModel('catalogsearch/fulltext_collection'); after this line add below code $collection->joinField('inventory_in_stock', 'cataloginventory_stock_item', 'is_in_stock', 'product_id=entity_id','is_in_stock>=0', 'left')->setOrder('inventory_in_stock', 'desc');
    – Raghav
    Sep 14, 2017 at 12:00
  • Thanks a lot for your help, but it does not seem to work. Still got that same problem with sort listing.
    – JGeer
    Sep 14, 2017 at 12:02
0

I have tried this in Magento 2 & it is working perfect for me as per we consider the simple product only because the Bundle Products & Configurable Products are having their stock_quantity value = 0. But as per we consider it for the simple products only it is working perfect for them.

Here my coding files with location

Magento_root/app/code/{Vendor}/{Module}/Block/Product/ProductList

Toolbar.php

<?php

namespace {Vendor}\{Module}\Block\Product\ProductList;

use Magento\Catalog\Helper\Product\ProductList;
use Magento\Catalog\Model\Product\ProductList\Toolbar as ToolbarModel;
use Magento\Framework\View\Element\Template;

class Toolbar extends \Magento\Catalog\Block\Product\ProductList\Toolbar{

    public function __construct(
        \Magento\Framework\View\Element\Template\Context $context,
        \Magento\Catalog\Model\Session $catalogSession,
        \Magento\Catalog\Model\Config $catalogConfig, 
        ToolbarModel $toolbarModel, 
        \Magento\Framework\Url\EncoderInterface $urlEncoder, 
        ProductList $productListHelper, 
        \Magento\Framework\Data\Helper\PostHelper $postDataHelper, 
        \Magento\Framework\Registry $registry,
        array $data = []
    ) {
        parent::__construct(
                $context, $catalogSession, $catalogConfig, $toolbarModel, $urlEncoder, $productListHelper, $postDataHelper, $data
        );
    }
    public function setCollection($collection) {

        $this->_collection = $collection;
        $this->_collection->setCurPage($this->getCurrentPage());
        $limit = (int) $this->getLimit();
        if ($limit) {
            $this->_collection->setPageSize($limit);
        }
        if ($this->getCurrentOrder()) {
            if ($this->getCurrentOrder() == 'position' && $this->getCurrentDirection() == 'asc'){
                $zeroStockLast = new \Zend_Db_Expr('`stock_status_index`.`qty` = 0 ASC, `stock_status_index`.`qty`  ASC'); 
                $this->_collection->getSelect()->order($zeroStockLast);

            } else if ($this->getCurrentOrder() == 'position' && $this->getCurrentDirection() == 'desc'){
                $zeroStockLast = new \Zend_Db_Expr('`stock_status_index`.`qty` = 0 ASC, `stock_status_index`.`qty`  desc');
                $this->_collection->getSelect()->order($zeroStockLast);
            } else {
                $this->_collection->setOrder($this->getCurrentOrder(), $this->getCurrentDirection());
            }
        }
    }

}

Here you can choose All/Whatever sort_by attribute you want to use for product sorting, I used position just for the testing purpose.

Magento_root/app/code/{Vendor}/{Module}/etc/frontend

di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
  <preference for="Magento\Catalog\Block\Product\ProductList\Toolbar" type="{Vendor}\{Module}\Block\Product\ProductList\Toolbar" />
</config>

I am not putting the registration.php & module.xml code because it is well known to everyone the compulsion of these files for any module creation.

I don't know How you will do it for Magento 1.9.I used preferences for the Magento 2 & tested this code on Magento 2.2.0 So kindly Please Consider this for your use of this code in Magento 1.9

Thank You!

3
  • There are a lot of differences between Magento 1 & 2, So it will be useless to post Magento 2 code on Magento1 question, instead try to explain steps which can be followed
    – Piyush
    Mar 29, 2018 at 5:26
  • If you look into my code it is similar code as it is available in magento 1.9 for Toolbar.php & the table structure for the stock_status is also same there is just difference file location. I just mentioned this over here & tested this code in Magento 2 because I don't how to use observer in magento 1.9 that because I didn't worked on magento 2. But as we can see that the PO of this question has already used an observer so he will understand that how to use it in magento 1.9. Mar 29, 2018 at 5:57
  • I didn't used anything extra in constructor as well which is differs then the magento 1. So I don't think that this will be useless that to put this code over here. If you still have any doubt you can test it in your magento 1.9 & for the clearance I have already mentioned here that I have used it in magento 2 so for magento 1 you can judge it only after testing it may be it will solve the problem of POwith some minor changes. ;)! Mar 29, 2018 at 6:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.