Modifique a taxa de imposto nos itens de cotação do carrinho e recalcule

31

Tenho uma categoria de produtos que (legalmente) precisam ter sua taxa de imposto alterada quando você está solicitando mais do que uma determinada quantidade. Estendi os vários modelos de impostos para que isso funcione quando você adiciona um novo produto ao carrinho, mas estou com problemas quando o usuário atualiza as quantidades no carrinho ou adiciona produtos adicionais que ultrapassam o limite do carrinho. montante.

Problema 1:

Antes de tudo, não sou 100% dos eventos a serem observados. Eu tentei o seguinte;

checkout_cart_save_after(com base nisso -> https://stackoverflow.com/questions/14362702/magento-programatically-update-cart-via-event )

checkout_cart_update_items_after(com base nisso -> https://stackoverflow.com/questions/5104482/programmatically-add-product-to-cart-with-price-change )

sales_quote_save_before(com base nisso -> https://stackoverflow.com/questions/7638858/magento-recalculate-cart-total-in-observer )

Problema 2:

Consigo acessar os itens de cotação do carrinho, existem várias maneiras de fazer isso ao que parece. Também posso percorrer os itens individuais no carrinho, atualizar as propriedades desses itens e salvá-los (pelo menos temporariamente). No entanto, não consigo salvar a cotação e recalcular os impostos na finalização da compra.

Parte do motivo é que, embora eu possa acessar a cotação do carrinho, não sei ao certo qual método usar para poder escrever nele.

O que eu tentei:

O que eu tentei em termos de acesso ao conteúdo do carrinho dependeu do evento que observei, mas tentei o seguinte;

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(); 

O que parece pelo menos permitir que eu acesse a cotação, execute-a e atualize os itens é

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

Isso me permite atualizar cada item de cotação quando iterar (acredito que usando setters mágicos, pois não consigo encontrar nenhum método correspondente). Esperava poder atualizar o ID da classe de imposto para o item de cotação e recalcular os impostos. Se eu usar o seguinte (onde $ taxClassId é diferente daquele já usado por cada item de cotação);

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

E então registre os resultados;

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

Isso mostra que eu realmente atualizei este item de cotação e alterei a identificação fiscal. No entanto, se eu seguir adiante e tentar salvar a cotação modificada;

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

E então depure novamente;

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

Minhas alterações não foram salvas, a alteração do item de cotação foi redefinida e os totais do carrinho não são recalculados. Começando a pensar se encontrar um prédio alto para pular pode ser a solução para este.

McNab
fonte
por favor alguém me ajude a resolver isso: stackoverflow.com/questions/27978781/… obrigado.
satish

Respostas:

35

Minha sugestão seria colocar um observador no sales_quote_collect_totals_beforeevento disparado no Mage_Sales_Model_Quote::collectTotalsmétodo antes de iniciar o processo total de coleta. Em seguida, de dentro desse método do observador, itere os itens da cotação e altere a classe de imposto no objeto do produto (já carregado) que você pode recuperar do item da cotação.

Depois de definir as informações no objeto do produto, faça o que fizer, NÃO tente salvá-las no banco de dados. A definição da classe de imposto conforme necessário no objeto do produto na memória será suficiente para que a lógica de totais coletados seja encontrada na Mage_Tax_Model_Sales_Total_Quote_Taxcoleta em qual classe de imposto ela deve basear seus cálculos. Salvar o produto (como você parece estar tentando fazer no seu exemplo de código acima) causará grandes problemas de desempenho, criará condições de corrida no processo de cálculo e simplesmente não é uma boa prática.

A razão pela qual os eventos com os quais você está tentando trabalhar não está permitindo que você realize o que está tentando realizar é porque todos vêm após o cálculo total, um processo que só é executado uma vez antes de salvar a cotação.

Vale ressaltar sobre o processo de coletar totais é que, uma vez executado, sem fazer um trabalho extra, você não pode chamá-lo novamente para que ele seja recalculado com base nas alterações feitas nos itens de cotação. Veja este artigo que tirei da série de blogs que um colega meu recentemente montou no processo de coletar totais:

Agora que você entende o que ocorre durante o processo de coleta de totais, pode ser conveniente ou necessário chamá-lo diretamente. Antes de começar a se sentir confiante em usar o collectTotals para seus próprios fins, lembre-se da seguinte regra:

Os produtos não podem ser adicionados à cotação após a execução do collectTotals!

. . . a menos que os caches de itens dos endereços de cotação sejam limpos.

Quase todo método de "coleta" de todo modelo depende de buscar os itens de cotação no endereço e percorrê-los. Na primeira vez em que getAllItems é executado em um endereço de cotação, a coleção de itens é realmente armazenada em cache com uma chave exclusiva e é essa coleção em cache que é retornada nas chamadas subseqüentes.

Se você tem uma idéia de realmente mergulhar nas profundezas de como o processo de coletar totais funciona, você pode conferir a primeira das quatro partes da coleção total aqui para uma leitura mais aprofundada: Desvendando o collectTotals do Magento: Introdução

Para resumir, você precisa capturar um evento que é executado antes do processo de coleta total (e antes que getAllItems seja chamado nos endereços de cotação), para que as alterações feitas nos itens sejam usadas pelo total de coletores. Não verifiquei se o sales_quote_collect_totals_beforeevento sugerido é executado antes de qualquer chamada para o getAllItemsendereço de cotação, mas estou quase certo de que ele funcionará para o que você precisa. Mas, se não, espero que eu tenha fornecido contexto suficiente para você descobrir qual evento você precisa capturar para fazê-lo funcionar.

davidalger
fonte
Essa resposta está muito além do que eu esperava. Brilhante, obrigado por dedicar um tempo. Resposta fantástica.
McNab
Argh! Depois de passar o dia todo nisso e de não fazê-lo funcionar, finalmente percebi que o modelo estava reescrito em outras partes do módulo. Isso funciona perfeitamente e eu aprendi muito com isso, obrigado novamente David.
21413 McNab
@ McNab Fico feliz em saber que você conseguiu. Definitivamente, uma das áreas mais complexas do Magento em tratamento. :)
davidalger
+1 no blog vinculado. Eu a ignorei nas primeiras vezes que li. É uma grande ajuda.
Psp2 #
6

Há outro evento: sales_quote_item_set_productem Mage_Sales_Model_Quote_Item :: setProduct

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

Você pode modificar a classe de imposto do produto usando este evento. Use o método quoteItem getQty para encontrar o qty adicionado ao carrinho.

PandaWebStudio
fonte
Obrigado por isso, é útil saber - compreendo, com base na resposta de @ davidalger, que não deveria modificar a classe de imposto do produto agora, mas o modelo de cotação. É bom saber embora.
21413 McNab
Bem, você pode realmente modificar a classe de imposto do item de cotação, mas também terá acesso no evento ao objeto quoteItem.
PandaWebStudio
Ah ok - eu entendi errado. Obrigado por esclarecer :)
McNab
@PandaWebStudio, como definir o valor do imposto personalizado para o item de cotação? aqui está a minha pergunta, magento.stackexchange.com/questions/274520/…
jafar pinjar
2

Talvez tentar alterar a classe fiscal não seja a melhor abordagem. Por que não criar um produto semelhante para os produtos que usam a classe de imposto mais alta e definem uma quantidade mínima no carrinho para esse produto. Em seguida, use o checkout_cart_update_items_afterpara trocar produtos com base na quantidade total no carrinho?

Definitivamente, essa não é uma 'melhor prática', mas pode ajudá-lo a pensar em outra direção.

Como alternativa, tente configurar algo com http://www.mageworx.com/multi-fees-magento-extension.html, onde você adiciona uma "taxa" pelo imposto extra. Na verdade, essa pode ser uma maneira mais agradável de fazê-lo, mas não aparecerá nos totais dos impostos, mais como uma linha total do pedido extra.

Sander Mangel
fonte
Obrigado pela resposta Sander. É uma boa ideia e eu não tinha pensado nisso. Vou lhe dizer por que não gosto disso - todos os produtos subjacentes estão sendo executados no pacote uMarketplace da Unirgy e tem sido uma tarefa difícil levá-lo aonde está, pois está funcionando como um site de comparação de preços. Eu acho que pode ser um grande trabalho. Se eu não conseguir atualizar esse item de cotação, terei de examiná-lo.
21413 McNab
Porra, eu não posso nem votar na sua resposta, já que gastei todo o meu representante nessa recompensa! +1 :) Será votado quando tiver mais.
McNab
haha não tem problema, entendo o problema e isso não seria uma boa solução para o caso. Provavelmente eu iria com as multíplices na época, essa é uma solução 'limpa'
Sander Mangel
FWIW, eu não sugeriria essa rota ... apenas porque tornaria a contabilidade de vendas e o rastreamento de estoque um pesadelo em potencial. Como o OP disse, não é uma prática recomendada, mas vou acrescentar: Causará mais problemas do que resolveria.
Davidalger
0

Usa isto <sales_quote_collect_totals_before>

e na sua função gosta

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

Espero que isso funcione definitivamente

Mage2Solutions
fonte