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:
35: class Mage_Bundle_Model_Resource_Indexer_Price extends Mage_Catalog_Model_Resource_Product_Indexer_Price_Default
36: {
37: 38: 39: 40: 41:
42: public function reindexAll()
43: {
44: $this->useIdxTable(true);
45:
46: $this->beginTransaction();
47: try {
48: $this->_prepareBundlePrice();
49: $this->commit();
50: } catch (Exception $e) {
51: $this->rollBack();
52: throw $e;
53: }
54:
55: return $this;
56: }
57:
58: 59: 60: 61: 62: 63:
64: public function reindexEntity($entityIds)
65: {
66: $this->_prepareBundlePrice($entityIds);
67:
68: return $this;
69: }
70:
71: 72: 73: 74: 75:
76: protected function _getBundlePriceTable()
77: {
78: if ($this->useIdxTable()) {
79: return $this->getTable('bundle/price_indexer_idx');
80: }
81: return $this->getTable('bundle/price_indexer_tmp');
82: }
83:
84: 85: 86: 87: 88:
89: protected function _getBundleSelectionTable()
90: {
91: if ($this->useIdxTable()) {
92: return $this->getTable('bundle/selection_indexer_idx');
93: }
94: return $this->getTable('bundle/selection_indexer_tmp');
95: }
96:
97: 98: 99: 100: 101:
102: protected function _getBundleOptionTable()
103: {
104: if ($this->useIdxTable()) {
105: return $this->getTable('bundle/option_indexer_idx');
106: }
107: return $this->getTable('bundle/option_indexer_tmp');
108: }
109:
110: 111: 112: 113: 114:
115: protected function _prepareBundlePriceTable()
116: {
117: $this->_getWriteAdapter()->delete($this->_getBundlePriceTable());
118: return $this;
119: }
120:
121: 122: 123: 124: 125:
126: protected function _prepareBundleSelectionTable()
127: {
128: $this->_getWriteAdapter()->delete($this->_getBundleSelectionTable());
129: return $this;
130: }
131:
132: 133: 134: 135: 136:
137: protected function _prepareBundleOptionTable()
138: {
139: $this->_getWriteAdapter()->delete($this->_getBundleOptionTable());
140: return $this;
141: }
142:
143: 144: 145: 146: 147: 148: 149:
150: protected function _prepareBundlePriceByType($priceType, $entityIds = null)
151: {
152: $write = $this->_getWriteAdapter();
153: $table = $this->_getBundlePriceTable();
154:
155: $select = $write->select()
156: ->from(array('e' => $this->getTable('catalog/product')), array('entity_id'))
157: ->join(
158: array('cg' => $this->getTable('customer/customer_group')),
159: '',
160: array('customer_group_id')
161: );
162: $this->_addWebsiteJoinToSelect($select, true);
163: $this->_addProductWebsiteJoinToSelect($select, 'cw.website_id', 'e.entity_id');
164: $select->columns('website_id', 'cw')
165: ->join(
166: array('cwd' => $this->_getWebsiteDateTable()),
167: 'cw.website_id = cwd.website_id',
168: array()
169: )
170: ->joinLeft(
171: array('tp' => $this->_getTierPriceIndexTable()),
172: 'tp.entity_id = e.entity_id AND tp.website_id = cw.website_id'
173: . ' AND tp.customer_group_id = cg.customer_group_id',
174: array()
175: )
176: ->joinLeft(
177: array('gp' => $this->_getGroupPriceIndexTable()),
178: 'gp.entity_id = e.entity_id AND gp.website_id = cw.website_id'
179: . ' AND gp.customer_group_id = cg.customer_group_id',
180: array()
181: )
182: ->where('e.type_id=?', $this->getTypeId());
183:
184:
185: $statusCond = $write->quoteInto('=?', Mage_Catalog_Model_Product_Status::STATUS_ENABLED);
186: $this->_addAttributeToSelect($select, 'status', 'e.entity_id', 'cs.store_id', $statusCond, true);
187: if (Mage::helper('core')->isModuleEnabled('Mage_Tax')) {
188: $taxClassId = $this->_addAttributeToSelect($select, 'tax_class_id', 'e.entity_id', 'cs.store_id');
189: } else {
190: $taxClassId = new Zend_Db_Expr('0');
191: }
192:
193: if ($priceType == Mage_Bundle_Model_Product_Price::PRICE_TYPE_DYNAMIC) {
194: $select->columns(array('tax_class_id' => new Zend_Db_Expr('0')));
195: } else {
196: $select->columns(
197: array('tax_class_id' => $write->getCheckSql($taxClassId . ' IS NOT NULL', $taxClassId, 0))
198: );
199: }
200:
201: $priceTypeCond = $write->quoteInto('=?', $priceType);
202: $this->_addAttributeToSelect($select, 'price_type', 'e.entity_id', 'cs.store_id', $priceTypeCond);
203:
204: $price = $this->_addAttributeToSelect($select, 'price', 'e.entity_id', 'cs.store_id');
205: $specialPrice = $this->_addAttributeToSelect($select, 'special_price', 'e.entity_id', 'cs.store_id');
206: $specialFrom = $this->_addAttributeToSelect($select, 'special_from_date', 'e.entity_id', 'cs.store_id');
207: $specialTo = $this->_addAttributeToSelect($select, 'special_to_date', 'e.entity_id', 'cs.store_id');
208: $curentDate = new Zend_Db_Expr('cwd.website_date');
209:
210: $specialExpr = $write->getCheckSql(
211: $write->getCheckSql(
212: $specialFrom . ' IS NULL',
213: '1',
214: $write->getCheckSql(
215: $specialFrom . ' <= ' . $curentDate,
216: '1',
217: '0'
218: )
219: ) . " > 0 AND ".
220: $write->getCheckSql(
221: $specialTo . ' IS NULL',
222: '1',
223: $write->getCheckSql(
224: $specialTo . ' >= ' . $curentDate,
225: '1',
226: '0'
227: )
228: )
229: . " > 0 AND {$specialPrice} > 0 AND {$specialPrice} < 100 ",
230: $specialPrice,
231: '0'
232: );
233:
234: $groupPriceExpr = $write->getCheckSql(
235: 'gp.price IS NOT NULL AND gp.price > 0 AND gp.price < 100',
236: 'gp.price',
237: '0'
238: );
239:
240: $tierExpr = new Zend_Db_Expr("tp.min_price");
241:
242: if ($priceType == Mage_Bundle_Model_Product_Price::PRICE_TYPE_FIXED) {
243: $finalPrice = $write->getCheckSql(
244: $specialExpr . ' > 0',
245: 'ROUND(' . $price . ' * (' . $specialExpr . ' / 100), 4)',
246: $price
247: );
248: $tierPrice = $write->getCheckSql(
249: $tierExpr . ' IS NOT NULL',
250: 'ROUND(' . $price . ' - ' . '(' . $price . ' * (' . $tierExpr . ' / 100)), 4)',
251: 'NULL'
252: );
253: $groupPrice = $write->getCheckSql(
254: $groupPriceExpr . ' > 0',
255: 'ROUND(' . $price . ' - ' . '(' . $price . ' * (' . $groupPriceExpr . ' / 100)), 4)',
256: 'NULL'
257: );
258: $finalPrice = $write->getCheckSql(
259: "{$groupPrice} IS NOT NULL AND {$groupPrice} < {$finalPrice}",
260: $groupPrice,
261: $finalPrice
262: );
263: } else {
264: $finalPrice = new Zend_Db_Expr("0");
265: $tierPrice = $write->getCheckSql($tierExpr . ' IS NOT NULL', '0', 'NULL');
266: $groupPrice = $write->getCheckSql($groupPriceExpr . ' > 0', $groupPriceExpr, 'NULL');
267: }
268:
269: $select->columns(array(
270: 'price_type' => new Zend_Db_Expr($priceType),
271: 'special_price' => $specialExpr,
272: 'tier_percent' => $tierExpr,
273: 'orig_price' => $write->getCheckSql($price . ' IS NULL', '0', $price),
274: 'price' => $finalPrice,
275: 'min_price' => $finalPrice,
276: 'max_price' => $finalPrice,
277: 'tier_price' => $tierPrice,
278: 'base_tier' => $tierPrice,
279: 'group_price' => $groupPrice,
280: 'base_group_price' => $groupPrice,
281: 'group_price_percent' => new Zend_Db_Expr('gp.price'),
282: ));
283:
284: if (!is_null($entityIds)) {
285: $select->where('e.entity_id IN(?)', $entityIds);
286: }
287:
288: 289: 290:
291: Mage::dispatchEvent('catalog_product_prepare_index_select', array(
292: 'select' => $select,
293: 'entity_field' => new Zend_Db_Expr('e.entity_id'),
294: 'website_field' => new Zend_Db_Expr('cw.website_id'),
295: 'store_field' => new Zend_Db_Expr('cs.store_id')
296: ));
297:
298: $query = $select->insertFromSelect($table);
299: $write->query($query);
300:
301: return $this;
302: }
303:
304: 305: 306: 307: 308:
309: protected function _calculateBundleOptionPrice()
310: {
311: $write = $this->_getWriteAdapter();
312:
313: $this->_prepareBundleSelectionTable();
314: $this->_calculateBundleSelectionPrice(Mage_Bundle_Model_Product_Price::PRICE_TYPE_FIXED);
315: $this->_calculateBundleSelectionPrice(Mage_Bundle_Model_Product_Price::PRICE_TYPE_DYNAMIC);
316:
317: $this->_prepareBundleOptionTable();
318:
319: $select = $write->select()
320: ->from(
321: array('i' => $this->_getBundleSelectionTable()),
322: array('entity_id', 'customer_group_id', 'website_id', 'option_id')
323: )
324: ->group(array('entity_id', 'customer_group_id', 'website_id', 'option_id', 'is_required', 'group_type'))
325: ->columns(array(
326: 'min_price' => $write->getCheckSql('i.is_required = 1', 'MIN(i.price)', '0'),
327: 'alt_price' => $write->getCheckSql('i.is_required = 0', 'MIN(i.price)', '0'),
328: 'max_price' => $write->getCheckSql('i.group_type = 1', 'SUM(i.price)', 'MAX(i.price)'),
329: 'tier_price' => $write->getCheckSql('i.is_required = 1', 'MIN(i.tier_price)', '0'),
330: 'alt_tier_price' => $write->getCheckSql('i.is_required = 0', 'MIN(i.tier_price)', '0'),
331: 'group_price' => $write->getCheckSql('i.is_required = 1', 'MIN(i.group_price)', '0'),
332: 'alt_group_price' => $write->getCheckSql('i.is_required = 0', 'MIN(i.group_price)', '0'),
333: ));
334:
335: $query = $select->insertFromSelect($this->_getBundleOptionTable());
336: $write->query($query);
337:
338: $this->_prepareDefaultFinalPriceTable();
339:
340: $minPrice = new Zend_Db_Expr($write->getCheckSql(
341: 'SUM(io.min_price) = 0',
342: 'MIN(io.alt_price)',
343: 'SUM(io.min_price)'
344: ) . ' + i.price');
345: $maxPrice = new Zend_Db_Expr("SUM(io.max_price) + i.price");
346: $tierPrice = $write->getCheckSql(
347: 'MIN(i.tier_percent) IS NOT NULL',
348: $write->getCheckSql(
349: 'SUM(io.tier_price) = 0',
350: 'SUM(io.alt_tier_price)',
351: 'SUM(io.tier_price)'
352: ) . ' + MIN(i.tier_price)',
353: 'NULL'
354: );
355: $groupPrice = $write->getCheckSql(
356: 'MIN(i.group_price_percent) IS NOT NULL',
357: $write->getCheckSql(
358: 'SUM(io.group_price) = 0',
359: 'SUM(io.alt_group_price)',
360: 'SUM(io.group_price)'
361: ) . ' + MIN(i.group_price)',
362: 'NULL'
363: );
364:
365: $select = $write->select()
366: ->from(
367: array('io' => $this->_getBundleOptionTable()),
368: array('entity_id', 'customer_group_id', 'website_id')
369: )
370: ->join(
371: array('i' => $this->_getBundlePriceTable()),
372: 'i.entity_id = io.entity_id AND i.customer_group_id = io.customer_group_id'
373: . ' AND i.website_id = io.website_id',
374: array()
375: )
376: ->group(array('io.entity_id', 'io.customer_group_id', 'io.website_id',
377: 'i.tax_class_id', 'i.orig_price', 'i.price'))
378: ->columns(array('i.tax_class_id',
379: 'orig_price' => 'i.orig_price',
380: 'price' => 'i.price',
381: 'min_price' => $minPrice,
382: 'max_price' => $maxPrice,
383: 'tier_price' => $tierPrice,
384: 'base_tier' => 'MIN(i.base_tier)',
385: 'group_price' => $groupPrice,
386: 'base_group_price' => 'MIN(i.base_group_price)',
387: ));
388:
389: $query = $select->insertFromSelect($this->_getDefaultFinalPriceTable());
390: $write->query($query);
391:
392: return $this;
393: }
394:
395: 396: 397: 398: 399: 400:
401: protected function _calculateBundleSelectionPrice($priceType)
402: {
403: $write = $this->_getWriteAdapter();
404:
405: if ($priceType == Mage_Bundle_Model_Product_Price::PRICE_TYPE_FIXED) {
406:
407: $selectionPriceValue = $write->getCheckSql(
408: 'bsp.selection_price_value IS NULL',
409: 'bs.selection_price_value',
410: 'bsp.selection_price_value'
411: );
412: $selectionPriceType = $write->getCheckSql(
413: 'bsp.selection_price_type IS NULL',
414: 'bs.selection_price_type',
415: 'bsp.selection_price_type'
416: );
417: $priceExpr = new Zend_Db_Expr(
418: $write->getCheckSql(
419: $selectionPriceType . ' = 1',
420: 'ROUND(i.price * (' . $selectionPriceValue . ' / 100),4)',
421: $write->getCheckSql(
422: 'i.special_price > 0 AND i.special_price < 100',
423: 'ROUND(' . $selectionPriceValue . ' * (i.special_price / 100),4)',
424: $selectionPriceValue
425: )
426: ) . '* bs.selection_qty'
427: );
428:
429: $tierExpr = $write->getCheckSql(
430: 'i.base_tier IS NOT NULL',
431: $write->getCheckSql(
432: $selectionPriceType .' = 1',
433: 'ROUND(i.base_tier - (i.base_tier * (' . $selectionPriceValue . ' / 100)),4)',
434: $write->getCheckSql(
435: 'i.tier_percent > 0',
436: 'ROUND(' . $selectionPriceValue
437: . ' - (' . $selectionPriceValue . ' * (i.tier_percent / 100)),4)',
438: $selectionPriceValue
439: )
440: ) . ' * bs.selection_qty',
441: 'NULL'
442: );
443:
444: $groupExpr = $write->getCheckSql(
445: 'i.base_group_price IS NOT NULL',
446: $write->getCheckSql(
447: $selectionPriceType .' = 1',
448: $priceExpr,
449: $write->getCheckSql(
450: 'i.group_price_percent > 0',
451: 'ROUND(' . $selectionPriceValue
452: . ' - (' . $selectionPriceValue . ' * (i.group_price_percent / 100)),4)',
453: $selectionPriceValue
454: )
455: ) . ' * bs.selection_qty',
456: 'NULL'
457: );
458: $priceExpr = new Zend_Db_Expr(
459: $write->getCheckSql("{$groupExpr} < {$priceExpr}", $groupExpr, $priceExpr)
460: );
461: } else {
462: $priceExpr = new Zend_Db_Expr(
463: $write->getCheckSql(
464: 'i.special_price > 0 AND i.special_price < 100',
465: 'ROUND(idx.min_price * (i.special_price / 100), 4)',
466: 'idx.min_price'
467: ) . ' * bs.selection_qty'
468: );
469: $tierExpr = $write->getCheckSql(
470: 'i.base_tier IS NOT NULL',
471: 'ROUND(idx.min_price * (i.base_tier / 100), 4)* bs.selection_qty',
472: 'NULL'
473: );
474: $groupExpr = $write->getCheckSql(
475: 'i.base_group_price IS NOT NULL',
476: 'ROUND(idx.min_price * (i.base_group_price / 100), 4)* bs.selection_qty',
477: 'NULL'
478: );
479: $groupPriceExpr = new Zend_Db_Expr(
480: $write->getCheckSql(
481: 'i.base_group_price IS NOT NULL AND i.base_group_price > 0 AND i.base_group_price < 100',
482: 'ROUND(idx.min_price - idx.min_price * (i.base_group_price / 100), 4)',
483: 'idx.min_price'
484: ) . ' * bs.selection_qty'
485: );
486: $priceExpr = new Zend_Db_Expr(
487: $write->getCheckSql("{$groupPriceExpr} < {$priceExpr}", $groupPriceExpr, $priceExpr)
488: );
489: }
490:
491: $select = $write->select()
492: ->from(
493: array('i' => $this->_getBundlePriceTable()),
494: array('entity_id', 'customer_group_id', 'website_id')
495: )
496: ->join(
497: array('bo' => $this->getTable('bundle/option')),
498: 'bo.parent_id = i.entity_id',
499: array('option_id')
500: )
501: ->join(
502: array('bs' => $this->getTable('bundle/selection')),
503: 'bs.option_id = bo.option_id',
504: array('selection_id')
505: )
506: ->joinLeft(
507: array('bsp' => $this->getTable('bundle/selection_price')),
508: 'bs.selection_id = bsp.selection_id AND bsp.website_id = i.website_id',
509: array('')
510: )
511: ->join(
512: array('idx' => $this->getIdxTable()),
513: 'bs.product_id = idx.entity_id AND i.customer_group_id = idx.customer_group_id'
514: . ' AND i.website_id = idx.website_id',
515: array()
516: )
517: ->join(
518: array('e' => $this->getTable('catalog/product')),
519: 'bs.product_id = e.entity_id AND e.required_options=0',
520: array()
521: )
522: ->where('i.price_type=?', $priceType)
523: ->columns(array(
524: 'group_type' => $write->getCheckSql(
525: "bo.type = 'select' OR bo.type = 'radio'",
526: '0',
527: '1'
528: ),
529: 'is_required' => 'bo.required',
530: 'price' => $priceExpr,
531: 'tier_price' => $tierExpr,
532: 'group_price' => $groupExpr,
533: ));
534:
535: $query = $select->insertFromSelect($this->_getBundleSelectionTable());
536: $write->query($query);
537:
538: return $this;
539: }
540:
541: 542: 543: 544: 545: 546:
547: protected function _prepareBundlePrice($entityIds = null)
548: {
549: $this->_prepareTierPriceIndex($entityIds);
550: $this->_prepareGroupPriceIndex($entityIds);
551: $this->_prepareBundlePriceTable();
552: $this->_prepareBundlePriceByType(Mage_Bundle_Model_Product_Price::PRICE_TYPE_FIXED, $entityIds);
553: $this->_prepareBundlePriceByType(Mage_Bundle_Model_Product_Price::PRICE_TYPE_DYNAMIC, $entityIds);
554:
555: 556: 557:
558: $select = $this->_getWriteAdapter()->select()
559: ->join(array('wd' => $this->_getWebsiteDateTable()),
560: 'i.website_id = wd.website_id',
561: array()
562: );
563: Mage::dispatchEvent('prepare_catalog_product_price_index_table', array(
564: 'index_table' => array('i' => $this->_getBundlePriceTable()),
565: 'select' => $select,
566: 'entity_id' => 'i.entity_id',
567: 'customer_group_id' => 'i.customer_group_id',
568: 'website_id' => 'i.website_id',
569: 'website_date' => 'wd.website_date',
570: 'update_fields' => array('price', 'min_price', 'max_price')
571: ));
572:
573: $this->_calculateBundleOptionPrice();
574: $this->_applyCustomOption();
575:
576: $this->_movePriceDataToIndexTable();
577:
578: return $this;
579: }
580:
581: 582: 583: 584: 585: 586: 587: 588:
589: protected function _prepareTierPriceIndex($entityIds = null)
590: {
591: $adapter = $this->_getWriteAdapter();
592:
593:
594: $select = $adapter->select()
595: ->from(array('i' => $this->_getTierPriceIndexTable()), null)
596: ->join(
597: array('e' => $this->getTable('catalog/product')),
598: 'i.entity_id=e.entity_id',
599: array()
600: )
601: ->where('e.type_id=?', $this->getTypeId());
602: $query = $select->deleteFromSelect('i');
603: $adapter->query($query);
604:
605: $select = $adapter->select()
606: ->from(
607: array('tp' => $this->getValueTable('catalog/product', 'tier_price')),
608: array('entity_id')
609: )
610: ->join(
611: array('e' => $this->getTable('catalog/product')),
612: 'tp.entity_id=e.entity_id',
613: array()
614: )
615: ->join(
616: array('cg' => $this->getTable('customer/customer_group')),
617: 'tp.all_groups = 1 OR (tp.all_groups = 0 AND tp.customer_group_id = cg.customer_group_id)',
618: array('customer_group_id')
619: )
620: ->join(
621: array('cw' => $this->getTable('core/website')),
622: 'tp.website_id = 0 OR tp.website_id = cw.website_id',
623: array('website_id')
624: )
625: ->where('cw.website_id != 0')
626: ->where('e.type_id=?', $this->getTypeId())
627: ->columns(new Zend_Db_Expr('MIN(tp.value)'))
628: ->group(array('tp.entity_id', 'cg.customer_group_id', 'cw.website_id'));
629:
630: if (!empty($entityIds)) {
631: $select->where('tp.entity_id IN(?)', $entityIds);
632: }
633:
634: $query = $select->insertFromSelect($this->_getTierPriceIndexTable());
635: $adapter->query($query);
636:
637: return $this;
638: }
639:
640: 641: 642: 643: 644: 645: 646: 647:
648: protected function _prepareGroupPriceIndex($entityIds = null)
649: {
650: $adapter = $this->_getWriteAdapter();
651:
652:
653: $select = $adapter->select()
654: ->from(array('i' => $this->_getGroupPriceIndexTable()), null)
655: ->join(
656: array('e' => $this->getTable('catalog/product')),
657: 'i.entity_id=e.entity_id',
658: array()
659: )
660: ->where('e.type_id=?', $this->getTypeId());
661: $query = $select->deleteFromSelect('i');
662: $adapter->query($query);
663:
664: $select = $adapter->select()
665: ->from(
666: array('gp' => $this->getValueTable('catalog/product', 'group_price')),
667: array('entity_id')
668: )
669: ->join(
670: array('e' => $this->getTable('catalog/product')),
671: 'gp.entity_id=e.entity_id',
672: array()
673: )
674: ->join(
675: array('cg' => $this->getTable('customer/customer_group')),
676: 'gp.all_groups = 1 OR (gp.all_groups = 0 AND gp.customer_group_id = cg.customer_group_id)',
677: array('customer_group_id')
678: )
679: ->join(
680: array('cw' => $this->getTable('core/website')),
681: 'gp.website_id = 0 OR gp.website_id = cw.website_id',
682: array('website_id')
683: )
684: ->where('cw.website_id != 0')
685: ->where('e.type_id=?', $this->getTypeId())
686: ->columns(new Zend_Db_Expr('MIN(gp.value)'))
687: ->group(array('gp.entity_id', 'cg.customer_group_id', 'cw.website_id'));
688:
689: if (!empty($entityIds)) {
690: $select->where('gp.entity_id IN(?)', $entityIds);
691: }
692:
693: $query = $select->insertFromSelect($this->_getGroupPriceIndexTable());
694: $adapter->query($query);
695:
696: return $this;
697: }
698: }
699: