修改购物车报价项目的税率并重新计算


31

我有一类产品,当您订购的数量超过一定数量时,(法律上)需要更改其税率。当您将新产品添加到购物车时,我扩展了各种税收模型以使其工作,但是当用户更新购物车中的数量或添加其他产品以使购物车中的数量超过阈值时,我遇到了问题量。

问题一:

首先,我不是100%要观察哪个事件。我尝试了以下方法;

checkout_cart_save_after(基于此-> https://stackoverflow.com/questions/14362702/magento-programatically-update-cart-via-event

checkout_cart_update_items_after(基于此-> https://stackoverflow.com/questions/5104482/programmatically-add-product-to-cart-with-price-change

sales_quote_save_before(基于此-> https://stackoverflow.com/questions/7638858/magento-recalculate-cart-total-in-observer

问题2:

我能够从购物车中访问报价项目,看来有很多方法可以做到。我还能够遍历购物车中的各个项目,更新这些项目的属性,然后保存这些项目(至少是暂时的)。但是,我那时无法保存报价并在结帐时重新计算税款。

部分原因是,尽管我可以访问购物车报价,但是我不确定使用哪种方法能够写入购物车报价。

我尝试过的

关于访问购物车内容的尝试取决于我观察到的事件,但我尝试了以下所有方法:

1. 
$item = $observer->getQuoteItem;

2.
$cart = Mage::getSingleton('checkout/cart');
$cartItems = $cart->getCart()->getItems(); 

3.
$cart = $observer->getData('cart');
$quote = $cart->getData('quote');
$cartItems = $quote->getAllVisibleItems();

4.
$cartHelper = Mage::helper('checkout/cart');
$cartItems = $cartHelper->getCart()->getItems(); 

5.
$quote = Mage::getModel('checkout/cart');
$cartItems = $quote->getItems(); 

似乎至少允许我访问报价,遍历报价并更新商品的商品是

6.
$quote = Mage::getSingleton('checkout/session')->getQuote();
$cartItems = $quote->getAllVisibleItems();

这使我可以在迭代时更新每个报价项(我相信使用魔术设置器,因为我找不到任何相应的方法)。我希望能够更新报价项目的税种ID,然后重新计算税种。如果我使用以下内容(其中$ taxClassId与每个引用项目已使用的内容不同);

$item->setTaxClassId( $taxClassId );
$item->getProduct()->setIsSuperMode(true);
$item->save;

然后记录结果;

Mage::log($item->debug(), null,'taxobserver.log', true);

它表明我确实已经更新了该报价项目并更改了税号。但是,如果我随后继续尝试并保存修改后的报价;

$quote->setTotalsCollectedFlag(false)->collectTotals();
$quote->save();     

然后再次调试;

Mage::log($item->debug(), null,'taxobserver.log', true);

我的更改尚未保存,报价项目更改已重置,购物车总额未重新计算。开始怀疑是否找到跳高的建筑物可能是解决这一问题的方法。


请任何人帮我解决这个问题: stackoverflow.com/questions/27978781/… 谢谢。
讽刺意味

Answers:


35

我的建议是请一名观察员参加 sales_quote_collect_totals_before是在Mage_Sales_Model_Quote::collectTotals启动整个收集过程之前该方法中触发事件。然后从此观察者方法内部,迭代报价项目,并更改可从报价项目检索的(已加载)产品对象的税种。

在产品对象上设置信息之后,无论做什么,都不要尝试将其保存到数据库中。在内存中根据需要在产品对象上设置税种将足以使收集总计逻辑在Mage_Tax_Model_Sales_Total_Quote_Tax取件中它应该基于该税种进行计算。保存产品(就像您在上面的代码示例中试图做的那样)将导致严重的性能问题,将在计算过程中创建竞争条件,这绝对不是一个好习惯。

您尝试使用的事件无法使您完成想要完成的事情的原因是,这些事件都发生在总计算之后,该过程仅在保存报价之前运行一次。

值得一提的是,“收集总计”流程一旦运行就无需做额外的工作,就无法再次调用它以使其根据对报价项目所做的更改进行重新计算。请参阅我从博客系列中获得的一个领带,这是我最近收集的汇总信息,用于收集总计过程:

既然您了解了总计收集过程中发生的情况,您可能会发现方便或有必要直接直接调用它。但是,在开始为自己的目的使用collectTotals感到自信之前,请记住以下规则:

在运行collectTotals之后,不能将产品添加到报价中!

。。。除非清除报价地址的项目缓存。

几乎每个模型的“收集”方法都依赖于从地址中获取报价项并对其进行循环。第一次在引用地址上运行getAllItems时,实际上使用唯一键缓存了item集合,并且此缓存的集合在后续调用中返回。

如果您确实确实想深入了解“收集总计”流程的工作原理,则可以在此处查看“收集总计”的四个部分系列中的第一个,以进行更深入的阅读:阐明Magento的collectTotals:简介

总而言之,您需要捕获一个在收集总计过程之前(以及在报价地址上调用getAllItems之前)运行的事件,以便您对项目进行的更改将被总计收集者使用。我尚未验证建议的sales_quote_collect_totals_before事件getAllItems是否在引用地址上的任何调用之前运行,但是我几乎可以肯定它会满足您的需求。但是,如果没有,希望我已经为您提供了足够的背景信息,以确定您需要捕获哪个事件才能使其正常工作。


这个答案远远超出了我的期望。太棒了,谢谢您抽出宝贵的时间。很棒的答案。
McNab 2013年

啊!在花了整整一天时间并没有使它投入使用之后,II终于意识到,它归结为模块中其他地方的严重重写模型。这非常有效,我已经从中学习了很多负载,再次感谢David。
McNab

@McNab很高兴听到您正在使用它。绝对是Magento处理的最复杂区域之一。:)
davidalger

在链接的博客上+1。我读完前几次都忽略了它。这是一个很大的帮助。
pspahn

6

还有另一个事件:sales_quote_item_set_product在Mage_Sales_Model_Quote_Item :: setProduct中

Mage::dispatchEvent('sales_quote_item_set_product', array(
            'product' => $product,
            'quote_item'=>$this
        ));

您可以使用此事件修改产品税类。使用quoteItem getQty方法查找添加到购物车的数量。


谢谢您,有必要知道-我基于@davidalger的回答意识到,我现在不应该修改产品的税种,而应该修改报价模型。很高兴知道。
McNab

好了,您实际上可以修改报价项目税种,您还可以在事件中访问quoteItem对象。
PandaWebStudio

好的-我误会了。感谢您的澄清:)
McNab

@PandaWebStudio,如何设置报价项目的自定义税额?这是我的问题,magento.stackexchange.com
贾法尔·平贾尔

2

也许尝试更改税种可能不是最好的方法。为什么不为那些使用较高税种的产品创建类似的产品,并为该产品设置最小的购物车数量。然后checkout_cart_update_items_after根据购物车中的总数量使用来交换产品?

这绝对不是“最佳实践”,但可以帮助您从另一个方向思考。

另外,也可以尝试使用http://www.mageworx.com/multi-fees-magento-extension.html进行设置,并在其中添加“费用”作为额外税款。这实际上可能是一种更好的方法,但是它不会显示在税收总额中,更多地显示为额外的订单总额行。


感谢桑德的回复。这是个好主意,我没想到。我会告诉你为什么我不喜欢它-基础产品都通过Unirgy的uMarketplace套件运行,并且要使其像价格比较站点那样运转,将它推向原地是一项艰巨的任务。我认为这可能是一项艰巨的工作。如果我无法更新此报价项目,我将不得不对其进行查看。
McNab

该死,我已经把所有代表都花在了这笔悬赏上,我什至无法支持你的答案!+1 :)当我得到更多时,我会投票赞成。
McNab 2013年

哈哈,没问题,我了解这个问题,对于这种情况,这不是一个好的解决方案。那时我可能会选择杂费,这是一个“更清洁”的解决方案
Sander Mangel

FWIW,我不建议使用此路线…只是因为它会使销售核算和跟踪库存成为潜在的噩梦。正如OP所说,这不是最佳实践,但我要补充一点:这将带来比解决方法更多的麻烦。
davidalger

0

用这个 <sales_quote_collect_totals_before>

在你的功能上喜欢

 public function quoteCollectTotalsBefore(Varien_Event_Observer $observer)
    $quote = $observer->getQuote();
    foreach ($quote->getAllItems() as $item)
    {
        $product = $item->getProduct();
        $product->setTaxClassId($product_tax_class_id);
    }
 }

我希望这一定会起作用

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.