- <?php
- namespace App\Entity;
- use App\Entity\Media;
- use App\Repository\ProductRepository;
- use DateInterval;
- use DateTime;
- use App\SlugHandler\ProductNameSlugHandler;
- use Doctrine\Common\Collections\ArrayCollection;
- use Doctrine\Common\Collections\Collection;
- use Doctrine\Common\Collections\Criteria;
- use Doctrine\DBAL\Types\Types;
- use Gedmo\Mapping\Annotation\Slug;
- use Doctrine\ORM\Mapping as ORM;
- use Doctrine\ORM\Mapping\PrePersist;
- use Gedmo\Blameable\Traits\BlameableEntity;
- use Gedmo\Mapping\Annotation\SlugHandler;
- use Gedmo\Mapping\Annotation\Translatable;
- use Gedmo\Sluggable\Handler\InversedRelativeSlugHandler;
- use Gedmo\Sluggable\Handler\RelativeSlugHandler;
- use Gedmo\Timestampable\Traits\TimestampableEntity;
- use Knp\DoctrineBehaviors\Contract\Entity\TranslatableInterface;
- use Knp\DoctrineBehaviors\Model\Translatable\TranslatableTrait;
- use Symfony\Component\PropertyAccess\PropertyAccess;
- use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
- use Symfony\Component\Serializer\Annotation\SerializedName;
- use Symfony\Component\Validator\Constraints as Assert;
- #[ORM\MappedSuperclass()]
- #[UniqueEntity('slug')]
- #[ORM\HasLifecycleCallbacks]
- #[ORM\Entity(repositoryClass: ProductRepository::class)]
- class Product implements TranslatableInterface
- {
-     use BlameableEntity; //Hook blameable behaviour. Updates createdBy, updatedBy fields
-     use TimestampableEntity; //Hook timestampable behaviour. Updates createdAt, updatedAt fields 
-     use TranslatableTrait;
-     const STATUS_DRAFT = 'DRAFT';
-     const STATUS_SCHEDULED = 'SCHEDULED';
-     const STATUS_ACTIVE = 'ACTIVE';
-     const STATUS_BLOCKED = 'BLOCKED';
-     const STATUS_FINISHED = 'FINISHED';
-     const DEFAULT_SHIPPING_INDIVIDUAL_DURANTION = 3;
-     const DEFAULT_SHIPPING_SHARED_DURANTION = 8;
-     #[Assert\Valid]
-     protected $translations;
-     #[ORM\Id]
-     #[ORM\GeneratedValue(strategy: "IDENTITY")]
-     #[ORM\Column]
-     private ?int $id = null;
-     #[ORM\Column(length: 255, unique: true, updatable:true)]
-     #[Slug(fields: ['slug'])]
-     private ?string $slug = null;
-     #[ORM\ManyToOne(inversedBy: 'products')]
-     #[ORM\JoinColumn(nullable: false)]
-     #[Assert\NotNull()]
-     private ?ProductType $type = null;
-     #[ORM\Column]
-     #[Assert\NotNull()]
-     private ?bool $isDraft = true;
-     #[ORM\Column]
-     #[Assert\NotNull()]
-     private ?bool $isBlocked = false;
-     #[ORM\Column]
-     #[Assert\NotNull()]
-     private ?bool $isSoldOut = false;
-     #[ORM\Column(nullable: true)]
-     #[Assert\Positive()]
-     #[Assert\Expression(
-         "!this.getShipping() || (this.getVolumetricWeight() || value)",
-     )]
-     private ?float $weight = null;
-     #[ORM\Column(nullable: true)]
-     #[Assert\Positive()]
-     private ?int $width = null;
-     #[ORM\Column(nullable: true)]
-     #[Assert\Positive()]
-     private ?int $length = null;
-     #[ORM\Column(nullable: true)]
-     #[Assert\Positive()]
-     private ?int $height = null;
-     #[ORM\Column(nullable: true)]
-     #[Assert\Positive()]
-     #[Assert\Expression(
-         "!this.getShipping() || (this.getWeight() || value)",
-     )]
-     private ?float $volumetricWeight = null;
-     #[ORM\Column(nullable: true)]
-     #[Assert\Positive()]
-     private ?int $unitsPerBox = 1;
-     #[ORM\Column(nullable: true)]
-     #[Assert\Positive()]
-     private ?int $unitsPerBoxGrouped = 1;
-     #[ORM\Column]
-     #[Assert\NotNull()]
-     private ?bool $hideDiscount = false;
-     #[ORM\Column(length: 50, nullable: true)]
-     #[Assert\Length(max: 50)]
-     private ?string $ean = null;
-     #[ORM\ManyToMany(targetEntity: Category::class, inversedBy: 'products')]
-     #[Assert\Count(min: 1)]
-     private Collection $categories;
-     #[ORM\ManyToMany(targetEntity: Subcategory::class, inversedBy: 'products')]
-     private Collection $subcategories;
-     #[ORM\Column(length: 50, nullable: true)]
-     #[Assert\Length(max: 50)]
-     private ?string $purchaseOrderNumber = null;
-     #[ORM\OneToMany(mappedBy: 'productImage', targetEntity: Media::class, cascade: ["persist", "remove"])]
-     #[ORM\OrderBy(["position" => "ASC"])]
-     private Collection $productImages;
-     #[ORM\OneToMany(mappedBy: 'productVideo', targetEntity: Media::class, cascade: ["persist", "remove"])]
-     private Collection $productVideos;
-     #[ORM\ManyToMany(targetEntity: Label::class, inversedBy: 'products')]
-     private Collection $labels;
-     #[ORM\Column]
-     #[Assert\NotNull()]
-     private ?bool $isMandatoryProductFeatures = false;
-     #[ORM\Column]
-     #[Assert\NotNull()]
-     private ?bool $isMandatoryProducer = false;
-     #[ORM\Column(nullable: true)]
-     private ?bool $isMandatoryTriweerList = false;
-     #[ORM\Column(nullable: true)]
-     private ?bool $isMandatoryTriweerComments = false;
-     #[ORM\Column]
-     #[Assert\NotNull()]
-     private ?bool $isLiveShopping = false;
-     #[ORM\Column]
-     #[Assert\NotNull()]
-     private ?bool $hasBlockchainTraceability = false;
-     #[ORM\Column]
-     #[Assert\NotNull()]
-     private ?bool $showOnWall = true;
-     #[ORM\Column]
-     #[Assert\NotNull()]
-     private ?bool $allowReturn = false;
-     #[ORM\Column(nullable: true)]
-     #[Assert\Expression(
-         "this.getAllowReturn() == false || value",
-     )]
-     #[Assert\Positive()]
-     private ?int $nDaysAllowedForReturn = null;
-     #[ORM\Column]
-     #[Assert\NotNull()]
-     private ?bool $sendNotifications = true;
-     #[ORM\Column(length: 255, nullable: true)]
-     #[Assert\Length(max: 255)]
-     private ?string $producerPurchaseOrderNumber = null;
-     #[ORM\Column]
-     #[Assert\NotNull()]
-     #[Assert\Positive()]
-     private ?int $limitUnitsPerBuyer = null;
-     #[ORM\Column(nullable: true)]
-     #[Assert\Positive()]
-     private ?int $limitUnitsToSell = null;
-     #[ORM\Column(type: Types::DATETIME_MUTABLE)]
-     #[Assert\NotNull()]
-     private ?\DateTimeInterface $comingSoonDate = null;
-     #[ORM\Column(type: Types::DATETIME_MUTABLE)]
-     #[Assert\NotNull()]
-     private ?\DateTimeInterface $offerLaunchDate = null;
-     #[ORM\Column(type: Types::DATETIME_MUTABLE)]
-     #[Assert\NotNull()]
-     private ?\DateTimeInterface $countdownDate = null;
-     #[ORM\Column(type: Types::DATETIME_MUTABLE)]
-     #[Assert\NotNull()]
-     private ?\DateTimeInterface $endOfferDate = null;
-     #[ORM\Column(type: Types::DATETIME_MUTABLE)]
-     //#[Assert\NotNull()]
-     private ?\DateTimeInterface $shippingDate = null;
-     #[ORM\Column(nullable: true)]
-     #[Assert\PositiveOrZero()]
-     // #[Assert\NotNull()]
-     private ?int $individualShippingDuration = null;
-     #[ORM\Column(nullable: true)]
-     #[Assert\PositiveOrZero()]
-     // #[Assert\NotNull()]
-     private ?int $sharedShippingDuration = null;
-     #[ORM\Column(length: 255, nullable: true)]
-     #[Assert\Length(max: 255)]
-     private ?string $individualPackageFormat = null;
-     #[ORM\Column]
-     #[Assert\NotNull()]
-     #[Assert\PositiveOrZero()]
-     private ?int $nHoursOnWallAfterEnd = null;
-     #[ORM\ManyToOne(inversedBy: 'products')]
-     #[ORM\JoinColumn(nullable: false)]
-     #[Assert\NotNull()]
-     private ?Iva $iva = null;
-     #[ORM\OneToMany(mappedBy: 'product', targetEntity: ProductPriceScale::class, cascade: ["persist", "remove"], orphanRemoval: true)]
-     #[ORM\OrderBy(["initialPrice" => "DESC"])]
-     #[Assert\Count(min: 1)]
-     #[Assert\Valid]
-     private Collection $priceScales;
-     #[ORM\Column]
-     #[Assert\NotNull()]
-     #[Assert\PositiveOrZero()]
-     private ?int $maxCoinsToSpent = null;
-     #[ORM\ManyToOne(inversedBy: 'products')]
-     #[ORM\JoinColumn(nullable: true)]
-     #[Assert\NotNull()]
-     private ?Brand $brand = null;
-     #[ORM\ManyToOne(inversedBy: 'products')]
-     #[Assert\Expression(
-         "this.getIsMandatoryProducer() == false || value",
-     )]
-     private ?Producer $producer = null;
-     #[ORM\ManyToOne(inversedBy: 'products')]
-     #[ORM\JoinColumn(nullable: false)]
-     #[Assert\NotNull()]
-     private ?UnitMeasurement $unitMeasurement = null;
-     #[ORM\OneToMany(mappedBy: 'product', targetEntity: OrderDetail::class)]
-     private Collection $orderDetails;
-     #[ORM\Column]
-     #[Assert\NotNull()]
-     #[Assert\Positive()]
-     private ?float $originalPrice = null;
-     #[ORM\Column(nullable: true)]
-     #[Assert\Positive()]
-     private ?float $individualPrice = null;
-     #[ORM\Column(options: ['default' => false])]
-     private ?bool $individualDisabled = false;
-     #[ORM\Column(options: ['default' => 0])]
-     #[Assert\NotNull()]
-     #[Assert\PositiveOrZero()]
-     #[Assert\Expression(
-         "value <= this.getProductMaxQuantity()",
-     )]
-     private ?int $fakeUsers = 0;
-     #[ORM\JoinTable(name: 'faketriweers_product')]
-     #[ORM\JoinColumn(name: 'fake_triweer_id', referencedColumnName: 'id')]
-     #[ORM\InverseJoinColumn(name: 'product_id', referencedColumnName: 'id')]
-     #[ORM\ManyToMany(targetEntity: User::class)]
-     private Collection $fakeTriweersInOffer;
-     #[ORM\Column(type: Types::TEXT, nullable: true)]
-     private ?string $additionalInfo = null;
-     /**
-      * @deprecated
-      */
-     #[ORM\Column(nullable: true)]
-     #[Assert\PositiveOrZero()]
-     private ?float $shippingCost = null;
-     #[ORM\Column(length: 500, nullable: true)]
-     private ?string $holdedId = null;
-     #[ORM\OneToMany(mappedBy: 'product', targetEntity: UserShared::class)]
-     private Collection $influencerShareds;
-     #[ORM\ManyToOne(inversedBy: 'products')]
-     #[ORM\JoinColumn(nullable: false)]
-     #[Assert\NotNull()]
-     private ?ProductUnique $productUnique = null;
-     #[ORM\Column(options: ['default' => false])]
-     private ?bool $onlyAdults = false;
-     #[ORM\Column(nullable: true)]
-     #[Assert\PositiveOrZero()]
-     private ?int $amountForFreeShipping = null;
-     #[ORM\Column(nullable: true)]
-     private ?bool $better_price = null;
-     #[ORM\ManyToOne(inversedBy: 'products')]
-     #[Assert\NotNull()]
-     private ?Shipping $shipping = null;
-     #[ORM\ManyToMany(targetEntity: User::class, mappedBy: "favouriteProducts")]
-     private Collection $userFavourites;
-     private Collection $randomUserFavourites;
-     #[ORM\OneToMany(mappedBy: 'product', targetEntity: Review::class)]
-     private Collection $userReviews;
-     #[ORM\Column(length: 255, nullable: true)]
-     private ?string $meta_title = null;
-     #[ORM\Column(length: 255, nullable: true)]
-     private ?string $meta_description = null;
-     #[ORM\Column(nullable: false, options: ['default' => false])]
-     private ?bool $showPrice = false;
-     #[ORM\PrePersist]
-     
-     public function setSlugValue()
-     {
-         $this->setSlug($this->translate('es')->getName());
-     }
-     public function setSlugEditValue()
-     {
-         $name = $this->translate('es')->getName() ?? '';
-         $this->setSlug($this->generateSlug($name)); 
-     }
-     private function generateSlug(string $name): string
-     {
-         return strtolower(trim(preg_replace('/[^A-Za-z0-9-]+/', '-', $name)));
-     }
-     public function __call($method, $arguments)
-     {
-         return $this->proxyCurrentLocaleTranslation($method, $arguments);
-     }
-     public function __construct()
-     {
-         $this->categories          = new ArrayCollection();
-         $this->subcategories       = new ArrayCollection();
-         $this->productImages       = new ArrayCollection();
-         $this->productVideos       = new ArrayCollection();
-         $this->labels              = new ArrayCollection();
-         $this->priceScales         = new ArrayCollection();
-         $this->orderDetails        = new ArrayCollection();
-         $this->influencerShareds   = new ArrayCollection();
-         $this->userFavourites      = new ArrayCollection();
-         $this->fakeTriweersInOffer = new ArrayCollection();
-         $this->userReviews         = new ArrayCollection();
-     }
-     public function __clone()
-     {
-         $this->orderDetails      = new ArrayCollection();
-         $this->influencerShareds = new ArrayCollection();
-         $this->userFavourites    = new ArrayCollection();
-         $this->userReviews       = new ArrayCollection();
-         if ($this->id) {
-             $this->setId(null);
-         }
-         if ($this->holdedId) {
-             $this->setHoldedId('');
-         }
-         $this->setIsDraft(true);
-         foreach ($this->getTranslations() as $trans) {
-             /** @var \App\Entity\ProductTranslation $trans */
-             $clonedTrans = clone $trans;
-             $clonedTrans->setName('Clon ' . $clonedTrans->getName());
-             $this->addTranslation($clonedTrans);
-         }
-         foreach ($this->getProductImages() as $idx => $media) {
-             $this->addProductImage((new Media())->clone($media, 'product', $idx));
-         }
-         foreach ($this->getProductVideos() as $idx => $media) {
-             $this->addProductVideo((new Media())->clone($media, 'product', $idx));
-         }
-         foreach ($this->getPriceScales() as $idx => $scale) {
-             $this->addPriceScale(clone $scale);
-         }
-     }
-     public function setId(?int $id): self
-     {
-         $this->id = $id;
-         return $this;
-     }
-     public function getId(): ?int
-     {
-         return $this->id;
-     }
-     public function getSlug(): ?string
-     {
-         return $this->slug;
-     }
-     public function setSlug(string $slug): self
-     {
-         $this->slug = $slug;
-         return $this;
-     }
-     public function getStatus(): string
-     {
-         if ($this->isDraft) {
-             return Product::STATUS_DRAFT;
-         } else if ($this->isBlocked) {
-             return Product::STATUS_BLOCKED;
-         } else if ($this->isSoldOut || $this->endOfferDate < (new \DateTime())) {
-             return Product::STATUS_FINISHED;
-         } else if ($this->offerLaunchDate > (new \DateTime())) {
-             return Product::STATUS_SCHEDULED;
-         }
-         return Product::STATUS_ACTIVE;
-     }
-     public function getIsScheduled(): bool
-     {
-         return $this->getStatus() == Product::STATUS_SCHEDULED;
-     }
-     public function getIsActive(): bool
-     {
-         return $this->getStatus() == Product::STATUS_ACTIVE;
-     }
-     public function getIsFinished(): bool
-     {
-         return $this->getStatus() == Product::STATUS_FINISHED;
-     }
-     public function getIsFinishedPlusExtra(): bool
-     {
-         if ($this->getStatus() != Product::STATUS_FINISHED) {
-             return false;
-         }
-         if ($this->nHoursOnWallAfterEnd > 0) {
-             $endOfferDate = DateTime::createFromInterface($this->endOfferDate);
-             $endOfferDate->add(new DateInterval("PT{$this->nHoursOnWallAfterEnd}H"));
-             return $endOfferDate <= (new \DateTime());
-         }
-         return true;
-     }
-     public function getStatusBgColor(): string
-     {
-         $status = $this->getStatus();
-         switch ($status) {
-             case Product::STATUS_DRAFT:
-                 $color = "#F1C14F";
-                 break;
-             case Product::STATUS_BLOCKED:
-                 $color = "#000000";
-                 break;
-             case Product::STATUS_SCHEDULED:
-                 $color = "#36A9E1";
-                 break;
-             case Product::STATUS_ACTIVE:
-                 $color = "#32D29D";
-                 break;
-             case Product::STATUS_FINISHED:
-                 $color = "#FF4863";
-                 break;
-         }
-         return $color;
-     }
-     public function getStatusColor(): string
-     {
-         $status = $this->getStatus();
-         switch ($status) {
-             case Product::STATUS_DRAFT:
-                 $color = "#FFFFFF";
-                 break;
-             case Product::STATUS_BLOCKED:
-                 $color = "#FFFFFF";
-                 break;
-             case Product::STATUS_SCHEDULED:
-                 $color = "#FFFFFF";
-                 break;
-             case Product::STATUS_ACTIVE:
-                 $color = "#FFFFFF";
-                 break;
-             case Product::STATUS_FINISHED:
-                 $color = "#FFFFFF";
-                 break;
-         }
-         return $color;
-     }
-     public function getNameWithId(): ?string
-     {
-         return $this->getId() . ' - ' . $this->getName();
-     }
-     public function getType(): ?ProductType
-     {
-         return $this->type;
-     }
-     public function setType(?ProductType $type): self
-     {
-         $this->type = $type;
-         return $this;
-     }
-     public function getIsDraft(): ?bool
-     {
-         return $this->isDraft;
-     }
-     public function setIsDraft(?bool $isDraft): self
-     {
-         $this->isDraft = $isDraft;
-         return $this;
-     }
-     public function getIsBlocked(): ?bool
-     {
-         return $this->isBlocked;
-     }
-     public function setIsBlocked(?bool $isBlocked): self
-     {
-         $this->isBlocked = $isBlocked;
-         return $this;
-     }
-     public function getIsSoldOut(): ?bool
-     {
-         return $this->isSoldOut;
-     }
-     public function setIsSoldOut(bool $isSoldOut): self
-     {
-         $this->isSoldOut = $isSoldOut;
-         return $this;
-     }
-     public function getWeight(): ?float
-     {
-         return $this->weight;
-     }
-     public function setWeight(?float $weight): self
-     {
-         $this->weight = $weight;
-         return $this;
-     }
-     public function getWidth(): ?int
-     {
-         return $this->width;
-     }
-     public function setWidth(?int $width): self
-     {
-         $this->width = $width;
-         return $this;
-     }
-     public function getLength(): ?int
-     {
-         return $this->length;
-     }
-     public function setLength(?int $length): self
-     {
-         $this->length = $length;
-         return $this;
-     }
-     public function getHeight(): ?int
-     {
-         return $this->height;
-     }
-     public function setHeight(?int $height): self
-     {
-         $this->height = $height;
-         return $this;
-     }
-     public function getVolumetricWeight(): ?float
-     {
-         return $this->volumetricWeight;
-     }
-     public function setVolumetricWeight(?float $volumetricWeight): self
-     {
-         $this->volumetricWeight = $volumetricWeight;
-         return $this;
-     }
-     /**
-      *  Max value between weight and volumetric weight
-      */
-     public function getShippingWeight(): ?float
-     {
-         return max($this->volumetricWeight, $this->weight);
-     }
-     public function getEan(): ?string
-     {
-         return $this->ean;
-     }
-     public function setEan(?string $ean): self
-     {
-         $this->ean = $ean;
-         return $this;
-     }
-     public function getUnitsPerBox(): ?int
-     {
-         return $this->unitsPerBox;
-     }
-     public function setUnitsPerBox(?int $unitsPerBox): self
-     {
-         $this->unitsPerBox = $unitsPerBox;
-         return $this;
-     }
-     public function getUnitsPerBoxGrouped(): ?int
-     {
-         return $this->unitsPerBoxGrouped ?? 1;
-     }
-     public function setUnitsPerBoxGrouped(?int $unitsPerBoxGrouped): self
-     {
-         $this->unitsPerBoxGrouped = $unitsPerBoxGrouped;
-         return $this;
-     }
-     public function getHideDiscount(): ?bool
-     {
-         return $this->hideDiscount ?? false;
-     }
-     public function setHideDiscount(?bool $hideDiscount): self
-     {
-         $this->hideDiscount = $hideDiscount;
-         return $this;
-     }
-     /**
-      * @return Collection<int, Category>
-      */
-     public function getCategories(): Collection
-     {
-         return $this->categories;
-     }
-     public function getCategoriesText(): ?string
-     {
-         return implode(', ', $this->categories->toArray());
-     }
-     public function addCategory(Category $category): self
-     {
-         if (!$this->categories->contains($category)) {
-             $this->categories->add($category);
-         }
-         return $this;
-     }
-     public function removeCategory(Category $category): self
-     {
-         $this->categories->removeElement($category);
-         return $this;
-     }
-     /**
-      * @return Collection<int, Subcategory>
-      */
-     public function getSubcategories(): Collection
-     {
-         return $this->subcategories;
-     }
-     public function getSubcategoriesText(): ?string
-     {
-         return implode(', ', $this->subcategories->toArray());
-     }
-     public function addSubcategory(Subcategory $subcategory): self
-     {
-         if (!$this->subcategories->contains($subcategory)) {
-             $this->subcategories->add($subcategory);
-         }
-         return $this;
-     }
-     public function removeSubcategory(Subcategory $subcategory): self
-     {
-         $this->subcategories->removeElement($subcategory);
-         return $this;
-     }
-     public function getPurchaseOrderNumber(): ?string
-     {
-         return $this->purchaseOrderNumber;
-     }
-     public function setPurchaseOrderNumber(?string $purchaseOrderNumber): self
-     {
-         $this->purchaseOrderNumber = $purchaseOrderNumber;
-         return $this;
-     }
-     /**
-      * Main image is the one that have position 0
-      * @return Media|null
-      */
-     public function getMainProductImage(): ?Media
-     {
-         if ($this->productImages) {
-             $filteredProductImages = $this->productImages->filter(function (Media $productImage) {
-                 return $productImage->getPosition() == 0;
-             });
-             return (count($filteredProductImages) > 0) ? $filteredProductImages->first() : null;
-         } else {
-             return null;
-         }
-     }
-     /**
-      * @return Collection<int, Media>
-      */
-     public function getProductImages(): Collection
-     {
-         return $this->productImages;
-     }
-     public function addProductImage(Media $productImage): self
-     {
-         if (!$this->productImages->contains($productImage)) {
-             $productImage->setDirectory('product');
-             $this->productImages->add($productImage);
-             $productImage->setProductImage($this);
-         }
-         return $this;
-     }
-     public function removeProductImage(Media $productImage): self
-     {
-         if ($this->productImages->removeElement($productImage)) {
-             // set the owning side to null (unless already changed)
-             if ($productImage->getProductImage() === $this) {
-                 $productImage->setProductImage(null);
-             }
-         }
-         return $this;
-     }
-     /**
-      * @return Collection<int, Media>
-      */
-     public function getProductVideos(): Collection
-     {
-         return $this->productVideos;
-     }
-     public function addProductVideo(Media $productVideo): self
-     {
-         if (!$this->productVideos->contains($productVideo)) {
-             $productVideo->setDirectory('product');
-             $this->productVideos->add($productVideo);
-             $productVideo->setProductVideo($this);
-         }
-         return $this;
-     }
-     public function removeProductVideo(Media $productVideo): self
-     {
-         if ($this->productVideos->removeElement($productVideo)) {
-             // set the owning side to null (unless already changed)
-             if ($productVideo->getProductVideo() === $this) {
-                 $productVideo->setProductVideo(null);
-             }
-         }
-         return $this;
-     }
-     /**
-      * @return Collection<int, Label>
-      */
-     public function getLabels(): Collection
-     {
-         return $this->labels;
-     }
-     public function getLabelsText(): ?string
-     {
-         return implode(', ', $this->labels->toArray());
-     }
-     public function addLabel(Label $label): self
-     {
-         if (!$this->labels->contains($label)) {
-             $this->labels->add($label);
-         }
-         return $this;
-     }
-     public function removeLabel(Label $label): self
-     {
-         $this->labels->removeElement($label);
-         return $this;
-     }
-     public function getIsMandatoryProductFeatures(): ?bool
-     {
-         return $this->isMandatoryProductFeatures;
-     }
-     public function setIsMandatoryProductFeatures(bool $isMandatoryProductFeatures): self
-     {
-         $this->isMandatoryProductFeatures = $isMandatoryProductFeatures;
-         return $this;
-     }
-     public function getIsMandatoryProducer(): ?bool
-     {
-         return $this->isMandatoryProducer;
-     }
-     public function setIsMandatoryProducer(bool $isMandatoryProducer): self
-     {
-         $this->isMandatoryProducer = $isMandatoryProducer;
-         return $this;
-     }
-     public function getIsMandatoryTriweerList(): ?bool
-     {
-         return $this->isMandatoryTriweerList;
-     }
-     public function setIsMandatoryTriweerList(?bool $isMandatoryTriweerList): self
-     {
-         $this->isMandatoryTriweerList = $isMandatoryTriweerList;
-         return $this;
-     }
-     public function getIsMandatoryTriweerComments(): ?bool
-     {
-         return $this->isMandatoryTriweerComments;
-     }
-     public function setIsMandatoryTriweerComments(?bool $isMandatoryTriweerComments): self
-     {
-         $this->isMandatoryTriweerComments = $isMandatoryTriweerComments;
-         return $this;
-     }
-     public function isIsLiveShopping(): ?bool
-     {
-         return $this->isLiveShopping;
-     }
-     public function setIsLiveShopping(bool $isLiveShopping): self
-     {
-         $this->isLiveShopping = $isLiveShopping;
-         return $this;
-     }
-     public function isHasBlockchainTraceability(): ?bool
-     {
-         return $this->hasBlockchainTraceability;
-     }
-     public function setHasBlockchainTraceability(bool $hasBlockchainTraceability): self
-     {
-         $this->hasBlockchainTraceability = $hasBlockchainTraceability;
-         return $this;
-     }
-     public function getShowOnWall(): ?bool
-     {
-         return $this->showOnWall;
-     }
-     public function setShowOnWall(bool $showOnWall): self
-     {
-         $this->showOnWall = $showOnWall;
-         return $this;
-     }
-     public function getAllowReturn(): ?bool
-     {
-         return $this->allowReturn;
-     }
-     public function setAllowReturn(bool $allowReturn): self
-     {
-         $this->allowReturn = $allowReturn;
-         return $this;
-     }
-     public function getNDaysAllowedForReturn(): ?int
-     {
-         return $this->nDaysAllowedForReturn;
-     }
-     public function setNDaysAllowedForReturn(?int $nDaysAllowedForReturn): self
-     {
-         $this->nDaysAllowedForReturn = $nDaysAllowedForReturn;
-         return $this;
-     }
-     public function isInWarrantyPeriod(DateTime $dateBought): ?bool
-     {
-         $now = new DateTime('now');
-         if ($this->getAllowReturn() && $this->getNDaysAllowedForReturn()) {
-             $dayToCompare = $dateBought->add(new DateInterval('P' . $this->getNDaysAllowedForReturn() . 'D'));
-             if ($now > $dateBought) {
-                 return true;
-             } else {
-                 return false;
-             }
-         } else {
-             return false;
-         }
-     }
-     public function isSendNotifications(): ?bool
-     {
-         return $this->sendNotifications;
-     }
-     public function setSendNotifications(bool $sendNotifications): self
-     {
-         $this->sendNotifications = $sendNotifications;
-         return $this;
-     }
-     public function getProducerPurchaseOrderNumber(): ?string
-     {
-         return $this->producerPurchaseOrderNumber;
-     }
-     public function setProducerPurchaseOrderNumber(?string $producerPurchaseOrderNumber): self
-     {
-         $this->producerPurchaseOrderNumber = $producerPurchaseOrderNumber;
-         return $this;
-     }
-     public function getLimitUnitsPerBuyer(): ?int
-     {
-         return $this->limitUnitsPerBuyer;
-     }
-     public function setLimitUnitsPerBuyer(int $limitUnitsPerBuyer): self
-     {
-         $this->limitUnitsPerBuyer = $limitUnitsPerBuyer;
-         return $this;
-     }
-     public function getLimitUnitsToSell(): ?int
-     {
-         return $this->limitUnitsToSell;
-     }
-     public function setLimitUnitsToSell(?int $limitUnitsToSell): self
-     {
-         $this->limitUnitsToSell = $limitUnitsToSell;
-         return $this;
-     }
-     public function getComingSoonDate(): ?\DateTimeInterface
-     {
-         return $this->comingSoonDate;
-     }
-     public function setComingSoonDate(?\DateTimeInterface $comingSoonDate): self
-     {
-         $this->comingSoonDate = $comingSoonDate;
-         return $this;
-     }
-     public function getOfferLaunchDate(): ?\DateTimeInterface
-     {
-         return $this->offerLaunchDate;
-     }
-     public function setOfferLaunchDate(?\DateTimeInterface $offerLaunchDate): self
-     {
-         $this->offerLaunchDate = $offerLaunchDate;
-         return $this;
-     }
-     /**
-      * Indicates if it should show the countdown in templates
-      *
-      * @return boolean
-      */
-     public function getShowCountdown(): bool
-     {
-         if ($this->countdownDate && $this->countdownDate < (new \DateTime())) {
-             return true;
-         }
-         return false;
-     }
-     public function getCountdownDate(): ?\DateTimeInterface
-     {
-         return $this->countdownDate;
-     }
-     public function setCountdownDate(?\DateTimeInterface $countdownDate): self
-     {
-         $this->countdownDate = $countdownDate;
-         return $this;
-     }
-     public function getEndOfferDate(): ?\DateTimeInterface
-     {
-         return $this->endOfferDate;
-     }
-     public function setEndOfferDate(?\DateTimeInterface $endOfferDate): self
-     {
-         $this->endOfferDate = $endOfferDate;
-         return $this;
-     }
-     public function getShippingDate(): ?\DateTimeInterface
-     {
-         return $this->shippingDate;
-     }
-     public function setShippingDate(?\DateTimeInterface $shippingDate): self
-     {
-         $this->shippingDate = $shippingDate;
-         return $this;
-     }
-     public function getIndividualShippingDuration(): ?int
-     {
-         return $this->individualShippingDuration ?? Product::DEFAULT_SHIPPING_INDIVIDUAL_DURANTION;
-     }
-     public function setIndividualShippingDuration(?int $individualShippingDuration): self
-     {
-         $this->individualShippingDuration = $individualShippingDuration;
-         return $this;
-     }
-     public function getSharedShippingDuration(): ?int
-     {
-         return $this->sharedShippingDuration ?? Product::DEFAULT_SHIPPING_SHARED_DURANTION;
-     }
-     public function setSharedShippingDuration(?int $sharedShippingDuration): self
-     {
-         $this->sharedShippingDuration = $sharedShippingDuration;
-         return $this;
-     }
-     public function getIndividualPackageFormat(): ?string
-     {
-         return $this->individualPackageFormat;
-     }
-     public function setIndividualPackageFormat(?string $individualPackageFormat): self
-     {
-         $this->individualPackageFormat = $individualPackageFormat;
-         return $this;
-     }
-     public function getNHoursOnWallAfterEnd(): ?int
-     {
-         return $this->nHoursOnWallAfterEnd;
-     }
-     public function setNHoursOnWallAfterEnd(int $nHoursOnWallAfterEnd): self
-     {
-         $this->nHoursOnWallAfterEnd = $nHoursOnWallAfterEnd;
-         return $this;
-     }
-     public function getIva(): ?Iva
-     {
-         return $this->iva;
-     }
-     public function setIva(?Iva $iva): self
-     {
-         $this->iva = $iva;
-         return $this;
-     }
-     public function getIndividualPrice(): ?float
-     {
-         return $this->individualPrice ?? $this->getInitialPrice();
-     }
-     public function setIndividualPrice(?float $individualPrice): self
-     {
-         $this->individualPrice = $individualPrice;
-         return $this;
-     }
-     public function getIndividualDisabled(): ?bool
-     {
-         return $this->individualDisabled ?? $this->getInitialPrice();
-     }
-     public function setIndividualDisabled(?bool $individualDisabled): self
-     {
-         $this->individualDisabled = $individualDisabled;
-         return $this;
-     }
-     public function getInitialPrice(): ?float
-     {
-         if ($this->priceScales->count() === 0) {
-             return $this->originalPrice;
-         }
-         return $this->priceScales[0]->getInitialPrice();
-     }
-     public function getCurrentPrice(): float
-     {
-         $currentQuantityOrdered = $this->getCurrentQuantityOrdered();
-         $currentPriceScale = $this->getCurrentPriceScale($currentQuantityOrdered);
-         if ($currentPriceScale->isSellProductIfNotComplete()) {
-             if ($currentQuantityOrdered  < $currentPriceScale->getTotalMaxQuantity()) {
-                 return $currentPriceScale->getInitialPrice();
-             } else {
-                 return $currentPriceScale->getFinalPrice();
-             }
-         } else {
-             return $this->getNextPrice();
-         }
-     }
-     public function getNextPrice(?int $cartQuantity = 0): float
-     {
-         $currentQuantityOrdered = $this->getCurrentQuantityOrdered();
-         $currentPriceScale      = $this->getCurrentPriceScale($currentQuantityOrdered);
-         // if (($this->priceScales->count() === 1) or ($this->currentScaleIsFirst($currentPriceScale))) {
-         //     if ($currentPriceScale->isSellProductIfNotComplete()) {
-         //         return $currentPriceScale->getInitialPrice();
-         //     }else{
-         //         return $currentPriceScale->getFinalPrice();
-         //     }
-         // }
-         if ($currentPriceScale->isSellProductIfNotComplete()) {
-             $belowMinQty = ($currentQuantityOrdered + $cartQuantity) < $this->getScalesAccumulatedMinQuantity();
-             return $belowMinQty
-                 ? $currentPriceScale->getInitialPrice()
-                 : $currentPriceScale->getFinalPrice();
-         } else {
-             return $currentPriceScale->getFinalPrice();
-         }
-     }
-     /**
-      * Get the accumulated minimum quantity for multiple price scales.
-      */
-     public function getScalesAccumulatedMinQuantity(): int
-     {
-         $currentQuantityOrdered = $this->getCurrentQuantityOrdered();
-         $currentPriceScale      = $this->getCurrentPriceScale($currentQuantityOrdered);
-         return $this->getPriceScales()->reduce(
-             fn ($acc, $scale) =>
-             $currentPriceScale->getFinalPrice() <= $scale->getFinalPrice()
-                 ? $acc + $scale->getScaleQuantity()
-                 : $acc
-         );
-     }
-     /**
-      * Get the goal of orders (sum. of all scales units)
-      *
-      * @return float|null
-      */
-     public function getScaleOrdersGoal(): ?float
-     {
-         return $this->getPriceScales()->reduce(
-             fn ($acc, $scale) => $acc + $scale->getScaleQuantity()
-         );
-     }
-     /**
-      * Get the current quantity of orders (sum. of all scales units until the current one)
-      *
-      * @return float|null
-      */
-     public function getScaleOrdersCurrent(): ?float
-     {
-         $current = $this->getCurrentPriceScale();
-         return $this->getPriceScales()->reduce(
-             function ($acc, $scale) use ($current) {
-                 if ($current->getFinalPrice() <= $scale->getFinalPrice()) {
-                     $acc += $scale->getScaleQuantity();
-                 }
-                 return $acc;
-             }
-         );
-     }
-     /**
-      * Check if the current price scale is the first one.
-      */
-     public function currentScaleIsFirst($currentPriceScale): bool
-     {
-         return $this->priceScales->first()->getId() === $currentPriceScale->getId();
-     }
-     /**
-      * Get the current price scale. It depends on the quantity already ordered
-      *
-      * @return ProductPriceScale
-      */
-     public function getCurrentPriceScale($currentQuantityOrdered = null): ProductPriceScale
-     {
-         if ($currentQuantityOrdered === null) {
-             $currentQuantityOrdered = $this->getCurrentQuantityOrdered();
-         }
-         $currentPriceScale = null;
-         /** @var ProductPriceScale */
-         foreach ($this->priceScales as $priceScale) {
-             if (
-                 ($priceScale->getTotalMinQuantity() <= $currentQuantityOrdered) &&
-                 ($currentQuantityOrdered < $priceScale->getTotalMaxQuantity())
-             ) {
-                 $currentPriceScale = $priceScale;
-                 break;
-             }
-         }
-         if (!$currentPriceScale) {
-             $currentPriceScale = $priceScale;
-         }
-         return $currentPriceScale;
-     }
-     /**
-      * @return boolean
-      */
-     public function getIsSellIsEnought()
-     {
-         return $this->getCurrentPriceScale()->isSellProductIfNotComplete();
-     }
-     /**
-      * Get the current price scale. It depends on the quantity already ordered
-      *
-      * @return ProductPriceScale
-      */
-     public function getNextPriceScale($currentQuantityOrdered = null): ProductPriceScale
-     {
-         if ($currentQuantityOrdered === null) {
-             $currentQuantityOrdered = $this->getCurrentQuantityOrdered();
-         }
-         $currentPriceScale = null;
-         $next = False;
-         $nextPriceScale = null;
-         /** @var ProductPriceScale */
-         foreach ($this->priceScales as $priceScale) {
-             if ($next) {
-                 $nextPriceScale = $priceScale;
-                 $next = False;
-             }
-             if (
-                 ($priceScale->getTotalMinQuantity() <= $currentQuantityOrdered) &&
-                 ($currentQuantityOrdered < $priceScale->getTotalMaxQuantity())
-             ) {
-                 $next = true;
-                 $currentPriceScale = $priceScale;
-             }
-         }
-         if (!$currentPriceScale) {
-             $currentPriceScale = $priceScale;
-         }
-         if (!$nextPriceScale) {
-             $nextPriceScale = $currentPriceScale;
-         }
-         return $nextPriceScale;
-     }
-     /**
-      * Max product quantity
-      *
-      * @return integer
-      */
-     public function getProductMaxQuantity(): int
-     {
-         $totalQuantity = 0;
-         if ($this->priceScales) {
-             /** @var ProductPriceScale */
-             foreach ($this->priceScales as $priceScale) {
-                 $totalQuantity += $priceScale->getScaleQuantity();
-             }
-         }
-         return $totalQuantity;
-     }
-     /**
-      * Max product quantity
-      *
-      * @return integer
-      */
-     public function getProductMaxQuantityAvailable(): int
-     {
-         $totalQuantity = 0;
-         if ($this->priceScales) {
-             /** @var ProductPriceScale */
-             foreach ($this->priceScales as $priceScale) {
-                 $totalQuantity += $priceScale->getScaleQuantityAvailable();
-             }
-         }
-         return $totalQuantity;
-     }
-     /**
-      * @return ProductPriceScale
-      */
-     public function getInitialPriceScale(): ProductPriceScale
-     {
-         return $this->priceScales->first();
-     }
-     /**
-      * @return ProductPriceScale
-      */
-     public function getLastPriceScale(): ProductPriceScale
-     {
-         return $this->priceScales->last();
-     }
-     public function getOrderedPriceScales(): Collection
-     {
-         $criteria = Criteria::create()
-             ->orderBy(['scaleQuantity' => Criteria::ASC]);
-         $orderedPrices = $this->priceScales->matching($criteria);
-         return $orderedPrices;
-     }
-     /**
-      * @return Collection<int, ProductPriceScale>
-      */
-     public function getPriceScales(): Collection
-     {
-         return $this->priceScales;
-     }
-     public function addPriceScale(ProductPriceScale $priceScale): self
-     {
-         if (!$this->priceScales->contains($priceScale)) {
-             $this->priceScales->add($priceScale);
-             $priceScale->setProduct($this);
-         }
-         return $this;
-     }
-     public function removePriceScale(ProductPriceScale $priceScale): self
-     {
-         if ($this->priceScales->removeElement($priceScale)) {
-             // set the owning side to null (unless already changed)
-             if ($priceScale->getProduct() === $this) {
-                 $priceScale->setProduct(null);
-             }
-         }
-         return $this;
-     }
-     public function getMaxCoinsToSpent(): ?int
-     {
-         return $this->maxCoinsToSpent;
-     }
-     public function setMaxCoinsToSpent(int $maxCoinsToSpent): self
-     {
-         $this->maxCoinsToSpent = $maxCoinsToSpent;
-         return $this;
-     }
-     public function getBrand(): ?Brand
-     {
-         return $this->brand;
-     }
-     public function setBrand(?Brand $brand): self
-     {
-         $this->brand = $brand;
-         return $this;
-     }
-     public function getProducer(): ?Producer
-     {
-         return $this->producer;
-     }
-     public function setProducer(?Producer $producer): self
-     {
-         $this->producer = $producer;
-         return $this;
-     }
-     public function getUnitMeasurement(): ?UnitMeasurement
-     {
-         return $this->unitMeasurement;
-     }
-     public function setUnitMeasurement(?UnitMeasurement $unitMeasurement): self
-     {
-         $this->unitMeasurement = $unitMeasurement;
-         return $this;
-     }
-     /**
-      * Get the current products's quantity ordered
-      * @return int
-      */
-     public function getCurrentQuantityOrdered(): int
-     {
-         $currentQuantityOrdered = $this->fakeUsers ? $this->fakeUsers : 0;
-         /** @var OrderDetail */
-         foreach ($this->orderDetails as $orderDetail) {
-             if (
-                 $orderDetail->getHeader()->getStatus()->getKey() == OrderStatus::PENDING_PAYMENT ||
-                 $orderDetail->getHeader()->getStatus()->getKey() == OrderStatus::CANCELED
-             ) {
-                 continue;
-             }
-             $currentQuantityOrdered += $orderDetail->getQuantity();
-         }
-         return $currentQuantityOrdered;
-     }
-     /**
-      * Get the current products's quantity ordered
-      * @return bool
-      */
-     public function hasBeenPurchasedRecently(?int $orderID = null): bool
-     {
-         /** @var OrderDetail */
-         foreach ($this->orderDetails as $orderDetail) {
-             $order = $orderDetail->getHeader();
-             if ($orderID && $order->getId() === $orderID) continue;
-             if ($order->getStatus()->getKey() == OrderStatus::MONEY_WITHHELD) {
-                 return true;
-             }
-         }
-         return false;
-     }
-     /**
-      * Get the current products's quantity ordered in percentage
-      * @return float
-      */
-     public function getCurrentOrderedPercentage(): float
-     {
-         $productMaxQuantity = $this->getProductMaxQuantity();
-         if ($productMaxQuantity) {
-             return (100 * $this->getCurrentQuantityOrdered() / $productMaxQuantity);
-         } else {
-             return 0;
-         }
-     }
-     /**
-      * @return Collection<int, OrderDetail>
-      */
-     public function getOrderDetails(): Collection
-     {
-         return $this->orderDetails;
-     }
-     public function addOrderDetail(OrderDetail $orderDetail): self
-     {
-         if (!$this->orderDetails->contains($orderDetail)) {
-             $this->orderDetails->add($orderDetail);
-             $orderDetail->setProduct($this);
-         }
-         return $this;
-     }
-     public function removeOrderDetail(OrderDetail $orderDetail): self
-     {
-         if ($this->orderDetails->removeElement($orderDetail)) {
-             // set the owning side to null (unless already changed)
-             if ($orderDetail->getProduct() === $this) {
-                 $orderDetail->setProduct(null);
-             }
-         }
-         return $this;
-     }
-     public function getPendingOrderDetails(): Collection
-     {
-         return $this->getOrderDetails()->filter(function($i) {
-             $validStatus = !in_array($i->getHeader()->getStatus()->getKey(), [OrderStatus::PENDING_PAYMENT, OrderStatus::CANCELED, OrderStatus::NOT_SOLD]);
-             $validDate   = $i->getCreatedAt() > $this->getOfferLaunchDate();
-             
-             return $validStatus && $validDate;
-         });
-     }
-     public function getPendingOrderDetailsQuantity(): int
-     {
-         return $this->getOrderDetails()->reduce(function($acc, $item) {
-             if (in_array($item->getHeader()->getStatus()->getKey(), [OrderStatus::MONEY_WITHHELD, OrderStatus::BANK_TRANSFER])) {
-                 $acc += $item->getQuantity();
-             }
-             return $acc;
-         }, 0);
-     }
-     public function getNumberOfOrders(): ?int
-     {
-         $ordersById = [];
-         /** @var OrderDetail */
-         foreach ($this->orderDetails as $orderDetail) {
-             if (
-                 $orderDetail->getHeader()->getStatus()->getKey() == OrderStatus::PENDING_PAYMENT ||
-                 $orderDetail->getHeader()->getStatus()->getKey() == OrderStatus::CANCELED ||
-                 $orderDetail->getHeader()->getStatus()->getKey() == OrderStatus::NOT_SOLD
-             ) {
-                 continue;
-             }
-             array_push($ordersById, [$orderDetail->getHeader()->getId() => $orderDetail]);
-         }
-         return count($ordersById);
-     }
-     public function getOriginalPrice(): ?float
-     {
-         return $this->originalPrice;
-     }
-     public function setOriginalPrice(?float $originalPrice): self
-     {
-         $this->originalPrice = $originalPrice;
-         return $this;
-     }
-     public function getFakeUsers(): ?int
-     {
-         return $this->fakeUsers;
-     }
-     public function setFakeUsers(?int $fakeUsers): self
-     {
-         $this->fakeUsers = $fakeUsers;
-         return $this;
-     }
-     /**
-      * @return Collection<int, User>
-      */
-     public function getFakeTriweersInOffer(): Collection
-     {
-         return $this->fakeTriweersInOffer;
-     }
-     public function addFakeTriweersInOffer(User $user): self
-     {
-         if (!$this->fakeTriweersInOffer->contains($user)) {
-             $this->fakeTriweersInOffer[] = $user;
-         }
-         return $this;
-     }
-     public function removeFakeTriweersInOffer(User $user): self
-     {
-         $this->fakeTriweersInOffer->removeElement($user);
-         return $this;
-     }
-     /**
-      * Calculate discount percentage dynamically based on field values
-      *
-      * @return float|null
-      */
-     public function getDiscountPercentage(): ?float 
-     {
-         if ($this->getUnitsPerBoxGrouped() > 0) {
-             $originalUnitPrice = $this->originalPrice / ($this->getUnitsPerBox() ?? 1);
-             $sharedUnitPrice = $this->getNextPrice() / $this->getUnitsPerBoxGrouped();
-             return (100 - (100 * $sharedUnitPrice / $originalUnitPrice));
-         }
-         return (100 - (100 * $this->getNextPrice() / $this->originalPrice));
-     }
-     public function getCartSavings($hasGroup)
-     {
-         $finalPrice = $this->getNextPrice();
-         $saving     = 0;
-         if ($hasGroup) {
-             $originalUnitPrice = $this->getOriginalPrice() / $this->getUnitsPerBoxGrouped();
-             $unitPrice         = $finalPrice / $this->getUnitsPerBoxGrouped();
-             $saving            = ($this->getUnitsPerBoxGrouped() > 0)
-                 ? (100 - (100 * $unitPrice / $originalUnitPrice))
-                 : (100 - (100 * $finalPrice / $this->getOriginalPrice()));
-         } else {
-             $originalUnitPrice = $this->getOriginalPrice() / $this->getUnitsPerBox();
-             $unitPrice         = $finalPrice / $this->getUnitsPerBox();
-             $saving            = ($this->getUnitsPerBox() > 0)
-                  ? (100 - (100 * $unitPrice / $originalUnitPrice))
-                  : (100 - (100 * $finalPrice / $this->getOriginalPrice()));
-         }
-         return $saving;
-     }
-     /**
-      * Calculate max. discount percentage dynamically based on field values
-      *
-      * @return float|null
-      */
-     public function getMaxDiscountPercentage(): ?float
-     {
-         $lastScale = $this->getPriceScales()->last();
-         $originalUnitPrice = $this->originalPrice / $this->getUnitsPerBox();
-         $sharedUnitPrice = $lastScale->getFinalPrice() / ($this->getUnitsPerBoxGrouped() ?? 1);
-         return (100 - (100 * $sharedUnitPrice / $originalUnitPrice));
-     }
-     /**
-      * Calculate max. discount price dynamically based on field values
-      *
-      * @return float|null
-      */
-     public function getMaxDiscountUnitPrice(): ?float
-     {
-         $lastScale = $this->getPriceScales()->last();
-         $sharedUnitPrice = $lastScale->getFinalPrice() / ($this->getUnitsPerBoxGrouped() ?? 1);
-         return $sharedUnitPrice;
-     }
-     /**
-      * Calculate discount percentage for collective purchase dynamically based on field values
-      *
-      * @return float|null
-      */
-     public function getIndividualDiscountPercentage(): ?float
-     {
-         return (100 - (100 * $this->getIndividualPrice() / $this->originalPrice));
-     }
-     public function getNextDiscountPercentage(): ?float
-     {
-         if (count($this->getPriceScales()) > 1) {
-             return (100 - (100 * $this->getNextPrice() / $this->originalPrice));
-         } else {
-             // Return Discount relative to final price Scale if only 1 price
-             // scale is defined. #316
-             return (100 - (100 * $this->getLastPriceScale()->getFinalPrice() / $this->originalPrice));
-         };
-     }
-     public function getShippingCost(): ?float
-     {
-         return $this->getShipping() ? $this->getShipping()->getCostByKgs($this->weight) : null;
-     }
-     public function setShippingCost(?float $shippingCost): self
-     {
-         $this->shippingCost = $shippingCost;
-         return $this;
-     }
-     public function getHoldedId(): ?string
-     {
-         return $this->holdedId;
-     }
-     public function setHoldedId(?string $holdedId): self
-     {
-         $this->holdedId = $holdedId;
-         return $this;
-     }
-     /**
-      * @return Collection<int, UserShared>
-      */
-     public function getInfluencerShareds(): Collection
-     {
-         return $this->influencerShareds;
-     }
-     public function addInfluencerShared(UserShared $influencerShared): self
-     {
-         if (!$this->influencerShareds->contains($influencerShared)) {
-             $this->influencerShareds->add($influencerShared);
-             $influencerShared->setProduct($this);
-         }
-         return $this;
-     }
-     public function removeInfluencerShared(UserShared $influencerShared): self
-     {
-         if ($this->influencerShareds->removeElement($influencerShared)) {
-             // set the owning side to null (unless already changed)
-             if ($influencerShared->getProduct() === $this) {
-                 $influencerShared->setProduct(null);
-             }
-         }
-         return $this;
-     }
-     public function getProductUnique(): ?ProductUnique
-     {
-         return $this->productUnique;
-     }
-     public function setProductUnique(?ProductUnique $productUnique): self
-     {
-         $this->productUnique = $productUnique;
-         return $this;
-     }
-     public function isOnlyAdults(): ?bool
-     {
-         return $this->onlyAdults;
-     }
-     public function setOnlyAdults(bool $onlyAdults): self
-     {
-         $this->onlyAdults = $onlyAdults;
-         return $this;
-     }
-     public function getAmountForFreeShipping(): ?int
-     {
-         return $this->amountForFreeShipping;
-     }
-     public function setAmountForFreeShipping(?int $amountForFreeShipping): self
-     {
-         $this->amountForFreeShipping = $amountForFreeShipping;
-         return $this;
-     }
-     public function isBetterPrice(): ?bool
-     {
-         return $this->better_price;
-     }
-     public function setBetterPrice(?bool $better_price): self
-     {
-         $this->better_price = $better_price;
-         return $this;
-     }
-     public function getShipping(): ?Shipping
-     {
-         return $this->shipping;
-     }
-     public function setShipping(?Shipping $shipping): self
-     {
-         $this->shipping = $shipping;
-         return $this;
-     }
-     /**
-      * @return Collection<int, User>
-      */
-     public function getUserFavourites(): Collection
-     {
-         return $this->userFavourites;
-     }
-     /**
-      * Shuffles the collection
-      * 
-      * @return Collection<int, User>
-      */
-     public function getRandomUserFavourites(): Collection
-     {
-         $array = $this->userFavourites->toArray();
-         shuffle($array);
-         return new ArrayCollection($array);
-     }
-     /**
-      * @return Collection<int, Review>
-      */
-     public function getUserReviews(): Collection
-     {
-         return $this->userReviews;
-     }
-     public function getMetaTitle(): ?string
-     {
-         return $this->meta_title;
-     }
-     public function setMetaTitle(?string $meta_title): self
-     {
-         $this->meta_title = $meta_title;
-         return $this;
-     }
-     public function getMetaDescription(): ?string
-     {
-         return $this->meta_description;
-     }
-     public function setMetaDescription(?string $meta_description): self
-     {
-         $this->meta_description = $meta_description;
-         return $this;
-     }
-     public function isShowPrice(): ?bool
-     {
-         return $this->showPrice;
-     }
-     public function setShowPrice(?bool $showPrice): self
-     {
-         $this->showPrice = $showPrice;
-         return $this;
-     }
- }
-