src/Entity/Produit.php line 16

Open in your IDE?
  1. <?php
  2. namespace App\Entity;
  3. use App\Repository\ProduitRepository;
  4. use Doctrine\Common\Collections\ArrayCollection;
  5. use Doctrine\Common\Collections\Collection;
  6. use Doctrine\ORM\Mapping as ORM;
  7. use JsonSerializable;
  8. use Symfony\Component\Serializer\Annotation\Groups;
  9. use App\Entity\ProduitPromotionHistory;
  10. /**
  11.  * @ORM\Entity(repositoryClass=ProduitRepository::class)
  12.  */
  13. class Produit implements JsonSerializable
  14. {
  15.     /**
  16.      * @ORM\Id
  17.      * @ORM\GeneratedValue
  18.      * @ORM\Column(type="integer")
  19.      */
  20.     private $id;
  21.     private $isNew false;
  22.     private $stock 0;
  23.     /**
  24.      * @ORM\Column(type="string", length=255)
  25.      */
  26.     private $reference;
  27.     /**
  28.      * @ORM\Column(type="string", length=100, nullable=true)
  29.      */
  30.     private $barcode;
  31.     /**
  32.      * @ORM\Column(type="string", length=60)
  33.      */
  34.     private $name;
  35.     /**
  36.      *
  37.      * @ORM\Column(type="text", nullable=true)
  38.      */
  39.     private $description;
  40.     /**
  41.      * @ORM\Column(type="integer")
  42.      */
  43.     private $usual_quantity;
  44.     /**
  45.      * @ORM\Column(name="buying_price_ht", type="float", options={"comment":"Prix d'achat HT (référence marge)"})
  46.      */
  47.     private float $buyingPriceHt 0.0;
  48.     /**
  49.      * @ORM\Column(name="buying_price_ttc", type="float", options={"comment":"Prix d'achat TTC (héritage)"})
  50.      */
  51.     private float $buyingPriceTtc 0.0;
  52.     /**
  53.      * @ORM\Column(name="real_unit_value", type="float", nullable=true, options={"comment":"Valeur reelle unitaire pour la valorisation stock"})
  54.      */
  55.     private ?float $realUnitValue null;
  56.     public function getBuyingPriceTtc(): ?float
  57.     {
  58.         return $this->buyingPriceTtc;
  59.     }
  60.     public function setBuyingPriceTtc(float $buyingPriceTtc): self
  61.     {
  62.         $this->buyingPriceTtc round($buyingPriceTtc3);
  63.         if ($this->realUnitValue === null) {
  64.             $this->realUnitValue round($this->buyingPriceTtc3);
  65.         }
  66.         return $this;
  67.     }
  68.     /**
  69.      *
  70.      * @ORM\Column(type="float")
  71.      */
  72.     private float $price_ht 0.0;
  73.     /**
  74.      *
  75.      * @ORM\Column(type="float")
  76.      */
  77.     private float $price_ttc 0.0;
  78.     /**
  79.      * @ORM\Column(type="float", nullable=true, options={"comment":"Prix TTC reserve aux revendeurs"})
  80.      */
  81.     private ?float $resellerPriceTtc null;
  82.     /**
  83.      * @ORM\ManyToOne(targetEntity=Category::class, inversedBy="produits")
  84.      */
  85.     private $categories;
  86.     /**
  87.      * @ORM\ManyToOne(targetEntity=Tva::class, inversedBy="produits")
  88.      */
  89.     private $tva;
  90.      /**
  91.      * @ORM\ManyToOne(targetEntity=Tva::class) @ORM\JoinColumn(name="buy_tva_id", referencedColumnName="id", nullable=true, onDelete="SET NULL")
  92.      */
  93.     private ?Tva $tvaBuy null;
  94.     /**
  95.      * @ORM\ManyToMany(targetEntity=Tag::class, inversedBy="produits")
  96.      */
  97.     private $tags;
  98.     /**
  99.      * @ORM\Column(type="string", length=255)
  100.      */
  101.     private $unit;
  102.     /**
  103.      * @ORM\Column(type="boolean")
  104.      */
  105.     private $isStock;
  106.     /**
  107.      * @ORM\Column(type="boolean")
  108.      */
  109.     private $isDeclination;
  110.     /**
  111.      * @ORM\Column(type="datetime")
  112.      */
  113.     private $createdAt;
  114.     /**
  115.      * @ORM\ManyToMany(targetEntity=Declination::class, mappedBy="Produits")
  116.      */
  117.     private $declinations;
  118.     /**
  119.      * @ORM\OneToMany(targetEntity=ProduitDeclinationValue::class, mappedBy="produit", orphanRemoval=true)
  120.      */
  121.     private $produitDeclinationValues;
  122.     /**
  123.      *
  124.      * @ORM\ManyToMany(targetEntity=File::class, cascade={"persist"})
  125.      */
  126.     private $picture;
  127.     public $image;
  128.     /**
  129.      * @ORM\OneToMany(targetEntity=DocumentProduit::class, mappedBy="produit")
  130.      */
  131.     private $documentProduits;
  132.     /**
  133.      * @ORM\OneToMany(targetEntity=Stock::class, mappedBy="produit")
  134.      */
  135.     private $stocks;
  136.     /**
  137.      * @ORM\Column(type="integer", nullable=true)
  138.      */
  139.     private $uuid;
  140.     /**
  141.      * @ORM\ManyToOne(targetEntity=Promotion::class, inversedBy="produits")
  142.      */
  143.     private $promotion;
  144.     /**
  145.      * @ORM\OneToMany(targetEntity=Activity::class, mappedBy="produit")
  146.      */
  147.     private $activities;
  148.     /**
  149.      * @ORM\Column(type="text", nullable=true)
  150.      */
  151.     private $information;
  152.     /**
  153.      * @ORM\Column(type="boolean", options={"default": false})
  154.      */
  155.     private bool $isArchived false;
  156.     /**
  157.      * @ORM\OneToMany(targetEntity=Comment::class, mappedBy="produit")
  158.      */
  159.     private $comments;
  160. //    /**
  161. //     * @ORM\ManyToOne(targetEntity=Category::class, inversedBy="produitsCategory")
  162. //     */
  163. //    private $principalCategory;
  164.     /**
  165.      * @ORM\Column(type="datetime", nullable=true)
  166.      */
  167.     private $deletedAt;
  168.     /**
  169.      * @ORM\Column(type="text", nullable=true)
  170.      */
  171.     private $reasonOfDelete;
  172.     /**
  173.      * @ORM\ManyToMany(targetEntity=User::class, inversedBy="produits")
  174.      * @ORM\JoinTable(name="supplier_produit",
  175.      *      joinColumns={@ORM\JoinColumn(name="produit_id", referencedColumnName="id")},
  176.      *      inverseJoinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")}
  177.      * )
  178.      */
  179.     private $users;
  180.     /**
  181.      * @ORM\Column(type="boolean", nullable=true)
  182.      */
  183.     private $bestSelection;
  184.     /**
  185.      * @ORM\Column(type="float", nullable=true, options={"default": 0})
  186.      */
  187.     private ?float $ratingScore 0.0;
  188.     /**
  189.      * @ORM\Column(type="integer", nullable=true, options={"default": 0})
  190.      */
  191.     private ?int $ratingCount 0;
  192.     /**
  193.      * @ORM\Column(type="string", length=255, nullable=true)
  194.      */
  195.     private ?string $material null;
  196.     /**
  197.      * @ORM\ManyToOne(targetEntity=Supplier::class)
  198.      * @ORM\JoinColumn(name="supplier_id", referencedColumnName="id", nullable=true)
  199.      */
  200.     private $supplier;
  201.     /**
  202.      * @ORM\Column(name="supplier_reference", type="string", length=100, nullable=true)
  203.      */
  204.     private $supplierReference;
  205.     /**
  206.      * @ORM\Column(type="string", length=255, nullable=true)
  207.      */
  208.     private ?string $metaDescription null;
  209.     /**
  210.      * @ORM\Column(name="video_url", type="string", length=255, nullable=true)
  211.      */
  212.     private ?string $videoUrl null;
  213.     /**
  214.      * @ORM\OneToMany(targetEntity=ProduitExternalLink::class, mappedBy="produit", orphanRemoval=true, cascade={"persist"})
  215.      * @ORM\OrderBy({"position"="ASC", "id"="ASC"})
  216.      */
  217.     private $externalVideoLinks;
  218.     /**
  219.      * @ORM\Column(type="boolean", options={"default" : true})
  220.      */
  221.     private $showInWebSite;
  222.     /**
  223.      * @ORM\Column(type="boolean", options={"default": false})
  224.      */
  225.     private bool $showInPosDefault false;
  226.     /**
  227.      * {# #} Indique si le produit peut être réassorti
  228.      * @ORM\Column(type="boolean", options={"default": true})
  229.      */
  230.     private bool $canBeRestocked false;
  231.     /** @ORM\OneToMany(
  232.      *   targetEntity=ProduitPromotionHistory::class,
  233.      *   mappedBy="product",
  234.      *   orphanRemoval=true
  235.      * )
  236.      * @ORM\OrderBy({"startedAt":"DESC"})
  237.      */
  238.     private Collection $promotionHistories;
  239.     public function __construct()
  240.     {
  241.         $this->tags = new ArrayCollection();
  242.         $this->declinations = new ArrayCollection();
  243.         $this->produitDeclinationValues = new ArrayCollection();
  244.         $this->picture = new ArrayCollection();
  245.         $this->documentProduits = new ArrayCollection();
  246.         $this->stocks = new ArrayCollection();
  247.         $this->activities = new ArrayCollection();
  248.         $this->comments = new ArrayCollection();
  249.         $this->users = new ArrayCollection();
  250.         $this->promotionHistories = new ArrayCollection();
  251.         $this->externalVideoLinks = new ArrayCollection();
  252.         $this->createdAt = new \DateTime();
  253.     }
  254.     public function getImage(): ?string
  255.     {
  256.         return $this->image;
  257.     }
  258.     public function setImage(?string $image): self
  259.     {
  260.         $this->image $image;
  261.         return $this;
  262.     }
  263.     public function getId(): ?int
  264.     {
  265.         return $this->id;
  266.     }
  267.     public function getReference(): ?string
  268.     {
  269.         return $this->reference;
  270.     }
  271.     public function setReference(string $reference): self
  272.     {
  273.         $this->reference $reference;
  274.         return $this;
  275.     }
  276.     public function getBarcode(): ?string
  277.     {
  278.         return $this->barcode;
  279.     }
  280.     public function setBarcode(?string $barcode): self
  281.     {
  282.         $this->barcode $barcode;
  283.         return $this;
  284.     }
  285.     public function getName(): ?string
  286.     {
  287.         return $this->name;
  288.     }
  289.     public function setName(string $name): self
  290.     {
  291.         $this->name $name;
  292.         return $this;
  293.     }
  294.     public function getDescription(): ?string
  295.     {
  296.         return $this->description;
  297.     }
  298.     public function setDescription(?string $description): self
  299.     {
  300.         $this->description $description;
  301.         return $this;
  302.     }
  303.     public function getUsualQuantity(): ?int
  304.     {
  305.         return $this->usual_quantity;
  306.     }
  307.     public function setUsualQuantity(int $usual_quantity): self
  308.     {
  309.         $this->usual_quantity $usual_quantity;
  310.         return $this;
  311.     }
  312.     public function getBuyingPriceHt(): ?float
  313.     {
  314.         return $this->buyingPriceHt;
  315.     }
  316.     public function setBuyingPriceHt(float $buyingPriceHt): self
  317.     {
  318.         $this->buyingPriceHt round($buyingPriceHt3);
  319.         return $this;
  320.     }
  321.     public function getRealUnitValue(): ?float
  322.     {
  323.         return $this->realUnitValue;
  324.     }
  325.     public function setRealUnitValue(?float $realUnitValue): self
  326.     {
  327.         $this->realUnitValue $realUnitValue !== null round($realUnitValue3) : null;
  328.         return $this;
  329.     }
  330.     public function getPriceHt(): ?float
  331.     {
  332.         return (float) $this->price_ht;
  333.     }
  334.     public function setPriceHt(float $price_ht): self
  335.     {
  336.         $this->price_ht round($price_ht3);
  337.         return $this;
  338.     }
  339.     public function getPriceTtc(): ?float
  340.     {
  341.         return $this->price_ttc;
  342.     }
  343.     public function setPriceTtc(float $price_ttc): self
  344.     {
  345.         $this->price_ttc round($price_ttc3);
  346.         return $this;
  347.     }
  348.     public function getResellerPriceTtc(): ?float
  349.     {
  350.         return $this->resellerPriceTtc;
  351.     }
  352.     public function setResellerPriceTtc(?float $resellerPriceTtc): self
  353.     {
  354.         $this->resellerPriceTtc $resellerPriceTtc !== null round($resellerPriceTtc3) : null;
  355.         return $this;
  356.     }
  357.     public function getTvaBuy(): ?Tva
  358.     {
  359.         return $this->tvaBuy;
  360.     }
  361.     public function setTvaBuy(?Tva $tva): self
  362.     {
  363.          $this->tvaBuy $tva; return $this;
  364.     }
  365.      public function getTva(): ?Tva
  366.     {
  367.         return $this->tva;
  368.     }
  369.     public function setTva(?Tva $tva): self
  370.     {
  371.         $this->tva $tva;
  372.         return $this;
  373.     }
  374.     /** @ORM\PrePersist @ORM\PreUpdate */
  375.     public function ensureBuyingCost(): void {
  376.         if ($this->buyingPriceHt === null || $this->buyingPriceHt === '') {
  377.             $rate $this->tvaBuy? (float)$this->tvaBuy->getNumber() : 0.0;
  378.             $ttc  = (float)$this->buyingPriceTtc;
  379.             $this->buyingPriceHt number_format($ttc/(1+$rate/100), 3'.''');
  380.         }
  381.     }
  382.     public function getCategories(): ?Category
  383.     {
  384.         return $this->categories;
  385.     }
  386.     public function setCategories(?Category $categories): self
  387.     {
  388.         $this->categories $categories;
  389.         return $this;
  390.     }
  391.     public function getSupplier(): ?Supplier
  392.     {
  393.         return $this->supplier;
  394.     }
  395.     public function setSupplier(?Supplier $supplier): self
  396.     {
  397.         $this->supplier $supplier;
  398.         return $this;
  399.     }
  400.     /**
  401.      * @return Collection|Tag[]
  402.      */
  403.     public function getTags(): Collection
  404.     {
  405.         return $this->tags;
  406.     }
  407.     public function addTag(Tag $tag): self
  408.     {
  409.         if( !$this->tags->contains($tag)) {
  410.             $this->tags[] = $tag;
  411.         }
  412.         return $this;
  413.     }
  414.     public function removeTag(Tag $tag): self
  415.     {
  416.         $this->tags->removeElement($tag);
  417.         return $this;
  418.     }
  419.     public function getUnit(): ?string
  420.     {
  421.         return $this->unit;
  422.     }
  423.     public function setUnit(string $unit): self
  424.     {
  425.         $this->unit $unit;
  426.         return $this;
  427.     }
  428.     public function getIsStock(): ?bool
  429.     {
  430.         return $this->isStock;
  431.     }
  432.     public function setIsStock(bool $isStock): self
  433.     {
  434.         $this->isStock $isStock;
  435.         return $this;
  436.     }
  437.     public function getIsDeclination(): ?bool
  438.     {
  439.         return $this->isDeclination;
  440.     }
  441.     public function setIsDeclination(bool $isDeclination): self
  442.     {
  443.         $this->isDeclination $isDeclination;
  444.         return $this;
  445.     }
  446.     public function getCreatedAt(): ?\DateTimeInterface
  447.     {
  448.         return $this->createdAt;
  449.     }
  450.     public function setCreatedAt(\DateTimeInterface $createdAt): self
  451.     {
  452.         $this->createdAt $createdAt;
  453.         return $this;
  454.     }
  455.     /**
  456.      * @return Collection|Declination[]
  457.      */
  458.     public function getDeclinations(): Collection
  459.     {
  460.         return $this->declinations;
  461.     }
  462.     public function addDeclination(Declination $declination): self
  463.     {
  464.         if( !$this->declinations->contains($declination)) {
  465.             $this->declinations[] = $declination;
  466.             $declination->addProduit($this);
  467.         }
  468.         return $this;
  469.     }
  470.     public function removeDeclination(Declination $declination): self
  471.     {
  472.         if( $this->declinations->removeElement($declination)) {
  473.             $declination->removeProduit($this);
  474.         }
  475.         return $this;
  476.     }
  477.     /**
  478.      * @return Collection|ProduitDeclinationValue[]
  479.      */
  480.     public function getProduitDeclinationValues(): Collection
  481.     {
  482.         return $this->produitDeclinationValues;
  483.     }
  484.     public function addProduitDeclinationValue(ProduitDeclinationValue $produitDeclinationValue): self
  485.     {
  486.         if( !$this->produitDeclinationValues->contains($produitDeclinationValue)) {
  487.             $this->produitDeclinationValues[] = $produitDeclinationValue;
  488.             $produitDeclinationValue->setProduit($this);
  489.         }
  490.         return $this;
  491.     }
  492.     public function removeProduitDeclinationValue(ProduitDeclinationValue $produitDeclinationValue): self
  493.     {
  494.         if( $this->produitDeclinationValues->removeElement($produitDeclinationValue)) {
  495.             // set the owning side to null (unless already changed)
  496.             if( $produitDeclinationValue->getProduit() === $this) {
  497.                 $produitDeclinationValue->setProduit(null);
  498.             }
  499.         }
  500.         return $this;
  501.     }
  502.     /**
  503.      * @return Collection|File[]
  504.      */
  505.     public function getPicture(): Collection
  506.     {
  507.         return $this->picture;
  508.     }
  509.     public function addPicture(File $picture): self
  510.     {
  511.         if( !$this->picture->contains($picture))
  512.             $this->picture[] = $picture;
  513.         return $this;
  514.     }
  515.     public function removePicture(File $picture): self
  516.     {
  517.         $this->picture->removeElement($picture);
  518.         return $this;
  519.     }
  520.     /**
  521.      * @return Collection|DocumentProduit[]
  522.      */
  523.     public function getDocumentProduits(): Collection
  524.     {
  525.         return $this->documentProduits;
  526.     }
  527.     public function addDocumentProduit(DocumentProduit $documentProduit): self
  528.     {
  529.         if( !$this->documentProduits->contains($documentProduit)) {
  530.             $this->documentProduits[] = $documentProduit;
  531.             $documentProduit->setProduit($this);
  532.         }
  533.         return $this;
  534.     }
  535.     public function removeDocumentProduit(DocumentProduit $documentProduit): self
  536.     {
  537.         if( $this->documentProduits->removeElement($documentProduit))
  538.             // set the owning side to null (unless already changed)
  539.             if( $documentProduit->getProduit() === $this)
  540.                 $documentProduit->setProduit(null);
  541.         return $this;
  542.     }
  543.     /**
  544.      * @return Collection|Stock[]
  545.      */
  546.     public function getStocks(): Collection
  547.     {
  548.         return $this->stocks;
  549.     }
  550.     public function addStock(Stock $stock): self
  551.     {
  552.         if( !$this->stocks->contains($stock)) {
  553.             $this->stocks[] = $stock;
  554.             $stock->setProduit($this);
  555.         }
  556.         return $this;
  557.     }
  558.     public function removeStock(Stock $stock): self
  559.     {
  560.         if( $this->stocks->removeElement($stock))
  561.             // set the owning side to null (unless already changed)
  562.             if( $stock->getProduit() === $this)
  563.                 $stock->setProduit(null);
  564.         return $this;
  565.     }
  566.     public function getUuid(): ?int
  567.     {
  568.         return $this->uuid;
  569.     }
  570.     public function setUuid(?int $uuid): self
  571.     {
  572.         $this->uuid $uuid;
  573.         return $this;
  574.     }
  575.     public function getPromotion(): ?Promotion
  576.     {
  577.         return $this->promotion;
  578.     }
  579.     public function setPromotion(?Promotion $promotion): self
  580.     {
  581.         $this->promotion $promotion;
  582.         return $this;
  583.     }
  584.     /**
  585.      * @return Collection|Activity[]
  586.      */
  587.     public function getActivities(): Collection
  588.     {
  589.         return $this->activities;
  590.     }
  591.     public function addActivity(Activity $activity): self
  592.     {
  593.         if( !$this->activities->contains($activity)) {
  594.             $this->activities[] = $activity;
  595.             $activity->setProduit($this);
  596.         }
  597.         return $this;
  598.     }
  599.     public function removeActivity(Activity $activity): self
  600.     {
  601.         if( $this->activities->removeElement($activity))
  602.             // set the owning side to null (unless already changed)
  603.             if( $activity->getProduit() === $this)
  604.                 $activity->setProduit(null);
  605.         return $this;
  606.     }
  607.     public function getInformation(): ?string
  608.     {
  609.         return $this->information;
  610.     }
  611.     public function setInformation(?string $information): self
  612.     {
  613.         $this->information $information;
  614.         return $this;
  615.     }
  616.     public function getIsArchived(): ?bool
  617.     {
  618.         return $this->isArchived;
  619.     }
  620.     public function setIsArchived(?bool $isArchived): self
  621.     {
  622.         $this->isArchived $isArchived;
  623.         return $this;
  624.     }
  625.     public function isArchived(): bool
  626.     {
  627.         return $this->deletedAt !== null;
  628.     }
  629.     /**
  630.      * @return Collection|Comment[]
  631.      */
  632.     public function getComments(): Collection
  633.     {
  634.         return $this->comments;
  635.     }
  636.     public function addComment(Comment $comment): self
  637.     {
  638.         if( !$this->comments->contains($comment)) {
  639.             $this->comments[] = $comment;
  640.             $comment->setProduit($this);
  641.         }
  642.         return $this;
  643.     }
  644.     public function removeComment(Comment $comment): self
  645.     {
  646.         if( $this->comments->removeElement($comment))
  647.             // set the owning side to null (unless already changed)
  648.             if( $comment->getProduit() === $this)
  649.                 $comment->setProduit(null);
  650.         return $this;
  651.     }
  652.     public function getIsNew(): ?bool
  653.     {
  654.         return $this->isNew;
  655.     }
  656.     public function setIsNew(bool $isNew): self
  657.     {
  658.         $this->isNew $isNew;
  659.         return $this;
  660.     }
  661.     public function getStock(): ?int
  662.     {
  663.         foreach ($this->getStocks() as $stock) {
  664.             $this->stock += $stock->getQtStock() - $stock->getQtReserved();
  665.         }
  666.         return $this->stock;
  667.     }
  668.     public function getIncomingQuantity(): int
  669.     {
  670.         $qty 0;
  671.         foreach ($this->getStocks() as $stock) {
  672.             $qty += (int) $stock->getIncomingQuantity();
  673.         }
  674.         return $qty;
  675.     }
  676.     public function getIncomingRemainingQuantity(): int
  677.     {
  678.         $qty 0;
  679.         foreach ($this->getStocks() as $stock) {
  680.             $qty += (int) $stock->getIncomingRemainingQuantity();
  681.         }
  682.         return $qty;
  683.     }
  684.     public function getExchangeIncomingQuantity(): int
  685.     {
  686.         $qty 0;
  687.         foreach ($this->getStocks() as $stock) {
  688.             $qty += (int) $stock->getExchangeIncomingQuantity();
  689.         }
  690.         return $qty;
  691.     }
  692.     public function getAvailableQuantityForWebsite(): int
  693.     {
  694.         $qty 0;
  695.         foreach ($this->getStocks() as $stock) {
  696.             $qty += (int) $stock->getAvailableQuantityForWebsite();
  697.         }
  698.         return $qty;
  699.     }
  700.     public function setStock($stock): self
  701.     {
  702.         $this->stock $stock;
  703.         return $this;
  704.     }
  705.     public function isNew()
  706.     {
  707.         // On va chercher les produit nouveau dont la date de création ne dépasse pas 90 jours
  708.         $date = new \DateTime('now');
  709.         $date->modify('-90 day');
  710.         if( $this->getCreatedAt() >= $date) {
  711.             $this->setIsNew(true);
  712.         }
  713.         return $this->isNew;
  714.     }
  715.     public function getBestSelection(): ?bool
  716.     {
  717.         return $this->bestSelection;
  718.     }
  719.     public function setBestSelection(bool $bestSelection): self
  720.     {
  721.         $this->bestSelection $bestSelection;
  722.         return $this;
  723.     }
  724.     public function getRatingScore(): ?float
  725.     {
  726.         return $this->ratingScore;
  727.     }
  728.     public function setRatingScore(?float $ratingScore): self
  729.     {
  730.         $this->ratingScore $ratingScore;
  731.         return $this;
  732.     }
  733.     public function getRatingCount(): ?int
  734.     {
  735.         return $this->ratingCount;
  736.     }
  737.     public function setRatingCount(?int $ratingCount): self
  738.     {
  739.         $this->ratingCount $ratingCount;
  740.         return $this;
  741.     }
  742.     #[\ReturnTypeWillChange]
  743.     public function jsonSerialize()
  744.     {
  745.         $tabPictures = [];
  746.         $colorSwatches = [];
  747.         $colorIndex = [];
  748.         $primaryImage null;
  749.         $hoverImage null;
  750.         foreach ($this->getPicture() as $picture) {
  751.             array_push($tabPictures$picture->getImageName());
  752.         }
  753.         foreach ($this->getPicture() as $picture) {
  754.             if ($picture->getIsSelected()) {
  755.                 $primaryImage $picture->getImageName();
  756.                 break;
  757.             }
  758.         }
  759.         if (!$primaryImage && count($tabPictures)) {
  760.             $primaryImage $tabPictures[0];
  761.         }
  762.         foreach ($tabPictures as $pictureName) {
  763.             if ($primaryImage && $pictureName === $primaryImage) {
  764.                 continue;
  765.             }
  766.             $hoverImage $pictureName;
  767.             break;
  768.         }
  769.         foreach ($this->getProduitDeclinationValues() as $declinationValue) {
  770.             $colorValue null;
  771.             $sizeValue null;
  772.             foreach ($declinationValue->getGroupDeclinationValues() as $group) {
  773.                 $declination $group->getDeclination();
  774.                 if (!$declination) {
  775.                     continue;
  776.                 }
  777.                 if ($declination->getPosition() === 1) {
  778.                     $colorValue $group->getValue();
  779.                 }
  780.                 if ($declination->getPosition() === 2) {
  781.                     $sizeValue $group->getValue();
  782.                 }
  783.             }
  784.             if (!$colorValue) {
  785.                 continue;
  786.             }
  787.             $colorCode $colorValue->getCode();
  788.             if (!$colorCode && $colorValue->getParent()) {
  789.                 $colorCode $colorValue->getParent()->getCode();
  790.             }
  791.             $colorKey = (string) $colorValue->getId();
  792.             if (!isset($colorIndex[$colorKey])) {
  793.                 $decPictures = [];
  794.                 $decPrimary null;
  795.                 $decHover null;
  796.                 foreach ($declinationValue->getPicture() as $picture) {
  797.                     $decPictures[] = $picture->getImageName();
  798.                 }
  799.                 foreach ($declinationValue->getPicture() as $picture) {
  800.                     if ($picture->getIsSelected()) {
  801.                         $decPrimary $picture->getImageName();
  802.                         break;
  803.                     }
  804.                 }
  805.                 if (!$decPrimary && count($decPictures)) {
  806.                     $decPrimary $decPictures[0];
  807.                 }
  808.                 foreach ($decPictures as $pictureName) {
  809.                     if ($decPrimary && $pictureName === $decPrimary) {
  810.                         continue;
  811.                     }
  812.                     $decHover $pictureName;
  813.                     break;
  814.                 }
  815.                 if (!$decPrimary) {
  816.                     $decPrimary $this->getImage();
  817.                 }
  818.                 $colorSwatches[] = [
  819.                     'id' => $colorValue->getId(),
  820.                     'code' => $colorCode,
  821.                     'name' => $colorValue->getName(),
  822.                     'image' => $decPrimary,
  823.                     'hoverImage' => $decHover,
  824.                     'sizes' => [],
  825.                 ];
  826.                 $colorIndex[$colorKey] = count($colorSwatches) - 1;
  827.             }
  828.             $sizeLabel $sizeValue $sizeValue->getName() : $declinationValue->getName();
  829.             $sizeName trim($this->getName() . ' ' $sizeLabel);
  830.             $sizePictures = [];
  831.             foreach ($declinationValue->getPicture() as $picture) {
  832.                 $sizePictures[] = $picture->getImageName();
  833.             }
  834.             if (!count($sizePictures) && $this->getImage()) {
  835.                 $sizePictures[] = $this->getImage();
  836.             }
  837.             $colorSwatches[$colorIndex[$colorKey]]['sizes'][] = [
  838.                 'id' => $declinationValue->getId(),
  839.                 'name' => $sizeName,
  840.                 'label' => $sizeLabel,
  841.                 'price_ttc' => $this->getPriceTtc(),
  842.                 'qty' => $declinationValue->getQtyAvailableForWebsite(),
  843.                 'picture' => $sizePictures,
  844.             ];
  845.         }
  846.         return array(
  847.             'id' => $this->getId(),
  848.             'name' => $this->getName(),
  849.             'reference' => $this->getReference(),
  850.             'description' => $this->getDescription(),
  851.             'specification' => $this->getInformation(),
  852.               'picture' => $tabPictures,
  853.               'image' => $this->getImage(),
  854.               'hoverImage' => $hoverImage,
  855.               'aspectRatio' => $this->getCategories() && $this->getCategories()->getAspectRatio() ? $this->getCategories()->getAspectRatio() : 0.8,
  856.               'priceHT' => $this->getPriceHt(),
  857.               'priceTTC' => $this->getPriceTtc(),
  858.             'category' => $this->getCategories() ? $this->getCategories()->getId() : 0,
  859.             'categoryName' => $this->getCategories() ? $this->getCategories()->getName() : '',
  860.             //'produitDeclinationValues' => $this->getProduitDeclinationValues()->toArray(),
  861.             'promo' => $this->getPromotion(),
  862.             'isNew' => $this->isNew(),
  863.             'isDeclination' => $this->getIsDeclination(),
  864.             'stock' => $this->getStock(),
  865.             'ratingScore' => $this->getRatingScore(),
  866.             'ratingCount' => $this->getRatingCount(),
  867.             'colorSwatches' => $colorSwatches,
  868.             //'tags' => $this->getTags()->toArray(),
  869.         );
  870.     }
  871.     public function getPrincipalCategory(): ?Category
  872.     {
  873.         return $this->principalCategory;
  874.     }
  875.     public function setPrincipalCategory(?Category $principalCategory): self
  876.     {
  877.         $this->principalCategory $principalCategory;
  878.         return $this;
  879.     }
  880.     public function getDeletedAt(): ?\DateTimeInterface
  881.     {
  882.         return $this->deletedAt;
  883.     }
  884.     public function setDeletedAt(?\DateTimeInterface $deletedAt): self
  885.     {
  886.         $this->deletedAt $deletedAt;
  887.         return $this;
  888.     }
  889.     public function getReasonOfDelete(): ?string
  890.     {
  891.         return $this->reasonOfDelete;
  892.     }
  893.     public function setReasonOfDelete(?string $reasonOfDelete): self
  894.     {
  895.         $this->reasonOfDelete $reasonOfDelete;
  896.         return $this;
  897.     }
  898.     /**
  899.      * @return Collection|User[]
  900.      */
  901.     public function getUsers(): Collection
  902.     {
  903.         return $this->users;
  904.     }
  905.     public function addUser(User $user): self
  906.     {
  907.         if( !$this->users->contains($user)) {
  908.             $this->users[] = $user;
  909.         }
  910.         return $this;
  911.     }
  912.     public function removeUser(User $user): self
  913.     {
  914.         if( $this->users->contains($user)) {
  915.             $this->users->removeElement($user);
  916.         }
  917.         return $this;
  918.     }
  919.     public function getShowInWebsite(): ?bool
  920.     {
  921.         return $this->showInWebSite;
  922.     }
  923.     public function setShowInWebSite(?bool $showInWebSite): self
  924.     {
  925.         $this->showInWebSite $showInWebSite;
  926.         return $this;
  927.     }
  928.     public function isShowInPosDefault(): bool
  929.     {
  930.         return $this->showInPosDefault;
  931.     }
  932.     public function getShowInPosDefault(): bool
  933.     {
  934.         return $this->showInPosDefault;
  935.     }
  936.     public function setShowInPosDefault(bool $showInPosDefault): self
  937.     {
  938.         $this->showInPosDefault $showInPosDefault;
  939.         return $this;
  940.     }
  941.     public function getMaterial(): ?string
  942.     {
  943.         return $this->material;
  944.     }
  945.     public function setMaterial(?string $material): self
  946.     {
  947.         $this->material $material; return $this;
  948.     }
  949.      /**
  950.      * @return string|null
  951.      */
  952.     public function getSupplierReference(): ?string
  953.     {
  954.         return $this->supplierReference;
  955.     }
  956.     /**
  957.      * @param string|null $supplierReference
  958.      * @return self
  959.      */
  960.     public function setSupplierReference(?string $supplierReference): self
  961.     {
  962.         $this->supplierReference $supplierReference;
  963.         return $this;
  964.     }
  965.     public function getPromotionHistories(): Collection {
  966.         return $this->promotionHistories;
  967.     }
  968.      public function getMetaDescription(): ?string
  969.     {
  970.         return $this->metaDescription;
  971.     }
  972.     public function setMetaDescription(?string $metaDescription): self
  973.     {
  974.         $this->metaDescription $metaDescription;
  975.         return $this;
  976.     }
  977.     public function getVideoUrl(): ?string
  978.     {
  979.         return $this->videoUrl;
  980.     }
  981.     public function setVideoUrl(?string $videoUrl): self
  982.     {
  983.         $this->videoUrl $videoUrl;
  984.         return $this;
  985.     }
  986.     public function getYoutubeVideoId(): ?string
  987.     {
  988.         $url trim((string) $this->videoUrl);
  989.         if ($url === '') {
  990.             return null;
  991.         }
  992.         $parts parse_url($url);
  993.         if (!is_array($parts) || empty($parts['host'])) {
  994.             return null;
  995.         }
  996.         $host strtolower((string) $parts['host']);
  997.         $path trim((string) ($parts['path'] ?? ''), '/');
  998.         if ($host === 'youtu.be' && $path !== '') {
  999.             return explode('/'$path)[0] ?: null;
  1000.         }
  1001.         if (in_array($host, ['youtube.com''www.youtube.com''m.youtube.com'], true)) {
  1002.             if ($path === 'watch') {
  1003.                 $query = [];
  1004.                 parse_str((string) ($parts['query'] ?? ''), $query);
  1005.                 $videoId trim((string) ($query['v'] ?? ''));
  1006.                 return $videoId !== '' $videoId null;
  1007.             }
  1008.             foreach (['embed/''shorts/''live/'] as $prefix) {
  1009.                 if (str_starts_with($path$prefix)) {
  1010.                     $videoId explode('/'substr($pathstrlen($prefix)))[0] ?? '';
  1011.                     $videoId trim((string) $videoId);
  1012.                     return $videoId !== '' $videoId null;
  1013.                 }
  1014.             }
  1015.         }
  1016.         return null;
  1017.     }
  1018.     public function getYoutubeEmbedUrl(): ?string
  1019.     {
  1020.         $videoId $this->getYoutubeVideoId();
  1021.         if (!$videoId) {
  1022.             return null;
  1023.         }
  1024.         return 'https://www.youtube.com/embed/' rawurlencode($videoId);
  1025.     }
  1026.     /**
  1027.      * @return Collection|ProduitExternalLink[]
  1028.      */
  1029.     public function getExternalVideoLinks(): Collection
  1030.     {
  1031.         return $this->externalVideoLinks;
  1032.     }
  1033.     public function addExternalVideoLink(ProduitExternalLink $externalVideoLink): self
  1034.     {
  1035.         if (!$this->externalVideoLinks->contains($externalVideoLink)) {
  1036.             $this->externalVideoLinks[] = $externalVideoLink;
  1037.             $externalVideoLink->setProduit($this);
  1038.         }
  1039.         return $this;
  1040.     }
  1041.     public function removeExternalVideoLink(ProduitExternalLink $externalVideoLink): self
  1042.     {
  1043.         if ($this->externalVideoLinks->removeElement($externalVideoLink)) {
  1044.             if ($externalVideoLink->getProduit() === $this) {
  1045.                 $externalVideoLink->setProduit(null);
  1046.             }
  1047.         }
  1048.         return $this;
  1049.     }
  1050.     public function isCanBeRestocked(): bool
  1051.     {
  1052.         return $this->canBeRestocked;
  1053.     }
  1054.     public function setCanBeRestocked(bool $canBeRestocked): self
  1055.     {
  1056.         $this->canBeRestocked $canBeRestocked;
  1057.         return $this;
  1058.     }
  1059. }