DefaultSelectionPriceListProvider.php 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Bundle\Pricing\Adjustment;
  7. use Magento\Bundle\Model\Option;
  8. use Magento\Bundle\Pricing\Price\BundleSelectionFactory;
  9. use Magento\Catalog\Model\Product;
  10. use Magento\Bundle\Model\Product\Price;
  11. /**
  12. * Provide lightweight implementation which uses price index
  13. */
  14. class DefaultSelectionPriceListProvider implements SelectionPriceListProviderInterface
  15. {
  16. /**
  17. * @var BundleSelectionFactory
  18. */
  19. private $selectionFactory;
  20. /**
  21. * @var \Magento\Bundle\Pricing\Price\BundleSelectionPrice[]
  22. */
  23. private $priceList;
  24. /**
  25. * @param BundleSelectionFactory $bundleSelectionFactory
  26. */
  27. public function __construct(BundleSelectionFactory $bundleSelectionFactory)
  28. {
  29. $this->selectionFactory = $bundleSelectionFactory;
  30. }
  31. /**
  32. * {@inheritdoc}
  33. */
  34. public function getPriceList(Product $bundleProduct, $searchMin, $useRegularPrice)
  35. {
  36. $shouldFindMinOption = $this->isShouldFindMinOption($bundleProduct, $searchMin);
  37. $canSkipRequiredOptions = $searchMin && !$shouldFindMinOption;
  38. /** @var \Magento\Bundle\Model\Product\Type $typeInstance */
  39. $typeInstance = $bundleProduct->getTypeInstance();
  40. $this->priceList = [];
  41. foreach ($this->getBundleOptions($bundleProduct) as $option) {
  42. /** @var Option $option */
  43. if ($this->canSkipOption($option, $canSkipRequiredOptions)) {
  44. continue;
  45. }
  46. $selectionsCollection = $typeInstance->getSelectionsCollection(
  47. [(int)$option->getOptionId()],
  48. $bundleProduct
  49. );
  50. $selectionsCollection->removeAttributeToSelect();
  51. $selectionsCollection->addQuantityFilter();
  52. if (!$useRegularPrice) {
  53. $selectionsCollection->addAttributeToSelect('special_price');
  54. $selectionsCollection->addAttributeToSelect('special_from_date');
  55. $selectionsCollection->addAttributeToSelect('special_to_date');
  56. $selectionsCollection->addAttributeToSelect('tax_class_id');
  57. }
  58. if (!$searchMin && $option->isMultiSelection()) {
  59. $this->addMaximumMultiSelectionPriceList($bundleProduct, $selectionsCollection, $useRegularPrice);
  60. } else {
  61. $this->addMiniMaxPriceList($bundleProduct, $selectionsCollection, $searchMin, $useRegularPrice);
  62. }
  63. }
  64. if ($shouldFindMinOption) {
  65. $this->processMinPriceForNonRequiredOptions();
  66. }
  67. return $this->priceList;
  68. }
  69. /**
  70. * Flag shows - is it necessary to find minimal option amount in case if all options are not required
  71. *
  72. * @param Product $bundleProduct
  73. * @param bool $searchMin
  74. * @return bool
  75. */
  76. private function isShouldFindMinOption(Product $bundleProduct, $searchMin)
  77. {
  78. $shouldFindMinOption = false;
  79. if ($searchMin
  80. && $bundleProduct->getPriceType() == Price::PRICE_TYPE_DYNAMIC
  81. && !$this->hasRequiredOption($bundleProduct)
  82. ) {
  83. $shouldFindMinOption = true;
  84. }
  85. return $shouldFindMinOption;
  86. }
  87. /**
  88. * Add minimum or maximum price for option
  89. *
  90. * @param Product $bundleProduct
  91. * @param \Magento\Bundle\Model\ResourceModel\Selection\Collection $selectionsCollection
  92. * @param bool $searchMin
  93. * @param bool $useRegularPrice
  94. * @return void
  95. */
  96. private function addMiniMaxPriceList(Product $bundleProduct, $selectionsCollection, $searchMin, $useRegularPrice)
  97. {
  98. $selectionsCollection->addPriceFilter($bundleProduct, $searchMin, $useRegularPrice);
  99. $selectionsCollection->setPage(0, 1);
  100. $selection = $selectionsCollection->getFirstItem();
  101. if (!$selection->isEmpty()) {
  102. $this->priceList[] = $this->selectionFactory->create(
  103. $bundleProduct,
  104. $selection,
  105. $selection->getSelectionQty(),
  106. [
  107. 'useRegularPrice' => $useRegularPrice,
  108. ]
  109. );
  110. }
  111. }
  112. /**
  113. * Add maximum price for multi selection option
  114. *
  115. * @param Product $bundleProduct
  116. * @param \Magento\Bundle\Model\ResourceModel\Selection\Collection $selectionsCollection
  117. * @param bool $useRegularPrice
  118. * @return void
  119. */
  120. private function addMaximumMultiSelectionPriceList(Product $bundleProduct, $selectionsCollection, $useRegularPrice)
  121. {
  122. $selectionsCollection->addPriceData();
  123. foreach ($selectionsCollection as $selection) {
  124. $this->priceList[] = $this->selectionFactory->create(
  125. $bundleProduct,
  126. $selection,
  127. $selection->getSelectionQty(),
  128. [
  129. 'useRegularPrice' => $useRegularPrice,
  130. ]
  131. );
  132. }
  133. }
  134. /**
  135. * @return void
  136. */
  137. private function processMinPriceForNonRequiredOptions()
  138. {
  139. $minPrice = null;
  140. $priceSelection = null;
  141. foreach ($this->priceList as $price) {
  142. $minPriceTmp = $price->getAmount()->getValue() * $price->getQuantity();
  143. if (!$minPrice || $minPriceTmp < $minPrice) {
  144. $minPrice = $minPriceTmp;
  145. $priceSelection = $price;
  146. }
  147. }
  148. $this->priceList = $priceSelection ? [$priceSelection] : [];
  149. }
  150. /**
  151. * Check this option if it should be skipped
  152. *
  153. * @param Option $option
  154. * @param bool $canSkipRequiredOption
  155. * @return bool
  156. */
  157. private function canSkipOption($option, $canSkipRequiredOption)
  158. {
  159. return $canSkipRequiredOption && !$option->getRequired();
  160. }
  161. /**
  162. * Check the bundle product for availability of required options
  163. *
  164. * @param Product $bundleProduct
  165. * @return bool
  166. */
  167. private function hasRequiredOption($bundleProduct)
  168. {
  169. $collection = clone $this->getBundleOptions($bundleProduct);
  170. $collection->clear();
  171. return $collection->addFilter(Option::KEY_REQUIRED, 1)->getSize() > 0;
  172. }
  173. /**
  174. * Get bundle options
  175. *
  176. * @param Product $saleableItem
  177. * @return \Magento\Bundle\Model\ResourceModel\Option\Collection
  178. */
  179. private function getBundleOptions(Product $saleableItem)
  180. {
  181. return $saleableItem->getTypeInstance()->getOptionsCollection($saleableItem);
  182. }
  183. }