<?php
namespace App\Entity;
use App\Repository\SaleOrderItemRepository;
use App\Traits\DateTrait;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as Serializer;
use JMS\Serializer\Annotation\Expose;
use JMS\Serializer\Annotation\Groups;
use JMS\Serializer\Annotation\SerializedName;
/**
* @ORM\Table(indexes={
* @ORM\Index(columns={"status"})
* })
* @ORM\Entity(repositoryClass=SaleOrderItemRepository::class)
*
* @Serializer\ExclusionPolicy("ALL")
*/
class SaleOrderItem
{
use DateTrait;
public const TYPE_EVASION = 'evasion';
public const TYPE_SHOPPING = 'shopping';
public const TYPE_COFFRET = 'coffret';
public const STATUS_PROCESSING = 'processing';
public const STATUS_NOT_CONFIRMED = 'not_confirmed';
public const STATUS_CANCELED = 'canceled';
public const STATUS_SHIPPED = 'shipped';
// Liste des statuts des commandes que l'on envoie au BO pour la synchronisation
public const ALL_STATUS = [
self::STATUS_PROCESSING,
self::STATUS_NOT_CONFIRMED,
self::STATUS_CANCELED,
self::STATUS_SHIPPED,
];
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*
* @Expose
* @Groups({"get:read", "sale_oder_item:list"})
*/
private ?int $id = NULL;
/**
* Identifiant unique
*
* @ORM\Column(type="string", length=255)
*
* @Expose
* @Groups({"sale_order:item", "sale_oder_item:list", "sale_order:post", "get:read"})
*/
private ?string $sku = NULL;
/**
* Anciennement '$order' mais c'est un mot reservé (mysql) on ne peut plus l'utiliser
*
* @ORM\ManyToOne(targetEntity=SaleOrder::class, inversedBy="items")
* @ORM\JoinColumn(nullable=false, name="order_id")
*/
private ?SaleOrder $saleOrder = NULL;
/**
* Quantité
*
* @ORM\Column(type="integer")
*
* @Expose
* @Groups({"sale_order:item", "sale_oder_item:list", "sale_order:post", "get:read","export_order_datatable"})
*/
private ?int $quantity = NULL;
/**
* @ORM\Column(type="integer", nullable=true)
*
* @Expose
* @Groups({"sale_order:item", "sale_oder_item:list","get:read"})
*/
private ?int $quantityNoBatch = NULL;
/**
* @ORM\Column(type="string", length=100, options={"default":self::STATUS_PROCESSING})
*
* @Expose
* @Groups({"get:read", "sale_oder_item:list"})
*/
private string $status = self::STATUS_PROCESSING;
/**
* @ORM\Column(type="string", length=255)
*
* @Expose
* @Groups({"get:read"})
*/
private ?string $reference = NULL;
/**
* @ORM\Column(type="string", length=255)
*
* @Expose
* @Groups({"sale_order:item", "sale_oder_item:list", "get:read","export_order_datatable"})
*/
private ?string $name = NULL;
/**
* @ORM\Column(type="text", nullable=true)
*
* @Expose
* @Groups({"get:read"})
*/
private ?string $description = NULL;
/**
* @ORM\Column(type="string", length=255)
*
* @Expose
* @Groups({"get:read", "sale_oder_item:list"})
*/
private ?string $gamme = NULL;
/**
* @ORM\Column(type="decimal", precision=12, scale=4, nullable=true)
*
* @Expose
* @Groups({"get:read", "sale_oder_item:list"})
* @SerializedName ("price_h_t")
*/
private ?string $priceHT = NULL;
/**
* @ORM\Column(type="decimal", precision=12, scale=4, nullable=true)
*/
private ?string $priceTTC = NULL;
/**
* @ORM\Column(type="decimal", precision=12, scale=4, nullable=true)
*/
private ?string $unitPoint = NULL;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*
* @Expose
* @Groups({"get:read"})
*/
private ?string $imageUrl = NULL;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private ?string $imageThumbnailUrl = NULL;
/**
* @ORM\Column(type="decimal", precision=12, scale=4, nullable=true)
*
* @Expose
* @Groups({"get:read"})
*/
private ?string $taxableAmount = NULL;
/**
* @ORM\OneToMany(targetEntity=SaleOrderParticipant::class, mappedBy="saleOrderItem", cascade={"persist","remove"}, orphanRemoval=true)
* @Expose
* @Groups({"sale_order:item", "sale_order:post", "get:read", "export_order_datatable"})
*/
private ?Collection $participants = null;
/**
* @ORM\OneToMany(targetEntity=SaleOrderItemOption::class, mappedBy="item")
*/
private ?Collection $options = null;
/**
* @ORM\Column(type="text", nullable=true)
*/
private ?string $categoryValues;
/**
* @ORM\Column(type="text", nullable=true)
*/
private ?string $totalChosenCategoryValues;
/**
* @ORM\Column(type="datetime", nullable=true)
* @Expose
* @Groups({"get:read"})
*/
private $wishDateEvasion;
/**
* @ORM\Column(type="float", nullable=true)
*/
private $weight;
/**
* @ORM\Column(type="boolean", options={"default":true}) nullable=false)
*
* @Expose
* @Groups({"get:read", "sale_oder_item:list"})
*/
private ?bool $isRefundable = true;
/**
*
* @ORM\Column(type="boolean", options={"default":false}) nullable=true)
*
* @Expose
* @Groups({"get:read", "sale_oder_item:list"})
*/
private ?bool $isReplaced = false;
/**
* @ORM\OneToMany(targetEntity=PointTransaction::class, mappedBy="saleOrderItem", cascade={"persist"})
*/
//On lie un SaleOrderItem a une transaction seulement à l'annulation, pour pouvoir lier un remboursement a un produit
private Collection $pointTransactions;
/**
* @ORM\OneToOne(targetEntity=SaleOrderShipmentItem::class, mappedBy="saleOrderItem", cascade={"persist", "remove"})
*/
private $saleOrderShipmentItem;
/**
* @ORM\OneToOne(targetEntity=SaleOrderItem::class, cascade={"persist", "remove"})
*/
private $replaceItem;
/**
* @ORM\Column(type="integer", nullable=true)
*/
private $boId;
public function __construct()
{
$this->categoryValues = '';
$this->totalChosenCategoryValues = '';
$this->participants = new ArrayCollection();
$this->options = new ArrayCollection();
$this->pointTransactions = new ArrayCollection();
}
public function __clone()
{
if ($this->id) {
$this->setId(NULL);
$this->setSaleOrder(NULL);
}
}
public function __toString()
{
return $this->getSku();
}
/*
* ============================================================================================
* =============================== FONCTIONS CUSTOM ===========================================
* ============================================================================================
*/
public function getSku(): ?string
{
return $this->sku;
}
public function setSku(?string $sku): self
{
$this->sku = $sku;
return $this;
}
/**
* @Serializer\VirtualProperty()
* @Serializer\SerializedName("array_category_values")
*/
public function getArrayCategoryValues()
{
return json_decode($this->categoryValues, TRUE) ?? [];
}
/**
* @Serializer\VirtualProperty()
* @Serializer\SerializedName("array_total_chosen_category_values")
*/
public function getArrayTotalChosenCategoryValues()
{
return json_decode($this->totalChosenCategoryValues, TRUE) ?? [];
}
/**
* @param string $slug
* @param int $value
*
* @return $this
*/
public function modifyValueToCategory(string $slug, int $value): self
{
$newArray = $this->getArrayCategoryValues();
$newArray[ $slug ] = $value;
$this->categoryValues = json_encode($newArray);
return $this;
}
/**
* @param float $multiplication
*
* @return $this
*/
public function multiplicationCategoryValues(float $multiplication): self
{
$newArray = $this->getArrayCategoryValues();
foreach ($newArray as $cat => $val) {
$newArray[ $cat ] = $val * $multiplication;
}
$this->categoryValues = json_encode($newArray);
return $this;
}
/*
* ============================================================================================
* ============================== FIN FONCTIONS CUSTOM ========================================
* ============================================================================================
*/
public function getTotalPrice()
{
$quantity = $this->getQuantity() ?? 1;
$price = $this->getPriceHT() ?? 0;
return $price * $quantity;
}
public function getQuantity(): ?int
{
return $this->quantity;
}
public function setQuantity(int $quantity): self
{
$this->quantity = $quantity;
return $this;
}
public function getPriceHT(): ?string
{
return $this->priceHT;
}
public function setPriceHT(?string $priceHT): self
{
$this->priceHT = $priceHT;
return $this;
}
public function getTotalPoint()
{
$unitPoint = $this->getUnitPoint() ?? 0;
$quantity = $this->getQuantity() ?? 1;
return $unitPoint * $quantity;
}
public function setId($id)
{
$this->id = $id;
}
public function getId(): ?int
{
return $this->id;
}
public function getQuantityNoBatch(): ?int
{
return $this->quantityNoBatch;
}
public function setQuantityNoBatch(?int $quantityNoBatch): self
{
$this->quantityNoBatch = $quantityNoBatch;
return $this;
}
public function getStatus(): string
{
return $this->status;
}
public function setStatus(string $status): self
{
$this->status = $status;
return $this;
}
public function getReference(): ?string
{
return $this->reference;
}
public function setReference(?string $reference): self
{
$this->reference = $reference;
return $this;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(?string $name): self
{
$this->name = $name;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): self
{
$this->description = $description;
return $this;
}
public function getGamme(): ?string
{
return $this->gamme;
}
public function setGamme(?string $gamme): self
{
$this->gamme = $gamme;
return $this;
}
public function getPriceTTC(): ?string
{
return $this->priceTTC;
}
public function setPriceTTC(?string $priceTTC): self
{
$this->priceTTC = $priceTTC;
return $this;
}
public function getUnitPoint(): ?string
{
return $this->unitPoint;
}
public function setUnitPoint(?string $unitPoint): self
{
$this->unitPoint = $unitPoint;
return $this;
}
public function getImageUrl(): ?string
{
return $this->imageUrl;
}
public function setImageUrl(?string $imageUrl): self
{
$this->imageUrl = $imageUrl;
return $this;
}
public function getImageThumbnailUrl(): ?string
{
return $this->imageThumbnailUrl;
}
public function setImageThumbnailUrl(?string $imageThumbnailUrl): self
{
$this->imageThumbnailUrl = $imageThumbnailUrl;
return $this;
}
public function getTaxableAmount(): ?string
{
return $this->taxableAmount;
}
public function setTaxableAmount(?string $taxableAmount): self
{
$this->taxableAmount = $taxableAmount;
return $this;
}
public function getSaleOrder(): ?SaleOrder
{
return $this->saleOrder;
}
public function setSaleOrder(?SaleOrder $saleOrder): self
{
$this->saleOrder = $saleOrder;
return $this;
}
/**
* @return Collection|SaleOrderParticipant[]
*/
public function getParticipants(): Collection
{
if(!$this->participants) $this->participants = new ArrayCollection();
return $this->participants;
}
public function addParticipant(SaleOrderParticipant $participant): self
{
if (!$this->participants->contains($participant)) {
$this->participants[] = $participant;
$participant->setSaleOrderItem($this);
}
return $this;
}
public function removeParticipant(SaleOrderParticipant $participant): self
{
if ($this->participants->removeElement($participant)) {
// set the owning side to null (unless already changed)
if ($participant->getSaleOrderItem() === $this) {
$participant->setSaleOrderItem(NULL);
}
}
return $this;
}
/**
* @return Collection|SaleOrderItemOption[]
*/
public function getOptions(): Collection
{
if(!$this->options) $this->options = new ArrayCollection();
return $this->options;
}
public function addOption(SaleOrderItemOption $option): self
{
if (!$this->options->contains($option)) {
$this->options[] = $option;
$option->setItem($this);
}
return $this;
}
public function removeOption(SaleOrderItemOption $option): self
{
if ($this->options->removeElement($option)) {
// set the owning side to null (unless already changed)
if ($option->getItem() === $this) {
$option->setItem(NULL);
}
}
return $this;
}
public function getCategoryValues(): ?string
{
return $this->categoryValues;
}
public function setCategoryValues(?string $categoryValues): self
{
$this->categoryValues = $categoryValues;
return $this;
}
public function getTotalChosenCategoryValues(): ?string
{
return $this->totalChosenCategoryValues;
}
public function setTotalChosenCategoryValues(?string $totalChosenCategoryValues): self
{
$this->totalChosenCategoryValues = $totalChosenCategoryValues;
return $this;
}
public function getWishDateEvasion()
{
return $this->wishDateEvasion;
}
public function setWishDateEvasion($wishDateEvasion)
{
$this->wishDateEvasion = $wishDateEvasion;
}
public function getWeight(): ?float
{
return $this->weight;
}
public function setWeight(?float $weight): self
{
$this->weight = $weight;
return $this;
}
public function getIsRefundable(): ?bool
{
return $this->isRefundable;
}
public function setIsRefundable(?bool $isRefundable): self
{
$this->isRefundable = $isRefundable;
return $this;
}
public function getisReplaced(): ?bool
{
return $this->isReplaced;
}
public function setisReplaced(?bool $isReplaced): self
{
$this->isReplaced = $isReplaced;
return $this;
}
public function getPointTransactions(): Collection
{
return $this->pointTransactions;
}
public function addPointTransaction(?PointTransaction $pointTransaction): self
{
if (!$this->pointTransactions->contains($pointTransaction)) {
$this->pointTransactions[] = $pointTransaction;
}
return $this;
}
public function removePointTransaction(?PointTransaction $pointTransaction): self
{
$this->pointTransactions->removeElement($pointTransaction);
return $this;
}
public function getSaleOrderShipmentItem(): ?SaleOrderShipmentItem
{
return $this->saleOrderShipmentItem;
}
public function setSaleOrderShipmentItem(SaleOrderShipmentItem $saleOrderShipmentItem): self
{
// set the owning side of the relation if necessary
if ($saleOrderShipmentItem->getSaleOrderItem() !== $this) {
$saleOrderShipmentItem->setSaleOrderItem($this);
}
$this->saleOrderShipmentItem = $saleOrderShipmentItem;
return $this;
}
public function getReplacedItem(): ?self
{
return $this->replaceItem;
}
public function setReplacedItem(?self $replaceItem): self
{
$this->replaceItem = $replaceItem;
return $this;
}
public function getOriginalRefundableItem(): ?self
{
$current = $this;
$visited = [$this->getId()]; // On marque le départ
while ($replaced = $current->getReplacedItem()) {
$replacedId = $replaced->getId();
// Protection anti-boucle : si on retombe sur un ID déjà vu, ABORT
if (in_array($replacedId, $visited, true)) {
return null; // Boucle circulaire détectée
}
$visited[] = $replacedId; // On marque comme traité
// Trouvé un item remboursable
if ($replaced->getIsRefundable()) {
return $replaced;
}
$current = $replaced; // On continue la remontée
}
// Bout de chaîne sans item remboursable
return null;
}
public function getBoId(): ?int
{
return $this->boId;
}
public function setBoId(?int $boId): self
{
$this->boId = $boId;
return $this;
}
}