No es frecuente tener que entrar a pelear con cómo se calculan los totales en Magento (la visualización de los mismos se puede configurar en el adminitrador, como veremos más adelante), pero si nos toca hacerlo, puede ser un poco frustrante si no sabemos por donde nos movemos, sobre todo si no nos damos cuenta de que cálculo y visualización pueden tener diferente orden en una página Magento.
Cómo se calculan los totales en Magento
En los ficheros de configuración de Magento, por ejemplo en:
app/code/core/Mage/Sales/etc/config.xml
Podemos encontrar fragmentos como el siguiente:
<totals> <nominal> <class>sales/quote_address_total_nominal</class> <before>subtotal</before> </nominal> <subtotal> <class>sales/quote_address_total_subtotal</class> <after>nominal</after> <before>grand_total</before> </subtotal> <shipping> <class>sales/quote_address_total_shipping</class> <after>subtotal,freeshipping,tax_subtotal</after> <before>grand_total</before> </shipping> <grand_total> <class>sales/quote_address_total_grand</class> <after>subtotal</after> </grand_total> </totals>
En el mismo, se indica para cada uno de los totalizadores las relaciones «antes de» o «después de», que indican antes y después de qué totalizadores debe realizar Magento el cálculo cada uno de ellos.
Cuando el usuario añade productos al carrito de la compra, Magento crea una instancia, asociada a la sesión del usuario, de la clase:
Mage_Sales_Model_Quote
Dicha instancia es la encargada de almacenar toda la información relacionada con el pedido (todavía sin completar) del usuario. Almacena, entre otras cosas, referencias a la lista de productos, direcciones de facturación y envío, y por supuesto los totales acumulados.
Para realizar el cálculo de los totales del pedido, Magento se apoya en una instancia de de la clase:
Mage_Sales_Model_Quote_Address_Total_Collector
En concreto, podemos ver en una de las primeras líneas de la clase, la línea…
protected $_totalsConfigNode = 'global/sales/quote/totals';
…que corresponde con el nodo de configuración que se utilizará para obtener la lista de totalizadores a aplicar.
Mediante dicha clase, y en el método _getSortedCollectorCodes(), Maegnto obtiene la lista de totalizadores a ejecutar. En esta función además podemos ver el algoritmo que ordena los totalizadores en función de los nodos
Posteriormente, también la clase Quote, crea para cada dirección configurada (recordar que Magento permite múltiples direcciones de envío en los pedidos, aunque poca gente lo utilice), una instancia de la clase:
Mage_Sales_Model_Quote_Address
Al llegar a la página del carrito, Magento, a través de la instancia de la clase Quote, llama para cada una de las direcciones configuradas, al método collectTotals de la clase Address.php.
Este método no hace otra cosa, que calcular los totales, sin considerar a los otros totalizadores, es decir, calcula subtotal, gastos de envío, impuestos y total en función de sus propios parámetros, y sin considerar el resto de totalizadores.
Finalmente, todos los totales calculados individualmente, se suman, mediante el mismo médodo collectTotals.
Cómo se muestran los totales en Magento
Magento muestra los totales una vez calculados mediante la siguiente cadena de llamadas:
Mage_Checkout_Block_Cart_Totals::renderTotals --> Mage_Checkout_Block_Cart_Totals::getTotals --> Mage_Sales_Model_Quote::getTotals
Que como vemos, termina por volver a donde terminamos el apartado anterior, la clase Mage_Sales_Model_Quote.
Aquí se lía un poco el tema, porque aunque pueda parecer que Magento, podría utilizar el primer fragmento de código para mostrar en el mismo orden los totales, calculados, en la línea de complicar las cosas, la gente de Magento, define un orden independiente para el cálculo y para la visualización.
En el caso de la visualización, si seguimos el orden de llamadas anterior:
Mage_Checkout_Block_Cart_Totals::renderTotals --> Mage_Checkout_Block_Cart_Totals::getTotals --> Mage_Sales_Model_Quote::getTotals --> Mage_Sales_Model_Quote_Address::getTotalModels --> Mage_Sales_Model_Quote_Address::getTotalCollector
vemos que terminamos, nuevamente, en la instancia de Mage_Sales_Model_Quote_Address_Total_Collector, que habíamos creado al principio de todo el proceso.
Allí, al mismo tiempo que se inicia el orden de cálculo, se inicia el orden de visualización, en este caso, en el método _initRetrievers
Cuya primera línea indica:
$sorts = Mage::getStoreConfig('sales/totals_sort', $this->_store);
Que nos dice que Magento obtiene el orden de visualización de los totales desde una sección configurable en el administrador. En concreto desde Sistema => Configuración => Ventas => Orden de totales del pedido
Los valores iniciales de esa sección, están definidos, como no, en el omnipresente fichero de configuración de Magento, en concreto en:
app/code/core/Mage/Sales/etc/config.xml
y podemos verlo a continuación:
<default> <sales> <totals_sort> <discount>20</discount> <grand_total>100</grand_total> <shipping>30</shipping> <subtotal>10</subtotal> <tax>40</tax> </totals_sort> </sales> </default>
Buenas tardes
Estoy configurando una web en magento, y el eterno problema de las facturas no consigo resolverlo. He buscado por todos sitios pero no me entero. En la grabación de datos de la base de datos hay campos como base_price (que se supone es el precio de un artículo sin IVA), tax_amount (que es el IVA del artículo), discount_amount (este campo es el Descuento Total que se le descuenta al artículo)… pero el campo base_discount_amount (debería ser el Descuento sin IVA, ese campo se usa para restarlo a la Base Imponible y así calcular que le cuesta al cliente el artículo antes de sumar impuestos) repite la misma cantidad que discount_amount.
He revisado los datos que se graban en la base de datos y hay varios campos que no me parecen correctos. Ahora la pregunta del millón: ¿Que archivo es el que tiene todas estas formulas grabadas? así podría revisar los cálculos y comprenderlos mejor. No consigo encontrar las formulas.
Gracias
La cuestión es que, por desgracia, en un sistema como Magento, no existe un lugar donde se realice el cálculo de los totales. Cada uno de los módulos definidos en el sistema pone su parte.
Por ejemplo, para el cálculo de los gastos de envío, se utiliza alguno de los módulos disponibles para ello, así que tendrás que recurrir a las clases dentro de alguno de los módulos Fixed Rate, Table Rate, Free Shipping, etc.
En el caso de los impuestos, el código que calcula los impuestos aplicables estará dentro del módulo Mage/Tax, y así verás que cada uno de los totales se calcula en un lugar diferente del código.
Una cosa que veo que te está confundiendo es el tema de los campos de la base de datos: base_discount_amount y discount_amount almacenan el mismo valor, y eso es correcto. La diferencia entre ambos no tiene que ver con los impuestos, sino con la moneda: base_discount_amount muestra el valor en la moneda básica de la tienda, mientras discount_amount muestra el valor en la moneda elegida por el cliente para realizar el pedido. Si tu tienda sólo permite comprar en euros, entonces ambos valores tendrán siempre el mismo valor.
Espero que te sirva ;)
Muchas gracias por tu contestación,
Me ayuda mucho tu comentario y poder despejar mis dudas sobre el funcionamiento de Magento. Respecto a la base de datos comprendo lo que me comentas, como no he encontrado información no sabía muy bien por donde marchaba la cosa. A ver si averío más cosas de su funcionamiento y consigo aclararme un poco con tanto modulo.
Saludos