classes/XLite/Model/OrderItem.php line 24

Open in your IDE?
  1. <?php
  2. /**
  3.  * Copyright (c) 2011-present Qualiteam software Ltd. All rights reserved.
  4.  * See https://www.x-cart.com/license-agreement.html for license details.
  5.  */
  6. namespace XLite\Model;
  7. use Doctrine\ORM\Mapping as ORM;
  8. use XLite\Core\Request;
  9. use XLite\Model\OrderItem\Surcharge;
  10. /**
  11.  * Something customer can put into his cart
  12.  *
  13.  * @ORM\Entity
  14.  * @ORM\Table  (name="order_items",
  15.  *          indexes={
  16.  *               @ORM\Index (name="ooo", columns={"order_id","object_type","object_id"}),
  17.  *               @ORM\Index (name="object_id", columns={"object_id"}),
  18.  *               @ORM\Index (name="price", columns={"price"}),
  19.  *               @ORM\Index (name="amount", columns={"amount"})
  20.  *          }
  21.  * )
  22.  *
  23.  * @ORM\InheritanceType       ("SINGLE_TABLE")
  24.  * @ORM\DiscriminatorColumn   (name="object_type", type="string", length=16)
  25.  * @ORM\DiscriminatorMap      ({"product" = "XLite\Model\OrderItem"})
  26.  */
  27. class OrderItem extends \XLite\Model\Base\SurchargeOwner
  28. {
  29.     public const PRODUCT_TYPE 'product';
  30.     /**
  31.      * Primary key
  32.      *
  33.      * @var integer
  34.      *
  35.      * @ORM\Id
  36.      * @ORM\GeneratedValue (strategy="AUTO")
  37.      * @ORM\Column         (type="integer")
  38.      */
  39.     protected $item_id;
  40.     /**
  41.      * Object (product)
  42.      *
  43.      * @var \XLite\Model\Product
  44.      *
  45.      * @ORM\ManyToOne  (targetEntity="XLite\Model\Product", inversedBy="order_items", cascade={"merge","detach"})
  46.      * @ORM\JoinColumn (name="object_id", referencedColumnName="product_id", onDelete="SET NULL")
  47.      */
  48.     protected $object;
  49.     /**
  50.      * Item name
  51.      *
  52.      * @var string
  53.      *
  54.      * @ORM\Column (type="string", length=255)
  55.      */
  56.     protected $name;
  57.     /**
  58.      * Item SKU
  59.      *
  60.      * @var string
  61.      *
  62.      * @ORM\Column (type="string", length=32)
  63.      */
  64.     protected $sku '';
  65.     /**
  66.      * Item price
  67.      *
  68.      * @var float
  69.      *
  70.      * @ORM\Column (type="decimal", precision=14, scale=4)
  71.      */
  72.     protected $price;
  73.     /**
  74.      * Item net price
  75.      *
  76.      * @var float
  77.      *
  78.      * @ORM\Column (type="decimal", precision=14, scale=4)
  79.      */
  80.     protected $itemNetPrice;
  81.     /**
  82.      * Item discounted subtotal
  83.      *
  84.      * @var float
  85.      *
  86.      * @ORM\Column (type="decimal", precision=14, scale=4)
  87.      */
  88.     protected $discountedSubtotal 0;
  89.     /**
  90.      * Item quantity
  91.      *
  92.      * @var integer
  93.      *
  94.      * @ORM\Column (type="integer")
  95.      */
  96.     protected $amount 1;
  97.     /**
  98.      * Item quantity
  99.      *
  100.      * @var integer
  101.      *
  102.      * @ORM\Column (type="integer")
  103.      */
  104.     protected $backorderedAmount 0;
  105.     /**
  106.      * Item order
  107.      *
  108.      * @var \XLite\Model\Order
  109.      *
  110.      * @ORM\ManyToOne  (targetEntity="XLite\Model\Order", inversedBy="items")
  111.      * @ORM\JoinColumn (name="order_id", referencedColumnName="order_id", onDelete="CASCADE")
  112.      */
  113.     protected $order;
  114.     /**
  115.      * Order item surcharges
  116.      *
  117.      * @var \Doctrine\Common\Collections\Collection
  118.      *
  119.      * @ORM\OneToMany (targetEntity="XLite\Model\OrderItem\Surcharge", mappedBy="owner", cascade={"all"})
  120.      * @ORM\OrderBy   ({"weight" = "ASC", "id" = "ASC"})
  121.      */
  122.     protected $surcharges;
  123.     /**
  124.      * Dump product (deleted)
  125.      *
  126.      * @var \XLite\Model\Product
  127.      */
  128.     protected $dumpProduct;
  129.     /**
  130.      * Attribute values
  131.      *
  132.      * @var \Doctrine\Common\Collections\Collection
  133.      *
  134.      * @ORM\OneToMany (targetEntity="XLite\Model\OrderItem\AttributeValue", mappedBy="orderItem", cascade={"all"})
  135.      */
  136.     protected $attributeValues;
  137.     /**
  138.      * Update date (UNIX timestamp)
  139.      *
  140.      * @var integer
  141.      *
  142.      * @ORM\Column (type="integer")
  143.      */
  144.     protected $updateDate 0;
  145.     /**
  146.      * Constructor
  147.      *
  148.      * @param array $data Entity properties OPTIONAL
  149.      */
  150.     public function __construct(array $data = [])
  151.     {
  152.         $this->surcharges = new \Doctrine\Common\Collections\ArrayCollection();
  153.         $this->attributeValues = new \Doctrine\Common\Collections\ArrayCollection();
  154.         parent::__construct($data);
  155.     }
  156.     /**
  157.      * Get name
  158.      *
  159.      * @return string
  160.      */
  161.     public function getName()
  162.     {
  163.         return $this->getObject() ? $this->getObject()->getName() : $this->name;
  164.     }
  165.     /**
  166.      * Set order
  167.      *
  168.      * @param \XLite\Model\Order $order Order OPTIONAL
  169.      */
  170.     public function setOrder(\XLite\Model\Order $order null)
  171.     {
  172.         $this->order $order;
  173.     }
  174.     /**
  175.      * Clone order item object. The product only is set additionally
  176.      * since the order could be different and should be set manually
  177.      *
  178.      * @return \XLite\Model\AEntity
  179.      */
  180.     public function cloneEntity()
  181.     {
  182.         $newItem parent::cloneEntity();
  183.         if ($this->getObject()) {
  184.             $newItem->setObject($this->getObject());
  185.         }
  186.         foreach ($this->getSurcharges() as $surchrg) {
  187.             $cloned $surchrg->cloneEntity();
  188.             $cloned->setOwner($newItem);
  189.             $newItem->addSurcharges($cloned);
  190.         }
  191.         if ($this->hasAttributeValues()) {
  192.             foreach ($this->getAttributeValues() as $av) {
  193.                 $cloned $av->cloneEntity();
  194.                 $cloned->setOrderItem($newItem);
  195.                 $newItem->addAttributeValues($cloned);
  196.             }
  197.         }
  198.         return $newItem;
  199.     }
  200.     /**
  201.      * Get item clear price. This value is used as a base item price for calculation of netPrice
  202.      *
  203.      * @return float
  204.      */
  205.     public function getClearPrice()
  206.     {
  207.         return $this->getProduct()->getClearPrice();
  208.     }
  209.     /**
  210.      * Get net Price
  211.      *
  212.      * @return float
  213.      */
  214.     public function getNetPrice()
  215.     {
  216.         return \XLite\Logic\Price::getInstance()->apply($this'getClearPrice', ['taxable'], 'net');
  217.     }
  218.     /**
  219.      * Get display Price
  220.      *
  221.      * @return float
  222.      */
  223.     public function getDisplayPrice()
  224.     {
  225.         return \XLite\Logic\Price::getInstance()->apply($this'getNetPrice', ['taxable'], 'display');
  226.     }
  227.     /**
  228.      * Get item price
  229.      *
  230.      * @return float
  231.      */
  232.     public function getItemPrice()
  233.     {
  234.         return $this->isOrderOpen() ? $this->getClearPrice() : $this->getPrice();
  235.     }
  236.     /**
  237.      * Get item net price
  238.      *
  239.      * @return float
  240.      */
  241.     public function getItemNetPrice()
  242.     {
  243.         return $this->isOrderOpen() ? $this->getNetPrice() : $this->itemNetPrice;
  244.     }
  245.     /**
  246.      * Return false if order is fixed in the database (i.e. order is placed) and true if order is still used as "cart"
  247.      *
  248.      * @return boolean
  249.      */
  250.     public function isOrderOpen()
  251.     {
  252.         $order $this->getOrder();
  253.         return $order && method_exists($order'hasCartStatus') && $order->hasCartStatus();
  254.     }
  255.     /**
  256.      * Get through exclude surcharges
  257.      *
  258.      * @return array
  259.      */
  260.     public function getThroughExcludeSurcharges()
  261.     {
  262.         $list $this->getOrder()->getItemsExcludeSurcharges();
  263.         foreach ($list as $key => $value) {
  264.             $list[$key] = null;
  265.             foreach ($this->getExcludeSurcharges() as $surcharge) {
  266.                 if ($surcharge->getKey() == $key) {
  267.                     $list[$key] = $surcharge;
  268.                     break;
  269.                 }
  270.             }
  271.         }
  272.         return $list;
  273.     }
  274.     /**
  275.      * Wrapper. If the product was deleted,
  276.      * item will use save product name and SKU
  277.      * TODO - switch to getObject() and remove
  278.      *
  279.      * @return \XLite\Model\Product
  280.      */
  281.     public function getProduct()
  282.     {
  283.         if ($this->isDeleted()) {
  284.             $result $this->getDeletedProduct();
  285.         } else {
  286.             $result $this->getObject();
  287.             $result->setAttrValues($this->getAttributeValuesIds());
  288.         }
  289.         return $result;
  290.     }
  291.     /**
  292.      * Get item product id if it exists
  293.      *
  294.      * @return int|null
  295.      */
  296.     public function getProductId()
  297.     {
  298.         return $this->isDeleted() ? null $this->getObject()->getProductId();
  299.     }
  300.     /**
  301.      * Save some fields from product
  302.      *
  303.      * @param \XLite\Model\Product $product Product to set OPTIONAL
  304.      *
  305.      * @return void
  306.      */
  307.     public function setProduct(\XLite\Model\Product $product null)
  308.     {
  309.         $this->setObject($product);
  310.     }
  311.     /**
  312.      * Set object
  313.      *
  314.      * @param \XLite\Model\Base\IOrderItem $item Order item related object OPTIONAL
  315.      *
  316.      * @return void
  317.      */
  318.     public function setObject(\XLite\Model\Base\IOrderItem $item null)
  319.     {
  320.         $this->object $item;
  321.         if ($item) {
  322.             $this->saveItemState($item);
  323.         } else {
  324.             $this->resetItemState();
  325.         }
  326.     }
  327.     /**
  328.      * Define the warning if amount is less or more than purchase limits
  329.      *
  330.      * @param integer $amount
  331.      *
  332.      * @return string
  333.      */
  334.     public function getAmountWarning($amount)
  335.     {
  336.         $result '';
  337.         if ($this->getObject() === null) {
  338.             return $result;
  339.         }
  340.         $minQuantity $this->getObject()->getMinPurchaseLimit();
  341.         $maxQuantity $this->getObject()->getMaxPurchaseLimit();
  342.         if ($amount $minQuantity) {
  343.             //There's a minimum purchase limit of MinQuantity. The number of units of the product ProductName in cart has been adjusted to reach this limit.
  344.             $result \XLite\Core\Translation::lbl('There is a minimum purchase limit of MinQuantity', [
  345.                 'minQuantity' => $minQuantity,
  346.                 'productName' => $this->getName(),
  347.             ]);
  348.         } elseif ($amount $maxQuantity) {
  349.             $result \XLite\Core\Translation::lbl('There is a maximum purchase limit of MaxQuantity', [
  350.                 'maxQuantity' => $maxQuantity,
  351.                 'productName' => $this->getName(),
  352.             ]);
  353.         }
  354.         return $result;
  355.     }
  356.     /**
  357.      * Modified setter
  358.      *
  359.      * @param integer $amount Value to set
  360.      *
  361.      * @return void
  362.      */
  363.     public function setAmount($amount)
  364.     {
  365.         $correctedAmount $amount;
  366.         if (
  367.             ($amount !== $this->getAmount() && !\XLite::isAdminZone() && !Request::getInstance()->isCLI())
  368.             || !$this->getOrder()
  369.             || $this->isOrderOpen()
  370.         ) {
  371.             $correctedAmount $this->processAmount($amount);
  372.             if ($warningText $this->getAmountWarning($amount)) {
  373.                 \XLite\Core\TopMessage::addWarning($warningText);
  374.             }
  375.         }
  376.         $this->amount $correctedAmount;
  377.     }
  378.     /**
  379.      * Set Backordered Amount
  380.      *
  381.      * @param int $backorderedAmount
  382.      *
  383.      * @return $this
  384.      */
  385.     public function setBackorderedAmount($backorderedAmount)
  386.     {
  387.         $this->backorderedAmount $backorderedAmount;
  388.         return $this;
  389.     }
  390.     /**
  391.      * Process amount value before set
  392.      *
  393.      * @param $amount
  394.      *
  395.      * @return mixed
  396.      */
  397.     public function processAmount($amount)
  398.     {
  399.         if ($this->getObject()) {
  400.             $amount max($amount$this->getObject()->getMinPurchaseLimit());
  401.             $amount min($amount$this->getObject()->getMaxPurchaseLimit());
  402.         }
  403.         return $amount;
  404.     }
  405.     /**
  406.      * Get item weight
  407.      *
  408.      * @return float
  409.      */
  410.     public function getWeight()
  411.     {
  412.         $result $this->getClearWeight();
  413.         foreach ($this->getAttributeValues() as $attributeValue) {
  414.             $av $attributeValue->getAttributeValue();
  415.             if (is_object($av)) {
  416.                 $result += $av->getAbsoluteValue('weight');
  417.             }
  418.         }
  419.         return $result
  420.             $result $this->getAmount()
  421.             : 0;
  422.     }
  423.     /**
  424.      * Get clear weight
  425.      *
  426.      * @return float
  427.      */
  428.     public function getClearWeight()
  429.     {
  430.         return $this->getObject() ? $this->getObject()->getClearWeight() : 0;
  431.     }
  432.     /**
  433.      * Check if item has a image
  434.      *
  435.      * @return boolean
  436.      */
  437.     public function hasImage()
  438.     {
  439.         return $this->getImage() !== null && (bool) $this->getImage()->getId();
  440.     }
  441.     /**
  442.      * Check if item has a wrong amount
  443.      *
  444.      * @return boolean
  445.      */
  446.     public function hasWrongAmount()
  447.     {
  448.       
  449.         return $this->getProduct()->getInventoryEnabled()
  450.             && ($this->getProduct()->getPublicAmount() < $this->getAmount());
  451.     }
  452.     /**
  453.      * Get item image URL
  454.      *
  455.      * @return string
  456.      */
  457.     public function getImageURL()
  458.     {
  459.         return $this->getImage()->getURL();
  460.     }
  461.     /**
  462.      * Get item image relative URL
  463.      *
  464.      * @return string
  465.      */
  466.     public function getImageRelativeURL()
  467.     {
  468.         return \Includes\Utils\FileManager::getRelativePath($this->getImage()->getStoragePath(), LC_DIR_ROOT);
  469.     }
  470.     /**
  471.      * Get item resized image relative URL
  472.      *
  473.      * @return string
  474.      */
  475.     public function getResizedImageURL($width$height)
  476.     {
  477.         $img $this->getImage();
  478.         $img->doResize($width$height);
  479.         return $img->getResizedURL($width$height)[2];
  480.     }
  481.     /**
  482.      * Get item image
  483.      *
  484.      * @return \XLite\Model\Base\Image
  485.      */
  486.     public function getImage()
  487.     {
  488.         return $this->getProduct()->getImage();
  489.     }
  490.     /**
  491.      * Get minicart image width
  492.      *
  493.      * @return string
  494.      */
  495.     public function getMiniCartImageWidth()
  496.     {
  497.         return 60;
  498.     }
  499.     /**
  500.      * Get minicart image height
  501.      *
  502.      * @return string
  503.      */
  504.     public function getMiniCartImageHeight()
  505.     {
  506.         return 60;
  507.     }
  508.     /**
  509.      * Get item description
  510.      *
  511.      * @return string
  512.      */
  513.     public function getDescription()
  514.     {
  515.         return $this->getProduct()->getName() . ' (' $this->getAmount() . ')';
  516.     }
  517.     /**
  518.      * Get extended item description
  519.      *
  520.      * @return string
  521.      */
  522.     public function getExtendedDescription()
  523.     {
  524.         return '';
  525.     }
  526.     /**
  527.      * Get available amount for the product
  528.      *
  529.      * @return integer
  530.      */
  531.     public function getProductAvailableAmount()
  532.     {
  533.         return $this->getProduct()->getInventoryEnabled()
  534.             ? $this->getProduct()->getPublicAmount()
  535.             : $this->getProduct()->getMaxPurchaseLimit();
  536.     }
  537.     /**
  538.      * Get item URL
  539.      *
  540.      * @return string
  541.      */
  542.     public function getURL()
  543.     {
  544.         return $this->getProduct()->getURL();
  545.     }
  546.     /**
  547.      * Flag; is this item needs to be shipped
  548.      *
  549.      * @return boolean
  550.      */
  551.     public function isShippable()
  552.     {
  553.         return !$this->getProduct()->getFreeShipping();
  554.     }
  555.     /**
  556.      * This key is used when checking if item is unique in the cart
  557.      *
  558.      * @return string
  559.      */
  560.     public function getKey()
  561.     {
  562.         $result = static::PRODUCT_TYPE '.' . ($this->getObject() ? $this->getObject()->getId() : null);
  563.         foreach ($this->getAttributeValues() as $attributeValue) {
  564.             $result .= '||'
  565.                 $attributeValue->getActualName()
  566.                 . '::'
  567.                 $attributeValue->getActualValue();
  568.         }
  569.         return $result;
  570.     }
  571.     /**
  572.      * Return attribute values ids
  573.      *
  574.      * @return array
  575.      */
  576.     public function getAttributeValuesIds()
  577.     {
  578.         $result = [];
  579.         foreach ($this->getAttributeValues() as $itemValue) {
  580.             $attributeValue $itemValue->getAttributeValue();
  581.             if ($attributeValue) {
  582.                 if ($attributeValue instanceof \XLite\Model\AttributeValue\AttributeValueText) {
  583.                     $result[$attributeValue->getAttribute()->getId()] = $itemValue->getValue();
  584.                 } else {
  585.                     $result[$attributeValue->getAttribute()->getId()] = $attributeValue->getId();
  586.                 }
  587.             }
  588.         }
  589.         ksort($result);
  590.         return $result;
  591.     }
  592.     /**
  593.      * Get attribute values as plain values
  594.      *
  595.      * @return array
  596.      */
  597.     public function getAttributeValuesPlain()
  598.     {
  599.         $result = [];
  600.         foreach ($this->getAttributeValues() as $attributeValue) {
  601.             $actualAttributeValue $attributeValue->getAttributeValue();
  602.             if ($actualAttributeValue) {
  603.                 if ($actualAttributeValue instanceof \XLite\Model\AttributeValue\AttributeValueText) {
  604.                     $value $attributeValue->getValue();
  605.                 } else {
  606.                     $value $actualAttributeValue->getId();
  607.                 }
  608.                 $result[$actualAttributeValue->getAttribute()->getId()] = $value;
  609.             }
  610.         }
  611.         ksort($result);
  612.         return $result;
  613.     }
  614.     /**
  615.      * Get attribute values string
  616.      *
  617.      * @return string
  618.      */
  619.     public function getAttributeValuesAsString()
  620.     {
  621.         $result = [];
  622.         foreach ($this->getAttributeValues() as $value) {
  623.             $result[] = $value->getValue();
  624.         }
  625.         return $result implode(' / '$result) : '';
  626.     }
  627.     /**
  628.      * Check - item has product attrbiute values or not
  629.      *
  630.      * @return boolean
  631.      */
  632.     public function getAttributeValuesCount()
  633.     {
  634.         return $this->getAttributeValues()->count();
  635.     }
  636.     /**
  637.      * Return attribute values ids
  638.      *
  639.      * @param integer|null $limit Limit length for returned array OPTIONAL
  640.      *
  641.      * @return array
  642.      */
  643.     public function getSortedAttributeValues($limit null)
  644.     {
  645.         $result $this->getAttributeValues()->toArray();
  646.         if ($this->getProduct()) {
  647.              usort($result, [$this'sortAttributeValues']);
  648.         }
  649.         if ($limit !== null) {
  650.             $result array_slice($result0$limit);
  651.         }
  652.         return $result;
  653.     }
  654.     /**
  655.      * Sort attribute values
  656.      *
  657.      * @param array $a Attribute A
  658.      * @param array $b Attribute B
  659.      *
  660.      * @return boolean
  661.      */
  662.     protected function sortAttributeValues($a$b)
  663.     {
  664.         return $a->getAttributeValue()
  665.             && $b->getAttributeValue()
  666.             && $a->getAttributeValue()->getAttribute()
  667.             && $b->getAttributeValue()->getAttribute()
  668.             && $a->getAttributeValue()->getAttribute()->getPosition($this->getProduct()) >= $b->getAttributeValue()->getAttribute()->getPosition($this->getProduct());
  669.     }
  670.     /**
  671.      * Check if item is valid
  672.      *
  673.      * @return boolean
  674.      */
  675.     public function isValid()
  676.     {
  677.         $result $this->getProduct()->getEnabled() && $this->getAmount();
  678.         if ($result && $this->getProduct()->isUpcomingProduct()) {
  679.             $result $this->getProduct()->isAllowedUpcomingProduct();
  680.         }
  681.         if (
  682.             $result
  683.             && (
  684.                 $this->hasAttributeValues()
  685.                 || $this->getProduct()->hasEditableAttributes()
  686.             )
  687.         ) {
  688.             $result array_keys($this->getAttributeValuesIds()) == $this->getProduct()->getEditableAttributesIds();
  689.         }
  690.         return $result;
  691.     }
  692.     /**
  693.      * Check if item is allowed to add to cart
  694.      *
  695.      * @return boolean
  696.      */
  697.     public function isConfigured()
  698.     {
  699.         return true;
  700.     }
  701.     /**
  702.      * Check - can change item's amount or not
  703.      *
  704.      * @return boolean
  705.      */
  706.     public function canChangeAmount()
  707.     {
  708.         $product $this->getProduct();
  709.         return !$product
  710.             || !$product->getInventoryEnabled()
  711.             || $product->getPublicAmount();
  712.     }
  713.     /**
  714.      * Check - item has valid amount or not
  715.      *
  716.      * @return boolean
  717.      */
  718.     public function isValidAmount()
  719.     {
  720.         return $this->checkAmount();
  721.     }
  722.     /**
  723.      * Check if the item is valid to clone through the Re-order functionality
  724.      *
  725.      * @return boolean
  726.      */
  727.     public function isValidToClone()
  728.     {
  729.         $result = !$this->isDeleted() && $this->isValid() && $this->getProduct()->isAvailable();
  730.         if ($result && !$this->isActualAttributes()) {
  731.             $result false;
  732.         }
  733.         return $result;
  734.     }
  735.     /**
  736.      * Return true if order item's attribute values are all up-to-date
  737.      *
  738.      * @return boolean
  739.      */
  740.     public function isActualAttributes()
  741.     {
  742.         $result true;
  743.         if ($this->hasAttributeValues()) {
  744.             foreach ($this->getAttributeValues() as $av) {
  745.                 if (!$av->getAttributeValue()) {
  746.                     $result false;
  747.                     break;
  748.                 }
  749.             }
  750.         } elseif ($this->getObject() && $this->getObject()->hasEditableAttributes()) {
  751.             $result false;
  752.         }
  753.         return $result;
  754.     }
  755.     /**
  756.      * Set price
  757.      *
  758.      * @param float $price Price
  759.      *
  760.      * @return void
  761.      */
  762.     public function setPrice($price)
  763.     {
  764.         $this->price $price;
  765.         if ($this->itemNetPrice === null) {
  766.             $this->setItemNetPrice($price);
  767.         }
  768.     }
  769.     /**
  770.      * Set attrbiute values
  771.      *
  772.      * @param array $attributeValues Attrbiute values (prepared, from request)
  773.      *
  774.      * @return void
  775.      */
  776.     public function setAttributeValues(array $attributeValues)
  777.     {
  778.         foreach ($this->getAttributeValues() as $av) {
  779.             \XLite\Core\Database::getEM()->remove($av);
  780.         }
  781.         $this->getAttributeValues()->clear();
  782.         foreach ($attributeValues as $av) {
  783.             if (is_array($av)) {
  784.                 $value $av['value'];
  785.                 $av $av['attributeValue'];
  786.             } else {
  787.                 $value $av->asString();
  788.             }
  789.             $newValue = new \XLite\Model\OrderItem\AttributeValue();
  790.             $newValue->setName($av->getAttribute()->getName());
  791.             $newValue->setValue($value);
  792.             $newValue->setAttributeId($av->getAttribute()->getId());
  793.             $newValue->setOrderItem($this);
  794.             $this->addAttributeValues($newValue);
  795.             $newValue->setAttributeValue($av);
  796.         }
  797.     }
  798.     /**
  799.      * Check - item has product attrbiute values or not
  800.      *
  801.      * @return boolean
  802.      */
  803.     public function hasAttributeValues()
  804.     {
  805.         return $this->getAttributeValues()->count();
  806.     }
  807.     /**
  808.      * Initial calculate order item
  809.      *
  810.      * @return void
  811.      */
  812.     public function calculate()
  813.     {
  814.         $subtotal $this->calculateNetSubtotal();
  815.         $this->setSubtotal($subtotal);
  816.         $this->setDiscountedSubtotal($subtotal);
  817.         $this->setTotal($subtotal);
  818.     }
  819.     /**
  820.      * Renew order item
  821.      *
  822.      * @return boolean
  823.      */
  824.     public function renew()
  825.     {
  826.         $available true;
  827.         $product $this->getProduct();
  828.         if ($product) {
  829.             if (!$product->getId()) {
  830.                 $available false;
  831.             } else {
  832.                 $this->setPrice($product->getDisplayPrice());
  833.                 $this->setName($product->getName());
  834.                 $this->setSku($product->getSku());
  835.             }
  836.         }
  837.         return $available;
  838.     }
  839.     /**
  840.      * Return true if ordered item is a valid product and is taxable
  841.      *
  842.      * @return boolean
  843.      */
  844.     public function getTaxable()
  845.     {
  846.         $product $this->getProduct();
  847.         return $product $product->getTaxable() : false;
  848.     }
  849.     /**
  850.      * Get item taxable basis
  851.      *
  852.      * @return float
  853.      */
  854.     public function getTaxableBasis()
  855.     {
  856.         $product $this->getProduct();
  857.         return $product $product->getTaxableBasis() : null;
  858.     }
  859.     /**
  860.      * Get product classes
  861.      *
  862.      * @return array
  863.      */
  864.     public function getProductClass()
  865.     {
  866.         $product $this->getProduct();
  867.         return $product $product->getClass() : null;
  868.     }
  869.     /**
  870.      * Get event cell base information
  871.      *
  872.      * @return array
  873.      */
  874.     public function getEventCell()
  875.     {
  876.         return [
  877.             'item_id'     => $this->getItemId(),
  878.             'key'         => $this->getKey(),
  879.             'object_type' => static::PRODUCT_TYPE,
  880.             'object_id'   => $this->getProductId(),
  881.         ];
  882.     }
  883.     /**
  884.      * 'IsDeleted' flag
  885.      *
  886.      * @return boolean
  887.      */
  888.     public function isDeleted()
  889.     {
  890.         return !$this->getObject();
  891.     }
  892.     /**
  893.      * Calculate item total
  894.      *
  895.      * @return float
  896.      */
  897.     public function calculateTotal()
  898.     {
  899.         $total $this->getSubtotal();
  900.         /** @var Surcharge $surcharge */
  901.         foreach ($this->getExcludeSurcharges() as $surcharge) {
  902.             if ($surcharge->getAvailable()) {
  903.                 $total += $surcharge->getValue();
  904.             }
  905.         }
  906.         return $total;
  907.     }
  908.     /**
  909.      * Get total with VAT
  910.      */
  911.     public function getDisplayTotal()
  912.     {
  913.         return $this->getTotal();
  914.     }
  915.     /**
  916.      * Calculate net subtotal
  917.      *
  918.      * @return float
  919.      */
  920.     public function calculateNetSubtotal()
  921.     {
  922.         if ($this->isOrderOpen() || $this->getItemNetPrice() === null) {
  923.             $this->setItemNetPrice($this->defineNetPrice());
  924.         }
  925.         return $this->getItemNetPrice() * $this->getAmount();
  926.     }
  927.     /**
  928.      * Get net subtotal without round net price
  929.      *
  930.      * @return float
  931.      */
  932.     public function getNetSubtotal()
  933.     {
  934.         return $this->calculateNetSubtotal();
  935.     }
  936.     /**
  937.      * Get inventory amount of this item
  938.      *
  939.      * @return int
  940.      */
  941.     public function getInventoryAmount()
  942.     {
  943.         return $this->getProduct()->getAmount()+$this->getProduct()->getquantity1();
  944.     }
  945.     /**
  946.      * Increase / decrease product inventory amount
  947.      *
  948.      * @param integer $delta Amount delta
  949.      *
  950.      * @return void
  951.      */
  952.     public function changeAmount($delta)
  953.     {
  954.         $this->getProduct()->changeAmount($delta);
  955.     }
  956.     /**
  957.      * Check - item price is controlled by server or not
  958.      *
  959.      * @return boolean
  960.      */
  961.     public function isPriceControlledServer()
  962.     {
  963.         return false;
  964.     }
  965.     /**
  966.      * Define net price
  967.      *
  968.      * @return float
  969.      */
  970.     protected function defineNetPrice()
  971.     {
  972.         return $this->getNetPrice();
  973.     }
  974.     /**
  975.      * Get deleted product
  976.      *
  977.      * @return \XLite\Model\Product|void
  978.      */
  979.     protected function getDeletedProduct()
  980.     {
  981.         if ($this->dumpProduct === null) {
  982.             $this->dumpProduct = new \XLite\Model\Product();
  983.             $this->dumpProduct->setPrice($this->getItemPrice());
  984.             $this->dumpProduct->setName($this->getName());
  985.             $this->dumpProduct->setSku($this->getSku());
  986.         }
  987.         return $this->dumpProduct;
  988.     }
  989.     /**
  990.      * Check item amount
  991.      *
  992.      * @return boolean
  993.      */
  994.     protected function checkAmount()
  995.     {
  996.         $result true;
  997.         $product $this->getProduct();
  998.         if ($product && $product->getId()) {
  999.             $result = !$product->getInventoryEnabled()
  1000.                 || $product->getAvailableAmount() >= 0;
  1001.         }
  1002.         return $result;
  1003.     }
  1004.     /**
  1005.      * Save item state
  1006.      *
  1007.      * @param \XLite\Model\Base\IOrderItem $item Item object
  1008.      *
  1009.      * @return void
  1010.      */
  1011.     protected function saveItemState(\XLite\Model\Base\IOrderItem $item)
  1012.     {
  1013.         $price $item->getPrice();
  1014.         $this->setPrice(\Includes\Utils\Converter::formatPrice($price));
  1015.         $this->setName($item->getName());
  1016.         $this->setSku($item->getSku());
  1017.     }
  1018.     /**
  1019.      * Reset item state
  1020.      *
  1021.      * @return void
  1022.      */
  1023.     protected function resetItemState()
  1024.     {
  1025.         $this->price 0;
  1026.         $this->itemNetPrice 0;
  1027.         $this->name '';
  1028.         $this->sku '';
  1029.     }
  1030.     /**
  1031.      * Get item_id
  1032.      *
  1033.      * @return integer
  1034.      */
  1035.     public function getItemId()
  1036.     {
  1037.         return $this->item_id;
  1038.     }
  1039.     /**
  1040.      * Get item_id
  1041.      *
  1042.      * @return integer
  1043.      */
  1044.     public function getId()
  1045.     {
  1046.         return $this->getItemId();
  1047.     }
  1048.     /**
  1049.      * Set name
  1050.      *
  1051.      * @param string $name
  1052.      * @return OrderItem
  1053.      */
  1054.     public function setName($name)
  1055.     {
  1056.         $this->name $name;
  1057.         return $this;
  1058.     }
  1059.     /**
  1060.      * Set sku
  1061.      *
  1062.      * @param string $sku
  1063.      * @return OrderItem
  1064.      */
  1065.     public function setSku($sku)
  1066.     {
  1067.         $this->sku $sku;
  1068.         return $this;
  1069.     }
  1070.     /**
  1071.      * Get sku
  1072.      *
  1073.      * @return string
  1074.      */
  1075.     public function getSku()
  1076.     {
  1077.         return $this->sku;
  1078.     }
  1079.     /**
  1080.      * Get price
  1081.      *
  1082.      * @return float
  1083.      */
  1084.     public function getPrice()
  1085.     {
  1086.         return $this->price;
  1087.     }
  1088.     /**
  1089.      * Set itemNetPrice
  1090.      *
  1091.      * @param float $itemNetPrice
  1092.      * @return OrderItem
  1093.      */
  1094.     public function setItemNetPrice($itemNetPrice)
  1095.     {
  1096.         $this->itemNetPrice $itemNetPrice;
  1097.         return $this;
  1098.     }
  1099.     /**
  1100.      * Set discountedSubtotal
  1101.      *
  1102.      * @param float $discountedSubtotal
  1103.      * @return OrderItem
  1104.      */
  1105.     public function setDiscountedSubtotal($discountedSubtotal)
  1106.     {
  1107.         $this->discountedSubtotal $discountedSubtotal;
  1108.         return $this;
  1109.     }
  1110.     /**
  1111.      * Get discountedSubtotal
  1112.      *
  1113.      * @return float
  1114.      */
  1115.     public function getDiscountedSubtotal()
  1116.     {
  1117.         return $this->discountedSubtotal;
  1118.     }
  1119.     /**
  1120.      * Get amount
  1121.      *
  1122.      * @return integer
  1123.      */
  1124.     public function getAmount()
  1125.     {
  1126.         return $this->amount;
  1127.     }
  1128.     /**
  1129.      * Return BackorderedAmount
  1130.      *
  1131.      * @return int
  1132.      */
  1133.     public function getBackorderedAmount()
  1134.     {
  1135.         return $this->backorderedAmount;
  1136.     }
  1137.     /**
  1138.      * Get total
  1139.      *
  1140.      * @return float
  1141.      */
  1142.     public function getTotal()
  1143.     {
  1144.         return $this->total;
  1145.     }
  1146.     /**
  1147.      * Get subtotal
  1148.      *
  1149.      * @return float
  1150.      */
  1151.     public function getSubtotal()
  1152.     {
  1153.         return $this->subtotal;
  1154.     }
  1155.     /**
  1156.      * Get object
  1157.      *
  1158.      * @return \XLite\Model\Product
  1159.      */
  1160.     public function getObject()
  1161.     {
  1162.         return $this->object;
  1163.     }
  1164.     /**
  1165.      * Get order
  1166.      *
  1167.      * @return \XLite\Model\Order
  1168.      */
  1169.     public function getOrder()
  1170.     {
  1171.         return $this->order;
  1172.     }
  1173.     /**
  1174.      * Add surcharges
  1175.      *
  1176.      * @param \XLite\Model\OrderItem\Surcharge $surcharges
  1177.      * @return OrderItem
  1178.      */
  1179.     public function addSurcharges(\XLite\Model\OrderItem\Surcharge $surcharges)
  1180.     {
  1181.         $this->surcharges[] = $surcharges;
  1182.         return $this;
  1183.     }
  1184.     /**
  1185.      * Get surcharges
  1186.      *
  1187.      * @return \Doctrine\Common\Collections\Collection
  1188.      */
  1189.     public function getSurcharges()
  1190.     {
  1191.         return $this->surcharges;
  1192.     }
  1193.     /**
  1194.      * Add attributeValues
  1195.      *
  1196.      * @param \XLite\Model\OrderItem\AttributeValue $attributeValues
  1197.      * @return OrderItem
  1198.      */
  1199.     public function addAttributeValues(\XLite\Model\OrderItem\AttributeValue $attributeValues)
  1200.     {
  1201.         $this->attributeValues[] = $attributeValues;
  1202.         return $this;
  1203.     }
  1204.     /**
  1205.      * Get attributeValues
  1206.      *
  1207.      * @return \Doctrine\Common\Collections\Collection|\XLite\Model\OrderItem\AttributeValue[]
  1208.      */
  1209.     public function getAttributeValues()
  1210.     {
  1211.         return $this->attributeValues;
  1212.     }
  1213.     /**
  1214.      * Release backorder
  1215.      */
  1216.     public function releaseBackorder()
  1217.     {
  1218.         $this->setBackorderedAmount(0);
  1219.     }
  1220.     /**
  1221.      * @return bool
  1222.      */
  1223.     protected function isBackordered()
  1224.     {
  1225.         return $this->getOrder()
  1226.             && $this->getOrder()->isBackordered()
  1227.             && $this->getBackorderedAmount();
  1228.     }
  1229.     /**
  1230.      * Refresh update date
  1231.      */
  1232.     public function refreshUpdateDate()
  1233.     {
  1234.         $this->updateDate \XLite\Core\Converter::time();
  1235.     }
  1236.     /**
  1237.      * Get update date
  1238.      *
  1239.      * @return integer
  1240.      */
  1241.     public function getUpdateDate()
  1242.     {
  1243.         return $this->updateDate;
  1244.     }
  1245. }