Question

Context: we have a project which uses M2E so our client can sell on eBay. For easy reference, we've added custom columns to the product grid in the admin panel so that the eBay item ID is displayed next to the other product details.

The above all works fine, no problems.

The problem is that occasionally eBay issues a new item ID for an item for some reason or another, and then we have two eBay item IDs for the same product. This has just been flagged as an issue because when we use joinField to add the item ID to the product collection, it's grabbing the first ID it finds, not the latest one.

So what we want to do is grab the newest eBay item ID instead of the first one found but I'm struggling to find a way to make this work within Magento. Straight SQL would be no problem, but I'm a little less skilled with Magento DB queries.

This is the code we're using to join the eBay item ID table at present:

$collection->joinField('ebay_item_id', 'm2epro_ebay_item', 'item_id', 'product_id=entity_id', null, 'left');

This is what we tried adding to make it work (no luck):

$collection->addAttributeToSort('m2epro_ebay_item.update_date', 'DESC');

These are the relevant column headings in the table we're joining:

id (row ID)
item_id (eBay item ID)
product_id (Magento product ID)
update_date (last updated)
create_date (creation date)

It could be sorted by any of ID, update_date, or create_date, but I can't get my head around how to get it to do it within the Magento architecture.

So any help or pointers would be appreciated.

Edited to add:

class Digitalsix_CustomGrid_Model_Adminhtml_Observer {

    public function onBlockHtmlBefore(Varien_Event_Observer $observer) {
        $block = $observer->getBlock();
        if (!isset($block)) {
            return;
        }

        switch ($block->getType()) {
            case 'adminhtml/catalog_product_grid':
                $block->addColumn('ebay_item_id', array(
                    'header' => Mage::helper('catalog')->__('Ebay ID'),
                    'width' => '80px',
                    'index' => 'ebay_item_id',
                    'filter' => false,
                ));
                break;
        }
    }

    public function onEavLoadBefore(Varien_Event_Observer $observer) {
        $collection = $observer->getCollection();
        if (!isset($collection)) {
            return;
        }

        if (is_a($collection, 'Mage_Catalog_Model_Resource_Product_Collection')) {
            $collection->getSelect()->group('e.entity_id');

            if (!$collection->fieldAlreadyJoined("ebay_item_id")) {
                $collection->joinField('ebay_item_id', 'm2epro_ebay_item', 'item_id', 'product_id=entity_id', null, 'left');
            }
        }
    }

}
Was it helpful?

Solution

Basically, you've got two options here – there is a third one, but that's not recommended due to bad performance. Both queries shown here should perform well. Which one will be faster is hard to anticipate and depends on your use case.

1. Uncorrelated

public function onEavLoadBefore(Varien_Event_Observer $observer) {
    $collection = $observer->getCollection();
    if (!isset($collection)) {
        return;
    }

    if (is_a($collection, 'Mage_Catalog_Model_Resource_Product_Collection')) {
        $tableAlias = 'mei';
        $select = $collection->getSelect();

        if ( !array_key_exists ( $tableAlias, $select->getPart ( Varien_Db_Select::FROM ) ) )
        {
            $tableName = 'm2epro_ebay_item';
            $productIdFieldName = 'product_id';
            $sortFieldName = 'id';
            $sourceFieldName = 'item_id';
            $targetFieldName = 'ebay_item_id';
            $adapter = $select->getAdapter();

            $select
                ->joinLeft
                (
                    array
                    (
                        $tableAlias =>
                            $adapter
                                ->select()
                                ->from ( array ( $tableAlias => $tableName ) )
                                ->joinInner
                                (
                                    array
                                    (
                                        $tableAlias . 'grouped' =>
                                            $adapter
                                                ->select()
                                                ->from ( $tableName, array ( $productIdFieldName, 'MaxId' => 'MAX(`'.$sortFieldName.'`)' ) )
                                                ->group ( $productIdFieldName )
                                    ),
                                    '`'.$tableAlias.'`.`'.$productIdFieldName.'` = `'.$tableAlias . 'grouped`.`'.$productIdFieldName.'` AND `'.$tableAlias.'`.`'.$sortFieldName.'` = `'.$tableAlias . 'grouped`.`MaxId`',
                                    null
                                )
                    ),
                    '`e`.`entity_id` = `'.$tableAlias.'`.`'.$productIdFieldName.'`',
                    array ( $targetFieldName => $sourceFieldName )
                )
            ;
        }
    }
}

2. Correlated

public function onEavLoadBefore(Varien_Event_Observer $observer) {
    $collection = $observer->getCollection();
    if (!isset($collection)) {
        return;
    }

    if (is_a($collection, 'Mage_Catalog_Model_Resource_Product_Collection')) {
        $select = $collection->getSelect();
        $targetFieldName = 'ebay_item_id';

        $ebayItemIdAlreadyAdded = false;
        foreach ( $select->getPart ( Varien_Db_Select::COLUMNS ) as $column )
        {
            if ( $column[2] == $targetFieldName )
            {
                $ebayItemIdAlreadyAdded = true;
                break;
            }
        }
        if ( !$ebayItemIdAlreadyAdded )
        {
            $tableName = 'm2epro_ebay_item';
            $productIdFieldName = 'product_id';
            $sortFieldName = 'id';
            $sourceFieldName = 'item_id';

            $select
                ->from
                (
                    '',
                    array
                    (
                        $targetFieldName =>
                            $select
                                ->getAdapter()
                                ->select()
                                ->from ( $tableName, $sourceFieldName )
                                ->where ( '`e`.`entity_id` = `'.$tableName.'`.`'.$productIdFieldName.'`' )
                                ->order ( $sortFieldName . ' ' . Varien_Db_Select::SQL_DESC )
                                ->limit ( 1 )
                    )
                )
            ;
        }
    }
}

Instead of building queries this way, you might as well provide a string to improve performance somehow and/or make it more readable. Building e.g. the correlated query in a simpler way looks like

$select
    ->from
    (
        '',
        array
        (
            $targetFieldName =>
                sprintf
                (
                    '(SELECT `%1$s` FROM `%2$s` WHERE `e`.`entity_id` = `%2$s`.`%3$s` ORDER BY `%4$s` DESC LIMIT 1)',
                    $sourceFieldName,
                    $tableName,
                    $productIdFieldName,
                    $sortFieldName
                )
        )
    )
;

NB: fieldAlreadyJoined() has to be refactored depending on the method chosen (as implemented above).

OTHER TIPS

Right, so I have come up with a solution but it's not very elegant and it's going to be database-heavy so I'd still rather have a solution for the collection join. But that said, this is the solution I've come up with for the interim.

Basically, I've scrapped the joinField idea entirely and instead created a custom column renderer for the product grid which fetches the correct eBay item ID from the m2epro_ebay_item table by direct SQL. This works and provides the correct item information but is an additional SQL query for each row of the grid on each page load. Not ideal by a long stretch.

Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top