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, ): 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, ]); $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, ): 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'); } } 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->name->value()); $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); } }