123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687 |
- <?php
- /**
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
- */
- namespace Magento\Quote\Model\Quote\Item;
- use Magento\Quote\Model\Quote\Item;
- use Magento\Framework\Api\AttributeValueFactory;
- /**
- * Quote item abstract model
- *
- * Price attributes:
- * - price - initial item price, declared during product association
- * - original_price - product price before any calculations
- * - calculation_price - prices for item totals calculation
- * - custom_price - new price that can be declared by user and recalculated during calculation process
- * - original_custom_price - original defined value of custom price without any conversion
- *
- * @api
- * @method float getDiscountAmount()
- * @method \Magento\Quote\Model\Quote\Item\AbstractItem setDiscountAmount(float $amount)
- * @method float getBaseDiscountAmount()
- * @method \Magento\Quote\Model\Quote\Item\AbstractItem setBaseDiscountAmount(float $amount)
- * @method float getDiscountPercent()
- * @method \Magento\Quote\Model\Quote\Item\AbstractItem setDiscountPercent()
- * @method float getOriginalDiscountAmount()
- * @method \Magento\Quote\Model\Quote\Item\AbstractItem setOriginalDiscountAmount()
- * @method float getBaseOriginalDiscountAmount()
- * @method \Magento\Quote\Model\Quote\Item\AbstractItem setBaseOriginalDiscountAmount()
- * @method float getDiscountCalculationPrice()
- * @method \Magento\Quote\Model\Quote\Item\AbstractItem setDiscountCalculationPrice()
- * @method float getBaseDiscountCalculationPrice()
- * @method \Magento\Quote\Model\Quote\Item\AbstractItem setBaseDiscountCalculationPrice($price)
- * @method int[] getAppliedRuleIds()
- * @method \Magento\Quote\Model\Quote\Item\AbstractItem setAppliedRuleIds(array $ruleIds)
- * @method float getBaseTaxAmount()
- * @method float getBaseDiscountTaxCompensation()
- * @method float getBaseRowTotal()
- * @method float getQtyOrdered()
- * @method float getRowTotalInclTax()
- * @method float getTaxAmount()
- * @method float getDiscountTaxCompensation()
- * @method float getRowTotal()
- * @method float getPriceInclTax()
- * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
- * @since 100.0.2
- */
- abstract class AbstractItem extends \Magento\Framework\Model\AbstractExtensibleModel implements
- \Magento\Catalog\Model\Product\Configuration\Item\ItemInterface
- {
- /**
- * @var Item|null
- */
- protected $_parentItem = null;
- /**
- * @var \Magento\Quote\Model\Quote\Item\AbstractItem[]
- */
- protected $_children = [];
- /**
- * @var array
- */
- protected $_messages = [];
- /**
- * List of custom options
- *
- * @var array
- */
- protected $_optionsByCode;
- /**
- * @var \Magento\Catalog\Api\ProductRepositoryInterface
- */
- protected $productRepository;
- /**
- * @var \Magento\Framework\Pricing\PriceCurrencyInterface
- */
- protected $priceCurrency;
- /**
- * @param \Magento\Framework\Model\Context $context
- * @param \Magento\Framework\Registry $registry
- * @param \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory
- * @param AttributeValueFactory $customAttributeFactory
- * @param \Magento\Catalog\Api\ProductRepositoryInterface $productRepository
- * @param \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency
- * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource
- * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
- * @param array $data
- */
- public function __construct(
- \Magento\Framework\Model\Context $context,
- \Magento\Framework\Registry $registry,
- \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory,
- AttributeValueFactory $customAttributeFactory,
- \Magento\Catalog\Api\ProductRepositoryInterface $productRepository,
- \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency,
- \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
- \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
- array $data = []
- ) {
- parent::__construct(
- $context,
- $registry,
- $extensionFactory,
- $customAttributeFactory,
- $resource,
- $resourceCollection,
- $data
- );
- $this->productRepository = $productRepository;
- $this->priceCurrency = $priceCurrency;
- }
- /**
- * Retrieve Quote instance
- *
- * @return \Magento\Quote\Model\Quote
- */
- abstract public function getQuote();
- /**
- * Retrieve address model
- *
- * @return \Magento\Quote\Model\Quote\Address
- */
- abstract public function getAddress();
- /**
- * Retrieve product model object associated with item
- *
- * @return \Magento\Catalog\Model\Product
- */
- public function getProduct()
- {
- $product = $this->_getData('product');
- if ($product === null && $this->getProductId()) {
- $product = clone $this->productRepository->getById(
- $this->getProductId(),
- false,
- $this->getQuote()->getStoreId()
- );
- $this->setProduct($product);
- }
- /**
- * Reset product final price because it related to custom options
- */
- $product->setFinalPrice(null);
- if (is_array($this->_optionsByCode)) {
- $product->setCustomOptions($this->_optionsByCode);
- }
- return $product;
- }
- /**
- * Returns special download params (if needed) for custom option with type = 'file'
- * Needed to implement \Magento\Catalog\Model\Product\Configuration\Item\Interface.
- * Return null, as quote item needs no additional configuration.
- *
- * @return null|\Magento\Framework\DataObject
- */
- public function getFileDownloadParams()
- {
- return null;
- }
- /**
- * Specify parent item id before saving data
- *
- * @return $this
- */
- public function beforeSave()
- {
- parent::beforeSave();
- if ($this->getParentItem()) {
- $this->setParentItemId($this->getParentItem()->getId());
- }
- return $this;
- }
- /**
- * Set parent item
- *
- * @param Item $parentItem
- * @return $this
- */
- public function setParentItem($parentItem)
- {
- if ($parentItem) {
- $this->_parentItem = $parentItem;
- $parentItem->addChild($this);
- }
- return $this;
- }
- /**
- * Get parent item
- *
- * @return Item
- */
- public function getParentItem()
- {
- return $this->_parentItem;
- }
- /**
- * Get child items
- *
- * @return \Magento\Quote\Model\Quote\Item\AbstractItem[]
- */
- public function getChildren()
- {
- return $this->_children;
- }
- /**
- * Add child item
- *
- * @param \Magento\Quote\Model\Quote\Item\AbstractItem $child
- * @return $this
- */
- public function addChild($child)
- {
- $this->setHasChildren(true);
- $this->_children[] = $child;
- return $this;
- }
- /**
- * Adds message(s) for quote item. Duplicated messages are not added.
- *
- * @param mixed $messages
- * @return $this
- */
- public function setMessage($messages)
- {
- $messagesExists = $this->getMessage(false);
- if (!is_array($messages)) {
- $messages = [$messages];
- }
- foreach ($messages as $message) {
- if (!in_array($message, $messagesExists)) {
- $this->addMessage($message);
- }
- }
- return $this;
- }
- /**
- * Add message of quote item to array of messages
- *
- * @param string $message
- * @return $this
- */
- public function addMessage($message)
- {
- $this->_messages[] = $message;
- return $this;
- }
- /**
- * Get messages array of quote item
- *
- * @param bool $string flag for converting messages to string
- * @return array|string
- */
- public function getMessage($string = true)
- {
- if ($string) {
- return join("\n", $this->_messages);
- }
- return $this->_messages;
- }
- /**
- * Removes message by text
- *
- * @param string $text
- * @return $this
- */
- public function removeMessageByText($text)
- {
- foreach ($this->_messages as $key => $message) {
- if ($message == $text) {
- unset($this->_messages[$key]);
- }
- }
- return $this;
- }
- /**
- * Clears all messages
- *
- * @return $this
- */
- public function clearMessage()
- {
- $this->unsMessage();
- // For older compatibility, when we kept message inside data array
- $this->_messages = [];
- return $this;
- }
- /**
- * Retrieve store model object
- *
- * @return \Magento\Store\Model\Store
- */
- public function getStore()
- {
- return $this->getQuote()->getStore();
- }
- /**
- * Checking item data
- *
- * @return $this
- */
- public function checkData()
- {
- $this->setHasError(false);
- $this->clearMessage();
- $qty = $this->_getData('qty');
- try {
- $this->setQty($qty);
- } catch (\Magento\Framework\Exception\LocalizedException $e) {
- $this->setHasError(true);
- $this->setMessage($e->getMessage());
- } catch (\Exception $e) {
- $this->setHasError(true);
- $this->setMessage(__('Item qty declaration error'));
- }
- try {
- $this->getProduct()->getTypeInstance()->checkProductBuyState($this->getProduct());
- } catch (\Magento\Framework\Exception\LocalizedException $e) {
- $this->setHasError(true)->setMessage($e->getMessage());
- $this->getQuote()->setHasError(
- true
- )->addMessage(
- __('Some of the products below do not have all the required options.')
- );
- } catch (\Exception $e) {
- $this->setHasError(true)->setMessage(__('Something went wrong during the item options declaration.'));
- $this->getQuote()->setHasError(true)->addMessage(__('We found an item options declaration error.'));
- }
- if ($this->getProduct()->getHasError()) {
- $this->setHasError(true)->setMessage(__('Some of the selected options are not currently available.'));
- $this->getQuote()->setHasError(true)->addMessage($this->getProduct()->getMessage(), 'options');
- }
- if ($this->getHasConfigurationUnavailableError()) {
- $this->setHasError(
- true
- )->setMessage(
- __('Selected option(s) or their combination is not currently available.')
- );
- $this->getQuote()->setHasError(
- true
- )->addMessage(
- __('Some item options or their combination are not currently available.'),
- 'unavailable-configuration'
- );
- $this->unsHasConfigurationUnavailableError();
- }
- return $this;
- }
- /**
- * Get original (not related with parent item) item quantity
- *
- * @return int|float
- */
- public function getQty()
- {
- return $this->_getData('qty');
- }
- /**
- * Get total item quantity (include parent item relation)
- *
- * @return int|float
- */
- public function getTotalQty()
- {
- if ($this->getParentItem()) {
- return $this->getQty() * $this->getParentItem()->getQty();
- }
- return $this->getQty();
- }
- /**
- * Calculate item row total price
- *
- * @return $this
- */
- public function calcRowTotal()
- {
- $qty = $this->getTotalQty();
- // Round unit price before multiplying to prevent losing 1 cent on subtotal
- $total = $this->priceCurrency->round($this->getCalculationPriceOriginal()) * $qty;
- $baseTotal = $this->priceCurrency->round($this->getBaseCalculationPriceOriginal()) * $qty;
- $this->setRowTotal($this->priceCurrency->round($total));
- $this->setBaseRowTotal($this->priceCurrency->round($baseTotal));
- return $this;
- }
- /**
- * Get item price used for quote calculation process.
- *
- * This method get custom price (if it is defined) or original product final price
- *
- * @return float
- */
- public function getCalculationPrice()
- {
- $price = $this->_getData('calculation_price');
- if ($price === null) {
- if ($this->hasCustomPrice()) {
- $price = $this->getCustomPrice();
- } else {
- $price = $this->getConvertedPrice();
- }
- $this->setData('calculation_price', $price);
- }
- return $price;
- }
- /**
- * Get item price used for quote calculation process.
- *
- * This method get original custom price applied before tax calculation
- *
- * @return float
- */
- public function getCalculationPriceOriginal()
- {
- $price = $this->_getData('calculation_price');
- if ($price === null) {
- if ($this->hasOriginalCustomPrice()) {
- $price = $this->getOriginalCustomPrice();
- } else {
- $price = $this->getConvertedPrice();
- }
- $this->setData('calculation_price', $price);
- }
- return $price;
- }
- /**
- * Get calculation price used for quote calculation in base currency.
- *
- * @return float
- */
- public function getBaseCalculationPrice()
- {
- if (!$this->hasBaseCalculationPrice()) {
- if ($this->hasCustomPrice()) {
- $price = (double)$this->getCustomPrice();
- if ($price) {
- $rate = $this->priceCurrency->convert($price, $this->getStore()) / $price;
- $price = $price / $rate;
- }
- } else {
- $price = $this->getPrice();
- }
- $this->setBaseCalculationPrice($price);
- }
- return $this->_getData('base_calculation_price');
- }
- /**
- * Get original calculation price used for quote calculation in base currency.
- *
- * @return float
- */
- public function getBaseCalculationPriceOriginal()
- {
- if (!$this->hasBaseCalculationPrice()) {
- if ($this->hasOriginalCustomPrice()) {
- $price = (double)$this->getOriginalCustomPrice();
- if ($price) {
- $rate = $this->priceCurrency->convert($price, $this->getStore()) / $price;
- $price = $price / $rate;
- }
- } else {
- $price = $this->getPrice();
- }
- $this->setBaseCalculationPrice($price);
- }
- return $this->_getData('base_calculation_price');
- }
- /**
- * Get original price (retrieved from product) for item.
- *
- * Original price value is in quote selected currency
- *
- * @return float
- */
- public function getOriginalPrice()
- {
- $price = $this->_getData('original_price');
- if ($price === null) {
- $price = $this->priceCurrency->convert($this->getBaseOriginalPrice(), $this->getStore());
- $this->setData('original_price', $price);
- }
- return $price;
- }
- /**
- * Set original price to item (calculation price will be refreshed too)
- *
- * @param float $price
- * @return \Magento\Quote\Model\Quote\Item\AbstractItem
- */
- public function setOriginalPrice($price)
- {
- return $this->setData('original_price', $price);
- }
- /**
- * Get Original item price (got from product) in base website currency
- *
- * @return float
- */
- public function getBaseOriginalPrice()
- {
- return $this->_getData('base_original_price');
- }
- /**
- * Specify custom item price (used in case when we have apply not product price to item)
- *
- * @param float $value
- * @return \Magento\Quote\Model\Quote\Item\AbstractItem
- */
- public function setCustomPrice($value)
- {
- $this->setCalculationPrice($value);
- $this->setBaseCalculationPrice(null);
- return $this->setData('custom_price', $value);
- }
- /**
- * Get item price. Item price currency is website base currency.
- *
- * @return float
- */
- public function getPrice()
- {
- return $this->_getData('price');
- }
- /**
- * Specify item price (base calculation price and converted price will be refreshed too)
- *
- * @param float $value
- * @return $this
- */
- public function setPrice($value)
- {
- $this->setBaseCalculationPrice(null);
- $this->setConvertedPrice(null);
- return $this->setData('price', $value);
- }
- /**
- * Get item price converted to quote currency
- *
- * @return float
- */
- public function getConvertedPrice()
- {
- $price = $this->_getData('converted_price');
- if ($price === null) {
- $price = $this->priceCurrency->convert($this->getPrice(), $this->getStore());
- $this->setData('converted_price', $price);
- }
- return $price;
- }
- /**
- * Set new value for converted price
- *
- * @param float $value
- * @return $this
- */
- public function setConvertedPrice($value)
- {
- $this->setCalculationPrice(null);
- $this->setData('converted_price', $value);
- return $this;
- }
- /**
- * Clone quote item
- *
- * @return $this
- */
- public function __clone()
- {
- $this->setId(null);
- $this->_parentItem = null;
- $this->_children = [];
- $this->_messages = [];
- return $this;
- }
- /**
- * Checking if there children calculated or parent item when we have parent quote item and its children
- *
- * @return bool
- */
- public function isChildrenCalculated()
- {
- if ($this->getParentItem()) {
- $calculate = $this->getParentItem()->getProduct()->getPriceType();
- } else {
- $calculate = $this->getProduct()->getPriceType();
- }
- if (null !== $calculate &&
- (int)$calculate === \Magento\Catalog\Model\Product\Type\AbstractType::CALCULATE_CHILD
- ) {
- return true;
- }
- return false;
- }
- /**
- * Checking can we ship product separately
- *
- * Checking can we ship product separately (each child separately)
- * or each parent product item can be shipped only like one item
- *
- * @return bool
- */
- public function isShipSeparately()
- {
- if ($this->getParentItem()) {
- $shipmentType = $this->getParentItem()->getProduct()->getShipmentType();
- } else {
- $shipmentType = $this->getProduct()->getShipmentType();
- }
- if (null !== $shipmentType &&
- (int)$shipmentType === \Magento\Catalog\Model\Product\Type\AbstractType::SHIPMENT_SEPARATELY
- ) {
- return true;
- }
- return false;
- }
- /**
- * Returns the total discount amounts of all the child items.
- *
- * If there are no children, returns the discount amount of this item.
- *
- * @return float
- */
- public function getTotalDiscountAmount()
- {
- $totalDiscountAmount = 0;
- /* \Magento\Quote\Model\Quote\Item\AbstractItem[] */
- $children = $this->getChildren();
- if (!empty($children) && $this->isChildrenCalculated()) {
- foreach ($children as $child) {
- $totalDiscountAmount += $child->getDiscountAmount();
- }
- } else {
- $totalDiscountAmount = $this->getDiscountAmount();
- }
- return $totalDiscountAmount;
- }
- }
|