src/Entity/SharedEventCode.php line 20

  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Entity;
  4. use App\Entity\User\EmailB2B;
  5. use App\Repository\SharedEventCodeRepository;
  6. use Doctrine\DBAL\Types\Types;
  7. use Doctrine\ORM\Mapping as ORM;
  8. use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
  9. use Symfony\Component\Validator\Constraints as Assert;
  10. /**
  11.  * Code événement partagé : même code pour tous les participants, période de validité, tarification paramétrable.
  12.  */
  13. #[ORM\Entity(repositoryClassSharedEventCodeRepository::class)]
  14. #[ORM\Table(name'app_shared_event_code')]
  15. #[UniqueEntity('code')]
  16. class SharedEventCode
  17. {
  18.     /** Fuseau métier pour les bornes début/fin (saisie BO + comparaison API). */
  19.     public const VALIDITY_TIMEZONE 'Europe/Paris';
  20.     public const PRICING_OFFERED 'offered';
  21.     public const PRICING_NORMAL 'normal';
  22.     public const PRICING_SPECIAL 'special';
  23.     public const FRAME_10X15 '10x15';
  24.     public const FRAME_15X10 '15x10';
  25.     #[ORM\Id]
  26.     #[ORM\GeneratedValue]
  27.     #[ORM\Column]
  28.     private ?int $id null;
  29.     #[ORM\Column(length50)]
  30.     #[Assert\NotBlank]
  31.     #[Assert\Length(min1max10)]
  32.     #[Assert\Regex(pattern'/^[A-Za-z0-9]+$/')]
  33.     private ?string $code null;
  34.     #[ORM\ManyToOne]
  35.     #[ORM\JoinColumn(nullabletrueonDelete'SET NULL')]
  36.     private ?EmailB2B $emailB2B null;
  37.     #[ORM\Column(length255)]
  38.     #[Assert\NotBlank]
  39.     private ?string $name null;
  40.     #[ORM\Column(length255)]
  41.     #[Assert\NotBlank]
  42.     private ?string $nameInApp null;
  43.     #[ORM\Column(length255nullabletrue)]
  44.     private ?string $companyName null;
  45.     #[ORM\Column(typeTypes::DATETIME_MUTABLE)]
  46.     #[Assert\NotNull]
  47.     private ?\DateTimeInterface $startAt null;
  48.     #[ORM\Column(typeTypes::DATETIME_MUTABLE)]
  49.     #[Assert\NotNull]
  50.     private ?\DateTimeInterface $endAt null;
  51.     #[ORM\Column(length8)]
  52.     #[Assert\Choice(choices: [self::FRAME_10X15self::FRAME_15X10])]
  53.     private string $frameFormat self::FRAME_10X15;
  54.     #[ORM\Column]
  55.     private int $size 12;
  56.     #[ORM\Column(length255)]
  57.     private string $country 'FR';
  58.     #[ORM\Column(length255)]
  59.     private string $filenameLogo '';
  60.     #[ORM\Column(length255nullabletrue)]
  61.     private ?string $filenameTemplate null;
  62.     #[ORM\Column(length255nullabletrue)]
  63.     private ?string $filenameTemplateVertical null;
  64.     #[ORM\Column(length255nullabletrue)]
  65.     private ?string $filenameAddonPhoto null;
  66.     #[ORM\Column(length20)]
  67.     #[Assert\Choice(choices: [self::PRICING_OFFEREDself::PRICING_NORMALself::PRICING_SPECIAL])]
  68.     private string $pricingType self::PRICING_OFFERED;
  69.     /** Prix produit TTC en centimes (hors port), utilisé si pricingType = special */
  70.     #[ORM\Column(nullabletrue)]
  71.     private ?int $specialPriceCents null;
  72.     /** Première fois qu’un participant a utilisé le code (rattachement B2B ou commande). */
  73.     #[ORM\Column(typeTypes::DATETIME_IMMUTABLEnullabletrue)]
  74.     private ?\DateTimeImmutable $firstUsedAt null;
  75.     public function getId(): ?int
  76.     {
  77.         return $this->id;
  78.     }
  79.     public function getCode(): ?string
  80.     {
  81.         return $this->code;
  82.     }
  83.     public function setCode(string $code): self
  84.     {
  85.         $this->code strtoupper(trim($code));
  86.         return $this;
  87.     }
  88.     public function getEmailB2B(): ?EmailB2B
  89.     {
  90.         return $this->emailB2B;
  91.     }
  92.     public function setEmailB2B(?EmailB2B $emailB2B): self
  93.     {
  94.         $this->emailB2B $emailB2B;
  95.         return $this;
  96.     }
  97.     public function getName(): ?string
  98.     {
  99.         return $this->name;
  100.     }
  101.     public function setName(string $name): self
  102.     {
  103.         $this->name $name;
  104.         return $this;
  105.     }
  106.     public function getNameInApp(): ?string
  107.     {
  108.         return $this->nameInApp;
  109.     }
  110.     public function setNameInApp(string $nameInApp): self
  111.     {
  112.         $this->nameInApp $nameInApp;
  113.         return $this;
  114.     }
  115.     public function getCompanyName(): ?string
  116.     {
  117.         return $this->companyName;
  118.     }
  119.     public function setCompanyName(?string $companyName): self
  120.     {
  121.         $this->companyName $companyName;
  122.         return $this;
  123.     }
  124.     public function getStartAt(): ?\DateTimeInterface
  125.     {
  126.         return $this->startAt;
  127.     }
  128.     public function setStartAt(\DateTimeInterface $startAt): self
  129.     {
  130.         $this->startAt $startAt;
  131.         return $this;
  132.     }
  133.     public function getEndAt(): ?\DateTimeInterface
  134.     {
  135.         return $this->endAt;
  136.     }
  137.     public function setEndAt(\DateTimeInterface $endAt): self
  138.     {
  139.         $this->endAt $endAt;
  140.         return $this;
  141.     }
  142.     public function getFrameFormat(): string
  143.     {
  144.         return $this->frameFormat;
  145.     }
  146.     public function setFrameFormat(string $frameFormat): self
  147.     {
  148.         $this->frameFormat $frameFormat;
  149.         return $this;
  150.     }
  151.     public function getSize(): int
  152.     {
  153.         return $this->size;
  154.     }
  155.     public function setSize(int $size): self
  156.     {
  157.         $this->size $size;
  158.         return $this;
  159.     }
  160.     public function getCountry(): string
  161.     {
  162.         return $this->country;
  163.     }
  164.     public function setCountry(string $country): self
  165.     {
  166.         $this->country $country;
  167.         return $this;
  168.     }
  169.     public function getFilenameLogo(): string
  170.     {
  171.         return $this->filenameLogo;
  172.     }
  173.     public function setFilenameLogo(string $filenameLogo): self
  174.     {
  175.         $this->filenameLogo $filenameLogo;
  176.         return $this;
  177.     }
  178.     public function getFilenameTemplate(): ?string
  179.     {
  180.         return $this->filenameTemplate;
  181.     }
  182.     public function setFilenameTemplate(?string $filenameTemplate): self
  183.     {
  184.         $this->filenameTemplate $filenameTemplate;
  185.         return $this;
  186.     }
  187.     public function getFilenameTemplateVertical(): ?string
  188.     {
  189.         return $this->filenameTemplateVertical;
  190.     }
  191.     public function setFilenameTemplateVertical(?string $filenameTemplateVertical): self
  192.     {
  193.         $this->filenameTemplateVertical $filenameTemplateVertical;
  194.         return $this;
  195.     }
  196.     public function getFilenameAddonPhoto(): ?string
  197.     {
  198.         return $this->filenameAddonPhoto;
  199.     }
  200.     public function setFilenameAddonPhoto(?string $filenameAddonPhoto): self
  201.     {
  202.         $this->filenameAddonPhoto $filenameAddonPhoto;
  203.         return $this;
  204.     }
  205.     public function getPricingType(): string
  206.     {
  207.         return $this->pricingType;
  208.     }
  209.     public function setPricingType(string $pricingType): self
  210.     {
  211.         $this->pricingType $pricingType;
  212.         return $this;
  213.     }
  214.     public function getSpecialPriceCents(): ?int
  215.     {
  216.         return $this->specialPriceCents;
  217.     }
  218.     public function setSpecialPriceCents(?int $specialPriceCents): self
  219.     {
  220.         $this->specialPriceCents $specialPriceCents;
  221.         return $this;
  222.     }
  223.     /**
  224.      * Les dates en base (DATETIME) et le formulaire admin sont interprétées comme heure locale France.
  225.      * Compare à l’instant courant dans ce même fuseau, pour éviter les décalages si PHP/serveur est en UTC.
  226.      */
  227.     public function isValidAt(?\DateTimeInterface $now null): bool
  228.     {
  229.         $start $this->startAt;
  230.         $end $this->endAt;
  231.         if ($start === null || $end === null) {
  232.             return false;
  233.         }
  234.         $tz = new \DateTimeZone(self::VALIDITY_TIMEZONE);
  235.         $startParis = new \DateTimeImmutable($start->format('Y-m-d H:i:s'), $tz);
  236.         $endParis = new \DateTimeImmutable($end->format('Y-m-d H:i:s'), $tz);
  237.         $nowParis $now === null
  238.             ? new \DateTimeImmutable('now'$tz)
  239.             : \DateTimeImmutable::createFromInterface($now)->setTimezone($tz);
  240.         return $startParis <= $nowParis && $nowParis <= $endParis;
  241.     }
  242.     public function getFirstUsedAt(): ?\DateTimeImmutable
  243.     {
  244.         return $this->firstUsedAt;
  245.     }
  246.     public function setFirstUsedAt(?\DateTimeImmutable $firstUsedAt): self
  247.     {
  248.         $this->firstUsedAt $firstUsedAt;
  249.         return $this;
  250.     }
  251.     /** Enregistre la première utilisation (idempotent). */
  252.     public function markFirstUseIfUnset(): void
  253.     {
  254.         if ($this->firstUsedAt !== null) {
  255.             return;
  256.         }
  257.         $this->firstUsedAt = new \DateTimeImmutable();
  258.     }
  259.     public function isUsed(): bool
  260.     {
  261.         return $this->firstUsedAt !== null;
  262.     }
  263. }