<?php
namespace App\Entity;
use App\Entity\Enum\RegistrationOrigin;
use App\Entity\Enum\RegistrationStatus;
use App\Entity\Enum\TransactionStatus;
use App\Entity\Traits\Identifiable;
use App\Entity\Traits\Timestampable;
use App\Repository\RegistrationRepository;
use DateInterval;
use DateTimeImmutable;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: RegistrationRepository::class)]
class Registration
{
use Timestampable;
use Identifiable;
#[ORM\Column(type: 'string', length: 20, enumType: RegistrationStatus::class)]
private RegistrationStatus $status = RegistrationStatus::Prospect;
#[ORM\Column(type: 'boolean', nullable: true)]
private $hasTaxReceipt;
#[ORM\Column(type: 'boolean', nullable: true)]
private $hasCompanyReceipt;
#[ORM\ManyToOne(targetEntity: Person::class, inversedBy: 'registrations', cascade: ['persist'])]
#[ORM\JoinColumn(nullable: false)]
private $person;
#[ORM\ManyToOne(targetEntity: Person::class, inversedBy: 'signedRegistrations')]
private $signatory;
#[ORM\ManyToMany(targetEntity: Slot::class, inversedBy: 'registrations')]
private $slots;
#[ORM\ManyToOne(targetEntity: Lesson::class, inversedBy: 'registrations')]
private $lesson;
#[ORM\ManyToOne(targetEntity: Season::class, inversedBy: 'registrations')]
#[ORM\JoinColumn(nullable: false)]
private $season;
#[ORM\OneToOne(mappedBy: 'registration', targetEntity: Order::class, cascade: ['persist', 'remove'])]
private $order;
#[ORM\ManyToMany(targetEntity: Lesson::class)]
#[ORM\JoinTable(name: 'registration_proposed_lesson')]
private $proposedLessons;
#[ORM\ManyToMany(targetEntity: Slot::class, inversedBy: 'registrationPropositions')]
#[ORM\JoinTable(name: 'registration_proposed_slot')]
private $proposedSlots;
#[ORM\Column(type: 'smallint', nullable: true)]
private $validationStep = 1;
#[ORM\Column(type: 'integer', nullable: true)]
private $oldId;
#[ORM\OneToMany(mappedBy: 'registration', targetEntity: Document::class, cascade: ['remove'])]
private $documents;
#[ORM\Column(type: 'smallint')]
private $reminder = 0;
#[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)]
private ?\DateTimeInterface $lastReminder = null;
#[ORM\Column(type: 'string', length: 100, enumType: RegistrationOrigin::class)]
private $origin = RegistrationOrigin::Frontoffice;
public function __construct()
{
$this->slots = new ArrayCollection();
$this->proposedLessons = new ArrayCollection();
$this->proposedSlots = new ArrayCollection();
$this->setOrder(new Order());
$this->documents = new ArrayCollection();
}
public function getStatus(): ?RegistrationStatus
{
return $this->status;
}
public function setStatus(RegistrationStatus $status): self
{
$this->status = $status;
return $this;
}
public function getSignatory(): ?Person
{
return $this->signatory;
}
public function setSignatory(?Person $signatory): self
{
$this->signatory = $signatory;
return $this;
}
public function getHasTaxReceipt(): ?bool
{
return $this->hasTaxReceipt;
}
public function setHasTaxReceipt(bool $hasTaxReceipt): self
{
$this->hasTaxReceipt = $hasTaxReceipt;
return $this;
}
public function getHasCompanyReceipt(): ?bool
{
return $this->hasCompanyReceipt;
}
public function setHasCompanyReceipt(bool $hasCompanyReceipt): self
{
$this->hasCompanyReceipt = $hasCompanyReceipt;
return $this;
}
/**
* @return Collection<int, Slot>
*/
public function getSlots(): Collection
{
return $this->slots;
}
public function addSlot(Slot $slot): self
{
if (!$this->slots->contains($slot)) {
$this->slots[] = $slot;
$slot->addRegistration($this);
}
return $this;
}
public function removeSlot(Slot $slot): self
{
if ($this->slots->removeElement($slot)) {
$slot->removeRegistration($this);
}
return $this;
}
public function getPerson(): ?Person
{
return $this->person;
}
public function setPerson(?Person $person): self
{
$this->person = $person;
return $this;
}
public function getSeason(): ?Season
{
return $this->season;
}
public function setSeason(?Season $season): self
{
$this->season = $season;
return $this;
}
public function getOrder(): ?Order
{
return $this->order;
}
public function setOrder(?Order $order): self
{
// unset the owning side of the relation if necessary
if ($order === null && $this->order !== null) {
$this->order->setRegistration(null);
}
// set the owning side of the relation if necessary
if ($order !== null && $order->getRegistration() !== $this) {
$order->setRegistration($this);
}
$this->order = $order;
return $this;
}
/**
* @return Collection<int, Lesson>
*/
public function getProposedLessons(): Collection
{
return $this->proposedLessons;
}
public function addProposedLesson(Lesson $proposedLesson): self
{
if (!$this->proposedLessons->contains($proposedLesson)) {
$this->proposedLessons[] = $proposedLesson;
}
return $this;
}
public function removeProposedLesson(Lesson $proposedLesson): self
{
$this->proposedLessons->removeElement($proposedLesson);
return $this;
}
/**
* @return Collection<int, Slot>
*/
public function getProposedSlots(): Collection
{
return $this->proposedSlots;
}
public function addProposedSlot(Slot $proposedSlot): self
{
if (!$this->proposedSlots->contains($proposedSlot)) {
$this->proposedSlots[] = $proposedSlot;
}
return $this;
}
public function removeProposedSlot(Slot $proposedSlot): self
{
$this->proposedSlots->removeElement($proposedSlot);
return $this;
}
public function getLesson(): ?Lesson
{
return $this->lesson;
}
public function setLesson(?Lesson $lesson): self
{
$this->lesson = $lesson;
return $this;
}
public function getValidationStep(): ?int
{
return $this->validationStep;
}
public function setValidationStep(?int $validationStep): self
{
$this->validationStep = $validationStep;
return $this;
}
public static function unaffectLessonsAndSlots(self $registration): self
{
$registration->setLesson(null);
$registration->getSlots()->clear();
return $registration;
}
public function getSection(): ?Section
{
return $this->getSeason()?->getSection();
}
public function getOldId(): ?int
{
return $this->oldId;
}
public function setOldId(?int $oldId): self
{
$this->oldId = $oldId;
return $this;
}
/**
* @return Collection<int, Document>
*/
public function getDocuments(bool $activeVersionOnly = false): Collection
{
$documents = $this->documents;
if ($activeVersionOnly) {
$finalArray = [];
$models = [];
$documentsArray = array_reverse($documents->toArray());
/** @var Document $item */
foreach ($documentsArray as $item) {
$modelId = $item->getModel()?->getId();
if ($modelId) {
if (!in_array($modelId, $models, true)) {
$models[] = $modelId;
$finalArray[] = $item;
}
} else {
$finalArray[] = $item;
}
}
return new ArrayCollection(array_reverse($finalArray));
}
return $documents;
}
public function addDocument(Document $document): self
{
if (!$this->documents->contains($document)) {
$this->documents[] = $document;
$document->setRegistration($this);
}
return $this;
}
public function removeDocument(Document $document): self
{
if ($this->documents->removeElement($document)) {
// set the owning side to null (unless already changed)
if ($document->getRegistration() === $this) {
$document->setRegistration(null);
}
}
return $this;
}
/**
* @param bool $includeRentals
* @param bool $linkDocuments
* @return Collection<int, DocumentModel>
*/
public function getRemainingDocumentModels(bool $includeRentals = true, bool $linkDocuments = false, bool $removeAdminOnly = false): Collection
{
/** @var Collection<int, DocumentModel> $models */
$models = new ArrayCollection();
$cart = $this->getOrder()?->getCart();
foreach ($cart->getDiscounts() as $itemDiscount) {
foreach ($itemDiscount->getDiscount()?->getModel()?->getDocumentModels() ?? [] as $model) {
if ($model->getSeason()->getGlobalSeason()->getId() ===
$this->getSeason()->getGlobalSeason()->getId()) {
$models->add($model);
}
}
}
foreach ($this->getSeason()?->getDocumentModels(false) ?? [] as $model) {
if (($this->getPerson()->isMinor() && $model->getIsForMinor()) ||
(!$this->getPerson()->isMinor() && $model->getIsForAdult())) {
$models->add($model);
}
}
// Remove all models that are for admins only
if ($removeAdminOnly) {
foreach ($models as $model) {
if ($model->isAdminOnly()) {
$models->removeElement($model);
}
}
}
if ($linkDocuments) {
foreach ($models as $model) {
foreach ($this->getDocuments() as $document) {
if ($document->getModel() === $model) {
$model->addLinkedDocument($document);
}
}
}
}
return $models;
}
public function getReminder(): ?int
{
return $this->reminder;
}
public function setReminder(int $reminder): self
{
$this->reminder = $reminder;
return $this;
}
public function getLastReminder(): ?\DateTimeInterface
{
return $this->lastReminder;
}
public function setLastReminder(?\DateTimeInterface $lastReminder): self
{
$this->lastReminder = $lastReminder;
return $this;
}
public function getDiffSinceLastReminder(): ?DateInterval
{
$reminder = $this->getLastReminder() ?? $this->getUpdatedAt() ?? new DateTimeImmutable();
$now = new DateTimeImmutable();
return $reminder->diff($now);
}
public function getOrigin(): ?RegistrationOrigin
{
return $this->origin;
}
public function setOrigin(RegistrationOrigin $origin): self
{
$this->origin = $origin;
return $this;
}
public function guessPaymentType($printable = false): ?string
{
$transaction = $this->getOrder()->getTransactions(statuses: [
TransactionStatus::Created,
TransactionStatus::Waiting,
TransactionStatus::Successful,
])->first();
if ($transaction) {
$class = get_class($transaction);
if ($printable && Transaction::getNameByClass($class)) {
return Transaction::getNameByClass($class);
}
return $class;
}
return null;
}
public function __clone()
{
$this->uuid = null;
$this->id = null;
$this->__construct();
$this->status = RegistrationStatus::Prospect;
$this->hasTaxReceipt = null;
$this->hasCompanyReceipt = null;
$this->signatory = null;
$this->lesson = null;
$this->season = null;
$this->validationStep = 1;
$this->reminder = 0;
$this->createdAt = null;
$this->updatedAt = null;
}
}