Modifica l'aliquota fiscale sugli articoli di preventivo del carrello e ricalcola


31

Ho una categoria di prodotti che (legalmente) devono cambiare l'aliquota fiscale quando ordini più di un determinato quantitativo. Ho esteso i vari modelli fiscali per farlo funzionare quando aggiungi un nuovo prodotto al carrello, ma sto riscontrando problemi quando l'utente aggiorna le quantità nel carrello o aggiunge altri prodotti che ribaltano le quantità già presenti nel carrello oltre la soglia quantità.

Problema 1:

Prima di tutto, non sono al 100% quale evento (i) da osservare. Ho provato quanto segue;

checkout_cart_save_after(basato su questo -> https://stackoverflow.com/questions/14362702/magento-programmatic-update-cart-via-event )

checkout_cart_update_items_after(basato su questo -> https://stackoverflow.com/questions/5104482/programmatical-add-product-to-cart-with-price-change )

sales_quote_save_before(basato su questo -> https://stackoverflow.com/questions/7638858/magento-recalculate-cart-total-in-observer )

Problema 2:

Sono in grado di accedere agli articoli di preventivo dal carrello, ci sono molti modi per farlo, a quanto pare. Sono anche in grado di scorrere i singoli articoli nel carrello, aggiornare le proprietà di tali articoli e quindi salvare gli articoli (almeno temporaneamente). Tuttavia, non sono quindi in grado di salvare il preventivo e ricalcolare le tasse alla cassa.

Parte del motivo è che mentre posso accedere al preventivo del carrello, non sono sicuro del metodo da utilizzare per poterlo scrivere.

Quello che ho provato:

Quello che ho provato in termini di accesso al contenuto del carrello è dipeso dall'evento che ho osservato ma ho provato tutto quanto segue;

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

Quello che sembra almeno consentirmi di accedere al preventivo, scorrerli e aggiornare gli articoli è

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

Questo mi permette di aggiornare ogni elemento di preventivo quando eseguo l'iterazione (credo di usare setter magici in quanto non riesco a trovare alcun metodo corrispondente). Speravo di poter aggiornare l'ID della classe di imposta per l'articolo di preventivo e quindi ricalcolare le tasse. Se utilizzo quanto segue (dove $ taxClassId è diverso da quello già utilizzato da ciascun elemento di preventivo);

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

E quindi registra i risultati;

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

Indica che ho effettivamente aggiornato questo articolo di preventivo e modificato l'ID fiscale. Tuttavia, se poi seguo e provo a salvare il preventivo modificato;

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

E quindi eseguire nuovamente il debug;

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

Le mie modifiche non sono state salvate, la modifica dell'articolo preventivo è stata ripristinata e i totali del carrello non vengono ricalcolati. Iniziare a chiedersi se trovare un edificio alto per saltare potrebbe essere la soluzione per questo.


per favore qualcuno mi aiuti a risolvere questo: stackoverflow.com/questions/27978781/… grazie.
sabato

Risposte:


35

Il mio suggerimento sarebbe di mettere un osservatore sales_quote_collect_totals_beforesull'evento che viene attivato nel Mage_Sales_Model_Quote::collectTotalsmetodo prima che inizi il processo di raccolta totale. Quindi dall'interno di questo metodo osservatore, itera gli articoli di preventivo e modifica la classe di imposta sull'oggetto prodotto (già caricato) che puoi recuperare dall'elemento di preventivo.

Dopo aver impostato le informazioni sull'oggetto prodotto, qualunque cosa tu faccia, NON provare a salvarle nel database. Avere la classe fiscale impostata come necessario sull'oggetto prodotto in memoria sarà abbastanza buona da avere la logica dei totali di raccolta trovata nel Mage_Tax_Model_Sales_Total_Quote_Taxpickup su quale classe fiscale dovrebbe basare i suoi calcoli. Il salvataggio del prodotto (come sembra stia provando a fare nel precedente esempio di codice) causerà importanti problemi di prestazioni, creerà condizioni di gara nel processo di calcolo e semplicemente non è una buona pratica.

Il motivo per cui gli eventi con cui si sta tentando di lavorare non consentono di realizzare ciò che si sta tentando di realizzare è perché vengono tutti dopo il calcolo totale, un processo che viene eseguito solo una volta prima del salvataggio del preventivo.

Vale la pena sottolineare che il processo di raccolta dei totali è che una volta eseguito, senza fare un lavoro extra, non è possibile richiamarlo per farlo ricalcolare in base alle modifiche apportate alle voci di preventivo. Guarda questo tie-bit che ho preso dalla serie del blog un mio collega recentemente messo insieme nel processo di raccolta dei totali:

Ora che hai capito cosa succede durante il processo di raccolta dei totali, potresti trovare conveniente o necessario chiamarlo direttamente da solo. Prima di iniziare a sentirti troppo sicuro con l'uso di collectTotals per i tuoi scopi, tieni a mente le seguenti regole:

Non è possibile aggiungere prodotti al preventivo dopo l'esecuzione di collectTotals!

. . . a meno che le cache degli articoli degli indirizzi di preventivo non vengano cancellate.

Quasi tutti i metodi di "raccolta" di ogni modello totale si basano sul recupero degli articoli di preventivo dall'indirizzo e sul loro ciclo continuo. La prima volta che getAllItems viene eseguito su un indirizzo di preventivo, la raccolta di elementi viene effettivamente memorizzata nella cache con una chiave univoca ed è questa raccolta memorizzata nella cache che viene restituita nelle chiamate successive.

Se ti capita di avere una vaga idea di immergerti davvero nelle profondità di come funziona il processo di raccolta dei totali, puoi dare un'occhiata alla prima delle quattro serie di parti sulla raccolta totale qui per una lettura più approfondita: Unraveling's Magento's collectTotals: Introduzione

Per riassumere, è necessario rilevare un evento che viene eseguito prima del processo di raccolta dei totali (e prima che getAllItems venga chiamato sugli indirizzi delle offerte) in modo che le modifiche apportate agli articoli vengano utilizzate dai collezionisti totali. Non ho verificato che l' sales_quote_collect_totals_beforeevento suggerito venga eseguito prima di qualsiasi chiamata getAllItemsall'indirizzo di preventivo, ma sono quasi certo che funzionerà per quello che ti serve. Se no, spero di averti fornito un contesto sufficiente per capire quale evento devi catturare per farlo funzionare.


Questa risposta va ben oltre ciò che speravo. Fantastico, grazie per aver dedicato del tempo. Risposta fantastica.
McNab,

Argh! Dopo aver speso tutto il giorno su questo e non averlo fatto funzionare, ho finalmente capito che si trattava di un modello mal riscritto altrove nel modulo. Funziona perfettamente e ne ho imparato un sacco, grazie ancora David.
McNab,

@McNab Sono contento di sentire che hai funzionato. Sicuramente una delle aree più complesse di Magento in questione. :)
davidalger,

+1 sul blog collegato. L'ho trascurato le prime volte che ho letto. È di grande aiuto
pspahn

6

C'è un altro evento: sales_quote_item_set_productin Mage_Sales_Model_Quote_Item :: setProduct

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

È possibile modificare la classe di imposta sul prodotto utilizzando questo evento. Utilizzare il metodo quoteItem getQty per trovare la quantità aggiunta al carrello.


Grazie per questo, è utile sapere - mi rendo conto in base alla risposta di @ davidalger che non dovrei modificare la classe fiscale del prodotto ora, ma il modello di preventivo. Buono a sapersi però.
McNab,

Bene, puoi effettivamente modificare la classe fiscale dell'elemento preventivo, puoi anche accedere all'evento quoteItem nell'evento.
PandaWebStudio

Ah ok - ho capito male. Grazie per il chiarimento :)
McNab il

@PandaWebStudio, come impostare un importo fiscale personalizzato per l'articolo di preventivo? ecco la mia domanda, magento.stackexchange.com/questions/274520/…
pinjar

2

Forse provare a cambiare la classe di tassazione potrebbe non essere l'approccio migliore. Perché non creare un prodotto simile per quei prodotti che utilizzano la classe fiscale più elevata e impostano una quantità minima nel carrello per quel prodotto. Quindi utilizzare il checkout_cart_update_items_afterper scambiare prodotti in base alla quantità totale nel carrello?

Questa non è sicuramente una "best practice", ma potrebbe aiutarti a pensare in un'altra direzione.

In alternativa, prova a impostare qualcosa con http://www.mageworx.com/multi-fees-magento-extension.html in cui aggiungi una "tassa" per la tassa aggiuntiva. Questo potrebbe effettivamente essere un modo migliore per farlo, ma non verrà visualizzato nei totali delle imposte, più come una linea totale di ordini aggiuntivi.


Grazie per la risposta Sander. È una buona idea e non ci avevo pensato. Ti dirò perché non me lo immagino: i prodotti sottostanti sono tutti in esecuzione tramite la suite uMarketplace di Unirgy ed è stato un mostro di un compito portarlo dove si trova mentre funziona come un sito di confronto dei prezzi. Penso che potrebbe essere un grande lavoro. Se non riesco a ottenere questo articolo aggiornato, dovrò comunque guardarlo.
McNab,

Accidenti, non posso nemmeno votare la tua risposta dato che ho speso tutta la mia reputazione in questa generosità! +1 :) Valuterà quando ne avrò un po 'di più.
McNab,

haha no problem, capisco il problema e questa non sarebbe una buona soluzione per il caso. Probabilmente andrei con i multifees allora, questa è una soluzione "più pulita"
Sander Mangel

FWIW, non suggerirei questo percorso ... se non altro perché renderebbe la contabilità delle vendite e il monitoraggio delle scorte un potenziale incubo. Come ha detto l'OP, non è una buona pratica, ma aggiungerò: causerà più problemi di quanti ne risolva.
davidalger,

0

Usa questo <sales_quote_collect_totals_before>

e nella tua funzione piace

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

Spero che funzionerà sicuramente

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.