Add new booking handling features and improve validations
Introduced support for a `data` property in bookings, extended form handling with additional validation and input fields, and added functionality for retrieving booking counts by date and status. Improved safety seal labeling and enhanced PDF generation comments.
This commit is contained in:
@@ -146,7 +146,7 @@ class pdf_generator implements pdf_generator_i
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the filename to save the PDF as
|
||||
* Set the filename to save the PDF as (While the file is stored in a temporary location)
|
||||
* @param string|null $filename Filename to save the PDF as
|
||||
* @return self
|
||||
*/
|
||||
|
||||
@@ -47,6 +47,7 @@ class book_wash_f extends form_helper_c
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function afterSubmit(): void
|
||||
{
|
||||
@@ -72,8 +73,13 @@ class book_wash_f extends form_helper_c
|
||||
self::getSanitizedData('notes'),
|
||||
'pending',
|
||||
'',
|
||||
'pending'
|
||||
'pending',
|
||||
self::getSanitizedData('wash_type'),
|
||||
);
|
||||
// Validate the booking actually exists
|
||||
if (!$bookings_new->exists()) {
|
||||
throw new \Exception('Booking could not be created');
|
||||
}
|
||||
// Send the booking confirmation email
|
||||
$email->sendBookingConfirmationEmail(
|
||||
$bookings_new->id,
|
||||
@@ -105,6 +111,27 @@ class book_wash_f extends form_helper_c
|
||||
self::setSubmitButtonText('Book udvendig vask');
|
||||
// Set the form fields
|
||||
self::defineInputFieldsAdvanced([
|
||||
'department_id' => [
|
||||
'description' => 'Den lokation / vaskehal, hvor vasken skal finde sted.',
|
||||
'required' => true,
|
||||
'placeholder' => null,
|
||||
'label' => 'Vælg lokation',
|
||||
'help' => 'Vælg den lokation, hvor vasken skal finde sted.',
|
||||
'error' => 'Du skal vælge en afdeling.',
|
||||
'validation_method' => 'validateInt',
|
||||
'options' => self::getDepartmentOptions(),
|
||||
],
|
||||
'wash_type' => [
|
||||
'description' => 'Vasketype er den type vask, der skal udføres på køretøjet. Dette kan være en indvendig vask, udvendig vask eller begge dele.',
|
||||
'required' => true,
|
||||
'placeholder' => null,
|
||||
'label' => 'Vaskeydelser',
|
||||
'help' => 'Vælg de vaskeydelser, du ønsker.',
|
||||
'error' => 'Du skal vælge en vaskeydelser.',
|
||||
'validation_method' => 'validateInt',
|
||||
'options' => self::getWashTypes(),
|
||||
'allow_multiple' => true,
|
||||
],
|
||||
'customer_number' => [
|
||||
'description' => 'Et kunde nummer, er et unikt nummer, som er tildelt til hver kunde. Som standard er det telefonnummeret indtastet ved oprettelse af kunden.',
|
||||
'required' => true,
|
||||
@@ -122,12 +149,13 @@ class book_wash_f extends form_helper_c
|
||||
'help' => 'Vi sender en bekræftelse til denne email adresse.',
|
||||
'error' => 'Du skal indtaste en gyldig email adresse.',
|
||||
'validation_method' => 'validateEmail',
|
||||
'allow_auto_fill' => true,
|
||||
],
|
||||
'reference' => [
|
||||
'description' => 'Det er muligt at indtaste et reference nummer, hvis det er relevant for dig. Dette nummer kan være nyttigt til at identificere din booking.',
|
||||
'required' => false,
|
||||
'placeholder' => 'Indtast et reference nummer (hvis relevant)',
|
||||
'label' => 'Reference nummer',
|
||||
'label' => 'Reference nr.',
|
||||
'help' => 'Dette nummer tilføjes til din booking som reference.',
|
||||
'error' => 'Du skal indtaste et gyldigt reference nummer.',
|
||||
'validation_method' => 'validateString',
|
||||
@@ -137,7 +165,7 @@ class book_wash_f extends form_helper_c
|
||||
'description' => 'Nummerpladen på den trækkende enhed, som er det køretøj, der trækker traileren.',
|
||||
'required' => true,
|
||||
'placeholder' => 'Indtast registreringsnummeret på den trækkende enhed',
|
||||
'label' => 'Registreringsnummer (trækkende enhed)',
|
||||
'label' => 'Reg 1',
|
||||
'help' => 'Dette er nummerpladen på den trækkende enhed.',
|
||||
'error' => 'Du skal indtaste et gyldigt registreringsnummer.',
|
||||
'validation_method' => 'validateRegistrationNumber',
|
||||
@@ -146,7 +174,7 @@ class book_wash_f extends form_helper_c
|
||||
'description' => 'Nummerpladen på traileren, som er det køretøj, der bliver trukket af den trækkende enhed.',
|
||||
'required' => true,
|
||||
'placeholder' => 'Indtast registreringsnummeret på traileren',
|
||||
'label' => 'Registreringsnummer (trailer)',
|
||||
'label' => 'Reg 2',
|
||||
'help' => 'Dette er nummerpladen på traileren.',
|
||||
'error' => 'Du skal indtaste et gyldigt registreringsnummer.',
|
||||
'validation_method' => 'validateRegistrationNumber',
|
||||
@@ -172,6 +200,7 @@ class book_wash_f extends form_helper_c
|
||||
'display_if_value' => true,
|
||||
'required_if_display' => true,
|
||||
'default' => null,
|
||||
'allow_auto_fill' => true,
|
||||
],
|
||||
'date' => [
|
||||
'description' => 'Datoen for vasken, som er den dato, hvor vasken skal finde sted.',
|
||||
@@ -183,16 +212,6 @@ class book_wash_f extends form_helper_c
|
||||
'validation_method' => 'validateDate',
|
||||
'default' => date('Y-m-d'),
|
||||
],
|
||||
'department_id' => [
|
||||
'description' => 'Den afdeling / vaskehal, hvor vasken skal finde sted.',
|
||||
'required' => true,
|
||||
'placeholder' => null,
|
||||
'label' => 'Afdeling',
|
||||
'help' => 'Vælg den afdeling, hvor vasken skal finde sted.',
|
||||
'error' => 'Du skal vælge en afdeling.',
|
||||
'validation_method' => 'validateInt',
|
||||
'options' => self::getDepartmentOptions(),
|
||||
],
|
||||
'wants_pickup' => [
|
||||
'description' => 'Pickup er en service, hvor vi henter køretøjet og bringer det tilbage efter vasken.',
|
||||
'required' => false,
|
||||
@@ -210,8 +229,18 @@ class book_wash_f extends form_helper_c
|
||||
'error' => null,
|
||||
'validation_method' => 'validateString',
|
||||
'default' => '',
|
||||
'allow_auto_fill' => true,
|
||||
],
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
private static function getWashTypes(): array
|
||||
{
|
||||
return [
|
||||
1 => 'Udvendig sættevognstræk ( Trækker / trailer )',
|
||||
2 => 'Udvendigt trailer vask',
|
||||
3 => 'Indvendig trailer vask',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -103,8 +103,8 @@ class generate_booking_wash_certificate_f extends form_helper_c
|
||||
'description' => 'En sikkerhedssikring er en form for beskyttelse, der sikrer, at køretøjet ikke er blevet åbnet eller ændret efter vasken.',
|
||||
'required' => false,
|
||||
'placeholder' => 'Indtast sikkerhedssikring',
|
||||
'label' => 'Sikkerhedssikring',
|
||||
'help' => 'Dette er en sikkerhedssikring, der bruges til at sikre køretøjet.',
|
||||
'label' => 'Safety Seal / PLOM',
|
||||
'help' => 'Dette er et Safety Seal, der bruges til at dokumentere, at køretøjet er blevet vasket.',
|
||||
'error' => 'Du skal indtaste en gyldig sikkerhedssikring.',
|
||||
'validation_method' => 'validateInt',
|
||||
'default' => '',
|
||||
|
||||
@@ -30,7 +30,7 @@ class wash_certificate extends html2pdf_template
|
||||
/** Add the provider details */
|
||||
$html .= self::getProviderDetails();
|
||||
/** Add the regarding this document */
|
||||
$html .= self::getRegardingThisDocument('DK');
|
||||
//$html .= self::getRegardingThisDocument('DK');
|
||||
/** Add the regarding this document in English */
|
||||
$html .= self::getRegardingThisDocument('EN');
|
||||
/** Add the signature */
|
||||
|
||||
@@ -27,6 +27,7 @@ class bookings_new_o extends db
|
||||
public object_property $washCertificateStatus;
|
||||
public object_property $washCertificateUrl;
|
||||
public object_property $status;
|
||||
public object_property $data;
|
||||
|
||||
private static function isCancelled(int $id): bool
|
||||
{
|
||||
@@ -43,12 +44,6 @@ class bookings_new_o extends db
|
||||
$this->setTable('bookings_new');
|
||||
}
|
||||
|
||||
public function objectChanged(): void
|
||||
{
|
||||
// Clear the cache
|
||||
redis->clear_department_booking_count($this->department->value());
|
||||
}
|
||||
|
||||
public function delete(int $id): void
|
||||
{
|
||||
$this->id = $id;
|
||||
@@ -75,6 +70,7 @@ class bookings_new_o extends db
|
||||
$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
|
||||
@@ -111,7 +107,7 @@ class bookings_new_o extends db
|
||||
* @param string $status
|
||||
* @return void
|
||||
*/
|
||||
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
|
||||
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, array $data = []): void
|
||||
{
|
||||
global $db;
|
||||
// Avoid SQL injection
|
||||
@@ -135,6 +131,20 @@ class bookings_new_o extends db
|
||||
|
||||
// Get the id of the new record
|
||||
$this->id = $db->insert_id();
|
||||
|
||||
// Set the object properties
|
||||
self::getObjectProperties();
|
||||
|
||||
// Add the data to the object
|
||||
$this->data->set(json_encode($data));
|
||||
|
||||
self::objectChanged();
|
||||
}
|
||||
|
||||
public function objectChanged(): void
|
||||
{
|
||||
// Clear the cache
|
||||
redis->clear_department_booking_count($this->department->value());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -184,6 +194,7 @@ class bookings_new_o extends db
|
||||
])
|
||||
->getHtml()
|
||||
);
|
||||
// Generate the pdf
|
||||
$pdf_path = $pdf_generator->generate_pdf();
|
||||
// Set the wash certificate url
|
||||
$this->washCertificateUrl->set($pdf_path);
|
||||
|
||||
@@ -29,6 +29,7 @@ class bookings_o extends db
|
||||
public object_property $washCertificateStatus;
|
||||
public object_property $washCertificateUrl;
|
||||
public object_property $status;
|
||||
public object_property $data;
|
||||
|
||||
public function structure(): void
|
||||
{
|
||||
@@ -98,6 +99,7 @@ class bookings_o extends db
|
||||
$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
|
||||
@@ -366,7 +368,8 @@ class bookings_o extends db
|
||||
'notes' => $this->notes->value(),
|
||||
'washCertificateStatus' => $this->washCertificateStatus->value(),
|
||||
'washCertificateUrl' => $this->washCertificateUrl->value(),
|
||||
'status' => $this->status->value()
|
||||
'status' => $this->status->value(),
|
||||
'data' => $this->data->value() ? json_decode($this->data->value(), true) : null,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -462,4 +462,31 @@ class department_daily_reports_o extends db
|
||||
{
|
||||
return $this->doesDepartmentDailyReportExist($department_id, $date);
|
||||
}
|
||||
|
||||
public function getBookingsOnDateCount(string $date, int $department_id, string $status): int
|
||||
{
|
||||
global /** @var db $db */
|
||||
$db;
|
||||
$conn = $db->conn();
|
||||
$stmt = $conn->prepare(
|
||||
'SELECT COUNT(*) as amount FROM bookings_new o
|
||||
WHERE o.department = ? AND DATE(o.created_at) = ? AND o.status = ?'
|
||||
);
|
||||
|
||||
if ($stmt) {
|
||||
$stmt->bind_param('iss', $department_id, $date, $status); // Bind parameters (i = integer, s = string)
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result(); // Get the result set from the statement
|
||||
$data = $result->fetch_assoc(); // Fetch the result as an associative array
|
||||
|
||||
// Access the "amount" field
|
||||
$amount = $data['amount'];
|
||||
|
||||
$stmt->close(); // Close the statement
|
||||
} else {
|
||||
// Handle query preparation error
|
||||
die('Query preparation failed: ' . $conn->error);
|
||||
}
|
||||
return (int)$amount;
|
||||
}
|
||||
}
|
||||
@@ -550,5 +550,95 @@ class departmentDailyReportsRoute
|
||||
'department_access_:id' => 'Access the department'
|
||||
]
|
||||
);
|
||||
|
||||
$this->get('/departments/daily-reports/bookings-count', function () {
|
||||
// Require the user to be logged in
|
||||
global $response;
|
||||
$this->requirePermission('list_bookings');
|
||||
// Get the user object
|
||||
$user = (new authentication())->get_user();
|
||||
// Check if the request was successful
|
||||
if ($user) {
|
||||
// Check if the required fields are set
|
||||
self::requireParameters(
|
||||
[
|
||||
'date',
|
||||
'department_id'
|
||||
]
|
||||
);
|
||||
// Validate the date
|
||||
self::requireType(
|
||||
(string)self::getParameter('date'),
|
||||
self::type_string()
|
||||
);
|
||||
// Require the date to be at least 0 characters long
|
||||
self::requireMinLength(
|
||||
'date',
|
||||
0
|
||||
);
|
||||
// Require the date to be at most 10 characters long
|
||||
self::requireMaxLength(
|
||||
'date',
|
||||
10
|
||||
);
|
||||
// Validate the date format (YYYY-MM-DD)
|
||||
self::requireDateFormat(
|
||||
(string)self::getParameter('date'),
|
||||
'Y-m-d'
|
||||
);
|
||||
// Validate the department_id
|
||||
self::requireType(
|
||||
(int)self::getParameter('department_id'),
|
||||
self::type_int()
|
||||
);
|
||||
// Require the department_id to be above 0
|
||||
self::requireMinValue(
|
||||
(int)self::getParameter('department_id'),
|
||||
1
|
||||
);
|
||||
// Determine if the user has access to the department
|
||||
self::requireDepartmentAccess((int)self::getParameter('department_id'));
|
||||
|
||||
// Log the incident
|
||||
(new logs_o())->add('departments', 'global', 1, $user->id, 'LIST_DEPARTMENT_DAILY_REPORTS_PRODUCTS', 'Successfully listed departments daily reports products');
|
||||
// Return the list of products sold on the selected date
|
||||
$response->success(
|
||||
[
|
||||
'pending' =>
|
||||
(new department_daily_reports_o())
|
||||
->getBookingsOnDateCount(
|
||||
(string)self::getParameter('date'),
|
||||
(int)self::getParameter('department_id'),
|
||||
'pending'
|
||||
),
|
||||
'completed' =>
|
||||
(new department_daily_reports_o())
|
||||
->getBookingsOnDateCount(
|
||||
(string)self::getParameter('date'),
|
||||
(int)self::getParameter('department_id'),
|
||||
'completed'
|
||||
),
|
||||
'cancelled' =>
|
||||
(new department_daily_reports_o())
|
||||
->getBookingsOnDateCount(
|
||||
(string)self::getParameter('date'),
|
||||
(int)self::getParameter('department_id'),
|
||||
'cancelled'
|
||||
),
|
||||
|
||||
]
|
||||
);
|
||||
} else {
|
||||
// Log the incident
|
||||
(new logs_o())->add('departments', 'global', 1, 0, 'LIST_DEPARTMENT_DAILY_REPORTS_PRODUCTS', 'No user found, or invalid session');
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'list_department_daily_reports' => 'List the department daily reports, provided the user has access to the department',
|
||||
'department_access_:id' => 'Access the department'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -187,7 +187,39 @@ trait form_t
|
||||
// Check if the field is valid
|
||||
if (is_callable($validation_method) || method_exists($this, $validation_method)) {
|
||||
$callable = is_callable($validation_method) ? $validation_method : [$this, $validation_method];
|
||||
$is_valid = call_user_func($callable, $DATA[self::getFormFieldPrefix() . $field]);
|
||||
try {
|
||||
// Check if the field is multiple ( e.g. ['field1', 'field2'])
|
||||
if (is_array($DATA[self::getFormFieldPrefix() . $field])) {
|
||||
// If there's no value, check if the field is required
|
||||
if (count($DATA[self::getFormFieldPrefix() . $field]) === 0) {
|
||||
// If the field is required, add it to the missing fields
|
||||
if (self::isFieldRequired($field)) {
|
||||
$missing_fields[] = self::getFormFieldPrefix() . $field;
|
||||
}
|
||||
}
|
||||
// Loop through the array and check if each value is valid
|
||||
foreach ( $DATA[self::getFormFieldPrefix() . $field] as $value ) {
|
||||
// Call the validation method
|
||||
$is_valid = call_user_func($callable, $value);
|
||||
if (!$is_valid) {
|
||||
// If the value is not valid, add it to the errors
|
||||
$errors[self::getFormFieldPrefix() . $field] = [
|
||||
'error' => 'The field is invalid, please check the format',
|
||||
'field' => self::getFormFieldPrefix() . $field,
|
||||
];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Call the validation method
|
||||
$is_valid = call_user_func($callable, $DATA[self::getFormFieldPrefix() . $field]);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// If the validation method throws an exception, add it to the errors
|
||||
$errors[self::getFormFieldPrefix() . $field] = [
|
||||
'error' => 'The field is invalid, please check the format',
|
||||
'field' => self::getFormFieldPrefix() . $field,
|
||||
];
|
||||
}
|
||||
if (!$is_valid) {
|
||||
// Check if the value is empty, and the field isn't required
|
||||
// If the field is required, we don't need to add it to the errors
|
||||
|
||||
Reference in New Issue
Block a user