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_Helper_Data extends Mage_Core_Helper_Abstract
31: {
32: const PRICE_CONVERSION_PLUS = 1;
33: const PRICE_CONVERSION_MINUS = 2;
34:
35: 36: 37: 38: 39:
40: protected $_config = null;
41: protected $_calculator = null;
42: protected $_displayTaxColumn;
43: protected $_taxData;
44: protected $_priceIncludesTax;
45: protected $_shippingPriceIncludesTax;
46: protected $_applyTaxAfterDiscount;
47: protected $_priceDisplayType;
48: protected $_shippingPriceDisplayType;
49:
50: 51: 52: 53: 54:
55: protected $_postCodeSubStringLength = 10;
56:
57: public function __construct()
58: {
59: $this->_config = Mage::getSingleton('tax/config');
60: }
61:
62: 63: 64: 65: 66:
67: public function getPostCodeSubStringLength()
68: {
69: $len = (int)$this->_postCodeSubStringLength;
70: if ($len <= 0) {
71: $len = 10;
72: }
73: return $len;
74: }
75:
76: 77: 78: 79: 80:
81: public function getConfig()
82: {
83: return $this->_config;
84: }
85:
86: 87: 88: 89: 90:
91: public function getCalculator()
92: {
93: if ($this->_calculator === null) {
94: $this->_calculator = Mage::getSingleton('tax/calculation');
95: }
96: return $this->_calculator;
97: }
98:
99: 100: 101: 102: 103: 104: 105:
106: public function getProductPrice($product, $format=null)
107: {
108: try {
109: $value = $product->getPrice();
110: $value = Mage::app()->getStore()->convertPrice($value, $format);
111: } catch (Exception $e){
112: $value = $e->getMessage();
113: }
114: return $value;
115: }
116:
117: 118: 119: 120: 121: 122:
123: public function priceIncludesTax($store=null)
124: {
125: return $this->_config->priceIncludesTax($store) || $this->_config->getNeedUseShippingExcludeTax();
126: }
127:
128: 129: 130: 131: 132: 133:
134: public function applyTaxAfterDiscount($store=null)
135: {
136: return $this->_config->applyTaxAfterDiscount($store);
137: }
138:
139: 140: 141: 142: 143:
144: public function getIncExcText($flag, $store=null)
145: {
146: if ($flag) {
147: $s = $this->__('Incl. Tax');
148: } else {
149: $s = $this->__('Excl. Tax');
150: }
151: return $s;
152: }
153:
154: 155: 156: 157: 158: 159: 160: 161: 162:
163: public function getPriceDisplayType($store = null)
164: {
165: return $this->_config->getPriceDisplayType($store);
166: }
167:
168: 169: 170: 171: 172: 173: 174:
175: public function needPriceConversion($store = null)
176: {
177: $res = false;
178: if ($this->priceIncludesTax($store)) {
179: switch ($this->getPriceDisplayType($store)) {
180: case Mage_Tax_Model_Config::DISPLAY_TYPE_EXCLUDING_TAX:
181: case Mage_Tax_Model_Config::DISPLAY_TYPE_BOTH:
182: return self::PRICE_CONVERSION_MINUS;
183: case Mage_Tax_Model_Config::DISPLAY_TYPE_INCLUDING_TAX:
184: $res = true;
185: }
186: } else {
187: switch ($this->getPriceDisplayType($store)) {
188: case Mage_Tax_Model_Config::DISPLAY_TYPE_INCLUDING_TAX:
189: case Mage_Tax_Model_Config::DISPLAY_TYPE_BOTH:
190: return self::PRICE_CONVERSION_PLUS;
191: case Mage_Tax_Model_Config::DISPLAY_TYPE_EXCLUDING_TAX:
192: $res = false;
193: }
194: }
195:
196: if ($res === false) {
197: $res = $this->displayTaxColumn($store);
198: }
199: return $res;
200: }
201:
202: 203: 204: 205: 206: 207:
208: public function displayFullSummary($store = null)
209: {
210: return $this->_config->displayCartFullSummary($store);
211: }
212:
213: 214: 215: 216: 217: 218:
219: public function displayZeroTax($store = null)
220: {
221: return $this->_config->displayCartZeroTax($store);
222: }
223:
224: 225: 226: 227: 228: 229:
230: public function displayCartPriceInclTax($store = null)
231: {
232: return $this->_config->displayCartPricesInclTax($store);
233: }
234:
235: 236: 237: 238: 239: 240:
241: public function displayCartPriceExclTax($store = null)
242: {
243: return $this->_config->displayCartPricesExclTax($store);
244: }
245:
246: 247: 248: 249: 250: 251:
252: public function displayCartBothPrices($store = null)
253: {
254: return $this->_config->displayCartPricesBoth($store);
255: }
256:
257: 258: 259: 260: 261: 262:
263: public function displaySalesPriceInclTax($store = null)
264: {
265: return $this->_config->displaySalesPricesInclTax($store);
266: }
267:
268: 269: 270: 271: 272: 273:
274: public function displaySalesPriceExclTax($store = null)
275: {
276: return $this->_config->displaySalesPricesExclTax($store);
277: }
278:
279: 280: 281: 282: 283: 284:
285: public function displaySalesBothPrices($store = null)
286: {
287: return $this->_config->displaySalesPricesBoth($store);
288: }
289:
290:
291: 292: 293: 294: 295: 296:
297: public function displaySalesSubtotalBoth($store = null)
298: {
299: return $this->_config->displaySalesSubtotalBoth($store);
300: }
301:
302: 303: 304: 305: 306: 307:
308: public function displaySalesSubtotalInclTax($store = null)
309: {
310: return $this->_config->displaySalesSubtotalInclTax($store);
311: }
312:
313: 314: 315: 316: 317: 318:
319: public function displaySalesSubtotalExclTax($store = null)
320: {
321: return $this->_config->displaySalesSubtotalExclTax($store);
322: }
323:
324: 325: 326: 327: 328: 329:
330: public function displayTaxColumn($store = null)
331: {
332: return $this->_config->displayCartPricesBoth();
333: }
334:
335: 336: 337: 338: 339: 340:
341: public function getPriceFormat($store = null)
342: {
343: Mage::app()->getLocale()->emulate($store);
344: $priceFormat = Mage::app()->getLocale()->getJsPriceFormat();
345: Mage::app()->getLocale()->revert();
346: if ($store) {
347: $priceFormat['pattern'] = Mage::app()->getStore($store)->getCurrentCurrency()->getOutputFormat();
348: }
349: return Mage::helper('core')->jsonEncode($priceFormat);
350: }
351:
352: 353: 354: 355: 356: 357: 358: 359: 360:
361: public function getTaxRatesByProductClass()
362: {
363: return $this->_getAllRatesByProductClass();
364: }
365:
366: 367: 368: 369: 370: 371: 372: 373:
374: public function getAllRatesByProductClass($store=null)
375: {
376: return $this->_getAllRatesByProductClass($store);
377: }
378:
379:
380: 381: 382: 383: 384: 385: 386: 387:
388: protected function _getAllRatesByProductClass($store=null)
389: {
390: $result = array();
391: $calc = Mage::getSingleton('tax/calculation');
392: $rates = $calc->getRatesForAllProductTaxClasses($calc->getRateOriginRequest($store));
393:
394: foreach ($rates as $class=>$rate) {
395: $result["value_{$class}"] = $rate;
396: }
397:
398: return Mage::helper('core')->jsonEncode($result);
399: }
400:
401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411: 412: 413:
414: public function getPrice($product, $price, $includingTax = null, $shippingAddress = null, $billingAddress = null,
415: $ctc = null, $store = null, $priceIncludesTax = null
416: ) {
417: if (!$price) {
418: return $price;
419: }
420: $store = Mage::app()->getStore($store);
421: if (!$this->needPriceConversion($store)) {
422: return $store->roundPrice($price);
423: }
424: if (is_null($priceIncludesTax)) {
425: $priceIncludesTax = $this->priceIncludesTax($store);
426: }
427:
428: $percent = $product->getTaxPercent();
429: $includingPercent = null;
430:
431: $taxClassId = $product->getTaxClassId();
432: if (is_null($percent)) {
433: if ($taxClassId) {
434: $request = Mage::getSingleton('tax/calculation')
435: ->getRateRequest($shippingAddress, $billingAddress, $ctc, $store);
436: $percent = Mage::getSingleton('tax/calculation')
437: ->getRate($request->setProductClassId($taxClassId));
438: }
439: }
440: if ($taxClassId && $priceIncludesTax) {
441: $request = Mage::getSingleton('tax/calculation')->getRateRequest(false, false, false, $store);
442: $includingPercent = Mage::getSingleton('tax/calculation')
443: ->getRate($request->setProductClassId($taxClassId));
444: }
445:
446: if ($percent === false || is_null($percent)) {
447: if ($priceIncludesTax && !$includingPercent) {
448: return $price;
449: }
450: }
451:
452: $product->setTaxPercent($percent);
453:
454: if (!is_null($includingTax)) {
455: if ($priceIncludesTax) {
456: if ($includingTax) {
457: 458: 459:
460: if ($includingPercent != $percent) {
461: $price = $this->_calculatePrice($price, $includingPercent, false);
462: 463: 464: 465: 466: 467: 468: 469: 470: 471: 472: 473: 474:
475: if ($percent != 0) {
476: $price = $this->getCalculator()->round($price);
477: $price = $this->_calculatePrice($price, $percent, true);
478: }
479: }
480: } else {
481: $price = $this->_calculatePrice($price, $includingPercent, false);
482: }
483: } else {
484: if ($includingTax) {
485: $price = $this->_calculatePrice($price, $percent, true);
486: }
487: }
488: } else {
489: if ($priceIncludesTax) {
490: switch ($this->getPriceDisplayType($store)) {
491: case Mage_Tax_Model_Config::DISPLAY_TYPE_EXCLUDING_TAX:
492: case Mage_Tax_Model_Config::DISPLAY_TYPE_BOTH:
493: $price = $this->_calculatePrice($price, $includingPercent, false);
494: break;
495:
496: case Mage_Tax_Model_Config::DISPLAY_TYPE_INCLUDING_TAX:
497: $price = $this->_calculatePrice($price, $includingPercent, false);
498: $price = $this->_calculatePrice($price, $percent, true);
499: break;
500: }
501: } else {
502: switch ($this->getPriceDisplayType($store)) {
503: case Mage_Tax_Model_Config::DISPLAY_TYPE_INCLUDING_TAX:
504: $price = $this->_calculatePrice($price, $percent, true);
505: break;
506:
507: case Mage_Tax_Model_Config::DISPLAY_TYPE_BOTH:
508: case Mage_Tax_Model_Config::DISPLAY_TYPE_EXCLUDING_TAX:
509: break;
510: }
511: }
512: }
513: return $store->roundPrice($price);
514: }
515:
516: 517: 518: 519: 520:
521: public function displayPriceIncludingTax()
522: {
523: return $this->getPriceDisplayType() == Mage_Tax_Model_Config::DISPLAY_TYPE_INCLUDING_TAX;
524: }
525:
526: 527: 528: 529: 530:
531: public function displayPriceExcludingTax()
532: {
533: return $this->getPriceDisplayType() == Mage_Tax_Model_Config::DISPLAY_TYPE_EXCLUDING_TAX;
534: }
535:
536: 537: 538: 539: 540:
541: public function displayBothPrices()
542: {
543: return $this->getPriceDisplayType() == Mage_Tax_Model_Config::DISPLAY_TYPE_BOTH;
544: }
545:
546: 547: 548: 549: 550: 551: 552: 553:
554: protected function _calculatePrice($price, $percent, $type)
555: {
556: $calculator = Mage::getSingleton('tax/calculation');
557: if ($type) {
558: $taxAmount = $calculator->calcTaxAmount($price, $percent, false, false);
559: return $price + $taxAmount;
560: } else {
561: $taxAmount = $calculator->calcTaxAmount($price, $percent, true, false);
562: return $price - $taxAmount;
563: }
564: }
565:
566: public function getIncExcTaxLabel($flag)
567: {
568: $text = $this->getIncExcText($flag);
569: return $text ? ' <span class="tax-flag">('.$text.')</span>' : '';
570: }
571:
572: public function shippingPriceIncludesTax($store = null)
573: {
574: return $this->_config->shippingPriceIncludesTax($store);
575: }
576:
577: public function getShippingPriceDisplayType($store = null)
578: {
579: return $this->_config->getShippingPriceDisplayType($store);
580: }
581:
582: public function displayShippingPriceIncludingTax()
583: {
584: return $this->getShippingPriceDisplayType() == Mage_Tax_Model_Config::DISPLAY_TYPE_INCLUDING_TAX;
585: }
586:
587: public function displayShippingPriceExcludingTax()
588: {
589: return $this->getShippingPriceDisplayType() == Mage_Tax_Model_Config::DISPLAY_TYPE_EXCLUDING_TAX;
590: }
591:
592: public function displayShippingBothPrices()
593: {
594: return $this->getShippingPriceDisplayType() == Mage_Tax_Model_Config::DISPLAY_TYPE_BOTH;
595: }
596:
597: public function getShippingTaxClass($store)
598: {
599: return $this->_config->getShippingTaxClass($store);
600: }
601:
602: 603: 604: 605: 606:
607: public function getShippingPrice($price, $includingTax = null, $shippingAddress = null, $ctc = null, $store = null)
608: {
609: $pseudoProduct = new Varien_Object();
610: $pseudoProduct->setTaxClassId($this->getShippingTaxClass($store));
611:
612: $billingAddress = false;
613: if ($shippingAddress && $shippingAddress->getQuote() && $shippingAddress->getQuote()->getBillingAddress()) {
614: $billingAddress = $shippingAddress->getQuote()->getBillingAddress();
615: }
616:
617: $price = $this->getPrice(
618: $pseudoProduct,
619: $price,
620: $includingTax,
621: $shippingAddress,
622: $billingAddress,
623: $ctc,
624: $store,
625: $this->shippingPriceIncludesTax($store)
626: );
627: return $price;
628: }
629:
630: public function getPriceTaxSql($priceField, $taxClassField)
631: {
632: if (!$this->priceIncludesTax() && $this->displayPriceExcludingTax()) {
633: return '';
634: }
635:
636: $request = Mage::getSingleton('tax/calculation')->getRateRequest(false, false, false);
637: $defaultTaxes = Mage::getSingleton('tax/calculation')->getRatesForAllProductTaxClasses($request);
638:
639: $request = Mage::getSingleton('tax/calculation')->getRateRequest();
640: $currentTaxes = Mage::getSingleton('tax/calculation')->getRatesForAllProductTaxClasses($request);
641:
642: $defaultTaxString = $currentTaxString = '';
643:
644: $rateToVariable = array(
645: 'defaultTaxString'=>'defaultTaxes',
646: 'currentTaxString'=>'currentTaxes',
647: );
648: foreach ($rateToVariable as $rateVariable=>$rateArray) {
649: if ($$rateArray && is_array($$rateArray)) {
650: $$rateVariable = '';
651: foreach ($$rateArray as $classId=>$rate) {
652: if ($rate) {
653: $$rateVariable .= sprintf("WHEN %d THEN %12.4f ", $classId, $rate/100);
654: }
655: }
656: if ($$rateVariable) {
657: $$rateVariable = "CASE {$taxClassField} {$$rateVariable} ELSE 0 END";
658: }
659: }
660: }
661:
662: $result = '';
663:
664: if ($this->priceIncludesTax()) {
665: if ($defaultTaxString) {
666: $result = "-({$priceField}/(1+({$defaultTaxString}))*{$defaultTaxString})";
667: }
668: if (!$this->displayPriceExcludingTax() && $currentTaxString) {
669: $result .= "+(({$priceField}{$result})*{$currentTaxString})";
670: }
671: } else {
672: if ($this->displayPriceIncludingTax()) {
673: if ($currentTaxString) {
674: $result .= "+({$priceField}*{$currentTaxString})";
675: }
676: }
677: }
678: return $result;
679: }
680:
681: 682: 683: 684: 685: 686: 687:
688: public function joinTaxClass($select, $storeId, $priceTable = 'main_table')
689: {
690: $taxClassAttribute = Mage::getModel('eav/entity_attribute')
691: ->loadByCode(Mage_Catalog_Model_Product::ENTITY, 'tax_class_id');
692: $joinConditionD = implode(' AND ',array(
693: "tax_class_d.entity_id = {$priceTable}.entity_id",
694: $select->getAdapter()->quoteInto('tax_class_d.attribute_id = ?', (int)$taxClassAttribute->getId()),
695: 'tax_class_d.store_id = 0'
696: ));
697: $joinConditionC = implode(' AND ',array(
698: "tax_class_c.entity_id = {$priceTable}.entity_id",
699: $select->getAdapter()->quoteInto('tax_class_c.attribute_id = ?', (int)$taxClassAttribute->getId()),
700: $select->getAdapter()->quoteInto('tax_class_c.store_id = ?', (int)$storeId)
701: ));
702: $select
703: ->joinLeft(
704: array('tax_class_d' => $taxClassAttribute->getBackend()->getTable()),
705: $joinConditionD,
706: array())
707: ->joinLeft(
708: array('tax_class_c' => $taxClassAttribute->getBackend()->getTable()),
709: $joinConditionC,
710: array());
711:
712: return $this;
713: }
714:
715: 716: 717: 718: 719: 720:
721: public function discountTax($store=null)
722: {
723: return $this->_config->discountTax($store);
724: }
725:
726: 727: 728: 729: 730: 731:
732: public function getTaxBasedOn($store = null)
733: {
734: return Mage::getStoreConfig(Mage_Tax_Model_Config::CONFIG_XML_PATH_BASED_ON, $store);
735: }
736:
737: 738: 739: 740: 741: 742:
743: public function applyTaxOnCustomPrice($store = null)
744: {
745: return ((int) Mage::getStoreConfig(Mage_Tax_Model_Config::CONFIG_XML_PATH_APPLY_ON, $store) == 0);
746: }
747:
748: 749: 750: 751: 752: 753:
754: public function applyTaxOnOriginalPrice($store = null)
755: {
756: return ((int) Mage::getStoreConfig(Mage_Tax_Model_Config::CONFIG_XML_PATH_APPLY_ON, $store) == 1);
757: }
758:
759: 760: 761: 762: 763: 764: 765: 766:
767: public function getCalculationSequence($store=null)
768: {
769: return $this->_config->getCalculationSequence($store);
770: }
771:
772: 773: 774: 775: 776: 777:
778: public function getCalculationAgorithm($store=null)
779: {
780: return $this->_config->getAlgorithm($store);
781: }
782:
783: 784: 785: 786: 787: 788: 789: 790: 791: 792: 793: 794: 795: 796: 797: 798: 799:
800: public function getCalculatedTaxes($source)
801: {
802: if (Mage::registry('current_invoice')) {
803: $current = Mage::registry('current_invoice');
804: } elseif (Mage::registry('current_creditmemo')) {
805: $current = Mage::registry('current_creditmemo');
806: } else {
807: $current = $source;
808: }
809:
810: $taxClassAmount = array();
811: if ($current && $source) {
812: foreach($current->getItemsCollection() as $item) {
813: $taxCollection = Mage::getResourceModel('tax/sales_order_tax_item')
814: ->getTaxItemsByItemId(
815: $item->getOrderItemId() ? $item->getOrderItemId() : $item->getItemId()
816: );
817:
818: foreach ($taxCollection as $tax) {
819: $taxClassId = $tax['tax_id'];
820: $percent = $tax['tax_percent'];
821:
822: $price = $item->getRowTotal();
823: $basePrice = $item->getBaseRowTotal();
824: if ($this->applyTaxAfterDiscount($item->getStoreId())) {
825: $price = $price - $item->getDiscountAmount() + $item->getHiddenTaxAmount();
826: $basePrice = $basePrice - $item->getBaseDiscountAmount() + $item->getBaseHiddenTaxAmount();
827: }
828:
829: if (isset($taxClassAmount[$taxClassId])) {
830: $taxClassAmount[$taxClassId]['tax_amount'] += $price * $percent / 100;
831: $taxClassAmount[$taxClassId]['base_tax_amount'] += $basePrice * $percent / 100;
832: } else {
833: $taxClassAmount[$taxClassId]['tax_amount'] = $price * $percent / 100;
834: $taxClassAmount[$taxClassId]['base_tax_amount'] = $basePrice * $percent / 100;
835: $taxClassAmount[$taxClassId]['title'] = $tax['title'];
836: $taxClassAmount[$taxClassId]['percent'] = $tax['percent'];
837: }
838: }
839: }
840:
841: foreach ($taxClassAmount as $key=>$tax) {
842: if ($tax['tax_amount'] == 0 && $tax['base_tax_amount'] == 0) {
843: unset($taxClassAmount[$key]);
844: }
845: }
846:
847: $taxClassAmount = array_values($taxClassAmount);
848: }
849:
850: return $taxClassAmount;
851: }
852:
853: 854: 855: 856: 857: 858: 859: 860: 861: 862: 863: 864: 865: 866: 867: 868: 869:
870: public function getShippingTax($source)
871: {
872: if (Mage::registry('current_invoice')) {
873: $current = Mage::registry('current_invoice');
874: } elseif (Mage::registry('current_creditmemo')) {
875: $current = Mage::registry('current_creditmemo');
876: } else {
877: $current = $source;
878: }
879:
880: $taxClassAmount = array();
881: if ($current && $source) {
882: if ($current->getShippingTaxAmount() != 0 && $current->getBaseShippingTaxAmount() != 0) {
883: $taxClassAmount[0]['tax_amount'] = $current->getShippingTaxAmount();
884: $taxClassAmount[0]['base_tax_amount'] = $current->getBaseShippingTaxAmount();
885: if ($current->getShippingHiddenTaxAmount() > 0) {
886: $taxClassAmount[0]['hidden_tax_amount'] = $current->getShippingHiddenTaxAmount();
887: }
888: $taxClassAmount[0]['title'] = $this->__('Shipping & Handling Tax');
889: $taxClassAmount[0]['percent'] = NULL;
890: }
891: }
892:
893: return $taxClassAmount;
894: }
895: }
896: