1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25:
26:
27: 28: 29:
30: class Mage_Tax_Model_Sales_Total_Quote_Tax extends Mage_Sales_Model_Quote_Address_Total_Abstract
31: {
32: 33: 34: 35: 36:
37: protected $_helper;
38:
39: 40: 41: 42: 43:
44: protected $_calculator;
45:
46: 47: 48: 49: 50:
51: protected $_config;
52:
53: 54: 55: 56: 57: 58:
59: protected $_areTaxRequestsSimilar = false;
60:
61:
62: protected $_roundingDeltas = array();
63: protected $_baseRoundingDeltas = array();
64:
65: protected $_store;
66:
67: 68: 69: 70: 71:
72: protected $_hiddenTaxes = array();
73:
74: 75: 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: 87: 88: 89: 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: 153: 154: 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:
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:
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: 204: 205: 206: 207: 208: 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: 220: 221: 222: 223: 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: 292: 293: 294: 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: 356: 357: 358: 359: 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) {
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: 426: 427: 428: 429: 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: 491: 492: 493: 494: 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) {
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: 558: 559: 560: 561: 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: 620: 621: 622: 623: 624: 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: 717: 718: 719: 720: 721: 722: 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: 739: 740: 741: 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: 758: 759: 760: 761: 762: 763: 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: 809: 810: 811: 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: 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: 866: 867: 868: 869: 870: 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: 888: 889: 890:
891: public function getLabel()
892: {
893: return Mage::helper('tax')->__('Tax');
894: }
895: }
896: