304 lines
12 KiB
PHP
304 lines
12 KiB
PHP
<?php
|
|
|
|
namespace objects;
|
|
|
|
use classes\db;
|
|
use classes\gatewayapi;
|
|
use classes\object_property;
|
|
use Exception;
|
|
use traits\db_object_t;
|
|
|
|
class department_time_bookings_entries_o extends db
|
|
{
|
|
use db_object_t;
|
|
|
|
public object_property $department; // The department id
|
|
public object_property $type; // The booking type id
|
|
public object_property $start; // The start timestamp of the start time
|
|
public object_property $end; // The end timestamp of the end time
|
|
public object_property $note; // The note for the booking
|
|
public object_property $reg; // The registration number plate (optional)
|
|
public object_property $phone; // The phone number (optional))
|
|
public object_property $phone_country_code; // The phone country code (optional)
|
|
public object_property $deleted_at; // The deleted at timestamp
|
|
|
|
|
|
public function structure(): void
|
|
{
|
|
$this->setTable('department_time_bookings_entries');
|
|
}
|
|
|
|
/**
|
|
* Convert the object to an array
|
|
* @throws Exception If the object is not selected
|
|
* @throws Exception If the object is not found
|
|
*/
|
|
public function asArray(): array
|
|
{
|
|
self::requireSelected();
|
|
return [
|
|
'id' => (int)$this->id,
|
|
'department' => (int)$this->department->value(),
|
|
'type' => (int)$this->type->value(),
|
|
'start' => (string)$this->start->value(),
|
|
'end' => (string)$this->end->value(),
|
|
'note' => $this->note->value(),
|
|
'reg' => $this->reg->value(),
|
|
'phone' => (int)$this->phone->value(),
|
|
'phone_country_code' => (int)$this->phone_country_code->value(),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Add a new object to the database
|
|
* @param int $department_id The department id
|
|
* @param int $type_id The booking type id
|
|
* @param int $start The start timestamp of the start time
|
|
* @param int $end The end timestamp of the end time
|
|
* @param int $phone_country_code The phone country code
|
|
* @param int $phone The phone number
|
|
* @param null|string $note The note for the booking
|
|
* @param null|string $reg The registration number plate (optional)
|
|
* @return void
|
|
* @throws Exception If the object was not created successfully
|
|
*/
|
|
public function add(
|
|
int $department_id,
|
|
int $type_id,
|
|
string $start,
|
|
string $end,
|
|
int $phone_country_code,
|
|
int $phone,
|
|
?string $note = null,
|
|
?string $reg = null,
|
|
?array $addons = null,
|
|
): void
|
|
{
|
|
self::preChecks(...func_get_args());
|
|
$tmp_id = self::add_object([
|
|
'department' => (int)$department_id,
|
|
'type' => (int)$type_id,
|
|
'start' => $start,
|
|
'end' => $end,
|
|
'note' => $note,
|
|
'reg' => $reg,
|
|
'phone' => $phone,
|
|
'phone_country_code' => $phone_country_code,
|
|
'addons' => $addons,
|
|
]);
|
|
$this->id = $tmp_id;
|
|
self::getObjectProperties();
|
|
self::objectChanged();
|
|
// Notify the parties involved
|
|
self::notifyBooking(true);
|
|
}
|
|
|
|
/**
|
|
* Pre-checks for the add method
|
|
* @param int $department_id The department id
|
|
* @param int $type_id The booking type id
|
|
* @param string $start The start timestamp of the start time
|
|
* @param string $end The end timestamp of the end time
|
|
* @param int $phone_country_code The phone country code
|
|
* @param int $phone The phone number
|
|
* @param null|string $note The note for the booking
|
|
* @param null|string $reg The registration number plate (optional)
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public static function preChecks(
|
|
int $department_id,
|
|
int $type_id,
|
|
string $start,
|
|
string $end,
|
|
int $phone_country_code,
|
|
int $phone,
|
|
?string $note = null,
|
|
?string $reg = null,
|
|
?array $addons = null,
|
|
): void
|
|
{
|
|
// Check if the type_id exists
|
|
$type = new department_time_bookings_types_o();
|
|
$type->select($type_id);
|
|
$type->requireSelected();
|
|
// Check if the type_id belongs to the department
|
|
if ((int)$type->department->value() !== (int)$department_id) {
|
|
throw new Exception('Type ID does not belong to the department');
|
|
}
|
|
// Check if the time slot is during the opening hours
|
|
$opening_hours = new department_time_bookings_opening_hours_o();
|
|
$opening_hours->selectByDepartment((int)$department_id);
|
|
if (!$opening_hours->isOpen($start, $end)) {
|
|
throw new Exception('The time slot is not during the opening hours.');
|
|
}
|
|
// Make sure the start time is before the end time
|
|
if ($start >= $end) {
|
|
throw new Exception('The start time must be before the end time.');
|
|
}
|
|
// Check if the time slot is already booked
|
|
$bookings = new department_time_bookings_entries_o();
|
|
$bookings_overlapping = $bookings->getBookingsByDepartmentAndTime((int)$department_id, $start, $end);
|
|
if (count($bookings_overlapping) > 0) {
|
|
throw new Exception('The time slot is already booked');
|
|
}
|
|
// Validate phone number
|
|
if (!is_numeric($phone) || $phone <= 0) {
|
|
throw new Exception('Invalid phone number');
|
|
}
|
|
// Validate phone country code
|
|
if (!is_numeric($phone_country_code) || $phone_country_code <= 0) {
|
|
throw new Exception('Invalid phone country code');
|
|
}
|
|
}
|
|
|
|
private function getBookingsByDepartmentAndTime(int $department_id, string $start, string $end): array
|
|
{
|
|
global $db;
|
|
$query = "SELECT * FROM {$this->table} WHERE department = ? AND start < ? AND end > ?";
|
|
$stmt = $db->prepare($query);
|
|
$stmt->bind_param('iss', $department_id, $end, $start);
|
|
$stmt->execute();
|
|
$result = $stmt->get_result();
|
|
$bookings = [];
|
|
while ($row = $result->fetch_assoc()) {
|
|
$bookings[] = $row;
|
|
}
|
|
$stmt->close();
|
|
return $bookings;
|
|
}
|
|
|
|
public function getObjectProperties(): void
|
|
{
|
|
$this->department = new object_property($this->table, $this->id, 'department', 'int', true);
|
|
$this->type = new object_property($this->table, $this->id, 'type', 'int', true);
|
|
$this->start = new object_property($this->table, $this->id, 'start', 'int', true);
|
|
$this->end = new object_property($this->table, $this->id, 'end', 'int', true);
|
|
$this->note = new object_property($this->table, $this->id, 'note', 'string', true);
|
|
$this->reg = new object_property($this->table, $this->id, 'reg', 'string', true);
|
|
$this->phone = new object_property($this->table, $this->id, 'phone', 'int', true);
|
|
$this->phone_country_code = new object_property($this->table, $this->id, 'phone_country_code', 'int', true);
|
|
$this->deleted_at = new object_property($this->table, $this->id, 'deleted_at', 'int', true);
|
|
}
|
|
|
|
public function objectChanged(): void
|
|
{
|
|
//TODO: Add cache invalidation
|
|
}
|
|
|
|
/**
|
|
* Notify the parties involved
|
|
* @param bool $is_new_booking True if the booking is new, false if it is an update
|
|
* @return void
|
|
* @throws Exception If the object is not selected
|
|
* @throws Exception If the department is not found
|
|
*/
|
|
public function notifyBooking(bool $is_new_booking): void
|
|
{
|
|
self::requireSelected();
|
|
$department = new departments_o();
|
|
$department->select((int)$this->department->value());
|
|
$gateway = new gatewayapi();
|
|
if ($gateway->isEnabled()) {
|
|
// Send the message to the department
|
|
$gateway->send(
|
|
[...$department->notificationSmsPhoneNumbers()],
|
|
($is_new_booking
|
|
? self::generateNewBookingMessage(true)
|
|
: self::generateUpdateBookingMessage(true)),
|
|
true,
|
|
);
|
|
//print_r($department->notificationSmsPhoneNumbers());
|
|
// Get the phone numbers of the customer
|
|
$customer_phone_numbers = [];
|
|
$customer_phone_numbers[] = '' . $this->phone_country_code->value() . $this->phone->value();
|
|
//print_r($customer_phone_numbers);
|
|
// Send the message to the customer
|
|
$gateway->send(
|
|
[...$customer_phone_numbers],
|
|
($is_new_booking
|
|
? $this->generateNewBookingMessage(false)
|
|
: $this->generateUpdateBookingMessage(false)),
|
|
true,
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generate the message for a new booking
|
|
* @param bool $is_to_department True if the message is to the department, false if it is to the customer
|
|
* @return string The message
|
|
* @throws Exception If the object is not selected
|
|
* @throws Exception If the department is not found
|
|
*/
|
|
public function generateNewBookingMessage(bool $is_to_department = false): string
|
|
{
|
|
self::requireSelected();
|
|
$department = new departments_o();
|
|
$department->select((int)$this->department->value());
|
|
$type = new department_time_bookings_types_o();
|
|
$type->select((int)$this->type->value());
|
|
|
|
$message = '';
|
|
if ($is_to_department) {
|
|
$message .= self::addNewline('Din afdeling har modtaget en ny booking');
|
|
} else {
|
|
$message .= self::addNewline('Bookingbekræftelse');
|
|
}
|
|
return $this->generateBookingMessageContent($department, $message, $type, $is_to_department);
|
|
}
|
|
|
|
private function addNewline(string $message): string
|
|
{
|
|
return $message . "\n";
|
|
}
|
|
|
|
/**
|
|
* @param departments_o $department
|
|
* @param string $message
|
|
* @param department_time_bookings_types_o $type
|
|
* @param bool $is_to_department
|
|
* @return string
|
|
* @throws Exception
|
|
*/
|
|
public function generateBookingMessageContent(departments_o $department, string $message, department_time_bookings_types_o $type, bool $is_to_department): string
|
|
{
|
|
self::requireSelected();
|
|
$message .= self::addNewline('Afdeling: ' . $department->name->value());
|
|
$message .= self::addNewline('Tidspunkt: ' . (string)$this->start->value());
|
|
$message .= self::addNewline('Type: ' . (string)$type->getName());
|
|
$registration_number = $this->reg->value();
|
|
if (!empty($registration_number)) {
|
|
$message .= self::addNewline('Registreringsnummer: ' . $registration_number);
|
|
}
|
|
$message .= self::addNewline('Telefonnummer: +' . $this->phone_country_code->value() . $this->phone->value());
|
|
if (!empty($this->note->value())) {
|
|
$message .= self::addNewline('Note: ' . $this->note->value());
|
|
}
|
|
if (!$is_to_department) {
|
|
$message .= self::addNewline('For mere information, kontakt venligst afdelingen.');
|
|
}
|
|
$message .= 'Denne besked er genereret automatisk og kan ikke besvares.';
|
|
return $message;
|
|
}
|
|
|
|
/**
|
|
* Generate the message for an updated booking
|
|
* @param bool $is_to_department True if the message is to the department, false if it is to the customer
|
|
* @return string The message
|
|
* @throws Exception If the object is not selected
|
|
* @throws Exception If the department is not found
|
|
*/
|
|
public function generateUpdateBookingMessage(bool $is_to_department = false): string
|
|
{
|
|
self::requireSelected();
|
|
$department = new departments_o();
|
|
$department->select((int)$this->department->value());
|
|
$type = new department_time_bookings_types_o();
|
|
$type->select((int)$this->type->value());
|
|
$message = $is_to_department
|
|
? self::addNewline('Din afdeling har modtaget en opdatering på en booking')
|
|
: self::addNewline('Du har modtaget en opdatering på en booking');
|
|
return $this->generateBookingMessageContent($department, $message, $type, $is_to_department);
|
|
}
|
|
} |