vendor/bluue/sales-bundle/src/Entity/OrderLine.php line 43

Open in your IDE?
  1. <?php
  2. /**
  3.  * @author Quentin CHATELAIN (contact@scaledev.fr)
  4.  * @copyright 2021 - ScaleDEV SAS, 12 RUE CHARLES MORET, 10120 ST ANDRE LES VERGERS
  5.  * @license commercial
  6.  */
  7. declare(strict_types=1);
  8. namespace Bluue\SalesBundle\Entity;
  9. use App\Entity\Traits\EntityManagerServiceEntity;
  10. use DateTime;
  11. use App\Entity\TaxRule;
  12. use Doctrine\ORM\NonUniqueResultException;
  13. use Symfony\Component\Uid\Uuid;
  14. use Doctrine\ORM\Mapping as ORM;
  15. use Gedmo\Mapping\Annotation as Gedmo;
  16. use Doctrine\Common\Collections\Collection;
  17. use Doctrine\Common\Collections\ArrayCollection;
  18. use Bluue\SalesBundle\Repository\OrderLineRepository;
  19. use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
  20. use App\DoctrineExtensions\Cancelable\Traits\UserCancelableEntity;
  21. use App\DoctrineExtensions\Timestampable\Traits\UserTimestampableEntity;
  22. use App\DoctrineExtensions\SoftDeleteable\Traits\UserSoftDeleteableEntity;
  23. use App\Entity\Traits\ConfigurationServiceEntity;
  24. use App\Services\SoftdeleteFilter;
  25. use Bluue\CustomersBundle\Entity\Customer;
  26. use Bluue\ProductsBundle\Entity\Declination;
  27. use Bluue\ProductsBundle\Entity\Product;
  28. /**
  29.  * @ORM\Entity(repositoryClass=OrderLineRepository::class)
  30.  * @ORM\Table(name="sales_bundle__order_line", indexes={
  31.  *  @ORM\Index(name="deleted_at", columns={"deleted_at"}),
  32.  *  @ORM\Index(name="created_at", columns={"created_at"}),
  33.  *  @ORM\Index(name="updated_at", columns={"updated_at"}),
  34.  *  @ORM\Index(name="canceled_at", columns={"canceled_at"})
  35.  * })
  36.  * @Gedmo\SoftDeleteable(fieldName="deletedAt", timeAware=false, hardDelete=true)
  37.  */
  38. class OrderLine
  39. {
  40.     use UserTimestampableEntity;
  41.     use UserSoftDeleteableEntity;
  42.     use UserCancelableEntity;
  43.     use ConfigurationServiceEntity;
  44.     use EntityManagerServiceEntity;
  45.     /**
  46.      * @ORM\Id
  47.      * @ORM\Column(type="uuid")
  48.      * @ORM\GeneratedValue(strategy="CUSTOM")
  49.      * @ORM\CustomIdGenerator(class=UuidGenerator::class)
  50.      */
  51.     private ?Uuid $id null;
  52.     /**
  53.      * @ORM\ManyToOne(targetEntity=Order::class, inversedBy="lines")
  54.      * @ORM\JoinColumn(nullable=false)
  55.      */
  56.     private ?Order $order null;
  57.     /**
  58.      * @ORM\ManyToOne(targetEntity=LineType::class)
  59.      */
  60.     private ?LineType $line_type null;
  61.     /**
  62.      * @ORM\ManyToOne(targetEntity=TaxRule::class)
  63.      */
  64.     private ?TaxRule $tax_rule null;
  65.     /**
  66.      * @ORM\ManyToOne(targetEntity="OrderLine", inversedBy="childrens")
  67.      * @ORM\JoinColumn(name="parent_id", referencedColumnName="id")
  68.      */
  69.     private ?OrderLine $parent null;
  70.     /**
  71.      * @ORM\Column(type="boolean")
  72.      */
  73.     private bool $is_group false;
  74.     /**
  75.      * @ORM\ManyToOne(targetEntity="OrderLine", inversedBy="packChildrens")
  76.      * @ORM\JoinColumn(name="pack_parent_id", referencedColumnName="id")
  77.      */
  78.     private ?OrderLine $packParent null;
  79.     /**
  80.      * @ORM\Column(type="boolean")
  81.      */
  82.     private bool $is_pack false;
  83.     /**
  84.      * @ORM\Column(type="string", length=128, nullable="true")
  85.      */
  86.     private ?string $reference null;
  87.     /**
  88.      * @ORM\Column(type="string", length=128, nullable="true")
  89.      */
  90.     private ?string $referenceBrand null;
  91.     /**
  92.      * @ORM\Column(type="string", length=255, nullable="true")
  93.      */
  94.     private ?string $name null;
  95.     /**
  96.      * @ORM\Column(type="text", nullable="true")
  97.      */
  98.     private ?string $description null;
  99.     /**
  100.      * @ORM\Column(type="decimal", precision=20, scale=6, nullable="true")
  101.      */
  102.     private ?string $unit_price null;
  103.     /**
  104.      * @ORM\Column(type="decimal", precision=20, scale=6, nullable="true")
  105.      */
  106.     private ?string $unitPriceWithTax null;
  107.     /**
  108.      * @ORM\Column(type="decimal", precision=20, scale=6, nullable="true")
  109.      */
  110.     private ?string $quantity null;
  111.     /**
  112.      * @ORM\Column(type="decimal", precision=20, scale=6, nullable="true")
  113.      */
  114.     private ?string $quantity_delivered null;
  115.     /**
  116.      * @ORM\Column(type="decimal", precision=20, scale=6, nullable="true")
  117.      */
  118.     private ?string $wholesale_price null;
  119.     /**
  120.      * @ORM\Column(type="decimal", precision=20, scale=6, nullable="true")
  121.      */
  122.     private ?string $margin_ratio null;
  123.     /**
  124.      * @ORM\Column(type="decimal", precision=20, scale=6, nullable="true")
  125.      */
  126.     private ?string $percentage_discount_untaxed null;
  127.     /**
  128.      * @ORM\Column(type="decimal", precision=20, scale=6, nullable="true")
  129.      */
  130.     private ?string $total_discount_untaxed null;
  131.     /**
  132.      * @ORM\Column(type="decimal", precision=20, scale=6, nullable="true")
  133.      */
  134.     private ?string $totalDiscount null;
  135.     /**
  136.      * @ORM\Column(type="decimal", precision=20, scale=6, nullable="true")
  137.      */
  138.     private ?string $total_amount_no_discount_untaxed null;
  139.     /**
  140.      * @ORM\Column(type="decimal", precision=20, scale=6, nullable="true")
  141.      */
  142.     private ?string $totalAmountNoDiscount null;
  143.     /**
  144.      * @ORM\Column(type="decimal", precision=20, scale=6, nullable="true")
  145.      */
  146.     private ?string $total_amount_untaxed null;
  147.     /**
  148.      * @ORM\Column(type="decimal", precision=20, scale=6, nullable="true")
  149.      */
  150.     private ?string $total_tax_amount null;
  151.     /**
  152.      * @ORM\Column(type="decimal", precision=20, scale=6, nullable="true")
  153.      */
  154.     private ?string $total_amount null;
  155.     /**
  156.      * @ORM\Column(type="integer")
  157.      */
  158.     private ?int $position null;
  159.     /**
  160.      * @ORM\Column(type="json")
  161.      */
  162.     private array $options = [];
  163.     /**
  164.      * @ORM\OneToMany(targetEntity="OrderLine", mappedBy="parent", cascade={"persist", "remove"}, fetch="EXTRA_LAZY")
  165.      * @ORM\OrderBy({"position" = "ASC"})
  166.      */
  167.     private Collection $childrens;
  168.     /**
  169.      * @ORM\OneToMany(
  170.      *      targetEntity="OrderLine",
  171.      *      mappedBy="packParent",
  172.      *      cascade={"persist", "remove"},
  173.      *      fetch="EXTRA_LAZY"
  174.      * )
  175.      * @ORM\OrderBy({"position" = "ASC"})
  176.      */
  177.     private Collection $packChildrens;
  178.     private $stockOrderLine;
  179.     private bool $stockReserved false;
  180.     /**
  181.      * @ORM\ManyToOne(targetEntity=Product::class)
  182.      */
  183.     private ?Product $product null;
  184.     /**
  185.      * @ORM\ManyToOne(targetEntity=Declination::class)
  186.      */
  187.     private ?Declination $declination null;
  188.     public function __construct()
  189.     {
  190.         $this->childrens = new ArrayCollection();
  191.         $this->packChildrens = new ArrayCollection();
  192.     }
  193.     /**
  194.      * @return Uuid|null
  195.      */
  196.     public function getId(): ?Uuid
  197.     {
  198.         return $this->id;
  199.     }
  200.     /**
  201.      * @return OrderLine
  202.      */
  203.     public function setId(): self
  204.     {
  205.         $this->id null;
  206.         return $this;
  207.     }
  208.     /**
  209.      * @return Order|null
  210.      */
  211.     public function getOrder(): ?Order
  212.     {
  213.         return $this->order;
  214.     }
  215.     /**
  216.      * @param Order $order
  217.      * @return OrderLine
  218.      */
  219.     public function setOrder(Order $order): self
  220.     {
  221.         $this->order $order;
  222.         return $this;
  223.     }
  224.     /**
  225.      * @return LineType|null
  226.      */
  227.     public function getLineType(): ?LineType
  228.     {
  229.         return $this->line_type;
  230.     }
  231.     /**
  232.      * @param LineType|null $line_type
  233.      * @return OrderLine
  234.      */
  235.     public function setLineType(?LineType $line_type): self
  236.     {
  237.         $this->line_type $line_type;
  238.         return $this;
  239.     }
  240.     /**
  241.      * @return TaxRule|null
  242.      * @throws NonUniqueResultException
  243.      */
  244.     public function getTaxRule(): ?TaxRule
  245.     {
  246.         if ($this->em && $this->tax_rule) {
  247.             SoftdeleteFilter::disable($this->em, [TaxRule::class]);
  248.             $taxRule $this->em->getRepository(TaxRule::class)
  249.                 ->createQueryBuilder('tr')
  250.                 ->where('tr.id = :taxRuleId')
  251.                 ->setParameter('taxRuleId'$this->tax_rule->getId()->toBinary())
  252.                 ->getQuery()
  253.                 ->getOneOrNullResult();
  254.             SoftdeleteFilter::enable($this->em, [TaxRule::class]);
  255.             return $taxRule;
  256.         }
  257.         return $this->tax_rule;
  258.     }
  259.     /**
  260.      * @param TaxRule|null $tax_rule
  261.      * @return OrderLine
  262.      */
  263.     public function setTaxRule(?TaxRule $tax_rule): self
  264.     {
  265.         $this->tax_rule $tax_rule;
  266.         return $this;
  267.     }
  268.     /**
  269.      * @return OrderLine|null
  270.      */
  271.     public function getParent(): ?OrderLine
  272.     {
  273.         return $this->parent;
  274.     }
  275.     /**
  276.      * @param OrderLine|null $parent
  277.      * @return OrderLine
  278.      */
  279.     public function setParent(?OrderLine $parent): self
  280.     {
  281.         $this->parent $parent;
  282.         return $this;
  283.     }
  284.     /**
  285.      * @return bool
  286.      */
  287.     public function getIsGroup(): bool
  288.     {
  289.         return $this->is_group;
  290.     }
  291.     /**
  292.      * @param bool $is_group
  293.      * @return OrderLine
  294.      */
  295.     public function setIsGroup(bool $is_group): self
  296.     {
  297.         $this->is_group $is_group;
  298.         return $this;
  299.     }
  300.     /**
  301.      * @return OrderLine|null
  302.      */
  303.     public function getPackParent(): ?OrderLine
  304.     {
  305.         return $this->packParent;
  306.     }
  307.     /**
  308.      * @param OrderLine|null $packParent
  309.      * @return OrderLine
  310.      */
  311.     public function setPackParent(?OrderLine $packParent): self
  312.     {
  313.         $this->packParent $packParent;
  314.         return $this;
  315.     }
  316.     /**
  317.      * @return bool
  318.      */
  319.     public function getIsPack(): bool
  320.     {
  321.         return $this->is_pack;
  322.     }
  323.     /**
  324.      * @param bool $is_pack
  325.      * @return OrderLine
  326.      */
  327.     public function setIsPack(bool $is_pack): self
  328.     {
  329.         $this->is_pack $is_pack;
  330.         return $this;
  331.     }
  332.     /**
  333.      * @return string|null
  334.      */
  335.     public function getReference(): ?string
  336.     {
  337.         return $this->reference;
  338.     }
  339.     /**
  340.      * @param string|null $reference
  341.      * @return OrderLine
  342.      */
  343.     public function setReference(?string $reference): self
  344.     {
  345.         $this->reference $reference;
  346.         return $this;
  347.     }
  348.     /**
  349.      * @return string|null
  350.      */
  351.     public function getReferenceBrand(): ?string
  352.     {
  353.         return $this->referenceBrand;
  354.     }
  355.     /**
  356.      * @param string|null $referenceBrand
  357.      * @return OrderLine
  358.      */
  359.     public function setReferenceBrand(?string $referenceBrand): self
  360.     {
  361.         $this->referenceBrand $referenceBrand;
  362.         return $this;
  363.     }
  364.     /**
  365.      * @return string|null
  366.      */
  367.     public function getName(): ?string
  368.     {
  369.         return $this->name;
  370.     }
  371.     /**
  372.      * @param string|null $name
  373.      * @return OrderLine
  374.      */
  375.     public function setName(?string $name): self
  376.     {
  377.         $this->name $name;
  378.         return $this;
  379.     }
  380.     /**
  381.      * @return string|null
  382.      */
  383.     public function getDescription(): ?string
  384.     {
  385.         return $this->description;
  386.     }
  387.     /**
  388.      * @param string|null $description
  389.      * @return OrderLine
  390.      */
  391.     public function setDescription(?string $description): self
  392.     {
  393.         $this->description $description;
  394.         return $this;
  395.     }
  396.     /**
  397.      * @return string|null
  398.      */
  399.     public function getUnitPrice(): ?string
  400.     {
  401.         return $this->unit_price;
  402.     }
  403.     /**
  404.      * @param string|null $unit_price
  405.      * @return OrderLine
  406.      */
  407.     public function setUnitPrice(?string $unit_price): self
  408.     {
  409.         $this->unit_price $unit_price;
  410.         return $this;
  411.     }
  412.     /**
  413.      * @return string|null
  414.      */
  415.     public function getUnitPriceWithTax(): ?string
  416.     {
  417.         return $this->unitPriceWithTax;
  418.     }
  419.     /**
  420.      * @param string|null $unitPriceWithTax
  421.      * @return OrderLine
  422.      */
  423.     public function setUnitPriceWithTax(?string $unitPriceWithTax): OrderLine
  424.     {
  425.         $this->unitPriceWithTax $unitPriceWithTax;
  426.         return $this;
  427.     }
  428.     /**
  429.      * @return string|null
  430.      */
  431.     public function getQuantity(): ?string
  432.     {
  433.         return $this->quantity;
  434.     }
  435.     /**
  436.      * @param string|null $quantity
  437.      * @return OrderLine
  438.      */
  439.     public function setQuantity(?string $quantity): self
  440.     {
  441.         $this->quantity $quantity;
  442.         return $this;
  443.     }
  444.     /**
  445.      * @return string|null
  446.      */
  447.     public function getQuantityDelivered(): ?string
  448.     {
  449.         return $this->quantity_delivered;
  450.     }
  451.     /**
  452.      * @param string|null $quantity_delivered
  453.      * @return OrderLine
  454.      */
  455.     public function setQuantityDelivered(?string $quantity_delivered): self
  456.     {
  457.         $this->quantity_delivered $quantity_delivered;
  458.         return $this;
  459.     }
  460.     /**
  461.      * @param bool $virtual
  462.      * @return string|null
  463.      */
  464.     public function getRemainingQuantity(bool $virtual false): ?string
  465.     {
  466.         if ($this->isCanceled()) {
  467.             return '0';
  468.         }
  469.         $quantity = (int) $this->quantity - (int) $this->quantity_delivered;
  470.         if ($virtual && !empty($this->options['product']['virtual_quantity'])) {
  471.             return (string) ($quantity $this->options['product']['virtual_quantity']);
  472.         } else {
  473.             return (string) $quantity;
  474.         }
  475.     }
  476.     /**
  477.      * @return string|null
  478.      */
  479.     public function getWholesalePrice(): ?string
  480.     {
  481.         return $this->wholesale_price;
  482.     }
  483.     /**
  484.      * @param string|null $wholesale_price
  485.      * @return OrderLine
  486.      */
  487.     public function setWholesalePrice(?string $wholesale_price): self
  488.     {
  489.         $this->wholesale_price $wholesale_price;
  490.         return $this;
  491.     }
  492.     /**
  493.      * @return string|null
  494.      */
  495.     public function getMarginRatio(): ?string
  496.     {
  497.         return $this->margin_ratio;
  498.     }
  499.     /**
  500.      * @param string|null $margin_ratio
  501.      * @return OrderLine
  502.      */
  503.     public function setMarginRatio(?string $margin_ratio): self
  504.     {
  505.         $this->margin_ratio $margin_ratio;
  506.         return $this;
  507.     }
  508.     /**
  509.      * @param bool $calcWithPackaging
  510.      * @return float|null
  511.      */
  512.     public function getTotalMargin(bool $calcWithPackaging false): ?float
  513.     {
  514.         if ($this->wholesale_price === null) {
  515.             return 0;
  516.         }
  517.         if ($calcWithPackaging && !empty($this->options['unitQuantity'])) {
  518.             $quantity = (float) $this->options['unitQuantity'];
  519.         } else {
  520.             $quantity $this->isCanceled() ? (int) $this->quantity_delivered : (int) $this->quantity;
  521.         }
  522.         $sellPrice = (float) $this->total_amount_untaxed;
  523.         if (!empty($this->options['ecoPart']) && !empty($this->options['ecoPart']['amount'])) {
  524.             $sellPrice -= $this->options['ecoPart']['amount']  * $quantity;
  525.         }
  526.         return $sellPrice - (float) $this->wholesale_price $quantity;
  527.     }
  528.     /**
  529.      * @return string|null
  530.      */
  531.     public function getPercentageDiscountUntaxed(): ?string
  532.     {
  533.         return $this->percentage_discount_untaxed;
  534.     }
  535.     /**
  536.      * @param string|null $percentage_discount_untaxed
  537.      * @return OrderLine
  538.      */
  539.     public function setPercentageDiscountUntaxed(?string $percentage_discount_untaxed): self
  540.     {
  541.         $this->percentage_discount_untaxed $percentage_discount_untaxed;
  542.         return $this;
  543.     }
  544.     /**
  545.      * @return string|null
  546.      */
  547.     public function getTotalDiscountUntaxed(): ?string
  548.     {
  549.         return $this->total_discount_untaxed;
  550.     }
  551.     /**
  552.      * @param string|null $total_discount_untaxed
  553.      * @return OrderLine
  554.      */
  555.     public function setTotalDiscountUntaxed(?string $total_discount_untaxed): self
  556.     {
  557.         $this->total_discount_untaxed $total_discount_untaxed;
  558.         return $this;
  559.     }
  560.     /**
  561.      * @return string|null
  562.      */
  563.     public function getTotalDiscount(): ?string
  564.     {
  565.         return $this->totalDiscount;
  566.     }
  567.     /**
  568.      * @param string|null $totalDiscount
  569.      * @return OrderLine
  570.      */
  571.     public function setTotalDiscount(?string $totalDiscount): OrderLine
  572.     {
  573.         $this->totalDiscount $totalDiscount;
  574.         return $this;
  575.     }
  576.     /**
  577.      * @return string|null
  578.      */
  579.     public function getTotalAmountNoDiscountUntaxed(): ?string
  580.     {
  581.         return $this->total_amount_no_discount_untaxed;
  582.     }
  583.     /**
  584.      * @param string|null $total_amount_no_discount_untaxed
  585.      * @return OrderLine
  586.      */
  587.     public function setTotalAmountNoDiscountUntaxed(?string $total_amount_no_discount_untaxed): self
  588.     {
  589.         $this->total_amount_no_discount_untaxed $total_amount_no_discount_untaxed;
  590.         return $this;
  591.     }
  592.     /**
  593.      * @return string|null
  594.      */
  595.     public function getTotalAmountNoDiscount(): ?string
  596.     {
  597.         return $this->totalAmountNoDiscount;
  598.     }
  599.     /**
  600.      * @param string|null $totalAmountNoDiscount
  601.      * @return OrderLine
  602.      */
  603.     public function setTotalAmountNoDiscount(?string $totalAmountNoDiscount): OrderLine
  604.     {
  605.         $this->totalAmountNoDiscount $totalAmountNoDiscount;
  606.         return $this;
  607.     }
  608.     /**
  609.      * @return string|null
  610.      */
  611.     public function getTotalAmountUntaxed(): ?string
  612.     {
  613.         return $this->total_amount_untaxed;
  614.     }
  615.     /**
  616.      * @param string|null $total_amount_untaxed
  617.      * @return OrderLine
  618.      */
  619.     public function setTotalAmountUntaxed(?string $total_amount_untaxed): self
  620.     {
  621.         $this->total_amount_untaxed $total_amount_untaxed;
  622.         return $this;
  623.     }
  624.     /**
  625.      * @return string|null
  626.      */
  627.     public function getTotalTaxAmount(): ?string
  628.     {
  629.         return $this->total_tax_amount;
  630.     }
  631.     /**
  632.      * @param string|null $total_tax_amount
  633.      * @return OrderLine
  634.      */
  635.     public function setTotalTaxAmount(?string $total_tax_amount): self
  636.     {
  637.         $this->total_tax_amount $total_tax_amount;
  638.         return $this;
  639.     }
  640.     /**
  641.      * @return string|null
  642.      */
  643.     public function getTotalAmount(): ?string
  644.     {
  645.         return $this->total_amount;
  646.     }
  647.     /**
  648.      * @param string|null $total_amount
  649.      * @return OrderLine
  650.      */
  651.     public function setTotalAmount(?string $total_amount): self
  652.     {
  653.         $this->total_amount $total_amount;
  654.         return $this;
  655.     }
  656.     /**
  657.      * @return int|null
  658.      */
  659.     public function getPosition(): ?int
  660.     {
  661.         return $this->position;
  662.     }
  663.     /**
  664.      * @param int|null $position
  665.      * @return OrderLine
  666.      */
  667.     public function setPosition(?int $position): self
  668.     {
  669.         $this->position $position;
  670.         return $this;
  671.     }
  672.     /**
  673.      * @return array
  674.      */
  675.     public function getOptions(): array
  676.     {
  677.         return $this->options;
  678.     }
  679.     /**
  680.      * @param array $options
  681.      * @return OrderLine
  682.      */
  683.     public function setOptions(array $options): self
  684.     {
  685.         $this->options $options;
  686.         return $this;
  687.     }
  688.     /**
  689.      * @param array $options
  690.      * @return OrderLine
  691.      */
  692.     public function addOptions(array $options): self
  693.     {
  694.         return $this->setOptions(array_merge($this->options$options));
  695.     }
  696.     /**
  697.      * @return Collection|OrderLine[]
  698.      */
  699.     public function getChildrens(): Collection
  700.     {
  701.         return $this->childrens;
  702.     }
  703.     /**
  704.      * @param OrderLine $line
  705.      * @return OrderLine
  706.      */
  707.     public function addChildren(OrderLine $line): self
  708.     {
  709.         if (!$this->childrens->contains($line)) {
  710.             $this->childrens[] = $line;
  711.             $line->setParent($this);
  712.             if ($line->getOrder() !== $this->getOrder()) {
  713.                 $line->setOrder($this->getOrder());
  714.             }
  715.         }
  716.         return $this;
  717.     }
  718.     /**
  719.      * @return Collection|OrderLine[]
  720.      */
  721.     public function getPackChildrens(): Collection
  722.     {
  723.         return $this->packChildrens;
  724.     }
  725.     /**
  726.      * @param OrderLine $line
  727.      * @return $this
  728.      */
  729.     public function addPackChildren(OrderLine $line): self
  730.     {
  731.         if (!$this->packChildrens->contains($line)) {
  732.             $this->packChildrens[] = $line;
  733.             $line->setPackParent($this);
  734.             if ($line->getOrder() !== $this->getOrder()) {
  735.                 $line->setOrder($this->getOrder());
  736.             }
  737.         }
  738.         return $this;
  739.     }
  740.     /**
  741.      * @return Order|null
  742.      */
  743.     public function getDocument(): ?Order
  744.     {
  745.         return $this->getOrder();
  746.     }
  747.     /**
  748.      * @param Order $order
  749.      * @return OrderLine
  750.      */
  751.     public function duplicate(Order $order): OrderLine
  752.     {
  753.         if ($this->id) {
  754.             $clone = clone $this;
  755.             $clone->setId();
  756.             $clone->setOrder($order);
  757.             $clone->setQuantityDelivered(null);
  758.             $clone->setCreatedAt(new DateTime());
  759.             $clone->setCreatedBy(null);
  760.             $clone->setUpdatedAt(new DateTime());
  761.             $clone->setUpdatedBy(null);
  762.             $clone->childrens = new ArrayCollection();
  763.             foreach ($this->getChildrens() as $children) {
  764.                 $clone_children $children->duplicate($order);
  765.                 $clone->addChildren($clone_children);
  766.                 $children->packChildrens = new ArrayCollection();
  767.                 foreach ($children->getPackChildrens() as $packChildren) {
  768.                     $clone_pack_children $packChildren->duplicate($order);
  769.                     $children->addPackChildren($clone_pack_children);
  770.                 }
  771.             }
  772.             $clone->packChildrens = new ArrayCollection();
  773.             foreach ($this->getPackChildrens() as $packChildren) {
  774.                 $clone_pack_children $packChildren->duplicate($order);
  775.                 $clone->addPackChildren($clone_pack_children);
  776.             }
  777.             return $clone;
  778.         }
  779.         return $this;
  780.     }
  781.     /**
  782.      * @return false|string
  783.      */
  784.     public function getProductOptionUniqueKey()
  785.     {
  786.         if ($this->hasProductLinked()) {
  787.             return $this->options['product']['id']
  788.                 . ($this->hasDeclinationLinked() ? $this->options['product']['declination_id'] : '');
  789.         }
  790.         return false;
  791.     }
  792.     /**
  793.      * @return bool
  794.      */
  795.     public function isProduct(): bool
  796.     {
  797.         $options $this->getOptions();
  798.         return !empty($options['product']) && !empty($options['product']['id']);
  799.     }
  800.     /**
  801.      * @return bool
  802.      */
  803.     public function isDeclination(): bool
  804.     {
  805.         return $this->isProduct() && !empty($this->getOptions()['product']['declination_id']);
  806.     }
  807.     /**
  808.      * @return bool
  809.      */
  810.     public function hasProductLinked(): bool
  811.     {
  812.         if (!empty($this->options['product']) && !empty($this->options['product']['id'])) {
  813.             return true;
  814.         }
  815.         return false;
  816.     }
  817.     /**
  818.      * @return bool
  819.      */
  820.     public function hasDeclinationLinked(): bool
  821.     {
  822.         if (!empty($this->options['product']) && !empty($this->options['product']['declination_id'])) {
  823.             return true;
  824.         }
  825.         return false;
  826.     }
  827.     /**
  828.      * @return mixed|null
  829.      */
  830.     public function getProductId()
  831.     {
  832.         if ($this->hasProductLinked()) {
  833.             return $this->options['product']['id'];
  834.         } else {
  835.             return null;
  836.         }
  837.     }
  838.     /**
  839.      * @return mixed|null
  840.      */
  841.     public function getDeclinationId()
  842.     {
  843.         if ($this->hasDeclinationLinked()) {
  844.             return $this->options['product']['declination_id'];
  845.         } else {
  846.             return null;
  847.         }
  848.     }
  849.     /**
  850.      * @return mixed|null
  851.      */
  852.     public function getElementId()
  853.     {
  854.         if ($this->hasDeclinationLinked()) {
  855.             return $this->options['product']['declination_id'];
  856.         } elseif ($this->hasProductLinked()) {
  857.             return $this->options['product']['id'];
  858.         } else {
  859.             return null;
  860.         }
  861.     }
  862.     /**
  863.      * @return mixed
  864.      */
  865.     public function getStockOrderLine()
  866.     {
  867.         return $this->stockOrderLine;
  868.     }
  869.     public function setStockOrderLine($stockOrderLine): self
  870.     {
  871.         $this->stockOrderLine $stockOrderLine;
  872.         return $this;
  873.     }
  874.     /**
  875.      * @return bool
  876.      */
  877.     public function isStockReserved(): bool
  878.     {
  879.         return $this->stockReserved;
  880.     }
  881.     /**
  882.      * @param bool $stockReserved
  883.      * @return OrderLine
  884.      */
  885.     public function setStockReserved(bool $stockReserved): OrderLine
  886.     {
  887.         $this->stockReserved $stockReserved;
  888.         return $this;
  889.     }
  890.     /**
  891.      * @return bool
  892.      */
  893.     public function isCancelable(): bool
  894.     {
  895.         return $this->getRemainingQuantity() > && !$this->isCanceled();
  896.     }
  897.     /**
  898.      * @return string|null
  899.      */
  900.     public function getUnitPriceWithDiscount(): ?string
  901.     {
  902.         if ($this->getDocument()->isEditPricesWithTax()) {
  903.             $unitDiscount = (float) ($this->getOptions()['unitDiscount'] ?? 0);
  904.             return (string) ((float) $this->getUnitPriceWithTax() - $unitDiscount);
  905.         } else {
  906.             $unitDiscountUntaxed = (float) ($this->getOptions()['unitDiscountUntaxed'] ?? 0);
  907.             if ($unitDiscountUntaxed == && $percentageDiscount $this->getPercentageDiscountUntaxed()) {
  908.                 $unitDiscountUntaxed $this->getUnitPrice() * (float) $percentageDiscount 100;
  909.             }
  910.             return (string) ((float) $this->getUnitPrice() - $unitDiscountUntaxed);
  911.         }
  912.     }
  913.     /**
  914.      * @return Product|null
  915.      * @throws NonUniqueResultException
  916.      */
  917.     public function getProduct(): ?Product
  918.     {
  919.         if ($this->em && $this->product) {
  920.             SoftdeleteFilter::disable($this->em, [Product::class]);
  921.             $product $this->em->getRepository(Product::class)
  922.                 ->createQueryBuilder('p')
  923.                 ->where('p.id = :productId')
  924.                 ->setParameter('productId'$this->product->getId()->toBinary())
  925.                 ->getQuery()
  926.                 ->getOneOrNullResult();
  927.             SoftdeleteFilter::enable($this->em, [Product::class]);
  928.             return $product;
  929.         }
  930.         return $this->product;
  931.     }
  932.     /**
  933.      * @param Product|null $Product
  934.      * @return $this
  935.      */
  936.     public function setProduct(?Product $Product): self
  937.     {
  938.         $this->product $Product;
  939.         return $this;
  940.     }
  941.     /**
  942.      * @return Declination|null
  943.      * @throws NonUniqueResultException
  944.      */
  945.     public function getDeclination(): ?Declination
  946.     {
  947.         if ($this->em && $this->declination) {
  948.             SoftdeleteFilter::disable($this->em, [Declination::class]);
  949.             $declination $this->em->getRepository(Declination::class)
  950.                 ->createQueryBuilder('d')
  951.                 ->where('d.id = :declinationId')
  952.                 ->setParameter('declinationId'$this->declination->getId()->toBinary())
  953.                 ->getQuery()
  954.                 ->getOneOrNullResult();
  955.             SoftdeleteFilter::enable($this->em, [Declination::class]);
  956.             return $declination;
  957.         }
  958.         return $this->declination;
  959.     }
  960.     /**
  961.      * @param Declination|null $declination
  962.      * @return $this
  963.      */
  964.     public function setDeclination(?Declination $declination): self
  965.     {
  966.         $this->declination $declination;
  967.         return $this;
  968.     }
  969. }