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:
36: class Mage_Catalog_Model_Resource_Product_Indexer_Price_Default
37: extends Mage_Catalog_Model_Resource_Product_Indexer_Abstract
38: implements Mage_Catalog_Model_Resource_Product_Indexer_Price_Interface
39: {
40: 41: 42: 43: 44:
45: protected $_typeId;
46:
47: 48: 49: 50: 51:
52: protected $_isComposite = false;
53:
54: 55: 56: 57:
58: protected function _construct()
59: {
60: $this->_init('catalog/product_index_price', 'entity_id');
61: }
62:
63: 64: 65: 66: 67: 68:
69: public function setTypeId($typeCode)
70: {
71: $this->_typeId = $typeCode;
72: return $this;
73: }
74:
75: 76: 77: 78: 79:
80: public function getTypeId()
81: {
82: if (is_null($this->_typeId)) {
83: Mage::throwException(Mage::helper('catalog')->__('A product type is not defined for the indexer.'));
84: }
85: return $this->_typeId;
86: }
87:
88: 89: 90: 91: 92: 93:
94: public function setIsComposite($flag)
95: {
96: $this->_isComposite = (bool)$flag;
97: return $this;
98: }
99:
100: 101: 102: 103: 104:
105: public function getIsComposite()
106: {
107: return $this->_isComposite;
108: }
109:
110: 111: 112: 113: 114:
115: public function reindexAll()
116: {
117: $this->useIdxTable(true);
118: $this->beginTransaction();
119: try {
120: $this->_prepareFinalPriceData();
121: $this->_applyCustomOption();
122: $this->_movePriceDataToIndexTable();
123: $this->commit();
124: } catch (Exception $e) {
125: $this->rollBack();
126: throw $e;
127: }
128: return $this;
129: }
130:
131: 132: 133: 134: 135: 136:
137: public function reindexEntity($entityIds)
138: {
139: $this->useDisableKeys(false);
140: $this->_prepareFinalPriceData($entityIds);
141: $this->_applyCustomOption();
142: $this->_movePriceDataToIndexTable();
143: $this->useDisableKeys(true);
144:
145: return $this;
146: }
147:
148: 149: 150: 151: 152: 153: 154:
155: protected function _getDefaultFinalPriceTable()
156: {
157: if ($this->useIdxTable()) {
158: return $this->getTable('catalog/product_price_indexer_final_idx');
159: }
160: return $this->getTable('catalog/product_price_indexer_final_tmp');
161: }
162:
163: 164: 165: 166: 167:
168: protected function _prepareDefaultFinalPriceTable()
169: {
170: $this->_getWriteAdapter()->delete($this->_getDefaultFinalPriceTable());
171: return $this;
172: }
173:
174: 175: 176: 177: 178:
179: protected function _getWebsiteDateTable()
180: {
181: return $this->getTable('catalog/product_index_website');
182: }
183:
184: 185: 186: 187: 188: 189:
190: protected function _prepareFinalPriceData($entityIds = null)
191: {
192: $this->_prepareDefaultFinalPriceTable();
193:
194: $write = $this->_getWriteAdapter();
195: $select = $write->select()
196: ->from(array('e' => $this->getTable('catalog/product')), array('entity_id'))
197: ->join(
198: array('cg' => $this->getTable('customer/customer_group')),
199: '',
200: array('customer_group_id'))
201: ->join(
202: array('cw' => $this->getTable('core/website')),
203: '',
204: array('website_id'))
205: ->join(
206: array('cwd' => $this->_getWebsiteDateTable()),
207: 'cw.website_id = cwd.website_id',
208: array())
209: ->join(
210: array('csg' => $this->getTable('core/store_group')),
211: 'csg.website_id = cw.website_id AND cw.default_group_id = csg.group_id',
212: array())
213: ->join(
214: array('cs' => $this->getTable('core/store')),
215: 'csg.default_store_id = cs.store_id AND cs.store_id != 0',
216: array())
217: ->join(
218: array('pw' => $this->getTable('catalog/product_website')),
219: 'pw.product_id = e.entity_id AND pw.website_id = cw.website_id',
220: array())
221: ->joinLeft(
222: array('tp' => $this->_getTierPriceIndexTable()),
223: 'tp.entity_id = e.entity_id AND tp.website_id = cw.website_id'
224: . ' AND tp.customer_group_id = cg.customer_group_id',
225: array())
226: ->joinLeft(
227: array('gp' => $this->_getGroupPriceIndexTable()),
228: 'gp.entity_id = e.entity_id AND gp.website_id = cw.website_id'
229: . ' AND gp.customer_group_id = cg.customer_group_id',
230: array())
231: ->where('e.type_id = ?', $this->getTypeId());
232:
233:
234: $statusCond = $write->quoteInto('=?', Mage_Catalog_Model_Product_Status::STATUS_ENABLED);
235: $this->_addAttributeToSelect($select, 'status', 'e.entity_id', 'cs.store_id', $statusCond, true);
236: if (Mage::helper('core')->isModuleEnabled('Mage_Tax')) {
237: $taxClassId = $this->_addAttributeToSelect($select, 'tax_class_id', 'e.entity_id', 'cs.store_id');
238: } else {
239: $taxClassId = new Zend_Db_Expr('0');
240: }
241: $select->columns(array('tax_class_id' => $taxClassId));
242:
243: $price = $this->_addAttributeToSelect($select, 'price', 'e.entity_id', 'cs.store_id');
244: $specialPrice = $this->_addAttributeToSelect($select, 'special_price', 'e.entity_id', 'cs.store_id');
245: $specialFrom = $this->_addAttributeToSelect($select, 'special_from_date', 'e.entity_id', 'cs.store_id');
246: $specialTo = $this->_addAttributeToSelect($select, 'special_to_date', 'e.entity_id', 'cs.store_id');
247: $currentDate = $write->getDatePartSql('cwd.website_date');
248: $groupPrice = $write->getCheckSql('gp.price IS NULL', "{$price}", 'gp.price');
249:
250: $specialFromDate = $write->getDatePartSql($specialFrom);
251: $specialToDate = $write->getDatePartSql($specialTo);
252:
253: $specialFromUse = $write->getCheckSql("{$specialFromDate} <= {$currentDate}", '1', '0');
254: $specialToUse = $write->getCheckSql("{$specialToDate} >= {$currentDate}", '1', '0');
255: $specialFromHas = $write->getCheckSql("{$specialFrom} IS NULL", '1', "{$specialFromUse}");
256: $specialToHas = $write->getCheckSql("{$specialTo} IS NULL", '1', "{$specialToUse}");
257: $finalPrice = $write->getCheckSql("{$specialFromHas} > 0 AND {$specialToHas} > 0"
258: . " AND {$specialPrice} < {$price}", $specialPrice, $price);
259: $finalPrice = $write->getCheckSql("{$groupPrice} < {$finalPrice}", $groupPrice, $finalPrice);
260:
261: $select->columns(array(
262: 'orig_price' => $price,
263: 'price' => $finalPrice,
264: 'min_price' => $finalPrice,
265: 'max_price' => $finalPrice,
266: 'tier_price' => new Zend_Db_Expr('tp.min_price'),
267: 'base_tier' => new Zend_Db_Expr('tp.min_price'),
268: 'group_price' => new Zend_Db_Expr('gp.price'),
269: 'base_group_price' => new Zend_Db_Expr('gp.price'),
270: ));
271:
272: if (!is_null($entityIds)) {
273: $select->where('e.entity_id IN(?)', $entityIds);
274: }
275:
276: 277: 278:
279: Mage::dispatchEvent('prepare_catalog_product_index_select', array(
280: 'select' => $select,
281: 'entity_field' => new Zend_Db_Expr('e.entity_id'),
282: 'website_field' => new Zend_Db_Expr('cw.website_id'),
283: 'store_field' => new Zend_Db_Expr('cs.store_id')
284: ));
285:
286: $query = $select->insertFromSelect($this->_getDefaultFinalPriceTable(), array(), false);
287: $write->query($query);
288:
289: 290: 291:
292: $select = $write->select()
293: ->join(array('wd' => $this->_getWebsiteDateTable()),
294: 'i.website_id = wd.website_id',
295: array());
296: Mage::dispatchEvent('prepare_catalog_product_price_index_table', array(
297: 'index_table' => array('i' => $this->_getDefaultFinalPriceTable()),
298: 'select' => $select,
299: 'entity_id' => 'i.entity_id',
300: 'customer_group_id' => 'i.customer_group_id',
301: 'website_id' => 'i.website_id',
302: 'website_date' => 'wd.website_date',
303: 'update_fields' => array('price', 'min_price', 'max_price')
304: ));
305:
306: return $this;
307: }
308:
309: 310: 311: 312: 313:
314: protected function _getCustomOptionAggregateTable()
315: {
316: if ($this->useIdxTable()) {
317: return $this->getTable('catalog/product_price_indexer_option_aggregate_idx');
318: }
319: return $this->getTable('catalog/product_price_indexer_option_aggregate_tmp');
320: }
321:
322: 323: 324: 325: 326:
327: protected function _getCustomOptionPriceTable()
328: {
329: if ($this->useIdxTable()) {
330: return $this->getTable('catalog/product_price_indexer_option_idx');
331: }
332: return $this->getTable('catalog/product_price_indexer_option_tmp');
333: }
334:
335: 336: 337: 338: 339:
340: protected function _prepareCustomOptionAggregateTable()
341: {
342: $this->_getWriteAdapter()->delete($this->_getCustomOptionAggregateTable());
343: return $this;
344: }
345:
346: 347: 348: 349: 350:
351: protected function _prepareCustomOptionPriceTable()
352: {
353: $this->_getWriteAdapter()->delete($this->_getCustomOptionPriceTable());
354: return $this;
355: }
356:
357: 358: 359: 360: 361:
362: protected function _applyCustomOption()
363: {
364: $write = $this->_getWriteAdapter();
365: $coaTable = $this->_getCustomOptionAggregateTable();
366: $copTable = $this->_getCustomOptionPriceTable();
367:
368: $this->_prepareCustomOptionAggregateTable();
369: $this->_prepareCustomOptionPriceTable();
370:
371: $select = $write->select()
372: ->from(
373: array('i' => $this->_getDefaultFinalPriceTable()),
374: array('entity_id', 'customer_group_id', 'website_id'))
375: ->join(
376: array('cw' => $this->getTable('core/website')),
377: 'cw.website_id = i.website_id',
378: array())
379: ->join(
380: array('csg' => $this->getTable('core/store_group')),
381: 'csg.group_id = cw.default_group_id',
382: array())
383: ->join(
384: array('cs' => $this->getTable('core/store')),
385: 'cs.store_id = csg.default_store_id',
386: array())
387: ->join(
388: array('o' => $this->getTable('catalog/product_option')),
389: 'o.product_id = i.entity_id',
390: array('option_id'))
391: ->join(
392: array('ot' => $this->getTable('catalog/product_option_type_value')),
393: 'ot.option_id = o.option_id',
394: array())
395: ->join(
396: array('otpd' => $this->getTable('catalog/product_option_type_price')),
397: 'otpd.option_type_id = ot.option_type_id AND otpd.store_id = 0',
398: array())
399: ->joinLeft(
400: array('otps' => $this->getTable('catalog/product_option_type_price')),
401: 'otps.option_type_id = otpd.option_type_id AND otpd.store_id = cs.store_id',
402: array())
403: ->group(array('i.entity_id', 'i.customer_group_id', 'i.website_id', 'o.option_id'));
404:
405: $optPriceType = $write->getCheckSql('otps.option_type_price_id > 0', 'otps.price_type', 'otpd.price_type');
406: $optPriceValue = $write->getCheckSql('otps.option_type_price_id > 0', 'otps.price', 'otpd.price');
407: $minPriceRound = new Zend_Db_Expr("ROUND(i.price * ({$optPriceValue} / 100), 4)");
408: $minPriceExpr = $write->getCheckSql("{$optPriceType} = 'fixed'", $optPriceValue, $minPriceRound);
409: $minPriceMin = new Zend_Db_Expr("MIN({$minPriceExpr})");
410: $minPrice = $write->getCheckSql("MIN(o.is_require) = 1", $minPriceMin, '0');
411:
412: $tierPriceRound = new Zend_Db_Expr("ROUND(i.base_tier * ({$optPriceValue} / 100), 4)");
413: $tierPriceExpr = $write->getCheckSql("{$optPriceType} = 'fixed'", $optPriceValue, $tierPriceRound);
414: $tierPriceMin = new Zend_Db_Expr("MIN($tierPriceExpr)");
415: $tierPriceValue = $write->getCheckSql("MIN(o.is_require) > 0", $tierPriceMin, 0);
416: $tierPrice = $write->getCheckSql("MIN(i.base_tier) IS NOT NULL", $tierPriceValue, "NULL");
417:
418: $groupPriceRound = new Zend_Db_Expr("ROUND(i.base_group_price * ({$optPriceValue} / 100), 4)");
419: $groupPriceExpr = $write->getCheckSql("{$optPriceType} = 'fixed'", $optPriceValue, $groupPriceRound);
420: $groupPriceMin = new Zend_Db_Expr("MIN($groupPriceExpr)");
421: $groupPriceValue = $write->getCheckSql("MIN(o.is_require) > 0", $groupPriceMin, 0);
422: $groupPrice = $write->getCheckSql("MIN(i.base_group_price) IS NOT NULL", $groupPriceValue, "NULL");
423:
424: $maxPriceRound = new Zend_Db_Expr("ROUND(i.price * ({$optPriceValue} / 100), 4)");
425: $maxPriceExpr = $write->getCheckSql("{$optPriceType} = 'fixed'", $optPriceValue, $maxPriceRound);
426: $maxPrice = $write->getCheckSql("(MIN(o.type)='radio' OR MIN(o.type)='drop_down')",
427: "MAX($maxPriceExpr)", "SUM($maxPriceExpr)");
428:
429: $select->columns(array(
430: 'min_price' => $minPrice,
431: 'max_price' => $maxPrice,
432: 'tier_price' => $tierPrice,
433: 'group_price' => $groupPrice,
434: ));
435:
436: $query = $select->insertFromSelect($coaTable);
437: $write->query($query);
438:
439: $select = $write->select()
440: ->from(
441: array('i' => $this->_getDefaultFinalPriceTable()),
442: array('entity_id', 'customer_group_id', 'website_id'))
443: ->join(
444: array('cw' => $this->getTable('core/website')),
445: 'cw.website_id = i.website_id',
446: array())
447: ->join(
448: array('csg' => $this->getTable('core/store_group')),
449: 'csg.group_id = cw.default_group_id',
450: array())
451: ->join(
452: array('cs' => $this->getTable('core/store')),
453: 'cs.store_id = csg.default_store_id',
454: array())
455: ->join(
456: array('o' => $this->getTable('catalog/product_option')),
457: 'o.product_id = i.entity_id',
458: array('option_id'))
459: ->join(
460: array('opd' => $this->getTable('catalog/product_option_price')),
461: 'opd.option_id = o.option_id AND opd.store_id = 0',
462: array())
463: ->joinLeft(
464: array('ops' => $this->getTable('catalog/product_option_price')),
465: 'ops.option_id = opd.option_id AND ops.store_id = cs.store_id',
466: array());
467:
468: $optPriceType = $write->getCheckSql('ops.option_price_id > 0', 'ops.price_type', 'opd.price_type');
469: $optPriceValue = $write->getCheckSql('ops.option_price_id > 0', 'ops.price', 'opd.price');
470:
471: $minPriceRound = new Zend_Db_Expr("ROUND(i.price * ({$optPriceValue} / 100), 4)");
472: $priceExpr = $write->getCheckSql("{$optPriceType} = 'fixed'", $optPriceValue, $minPriceRound);
473: $minPrice = $write->getCheckSql("{$priceExpr} > 0 AND o.is_require > 1", $priceExpr, 0);
474:
475: $maxPrice = $priceExpr;
476:
477: $tierPriceRound = new Zend_Db_Expr("ROUND(i.base_tier * ({$optPriceValue} / 100), 4)");
478: $tierPriceExpr = $write->getCheckSql("{$optPriceType} = 'fixed'", $optPriceValue, $tierPriceRound);
479: $tierPriceValue = $write->getCheckSql("{$tierPriceExpr} > 0 AND o.is_require > 0", $tierPriceExpr, 0);
480: $tierPrice = $write->getCheckSql("i.base_tier IS NOT NULL", $tierPriceValue, "NULL");
481:
482: $groupPriceRound = new Zend_Db_Expr("ROUND(i.base_group_price * ({$optPriceValue} / 100), 4)");
483: $groupPriceExpr = $write->getCheckSql("{$optPriceType} = 'fixed'", $optPriceValue, $groupPriceRound);
484: $groupPriceValue = $write->getCheckSql("{$groupPriceExpr} > 0 AND o.is_require > 0", $groupPriceExpr, 0);
485: $groupPrice = $write->getCheckSql("i.base_group_price IS NOT NULL", $groupPriceValue, "NULL");
486:
487: $select->columns(array(
488: 'min_price' => $minPrice,
489: 'max_price' => $maxPrice,
490: 'tier_price' => $tierPrice,
491: 'group_price' => $groupPrice,
492: ));
493:
494: $query = $select->insertFromSelect($coaTable);
495: $write->query($query);
496:
497: $select = $write->select()
498: ->from(
499: array($coaTable),
500: array(
501: 'entity_id',
502: 'customer_group_id',
503: 'website_id',
504: 'min_price' => 'SUM(min_price)',
505: 'max_price' => 'SUM(max_price)',
506: 'tier_price' => 'SUM(tier_price)',
507: 'group_price' => 'SUM(group_price)',
508: ))
509: ->group(array('entity_id', 'customer_group_id', 'website_id'));
510: $query = $select->insertFromSelect($copTable);
511: $write->query($query);
512:
513: $table = array('i' => $this->_getDefaultFinalPriceTable());
514: $select = $write->select()
515: ->join(
516: array('io' => $copTable),
517: 'i.entity_id = io.entity_id AND i.customer_group_id = io.customer_group_id'
518: .' AND i.website_id = io.website_id',
519: array());
520: $select->columns(array(
521: 'min_price' => new Zend_Db_Expr('i.min_price + io.min_price'),
522: 'max_price' => new Zend_Db_Expr('i.max_price + io.max_price'),
523: 'tier_price' => $write->getCheckSql('i.tier_price IS NOT NULL', 'i.tier_price + io.tier_price', 'NULL'),
524: 'group_price' => $write->getCheckSql(
525: 'i.group_price IS NOT NULL',
526: 'i.group_price + io.group_price', 'NULL'
527: ),
528: ));
529: $query = $select->crossUpdateFromSelect($table);
530: $write->query($query);
531:
532: $write->delete($coaTable);
533: $write->delete($copTable);
534:
535: return $this;
536: }
537:
538: 539: 540: 541: 542:
543: protected function _movePriceDataToIndexTable()
544: {
545: $columns = array(
546: 'entity_id' => 'entity_id',
547: 'customer_group_id' => 'customer_group_id',
548: 'website_id' => 'website_id',
549: 'tax_class_id' => 'tax_class_id',
550: 'price' => 'orig_price',
551: 'final_price' => 'price',
552: 'min_price' => 'min_price',
553: 'max_price' => 'max_price',
554: 'tier_price' => 'tier_price',
555: 'group_price' => 'group_price',
556: );
557:
558: $write = $this->_getWriteAdapter();
559: $table = $this->_getDefaultFinalPriceTable();
560: $select = $write->select()
561: ->from($table, $columns);
562:
563: $query = $select->insertFromSelect($this->getIdxTable(), array(), false);
564: $write->query($query);
565:
566: $write->delete($table);
567:
568: return $this;
569: }
570:
571: 572: 573: 574: 575:
576: protected function _getTierPriceIndexTable()
577: {
578: return $this->getTable('catalog/product_index_tier_price');
579: }
580:
581: 582: 583: 584: 585:
586: protected function _getGroupPriceIndexTable()
587: {
588: return $this->getTable('catalog/product_index_group_price');
589: }
590:
591: 592: 593: 594: 595:
596: public function registerEvent(Mage_Index_Model_Event $event)
597: {
598:
599: }
600:
601: 602: 603: 604: 605: 606:
607: public function getIdxTable($table = null)
608: {
609: if ($this->useIdxTable()) {
610: return $this->getTable('catalog/product_price_indexer_idx');
611: }
612: return $this->getTable('catalog/product_price_indexer_tmp');
613: }
614: }
615: