feat: split nights off an accommodation booking as separate periods
addresses #869f6z36v
This commit is contained in:
1 parent
972839286c
commit
7001bc0cf2
35 files changed
+2221
-25
No files matched your search
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Entity\Groups;
|
||||
|
||||
use App\Entity\TimestampableEntityInterface;
|
||||
use App\Entity\TimestampableParentAwareInterface;
|
||||
use App\Enum\Groups\AccommodationBookingPeriodPosition;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* A stretch of nights split off the start or the end of a stay, such as the day an advance team
|
||||
* arrives before the group. It carries no pax, board or services of its own and is never priced
|
||||
* from the catalog: the office quotes it as free-form lines, which are added to the booking's
|
||||
* total and fall under its fixed total discount. The booking's own parameters price only what
|
||||
* remains between the leading and the trailing periods.
|
||||
*/
|
||||
#[ORM\Entity]
|
||||
class AccommodationBookingPeriod implements TimestampableParentAwareInterface
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'periods')]
|
||||
#[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
|
||||
private ?AccommodationBooking $booking = null;
|
||||
|
||||
#[ORM\Column(length: 10, enumType: AccommodationBookingPeriodPosition::class)]
|
||||
private AccommodationBookingPeriodPosition $position;
|
||||
|
||||
#[ORM\Column(type: Types::DATE_IMMUTABLE)]
|
||||
private \DateTimeImmutable $dateFrom;
|
||||
|
||||
// Exclusive, like the booking's: the departure day, not the last night.
|
||||
#[ORM\Column(type: Types::DATE_IMMUTABLE)]
|
||||
private \DateTimeImmutable $dateTo;
|
||||
|
||||
/** What the price breakdown calls the period, e.g. "Vorausteam"; without one it shows the dates alone. */
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $label = null;
|
||||
|
||||
/**
|
||||
* Amounts in minor units of the booking's pricing currency; a line has no currency of its own.
|
||||
*
|
||||
* The column is not called `lines`: that is a reserved word in MariaDB, and the ORM does
|
||||
* not quote column names in the statements it writes.
|
||||
*
|
||||
* @var list<array{label: string, amount: int}>
|
||||
*/
|
||||
#[ORM\Column(name: 'price_lines', type: Types::JSON)]
|
||||
private array $lines = [];
|
||||
|
||||
public function __construct(AccommodationBookingPeriodPosition $position, \DateTimeImmutable $dateFrom, \DateTimeImmutable $dateTo)
|
||||
{
|
||||
$this->position = $position;
|
||||
$this->dateFrom = $dateFrom;
|
||||
$this->dateTo = $dateTo;
|
||||
}
|
||||
|
||||
public function __clone()
|
||||
{
|
||||
$this->id = null;
|
||||
$this->booking = null;
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getBooking(): ?AccommodationBooking
|
||||
{
|
||||
return $this->booking;
|
||||
}
|
||||
|
||||
public function setBooking(?AccommodationBooking $booking): self
|
||||
{
|
||||
$this->booking = $booking;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTimestampableParent(): ?TimestampableEntityInterface
|
||||
{
|
||||
return $this->booking;
|
||||
}
|
||||
|
||||
public function getPosition(): AccommodationBookingPeriodPosition
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
public function isLeading(): bool
|
||||
{
|
||||
return AccommodationBookingPeriodPosition::Leading === $this->position;
|
||||
}
|
||||
|
||||
public function getDateFrom(): \DateTimeImmutable
|
||||
{
|
||||
return $this->dateFrom;
|
||||
}
|
||||
|
||||
public function getDateTo(): \DateTimeImmutable
|
||||
{
|
||||
return $this->dateTo;
|
||||
}
|
||||
|
||||
public function setDates(\DateTimeImmutable $dateFrom, \DateTimeImmutable $dateTo): self
|
||||
{
|
||||
$this->dateFrom = $dateFrom;
|
||||
$this->dateTo = $dateTo;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLabel(): ?string
|
||||
{
|
||||
return $this->label;
|
||||
}
|
||||
|
||||
public function setLabel(?string $label): self
|
||||
{
|
||||
$this->label = $label;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getNights(): int
|
||||
{
|
||||
return $this->dateFrom < $this->dateTo ? $this->dateFrom->diff($this->dateTo)->days : 0;
|
||||
}
|
||||
|
||||
/** @return list<array{label: string, amount: int}> */
|
||||
public function getLines(): array
|
||||
{
|
||||
return $this->lines;
|
||||
}
|
||||
|
||||
/** @param list<array{label: string, amount: int}> $lines */
|
||||
public function setLines(array $lines): self
|
||||
{
|
||||
$this->lines = $lines;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTotal(): int
|
||||
{
|
||||
return array_sum(array_column($this->lines, 'amount'));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user