Skip to content

Commit

Permalink
Issue firegento#13: Proportional shipping tax calculation (needs test…
Browse files Browse the repository at this point in the history
…ing!)
  • Loading branch information
Alexander Menk committed Mar 14, 2013
1 parent 6be1d51 commit fe1533b
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,20 @@ public function toOptionArray()
return array(
array(
'value' => 0,
'label' => $helper->__('No dynamic shipping tax caluclation')
'label' => $helper->__('Off (Use above tax class)')
),
array(
'value' => FireGento_GermanSetup_Model_Tax_Config::USE_HIGHTES_TAX_ON_PRODUCTS,
'value' => FireGento_GermanSetup_Model_Tax_Config::USE_HIGHEST_TAX_ON_PRODUCTS,
'label' => $helper->__('Use the highest product tax')
),
array(
'value' => FireGento_GermanSetup_Model_Tax_Config::USE_TAX_DEPENDING_ON_PRODUCT_VALUES,
'label' => $helper->__('Use the tax rate of products that make up the biggest amount')
),
array(
'value' => FireGento_GermanSetup_Model_Tax_Config::USE_PROPORTIONALLY_MIXED_TAX,
'label' => $helper->__('Use mixed tax rates (in proportion to product value)')
),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,21 @@ class FireGento_GermanSetup_Model_Tax_Config extends Mage_Tax_Model_Config
{
const XML_PATH_SHIPPING_TAX_ON_PRODUCT_TAX = 'tax/classes/shipping_tax_on_product_tax';

const USE_HIGHTES_TAX_ON_PRODUCTS = 1;
const USE_HIGHEST_TAX_ON_PRODUCTS = 1;
const USE_TAX_DEPENDING_ON_PRODUCT_VALUES = 2;
const USE_PROPORTIONALLY_MIXED_TAX = 3;

protected $_simulateClass = null;

public function setSimulateClass($simulateClass)
{
$this->_simulateClass = $simulateClass;
}

public function getSimulateClass()
{
return $this->_simulateClass;
}

/**
* Get tax class id specified for shipping tax estimation based on highest product
Expand All @@ -48,6 +61,9 @@ class FireGento_GermanSetup_Model_Tax_Config extends Mage_Tax_Model_Config
*/
public function getShippingTaxClass($store = null)
{
if ($this->_simulateClass != null) {
return $this->_simulateClass;
}

/* @var $session Mage_Checkout_Model_Session */
$session = Mage::getSingleton('checkout/session');
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<?php
/**
* This file is part of the FIREGENTO project.
*
* FireGento_GermanSetup is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This script is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* PHP version 5
*
* @category FireGento
* @package FireGento_GermanSetup
* @author FireGento Team <team@firegento.com>
* @copyright 2013 FireGento Team (http://www.firegento.de). All rights served.
* @license http://opensource.org/licenses/gpl-3.0 GNU General Public License, version 3 (GPLv3)
* @version $Id:$
*/

/**
* Tax total model for mixed tax class calculation
*
* @category FireGento
* @package FireGento_GermanSetup
* @author FireGento Team <team@firegento.com>
* @copyright 2012 FireGento Team (http://www.firegento.de). All rights served.
* @license http://opensource.org/licenses/gpl-3.0 GNU General Public License, version 3 (GPLv3)
* @version $Id:$
*/
class FireGento_GermanSetup_Model_Tax_Sales_Total_Quote_Tax extends Mage_Tax_Model_Sales_Total_Quote_Tax {


protected function _getQuoteItems()
{
/* @var $session Mage_Checkout_Model_Session */
$session = Mage::getSingleton('checkout/session');

if ($session->hasQuote()) {
$quoteItems = $session->getQuote()->getAllItems();
} else {
$quoteItems = array();
}
return $quoteItems;
}

/**
* Calculates the portions of a quote with a specifc tax class
* The price incl tax is used for the calculation
*
* @param $quoteItems
* @return array (taxClassId -> percentage in quote)
*/
protected function _collectTaxClassPortions($quoteItems)
{
$taxClassIds = array();

// Fetch the tax rates from the quote items
$taxClassSums = array();
$total = 0;
foreach ($quoteItems as $item) {
/** @var $item Mage_Sales_Model_Quote_Item */
if ($item->getParentItem()) {
continue;
}
// sum up all product values grouped by the tax class id
if (!isset($taxClassSums[$item->getTaxClassId()])) {
$taxClassSums[$item->getTaxClassId()] = 0;
}
$rowSum = $item->getPriceInclTax() * $item->getQty();
$taxClassSums[$item->getTaxClassId()] += $rowSum;
$total += $rowSum;
}

$portions = array();
foreach($taxClassSums as $taxClassId=>$sum) {
$portions[$taxClassId] = $sum/$total;
}
return $portions;
}

/**
*
* Calculate proportional mixed tax
*
* TODO Works only for "Shipping cost incl Tax"
*
* @param Mage_Sales_Model_Quote_Address $address
* @param Varien_Object $taxRateRequest
*
* @return $this|Mage_Tax_Model_Sales_Total_Quote
*/
protected function _calculateShippingTax(Mage_Sales_Model_Quote_Address $address, $taxRateRequest)
{
if (Mage::getStoreConfigFlag(FireGento_GermanSetup_Model_Tax_Config::XML_PATH_SHIPPING_TAX_ON_PRODUCT_TAX)
!= FireGento_GermanSetup_Model_Tax_Config::USE_PROPORTIONALLY_MIXED_TAX) {
return parent::_calculateShippingTax($address, $taxRateRequest);
}

if (!$address->getIsShippingInclTax()) {
throw Exception('Not implemented');
}
$portions = $this->_collectTaxClassPortions($this->_getQuoteItems());

$totalTaxable = $address->getShippingTaxable();
$totalBaseTaxable = $address->getBaseShippingTaxable();
$totalShippingTaxAmount = 0;
$totalBaseShippingTaxAmount = 0;
foreach($portions as $taxClassId=>$portion) {
$address->setShippingTaxable($totalTaxable * $portion);
$address->setBaseShippingTaxable($totalBaseTaxable * $portion);
$this->_config->setSimulateClass($taxClassId);
parent::_calculateShippingTax($address, $taxRateRequest);
$this->_config->setSimulateClass(null);
$totalShippingTaxAmount += $address->getShippingTaxAmount();
$totalBaseShippingTaxAmount += $address->getBaseShippingTaxAmount();
}
$address->setShippingTaxAmount($totalShippingTaxAmount);
$address->setBaseShippingTaxAmount($totalBaseShippingTaxAmount);

// now we have to adjust the actual shipping cost
// we just set it to brutto minus tax
$address->setTotalAmount('shipping', $address->getShippingInclTax() - $totalShippingTaxAmount);
$address->setBaseTotalAmount('shipping', $address->getBaseShippingInclTax() - $totalBaseShippingTaxAmount);

$address->setShippingTaxable($totalTaxable);
$address->setBaseShippingTaxable($totalBaseTaxable);

$address->setShippingAmount($address->getTotalAmount('shipping'));
$address->setBaseShippingAmount($address->getBaseTotalAmount('shipping'));

return $this;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
<tax>
<rewrite>
<config>FireGento_GermanSetup_Model_Tax_Config</config>
<sales_total_quote_tax>FireGento_GermanSetup_Model_Tax_Sales_Total_Quote_Tax</sales_total_quote_tax>
</rewrite>
</tax>
</models>
Expand Down
6 changes: 5 additions & 1 deletion src/app/code/community/FireGento/GermanSetup/etc/system.xml
Original file line number Diff line number Diff line change
Expand Up @@ -330,9 +330,13 @@
<groups>
<classes>
<fields>
<shipping_tax_class>
<depends>
<shipping_tax_on_product_tax>0</shipping_tax_on_product_tax>
</depends>
</shipping_tax_class>
<shipping_tax_on_product_tax translate="label,comment" module="germansetup">
<label>Dynamic Shipping Tax Class Calculation</label>
<comment><![CDATA[Set to "yes" if you want to calculate the shipping tax rate based on the highest product tax rate or according to the tax rate of products that make up the biggest amount in cart.<br /><b>ATTENTION:</b> This setting overwrites the "Tax Class for Shipping" setting above!]]></comment>
<frontend_type>select</frontend_type>
<source_model>germansetup/source_tax_dynamicType</source_model>
<sort_order>11</sort_order>
Expand Down
7 changes: 6 additions & 1 deletion src/app/locale/de_DE/FireGento_GermanSetup.csv
Original file line number Diff line number Diff line change
Expand Up @@ -106,4 +106,9 @@
"Configuration Settings","Konfigurations-Einstellungen"
"CMS Settings","CMS-Einstellungen"
"Email Settings","Email-Einstellungen"
"Tax Settings","Steuer-Einstellungen"
"Tax Settings","Steuer-Einstellungen"

"Off (Use above tax class)","Aus (verwende o.a. Steuerklasse)"
"Use the highest product tax","Verwende den höchsten Produktsteuersatz des Warenkorbs"
"Use the tax rate of products that make up the biggest amount","Verwende den Steuersatz des größten Produktanteils"
"Use mixed tax rates (in proportion to product value)","Gemischte Besteuerung anhand der Produktanteile"

1 comment on commit fe1533b

@SolsWebdesign
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much :-) With your solution I was able to write my own shipping method with 6% tax and 21% tax for orders with (Dutch) products of different tax classes! Thanks again :-)

Please sign in to comment.