4

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.

  • One quesiton... you want your applyTierPrice method to run after applying the custom price or before it? Or in case there is a custom price filled in to not call the applyTierPrice method? – Marius Apr 19 at 12:17
  • exactly, i would not call applyTierPrice if there is a custom price filled. – wdarking Apr 19 at 15:03
  • 2
    Cant you just check in your method if the product already has a custom price? If it does just do nothing – Marius Apr 19 at 16:45
  • Yes I can! Actually this is part of the intended solution. The problem is that I'm applying the tier price as custom price on the quote item. The tier price can change based on qty of products of a specific category. If the tier price changes, I need to re-apply the correct tier price on products, and by using the custom price system, this solution would not work because the first tier price would be already applied and would not pass the check statement to apply any other tier price, because it's already filled. That's the reason for the idea of change the item price instead of custom price. – wdarking Apr 22 at 18:06
0

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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