Overview

Packages

  • currencysymbol
  • MAbout
  • Mage
    • Admin
    • Adminhtml
    • AdminNotification
    • Api
    • Api2
    • Authorizenet
    • Backup
    • Bundle
    • Captcha
    • Catalog
    • CatalogIndex
    • CatalogInventory
    • CatalogRule
    • CatalogSearch
    • Centinel
    • Checkout
    • Cms
    • Compiler
    • Connect
    • Contacts
    • Core
    • Cron
    • CurrencySymbol
    • Customer
    • Dataflow
    • Directory
    • DirtectPost
    • Downloadable
    • Eav
    • GiftMessage
    • GoogleAnalytics
    • GoogleBase
    • GoogleCheckout
    • ImportExport
    • Index
    • Install
    • Log
    • Media
    • Newsletter
    • Oauth
    • Page
    • PageCache
    • Paygate
    • Payment
    • Paypal
    • PaypalUk
    • Persistent
    • Poll
    • ProductAlert
    • Rating
    • Reports
    • Review
    • Rss
    • Rule
    • Sales
    • SalesRule
    • Sedfriend
    • Sendfriend
    • Shipping
    • Sitemap
    • Tag
    • Tax
    • Usa
    • Weee
    • Widget
    • Wishlist
    • XmlConnect
  • None
  • Phoenix
    • Moneybookers
  • PHP
  • Zend
    • Date
    • Mime
    • XmlRpc

Classes

  • Mage_Tax_Block_Adminhtml_Frontend_Region_Updater
  • Mage_Tax_Block_Checkout_Discount
  • Mage_Tax_Block_Checkout_Grandtotal
  • Mage_Tax_Block_Checkout_Shipping
  • Mage_Tax_Block_Checkout_Subtotal
  • Mage_Tax_Block_Checkout_Tax
  • Mage_Tax_Block_Sales_Order_Tax
  • Mage_Tax_Helper_Data
  • Mage_Tax_Model_Calculation
  • Mage_Tax_Model_Calculation_Rate
  • Mage_Tax_Model_Calculation_Rate_Title
  • Mage_Tax_Model_Calculation_Rule
  • Mage_Tax_Model_Class
  • Mage_Tax_Model_Class_Source_Customer
  • Mage_Tax_Model_Class_Source_Product
  • Mage_Tax_Model_Config
  • Mage_Tax_Model_Config_Price_Include
  • Mage_Tax_Model_Mysql4_Calculation
  • Mage_Tax_Model_Mysql4_Calculation_Collection
  • Mage_Tax_Model_Mysql4_Calculation_Rate
  • Mage_Tax_Model_Mysql4_Calculation_Rate_Collection
  • Mage_Tax_Model_Mysql4_Calculation_Rate_Title
  • Mage_Tax_Model_Mysql4_Calculation_Rate_Title_Collection
  • Mage_Tax_Model_Mysql4_Calculation_Rule
  • Mage_Tax_Model_Mysql4_Calculation_Rule_Collection
  • Mage_Tax_Model_Mysql4_Class
  • Mage_Tax_Model_Mysql4_Class_Collection
  • Mage_Tax_Model_Mysql4_Report_Collection
  • Mage_Tax_Model_Mysql4_Report_Tax
  • Mage_Tax_Model_Mysql4_Report_Updatedat_Collection
  • Mage_Tax_Model_Mysql4_Sales_Order_Tax
  • Mage_Tax_Model_Mysql4_Sales_Order_Tax_Collection
  • Mage_Tax_Model_Mysql4_Setup
  • Mage_Tax_Model_Observer
  • Mage_Tax_Model_Resource_Calculation
  • Mage_Tax_Model_Resource_Calculation_Collection
  • Mage_Tax_Model_Resource_Calculation_Rate
  • Mage_Tax_Model_Resource_Calculation_Rate_Collection
  • Mage_Tax_Model_Resource_Calculation_Rate_Title
  • Mage_Tax_Model_Resource_Calculation_Rate_Title_Collection
  • Mage_Tax_Model_Resource_Calculation_Rule
  • Mage_Tax_Model_Resource_Calculation_Rule_Collection
  • Mage_Tax_Model_Resource_Class
  • Mage_Tax_Model_Resource_Class_Collection
  • Mage_Tax_Model_Resource_Report_Collection
  • Mage_Tax_Model_Resource_Report_Tax
  • Mage_Tax_Model_Resource_Report_Tax_Createdat
  • Mage_Tax_Model_Resource_Report_Tax_Updatedat
  • Mage_Tax_Model_Resource_Report_Updatedat_Collection
  • Mage_Tax_Model_Resource_Sales_Order_Tax
  • Mage_Tax_Model_Resource_Sales_Order_Tax_Collection
  • Mage_Tax_Model_Resource_Sales_Order_Tax_Item
  • Mage_Tax_Model_Resource_Sales_Order_Tax_Item_Collection
  • Mage_Tax_Model_Resource_Setup
  • Mage_Tax_Model_Sales_Order_Tax
  • Mage_Tax_Model_Sales_Order_Tax_Item
  • Mage_Tax_Model_Sales_Pdf_Grandtotal
  • Mage_Tax_Model_Sales_Pdf_Shipping
  • Mage_Tax_Model_Sales_Pdf_Subtotal
  • Mage_Tax_Model_Sales_Pdf_Tax
  • Mage_Tax_Model_Sales_Total_Quote_Discount
  • Mage_Tax_Model_Sales_Total_Quote_Nominal_Subtotal
  • Mage_Tax_Model_Sales_Total_Quote_Nominal_Tax
  • Mage_Tax_Model_Sales_Total_Quote_Shipping
  • Mage_Tax_Model_Sales_Total_Quote_Subtotal
  • Mage_Tax_Model_Sales_Total_Quote_Tax
  • Mage_Tax_Model_System_Config_Source_Algorithm
  • Mage_Tax_Model_System_Config_Source_Apply
  • Mage_Tax_Model_System_Config_Source_PriceType
  • Mage_Tax_Model_System_Config_Source_Tax_Country
  • Mage_Tax_Model_System_Config_Source_Tax_Display_Type
  • Mage_Tax_Model_System_Config_Source_Tax_Region

