feat: refactored accommodation booking status model
This commit is contained in:
@@ -9,8 +9,8 @@ use App\Entity\BlameableEntityInterface;
|
||||
use App\Entity\TimestampableEntity;
|
||||
use App\Entity\TimestampableEntityInterface;
|
||||
use App\Entity\User;
|
||||
use App\Enum\Groups\AccommodationBookingOrigin;
|
||||
use App\Enum\Groups\AccommodationBookingStatus;
|
||||
use App\Enum\Groups\AccommodationBookingType;
|
||||
use App\Enum\Groups\AdditionalServiceType;
|
||||
use App\Repository\Groups\AccommodationBookingRepository;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
@@ -81,12 +81,12 @@ class AccommodationBooking implements BlameableEntityInterface, TimestampableEnt
|
||||
private AccommodationBookingStatus $status = AccommodationBookingStatus::Draft;
|
||||
|
||||
/**
|
||||
* What kind of record this is — an offer the customer still has to accept, or a
|
||||
* directly placed, binding booking. Independent of the status: an accepted offer
|
||||
* keeps its Inquiry type, which is how offer-originated bookings stay recognisable.
|
||||
* How this record came about — through an offer the customer had to accept, or as a
|
||||
* booking the customer placed directly. Orthogonal to the status and never changed
|
||||
* after creation, so it stays truthful at every point of the lifecycle.
|
||||
*/
|
||||
#[ORM\Column(length: 20, enumType: AccommodationBookingType::class)]
|
||||
private AccommodationBookingType $type = AccommodationBookingType::Inquiry;
|
||||
#[ORM\Column(length: 20, enumType: AccommodationBookingOrigin::class)]
|
||||
private AccommodationBookingOrigin $origin = AccommodationBookingOrigin::Offer;
|
||||
|
||||
#[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)]
|
||||
private ?\DateTimeImmutable $accessLinkIssuedAt = null;
|
||||
@@ -118,14 +118,15 @@ class AccommodationBooking implements BlameableEntityInterface, TimestampableEnt
|
||||
private ?string $lastName = null;
|
||||
|
||||
/**
|
||||
* The `offer` group covers the one field a customer-facing booking cannot do without:
|
||||
* the access link and every notification are addressed to it. It is enforced on
|
||||
* creation as soon as the booking is not a draft, while `edit` additionally demands
|
||||
* the rest of the contact data.
|
||||
* The one field a customer-facing booking cannot do without — the access link and every
|
||||
* notification are addressed to it. A record on its way to the customer is validated with
|
||||
* `edit`, which additionally demands the rest of the contact data; the actions that
|
||||
* actually reach out (SendOfferController, ConfirmController) check the address again on
|
||||
* their own, since a draft may legitimately be saved without one.
|
||||
*/
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
#[Assert\NotBlank(groups: ['edit', 'offer'])]
|
||||
#[Assert\Email(groups: ['edit', 'offer'])]
|
||||
#[Assert\NotBlank(groups: ['edit'])]
|
||||
#[Assert\Email(groups: ['edit'])]
|
||||
private ?string $email = null;
|
||||
|
||||
#[ORM\Column(length: 50, nullable: true)]
|
||||
@@ -376,6 +377,11 @@ class AccommodationBooking implements BlameableEntityInterface, TimestampableEnt
|
||||
return AccommodationBookingStatus::Draft === $this->status;
|
||||
}
|
||||
|
||||
public function isRequested(): bool
|
||||
{
|
||||
return AccommodationBookingStatus::Requested === $this->status;
|
||||
}
|
||||
|
||||
public function isOpen(): bool
|
||||
{
|
||||
return AccommodationBookingStatus::Open === $this->status;
|
||||
@@ -396,26 +402,37 @@ class AccommodationBooking implements BlameableEntityInterface, TimestampableEnt
|
||||
return AccommodationBookingStatus::Discarded === $this->status;
|
||||
}
|
||||
|
||||
public function getType(): AccommodationBookingType
|
||||
public function getOrigin(): AccommodationBookingOrigin
|
||||
{
|
||||
return $this->type;
|
||||
return $this->origin;
|
||||
}
|
||||
|
||||
public function setType(AccommodationBookingType $type): self
|
||||
public function setOrigin(AccommodationBookingOrigin $origin): self
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->origin = $origin;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isInquiry(): bool
|
||||
public function isFromOffer(): bool
|
||||
{
|
||||
return AccommodationBookingType::Inquiry === $this->type;
|
||||
return AccommodationBookingOrigin::Offer === $this->origin;
|
||||
}
|
||||
|
||||
public function isBooking(): bool
|
||||
public function isDirectBooking(): bool
|
||||
{
|
||||
return AccommodationBookingType::Booking === $this->type;
|
||||
return AccommodationBookingOrigin::Direct === $this->origin;
|
||||
}
|
||||
|
||||
/**
|
||||
* What to call this record wherever it is named next to its status. An offer becomes a
|
||||
* booking the moment the customer commits, which is exactly what acceptedAt records — so
|
||||
* this can never contradict the status the way a stored type could. The origin is a
|
||||
* separate question ("where did this come from") and keeps its own label.
|
||||
*/
|
||||
public function recordLabel(): string
|
||||
{
|
||||
return null !== $this->acceptedAt ? 'Buchung' : 'Angebot';
|
||||
}
|
||||
|
||||
public function getAccessLinkIssuedAt(): ?\DateTimeImmutable
|
||||
|
||||
Reference in New Issue
Block a user