Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
Price.php
Go to the documentation of this file.
1 <?php
7 
12 use Magento\Catalog\Api\Data\ProductTierPriceExtensionFactory;
14 
22 class Price
23 {
27  const CACHE_TAG = 'PRODUCT_PRICE';
28 
32  protected static $attributeCache = [];
33 
39  protected $_eventManager;
40 
46  protected $_customerSession;
47 
51  protected $_localeDate;
52 
58  protected $_storeManager;
59 
65  protected $_ruleFactory;
66 
70  protected $priceCurrency;
71 
75  protected $_groupManagement;
76 
80  protected $tierPriceFactory;
81 
85  protected $config;
86 
90  private $tierPriceExtensionFactory;
91 
107  public function __construct(
108  \Magento\CatalogRule\Model\ResourceModel\RuleFactory $ruleFactory,
110  \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate,
111  \Magento\Customer\Model\Session $customerSession,
112  \Magento\Framework\Event\ManagerInterface $eventManager,
114  GroupManagementInterface $groupManagement,
115  \Magento\Catalog\Api\Data\ProductTierPriceInterfaceFactory $tierPriceFactory,
117  ProductTierPriceExtensionFactory $tierPriceExtensionFactory = null
118  ) {
119  $this->_ruleFactory = $ruleFactory;
120  $this->_storeManager = $storeManager;
121  $this->_localeDate = $localeDate;
122  $this->_customerSession = $customerSession;
123  $this->_eventManager = $eventManager;
124  $this->priceCurrency = $priceCurrency;
125  $this->_groupManagement = $groupManagement;
126  $this->tierPriceFactory = $tierPriceFactory;
127  $this->config = $config;
128  $this->tierPriceExtensionFactory = $tierPriceExtensionFactory ?: ObjectManager::getInstance()
129  ->get(ProductTierPriceExtensionFactory::class);
130  }
131 
138  public function getPrice($product)
139  {
140  return $product->getData('price');
141  }
142 
151  public function getBasePrice($product, $qty = null)
152  {
153  $price = (float) $product->getPrice();
154  return min(
155  $this->_applyTierPrice($product, $qty, $price),
157  );
158  }
159 
167  public function getFinalPrice($qty, $product)
168  {
169  if ($qty === null && $product->getCalculatedFinalPrice() !== null) {
170  return $product->getCalculatedFinalPrice();
171  }
172 
173  $finalPrice = $this->getBasePrice($product, $qty);
174  $product->setFinalPrice($finalPrice);
175 
176  $this->_eventManager->dispatch('catalog_product_get_final_price', ['product' => $product, 'qty' => $qty]);
177 
178  $finalPrice = $product->getData('final_price');
179  $finalPrice = $this->_applyOptionsPrice($product, $qty, $finalPrice);
180  $finalPrice = max(0, $finalPrice);
181  $product->setFinalPrice($finalPrice);
182 
183  return $finalPrice;
184  }
185 
195  public function getChildFinalPrice($product, $productQty, $childProduct, $childProductQty)
196  {
197  return $this->getFinalPrice($childProductQty, $childProduct);
198  }
199 
208  protected function getExistingPrices($product, $key, $returnRawData = false)
209  {
210  $prices = $product->getData($key);
211 
212  if ($prices === null) {
213  $attribute = $product->getResource()->getAttribute($key);
214  if ($attribute) {
215  $attribute->getBackend()->afterLoad($product);
216  $prices = $product->getData($key);
217  }
218  }
219 
220  if ($prices === null || !is_array($prices)) {
221  return ($returnRawData ? $prices : []);
222  }
223 
224  return $prices;
225  }
226 
232  protected function getWebsiteForPriceScope()
233  {
234  $websiteId = 0;
235  $value = $this->config->getValue('catalog/price/scope', \Magento\Store\Model\ScopeInterface::SCOPE_WEBSITE);
236  if ($value != 0) {
237  // use the website associated with the current store
238  $websiteId = $this->_storeManager->getWebsite()->getId();
239  }
240  return $websiteId;
241  }
242 
251  protected function _applyTierPrice($product, $qty, $finalPrice)
252  {
253  if ($qty === null) {
254  return $finalPrice;
255  }
256 
257  $tierPrice = $product->getTierPrice($qty);
258  if (is_numeric($tierPrice)) {
259  $finalPrice = min($finalPrice, $tierPrice);
260  }
261  return $finalPrice;
262  }
263 
273  public function getTierPrice($qty, $product)
274  {
275  $allGroupsId = $this->getAllCustomerGroupsId();
276 
277  $prices = $this->getExistingPrices($product, 'tier_price', true);
278  if ($prices === null || !is_array($prices)) {
279  if ($qty !== null) {
280  return $product->getPrice();
281  } else {
282  return [
283  [
284  'price' => $product->getPrice(),
285  'website_price' => $product->getPrice(),
286  'price_qty' => 1,
287  'cust_group' => $allGroupsId,
288  ]
289  ];
290  }
291  }
292 
293  $custGroup = $this->_getCustomerGroupId($product);
294  if ($qty) {
295  $prevQty = 1;
296  $prevPrice = $product->getPrice();
297  $prevGroup = $allGroupsId;
298 
299  foreach ($prices as $price) {
300  if ($price['cust_group'] != $custGroup && $price['cust_group'] != $allGroupsId) {
301  // tier not for current customer group nor is for all groups
302  continue;
303  }
304  if ($qty < $price['price_qty']) {
305  // tier is higher than product qty
306  continue;
307  }
308  if ($price['price_qty'] < $prevQty) {
309  // higher tier qty already found
310  continue;
311  }
312  if ($price['price_qty'] == $prevQty &&
313  $prevGroup != $allGroupsId &&
314  $price['cust_group'] == $allGroupsId) {
315  // found tier qty is same as current tier qty but current tier group is ALL_GROUPS
316  continue;
317  }
318  if ($price['website_price'] < $prevPrice) {
319  $prevPrice = $price['website_price'];
320  $prevQty = $price['price_qty'];
321  $prevGroup = $price['cust_group'];
322  }
323  }
324  return $prevPrice;
325  } else {
326  $qtyCache = [];
327  foreach ($prices as $priceKey => $price) {
328  if ($price['cust_group'] != $custGroup && $price['cust_group'] != $allGroupsId) {
329  unset($prices[$priceKey]);
330  } elseif (isset($qtyCache[$price['price_qty']])) {
331  $priceQty = $qtyCache[$price['price_qty']];
332  if ($prices[$priceQty]['website_price'] > $price['website_price']) {
333  unset($prices[$priceQty]);
334  $qtyCache[$price['price_qty']] = $priceKey;
335  } else {
336  unset($prices[$priceKey]);
337  }
338  } else {
339  $qtyCache[$price['price_qty']] = $priceKey;
340  }
341  }
342  }
343 
344  return $prices ?: [];
345  }
346 
352  protected function getAllCustomerGroupsId()
353  {
354  // ex: 32000
355  return $this->_groupManagement->getAllCustomersGroup()->getId();
356  }
357 
364  public function getTierPrices($product)
365  {
366  $prices = [];
367  $tierPrices = $this->getExistingPrices($product, 'tier_price');
368  foreach ($tierPrices as $price) {
370  $tierPrice = $this->tierPriceFactory->create()
371  ->setExtensionAttributes($this->tierPriceExtensionFactory->create());
372  $tierPrice->setCustomerGroupId($price['cust_group']);
373  if (array_key_exists('website_price', $price)) {
374  $value = $price['website_price'];
375  } else {
376  $value = $price['price'];
377  }
378  $tierPrice->setValue($value);
379  $tierPrice->setQty($price['price_qty']);
380  if (isset($price['percentage_value'])) {
381  $tierPrice->getExtensionAttributes()->setPercentageValue($price['percentage_value']);
382  }
383  $websiteId = isset($price['website_id']) ? $price['website_id'] : $this->getWebsiteForPriceScope();
384  $tierPrice->getExtensionAttributes()->setWebsiteId($websiteId);
385  $prices[] = $tierPrice;
386  }
387  return $prices;
388  }
389 
397  public function setTierPrices($product, array $tierPrices = null)
398  {
399  // null array means leave everything as is
400  if ($tierPrices === null) {
401  return $this;
402  }
403 
404  $allGroupsId = $this->getAllCustomerGroupsId();
406 
407  // build the new array of tier prices
408  $prices = [];
409  foreach ($tierPrices as $price) {
410  $extensionAttributes = $price->getExtensionAttributes();
411  $priceWebsiteId = $websiteId;
412  if (isset($extensionAttributes) && is_numeric($extensionAttributes->getWebsiteId())) {
413  $priceWebsiteId = (string)$extensionAttributes->getWebsiteId();
414  }
415  $prices[] = [
416  'website_id' => $priceWebsiteId,
417  'cust_group' => $price->getCustomerGroupId(),
418  'website_price' => $price->getValue(),
419  'price' => $price->getValue(),
420  'all_groups' => ($price->getCustomerGroupId() == $allGroupsId),
421  'price_qty' => $price->getQty(),
422  'percentage_value' => $extensionAttributes ? $extensionAttributes->getPercentageValue() : null
423  ];
424  }
425  $product->setData('tier_price', $prices);
426 
427  return $this;
428  }
429 
434  protected function _getCustomerGroupId($product)
435  {
436  if ($product->getCustomerGroupId() !== null) {
437  return $product->getCustomerGroupId();
438  }
439  return $this->_customerSession->getCustomerGroupId();
440  }
441 
449  protected function _applySpecialPrice($product, $finalPrice)
450  {
451  return $this->calculateSpecialPrice(
452  $finalPrice,
453  $product->getSpecialPrice(),
454  $product->getSpecialFromDate(),
455  $product->getSpecialToDate(),
456  $product->getStore()
457  );
458  }
459 
466  public function getTierPriceCount($product)
467  {
468  $price = $product->getTierPrice();
469  return count($price);
470  }
471 
481  public function getFormattedTierPrice($qty, $product)
482  {
483  $price = $product->getTierPrice($qty);
484  if (is_array($price)) {
485  foreach (array_keys($price) as $index) {
486  $price[$index]['formatted_price'] = $this->priceCurrency->convertAndFormat(
487  $price[$index]['website_price']
488  );
489  }
490  } else {
491  $price = $this->priceCurrency->format($price);
492  }
493 
494  return $price;
495  }
496 
508  public function getFormatedTierPrice($qty, $product)
509  {
510  return $this->getFormattedTierPrice($qty, $product);
511  }
512 
520  public function getFormattedPrice($product)
521  {
522  return $this->priceCurrency->format($product->getFinalPrice());
523  }
524 
534  public function getFormatedPrice($product)
535  {
536  return $this->getFormattedPrice($product);
537  }
538 
548  protected function _applyOptionsPrice($product, $qty, $finalPrice)
549  {
550  $optionIds = $product->getCustomOption('option_ids');
551  if ($optionIds) {
552  $basePrice = $finalPrice;
553  foreach (explode(',', $optionIds->getValue()) as $optionId) {
554  if ($option = $product->getOptionById($optionId)) {
555  $confItemOption = $product->getCustomOption('option_' . $option->getId());
556 
557  $group = $option->groupFactory($option->getType())
558  ->setOption($option)
559  ->setConfigurationItemOption($confItemOption);
560  $finalPrice += $group->getOptionPrice($confItemOption->getValue(), $basePrice);
561  }
562  }
563  }
564 
565  return $finalPrice;
566  }
567 
581  public function calculatePrice(
582  $basePrice,
583  $specialPrice,
584  $specialPriceFrom,
585  $specialPriceTo,
586  $rulePrice = false,
587  $wId = null,
588  $gId = null,
589  $productId = null
590  ) {
591  \Magento\Framework\Profiler::start('__PRODUCT_CALCULATE_PRICE__');
592  if ($wId instanceof Store) {
593  $sId = $wId->getId();
594  $wId = $wId->getWebsiteId();
595  } else {
596  $sId = $this->_storeManager->getWebsite($wId)->getDefaultGroup()->getDefaultStoreId();
597  }
598 
599  $finalPrice = $basePrice;
600 
601  $finalPrice = $this->calculateSpecialPrice(
602  $finalPrice,
603  $specialPrice,
604  $specialPriceFrom,
605  $specialPriceTo,
606  $sId
607  );
608 
609  if ($rulePrice === false) {
610  $date = $this->_localeDate->scopeDate($sId);
611  $rulePrice = $this->_ruleFactory->create()->getRulePrice($date, $wId, $gId, $productId);
612  }
613 
614  if ($rulePrice !== null && $rulePrice !== false) {
615  $finalPrice = min($finalPrice, $rulePrice);
616  }
617 
618  $finalPrice = max($finalPrice, 0);
619  \Magento\Framework\Profiler::stop('__PRODUCT_CALCULATE_PRICE__');
620  return $finalPrice;
621  }
622 
633  public function calculateSpecialPrice(
634  $finalPrice,
635  $specialPrice,
636  $specialPriceFrom,
637  $specialPriceTo,
638  $store = null
639  ) {
640  if ($specialPrice !== null && $specialPrice != false) {
641  if ($this->_localeDate->isScopeDateInInterval($store, $specialPriceFrom, $specialPriceTo)) {
642  $finalPrice = min($finalPrice, $specialPrice);
643  }
644  }
645  return $finalPrice;
646  }
647 
653  public function isTierPriceFixed()
654  {
655  return true;
656  }
657 }
_applyTierPrice($product, $qty, $finalPrice)
Definition: Price.php:251
_applyOptionsPrice($product, $qty, $finalPrice)
Definition: Price.php:548
__construct(\Magento\CatalogRule\Model\ResourceModel\RuleFactory $ruleFactory, \Magento\Store\Model\StoreManagerInterface $storeManager, \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate, \Magento\Customer\Model\Session $customerSession, \Magento\Framework\Event\ManagerInterface $eventManager, PriceCurrencyInterface $priceCurrency, GroupManagementInterface $groupManagement, \Magento\Catalog\Api\Data\ProductTierPriceInterfaceFactory $tierPriceFactory, \Magento\Framework\App\Config\ScopeConfigInterface $config, ProductTierPriceExtensionFactory $tierPriceExtensionFactory=null)
Definition: Price.php:107
elseif(isset( $params[ 'redirect_parent']))
Definition: iframe.phtml:17
getBasePrice($product, $qty=null)
Definition: Price.php:151
$group
Definition: sections.phtml:16
$storeManager
setTierPrices($product, array $tierPrices=null)
Definition: Price.php:397
$price
$value
Definition: gender.phtml:16
calculateSpecialPrice( $finalPrice, $specialPrice, $specialPriceFrom, $specialPriceTo, $store=null)
Definition: Price.php:633
calculatePrice( $basePrice, $specialPrice, $specialPriceFrom, $specialPriceTo, $rulePrice=false, $wId=null, $gId=null, $productId=null)
Definition: Price.php:581
getChildFinalPrice($product, $productQty, $childProduct, $childProductQty)
Definition: Price.php:195
getExistingPrices($product, $key, $returnRawData=false)
Definition: Price.php:208
$index
Definition: list.phtml:44
_applySpecialPrice($product, $finalPrice)
Definition: Price.php:449