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: 31: 32: 33:
34: class Mage_Bundle_Model_Product_Price extends Mage_Catalog_Model_Product_Type_Price
35: {
36: const PRICE_TYPE_FIXED = 1;
37: const PRICE_TYPE_DYNAMIC = 0;
38:
39: 40: 41: 42: 43:
44: protected $_isPricesCalculatedByIndex;
45:
46: 47: 48: 49: 50:
51: public function getIsPricesCalculatedByIndex()
52: {
53: return $this->_isPricesCalculatedByIndex;
54: }
55:
56: 57: 58: 59: 60: 61:
62: public function getPrice($product)
63: {
64: if ($product->getPriceType() == self::PRICE_TYPE_FIXED) {
65: return $product->getData('price');
66: } else {
67: return 0;
68: }
69: }
70:
71: 72: 73: 74: 75: 76: 77:
78: public function getTotalBundleItemsPrice($product, $qty = null)
79: {
80: $price = 0.0;
81: if ($product->hasCustomOptions()) {
82: $customOption = $product->getCustomOption('bundle_selection_ids');
83: if ($customOption) {
84: $selectionIds = unserialize($customOption->getValue());
85: $selections = $product->getTypeInstance(true)->getSelectionsByIds($selectionIds, $product);
86: $selections->addTierPriceData();
87: Mage::dispatchEvent('prepare_catalog_product_collection_prices', array(
88: 'collection' => $selections,
89: 'store_id' => $product->getStoreId(),
90: ));
91: foreach ($selections->getItems() as $selection) {
92: if ($selection->isSalable()) {
93: $selectionQty = $product->getCustomOption('selection_qty_' . $selection->getSelectionId());
94: if ($selectionQty) {
95: $price += $this->getSelectionFinalTotalPrice($product, $selection, $qty,
96: $selectionQty->getValue());
97: }
98: }
99: }
100: }
101: }
102: return $price;
103: }
104:
105: 106: 107: 108: 109: 110: 111:
112: public function getFinalPrice($qty = null, $product)
113: {
114: if (is_null($qty) && !is_null($product->getCalculatedFinalPrice())) {
115: return $product->getCalculatedFinalPrice();
116: }
117:
118: $finalPrice = $this->getBasePrice($product, $qty);
119: $product->setFinalPrice($finalPrice);
120: Mage::dispatchEvent('catalog_product_get_final_price', array('product' => $product, 'qty' => $qty));
121: $finalPrice = $product->getData('final_price');
122:
123: $finalPrice = $this->_applyOptionsPrice($product, $qty, $finalPrice);
124: $finalPrice += $this->getTotalBundleItemsPrice($product, $qty);
125:
126: $product->setFinalPrice($finalPrice);
127: return max(0, $product->getData('final_price'));
128: }
129:
130: 131: 132: 133: 134: 135: 136: 137: 138:
139: public function getChildFinalPrice($product, $productQty, $childProduct, $childProductQty)
140: {
141: return $this->getSelectionFinalTotalPrice($product, $childProduct, $productQty, $childProductQty, false);
142: }
143:
144: 145: 146: 147: 148: 149: 150: 151: 152: 153:
154: public function getPrices($product, $which = null)
155: {
156: return $this->getTotalPrices($product, $which);
157: }
158:
159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169:
170: public function getPricesDependingOnTax($product, $which = null, $includeTax = null)
171: {
172: return $this->getTotalPrices($product, $which, $includeTax);
173: }
174:
175: 176: 177: 178: 179: 180: 181: 182: 183:
184: public function getTotalPrices($product, $which = null, $includeTax = null, $takeTierPrice = true)
185: {
186:
187: if ($product->getData('min_price') && $product->getData('max_price')) {
188: $minimalPrice = Mage::helper('tax')->getPrice($product, $product->getData('min_price'), $includeTax);
189: $maximalPrice = Mage::helper('tax')->getPrice($product, $product->getData('max_price'), $includeTax);
190: $this->_isPricesCalculatedByIndex = true;
191: } else {
192: 193: 194:
195: $finalPrice = $product->getFinalPrice();
196: if ($product->getPriceType() == self::PRICE_TYPE_FIXED) {
197: $minimalPrice = $maximalPrice = Mage::helper('tax')->getPrice($product, $finalPrice, $includeTax);
198: } else {
199: $minimalPrice = $maximalPrice = 0;
200: }
201:
202: $options = $this->getOptions($product);
203: $minPriceFounded = false;
204:
205: if ($options) {
206: foreach ($options as $option) {
207:
208: $selections = $option->getSelections();
209: if ($selections) {
210: $selectionMinimalPrices = array();
211: $selectionMaximalPrices = array();
212:
213: foreach ($option->getSelections() as $selection) {
214:
215: if (!$selection->isSalable()) {
216: 217: 218:
219: continue;
220: }
221:
222: $qty = $selection->getSelectionQty();
223:
224: $item = $product->getPriceType() == self::PRICE_TYPE_FIXED ? $product : $selection;
225:
226: $selectionMinimalPrices[] = Mage::helper('tax')->getPrice(
227: $item,
228: $this->getSelectionFinalTotalPrice($product, $selection, 1, $qty, true, $takeTierPrice),
229: $includeTax
230: );
231: $selectionMaximalPrices[] = Mage::helper('tax')->getPrice(
232: $item,
233: $this->getSelectionFinalTotalPrice($product, $selection, 1, null, true, $takeTierPrice),
234: $includeTax
235: );
236: }
237:
238: if (count($selectionMinimalPrices)) {
239: $selMinPrice = min($selectionMinimalPrices);
240: if ($option->getRequired()) {
241: $minimalPrice += $selMinPrice;
242: $minPriceFounded = true;
243: } elseif (true !== $minPriceFounded) {
244: $selMinPrice += $minimalPrice;
245: $minPriceFounded = (false === $minPriceFounded)
246: ? $selMinPrice
247: : min($minPriceFounded, $selMinPrice);
248: }
249:
250: if ($option->isMultiSelection()) {
251: $maximalPrice += array_sum($selectionMaximalPrices);
252: } else {
253: $maximalPrice += max($selectionMaximalPrices);
254: }
255: }
256: }
257: }
258: }
259:
260: if (!is_bool($minPriceFounded)) {
261: $minimalPrice = $minPriceFounded;
262: }
263:
264: $customOptions = $product->getOptions();
265: if ($product->getPriceType() == self::PRICE_TYPE_FIXED && $customOptions) {
266: foreach ($customOptions as $customOption) {
267:
268: $values = $customOption->getValues();
269: if ($values) {
270: $prices = array();
271: foreach ($values as $value) {
272:
273: $valuePrice = $value->getPrice(true);
274:
275: $prices[] = $valuePrice;
276: }
277: if (count($prices)) {
278: if ($customOption->getIsRequire()) {
279: $minimalPrice += Mage::helper('tax')->getPrice($product, min($prices), $includeTax);
280: }
281:
282: $multiTypes = array(
283:
284: Mage_Catalog_Model_Product_Option::OPTION_TYPE_CHECKBOX,
285: Mage_Catalog_Model_Product_Option::OPTION_TYPE_MULTIPLE
286: );
287:
288: if (in_array($customOption->getType(), $multiTypes)) {
289: $maximalValue = array_sum($prices);
290: } else {
291: $maximalValue = max($prices);
292: }
293: $maximalPrice += Mage::helper('tax')->getPrice($product, $maximalValue, $includeTax);
294: }
295: } else {
296: $valuePrice = $customOption->getPrice(true);
297:
298: if ($customOption->getIsRequire()) {
299: $minimalPrice += Mage::helper('tax')->getPrice($product, $valuePrice, $includeTax);
300: }
301: $maximalPrice += Mage::helper('tax')->getPrice($product, $valuePrice, $includeTax);
302: }
303: }
304: }
305: $this->_isPricesCalculatedByIndex = false;
306: }
307:
308: if ($which == 'max') {
309: return $maximalPrice;
310: } elseif ($which == 'min') {
311: return $minimalPrice;
312: }
313:
314: return array($minimalPrice, $maximalPrice);
315: }
316:
317: 318: 319: 320: 321: 322:
323: public function getMinimalPrice($product)
324: {
325: return $this->getPricesTierPrice($product, 'min');
326: }
327:
328: 329: 330: 331: 332: 333:
334: public function getMaximalPrice($product)
335: {
336: return $this->getPricesTierPrice($product, 'max');
337: }
338:
339: 340: 341: 342: 343: 344:
345: public function getOptions($product)
346: {
347: $product->getTypeInstance(true)
348: ->setStoreFilter($product->getStoreId(), $product);
349:
350: $optionCollection = $product->getTypeInstance(true)
351: ->getOptionsCollection($product);
352:
353: $selectionCollection = $product->getTypeInstance(true)
354: ->getSelectionsCollection(
355: $product->getTypeInstance(true)->getOptionsIds($product),
356: $product
357: );
358:
359: return $optionCollection->appendSelections($selectionCollection, false, false);
360: }
361:
362: 363: 364: 365: 366: 367: 368: 369: 370: 371: 372: 373:
374: public function getSelectionPrice($bundleProduct, $selectionProduct, $selectionQty = null, $multiplyQty = true)
375: {
376: return $this->getSelectionFinalTotalPrice($bundleProduct, $selectionProduct, 0, $selectionQty, $multiplyQty);
377: }
378:
379: 380: 381: 382: 383: 384: 385: 386:
387: public function getSelectionPreFinalPrice($bundleProduct, $selectionProduct, $qty = null)
388: {
389: return $this->getSelectionPrice($bundleProduct, $selectionProduct, $qty);
390: }
391:
392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404:
405: public function getSelectionFinalPrice($bundleProduct, $selectionProduct, $bundleQty, $selectionQty = null,
406: $multiplyQty = true)
407: {
408: return $this->getSelectionFinalTotalPrice($bundleProduct, $selectionProduct, $bundleQty, $selectionQty,
409: $multiplyQty);
410: }
411:
412: 413: 414: 415: 416: 417: 418: 419: 420: 421: 422: 423:
424: public function getSelectionFinalTotalPrice($bundleProduct, $selectionProduct, $bundleQty, $selectionQty,
425: $multiplyQty = true, $takeTierPrice = true)
426: {
427: if (is_null($selectionQty)) {
428: $selectionQty = $selectionProduct->getSelectionQty();
429: }
430:
431: if ($bundleProduct->getPriceType() == self::PRICE_TYPE_DYNAMIC) {
432: $price = $selectionProduct->getFinalPrice($takeTierPrice ? $selectionQty : 1);
433: } else {
434: if ($selectionProduct->getSelectionPriceType()) {
435: $product = clone $bundleProduct;
436: $product->setFinalPrice($this->getPrice($product));
437: Mage::dispatchEvent(
438: 'catalog_product_get_final_price',
439: array('product' => $product, 'qty' => $bundleQty)
440: );
441: $price = $product->getData('final_price') * ($selectionProduct->getSelectionPriceValue() / 100);
442:
443: } else {
444: $price = $selectionProduct->getSelectionPriceValue();
445: }
446: }
447:
448: if ($multiplyQty) {
449: $price *= $selectionQty;
450: }
451:
452: return min($price,
453: $this->_applyGroupPrice($bundleProduct, $price),
454: $this->_applyTierPrice($bundleProduct, $bundleQty, $price),
455: $this->_applySpecialPrice($bundleProduct, $price)
456: );
457: }
458:
459: 460: 461: 462: 463: 464: 465:
466: protected function _applyGroupPrice($product, $finalPrice)
467: {
468: $result = $finalPrice;
469: $groupPrice = $product->getGroupPrice();
470:
471: if (is_numeric($groupPrice)) {
472: $groupPrice = $finalPrice - ($finalPrice * ($groupPrice / 100));
473: $result = min($finalPrice, $groupPrice);
474: }
475:
476: return $result;
477: }
478:
479: 480: 481: 482: 483: 484:
485: public function getGroupPrice($product)
486: {
487: $groupPrices = $product->getData('group_price');
488:
489: if (is_null($groupPrices)) {
490: $attribute = $product->getResource()->getAttribute('group_price');
491: if ($attribute) {
492: $attribute->getBackend()->afterLoad($product);
493: $groupPrices = $product->getData('group_price');
494: }
495: }
496:
497: if (is_null($groupPrices) || !is_array($groupPrices)) {
498: return null;
499: }
500:
501: $customerGroup = $this->_getCustomerGroupId($product);
502:
503: $matchedPrice = 0;
504:
505: foreach ($groupPrices as $groupPrice) {
506: if ($groupPrice['cust_group'] == $customerGroup && $groupPrice['website_price'] > $matchedPrice) {
507: $matchedPrice = $groupPrice['website_price'];
508: break;
509: }
510: }
511:
512: return $matchedPrice;
513: }
514:
515: 516: 517: 518: 519: 520: 521: 522:
523: protected function _applyTierPrice($product, $qty, $finalPrice)
524: {
525: if (is_null($qty)) {
526: return $finalPrice;
527: }
528:
529: $tierPrice = $product->getTierPrice($qty);
530:
531: if (is_numeric($tierPrice)) {
532: $tierPrice = $finalPrice - ($finalPrice * ($tierPrice / 100));
533: $finalPrice = min($finalPrice, $tierPrice);
534: }
535:
536: return $finalPrice;
537: }
538:
539: 540: 541: 542: 543: 544: 545:
546: public function getTierPrice($qty=null, $product)
547: {
548: $allGroups = Mage_Customer_Model_Group::CUST_GROUP_ALL;
549: $prices = $product->getData('tier_price');
550:
551: if (is_null($prices)) {
552: if ($attribute = $product->getResource()->getAttribute('tier_price')) {
553: $attribute->getBackend()->afterLoad($product);
554: $prices = $product->getData('tier_price');
555: }
556: }
557:
558: if (is_null($prices) || !is_array($prices)) {
559: if (!is_null($qty)) {
560: return $product->getPrice();
561: }
562: return array(array(
563: 'price' => $product->getPrice(),
564: 'website_price' => $product->getPrice(),
565: 'price_qty' => 1,
566: 'cust_group' => $allGroups
567: ));
568: }
569:
570: $custGroup = $this->_getCustomerGroupId($product);
571: if ($qty) {
572: $prevQty = 1;
573: $prevPrice = 0;
574: $prevGroup = $allGroups;
575:
576: foreach ($prices as $price) {
577: if ($price['cust_group']!=$custGroup && $price['cust_group']!=$allGroups) {
578:
579: continue;
580: }
581: if ($qty < $price['price_qty']) {
582:
583: continue;
584: }
585: if ($price['price_qty'] < $prevQty) {
586:
587: continue;
588: }
589: if ($price['price_qty'] == $prevQty && $prevGroup != $allGroups && $price['cust_group'] == $allGroups) {
590:
591: continue;
592: }
593:
594: if ($price['website_price'] > $prevPrice) {
595: $prevPrice = $price['website_price'];
596: $prevQty = $price['price_qty'];
597: $prevGroup = $price['cust_group'];
598: }
599: }
600:
601: return $prevPrice;
602: } else {
603: $qtyCache = array();
604: foreach ($prices as $i => $price) {
605: if ($price['cust_group'] != $custGroup && $price['cust_group'] != $allGroups) {
606: unset($prices[$i]);
607: } else if (isset($qtyCache[$price['price_qty']])) {
608: $j = $qtyCache[$price['price_qty']];
609: if ($prices[$j]['website_price'] < $price['website_price']) {
610: unset($prices[$j]);
611: $qtyCache[$price['price_qty']] = $i;
612: } else {
613: unset($prices[$i]);
614: }
615: } else {
616: $qtyCache[$price['price_qty']] = $i;
617: }
618: }
619: }
620:
621: return ($prices) ? $prices : array();
622: }
623:
624: 625: 626: 627: 628: 629: 630: 631: 632: 633: 634: 635: 636:
637: public static function calculatePrice($basePrice, $specialPrice, $specialPriceFrom, $specialPriceTo,
638: $rulePrice = false, $wId = null, $gId = null, $productId = null)
639: {
640: $resource = Mage::getResourceSingleton('bundle/bundle');
641: $selectionResource = Mage::getResourceSingleton('bundle/selection');
642: $productPriceTypeId = Mage::getSingleton('eav/entity_attribute')->getIdByCode(
643: Mage_Catalog_Model_Product::ENTITY,
644: 'price_type'
645: );
646:
647: if ($wId instanceof Mage_Core_Model_Store) {
648: $store = $wId->getId();
649: $wId = $wId->getWebsiteId();
650: } else {
651: $store = Mage::app()->getStore($wId)->getId();
652: $wId = Mage::app()->getStore($wId)->getWebsiteId();
653: }
654:
655: if (!$gId) {
656: $gId = Mage::getSingleton('customer/session')->getCustomerGroupId();
657: } else if ($gId instanceof Mage_Customer_Model_Group) {
658: $gId = $gId->getId();
659: }
660:
661: if (!isset(self::$attributeCache[$productId]['price_type'])) {
662: $attributes = $resource->getAttributeData($productId, $productPriceTypeId, $store);
663: self::$attributeCache[$productId]['price_type'] = $attributes;
664: } else {
665: $attributes = self::$attributeCache[$productId]['price_type'];
666: }
667:
668: $options = array(0);
669: $results = $resource->getSelectionsData($productId);
670:
671: if (!$attributes || !$attributes[0]['value']) {
672: foreach ($results as $result) {
673: if (!$result['product_id']) {
674: continue;
675: }
676:
677: if ($result['selection_can_change_qty'] && $result['type'] != 'multi'
678: && $result['type'] != 'checkbox'
679: ) {
680: $qty = 1;
681: } else {
682: $qty = $result['selection_qty'];
683: }
684:
685: $result['final_price'] = $selectionResource->getPriceFromIndex($result['product_id'], $qty, $store,
686: $gId);
687:
688: $selectionPrice = $result['final_price']*$qty;
689:
690: if (isset($options[$result['option_id']])) {
691: $options[$result['option_id']] = min($options[$result['option_id']], $selectionPrice);
692: } else {
693: $options[$result['option_id']] = $selectionPrice;
694: }
695: }
696: $basePrice = array_sum($options);
697: } else {
698: foreach ($results as $result) {
699: if (!$result['product_id']) {
700: continue;
701: }
702: if ($result['selection_price_type']) {
703: $selectionPrice = $basePrice*$result['selection_price_value']/100;
704: } else {
705: $selectionPrice = $result['selection_price_value'];
706: }
707:
708: if ($result['selection_can_change_qty'] && $result['type'] != 'multi'
709: && $result['type'] != 'checkbox'
710: ) {
711: $qty = 1;
712: } else {
713: $qty = $result['selection_qty'];
714: }
715:
716: $selectionPrice = $selectionPrice*$qty;
717:
718: if (isset($options[$result['option_id']])) {
719: $options[$result['option_id']] = min($options[$result['option_id']], $selectionPrice);
720: } else {
721: $options[$result['option_id']] = $selectionPrice;
722: }
723: }
724:
725: $basePrice = $basePrice + array_sum($options);
726: }
727:
728: $finalPrice = self::calculateSpecialPrice($basePrice, $specialPrice, $specialPriceFrom, $specialPriceTo,
729: $store);
730:
731: 732: 733:
734: $customOptions = Mage::getResourceSingleton('catalog/product_option_collection')->reset();
735: $customOptions->addFieldToFilter('is_require', '1')
736: ->addProductToFilter($productId)
737: ->addPriceToResult($store, 'price')
738: ->addValuesToResult();
739:
740: foreach ($customOptions as $customOption) {
741: if ($values = $customOption->getValues()) {
742: $prices = array();
743: foreach ($values as $value) {
744: $prices[] = $value->getPrice();
745: }
746: if (count($prices)) {
747: $finalPrice += min($prices);
748: }
749: } else {
750: $finalPrice += $customOption->getPrice();
751: }
752: }
753:
754: if ($rulePrice === false) {
755: $rulePrice = Mage::getResourceModel('catalogrule/rule')
756: ->getRulePrice(Mage::app()->getLocale()->storeTimeStamp($store), $wId, $gId, $productId);
757: }
758:
759: if ($rulePrice !== null && $rulePrice !== false) {
760: $finalPrice = min($finalPrice, $rulePrice);
761: }
762:
763: $finalPrice = max($finalPrice, 0);
764:
765: return $finalPrice;
766: }
767:
768: 769: 770: 771: 772: 773: 774: 775: 776: 777:
778: public static function calculateSpecialPrice($finalPrice, $specialPrice, $specialPriceFrom, $specialPriceTo,
779: $store = null)
780: {
781: if (!is_null($specialPrice) && $specialPrice != false) {
782: if (Mage::app()->getLocale()->isStoreDateInInterval($store, $specialPriceFrom, $specialPriceTo)) {
783: $specialPrice = Mage::app()->getStore()->roundPrice($finalPrice * $specialPrice / 100);
784: $finalPrice = min($finalPrice, $specialPrice);
785: }
786: }
787:
788: return $finalPrice;
789: }
790:
791: 792: 793: 794: 795:
796: public function isGroupPriceFixed()
797: {
798: return false;
799: }
800: }
801: