/vendor/magento/module-catalog/Pricing/Price/TierPrice.php

https://gitlab.com/yousafsyed/easternglamor · PHP · 301 lines · 179 code · 22 blank · 100 comment · 34 complexity · fb3b8d2beba22dee4a6383963f56faeb MD5 · raw file

  1. <?php
  2. /**
  3. * Copyright © 2016 Magento. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. // @codingStandardsIgnoreFile
  7. namespace Magento\Catalog\Pricing\Price;
  8. use Magento\Catalog\Model\Product;
  9. use Magento\Customer\Api\GroupManagementInterface;
  10. use Magento\Customer\Model\Session;
  11. use Magento\Framework\Pricing\Adjustment\CalculatorInterface;
  12. use Magento\Framework\Pricing\Amount\AmountInterface;
  13. use Magento\Framework\Pricing\Price\AbstractPrice;
  14. use Magento\Framework\Pricing\Price\BasePriceProviderInterface;
  15. use Magento\Framework\Pricing\PriceInfoInterface;
  16. /**
  17. * Tire prices model
  18. */
  19. class TierPrice extends AbstractPrice implements TierPriceInterface, BasePriceProviderInterface
  20. {
  21. /**
  22. * Price type tier
  23. */
  24. const PRICE_CODE = 'tier_price';
  25. /**
  26. * @var Session
  27. */
  28. protected $customerSession;
  29. /**
  30. * @var int
  31. */
  32. protected $customerGroup;
  33. /**
  34. * Raw price list stored in DB
  35. *
  36. * @var array
  37. */
  38. protected $rawPriceList;
  39. /**
  40. * Applicable price list
  41. *
  42. * @var array
  43. */
  44. protected $priceList;
  45. /**
  46. * @var GroupManagementInterface
  47. */
  48. protected $groupManagement;
  49. /**
  50. * @param Product $saleableItem
  51. * @param float $quantity
  52. * @param CalculatorInterface $calculator
  53. * @param \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency
  54. * @param Session $customerSession
  55. * @param GroupManagementInterface $groupManagement
  56. */
  57. public function __construct(
  58. Product $saleableItem,
  59. $quantity,
  60. CalculatorInterface $calculator,
  61. \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency,
  62. Session $customerSession,
  63. GroupManagementInterface $groupManagement
  64. ) {
  65. $quantity = $quantity ?: 1;
  66. parent::__construct($saleableItem, $quantity, $calculator, $priceCurrency);
  67. $this->customerSession = $customerSession;
  68. $this->groupManagement = $groupManagement;
  69. if ($saleableItem->hasCustomerGroupId()) {
  70. $this->customerGroup = (int) $saleableItem->getCustomerGroupId();
  71. } else {
  72. $this->customerGroup = (int) $this->customerSession->getCustomerGroupId();
  73. }
  74. }
  75. /**
  76. * Get price value
  77. *
  78. * @return bool|float
  79. */
  80. public function getValue()
  81. {
  82. if (null === $this->value) {
  83. $prices = $this->getStoredTierPrices();
  84. $prevQty = PriceInfoInterface::PRODUCT_QUANTITY_DEFAULT;
  85. $this->value = $prevPrice = $tierPrice = false;
  86. $priceGroup = $this->groupManagement->getAllCustomersGroup()->getId();
  87. foreach ($prices as $price) {
  88. if (!$this->canApplyTierPrice($price, $priceGroup, $prevQty)) {
  89. continue;
  90. }
  91. if (false === $prevPrice || $this->isFirstPriceBetter($price['website_price'], $prevPrice)) {
  92. $tierPrice = $prevPrice = $price['website_price'];
  93. $prevQty = $price['price_qty'];
  94. $priceGroup = $price['cust_group'];
  95. $this->value = (float)$tierPrice;
  96. }
  97. }
  98. }
  99. return $this->value;
  100. }
  101. /**
  102. * Returns true if first price is better
  103. *
  104. * Method filters tiers price values, lower tier price value is better
  105. *
  106. * @param float $firstPrice
  107. * @param float $secondPrice
  108. * @return bool
  109. */
  110. protected function isFirstPriceBetter($firstPrice, $secondPrice)
  111. {
  112. return $firstPrice < $secondPrice;
  113. }
  114. /**
  115. * @return int
  116. */
  117. public function getTierPriceCount()
  118. {
  119. return count($this->getTierPriceList());
  120. }
  121. /**
  122. * @return array
  123. */
  124. public function getTierPriceList()
  125. {
  126. if (null === $this->priceList) {
  127. $priceList = $this->getStoredTierPrices();
  128. $this->priceList = $this->filterTierPrices($priceList);
  129. array_walk(
  130. $this->priceList,
  131. function (&$priceData) {
  132. /* convert string value to float */
  133. $priceData['price_qty'] = $priceData['price_qty'] * 1;
  134. $priceData['price'] = $this->applyAdjustment($priceData['price']);
  135. }
  136. );
  137. }
  138. return $this->priceList;
  139. }
  140. /**
  141. * @param array $priceList
  142. * @return array
  143. */
  144. protected function filterTierPrices(array $priceList)
  145. {
  146. $qtyCache = [];
  147. $allCustomersGroupId = $this->groupManagement->getAllCustomersGroup()->getId();
  148. foreach ($priceList as $priceKey => &$price) {
  149. if (isset($price['price_qty']) && $price['price_qty'] == 1) {
  150. unset($priceList[$priceKey]);
  151. continue;
  152. }
  153. /* filter price by customer group */
  154. if ($price['cust_group'] != $this->customerGroup &&
  155. $price['cust_group'] != $allCustomersGroupId) {
  156. unset($priceList[$priceKey]);
  157. continue;
  158. }
  159. /* select a lower price for each quantity */
  160. if (isset($qtyCache[$price['price_qty']])) {
  161. $priceQty = $qtyCache[$price['price_qty']];
  162. if ($this->isFirstPriceBetter($price['website_price'], $priceList[$priceQty]['website_price'])) {
  163. unset($priceList[$priceQty]);
  164. $qtyCache[$price['price_qty']] = $priceKey;
  165. } else {
  166. unset($priceList[$priceKey]);
  167. }
  168. } else {
  169. $qtyCache[$price['price_qty']] = $priceKey;
  170. }
  171. }
  172. return array_values($priceList);
  173. }
  174. /**
  175. * @return float
  176. */
  177. protected function getBasePrice()
  178. {
  179. /** @var float $productPrice is a minimal available price */
  180. return $this->priceInfo->getPrice(BasePrice::PRICE_CODE)->getValue();
  181. }
  182. /**
  183. * @param AmountInterface $amount
  184. * @return float
  185. */
  186. public function getSavePercent(AmountInterface $amount)
  187. {
  188. return ceil(
  189. 100 - ((100 / $this->priceInfo->getPrice(RegularPrice::PRICE_CODE)->getAmount()->getBaseAmount())
  190. * $amount->getBaseAmount())
  191. );
  192. }
  193. /**
  194. * @param float|string $price
  195. * @return \Magento\Framework\Pricing\Amount\AmountInterface
  196. */
  197. protected function applyAdjustment($price)
  198. {
  199. return $this->calculator->getAmount($price, $this->product);
  200. }
  201. /**
  202. * Can apply tier price
  203. *
  204. * @param array $currentTierPrice
  205. * @param int $prevPriceGroup
  206. * @param float|string $prevQty
  207. * @return bool
  208. */
  209. protected function canApplyTierPrice(array $currentTierPrice, $prevPriceGroup, $prevQty)
  210. {
  211. $custGroupAllId = (int)$this->groupManagement->getAllCustomersGroup()->getId();
  212. // Tier price can be applied, if:
  213. // tier price is for current customer group or is for all groups
  214. if ((int)$currentTierPrice['cust_group'] !== $this->customerGroup
  215. && (int)$currentTierPrice['cust_group'] !== $custGroupAllId
  216. ) {
  217. return false;
  218. }
  219. // and tier qty is lower than product qty
  220. if ($this->quantity < $currentTierPrice['price_qty']) {
  221. return false;
  222. }
  223. // and tier qty is bigger than previous qty
  224. if ($currentTierPrice['price_qty'] < $prevQty) {
  225. return false;
  226. }
  227. // and found tier qty is same as previous tier qty, but current tier group isn't ALL_GROUPS
  228. if ($currentTierPrice['price_qty'] == $prevQty
  229. && $prevPriceGroup !== $custGroupAllId
  230. && $currentTierPrice['cust_group'] === $custGroupAllId
  231. ) {
  232. return false;
  233. }
  234. return true;
  235. }
  236. /**
  237. * Get clear tier price list stored in DB
  238. *
  239. * @return array
  240. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  241. */
  242. protected function getStoredTierPrices()
  243. {
  244. if (null === $this->rawPriceList) {
  245. $this->rawPriceList = $this->product->getData(self::PRICE_CODE);
  246. if (null === $this->rawPriceList || !is_array($this->rawPriceList)) {
  247. /** @var \Magento\Eav\Model\Entity\Attribute\AbstractAttribute $attribute */
  248. $attribute = $this->product->getResource()->getAttribute(self::PRICE_CODE);
  249. if ($attribute) {
  250. $attribute->getBackend()->afterLoad($this->product);
  251. $this->rawPriceList = $this->product->getData(self::PRICE_CODE);
  252. }
  253. }
  254. if (null === $this->rawPriceList || !is_array($this->rawPriceList)) {
  255. $this->rawPriceList = [];
  256. }
  257. if (!$this->isPercentageDiscount()) {
  258. foreach ($this->rawPriceList as $index => $rawPrice) {
  259. if (isset($rawPrice['price'])) {
  260. $this->rawPriceList[$index]['price'] =
  261. $this->priceCurrency->convertAndRound($rawPrice['price']);
  262. }
  263. if (isset($rawPrice['website_price'])) {
  264. $this->rawPriceList[$index]['website_price'] =
  265. $this->priceCurrency->convertAndRound($rawPrice['website_price']);
  266. }
  267. }
  268. }
  269. }
  270. return $this->rawPriceList;
  271. }
  272. /**
  273. * @return bool
  274. */
  275. public function isPercentageDiscount()
  276. {
  277. return false;
  278. }
  279. }