Files
api/services/nginx/app/objects/bookings_o.php
T
Jepp9350 dce9f1b616 Refactor bookings handling and update wash certificate logic
Reverted table name from 'bookings_new' to 'bookings' and removed unused sync data structure. Updated routes to use 'wash_certificate_store' instead of 'pdf_store' for wash certificate management. Added 'taulov' as a new department legacy name entry.
2025-03-27 13:11:17 +01:00

372 lines
17 KiB
PHP

<?php
namespace objects;
use classes\db;
use classes\object_property;
use classes\response;
use classes\slack;
use classes\wash_certificate_store;
use classes\wordpress_bookings_remote;
use Exception;
use traits\db_object_t;
class bookings_o extends db
{
use db_object_t;
public object_property $customer_number;
public object_property $wash_type;
public object_property $contact_email;
public object_property $reference_number;
public object_property $regNrTraekker;
public object_property $regNrTrailer;
public object_property $washCertificateEmail;
public object_property $date;
public object_property $department;
public object_property $pickup_bool;
public object_property $notes;
public object_property $washCertificateStatus;
public object_property $washCertificateUrl;
public object_property $status;
public object_property $data;
public function structure(): void
{
$this->setTable('bookings');
}
public function objectChanged(): void
{
// Clear the cache
redis->clear_department_booking_count($this->department->value());
}
public function getCustomerBookingsPaginated(int $customer_number, int $page = 1, int $limit = 10, array $order = ['id' => 'DESC'], string $search = null, array $filters = null): array
{
global /** @var response $response */
$db, $response;
// Add the customer number to the filters
$filters['customer_number'] = $customer_number;
// List the objects with pagination
$array = $this->listObjectsWithPagination($page, $limit, $search, $filters, $order);
// Get the total number of objects
$total = $this->getTotalObjects($search, $filters);
$response->paginate($page, $limit, $total);
return $array;
}
public function getDepartmentBookingsUnfulfilledCount(int $department_id): int
{
global /** @var response $response */
$db, $response;
// Check if the count is cached
if (redis->get_department_booking_count($department_id)) {
$response->add_meta('cached', true);
return redis->get_department_booking_count($department_id);
}
$sql = "SELECT COUNT(*) as count FROM $this->table WHERE department = $department_id AND status = 'pending'";
$result = $db->query($sql);
$row = $db->fetch_assoc($result);
// Cache the count
redis->cache_department_booking_count($department_id, $row['count']);
return $row['count'];
}
public function delete(int $id): void
{
$this->id = $id;
$this->getObjectProperties();
// Set the status to cancelled
$this->status->set('cancelled');
// Remove the cache
redis->clear_department_booking_count($this->department->value());
}
public function getObjectProperties(): void
{
$this->customer_number = new object_property($this->table, $this->id, 'customer_number', 'int', true);
$this->wash_type = new object_property($this->table, $this->id, 'wash_type', 'string', true);
$this->contact_email = new object_property($this->table, $this->id, 'contact_email', 'string', true);
$this->reference_number = new object_property($this->table, $this->id, 'reference_number', 'string', true);
$this->regNrTraekker = new object_property($this->table, $this->id, 'regNrTraekker', 'string', true);
$this->regNrTrailer = new object_property($this->table, $this->id, 'regNrTrailer', 'string', true);
$this->washCertificateEmail = new object_property($this->table, $this->id, 'washCertificateEmail', 'string', true);
$this->date = new object_property($this->table, $this->id, 'date', 'string', true);
$this->department = new object_property($this->table, $this->id, 'department', 'int', true);
$this->pickup_bool = new object_property($this->table, $this->id, 'pickup_bool', 'int', true);
$this->notes = new object_property($this->table, $this->id, 'notes', 'string', true);
$this->washCertificateStatus = new object_property($this->table, $this->id, 'washCertificateStatus', 'string', true);
$this->washCertificateUrl = new object_property($this->table, $this->id, 'washCertificateUrl', 'string', true);
$this->status = new object_property($this->table, $this->id, 'status', 'string', true);
$this->data = new object_property($this->table, $this->id, 'data', 'string', true);
}
public function parseBookings(array $listObjectsWithPaginationIfSet): array
{
// Parse the customer numbers
$bookings = $this->parseCustomerNumbers($listObjectsWithPaginationIfSet);
return $bookings;
}
public function parseCustomerNumbers(array $listObjectsWithPaginationIfSet): array
{
// Parse the customer numbers
foreach ( $listObjectsWithPaginationIfSet as $key => $value ) {
$listObjectsWithPaginationIfSet[$key]['customer_name'] = (new users_o())->getCustomerName($value['customer_number']);
}
return $listObjectsWithPaginationIfSet;
}
public function syncBookings(): array
{
global /** @var response $response */
$db, $response;
$wordpress_bookings_remote = new wordpress_bookings_remote();
// Get all the bookings from the remote API
$bookings = $wordpress_bookings_remote->get_all_bookings()['data']['all_wash_bookings'];
// Parse the bookings
$parsed_bookings = $wordpress_bookings_remote->parse_bookings($bookings);
// Remove the cancelled bookings from the $parsed_bookings array
$cancelled_bookings = $this->getAllCancelledOrCompletedBookings();
foreach ( $cancelled_bookings as $cancelled_booking ) {
// Remove the cancelled booking from the parsed bookings
foreach ( $parsed_bookings as $key => $parsed_booking ) {
if ((int)$parsed_booking['id'] === (int)$cancelled_booking['id']) {
unset($parsed_bookings[$key]);
}
}
}
// Sync the bookings
foreach ( $parsed_bookings as $booking ) {
// Add or update the booking
$this->addOrUpdate(
$booking['id'],
$booking['customer_number'],
$booking['wash_type'],
$booking['contact_email'],
$booking['reference_number'],
$booking['regNrTraekker'],
$booking['regNrTrailer'],
$booking['washCertificateEmail'],
$booking['date'],
$booking['department'],
$booking['pickup_bool'] ? 1 : 0,
$booking['notes'],
$booking['washCertificateStatus'],
$booking['washCertificateUrl'],
$booking['status']
);
}
return [
"bookings" => count($bookings),
"cancelled" => count($cancelled_bookings),
"parsed" => count($parsed_bookings),
];
}
public function getAllCancelledOrCompletedBookings(): array
{
global $db;
// Get all the cancelled bookings
$sql = "SELECT * FROM $this->table WHERE status = 'cancelled' OR status = 'completed'";
$result = $db->query($sql);
return $db->fetch_all($result);
}
public function addOrUpdate(int $id, $customer_number, $wash_type, $contact_email, $reference_number, $regNrTraekker, $regNrTrailer, $washCertificateEmail, $date, $department, $pickup_bool, $notes, $washCertificateStatus, $washCertificateUrl, $status): void
{
global $db;
// Avoid SQL injection
$wash_type = $db->escape_string($wash_type);
$contact_email = $db->escape_string($contact_email);
$reference_number = $db->escape_string($reference_number);
$regNrTraekker = $db->escape_string($regNrTraekker);
$regNrTrailer = $db->escape_string($regNrTrailer);
$washCertificateEmail = $db->escape_string($washCertificateEmail);
$date = $db->escape_string($date);
// Parse the department name to id
$department = $this->getDepartmentIdByLegacyName($department);
$notes = $db->escape_string($notes);
$washCertificateStatus = $db->escape_string($washCertificateStatus);
$washCertificateUrl = $db->escape_string($washCertificateUrl);
$status = $db->escape_string($status);
// Check if the entry already exists
$sql = "SELECT * FROM $this->table WHERE id = $id";
$result = $db->query($sql);
if ($db->num_rows($result) === 0) {
// Send a department webhook if the booking is new
$slack = new slack();
try {
$slack->send_department_booking_notification($department, $slack->format_new_booking(
$id,
$customer_number,
$wash_type,
$contact_email,
$reference_number,
$regNrTraekker,
$regNrTrailer,
$washCertificateEmail,
$date,
$department,
$pickup_bool,
$notes,
$washCertificateStatus,
$washCertificateUrl,
$status
));
} catch (Exception $e) {
// Log the error
$logs = new logs_o();
$logs->add('slack', 0, 3, 0, 'SEND_DEPARTMENT_BOOKING_NOTIFICATION', $e->getMessage());
}
}
// Create a new record in the database ( Replace the code, if an entry already exists )
$sql = "INSERT INTO $this->table (id, customer_number, wash_type, contact_email, reference_number, regNrTraekker, regNrTrailer, washCertificateEmail, date, department, pickup_bool, notes, washCertificateStatus, washCertificateUrl, status) VALUES ($id, $customer_number, '$wash_type', '$contact_email', '$reference_number', '$regNrTraekker', '$regNrTrailer', '$washCertificateEmail', '$date', '$department', $pickup_bool, '$notes', '$washCertificateStatus', '$washCertificateUrl', '$status') ON DUPLICATE KEY UPDATE customer_number = $customer_number, wash_type = '$wash_type', contact_email = '$contact_email', reference_number = '$reference_number', regNrTraekker = '$regNrTraekker', regNrTrailer = '$regNrTrailer', washCertificateEmail = '$washCertificateEmail', date = '$date', department = '$department', pickup_bool = $pickup_bool, notes = '$notes', washCertificateStatus = '$washCertificateStatus', washCertificateUrl = '$washCertificateUrl', status = '$status'";
$db->query($sql);
// Clear the cache
redis->clear_department_booking_count($department);
}
public function getDepartmentIdByLegacyName(string $departmentName): int
{
// Get the department id by the legacy name
$departmentLegacyNames = [
'køge' => 4,
'taastrup' => 2,
'aarhusc' => 5,
'roskilde' => 6,
'hvidovre' => 1,
'glostrup' => 3,
'taulov' => 7,
];
return $departmentLegacyNames[strtolower($departmentName)] ?? 0;
}
public function add(int $customer_number, string $wash_type, string $contact_email, string $reference_number, string $regNrTraekker, string $regNrTrailer, string $washCertificateEmail, string $date, string $department, int $pickup_bool, string $notes, string $washCertificateStatus, string $washCertificateUrl, string $status): void
{
global $db;
// Avoid SQL injection
$wash_type = $db->escape_string($wash_type);
$contact_email = $db->escape_string($contact_email);
$reference_number = $db->escape_string($reference_number);
$regNrTraekker = $db->escape_string($regNrTraekker);
$regNrTrailer = $db->escape_string($regNrTrailer);
$washCertificateEmail = $db->escape_string($washCertificateEmail);
$date = $db->escape_string($date);
// Parse the department name to id
$department = $this->getDepartmentIdByLegacyName($department);
$notes = $db->escape_string($notes);
$washCertificateStatus = $db->escape_string($washCertificateStatus);
$washCertificateUrl = $db->escape_string($washCertificateUrl);
$status = $db->escape_string($status);
// Create a new record in the database ( Replace the code, if an entry already exists )
$sql = "INSERT INTO $this->table (customer_number, wash_type, contact_email, reference_number, regNrTraekker, regNrTrailer, washCertificateEmail, date, department, pickup_bool, notes, washCertificateStatus, washCertificateUrl, status) VALUES ($customer_number, '$wash_type', '$contact_email', '$reference_number', '$regNrTraekker', '$regNrTrailer', '$washCertificateEmail', '$date', '$department', $pickup_bool, '$notes', '$washCertificateStatus', '$washCertificateUrl', '$status')";
$db->query($sql);
// Clear the cache
redis->clear_department_booking_count($department);
// Get the id of the new record
$this->id = $db->insert_id();
}
public function checkUnfulfilledBookings(): void
{
$unfulfilled_bookings = [];
function addUnfulfilledBooking(int $department, array $arr): array
{
// Check if the department has a count in the unfulfilled bookings array
if (!isset($arr[$department])) {
$arr[$department] = 0;
}
// Add the unfulfilled booking to the department count
$arr[$department]++;
return $arr;
}
global $db;
// Get all the unfulfilled bookings
$bookings = $this->listObjectsWithPagination(1, 100000, null, ['status' => 'pending']);
// Check if the booking has been fulfilled
foreach ( $bookings as $booking ) {
if ($this->isCancelled($booking['id'])) {
echo "Booking with ID $booking[id] has been cancelled\n";
continue;
}
// Check if the booking is scheduled for the future
if (strtotime($booking['date']) > time()) {
continue;
}
// Check if the booking has been fulfilled
$fulfilled = $this->checkBookingFulfilled($booking['id']);
if (!$fulfilled) {
$unfulfilled_bookings = addUnfulfilledBooking($booking['department'], $unfulfilled_bookings);
echo "Booking with ID $booking[id] has not been fulfilled\n";
}
}
// Send a department webhook if the booking has not been fulfilled
foreach ( $unfulfilled_bookings as $department => $count ) {
$slack = new slack();
try {
$slack->send_department_booking_notification($department, 'There are ' . $count . ' unfulfilled bookings');
} catch (Exception $e) {
// Log the error
$logs = new logs_o();
$logs->add('slack', 0, 3, 0, 'SEND_DEPARTMENT_UNFULFILLED_BOOKINGS_NOTIFICATION', $e->getMessage());
}
}
}
private static function isCancelled(int $id): bool
{
global $db;
// Check if the booking has been cancelled
$sql = "SELECT status FROM bookings WHERE id = $id";
$result = $db->query($sql);
$row = $db->fetch_assoc($result);
return $row['status'] === 'cancelled';
}
public function checkBookingFulfilled(int $booking_id): bool
{
// Check if the booking has a wash certificate
$wash_certificate_store = new wash_certificate_store();
return $wash_certificate_store->washCertificateExists($booking_id);
}
public function completeWashWithoutWashCertificate(int $id): void
{
global $db;
// Set the status to completed
$sql = "UPDATE $this->table SET status = 'completed', washCertificateStatus = 'cancelled' WHERE id = $id";
$db->query($sql);
}
/**
* @throws Exception If the object is not selected
*/
public function asArray(): array
{
self::requireSelected();
return [
'id' => (int)$this->id,
'customer_number' => (int)$this->customer_number->value(),
'wash_type' => $this->wash_type->value(),
'contact_email' => $this->contact_email->value(),
'reference_number' => $this->reference_number->value(),
'regNrTraekker' => $this->regNrTraekker->value(),
'regNrTrailer' => $this->regNrTrailer->value(),
'washCertificateEmail' => $this->washCertificateEmail->value(),
'date' => $this->date->value(),
'department' => (int)$this->department->value(),
'pickup_bool' => $this->pickup_bool->value() ? true : false,
'notes' => $this->notes->value(),
'washCertificateStatus' => $this->washCertificateStatus->value(),
'washCertificateUrl' => $this->washCertificateUrl->value(),
'status' => $this->status->value(),
'data' => $this->data->value() ? json_decode($this->data->value(), true) : null,
];
}
}