src/Entity/CalendarEvent.php line 16

Open in your IDE?
  1. <?php
  2. namespace App\Entity;
  3. use App\Enum\CalendarEvent\Status;
  4. use App\Enum\CalendarEvent\Type;
  5. use App\Library\Utils\DateUtils;
  6. use App\Repository\CalendarEventRepository;
  7. use Doctrine\Common\Collections\ArrayCollection;
  8. use Doctrine\Common\Collections\Collection;
  9. use Doctrine\ORM\Mapping as ORM;
  10. /**
  11.  * @ORM\Entity(repositoryClass=CalendarEventRepository::class)
  12.  */
  13. class CalendarEvent
  14. {
  15.     /**
  16.      * @ORM\Id
  17.      * @ORM\GeneratedValue
  18.      * @ORM\Column(type="integer")
  19.      */
  20.     private $id;
  21.     /**
  22.      * @ORM\Column(type="string", length=255, nullable=true)
  23.      */
  24.     private $name;
  25.     /**
  26.      * @ORM\Column(type="date")
  27.      */
  28.     private $startDate;
  29.     /**
  30.      * @ORM\Column(type="date")
  31.      */
  32.     private $endDate;
  33.     /**
  34.      * @ORM\Column(type="integer", nullable=true)
  35.      */
  36.     private $price;
  37.     /**
  38.      * @ORM\Column(type="smallint", nullable=true)
  39.      */
  40.     private $fromLevel;
  41.     /**
  42.      * @ORM\Column(type="smallint", nullable=true)
  43.      */
  44.     private $earnLevel;
  45.     /**
  46.      * @ORM\Column(type="time")
  47.      */
  48.     private $startTime;
  49.     /**
  50.      * @ORM\Column(type="time")
  51.      */
  52.     private $endTime;
  53.     /**
  54.      * @ORM\Column(type="enum", options={"values"="calendar_event_enum"})
  55.      */
  56.     private $type = Type::TYPE_COURSE;
  57.     /**
  58.      * @ORM\Column(type="boolean", nullable=true)
  59.      */
  60.     private $isCandidateReviewRequired = true;
  61.     /**
  62.     * @ORM\ManyToOne(targetEntity=PaymentRequisites::class)
  63.     * @ORM\JoinColumn(nullable=true)
  64.      */
  65.     private $paymentRequisites;
  66.     /**
  67.      * @ORM\Column(type="string", length=255, nullable=true)
  68.      */
  69.     private $telegramChannelUrl;
  70.     /**
  71.      * @ORM\Column(type="string", length=100, nullable=true)
  72.      */
  73.     private $telegramChannelId;
  74.     /**
  75.      * @ORM\ManyToMany(targetEntity=CalendarEvent::class)
  76.      */
  77.     private $requireCalendarEventsParticipations;
  78.     /**
  79.      * @ORM\Column(type="boolean", nullable=true)
  80.      */
  81.     private $eventDatesApproximate;
  82.     /**
  83.      * @ORM\Column(type="enum", options={"values"="calendar_event_enum", "default"="active"}))
  84.      */
  85.     private $status = Status::STATUS_ACTIVE;
  86.     /**
  87.      * @ORM\ManyToMany(targetEntity=CalendarEvent::class)
  88.      * @ORM\JoinTable(name="calendar_event_deny_participations",
  89.      *       joinColumns={@ORM\JoinColumn(name="calendar_event_id", referencedColumnName="id")},
  90.      *       inverseJoinColumns={@ORM\JoinColumn(name="deny_calendar_event_id", referencedColumnName="id")}
  91.      *  )
  92.      */
  93.     private $denyCalendarEventsParticipations;
  94.     /**
  95.      * @ORM\Column(type="smallint", nullable=true)
  96.      */
  97.     private $toLevel;
  98.     /**
  99.      * @ORM\Column(nullable=true)
  100.      */
  101.     private $requireStudentStatus;
  102.     /**
  103.      * @ORM\ManyToOne(targetEntity=CalendarEvent::class, inversedBy="connectedCalendarEvents")
  104.      * @ORM\JoinColumn(nullable=true)
  105.      */
  106.     private $connectingCalendarEvent;
  107.     /**
  108.      * @ORM\OneToMany(targetEntity=CalendarEvent::class, mappedBy="connectingCalendarEvent")
  109.      */
  110.     private $connectedCalendarEvents;
  111.     /**
  112.      * @ORM\ManyToMany(targetEntity=TelegramCampaignMessage::class)
  113.      */
  114.     private $approvedCandidatesCampaignMessages;
  115.     /**
  116.      * @ORM\ManyToOne(targetEntity=CalendarEventKind::class)
  117.      */
  118.     private $kind;
  119.     /**
  120.      * @ORM\Column(type="boolean", nullable=true)
  121.      */
  122.     private $connectingEventForAccountant;
  123.     /**
  124.      * @var bool|null
  125.      */
  126.     private $isEndDateSame;
  127.     /**
  128.      * @ORM\Column(type="boolean", nullable=true)
  129.      */
  130.     private $isTelegramChannelConfigurated;
  131.     /**
  132.      * @ORM\Column(type="datetime", nullable=true)
  133.      */
  134.     private $createdAt;
  135.     /**
  136.      * @ORM\Column(type="datetime", nullable=true)
  137.      */
  138.     private $updatedAt;
  139.     /**
  140.      * @ORM\Column(type="string", length=64, nullable=true, unique=true)
  141.      */
  142.     private $appCourseId;
  143.     public function __construct()
  144.     {
  145.         $this->createdAt = new \DateTime();
  146.         $this->updatedAt = new \DateTime();
  147.         $this->startDate = new \DateTime();
  148.         $this->endDate = new \DateTime();
  149.         $this->startTime = new \DateTime('10:00:00');
  150.         $this->endTime = new \DateTime('13:00:00');
  151.         $this->requireCalendarEventsParticipations = new ArrayCollection();
  152.         $this->approvedCandidatesCampaignMessages = new ArrayCollection();
  153.         $this->denyCalendarEventsParticipations = new ArrayCollection();
  154.         $this->connectedCalendarEvents = new ArrayCollection();
  155.     }
  156.     public function __toString()
  157.     {
  158.         return $this->getNameText();
  159.     }
  160.     public function getShortInfo(): string
  161.     {
  162.         return $this->getName() . " " . ($this->getStartDate() ? $this->getStartDate()->format('d.m.Y') : "") .
  163.             ($this->getFromLevel() ? " (с " . $this->getFromLevel() . " ур.)" : " (все ур.)");
  164.     }
  165.     public function getText(array $options = null)
  166.     {
  167.         $options = array_merge([
  168.             "quotes" => false,
  169.         ], $options ?? []);
  170.         $result = ($options['quotes'] ? $this->getNameText() : $this->getName());
  171.         return $result;
  172.     }
  173.     public function getNameText(): string
  174.     {
  175.         return $this->getTypeText() . " «" . $this->getName() . "»";
  176.     }
  177.     public function getOnTypeText(): string
  178.     {
  179.         $typeText = null;
  180.         switch ($this->getType()) {
  181.             case Type::TYPE_COURSE:
  182.             case Type::TYPE_CONSCIOUSNESS_DEVELOPMENT_COURSE:
  183.                 $typeText = "курс";
  184.                 break;
  185.             case Type::TYPE_OPEN_MEETING:
  186.                 $typeText = "открытую встречу";
  187.                 break;
  188.             case Type::TYPE_MEETING:
  189.                 $typeText = "конференцию";
  190.                 break;
  191.             case Type::TYPE_PERSONAL_CONSULTATION:
  192.                 $typeText = "личную консультацию";
  193.                 break;
  194.             default:
  195.                 $typeText = $this->getTypeText();
  196.                 break;
  197.         }
  198.         return $typeText;
  199.     }
  200.     public function getOfTypeText(): string
  201.     {
  202.         $typeText = null;
  203.         switch ($this->getType()) {
  204.             case Type::TYPE_COURSE:
  205.             case Type::TYPE_CONSCIOUSNESS_DEVELOPMENT_COURSE:
  206.                 $typeText = "курса";
  207.                 break;
  208.                 case Type::TYPE_OPEN_MEETING:
  209.                 $typeText = "открытой встречи";
  210.                 break;
  211.             case Type::TYPE_MEETING:
  212.                 $typeText = "конференции";
  213.                 break;
  214.             case Type::TYPE_PERSONAL_CONSULTATION:
  215.                 $typeText = "личной консультации";
  216.                 break;
  217.             default:
  218.                 $typeText = $this->getTypeText();
  219.                 break;
  220.         }
  221.         return $typeText;
  222.     }
  223.     public function getOnNameText(): string
  224.     {
  225.         $typeText = $this->getOnTypeText();
  226.         return $typeText . " «" . $this->getName() . "»";
  227.     }
  228.     public function getOfNameText(): string
  229.     {
  230.         $typeText = $this->getOfTypeText();
  231.         return $typeText . " «" . $this->getName() . "»";
  232.     }
  233.     public function getId(): ?int
  234.     {
  235.         return $this->id;
  236.     }
  237.     public function getName(): ?string
  238.     {
  239.         if (!$this->name) {
  240.             if ($this->getKind()) {
  241.                 return $this->getKind()->getTitle() ?? $this->getKind()->getName();
  242.             }
  243.         }
  244.         return $this->name;
  245.     }
  246.     public function setName(?string $name): self
  247.     {
  248.         $this->name = $name;
  249.         return $this;
  250.     }
  251.     public function getStartDate(): ?\DateTimeInterface
  252.     {
  253.         return $this->startDate;
  254.     }
  255.     public function setStartDate(\DateTimeInterface $startDate): self
  256.     {
  257.         $this->startDate = $startDate;
  258.         return $this;
  259.     }
  260.     public function getEndDate(): ?\DateTimeInterface
  261.     {
  262.         return $this->endDate;
  263.     }
  264.     public function setEndDate(\DateTimeInterface $endDate): self
  265.     {
  266.         $this->endDate = $endDate;
  267.         return $this;
  268.     }
  269.     private function _getPrice($isFirstCall = false): ?int
  270.     {
  271.         if ($isFirstCall) {
  272.             if (!$this->_getPrice() && $this->getConnectedCalendarEvents()->count()) {
  273.                 $isAllPricesEqual = true;
  274.                 $price = null;
  275.                 foreach ($this->getConnectedCalendarEvents() as $connectedEvent) {
  276.                     if ($connectedEvent->_getPrice()) {
  277.                         if ($price === null) {
  278.                             $price = $connectedEvent->_getPrice();
  279.                         } elseif ($price != $connectedEvent->_getPrice()) {
  280.                             $isAllPricesEqual = false;
  281.                             break;
  282.                         }
  283.                     }
  284.                 }
  285.                 if ($isAllPricesEqual) {
  286.                     return $price;
  287.                 }
  288.             }
  289.         }
  290.         return $this->price;
  291.     }
  292.     public function getPrice(): ?int
  293.     {
  294.       return $this->_getPrice(true);
  295.     }
  296.     public function isPriceNotNull(): bool
  297.     {
  298.         return $this->getPrice() === 0 || $this->getPrice();
  299.     }
  300.     public function setPrice(?int $price): self
  301.     {
  302.         $this->price = $price;
  303.         return $this;
  304.     }
  305.     public function getFromLevel(): ?int
  306.     {
  307.         if ($this->getKind()) {
  308.             return $this->getKind()->getFromLevel();
  309.         }
  310.         return $this->fromLevel;
  311.     }
  312.     public function getFromLevelEmoji(): string
  313.     {
  314.         $level = $this->getFromLevel();
  315.         if ($level === null || $level === 0) {
  316.             return "🔢";
  317.         }
  318.         $emojiNumbers = [
  319.             '0' => '0️⃣',
  320.             '1' => '1️⃣',
  321.             '2' => '2️⃣',
  322.             '3' => '3️⃣',
  323.             '4' => '4️⃣',
  324.             '5' => '5️⃣',
  325.             '6' => '6️⃣',
  326.             '7' => '7️⃣',
  327.             '8' => '8️⃣',
  328.             '9' => '9️⃣',
  329.         ];
  330.         $levelStr = (string)$level;
  331.         return $emojiNumbers[$levelStr[0]] . ($levelStr[1] ?? '');
  332.     }
  333.     public function getFromLevelText(): string
  334.     {
  335.         if ($this->getFromLevel() === null) {
  336.             return "";
  337.         }
  338.         if ($this->getFromLevel() === 0 && $this->getToLevel() === null) {
  339.             return "все ур.";
  340.         }
  341.         return ($this->getFromLevel() === $this->getToLevel() ? "для " : "с")
  342. //            . StringUtils::getEnding($this->getFromLevel(),
  343. //                "", "о", "",
  344. //                "")
  345.             . " " . $this->getFromLevelNumberText()
  346.             . ($this->getToLevel() === null
  347.                 || $this->getFromLevel() === $this->getToLevel()
  348.                 || $this->getToLevel() === Student::MAX_LEVEl ? "" : "–" . $this->getToLevelNumberText())
  349.             . " ур.";
  350.     }
  351.     public function getFromLevelNumberText(): ?string
  352.     {
  353.         if ($this->getFromLevel() === 0) {
  354.             return "баз.";
  355.         }
  356.         return $this->getFromLevel();
  357.     }
  358.     public function getToLevelNumberText(): ?string
  359.     {
  360.         if ($this->getToLevel() === 0) {
  361.             return "баз.";
  362.         }
  363.         return $this->getToLevel();
  364.     }
  365.     public function setFromLevel(?int $fromLevel): self
  366.     {
  367.         $this->fromLevel = $fromLevel;
  368.         return $this;
  369.     }
  370.     public function getEarnLevel(): ?int
  371.     {
  372.         if ($this->getKind()) {
  373.             return $this->getKind()->getEarnLevel();
  374.         }
  375.         return $this->earnLevel;
  376.     }
  377.     public function setEarnLevel(?int $level): self
  378.     {
  379.         $this->earnLevel = $level;
  380.         return $this;
  381.     }
  382.     public function getStartTime(): ?\DateTimeInterface
  383.     {
  384.         return $this->startTime;
  385.     }
  386.     public function setStartTime(\DateTimeInterface $startTime): self
  387.     {
  388.         $this->startTime = $startTime;
  389.         return $this;
  390.     }
  391.     public function getEndTime(): ?\DateTimeInterface
  392.     {
  393.         return $this->endTime;
  394.     }
  395.     public function setEndTime(\DateTimeInterface $endTime): self
  396.     {
  397.         $this->endTime = $endTime;
  398.         return $this;
  399.     }
  400.     public function getType()
  401.     {
  402.         if ($this->getKind() && $this->getKind()->getCalendarEventType() !== null) {
  403.             return $this->getKind()->getCalendarEventType();
  404.         }
  405.         return $this->type;
  406.     }
  407.     public function getTypeText(): string
  408.     {
  409.         return Type::getText($this->getType());
  410.     }
  411.     public function setType($type): self
  412.     {
  413.         $this->type = $type;
  414.         return $this;
  415.     }
  416.     public function getTopic(): string
  417.     {
  418.         if ($this->getType() === Type::TYPE_COURSE || $this->getType() === Type::TYPE_CONSCIOUSNESS_DEVELOPMENT_COURSE) {
  419.             return "Курс «" . $this->getName() . "»";
  420.         } elseif ($this->getType() === Type::TYPE_MEETING) {
  421.             return "Конференция «" . $this->getName() . "»";
  422.         } elseif ($this->getType() === Type::TYPE_OPEN_MEETING) {
  423.             return "Открытая встреча «" . $this->getName() . "»";
  424.         } else {
  425.             return $this->getTypeText() . " «" . $this->getName() . "»";
  426.         }
  427.     }
  428.     public function isIsCandidateReviewRequired(): ?bool
  429.     {
  430.         if ($this->getKind()) {
  431.             return $this->getKind()->getIsCandidateReviewRequired();
  432.         }
  433.         return $this->isCandidateReviewRequired;
  434.     }
  435.     public function setIsCandidateReviewRequired(?bool $isCandidateReviewRequired): self
  436.     {
  437.         $this->isCandidateReviewRequired = $isCandidateReviewRequired;
  438.         return $this;
  439.     }
  440.     public function getPaymentRequisites(): ?PaymentRequisites
  441.     {
  442.         return $this->paymentRequisites;
  443.     }
  444.     public function isForFree(): bool
  445.     {
  446.         return $this->getPrice() === 0;
  447.     }
  448.     public function checkPaymentRequisites(): bool
  449.     {
  450.         return $this->isPriceNotNull() && ($this->isForFree() || $this->getPaymentRequisites());
  451.     }
  452.     public function canCreateTelegramCampaign(): bool
  453.     {
  454.         return $this->isPriceNotNull() && $this->checkPaymentRequisites();
  455.     }
  456.     public function setPaymentRequisites(?PaymentRequisites $paymentRequisites): self
  457.     {
  458.         $this->paymentRequisites = $paymentRequisites;
  459.         return $this;
  460.     }
  461.     public function getNameWithCode(): string
  462.     {
  463.         return "Код " . $this->getPrice() . " – " . $this->getShortInfo();
  464.     }
  465.     public function isFinished(): bool
  466.     {
  467.         if (!$this->getFullEndDate()) {
  468.             return true;
  469.         }
  470.         $now = new \DateTime();
  471.         return $this->getFullEndDate() < $now;
  472.     }
  473.     public function isInProgress(): bool
  474.     {
  475.         return $this->isStarted() && !$this->isFinished();
  476.     }
  477.     public function isUpcoming(): bool
  478.     {
  479.         if (!$this->getFullStartDate()) {
  480.             return false;
  481.         }
  482.         $now = new \DateTime();
  483.         return $this->getFullStartDate() > $now;
  484.     }
  485.     public function getFullStartDate(): ?\DateTime
  486.     {
  487.         $startDate = $this->getStartDate();
  488.         if (!$startDate) {
  489.             return null;
  490.         }
  491.         $startTime = $this->getStartTime();
  492.         if ($startTime) {
  493.             $startDate = (clone $startDate)->setTime($startTime->format('H'), $startTime->format('i'), $startTime->format('s'));
  494.         }
  495.         return $startDate;
  496.     }
  497.     public function getFullEndDate(): ?\DateTime
  498.     {
  499.         $endDate = $this->getEndDate();
  500.         if (!$endDate) {
  501.             return null;
  502.         }
  503.         $endTime = $this->getEndTime();
  504.         if ($endTime) {
  505.             $endDate = (clone $endDate)->setTime($endTime->format('H'), $endTime->format('i'), $endTime->format('s'));
  506.         }
  507.         return $endDate;
  508.     }
  509.     public function isStarted(int $addDaysToStartDate = null): bool
  510.     {
  511.         if (!$this->getStartDate() || $this->isFinished()) {
  512.             return false;
  513.         }
  514.         $now = (new \DateTime())->setTime(0, 0, 0);
  515.         $startDate = (clone $this->getStartDate())->setTime(0, 0, 0);
  516.         if ($addDaysToStartDate) {
  517.             $startDate = $startDate->modify("+$addDaysToStartDate days");
  518.         }
  519.         return $startDate <= $now;
  520.     }
  521.     public function isRegistrationOpen(): bool
  522.     {
  523.         return !$this->isStarted(-2);
  524.     }
  525.     public function getLastRegistrationDate(): ?\DateTime
  526.     {
  527.         if (!$this->getStartDate()) {
  528.             return null;
  529.         }
  530.         $lastRegistrationDate = (clone $this->getStartDate())->modify("-3 days");
  531.         $weekendDays = 0;
  532.         if (in_array((int)$lastRegistrationDate->format('N'), [6, 7])) {
  533.             $weekendDays = (int)$lastRegistrationDate->format('N') - 5;
  534.         }
  535.         if ($weekendDays > 0) {
  536.             $lastRegistrationDate = $lastRegistrationDate->modify("-$weekendDays days");
  537.         }
  538.         return $lastRegistrationDate;
  539.     }
  540.     public function getHoursLeftBeforeStart(): int
  541.     {
  542.         return (int)ceil((($this->getStartDate()->getTimestamp() - (new \DateTime())->getTimestamp()) / 3600));
  543.     }
  544.     public function getTelegramChannelUrl(): ?string
  545.     {
  546.         return $this->telegramChannelUrl;
  547.     }
  548.     public function setTelegramChannelUrl(?string $telegramChannelUrl): self
  549.     {
  550.         $this->telegramChannelUrl = $telegramChannelUrl;
  551.         if (!$telegramChannelUrl) {
  552.             $this->setIsTelegramChannelConfigurated(false);
  553.         }
  554.         return $this;
  555.     }
  556.     public function getTelegramChannelId(): ?string
  557.     {
  558.         return $this->telegramChannelId;
  559.     }
  560.     public function setTelegramChannelId(?string $telegramChannelId): self
  561.     {
  562.         $this->telegramChannelId = $telegramChannelId;
  563.         if (!$telegramChannelId) {
  564.             $this->setIsTelegramChannelConfigurated(false);
  565.         }
  566.         return $this;
  567.     }
  568.     /**
  569.      * @return Collection<int, self>
  570.      */
  571.     public function getRequireCalendarEventsParticipations(): Collection
  572.     {
  573.         return $this->requireCalendarEventsParticipations;
  574.     }
  575.     public function getRequireCalendarEventsParticipationsText(): string
  576.     {
  577.         $texts = [];
  578.         foreach ($this->getRequireCalendarEventsParticipations() as $event) {
  579.             $texts[] = mb_lcfirst($event->getNameText(), 'UTF-8');
  580.         }
  581.         return implode(", ", $texts);
  582.     }
  583.     public function getDenyCalendarEventsParticipationsText(): string
  584.     {
  585.         $texts = [];
  586.         foreach ($this->getDenyCalendarEventsParticipations() as $event) {
  587.             $texts[] = mb_lcfirst($event->getNameText(), 'UTF-8');
  588.         }
  589.         return implode(", ", $texts);
  590.     }
  591.     public function addRequireCalendarEventsParticipation(self $requireCalendarEventsParticipation): self
  592.     {
  593.         if (!$this->requireCalendarEventsParticipations->contains($requireCalendarEventsParticipation)) {
  594.             $this->requireCalendarEventsParticipations[] = $requireCalendarEventsParticipation;
  595.         }
  596.         return $this;
  597.     }
  598.     public function removeRequireCalendarEventsParticipation(self $requireCalendarEventsParticipation): self
  599.     {
  600.         $this->requireCalendarEventsParticipations->removeElement($requireCalendarEventsParticipation);
  601.         return $this;
  602.     }
  603.     public function isStudentLevelCorrespond(?Person $person): bool
  604.     {
  605.         if (!$person) {
  606.             return false;
  607.         }
  608.         $eventLevel = $this->getFromLevel();
  609.         if ($eventLevel === null) {
  610.             return true;
  611.         }
  612.         if (!$person->getStudent() || $person->getStudent()->getLevel() === null) {
  613.             return false;
  614.         }
  615.         return $person->getStudent()->getLevel() >= $eventLevel;
  616.     }
  617.     public function isEventDatesApproximate(): ?bool
  618.     {
  619.         return $this->eventDatesApproximate;
  620.     }
  621.     public function setEventDatesApproximate(?bool $eventDatesApproximate): self
  622.     {
  623.         $this->eventDatesApproximate = $eventDatesApproximate;
  624.         return $this;
  625.     }
  626. //    /**
  627. //     * @return Collection<int, TelegramCampaignMessage>
  628. //     */
  629. //    public function getApprovedCandidatesCampaignMessages(): Collection
  630. //    {
  631. //        return $this->approvedCandidatesCampaignMessages;
  632. //    }
  633. //
  634. //    public function addApprovedCandidatesCampaignMessage(TelegramCampaignMessage $approvedCandidatesCampaignMessage): self
  635. //    {
  636. //        if (!$this->approvedCandidatesCampaignMessages->contains($approvedCandidatesCampaignMessage)) {
  637. //            $this->approvedCandidatesCampaignMessages[] = $approvedCandidatesCampaignMessage;
  638. //        }
  639. //
  640. //        return $this;
  641. //    }
  642. //
  643. //    public function removeApprovedCandidatesCampaignMessage(TelegramCampaignMessage $approvedCandidatesCampaignMessage): self
  644. //    {
  645. //        $this->approvedCandidatesCampaignMessages->removeElement($approvedCandidatesCampaignMessage);
  646. //
  647. //        return $this;
  648. //    }
  649.     public function getStatus()
  650.     {
  651.         return $this->status;
  652.     }
  653.     public function setStatus($status): self
  654.     {
  655.         $this->status = $status;
  656.         return $this;
  657.     }
  658.     public function getStatusText(): ?string
  659.     {
  660.         return Status::getText($this->getStatus());
  661.     }
  662.     public function getStatusCssClass($prefix = null): ?string
  663.     {
  664.         return Status::getCssClass($this->getStatus(), $prefix);
  665.     }
  666.     /**
  667.      * @return Collection<int, self>
  668.      */
  669.     public function getDenyCalendarEventsParticipations(): Collection
  670.     {
  671.         return $this->denyCalendarEventsParticipations;
  672.     }
  673.     public function addDenyCalendarEventsParticipation(self $denyCalendarEventsParticipation): self
  674.     {
  675.         if (!$this->denyCalendarEventsParticipations->contains($denyCalendarEventsParticipation)) {
  676.             $this->denyCalendarEventsParticipations[] = $denyCalendarEventsParticipation;
  677.         }
  678.         return $this;
  679.     }
  680.     public function removeDenyCalendarEventsParticipation(self $denyCalendarEventsParticipation): self
  681.     {
  682.         $this->denyCalendarEventsParticipations->removeElement($denyCalendarEventsParticipation);
  683.         return $this;
  684.     }
  685.     public function getToLevel(): ?int
  686.     {
  687.         if ($this->getKind()) {
  688.             return $this->getKind()->getToLevel();
  689.         }
  690.         return $this->toLevel;
  691.     }
  692.     public function setToLevel(?int $toLevel): self
  693.     {
  694.         $this->toLevel = $toLevel;
  695.         return $this;
  696.     }
  697.     public function getRequireStudentStatus()
  698.     {
  699.         return $this->requireStudentStatus;
  700.     }
  701.     public function getRequireStudentStatusText(): string
  702.     {
  703.         return \App\Enum\Student\Status::getText($this->getRequireStudentStatus());
  704.     }
  705.     public function setRequireStudentStatus($requireStudentStatus): self
  706.     {
  707.         $this->requireStudentStatus = $requireStudentStatus;
  708.         return $this;
  709.     }
  710.     public function getConnectingCalendarEvent(): ?self
  711.     {
  712.         return $this->connectingCalendarEvent;
  713.     }
  714.     public function setConnectingCalendarEvent(?self $connectingCalendarEvent): self
  715.     {
  716.         $this->connectingCalendarEvent = $connectingCalendarEvent;
  717.         return $this;
  718.     }
  719.     /**
  720.      * @return Collection<int, self>
  721.      */
  722.     public function getConnectedCalendarEvents(): Collection
  723.     {
  724.         return $this->connectedCalendarEvents;
  725.     }
  726.     public function addConnectedCalendarEvent(self $connectedCalendarEvent): self
  727.     {
  728.         if (!$this->connectedCalendarEvents->contains($connectedCalendarEvent)) {
  729.             $this->connectedCalendarEvents[] = $connectedCalendarEvent;
  730.             $connectedCalendarEvent->setConnectingCalendarEvent($this);
  731.         }
  732.         return $this;
  733.     }
  734.     public function removeConnectedCalendarEvent(self $connectedCalendarEvent): self
  735.     {
  736.         if ($this->connectedCalendarEvents->removeElement($connectedCalendarEvent)) {
  737.             // set the owning side to null (unless already changed)
  738.             if ($connectedCalendarEvent->getConnectingCalendarEvent() === $this) {
  739.                 $connectedCalendarEvent->setConnectingCalendarEvent(null);
  740.             }
  741.         }
  742.         return $this;
  743.     }
  744.     public function getKind(): ?CalendarEventKind
  745.     {
  746.         return $this->kind;
  747.     }
  748.     public function setKind(?CalendarEventKind $kind): self
  749.     {
  750.         $this->kind = $kind;
  751.         return $this;
  752.     }
  753.     public function getFinanceCategory(): ?FinanceCategory
  754.     {
  755.         $ceKind = $this->getKind();
  756.         return $ceKind ? $ceKind->getFinanceCategory() : null;
  757.     }
  758.     public function isSameFinanceCategory(FinanceCategory $financeCategory): bool
  759.     {
  760.         $ceFinanceCategory = $this->getFinanceCategory();
  761.         if (!$ceFinanceCategory) {
  762.             return false;
  763.         }
  764.         return $ceFinanceCategory->getId() === $financeCategory->getId();
  765.     }
  766.     public function isConnectingType(): bool
  767.     {
  768.         return $this->getType() == Type::TYPE_CONNECTING_EVENT;
  769.     }
  770.     public function isConnectingEventForAccountant(): ?bool
  771.     {
  772.         return $this->connectingEventForAccountant;
  773.     }
  774.     public function setConnectingEventForAccountant(?bool $connectingEventForAccountant): self
  775.     {
  776.         $this->connectingEventForAccountant = $connectingEventForAccountant;
  777.         return $this;
  778.     }
  779.     public function getIsEndDateSame(): ?bool
  780.     {
  781.         $result = $this->getStartDate()->format("d.m.Y") == $this->getEndDate()->format("d.m.Y");
  782.         return $result;
  783.     }
  784.     public function setIsEndDateSame(?bool $isEndDateSame): self
  785.     {
  786.         $this->isEndDateSame = $isEndDateSame;
  787.         return $this;
  788.     }
  789.     public function isIsTelegramChannelConfigurated(): ?bool
  790.     {
  791.         return $this->isTelegramChannelConfigurated;
  792.     }
  793.     public function setIsTelegramChannelConfigurated(?bool $isTelegramChannelConfigurated): self
  794.     {
  795.         $this->isTelegramChannelConfigurated = $isTelegramChannelConfigurated;
  796.         return $this;
  797.     }
  798.     public function getDaysUntilStart(): int
  799.     {
  800.         if (!$this->getStartDate()) {
  801.             throw new \Exception("Start date is not set");
  802.         }
  803.         if (new \DateTime() >= $this->getStartDate()) {
  804.             return 0;
  805.         } else {
  806.             return floor(DateUtils::getDateDiff($this->getStartDate(), null, "d"));
  807.         }
  808.     }
  809.     public function shouldAskReceipt(): bool
  810.     {
  811.         return $this->getDaysUntilStart() <= 1;
  812.     }
  813.     public function getCreatedAt(): ?\DateTimeInterface
  814.     {
  815.         return $this->createdAt;
  816.     }
  817.     public function setCreatedAt(?\DateTimeInterface $createdAt): self
  818.     {
  819.         $this->createdAt = $createdAt;
  820.         return $this;
  821.     }
  822.     public function getUpdatedAt(): ?\DateTime
  823.     {
  824.         return $this->updatedAt;
  825.     }
  826.     public function setUpdatedAt(?\DateTimeInterface $updatedAt): self
  827.     {
  828.         $this->updatedAt = $updatedAt;
  829.         return $this;
  830.     }
  831.     public function isUpdatedRecently(): bool
  832.     {
  833.         if (!$this->getUpdatedAt()) {
  834.             return false;
  835.         }
  836.         if (new \DateTime() < (clone $this->getUpdatedAt())->modify("+3 minutes")) {
  837.             return true;
  838.         }
  839.         return false;
  840.     }
  841.     public function getAppCourseId(): ?string
  842.     {
  843.         return $this->appCourseId;
  844.     }
  845.     public function setAppCourseId(?string $appCourseId): self
  846.     {
  847.         $this->appCourseId = $appCourseId ?: null;
  848.         return $this;
  849.     }
  850.     public function isLateRegistrationAvailable(): bool
  851.     {
  852.         //todo replace this minimal solution in future
  853.         return $this->getFinanceCategory()
  854.             && in_array($this->getFinanceCategory()->getName(),
  855.             [
  856.                 "Курс АВ",
  857.                 "Курс АС"
  858.             ]
  859.         );
  860.     }
  861. }