Subtotal.php 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Quote\Model\Quote\Address\Total;
  7. use Magento\Quote\Model\Quote\Address;
  8. use Magento\Quote\Model\Quote\Address\Item as AddressItem;
  9. use Magento\Quote\Model\Quote\Item;
  10. class Subtotal extends \Magento\Quote\Model\Quote\Address\Total\AbstractTotal
  11. {
  12. /**
  13. * Sales data
  14. *
  15. * @var \Magento\Quote\Model\QuoteValidator
  16. */
  17. protected $quoteValidator = null;
  18. /**
  19. * @param \Magento\Quote\Model\QuoteValidator $quoteValidator
  20. */
  21. public function __construct(\Magento\Quote\Model\QuoteValidator $quoteValidator)
  22. {
  23. $this->quoteValidator = $quoteValidator;
  24. }
  25. /**
  26. * Collect address subtotal
  27. *
  28. * @param \Magento\Quote\Model\Quote $quote
  29. * @param \Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment
  30. * @param Address\Total $total
  31. * @return $this
  32. */
  33. public function collect(
  34. \Magento\Quote\Model\Quote $quote,
  35. \Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment,
  36. \Magento\Quote\Model\Quote\Address\Total $total
  37. ) {
  38. parent::collect($quote, $shippingAssignment, $total);
  39. $baseVirtualAmount = $virtualAmount = 0;
  40. $address = $shippingAssignment->getShipping()->getAddress();
  41. $address->setTotalQty(0);
  42. /**
  43. * Process address items
  44. */
  45. $items = $shippingAssignment->getItems();
  46. foreach ($items as $item) {
  47. if ($this->_initItem($address, $item) && $item->getQty() > 0) {
  48. /**
  49. * Separately calculate subtotal only for virtual products
  50. */
  51. if ($item->getProduct()->isVirtual()) {
  52. $virtualAmount += $item->getRowTotal();
  53. $baseVirtualAmount += $item->getBaseRowTotal();
  54. }
  55. } else {
  56. $this->_removeItem($address, $item);
  57. }
  58. }
  59. $total->setBaseVirtualAmount($baseVirtualAmount);
  60. $total->setVirtualAmount($virtualAmount);
  61. /**
  62. * Initialize grand totals
  63. */
  64. $this->quoteValidator->validateQuoteAmount($quote, $total->getSubtotal());
  65. $this->quoteValidator->validateQuoteAmount($quote, $total->getBaseSubtotal());
  66. $address->setSubtotal($total->getSubtotal());
  67. $address->setBaseSubtotal($total->getBaseSubtotal());
  68. return $this;
  69. }
  70. /**
  71. * Address item initialization
  72. *
  73. * @param Address $address
  74. * @param AddressItem|Item $item
  75. * @return bool
  76. */
  77. protected function _initItem($address, $item)
  78. {
  79. if ($item instanceof AddressItem) {
  80. $quoteItem = $item->getAddress()->getQuote()->getItemById($item->getQuoteItemId());
  81. } else {
  82. $quoteItem = $item;
  83. }
  84. $product = $quoteItem->getProduct();
  85. $product->setCustomerGroupId($quoteItem->getQuote()->getCustomerGroupId());
  86. /**
  87. * Quote super mode flag mean what we work with quote without restriction
  88. */
  89. if ($item->getQuote()->getIsSuperMode()) {
  90. if (!$product) {
  91. return false;
  92. }
  93. } else {
  94. if (!$product || !$product->isVisibleInCatalog()) {
  95. return false;
  96. }
  97. }
  98. $quoteItem->setConvertedPrice(null);
  99. $originalPrice = $product->getPrice();
  100. if ($quoteItem->getParentItem() && $quoteItem->isChildrenCalculated()) {
  101. $finalPrice = $quoteItem->getParentItem()->getProduct()->getPriceModel()->getChildFinalPrice(
  102. $quoteItem->getParentItem()->getProduct(),
  103. $quoteItem->getParentItem()->getQty(),
  104. $product,
  105. $quoteItem->getQty()
  106. );
  107. $this->_calculateRowTotal($item, $finalPrice, $originalPrice);
  108. } elseif (!$quoteItem->getParentItem()) {
  109. $finalPrice = $product->getFinalPrice($quoteItem->getQty());
  110. $this->_calculateRowTotal($item, $finalPrice, $originalPrice);
  111. $this->_addAmount($item->getRowTotal());
  112. $this->_addBaseAmount($item->getBaseRowTotal());
  113. $address->setTotalQty($address->getTotalQty() + $item->getQty());
  114. }
  115. return true;
  116. }
  117. /**
  118. * Processing calculation of row price for address item
  119. *
  120. * @param AddressItem|Item $item
  121. * @param int $finalPrice
  122. * @param int $originalPrice
  123. * @return $this
  124. */
  125. protected function _calculateRowTotal($item, $finalPrice, $originalPrice)
  126. {
  127. if (!$originalPrice) {
  128. $originalPrice = $finalPrice;
  129. }
  130. $item->setPrice($finalPrice)->setBaseOriginalPrice($originalPrice);
  131. $item->calcRowTotal();
  132. return $this;
  133. }
  134. /**
  135. * Remove item
  136. *
  137. * @param Address $address
  138. * @param AddressItem|Item $item
  139. * @return $this
  140. */
  141. protected function _removeItem($address, $item)
  142. {
  143. if ($item instanceof Item) {
  144. $address->removeItem($item->getId());
  145. if ($address->getQuote()) {
  146. $address->getQuote()->removeItem($item->getId());
  147. }
  148. } elseif ($item instanceof AddressItem) {
  149. $address->removeItem($item->getId());
  150. if ($address->getQuote()) {
  151. $address->getQuote()->removeItem($item->getQuoteItemId());
  152. }
  153. }
  154. return $this;
  155. }
  156. /**
  157. * Assign subtotal amount and label to address object
  158. *
  159. * @param \Magento\Quote\Model\Quote $quote
  160. * @param Address\Total $total
  161. * @return array
  162. * @SuppressWarnings(PHPMD.UnusedFormalParameter)
  163. */
  164. public function fetch(\Magento\Quote\Model\Quote $quote, \Magento\Quote\Model\Quote\Address\Total $total)
  165. {
  166. return [
  167. 'code' => $this->getCode(),
  168. 'title' => $this->getLabel(),
  169. 'value' => $total->getSubtotal()
  170. ];
  171. }
  172. /**
  173. * Get Subtotal label
  174. *
  175. * @return \Magento\Framework\Phrase
  176. */
  177. public function getLabel()
  178. {
  179. return __('Subtotal');
  180. }
  181. }