Magento – Update quote item price without using custom price

magento-1.9quotequoteitem

We are developing a custom module which applies custom tier prices by product category. Our solution works on frontend checkout so far and consists of observing the sales_quote_item_set_product event and running custom code that checks other quote items of a given category to apply a custom price.

The function responsible for applying the custom price to the item is below:

public function applyTierPrice($item, $tier)
{
    $oldPrice = (float)$item->getProduct()->getPrice();
    $newPrice = (float)$tier['discount'];
    if ($tier['type'] === 'percent') {
        $newPrice = $oldPrice - $oldPrice * ($tier['discount'] / 100);
    }

    $item->setCustomPrice($newPrice);
    $item->setOriginalCustomPrice($newPrice);

    $item->getProduct()->setIsSuperMode(true);
    $item->save();
}

This solution becomes a problem on order creation by admin panel, because there is a field where you can set manually the item price, and apparently it also uses the methods setCustomPrice().

magento-se-issue-scrot

So, when we add a product to the quote, it runs the custom applyTierPrice() method. But if I want to use that custom price field, our solution will override that field input, and we lose the default custom price functionality.

So i was thinking of a solution where we set the quote item price by calling $item->setPrice(), and not messing with a custom price.

public function applyTierPrice($item, $tier)
{
    $oldPrice = (float)$item->getProduct()->getPrice();
    $newPrice = (float)$tier['discount'];
    if ($tier['type'] === 'percent') {
        $newPrice = $oldPrice - $oldPrice * ($tier['discount'] / 100);
    }

    // $item->setCustomPrice($newPrice);
    // $item->setOriginalCustomPrice($newPrice);

    $item->setPrice(42);

    $item->getProduct()->setIsSuperMode(true);
    $item->save();
}

$quote->collectTotals() and $quote->save() are being called after this function.

It updates the price field on the sales_flat_quote_item table, but the change doesn't reflect on subtotal, row total, order total calculations.

How can I solve it? Any advice is appreciated.

edit1: applyTierPrice method will not be called if there is a custom price filled.

Best Answer

Since the quote item price is retrieved by calling the getFinalPrice, we are overriding the getFinalPrice method.

It's not a clean/final solution, but we managed partially solve our problem so far by overriding the getFinalPrice from Mage_Catalog_Model_Product_Type_Price class. The custom code would be called only on quotes created by admin panel. The frontend quote (checkout) will continue using the quote item custom price.

<?php
class Wdarking_CPDiscount_Model_Catalog_Product_Type_Price extends Mage_Catalog_Model_Product_Type_Price
{
    /**
     * Retrieve product final price
     *
     * @param float|null $qty
     * @param Mage_Catalog_Model_Product $product
     * @return float
     */
    public function getFinalPrice($qty = null, $product)
    {
        $finalPrice = parent::getFinalPrice($qty, $product);

        // custom code
        $adminQuote = Mage::getSingleton('adminhtml/session_quote')->getQuote();

        if (!$adminQuote->getId()) {
            return $finalPrice;
        }

        $observerFlag = "wdk_cpd_product_flag:{$adminQuote->getId()}:{$product->getId()}";

        if (Mage::registry($observerFlag)) {
            return $finalPrice;
        }

        Mage::register($observerFlag, 1);

        $customFinalPrice = Mage::helper('cpdiscount')->productCpdFinalPrice($adminQuote, $product);

        if ($customFinalPrice) {
            return $customFinalPrice;
        }

        return $finalPrice;
    }
}

This solution have some problems, since we are overriding a method that is called multiple times during the quote proccess. To define the custom price we use the custom helper method productCpdFinalPrice, that iterates the quote items to define a custom price, and calling it from inside getFinalPrice would recursively call getFinalPrice again, leading to a infinite loop. Thats why I'm using the registry to avoid this behavior. The quote iteration in every getFinalPrice also leads to a slow performance of the quote processing. Also the getFinalPrice is defined in another classes like bundled producs, configurable, etc. We should override the method on those classes as well.

And might exist other problems I didn't catch.

This is not the intended solution, but we're using this solution. It partially solved our problem.

Feedback is appreciated.

Related Topic