<?php
namespace App\Entity;
use App\Entity\History\Code\ChangeCarteCadeau;
use App\Entity\History\Code\UpdateCarteCadeauHistory;
use App\Entity\Payment\EmptyPayment;
use App\Enum\TemplateCarteCadeau;
use App\Repository\CodeRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\PersistentCollection;
use App\Entity\History\Code\CarteCadeauHistory;
/**
* @ORM\Entity(repositoryClass=CodeRepository::class)
*/
class Code
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $Type;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $Offer;
/**
* @ORM\Column(type="integer", nullable=true)
*/
private $Solo;
/**
* @ORM\Column(type="integer", nullable=true)
*/
private $Duo;
/**
* @ORM\Column(type="datetime")
*/
private $validity;
/**
* @ORM\Column(type="string", length=255)
*/
private $Value;
/**
* @ORM\Column(type="boolean")
*/
private $used;
/**
* @ORM\Column(type="integer", nullable=true)
*/
private $max_used;
/**
* @ORM\Column(type="integer", nullable=true)
*/
private $count_used;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $services;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $comment;
/**
* @ORM\Column(type="string", length=255, enumType=TemplateCarteCadeau::class)
*/
private TemplateCarteCadeau $templateCarteCadeau;
/**
* @ORM\OneToMany(targetEntity=Token::class, mappedBy="codePromo", cascade={"persist", "remove"})
*/
private $token;
/**
* @ORM\Column(type="boolean", nullable=true)
*/
private $physicalCard;
/**
* @ORM\OneToOne(targetEntity=DeliveryAddress::class, inversedBy="code", cascade={"persist", "remove"})
*/
private $deliveryAddress;
/**
* @ORM\Column(type="float", nullable=true)
*/
private $resteAPayer;
/**
* @ORM\ManyToOne(targetEntity=Reservation::class, inversedBy="createdCodes")
*/
private $createdFromReservation;
/**
* @ORM\OneToMany(targetEntity=CarteCadeauHistory::class, mappedBy="code", cascade={"remove"})
*/
private $carteCadeauHistories;
/**
* @ORM\Column(type="datetime", nullable=true)
*/
private $createdAt;
/**
* Constructor
*/
public function __construct()
{
$now = new \DateTime('now');
$this->used = false;
$this->validity = $now->modify('+1 year')->setTime(23, 59, 59);
$this->Value = str_replace(['O', '0', 'o'], 'X', strtoupper(substr(str_repeat(md5(rand()), ceil(6/32)), 0, 6)));
// $this->Value = strtoupper(rtrim(strtr(base64_encode(random_bytes(5)), '+/', '-_'), '='));
}
public function getId(): ?int
{
return $this->id;
}
public function getType(): ?string
{
return $this->Type;
}
public function setType(string $Type): self
{
$this->Type = $Type;
return $this;
}
public function getOffer(): ?string
{
return $this->Offer;
}
public function setOffer(?string $Offer): self
{
$this->Offer = $Offer;
return $this;
}
public function getSolo(): ?int
{
return $this->Solo;
}
public function setSolo(?int $Solo): self
{
$this->Solo = $Solo;
return $this;
}
public function getDuo(): ?int
{
return $this->Duo;
}
public function setDuo(?int $Duo): self
{
$this->Duo = $Duo;
return $this;
}
public function getValidity(): ?\DateTimeInterface
{
return $this->validity;
}
public function getOriginalValidity(): ?\DateTimeInterface
{
$validityHistories = new ArrayCollection();
foreach($this->carteCadeauHistories as $carteCadeauHistory) {
if ($carteCadeauHistory instanceof UpdateCarteCadeauHistory) {
foreach ($carteCadeauHistory->getChangeCarteCadeaux() as $changeCarteCadeau) {
if ($changeCarteCadeau->getField() == "validity") {
$validityHistories->add($carteCadeauHistory);
}
}
}
}
// If no history exists, current validity is the original
if ($validityHistories->isEmpty()) {
return $this->validity;
}
// Sort histories by creation date (oldest first)
$iterator = $validityHistories->getIterator();
$iterator->uasort(function ($a, $b) {
return $a->getCreatedAt() <=> $b->getCreatedAt();
});
$sortedHistories = new ArrayCollection(iterator_to_array($iterator));
// Get the first history entry (oldest change)
$oldestHistory = $sortedHistories->first();
// Get the old value from the change record
foreach ($oldestHistory->getChangeCarteCadeaux() as $change) {
if ($change->getField() == "validity") {
return new \DateTime($change->getOldValue());
}
}
// Fallback to current validity if something went wrong
return $this->validity;
}
public function getValidityFormated($modifier = null): string
{
$months = [
'January' => 'janvier',
'February' => 'février',
'March' => 'mars',
'April' => 'avril',
'May' => 'mai',
'June' => 'juin',
'July' => 'juillet',
'August' => 'août',
'September' => 'septembre',
'October' => 'octobre',
'November' => 'novembre',
'December' => 'décembre'
];
$date = clone $this->validity;
if ($modifier) {
$date = $date->modify($modifier);
}
$day = $date->format('d'); // Day of the month
$monthName = $months[$date->format('F')]; // Full month name
$year = $date->format('Y'); // Year
// Combine the formatted string
$formattedDate = "$day $monthName $year";
return $formattedDate;
}
public function setValidity(\DateTimeInterface $validity): self
{
$this->validity = $validity;
return $this;
}
public function isExpired(): bool
{
return $this->getValidity() < new \DateTime('now');
}
public function getValue(): ?string
{
return $this->Value;
}
public function setValue(string $Value): self
{
$this->Value = $Value;
return $this;
}
public function getUsed(): ?bool
{
return $this->used;
}
public function setUsed(bool $used): self
{
$this->used = $used;
return $this;
}
public function getMaxUsed(): ?int
{
return $this->max_used;
}
public function setMaxUsed(?int $max_used): self
{
$this->max_used = $max_used;
return $this;
}
public function getCountUsed(): ?int
{
return $this->count_used;
}
public function setCountUsed(?int $count_used): self
{
$this->count_used = $count_used;
return $this;
}
public function getServices()
{
if($this->services) {
return json_decode($this->services);
} else {
return [];
}
}
public function setServices($services): self
{
$this->services = $services;
return $this;
}
public function getComment(): ?string
{
return $this->comment;
}
public function setComment(?string $comment): self
{
$this->comment = $comment;
return $this;
}
public function getTemplateCarteCadeau(): TemplateCarteCadeau
{
return $this->templateCarteCadeau;
}
public function setTemplateCarteCadeau(TemplateCarteCadeau $templateCarteCadeau): self
{
$this->templateCarteCadeau = $templateCarteCadeau;
return $this;
}
public function getTokens(): PersistentCollection
{
$this->token->initialize();
$iterator = $this->token->getIterator();
$iterator->uasort(function ($a, $b) {
return $b->getId() <=> $a->getId();
});
return $this->token;
}
public function getToken(): Token|null
{
if (!$this->token) {
return null;
}
if ($this->token->isEmpty()) {
return null;
}
// Get the criteria to sort by creation date if it exists, otherwise by ID
$criteria = Criteria::create()
->orderBy(['created' => 'ASC'])
->setMaxResults(1);
return $this->token->matching($criteria)->first() ?: $this->token->first();
}
public function getContact(): Contact|null
{
if (!$this->getToken()) {
return null;
}
$contact = $this->getToken()->getContact();
if (!$contact) {
foreach($this->getTokens() as $token) {
if ($token->getContact()) {
$contact = $token->getContact();
break;
}
}
}
return $contact;
}
public function setToken(?Token $token): self
{
// unset the owning side of the relation if necessary
if ($token === null && $this->token !== null) {
$this->token->setCodePromo(null);
}
// set the owning side of the relation if necessary
if ($token !== null && $token->getCodePromo() !== $this) {
$token->setCodePromo($this);
}
$this->token = $token;
return $this;
}
public function isPhysicalCard(): ?bool
{
return $this->physicalCard;
}
public function setPhysicalCard(?bool $physicalCard): self
{
$this->physicalCard = $physicalCard;
return $this;
}
public function getDeliveryAddress(): ?DeliveryAddress
{
return $this->deliveryAddress;
}
public function setDeliveryAddress(?DeliveryAddress $deliveryAddress): self
{
$this->deliveryAddress = $deliveryAddress;
return $this;
}
public function getResteAPayer(): ?float
{
return $this->resteAPayer ?? 0;
}
public function setResteAPayer(?float $resteAPayer): self
{
$this->resteAPayer = $resteAPayer;
return $this;
}
public function getCreatedFromReservation(): ?Reservation
{
return $this->createdFromReservation;
}
public function setCreatedFromReservation(?Reservation $createdFromReservation): self
{
$this->createdFromReservation = $createdFromReservation;
return $this;
}
public function getAllHistories(): array
{
$histories = new ArrayCollection();
foreach($this->getCarteCadeauHistories() as $history) {
$histories->add($history);
}
foreach($this->getToken()->getPayments() as $payment) {
if (!$payment instanceof EmptyPayment) {
$histories->add($payment);
}
// foreach($payment->getPaymentHistories() as $history) {
// $histories->add($history->getPayment());
// }
}
// sort by createdAt
$histories = $histories->toArray();
usort($histories, function($a, $b) {
return $b->getCreatedAt() <=> $a->getCreatedAt();
});
return $histories;
}
/**
* @return Collection<int, CarteCadeauHistory>
*/
public function getCarteCadeauHistories(): Collection
{
return $this->carteCadeauHistories;
}
public function addCarteCadeauHistory(CarteCadeauHistory $carteCadeauHistory): self
{
if (!$this->carteCadeauHistories->contains($carteCadeauHistory)) {
$this->carteCadeauHistories[] = $carteCadeauHistory;
$carteCadeauHistory->setCode($this);
}
return $this;
}
public function removeCarteCadeauHistory(CarteCadeauHistory $carteCadeauHistory): self
{
$this->carteCadeauHistories->removeElement($carteCadeauHistory);
return $this;
}
public function getCreatedAt(): ?\DateTimeInterface
{
return $this->createdAt;
}
public function setCreatedAt(?\DateTimeInterface $createdAt): self
{
$this->createdAt = $createdAt;
return $this;
}
/**
* Get the current status of the carte cadeau based on business rules
* @return string The status constant from CarteCadeauStatus
*/
public function getStatus(): string
{
if ($this->isExpired()) {
return CarteCadeauStatus::EXPIRE;
}
if ($this->getUsed()) {
return CarteCadeauStatus::UTILISE;
}
if ($this->getResteAPayer() && $this->getResteAPayer() != 0) {
return CarteCadeauStatus::INACTIF;
}
return CarteCadeauStatus::NON_UTILISE;
}
/**
* Get the human-readable label for the current status
* @return string The French label for the status
*/
public function getStatusLabel(): string
{
return CarteCadeauStatus::getLabel($this->getStatus());
}
/**
* Get the CSS class for the current status
* @return string The CSS class name for styling
*/
public function getStatusCssClass(): string
{
return CarteCadeauStatus::getCssStatusClass($this->getStatus());
}
}