Exceptions

  • Mage_Tax_Exception
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * Magento
  4:  *
  5:  * NOTICE OF LICENSE
  6:  *
  7:  * This source file is subject to the Open Software License (OSL 3.0)
  8:  * that is bundled with this package in the file LICENSE.txt.
  9:  * It is also available through the world-wide-web at this URL:
 10:  * http://opensource.org/licenses/osl-3.0.php
 11:  * If you did not receive a copy of the license and are unable to
 12:  * obtain it through the world-wide-web, please send an email
 13:  * to license@magentocommerce.com so we can send you a copy immediately.
 14:  *
 15:  * DISCLAIMER
 16:  *
 17:  * Do not edit or add to this file if you wish to upgrade Magento to newer
 18:  * versions in the future. If you wish to customize Magento for your
 19:  * needs please refer to http://www.magentocommerce.com for more information.
 20:  *
 21:  * @category    Mage
 22:  * @package     Mage_Tax
 23:  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
 24:  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
 25:  */
 26: 
 27: /**
 28:  * Tax totals calculation model
 29:  */
 30: class Mage_Tax_Model_Sales_Total_Quote_Tax extends Mage_Sales_Model_Quote_Address_Total_Abstract
 31: {
 32:     /**
 33:      * Tax module helper
 34:      *
 35:      * @var Mage_Tax_Helper_Data
 36:      */
 37:     protected $_helper;
 38: 
 39:     /**
 40:      * Tax calculation model
 41:      *
 42:      * @var Mage_Tax_Model_Calculation
 43:      */
 44:     protected $_calculator;
 45: 
 46:     /**
 47:      * Tax configuration object
 48:      *
 49:      * @var Mage_Tax_Model_Config
 50:      */
 51:     protected $_config;
 52: 
 53:     /**
 54:      * Flag which is initialized when collect method is start.
 55:      * Is used for checking if store tax and customer tax requests are similar
 56:      *
 57:      * @var bool
 58:      */
 59:     protected $_areTaxRequestsSimilar = false;
 60: 
 61: 
 62:     protected $_roundingDeltas = array();
 63:     protected $_baseRoundingDeltas = array();
 64: 
 65:     protected $_store;
 66: 
 67:     /**
 68:      * Hidden taxes array
 69:      *
 70:      * @var array
 71:      */
 72:     protected $_hiddenTaxes = array();
 73: 
 74:     /**
 75:      * Class constructor
 76:      */
 77:     public function __construct()
 78:     {
 79:         $this->setCode('tax');
 80:         $this->_helper      = Mage::helper('tax');
 81:         $this->_calculator  = Mage::getSingleton('tax/calculation');
 82:         $this->_config      = Mage::getSingleton('tax/config');
 83:     }
 84: 
 85:     /**
 86:      * Collect tax totals for quote address
 87:      *
 88:      * @param   Mage_Sales_Model_Quote_Address $address
 89:      * @return  Mage_Tax_Model_Sales_Total_Quote
 90:      */
 91:     public function collect(Mage_Sales_Model_Quote_Address $address)
 92:     {
 93:         parent::collect($address);
 94:         $this->_roundingDeltas      = array();
 95:         $this->_baseRoundingDeltas  = array();
 96:         $this->_hiddenTaxes         = array();
 97:         $address->setShippingTaxAmount(0);
 98:         $address->setBaseShippingTaxAmount(0);
 99: 
100:         $this->_store = $address->getQuote()->getStore();
101:         $customer = $address->getQuote()->getCustomer();
102:         if ($customer) {
103:             $this->_calculator->setCustomer($customer);
104:         }
105: 
106:         if (!$address->getAppliedTaxesReset()) {
107:             $address->setAppliedTaxes(array());
108:         }
109: 
110:         $items = $this->_getAddressItems($address);
111:         if (!count($items)) {
112:             return $this;
113:         }
114:         $request = $this->_calculator->getRateRequest(
115:             $address,
116:             $address->getQuote()->getBillingAddress(),
117:             $address->getQuote()->getCustomerTaxClassId(),
118:             $this->_store
119:         );
120: 
121:         if ($this->_config->priceIncludesTax($this->_store)) {
122:             $this->_areTaxRequestsSimilar = $this->_calculator->compareRequests(
123:                 $this->_calculator->getRateOriginRequest($this->_store),
124:                 $request
125:             );
126:         }
127: 
128:         switch ($this->_config->getAlgorithm($this->_store)) {
129:             case Mage_Tax_Model_Calculation::CALC_UNIT_BASE:
130:                 $this->_unitBaseCalculation($address, $request);
131:                 break;
132:             case Mage_Tax_Model_Calculation::CALC_ROW_BASE:
133:                 $this->_rowBaseCalculation($address, $request);
134:                 break;
135:             case Mage_Tax_Model_Calculation::CALC_TOTAL_BASE:
136:                 $this->_totalBaseCalculation($address, $request);
137:                 break;
138:             default:
139:                 break;
140:         }
141: 
142:         $this->_addAmount($address->getExtraTaxAmount());
143:         $this->_addBaseAmount($address->getBaseExtraTaxAmount());
144:         $this->_calculateShippingTax($address, $request);
145: 
146:         $this->_processHiddenTaxes();
147: 
148:         return $this;
149:     }
150: 
151:     /**
152:      * Process hidden taxes for items and shippings (in accordance with hidden tax type)
153:      *
154:      * @return void
155:      */
156:     protected function _processHiddenTaxes()
157:     {
158:         $this->_getAddress()->setTotalAmount('hidden_tax', 0);
159:         $this->_getAddress()->setBaseTotalAmount('hidden_tax', 0);
160:         $this->_getAddress()->setTotalAmount('shipping_hidden_tax', 0);
161:         $this->_getAddress()->setBaseTotalAmount('shipping_hidden_tax', 0);
162:         foreach ($this->_hiddenTaxes as $taxInfoItem) {
163:             if (isset($taxInfoItem['item'])) {
164:                 // Item hidden taxes
165:                 $item           = $taxInfoItem['item'];
166:                 $rateKey        = $taxInfoItem['rate_key'];
167:                 $hiddenTax      = $taxInfoItem['value'];
168:                 $baseHiddenTax  = $taxInfoItem['base_value'];
169:                 $inclTax        = $taxInfoItem['incl_tax'];
170:                 $qty            = $taxInfoItem['qty'];
171: 
172:                 if ($this->_config->getAlgorithm($this->_store) == Mage_Tax_Model_Calculation::CALC_TOTAL_BASE) {
173:                     $hiddenTax      = $this->_deltaRound($hiddenTax, $rateKey, $inclTax);
174:                     $baseHiddenTax  = $this->_deltaRound($baseHiddenTax, $rateKey, $inclTax, 'base');
175:                 } else {
176:                     $hiddenTax      = $this->_calculator->round($hiddenTax);
177:                     $baseHiddenTax  = $this->_calculator->round($baseHiddenTax);
178:                 }
179: 
180:                 $item->setHiddenTaxAmount(max(0, $qty * $hiddenTax));
181:                 $item->setBaseHiddenTaxAmount(max(0, $qty * $baseHiddenTax));
182:                 $this->_getAddress()->addTotalAmount('hidden_tax', $item->getHiddenTaxAmount());
183:                 $this->_getAddress()->addBaseTotalAmount('hidden_tax', $item->getBaseHiddenTaxAmount());
184:             } else {
185:                 // Shipping hidden taxes
186:                 $rateKey        = $taxInfoItem['rate_key'];
187:                 $hiddenTax      = $taxInfoItem['value'];
188:                 $baseHiddenTax  = $taxInfoItem['base_value'];
189:                 $inclTax        = $taxInfoItem['incl_tax'];
190: 
191:                 $hiddenTax      = $this->_deltaRound($hiddenTax, $rateKey, $inclTax);
192:                 $baseHiddenTax  = $this->_deltaRound($baseHiddenTax, $rateKey, $inclTax, 'base');
193: 
194:                 $this->_getAddress()->setShippingHiddenTaxAmount(max(0, $hiddenTax));
195:                 $this->_getAddress()->setBaseShippingHiddenTaxAmount(max(0, $baseHiddenTax));
196:                 $this->_getAddress()->addTotalAmount('shipping_hidden_tax', $hiddenTax);
197:                 $this->_getAddress()->addBaseTotalAmount('shipping_hidden_tax', $baseHiddenTax);
198:             }
199:         }
200:     }
201: 
202:     /**
203:      * Check if price include tax should be used for calculations.
204:      * We are using price include tax just in case when catalog prices are including tax
205:      * and customer tax request is same as store tax request
206:      *
207:      * @param $store
208:      * @return bool
209:      */
210:     protected function _usePriceIncludeTax($store)
211:     {
212:         if ($this->_config->priceIncludesTax($store) || $this->_config->getNeedUsePriceExcludeTax()) {
213:             return $this->_areTaxRequestsSimilar;
214:         }
215:         return false;
216:     }
217: 
218:     /**
219:      * Tax caclulation for shipping price
220:      *
221:      * @param   Mage_Sales_Model_Quote_Address $address
222:      * @param   Varien_Object $taxRateRequest
223:      * @return  Mage_Tax_Model_Sales_Total_Quote
224:      */
225:     protected function _calculateShippingTax(Mage_Sales_Model_Quote_Address $address, $taxRateRequest)
226:     {
227:         $taxRateRequest->setProductClassId($this->_config->getShippingTaxClass($this->_store));
228:         $rate           = $this->_calculator->getRate($taxRateRequest);
229:         $inclTax        = $address->getIsShippingInclTax();
230:         $shipping       = $address->getShippingTaxable();
231:         $baseShipping   = $address->getBaseShippingTaxable();
232:         $rateKey        = (string)$rate;
233: 
234:         $hiddenTax      = null;
235:         $baseHiddenTax  = null;
236:         switch ($this->_helper->getCalculationSequence($this->_store)) {
237:             case Mage_Tax_Model_Calculation::CALC_TAX_BEFORE_DISCOUNT_ON_EXCL:
238:             case Mage_Tax_Model_Calculation::CALC_TAX_BEFORE_DISCOUNT_ON_INCL:
239:                 $tax        = $this->_calculator->calcTaxAmount($shipping, $rate, $inclTax, false);
240:                 $baseTax    = $this->_calculator->calcTaxAmount($baseShipping, $rate, $inclTax, false);
241:                 break;
242:             case Mage_Tax_Model_Calculation::CALC_TAX_AFTER_DISCOUNT_ON_EXCL:
243:             case Mage_Tax_Model_Calculation::CALC_TAX_AFTER_DISCOUNT_ON_INCL:
244:                 $discountAmount     = $address->getShippingDiscountAmount();
245:                 $baseDiscountAmount = $address->getBaseShippingDiscountAmount();
246:                 $tax = $this->_calculator->calcTaxAmount(
247:                     $shipping - $discountAmount,
248:                     $rate,
249:                     $inclTax,
250:                     false
251:                 );
252:                 $baseTax = $this->_calculator->calcTaxAmount(
253:                     $baseShipping - $baseDiscountAmount,
254:                     $rate,
255:                     $inclTax,
256:                     false
257:                 );
258:                 break;
259:         }
260: 
261:         if ($this->_config->getAlgorithm($this->_store) == Mage_Tax_Model_Calculation::CALC_TOTAL_BASE) {
262:             $tax        = $this->_deltaRound($tax, $rate, $inclTax);
263:             $baseTax    = $this->_deltaRound($baseTax, $rate, $inclTax, 'base');
264:         } else {
265:             $tax        = $this->_calculator->round($tax);
266:             $baseTax    = $this->_calculator->round($baseTax);
267:         }
268: 
269:         if ($inclTax && !empty($discountAmount)) {
270:             $hiddenTax      = $this->_calculator->calcTaxAmount($discountAmount, $rate, $inclTax, false);
271:             $baseHiddenTax  = $this->_calculator->calcTaxAmount($baseDiscountAmount, $rate, $inclTax, false);
272:             $this->_hiddenTaxes[] = array(
273:                 'rate_key'   => $rateKey,
274:                 'value'      => $hiddenTax,
275:                 'base_value' => $baseHiddenTax,
276:                 'incl_tax'   => $inclTax,
277:             );
278:         }
279: 
280:         $this->_addAmount(max(0, $tax));
281:         $this->_addBaseAmount(max(0, $baseTax));
282:         $address->setShippingTaxAmount(max(0, $tax));
283:         $address->setBaseShippingTaxAmount(max(0, $baseTax));
284:         $applied = $this->_calculator->getAppliedRates($taxRateRequest);
285:         $this->_saveAppliedTaxes($address, $applied, $tax, $baseTax, $rate);
286: 
287:         return $this;
288:     }
289: 
290:     /**
291:      * Calculate address tax amount based on one unit price and tax amount
292:      *
293:      * @param   Mage_Sales_Model_Quote_Address $address
294:      * @return  Mage_Tax_Model_Sales_Total_Quote
295:      */
296:     protected function _unitBaseCalculation(Mage_Sales_Model_Quote_Address $address, $taxRateRequest)
297:     {
298:         $items = $this->_getAddressItems($address);
299:         $itemTaxGroups  = array();
300:         foreach ($items as $item) {
301:             if ($item->getParentItem()) {
302:                 continue;
303:             }
304: 
305:             if ($item->getHasChildren() && $item->isChildrenCalculated()) {
306:                 foreach ($item->getChildren() as $child) {
307:                     $taxRateRequest->setProductClassId($child->getProduct()->getTaxClassId());
308:                     $rate = $this->_calculator->getRate($taxRateRequest);
309:                     $this->_calcUnitTaxAmount($child, $rate);
310:                     $this->_addAmount($child->getTaxAmount());
311:                     $this->_addBaseAmount($child->getBaseTaxAmount());
312:                     $applied = $this->_calculator->getAppliedRates($taxRateRequest);
313:                     if ($rate > 0) {
314:                         $itemTaxGroups[$child->getId()] = $applied;
315:                     }
316:                     $this->_saveAppliedTaxes(
317:                         $address,
318:                         $applied,
319:                         $child->getTaxAmount(),
320:                         $child->getBaseTaxAmount(),
321:                         $rate
322:                     );
323:                     $child->setTaxRates($applied);
324:                 }
325:                 $this->_recalculateParent($item);
326:             }
327:             else {
328:                 $taxRateRequest->setProductClassId($item->getProduct()->getTaxClassId());
329:                 $rate = $this->_calculator->getRate($taxRateRequest);
330:                 $this->_calcUnitTaxAmount($item, $rate);
331:                 $this->_addAmount($item->getTaxAmount());
332:                 $this->_addBaseAmount($item->getBaseTaxAmount());
333:                 $applied = $this->_calculator->getAppliedRates($taxRateRequest);
334:                 if ($rate > 0) {
335:                     $itemTaxGroups[$item->getId()] = $applied;
336:                 }
337:                 $this->_saveAppliedTaxes(
338:                     $address,
339:                     $applied,
340:                     $item->getTaxAmount(),
341:                     $item->getBaseTaxAmount(),
342:                     $rate
343:                 );
344:                 $item->setTaxRates($applied);
345:             }
346:         }
347:         if ($address->getQuote()->getTaxesForItems()) {
348:             $itemTaxGroups += $address->getQuote()->getTaxesForItems();
349:         }
350:         $address->getQuote()->setTaxesForItems($itemTaxGroups);
351:         return $this;
352:     }
353: 
354:     /**
355:      * Calculate unit tax anount based on unit price
356:      *
357:      * @param   Mage_Sales_Model_Quote_Item_Abstract $item
358:      * @param   float $rate
359:      * @return  Mage_Tax_Model_Sales_Total_Quote
360:      */
361:     protected function _calcUnitTaxAmount(Mage_Sales_Model_Quote_Item_Abstract $item, $rate)
362:     {
363:         $qty        = $item->getTotalQty();
364:         $inclTax    = $item->getIsPriceInclTax();
365:         $price      = $item->getTaxableAmount() + $item->getExtraTaxableAmount();
366:         $basePrice  = $item->getBaseTaxableAmount() + $item->getBaseExtraTaxableAmount();
367:         $rateKey    = (string)$rate;
368:         $item->setTaxPercent($rate);
369: 
370:         $hiddenTax      = null;
371:         $baseHiddenTax  = null;
372:         switch ($this->_config->getCalculationSequence($this->_store)) {
373:             case Mage_Tax_Model_Calculation::CALC_TAX_BEFORE_DISCOUNT_ON_EXCL:
374:             case Mage_Tax_Model_Calculation::CALC_TAX_BEFORE_DISCOUNT_ON_INCL:
375:                 $unitTax        = $this->_calculator->calcTaxAmount($price, $rate, $inclTax);
376:                 $baseUnitTax    = $this->_calculator->calcTaxAmount($basePrice, $rate, $inclTax);
377:                 break;
378:             case Mage_Tax_Model_Calculation::CALC_TAX_AFTER_DISCOUNT_ON_EXCL:
379:             case Mage_Tax_Model_Calculation::CALC_TAX_AFTER_DISCOUNT_ON_INCL:
380:                 $discountAmount     = $item->getDiscountAmount() / $qty;
381:                 $baseDiscountAmount = $item->getBaseDiscountAmount() / $qty;
382: 
383:                 $unitTax = $this->_calculator->calcTaxAmount($price, $rate, $inclTax);
384:                 $discountRate = ($unitTax/$price) * 100;
385:                 $unitTaxDiscount = $this->_calculator->calcTaxAmount($discountAmount, $discountRate, $inclTax, false);
386:                 $unitTax = max($unitTax - $unitTaxDiscount, 0);
387:                 $baseUnitTax = $this->_calculator->calcTaxAmount($basePrice, $rate, $inclTax);
388:                 $baseDiscountRate = ($baseUnitTax/$basePrice) * 100;
389:                 $baseUnitTaxDiscount = $this->_calculator
390:                     ->calcTaxAmount($baseDiscountAmount, $baseDiscountRate, $inclTax, false);
391:                 $baseUnitTax = max($baseUnitTax - $baseUnitTaxDiscount, 0);
392: 
393:                 if ($inclTax && $discountAmount > 0) {
394:                     $hiddenTax      = $this->_calculator->calcTaxAmount($discountAmount, $rate, $inclTax, false);
395:                     $baseHiddenTax  = $this->_calculator->calcTaxAmount($baseDiscountAmount, $rate, $inclTax, false);
396:                     $this->_hiddenTaxes[] = array(
397:                         'rate_key'   => $rateKey,
398:                         'qty'        => $qty,
399:                         'item'       => $item,
400:                         'value'      => $hiddenTax,
401:                         'base_value' => $baseHiddenTax,
402:                         'incl_tax'   => $inclTax,
403:                     );
404:                 } elseif ($discountAmount > $price) { // case with 100% discount on price incl. tax
405:                     $hiddenTax      = $discountAmount - $price;
406:                     $baseHiddenTax  = $baseDiscountAmount - $basePrice;
407:                     $this->_hiddenTaxes[] = array(
408:                         'rate_key'   => $rateKey,
409:                         'qty'        => $qty,
410:                         'item'       => $item,
411:                         'value'      => $hiddenTax,
412:                         'base_value' => $baseHiddenTax,
413:                         'incl_tax'   => $inclTax,
414:                     );
415:                 }
416:                 break;
417:         }
418:         $item->setTaxAmount($this->_store->roundPrice(max(0, $qty*$unitTax)));
419:         $item->setBaseTaxAmount($this->_store->roundPrice(max(0, $qty*$baseUnitTax)));
420: 
421:         return $this;
422:     }
423: 
424:     /**
425:      * Calculate address total tax based on row total
426:      *
427:      * @param   Mage_Sales_Model_Quote_Address $address
428:      * @param   Varien_Object $taxRateRequest
429:      * @return  Mage_Tax_Model_Sales_Total_Quote
430:      */
431:     protected function _rowBaseCalculation(Mage_Sales_Model_Quote_Address $address, $taxRateRequest)
432:     {
433:         $items = $this->_getAddressItems($address);
434:         $itemTaxGroups  = array();
435:         foreach ($items as $item) {
436:             if ($item->getParentItem()) {
437:                 continue;
438:             }
439:             if ($item->getHasChildren() && $item->isChildrenCalculated()) {
440:                 foreach ($item->getChildren() as $child) {
441:                     $taxRateRequest->setProductClassId($child->getProduct()->getTaxClassId());
442:                     $rate = $this->_calculator->getRate($taxRateRequest);
443:                     $this->_calcRowTaxAmount($child, $rate);
444:                     $this->_addAmount($child->getTaxAmount());
445:                     $this->_addBaseAmount($child->getBaseTaxAmount());
446:                     $applied = $this->_calculator->getAppliedRates($taxRateRequest);
447:                     if ($rate > 0) {
448:                         $itemTaxGroups[$child->getId()] = $applied;
449:                     }
450:                     $this->_saveAppliedTaxes(
451:                         $address,
452:                         $applied,
453:                         $child->getTaxAmount(),
454:                         $child->getBaseTaxAmount(),
455:                         $rate
456:                     );
457:                     $child->setTaxRates($applied);
458:                 }
459:                 $this->_recalculateParent($item);
460:             }
461:             else {
462:                 $taxRateRequest->setProductClassId($item->getProduct()->getTaxClassId());
463:                 $rate = $this->_calculator->getRate($taxRateRequest);
464:                 $this->_calcRowTaxAmount($item, $rate);
465:                 $this->_addAmount($item->getTaxAmount());
466:                 $this->_addBaseAmount($item->getBaseTaxAmount());
467:                 $applied = $this->_calculator->getAppliedRates($taxRateRequest);
468:                 if ($rate > 0) {
469:                     $itemTaxGroups[$item->getId()] = $applied;
470:                 }
471:                 $this->_saveAppliedTaxes(
472:                     $address,
473:                     $applied,
474:                     $item->getTaxAmount(),
475:                     $item->getBaseTaxAmount(),
476:                     $rate
477:                 );
478:                 $item->setTaxRates($applied);
479:             }
480:         }
481: 
482:         if ($address->getQuote()->getTaxesForItems()) {
483:             $itemTaxGroups += $address->getQuote()->getTaxesForItems();
484:         }
485:         $address->getQuote()->setTaxesForItems($itemTaxGroups);
486:         return $this;
487:     }
488: 
489:     /**
490:      * Calculate item tax amount based on row total
491:      *
492:      * @param   Mage_Sales_Model_Quote_Item_Abstract $item
493:      * @param   float $rate
494:      * @return  Mage_Tax_Model_Sales_Total_Quote
495:      */
496:     protected function _calcRowTaxAmount($item, $rate)
497:     {
498:         $inclTax        = $item->getIsPriceInclTax();
499:         $subtotal       = $item->getTaxableAmount() + $item->getExtraRowTaxableAmount();
500:         $baseSubtotal   = $item->getBaseTaxableAmount() + $item->getBaseExtraRowTaxableAmount();
501:         $rateKey        = (string)$rate;
502:         $item->setTaxPercent($rate);
503: 
504:         $hiddenTax      = null;
505:         $baseHiddenTax  = null;
506:         switch ($this->_helper->getCalculationSequence($this->_store)) {
507:             case Mage_Tax_Model_Calculation::CALC_TAX_BEFORE_DISCOUNT_ON_EXCL:
508:             case Mage_Tax_Model_Calculation::CALC_TAX_BEFORE_DISCOUNT_ON_INCL:
509:                 $rowTax     = $this->_calculator->calcTaxAmount($subtotal, $rate, $inclTax);
510:                 $baseRowTax = $this->_calculator->calcTaxAmount($baseSubtotal, $rate, $inclTax);
511:                 break;
512:             case Mage_Tax_Model_Calculation::CALC_TAX_AFTER_DISCOUNT_ON_EXCL:
513:             case Mage_Tax_Model_Calculation::CALC_TAX_AFTER_DISCOUNT_ON_INCL:
514:                 $discountAmount     = $item->getDiscountAmount();
515:                 $baseDiscountAmount = $item->getBaseDiscountAmount();
516:                 $rowTax = $this->_calculator->calcTaxAmount(
517:                     max($subtotal - $discountAmount, 0),
518:                     $rate,
519:                     $inclTax
520:                 );
521:                 $baseRowTax = $this->_calculator->calcTaxAmount(
522:                     max($baseSubtotal - $baseDiscountAmount, 0),
523:                     $rate,
524:                     $inclTax
525:                 );
526:                 if ($inclTax && $discountAmount > 0) {
527:                     $hiddenTax      = $this->_calculator->calcTaxAmount($discountAmount, $rate, $inclTax, false);
528:                     $baseHiddenTax  = $this->_calculator->calcTaxAmount($baseDiscountAmount, $rate, $inclTax, false);
529:                     $this->_hiddenTaxes[] = array(
530:                         'rate_key'   => $rateKey,
531:                         'qty'        => 1,
532:                         'item'       => $item,
533:                         'value'      => $hiddenTax,
534:                         'base_value' => $baseHiddenTax,
535:                         'incl_tax'   => $inclTax,
536:                     );
537:                 } elseif ($discountAmount > $subtotal) { // case with 100% discount on price incl. tax
538:                     $hiddenTax      = $discountAmount - $subtotal;
539:                     $baseHiddenTax  = $baseDiscountAmount - $baseSubtotal;
540:                     $this->_hiddenTaxes[] = array(
541:                         'rate_key'   => $rateKey,
542:                         'qty'        => 1,
543:                         'item'       => $item,
544:                         'value'      => $hiddenTax,
545:                         'base_value' => $baseHiddenTax,
546:                         'incl_tax'   => $inclTax,
547:                     );
548:                 }
549:                 break;
550:         }
551:         $item->setTaxAmount(max(0, $rowTax));
552:         $item->setBaseTaxAmount(max(0, $baseRowTax));
553:         return $this;
554:     }
555: 
556:     /**
557:      * Calculate address total tax based on address subtotal
558:      *
559:      * @param   Mage_Sales_Model_Quote_Address $address
560:      * @param   Varien_Object $taxRateRequest
561:      * @return  Mage_Tax_Model_Sales_Total_Quote
562:      */
563:     protected function _totalBaseCalculation(Mage_Sales_Model_Quote_Address $address, $taxRateRequest)
564:     {
565:         $items          = $this->_getAddressItems($address);
566:         $store          = $address->getQuote()->getStore();
567:         $taxGroups      = array();
568:         $itemTaxGroups  = array();
569: 
570:         foreach ($items as $item) {
571:             if ($item->getParentItem()) {
572:                 continue;
573:             }
574: 
575:             if ($item->getHasChildren() && $item->isChildrenCalculated()) {
576:                 foreach ($item->getChildren() as $child) {
577:                     $taxRateRequest->setProductClassId($child->getProduct()->getTaxClassId());
578:                     $rate = $this->_calculator->getRate($taxRateRequest);
579:                     $applied_rates = $this->_calculator->getAppliedRates($taxRateRequest);
580:                     $taxGroups[(string)$rate]['applied_rates'] = $applied_rates;
581:                     $taxGroups[(string)$rate]['incl_tax'] = $child->getIsPriceInclTax();
582:                     $this->_aggregateTaxPerRate($child, $rate, $taxGroups);
583:                     if ($rate > 0) {
584:                         $itemTaxGroups[$child->getId()] = $applied_rates;
585:                     }
586:                 }
587:                 $this->_recalculateParent($item);
588:             } else {
589:                 $taxRateRequest->setProductClassId($item->getProduct()->getTaxClassId());
590:                 $rate = $this->_calculator->getRate($taxRateRequest);
591:                 $applied_rates = $this->_calculator->getAppliedRates($taxRateRequest);
592:                 $taxGroups[(string)$rate]['applied_rates'] = $applied_rates;
593:                 $taxGroups[(string)$rate]['incl_tax'] = $item->getIsPriceInclTax();
594:                 $this->_aggregateTaxPerRate($item, $rate, $taxGroups);
595:                 if ($rate > 0) {
596:                     $itemTaxGroups[$item->getId()] = $applied_rates;
597:                 }
598:             }
599:         }
600: 
601:         if ($address->getQuote()->getTaxesForItems()) {
602:             $itemTaxGroups += $address->getQuote()->getTaxesForItems();
603:         }
604:         $address->getQuote()->setTaxesForItems($itemTaxGroups);
605: 
606:         foreach ($taxGroups as $rateKey => $data) {
607:             $rate = (float) $rateKey;
608:             $inclTax = $data['incl_tax'];
609:             $totalTax = $this->_calculator->calcTaxAmount(array_sum($data['totals']), $rate, $inclTax);
610:             $baseTotalTax = $this->_calculator->calcTaxAmount(array_sum($data['base_totals']), $rate, $inclTax);
611:             $this->_addAmount($totalTax);
612:             $this->_addBaseAmount($baseTotalTax);
613:             $this->_saveAppliedTaxes($address, $data['applied_rates'], $totalTax, $baseTotalTax, $rate);
614:         }
615:         return $this;
616:     }
617: 
618:     /**
619:      * Aggregate row totals per tax rate in array
620:      *
621:      * @param   Mage_Sales_Model_Quote_Item_Abstract $item
622:      * @param   float $rate
623:      * @param   array $taxGroups
624:      * @return  Mage_Tax_Model_Sales_Total_Quote
625:      */
626:     protected function _aggregateTaxPerRate($item, $rate, &$taxGroups)
627:     {
628:         $inclTax        = $item->getIsPriceInclTax();
629:         $rateKey        = (string) $rate;
630:         $taxSubtotal    = $subtotal     = $item->getTaxableAmount() + $item->getExtraRowTaxableAmount();
631:         $baseTaxSubtotal= $baseSubtotal = $item->getBaseTaxableAmount() + $item->getBaseExtraRowTaxableAmount();
632:         $item->setTaxPercent($rate);
633: 
634:         if (!isset($taxGroups[$rateKey]['totals'])) {
635:             $taxGroups[$rateKey]['totals'] = array();
636:             $taxGroups[$rateKey]['base_totals'] = array();
637:         }
638: 
639:         $hiddenTax      = null;
640:         $baseHiddenTax  = null;
641:         switch ($this->_helper->getCalculationSequence($this->_store)) {
642:             case Mage_Tax_Model_Calculation::CALC_TAX_BEFORE_DISCOUNT_ON_EXCL:
643:             case Mage_Tax_Model_Calculation::CALC_TAX_BEFORE_DISCOUNT_ON_INCL:
644:                 $rowTax             = $this->_calculator->calcTaxAmount($subtotal, $rate, $inclTax, false);
645:                 $baseRowTax         = $this->_calculator->calcTaxAmount($baseSubtotal, $rate, $inclTax, false);
646:                 break;
647:             case Mage_Tax_Model_Calculation::CALC_TAX_AFTER_DISCOUNT_ON_EXCL:
648:             case Mage_Tax_Model_Calculation::CALC_TAX_AFTER_DISCOUNT_ON_INCL:
649:                 if ($this->_helper->applyTaxOnOriginalPrice($this->_store)) {
650:                     $discount           = $item->getOriginalDiscountAmount();
651:                     $baseDiscount       = $item->getBaseOriginalDiscountAmount();
652:                 } else {
653:                     $discount           = $item->getDiscountAmount();
654:                     $baseDiscount       = $item->getBaseDiscountAmount();
655:                 }
656: 
657:                 $taxSubtotal        = max($subtotal - $discount, 0);
658:                 $baseTaxSubtotal    = max($baseSubtotal - $baseDiscount, 0);
659:                 $rowTax             = $this->_calculator->calcTaxAmount($taxSubtotal, $rate, $inclTax, false);
660:                 $baseRowTax         = $this->_calculator->calcTaxAmount($baseTaxSubtotal, $rate, $inclTax, false);
661:                 if (!$item->getNoDiscount() && $item->getWeeeTaxApplied()) {
662:                     $rowTaxBeforeDiscount = $this->_calculator->calcTaxAmount(
663:                         $subtotal,
664:                         $rate,
665:                         $inclTax,
666:                         false
667:                     );
668:                     $baseRowTaxBeforeDiscount = $this->_calculator->calcTaxAmount(
669:                         $baseSubtotal,
670:                         $rate,
671:                         $inclTax,
672:                         false
673:                     );
674:                 }
675: 
676:                 if ($inclTax && $discount > 0) {
677:                     $hiddenTax      = $this->_calculator->calcTaxAmount($discount, $rate, $inclTax, false);
678:                     $baseHiddenTax  = $this->_calculator->calcTaxAmount($baseDiscount, $rate, $inclTax, false);
679:                     $this->_hiddenTaxes[] = array(
680:                         'rate_key'   => $rateKey,
681:                         'qty'        => 1,
682:                         'item'       => $item,
683:                         'value'      => $hiddenTax,
684:                         'base_value' => $baseHiddenTax,
685:                         'incl_tax'   => $inclTax,
686:                     );
687:                 }
688:                 break;
689:         }
690: 
691:         $rowTax     = $this->_deltaRound($rowTax, $rateKey, $inclTax);
692:         $baseRowTax = $this->_deltaRound($baseRowTax, $rateKey, $inclTax, 'base');
693:         $item->setTaxAmount(max(0, $rowTax));
694:         $item->setBaseTaxAmount(max(0, $baseRowTax));
695: 
696:         if (isset($rowTaxBeforeDiscount) && isset($baseRowTaxBeforeDiscount)) {
697:             $taxBeforeDiscount = max(
698:                 0,
699:                 $this->_deltaRound($rowTaxBeforeDiscount, $rateKey, $inclTax)
700:             );
701:             $baseTaxBeforeDiscount = max(
702:                 0,
703:                 $this->_deltaRound($baseRowTaxBeforeDiscount, $rateKey, $inclTax, 'base')
704:             );
705: 
706:             $item->setDiscountTaxCompensation($taxBeforeDiscount - max(0, $rowTax));
707:             $item->setBaseDiscountTaxCompensation($baseTaxBeforeDiscount - max(0, $baseRowTax));
708:         }
709: 
710:         $taxGroups[$rateKey]['totals'][]        = max(0, $taxSubtotal);
711:         $taxGroups[$rateKey]['base_totals'][]   = max(0, $baseTaxSubtotal);
712:         return $this;
713:     }
714: 
715:     /**
716:      * Round price based on previous rounding operation delta
717:      *
718:      * @param float $price
719:      * @param string $rate
720:      * @param bool $direction price including or excluding tax
721:      * @param string $type
722:      * @return float
723:      */
724:     protected function _deltaRound($price, $rate, $direction, $type='regular')
725:     {
726:         if ($price) {
727:             $rate  = (string) $rate;
728:             $type  = $type . $direction;
729:             $delta = isset($this->_roundingDeltas[$type][$rate]) ? $this->_roundingDeltas[$type][$rate] : 0;
730:             $price += $delta;
731:             $this->_roundingDeltas[$type][$rate] = $price - $this->_calculator->round($price);
732:             $price = $this->_calculator->round($price);
733:         }
734:         return $price;
735:     }
736: 
737:     /**
738:      * Recalculate parent item amounts base on children data
739:      *
740:      * @param   Mage_Sales_Model_Quote_Item_Abstract $item
741:      * @return  Mage_Tax_Model_Sales_Total_Quote
742:      */
743:     protected function _recalculateParent(Mage_Sales_Model_Quote_Item_Abstract $item)
744:     {
745:         $rowTaxAmount       = 0;
746:         $baseRowTaxAmount   = 0;
747:         foreach ($item->getChildren() as $child) {
748:             $rowTaxAmount       += $child->getTaxAmount();
749:             $baseRowTaxAmount   += $child->getBaseTaxAmount();
750:         }
751:         $item->setTaxAmount($rowTaxAmount);
752:         $item->setBaseTaxAmount($baseRowTaxAmount);
753:         return $this;
754:     }
755: 
756:     /**
757:      * Collect applied tax rates information on address level
758:      *
759:      * @param   Mage_Sales_Model_Quote_Address $address
760:      * @param   array $applied
761:      * @param   float $amount
762:      * @param   float $baseAmount
763:      * @param   float $rate
764:      */
765:     protected function _saveAppliedTaxes(Mage_Sales_Model_Quote_Address $address, $applied, $amount, $baseAmount, $rate)
766:     {
767:         $previouslyAppliedTaxes = $address->getAppliedTaxes();
768:         $process = count($previouslyAppliedTaxes);
769: 
770:         foreach ($applied as $row) {
771:             if ($row['percent'] == 0) {
772:                 continue;
773:             }
774:             if (!isset($previouslyAppliedTaxes[$row['id']])) {
775:                 $row['process']     = $process;
776:                 $row['amount']      = 0;
777:                 $row['base_amount'] = 0;
778:                 $previouslyAppliedTaxes[$row['id']] = $row;
779:             }
780: 
781:             if (!is_null($row['percent'])) {
782:                 $row['percent'] = $row['percent'] ? $row['percent'] : 1;
783:                 $rate = $rate ? $rate : 1;
784: 
785:                 $appliedAmount      = $amount/$rate*$row['percent'];
786:                 $baseAppliedAmount  = $baseAmount/$rate*$row['percent'];
787:             } else {
788:                 $appliedAmount      = 0;
789:                 $baseAppliedAmount  = 0;
790:                 foreach ($row['rates'] as $rate) {
791:                     $appliedAmount      += $rate['amount'];
792:                     $baseAppliedAmount  += $rate['base_amount'];
793:                 }
794:             }
795: 
796: 
797:             if ($appliedAmount || $previouslyAppliedTaxes[$row['id']]['amount']) {
798:                 $previouslyAppliedTaxes[$row['id']]['amount']       += $appliedAmount;
799:                 $previouslyAppliedTaxes[$row['id']]['base_amount']  += $baseAppliedAmount;
800:             } else {
801:                 unset($previouslyAppliedTaxes[$row['id']]);
802:             }
803:         }
804:         $address->setAppliedTaxes($previouslyAppliedTaxes);
805:     }
806: 
807:     /**
808:      * Add tax totals information to address object
809:      *
810:      * @param   Mage_Sales_Model_Quote_Address $address
811:      * @return  Mage_Tax_Model_Sales_Total_Quote
812:      */
813:     public function fetch(Mage_Sales_Model_Quote_Address $address)
814:     {
815:         $applied    = $address->getAppliedTaxes();
816:         $store      = $address->getQuote()->getStore();
817:         $amount     = $address->getTaxAmount();
818: 
819:         $items = $this->_getAddressItems($address);
820:         $discountTaxCompensation = 0;
821:         foreach ($items as $item) {
822:             $discountTaxCompensation += $item->getDiscountTaxCompensation();
823:         }
824:         $taxAmount = $amount + $discountTaxCompensation;
825: 
826:         $area       = null;
827:         if ($this->_config->displayCartTaxWithGrandTotal($store) && $address->getGrandTotal()) {
828:             $area   = 'taxes';
829:         }
830: 
831:         if (($amount != 0) || ($this->_config->displayCartZeroTax($store))) {
832:             $address->addTotal(array(
833:                 'code'      => $this->getCode(),
834:                 'title'     => Mage::helper('tax')->__('Tax'),
835:                 'full_info' => $applied ? $applied : array(),
836:                 'value'     => $amount,
837:                 'area'      => $area
838:             ));
839:         }
840: 
841:         $store = $address->getQuote()->getStore();
842:         /**
843:          * Modify subtotal
844:          */
845:         if ($this->_config->displayCartSubtotalBoth($store) || $this->_config->displayCartSubtotalInclTax($store)) {
846:             if ($address->getSubtotalInclTax() > 0) {
847:                 $subtotalInclTax = $address->getSubtotalInclTax();
848:             } else {
849:                 $subtotalInclTax = $address->getSubtotal() + $taxAmount - $address->getShippingTaxAmount();
850:             }
851: 
852:             $address->addTotal(array(
853:                 'code'      => 'subtotal',
854:                 'title'     => Mage::helper('sales')->__('Subtotal'),
855:                 'value'     => $subtotalInclTax,
856:                 'value_incl_tax' => $subtotalInclTax,
857:                 'value_excl_tax' => $address->getSubtotal(),
858:             ));
859:         }
860: 
861:         return $this;
862:     }
863: 
864:     /**
865:      * Process model configuration array.
866:      * This method can be used for changing totals collect sort order
867:      *
868:      * @param   array $config
869:      * @param   store $store
870:      * @return  array
871:      */
872:     public function processConfigArray($config, $store)
873:     {
874:         $calculationSequence = $this->_helper->getCalculationSequence($store);
875:          switch ($calculationSequence) {
876:             case Mage_Tax_Model_Calculation::CALC_TAX_BEFORE_DISCOUNT_ON_INCL:
877:                 $config['before'][] = 'discount';
878:                 break;
879:             default:
880:                 $config['after'][] = 'discount';
881:                 break;
882:         }
883:         return $config;
884:     }
885: 
886:     /**
887:      * Get Tax label
888:      *
889:      * @return string
890:      */
891:     public function getLabel()
892:     {
893:         return Mage::helper('tax')->__('Tax');
894:     }
895: }
896: 
Magento 1.7.0.2 API documentation generated by ApiGen 2.8.0