Files
api/services/nginx/app/objects/department_time_bookings_entries_o.php
T

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);
}
}