简体   繁体   中英

Configurable products ranking in Magento

I am trying to generate a "best selling products" list on my magento site. I tried following the answer from here . This works okay, however, I realized that this is only ideal for simple products. I am trying to create the ranking for configurable products so I believe I need to get the total orders for the simple products first which I'm not sure how I can do programmatically. This is basically the idea I have in mind:

Get the simple products associated to a configurable product

Get the total orders for each simple product and sum them up

Pass the total sum to configurable products again (i'm thinking of using an array here) then call the necessary data ordered by ranking.

So far I have come up with this code:

$storeId = Mage::app()->getStore()->getId();
$_collection = Mage::getResourceModel('reports/product_collection')
                    ->addAttributeToSelect('*')
                    ->addAttributeToFilter('type_id', 'configurable');
foreach($_collection as $c):
$configurable = $c->getTypeInstance()->getUsedProductIds();
foreach($configurable as $_config):
    $_simple = Mage::getModel('catalog/product')->load($_config);
                echo $_simple->getName()."<br/>";
                echo "qty:".(int)$_simple->ordered_qty."<br/>";
            endforeach;
        endforeach;

However, while trying to test it, all of my quantities return 0 so I'm stuck. How do I implement the ranking for configurable products? Please advise. Also, if possible, I'd like to make as little changes to the core files as possible.

Also, I have this ranking list limited to 10 and if the other products have 0 quantity sold, then they will automatically be sorted alphabetically. Same goes if for example 2 products have the same amount sold.

After literally more than 8 hours of trying to figure this out. I've come up with some sort of workaround (at least it seems to work for my case), the code surely need a lot of improvement so I'd be glad to accept any modifications and suggestions to my answer. Here's the code I came up with:

$filler = array();

$productCollection = Mage::getResourceModel('reports/product_collection')
            ->addAttributeToSelect('*')
            ->addAttributeToFilter('type_id', 'configurable')
            ->addOrderedQty()
            ->setOrder('ordered_qty', 'desc')
            ->setPage(1, 10);

foreach($productCollection as $product):
    echo "name:".$product->getName()." - qty:".(int)$product->ordered_qty."<br/>";
    array_push($filler, $product->getId());
endforeach;

if(count($productCollection) < 10):
    $add = 10 - count($productCollection);

    $fillCollection = Mage::getResourceModel('reports/product_collection')
            ->addAttributeToSelect('*')
            ->addAttributeToFilter('type_id', 'configurable')
            ->setOrder('name', 'desc');

    foreach($fillCollection as $item): 
        if(in_array($item->getId(), $filler)):
        else:
            if($add > 0):
                echo "name:".$item->getName()." - qty: 0 <br/>";
                $add = $add - 1;
            endif;
        endif;
    endforeach;
endif;  
unset($filler);

So the basic idea of this is I get the collection for products with orders only since as it appears, products with 0 orders are not retrieved. After that, I get the number of items I still need to display 10 products on my ranking. Then, I get another collection of products and echo them as long as there's still less than 10 products displayed. I used the filler array to make sure that products already called by the first collection are not displayed. Given this code, I now have a ranking of best selling products in my magento site.

Check this solution:

I found that configurable product sales are being summed correctly but aren't being included in the results; their child products appear instead. My solution was to include configurable products, do a left join on the catalog_product_super_link table, and filter out anything that has a parent_id . Here are the changes you'll need to make:

Collection.php:

    public function addOrderedQty($from = '', $to = '', $getComplexProducts=false, $getComplexChildProducts = true, $getRemovedProducts = true)
    {
        $qtyOrderedTableName = $this->getTable('sales/order_item');
        $qtyOrderedFieldName = 'qty_ordered';

        $productIdFieldName = 'product_id';

        if (!$getComplexProducts) {
            $compositeTypeIds = Mage::getSingleton('catalog/product_type')->getCompositeTypes();
            $productTypes = $this->getConnection()->quoteInto(' AND (e.type_id NOT IN (?))', $compositeTypeIds);
        } else {
            $productTypes = '';
        }

        if ($from != '' && $to != '') {
            $dateFilter = " AND `order`.created_at BETWEEN '{$from}' AND '{$to}'";
        } else {
            $dateFilter = "";
        }

        $this->getSelect()->reset()->from(
            array('order_items' => $qtyOrderedTableName),
            array(
                'ordered_qty' => "SUM(order_items.{$qtyOrderedFieldName})",
                'order_items_name' => 'order_items.name'
            )
        );

         $_joinCondition = $this->getConnection()->quoteInto(
                'order.entity_id = order_items.order_id AND order.state<>?', Mage_Sales_Model_Order::STATE_CANCELED
         );
         $_joinCondition .= $dateFilter;
         $this->getSelect()->joinInner(
            array('order' => $this->getTable('sales/order')),
            $_joinCondition,
            array()
         );

         // Add join to get the parent id for configurables
         $this->getSelect()->joinLeft(
             array('cpsl' => $this->getTable('catalog/product_super_link')),
             'cpsl.product_id = order_items.product_id',
             'cpsl.parent_id'
         );

        if(!$getComplexChildProducts)
            $this->getSelect()->having('parent_id IS NULL');

        if($getRemovedProducts)
        {
             $this->getSelect()
                ->joinLeft(array('e' => $this->getProductEntityTableName()),
                    "e.entity_id = order_items.{$productIdFieldName} AND e.entity_type_id = {$this->getProductEntityTypeId()}{$productTypes}")
                ->group('order_items.product_id');
        }
        else
        {
            $this->getSelect()
                ->joinInner(array('e' => $this->getProductEntityTableName()),
                    "e.entity_id = order_items.{$productIdFieldName} AND e.entity_type_id = {$this->getProductEntityTypeId()}{$productTypes}")
                ->group('e.entity_id');
        }


        $this->getSelect()->having('ordered_qty > 0');

        // This line is for debug purposes, in case you'd like to see what the SQL looks like
        // $x = $this->getSelect()->__toString();

        return $this;
    }

List.php - Find the following two lines...

$bestsellers->addOrderedQty($startDate, $todayDate, true);
$bestsellers->addOrderedQty('', '', true);

... and change them to:

$bestsellers->addOrderedQty($startDate, $todayDate, true, false, false);
$bestsellers->addOrderedQty('', '', true, false, false);

My changes added two new optional parameters, which both default to true , as to not break existing functionality.

  • When $getComplexChildProducts is set to false , all child items of the configurable product will be removed from the results.
  • $getRemovedProducts determines whether or not previously ordered products (which have since been deleted from Magento) should also appear.

Please note that your report statistics will need to be up-to-date in order to get accurate results.

Source and acknowledgements: https://stackoverflow.com/a/8419579/1136132

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM