Изменить ставку налога на товары в корзине и пересчитать

31

У меня есть категория продуктов, для которых (по закону) необходимо изменить налоговую ставку, когда вы заказываете больше определенного количества. Я расширил различные налоговые модели, чтобы это работало, когда вы добавляете новый продукт в корзину, но у меня возникают проблемы, когда пользователь обновляет количества в корзине или добавляет дополнительные продукты, которые превышают пороговое значение, уже находящееся в корзине. количество.

Проблема 1:

Прежде всего, я не на 100% какое событие (я) наблюдаю. Я пробовал следующее;

checkout_cart_save_after(на основании этого -> https://stackoverflow.com/questions/14362702/magento-programatics-update-cart-via-event )

checkout_cart_update_items_after(на основании этого -> https://stackoverflow.com/questions/5104482/programmatics-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();

Это позволяет мне обновлять каждый элемент цитаты, когда я выполняю итерацию (я считаю, что использую магические сеттеры, так как не могу найти соответствующие методы). Я надеялся, что смогу обновить идентификатор класса налога для позиции цитаты, а затем пересчитать налоги. Если я использую следующее (где $ 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);

Мои изменения не были сохранены, изменение позиции котировки было сброшено, а итоги корзины не были пересчитаны. Начинаю задумываться, может ли решение этой проблемы найти высокое здание, с которого можно спрыгнуть.

McNab
источник
Пожалуйста, кто-нибудь поможет мне решить эту проблему: stackoverflow.com/questions/27978781/… спасибо.
Сатист

Ответы:

35

Мое предложение состояло бы в том, чтобы назначить наблюдателя на sales_quote_collect_totals_beforeсобытие, которое запускается в Mage_Sales_Model_Quote::collectTotalsметоде, прежде чем он начнет общий процесс сбора. Затем внутри этого метода наблюдателя выполните итерацию элементов предложения и измените класс налога для (уже загруженного) объекта продукта, который вы можете извлечь из элемента предложения.

После того, как вы установите информацию об объекте продукта, что бы вы ни делали, НЕ пытайтесь сохранить ее в базе данных. Устанавливая необходимый класс налога для объекта продукта в памяти, будет достаточно, чтобы в Mage_Tax_Model_Sales_Total_Quote_Taxпикапе была обнаружена логика сбора итогов, на каком классе налога он должен основывать свои вычисления. Сохранение продукта (как вы, похоже, пытаетесь это сделать в приведенном выше примере кода) вызовет серьезные проблемы с производительностью, создаст условия гонки в процессе вычислений и просто не является хорошей практикой.

Причина, по которой события, с которыми вы пытаетесь работать, не позволяют вам выполнить то, что вы пытаетесь выполнить, состоят в том, что все они следуют после общего расчета, процесс, который запускается только один раз до сохранения предложения.

Стоит отметить, что процесс сбора итогов заключается в том, что после запуска, не выполняя дополнительную работу, вы не сможете вызывать его снова, чтобы выполнить его пересчет на основе изменений, внесенных вами в элементы предложения. Посмотрите на эту связку, которую я взял из серии блогов, недавно созданной моим коллегой по процессу сбора итогов:

Теперь, когда вы понимаете, что происходит в процессе сбора итогов, вам может быть удобно или необходимо позвонить напрямую. Прежде чем вы начнете чувствовать себя уверенно, используя collectTotals для своих собственных целей, имейте в виду следующее правило:

Товары не могут быть добавлены в цитату после запуска collectTotals!

, , , если кешированные пункты адресов не очищены.

Практически каждый метод "общей" модели модели полагается на выбор элементов кавычек с адреса и их циклический просмотр. При первом запуске getAllItems по адресу в кавычке коллекция элементов фактически кэшируется уникальным ключом, и именно эта коллекция кэшируется при последующих вызовах.

Если у вас есть подсказка для того, чтобы по-настоящему погрузиться в глубины того, как работает процесс сбора итогов, вы можете ознакомиться с первой из четырех серий статей по сбору итогов здесь для более подробного прочтения: Раскрытие коллекций Magento сборник: Введение

Подводя итог, вам нужно перехватить событие, которое запускается до процесса сбора итогов (и до вызова getAllItems по адресам котировок), чтобы изменения, которые вы вносите в элементы, использовались сборщиками итогов. Я не проверял, что предлагаемое sales_quote_collect_totals_beforeсобытие запускается перед любыми вызовами getAllItemsпо указанному адресу, но я почти уверен, что оно будет работать для того, что вам нужно. Но если нет, надеюсь, я предоставил вам достаточно контекста, чтобы выяснить, какое событие вам нужно отловить, чтобы оно заработало.

davidalger
источник
Этот ответ намного превосходит то, на что я надеялся. Отлично, спасибо, что нашли время. Фантастический ответ.
Макнаб
Argh! Потратив весь день на это и не заставляя его работать, я наконец понял, что это была плохо переписанная модель в другом месте модуля. Это отлично работает, и я многому научился, спасибо еще раз Дэвид.
Макнаб
@ McNab Рад слышать, что у вас это работает. Определенно одна из более сложных областей Magento, с которой мы имеем дело. :)
Давидгер
+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, чтобы найти кол-во, добавленное в корзину.

PandaWebStudio
источник
Спасибо за это, полезно знать - я понимаю, основываясь на ответе @ davidalger, что мне не нужно сейчас изменять налоговый класс продукта, а модель котировок. Приятно знать, хотя.
Макнаб
Ну, вы можете изменить класс налога для элемента цитаты, у вас также есть доступ в событии к объекту quoteItem.
PandaWebStudio
Ах, хорошо, - я неправильно понял. Спасибо за разъяснение :)
McNab
@PandaWebStudio, как установить пользовательскую сумму налога для элемента цитаты? вот мой вопрос, magento.stackexchange.com/questions/274520/…
Джафар Пинджар
2

Возможно, попытка изменить налоговый класс может оказаться не лучшим подходом. Почему бы не создать аналогичный продукт для тех продуктов, которые используют более высокий налоговый класс и установить минимальное количество в корзине для этого продукта. Затем использовать, checkout_cart_update_items_afterчтобы обменять продукты на основе общего количества в корзине?

Это определенно не «лучшая практика», но она может помочь вам мыслить в другом направлении.

В качестве альтернативы попробуйте настроить что-нибудь с http://www.mageworx.com/multi-fees-magento-extension.html, где вы добавляете «плату» за дополнительный налог. На самом деле это может быть более хороший способ сделать это, но он не будет отображаться в итоговых суммах налога, а скорее в виде строки итогового дополнительного заказа.

Сандер Мангель
источник
Спасибо за ответ, Сандер. Это хорошая идея, и я не думал об этом. Я скажу вам, почему мне это не нравится - все базовые продукты работают, хотя в пакете Unirgy uMarketplace, и было огромной задачей, чтобы получить его там, где он работает, как сайт сравнения цен. Я думаю, что это может быть большая работа. Если я не смогу обновить этот пункт цитаты, мне придется посмотреть на него.
Макнаб
Черт, я даже не могу высказать ваш ответ, так как потратил всю свою репутацию на эту награду! +1 :) Буду голосовать, когда я получу еще.
Макнаб
хаха нет проблем, я понимаю проблему, и это не будет хорошим решением для дела. Тогда я бы, наверное, выбрал мультифайсы, это более «чистое» решение
Сандер Мангель
FWIW, я бы не предложил этот маршрут ... хотя бы потому, что он сделал бы учет продаж и отслеживание запасов потенциальным кошмаром. Как сказал ОП, это не лучшая практика, но я добавлю: это вызовет больше проблем, чем решит.
Давидгер
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);
    }
 }

Я надеюсь, что это будет работать определенно

Mage2Solutions
источник