Refactor and enhance booking, customer, and caching logic
Improved booking handling with unfulfilled booking checks and Slack notifications. Enhanced customer data retrieval with caching optimizations and discount calculations. Added logging, debug capabilities, and expanded Redis functionalities for better data management.
This commit is contained in:
@@ -144,4 +144,173 @@ class redis implements redis_i
|
||||
$this->delete('department_name_' . $department_id);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function cache_economic_customer_discount_percentage(int $customer_number, int $discount_percentage): self
|
||||
{
|
||||
// Cache the economic customer discount percentage
|
||||
$this->set('economic_customer_discount_percentage_' . $customer_number, $discount_percentage);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function get_economic_customer_discount_percentage(int $customer_number): int|null
|
||||
{
|
||||
// Get the economic customer discount percentage
|
||||
return $this->get('economic_customer_discount_percentage_' . $customer_number);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function clear_economic_customer_discount_percentage(int $customer_number): self
|
||||
{
|
||||
// Clear the economic customer discount percentage
|
||||
$this->delete('economic_customer_discount_percentage_' . $customer_number);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function cache_customer_notes(int $customer_id, array $customer_notes): self
|
||||
{
|
||||
// Cache the customer notes
|
||||
$this->set_array('customer_notes_' . $customer_id, $customer_notes);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function get_customer_notes(int $customer_id): array|null
|
||||
{
|
||||
// Get the customer notes
|
||||
return $this->get_array('customer_notes_' . $customer_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function clear_customer_notes(int $customer_id): self
|
||||
{
|
||||
// Clear the customer notes
|
||||
$this->delete('customer_notes_' . $customer_id);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function add_log(string $module, string $department, int $type, int $user_id, string $action, string $message): redis_i
|
||||
{
|
||||
// Get the current timestamp
|
||||
$timestamp = strtotime('now');
|
||||
// Get unique id for the log
|
||||
$log_id = uniqid();
|
||||
// Add the log to the cache
|
||||
$this->set_array('log_' . $log_id, [
|
||||
'module' => $module,
|
||||
'department' => $department,
|
||||
'type' => $type,
|
||||
'user_id' => $user_id,
|
||||
'action' => $action,
|
||||
'message' => $message,
|
||||
'timestamp' => $timestamp
|
||||
]);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function get_logs(): array|null
|
||||
{
|
||||
// Get all logs from the cache
|
||||
return $this->get_arrays('log_*');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function clear_logs(): self
|
||||
{
|
||||
// Clear all logs from the cache
|
||||
$keys = $this->get_keys('log_*');
|
||||
foreach ( $keys as $key ) {
|
||||
$this->delete($key);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function get_department(int $department_id): array|null
|
||||
{
|
||||
// Get the department
|
||||
return $this->get_array('department_' . $department_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function clear_department(int $department_id): self
|
||||
{
|
||||
// Clear the departments
|
||||
$this->clear_departments();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function clear_departments(): self
|
||||
{
|
||||
// Clear all departments from the cache
|
||||
$this->delete('departments');
|
||||
$keys = $this->get_keys('department_*');
|
||||
foreach ( $keys as $key ) {
|
||||
$this->delete($key);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function get_departments(): array|null
|
||||
{
|
||||
// Get all departments from the cache
|
||||
return $this->get_array('departments');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function cache_departments(array $departments): self
|
||||
{
|
||||
// Cache the departments
|
||||
foreach ( $departments as $department ) {
|
||||
$this->cache_department($department['id'], $department);
|
||||
}
|
||||
redis->set_array('departments', $departments);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function cache_department(int $department_id, array $department): self
|
||||
{
|
||||
// Cache the department
|
||||
$this->set_array('department_' . $department_id, $department);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+29
-15
@@ -19,6 +19,7 @@ class response implements response_i
|
||||
|
||||
#[NoReturn] public function response(bool $success, mixed $data, int $status = null): void
|
||||
{
|
||||
global $DEBUG;
|
||||
header('Content-Type: application/json');
|
||||
if ($status) {
|
||||
http_response_code($status);
|
||||
@@ -29,6 +30,14 @@ class response implements response_i
|
||||
if (!is_array($data)) {
|
||||
$data = ['message' => $data];
|
||||
}
|
||||
// If the debug mode is enabled, add the debug data to the response
|
||||
if ($DEBUG) {
|
||||
$this->add_include('debug', [
|
||||
'memory' => memory_get_usage(),
|
||||
'time' => microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'],
|
||||
'data' => $this->get_data()
|
||||
]);
|
||||
}
|
||||
echo json_encode([
|
||||
'success' => $success,
|
||||
'data' => $data,
|
||||
@@ -38,6 +47,21 @@ class response implements response_i
|
||||
exit;
|
||||
}
|
||||
|
||||
public function add_include(string $string, array $dataArray): void
|
||||
{
|
||||
$this->add_included($string, $dataArray);
|
||||
}
|
||||
|
||||
public function add_included(string $key, mixed $value): void
|
||||
{
|
||||
$this->includes[$key] = $value;
|
||||
}
|
||||
|
||||
public function get_data(): array
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
#[NoReturn] public function not_found(): void
|
||||
{
|
||||
$this->error('Not found', 404);
|
||||
@@ -89,11 +113,6 @@ class response implements response_i
|
||||
$this->meta[$key] = $value;
|
||||
}
|
||||
|
||||
public function get_data(): array
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
public function is_matching_route_found(): bool
|
||||
{
|
||||
return $this->matching_route_found;
|
||||
@@ -123,16 +142,6 @@ class response implements response_i
|
||||
return $data[$key] ?? null;
|
||||
}
|
||||
|
||||
public function add_include(string $string, array $dataArray): void
|
||||
{
|
||||
$this->add_included($string, $dataArray);
|
||||
}
|
||||
|
||||
public function add_included(string $key, mixed $value): void
|
||||
{
|
||||
$this->includes[$key] = $value;
|
||||
}
|
||||
|
||||
public function parseFilters(?string $filters): array|null
|
||||
{
|
||||
if ($filters) {
|
||||
@@ -149,4 +158,9 @@ class response implements response_i
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function add_debug_list(string $list_name, int $key, $value): void
|
||||
{
|
||||
$this->add_data($list_name, [$key => $value]);
|
||||
}
|
||||
}
|
||||
+24
-1
@@ -90,7 +90,30 @@ class slack implements notification_i
|
||||
// Get the customer name
|
||||
$customer_name = (new users_o())->getCustomerName($customer_number);
|
||||
// Format the message
|
||||
return "New booking created\n"
|
||||
return "*New booking created* ( ID: " . $id . " )\n"
|
||||
. "Customer: $customer_name\n"
|
||||
. "Customer number: $customer_number\n"
|
||||
. "Wash type: $wash_type\n"
|
||||
. "Contact email: $contact_email\n"
|
||||
. "Reference number: $reference_number\n"
|
||||
. "RegNr Traekker: $regNrTraekker\n"
|
||||
. "RegNr Trailer: $regNrTrailer\n"
|
||||
. "Wash certificate email: $washCertificateEmail\n"
|
||||
. "Date: $date\n"
|
||||
. "Department: $department_name\n"
|
||||
. "Pickup: $pickup_bool\n"
|
||||
. "Notes: $notes\n"
|
||||
. "Status: $status";
|
||||
}
|
||||
|
||||
public function format_unfulfilled_booking($id, $customer_number, string $wash_type, string $contact_email, string $reference_number, string $regNrTraekker, string $regNrTrailer, string $washCertificateEmail, string $date, int $department, $pickup_bool, string $notes, string $washCertificateStatus, string $washCertificateUrl, string $status): string
|
||||
{
|
||||
// Get the department name
|
||||
$department_name = (new departments_o())->getDepartmentName($department);
|
||||
// Get the customer name
|
||||
$customer_name = (new users_o())->getCustomerName($customer_number);
|
||||
// Format the message
|
||||
return "Unfulfilled booking from " . $date . "\n"
|
||||
. "ID: $id\n"
|
||||
. "Customer: $customer_name\n"
|
||||
. "Customer number: $customer_number\n"
|
||||
|
||||
@@ -16,6 +16,10 @@ if ($args[1] === 'run') {
|
||||
echo "Running the redis test script";
|
||||
require_once 'tests/redis/redisTest.php';
|
||||
break;
|
||||
case 'redis-logSync-test':
|
||||
echo "Running the redis log sync test script";
|
||||
require_once 'tests/redis/redisLogSyncTest.php';
|
||||
break;
|
||||
case 'bookingModule-test':
|
||||
echo "Running the bookingModule test script";
|
||||
require_once 'tests/bookingModule/bookingModuleTest.php';
|
||||
@@ -31,6 +35,9 @@ if ($args[1] === 'run') {
|
||||
case 'bookingSync':
|
||||
require_once 'cron/SyncBookings.php';
|
||||
break;
|
||||
case 'SyncLogs':
|
||||
require_once 'cron/SyncLogs.php';
|
||||
break;
|
||||
default:
|
||||
echo "Invalid script name";
|
||||
break;
|
||||
|
||||
@@ -16,4 +16,7 @@ if (!defined('WD')) {
|
||||
|
||||
// Sync the bookings
|
||||
$bookings_o = new bookings_o();
|
||||
$bookings_o->syncBookings();
|
||||
$bookings_o->syncBookings();
|
||||
|
||||
// Check if any bookings from yesterday haven't been fulfilled
|
||||
$bookings_o->checkUnfulfilledBookings();
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
/**
|
||||
* This script is used to sync the logs to the database.
|
||||
* It is run as a cron job.
|
||||
*
|
||||
* index.php run SyncLogs
|
||||
*/
|
||||
|
||||
// prevent direct access
|
||||
|
||||
use objects\logs_o;
|
||||
|
||||
if (!defined('WD')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Sync the logs to the database
|
||||
$logs_o = new logs_o();
|
||||
$logs_o->syncLogsToDatabase();
|
||||
@@ -91,4 +91,114 @@ interface redis_i
|
||||
* @return self
|
||||
*/
|
||||
public function clear_department_name(int $department_id): self;
|
||||
|
||||
/**
|
||||
* Cache an economic customers discount percentage
|
||||
* @param int $customer_number
|
||||
* @param int $discount_percentage
|
||||
* @return self
|
||||
*/
|
||||
public function cache_economic_customer_discount_percentage(int $customer_number, int $discount_percentage): self;
|
||||
|
||||
/**
|
||||
* Get an economic customers discount percentage
|
||||
* @param int $customer_number
|
||||
* @return int|null
|
||||
*/
|
||||
public function get_economic_customer_discount_percentage(int $customer_number): int|null;
|
||||
|
||||
/**
|
||||
* Clear an economic customers discount percentage
|
||||
* @param int $customer_number
|
||||
* @return self
|
||||
*/
|
||||
public function clear_economic_customer_discount_percentage(int $customer_number): self;
|
||||
|
||||
/**
|
||||
* Cache a customer notes
|
||||
* @param int $customer_id
|
||||
* @param array $customer_notes
|
||||
* @return self
|
||||
*/
|
||||
public function cache_customer_notes(int $customer_id, array $customer_notes): self;
|
||||
|
||||
/**
|
||||
* Get a customer notes
|
||||
* @param int $customer_id
|
||||
* @return array|null
|
||||
*/
|
||||
public function get_customer_notes(int $customer_id): array|null;
|
||||
|
||||
/**
|
||||
* Clear a customer notes
|
||||
* @param int $customer_id
|
||||
* @return self
|
||||
*/
|
||||
public function clear_customer_notes(int $customer_id): self;
|
||||
|
||||
/**
|
||||
* Add a log to the logs cache
|
||||
* @param string $module
|
||||
* @param string $department
|
||||
* @param int $type
|
||||
* @param int $user_id
|
||||
* @param string $action
|
||||
* @param string $message
|
||||
* @return self
|
||||
*/
|
||||
public function add_log(string $module, string $department, int $type, int $user_id, string $action, string $message): self;
|
||||
|
||||
/**
|
||||
* Get all logs from the logs cache
|
||||
* @return array|null
|
||||
*/
|
||||
public function get_logs(): array|null;
|
||||
|
||||
/**
|
||||
* Clear all logs from the logs cache
|
||||
* @return self
|
||||
*/
|
||||
public function clear_logs(): self;
|
||||
|
||||
/**
|
||||
* Cache a department
|
||||
* @param int $department_id
|
||||
* @param array $department
|
||||
* @return self
|
||||
*/
|
||||
public function cache_department(int $department_id, array $department): self;
|
||||
|
||||
/**
|
||||
* Get a department
|
||||
* @param int $department_id
|
||||
* @return array|null
|
||||
*/
|
||||
public function get_department(int $department_id): array|null;
|
||||
|
||||
/**
|
||||
* Clear a department
|
||||
* @param int $department_id
|
||||
* @return self
|
||||
*/
|
||||
public function clear_department(int $department_id): self;
|
||||
|
||||
/**
|
||||
* Get departments from the cache
|
||||
* @return array|null
|
||||
*/
|
||||
public function get_departments(): array|null;
|
||||
|
||||
/**
|
||||
* Cache departments
|
||||
* @param array $departments
|
||||
* @return self
|
||||
*/
|
||||
public function cache_departments(array $departments): self;
|
||||
|
||||
/**
|
||||
* Clear departments from the cache
|
||||
* @return self
|
||||
*/
|
||||
public function clear_departments(): self;
|
||||
|
||||
}
|
||||
@@ -24,7 +24,7 @@ class economicCustomers extends economic_m
|
||||
}
|
||||
// Get the customer name from the economic system
|
||||
$customer = $this->getCustomerId($customer_number);
|
||||
if (count($customer) > 0) {
|
||||
if ($customer) {
|
||||
$customer = $customer[0];
|
||||
redis->cache_economic_customer_name($customer_number, $customer->name);
|
||||
return $customer->name;
|
||||
@@ -32,12 +32,47 @@ class economicCustomers extends economic_m
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getCustomerId(int $customerNumber): array|bool
|
||||
public function getCustomerId(int $customerNumber): object|bool
|
||||
{
|
||||
// Check if the customer exists
|
||||
$url = '/customers?filter=customerNumber$eq:' . $customerNumber;
|
||||
$url = '/customers/' . $customerNumber;
|
||||
$response = $this->send_request($url, 'GET', '');
|
||||
$response = json_decode($response);
|
||||
return $response->collection;
|
||||
|
||||
return isset($response->customerNumber) ? $response : false;
|
||||
}
|
||||
|
||||
public function getCustomerProduct(int $customer_number, int $product_id): object
|
||||
{
|
||||
// Get the customer product
|
||||
$url = '/customers/' . $customer_number . '/templates/invoiceline/' . $product_id;
|
||||
$response = $this->send_request($url, 'GET', '');
|
||||
return json_decode($response);
|
||||
}
|
||||
|
||||
public function getCustomerDiscountPercentage(int $customer_number): int
|
||||
{
|
||||
// Get the customer products
|
||||
$products = $this->getCustomerProducts($customer_number, 1)->collection;
|
||||
$discount = $this->getCustomerProductDiscount($customer_number, $products[0]->product->productNumber);
|
||||
// Since the discount is global, we only need to get the discount for one product
|
||||
return $discount->discountPercentage;
|
||||
}
|
||||
|
||||
public function getCustomerProducts(int $customer_number, int $limit = 10, int $page = 1): object
|
||||
{
|
||||
// Get the customer products
|
||||
$url = '/customers/' . $customer_number . '/templates/invoiceline/?pagesize=' . $limit . '&skippages=' . $page - 1;
|
||||
$response = $this->send_request($url, 'GET', '');
|
||||
return json_decode($response);
|
||||
}
|
||||
|
||||
public function getCustomerProductDiscount(int $customer_number, int $product_id)
|
||||
{
|
||||
// Get the customer global discount
|
||||
$url = '/customers/' . $customer_number . '/templates/invoiceline/' . $product_id;
|
||||
$response = $this->send_request($url, 'GET', '');
|
||||
$response = json_decode($response);
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace customers;
|
||||
|
||||
use classes\response;
|
||||
|
||||
class economic_customer_mo
|
||||
{
|
||||
public int $customer_number;
|
||||
@@ -22,8 +24,8 @@ class economic_customer_mo
|
||||
$economicCustomers = new economicCustomers();
|
||||
$customer = $economicCustomers->getCustomerId($customer_number);
|
||||
// Check if the customer exists
|
||||
if (count($customer) > 0) {
|
||||
return $this->parseCustomer($customer[0]);
|
||||
if ($customer) {
|
||||
return $this->parseCustomer($customer);
|
||||
}
|
||||
return $this;
|
||||
|
||||
@@ -31,6 +33,8 @@ class economic_customer_mo
|
||||
|
||||
public function parseCustomer($customer): static
|
||||
{
|
||||
global /** @var response $response */
|
||||
$response;
|
||||
$this->customer_number = $customer->customerNumber;
|
||||
$this->name = ($customer->name ?? null);
|
||||
$this->address = ($customer->address ?? null);
|
||||
@@ -43,6 +47,9 @@ class economic_customer_mo
|
||||
$this->country = ($customer->country ?? null);
|
||||
// Cache the customer name
|
||||
redis->cache_economic_customer_name($this->customer_number, $this->name);
|
||||
$economicCustomers = new economicCustomers();
|
||||
// Add the customer to the debug log
|
||||
$response->add_debug_list('economic_customer', $this->customer_number, $customer);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
+46
-10
@@ -6,6 +6,7 @@ use classes\db;
|
||||
use classes\object_property;
|
||||
use classes\response;
|
||||
use classes\slack;
|
||||
use classes\wash_certificate_store;
|
||||
use classes\wordpress_bookings_remote;
|
||||
use traits\db_object_t;
|
||||
|
||||
@@ -28,16 +29,6 @@ class bookings_o extends db
|
||||
public object_property $washCertificateUrl;
|
||||
public object_property $status;
|
||||
|
||||
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 structure(): void
|
||||
{
|
||||
$this->setTable('bookings');
|
||||
@@ -270,4 +261,49 @@ class bookings_o extends db
|
||||
$this->id = $db->insert_id();
|
||||
}
|
||||
|
||||
public function checkUnfulfilledBookings(): void
|
||||
{
|
||||
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 has been fulfilled
|
||||
$fulfilled = $this->checkBookingFulfilled($booking['id']);
|
||||
if (!$fulfilled) {
|
||||
echo "Booking with ID $booking[id] has not been fulfilled\n";
|
||||
// Send a department webhook if the booking has not been fulfilled
|
||||
$slack = new slack();
|
||||
try {
|
||||
$slack->send_department_booking_notification($booking['department'], $slack->format_unfulfilled_booking($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'], $booking['notes'], $booking['washCertificateStatus'], $booking['washCertificateUrl'], $booking['status']));
|
||||
} catch (\Exception $e) {
|
||||
// Log the error
|
||||
$logs = new logs_o();
|
||||
$logs->add('slack', 0, 3, 0, 'SEND_DEPARTMENT_BOOKING_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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,6 +9,7 @@ use traits\db_object_t;
|
||||
class customer_notes_o extends db
|
||||
{
|
||||
use db_object_t;
|
||||
|
||||
public object_property $customer_id;
|
||||
public object_property $note;
|
||||
public object_property $cashier_id;
|
||||
@@ -19,14 +20,6 @@ class customer_notes_o extends db
|
||||
$this->setTable('customer_notes');
|
||||
}
|
||||
|
||||
public function getObjectProperties(): void
|
||||
{
|
||||
$this->customer_id = new object_property($this->table, $this->id, 'customer_id', 'int', true);
|
||||
$this->note = new object_property($this->table, $this->id, 'note', 'string', true);
|
||||
$this->cashier_id = new object_property($this->table, $this->id, 'cashier_id', 'int', true);
|
||||
$this->deleted_at = new object_property($this->table, $this->id, 'deleted_at', 'timestamp', false);
|
||||
}
|
||||
|
||||
public function add(int $customer_id, string $note, int $cashier_id): customer_notes_o
|
||||
{
|
||||
global $db, $response;
|
||||
@@ -42,15 +35,32 @@ class customer_notes_o extends db
|
||||
|
||||
// Set the values of the object properties
|
||||
$this->getObjectProperties();
|
||||
|
||||
// Clear the cache
|
||||
redis->clear_customer_notes($customer_id);
|
||||
} catch (\Exception $e) {
|
||||
$response->error($e->getMessage());
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getObjectProperties(): void
|
||||
{
|
||||
$this->customer_id = new object_property($this->table, $this->id, 'customer_id', 'int', true);
|
||||
$this->note = new object_property($this->table, $this->id, 'note', 'string', true);
|
||||
$this->cashier_id = new object_property($this->table, $this->id, 'cashier_id', 'int', true);
|
||||
$this->deleted_at = new object_property($this->table, $this->id, 'deleted_at', 'timestamp', false);
|
||||
}
|
||||
|
||||
public function getCustomerNotesAsArray(int $customer_id): array
|
||||
{
|
||||
global $db;
|
||||
global $response, $db;
|
||||
// Check if the result is cached
|
||||
$cached = redis->get_customer_notes($customer_id);
|
||||
if ($cached) {
|
||||
$response->add_meta('cached', true);
|
||||
return $cached;
|
||||
}
|
||||
$sql = "SELECT * FROM $this->table WHERE customer_id = $customer_id AND deleted_at IS NULL";
|
||||
$result = $db->query($sql);
|
||||
$customer_notes = [];
|
||||
@@ -59,6 +69,8 @@ class customer_notes_o extends db
|
||||
$customer_notes[] = $row;
|
||||
}
|
||||
}
|
||||
// Cache the result
|
||||
redis->cache_customer_notes($customer_id, $customer_notes);
|
||||
return $customer_notes;
|
||||
}
|
||||
|
||||
@@ -81,6 +93,21 @@ class customer_notes_o extends db
|
||||
$this->id = $id;
|
||||
$sql = "UPDATE $this->table SET deleted_at = NOW() WHERE id = $this->id";
|
||||
$db->query($sql);
|
||||
// Clear the cache
|
||||
$customer_id = $this->getCustomerByNoteId($this->id);
|
||||
redis->clear_customer_notes($customer_id);
|
||||
}
|
||||
|
||||
public function getCustomerByNoteId(int $id): int
|
||||
{
|
||||
global $db;
|
||||
$sql = "SELECT customer_id FROM $this->table WHERE id = $id";
|
||||
$result = $db->query($sql);
|
||||
if ($result->num_rows > 0) {
|
||||
$row = $result->fetch_assoc();
|
||||
return $row['customer_id'];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function restore(int $id): void
|
||||
@@ -89,5 +116,8 @@ class customer_notes_o extends db
|
||||
$this->id = $id;
|
||||
$sql = "UPDATE $this->table SET deleted_at = NULL WHERE id = $this->id";
|
||||
$db->query($sql);
|
||||
// Clear the cache
|
||||
$customer_id = $this->getCustomerByNoteId($this->id);
|
||||
redis->clear_customer_notes($customer_id);
|
||||
}
|
||||
}
|
||||
+34
-10
@@ -35,6 +35,9 @@ class departments_o extends db
|
||||
|
||||
// Set the values of the object properties
|
||||
$this->getObjectProperties();
|
||||
|
||||
// Clear the cache
|
||||
redis->clear_departments();
|
||||
}
|
||||
|
||||
public function getObjectProperties(): void
|
||||
@@ -62,34 +65,55 @@ class departments_o extends db
|
||||
|
||||
// Set the values of the object properties
|
||||
$this->getObjectProperties();
|
||||
|
||||
// Clear the cache
|
||||
redis->clear_department($id);
|
||||
}
|
||||
|
||||
public function list($superUser = false): array
|
||||
{
|
||||
global $db;
|
||||
$sql = "SELECT * FROM $this->table";
|
||||
$result = $db->query($sql);
|
||||
$result = $db->fetch_all($result);
|
||||
// Check if the departments are cached
|
||||
$departments = redis->get_departments();
|
||||
// If the departments are not cached, get them from the database
|
||||
if ($departments === null) {
|
||||
$sql = "SELECT * FROM $this->table";
|
||||
$result = $db->query($sql);
|
||||
$departments = $db->fetch_all($result);
|
||||
// Cache the departments (If it is not empty or null)
|
||||
if (!empty($departments)) {
|
||||
redis->cache_departments($departments);
|
||||
}
|
||||
}
|
||||
// Only show the name, description and id if the user isn't a super user
|
||||
if (!$superUser) {
|
||||
$result = array_map(function ($department) {
|
||||
$departments = array_map(function ($department) {
|
||||
return [
|
||||
'name' => $department['name'],
|
||||
'description' => $department['description'],
|
||||
'id' => $department['id']
|
||||
];
|
||||
}, $result);
|
||||
return $result;
|
||||
}, $departments);
|
||||
}
|
||||
return $result;
|
||||
return $departments;
|
||||
}
|
||||
|
||||
public function getDepartmentById(int $id): array
|
||||
{
|
||||
global $db;
|
||||
$sql = "SELECT * FROM $this->table WHERE id = $id";
|
||||
$result = $db->query($sql);
|
||||
return $db->fetch_assoc($result);
|
||||
// Check if the department is cached
|
||||
$department = redis->get_department($id);
|
||||
// If the department is not cached, get it from the database
|
||||
if ($department === null) {
|
||||
$sql = "SELECT * FROM $this->table WHERE id = $id";
|
||||
$result = $db->query($sql);
|
||||
$department = $db->fetch_assoc($result);
|
||||
// Cache the department (If it is not empty or null)
|
||||
if (!empty($department)) {
|
||||
redis->cache_department($id, $department);
|
||||
}
|
||||
}
|
||||
return $department;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+29
-16
@@ -9,6 +9,7 @@ use traits\db_object_t;
|
||||
class logs_o extends db
|
||||
{
|
||||
use db_object_t;
|
||||
|
||||
public object_property $module;
|
||||
public object_property $department;
|
||||
public object_property $type;
|
||||
@@ -21,6 +22,12 @@ class logs_o extends db
|
||||
$this->setTable('logs');
|
||||
}
|
||||
|
||||
public function add(string $module, string $department, int $type, int $user_id, string $action, string $message): void
|
||||
{
|
||||
// Add to the cache instead of the database, to make it faster
|
||||
redis->add_log($module, $department, $type, $user_id, $action, $message);
|
||||
}
|
||||
|
||||
public function getObjectProperties(): void
|
||||
{
|
||||
$this->module = new object_property($this->table, $this->id, 'module', 'string', true);
|
||||
@@ -31,22 +38,28 @@ class logs_o extends db
|
||||
$this->message = new object_property($this->table, $this->id, 'message', 'string', false);
|
||||
}
|
||||
|
||||
public function add(string $module, string $department, int $type, int $user_id, string $action, string $message): void
|
||||
public function syncLogsToDatabase(): void
|
||||
{
|
||||
global $db;
|
||||
// Avoid SQL injection
|
||||
$module = $db->escape_string($module);
|
||||
$department = $db->escape_string($department);
|
||||
$action = $db->escape_string($action);
|
||||
$message = $db->escape_string($message);
|
||||
// Create a new record in the database
|
||||
$sql = "INSERT INTO $this->table (module, department, type, user_id, action, message) VALUES ('$module', '$department', $type, $user_id, '$action', '$message')";
|
||||
$db->query($sql);
|
||||
|
||||
// Get the id of the new record
|
||||
$this->id = $db->insert_id();
|
||||
|
||||
// Set the values of the object properties
|
||||
$this->getObjectProperties();
|
||||
global /** @var db $db */
|
||||
$db;
|
||||
// Get all logs from the cache
|
||||
$logs = redis->get_logs();
|
||||
if ($logs) {
|
||||
foreach ( $logs as $log ) {
|
||||
// Avoid SQL injection
|
||||
$module = $db->escape_string($log['module']);
|
||||
$department = $db->escape_string($log['department']);
|
||||
$action = $db->escape_string($log['action']);
|
||||
$message = $db->escape_string($log['message']);
|
||||
$timestamp = $log['timestamp'];
|
||||
// Convert the timestamp to a date
|
||||
$timestamp = date('Y-m-d H:i:s', $timestamp);
|
||||
// Create a new record in the database
|
||||
$sql = "INSERT INTO $this->table (module, department, type, user_id, action, message, created_at, updated_at) VALUES ('$module', '$department', {$log['type']}, {$log['user_id']}, '$action', '$message', '$timestamp', '$timestamp')";
|
||||
$db->query($sql);
|
||||
}
|
||||
// Clear all logs from the cache
|
||||
redis->clear_keys($logs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,6 @@ class orders_o extends db
|
||||
return $this;
|
||||
} catch (\Exception $e) {
|
||||
$response->error($e->getMessage());
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -106,15 +106,22 @@ class user_price_overrides_o extends db
|
||||
if (!$is_category) {
|
||||
$product = (new products_o())->getProductById($product_or_category_id);
|
||||
if ($product->apply_category_discount->value()) {
|
||||
// Get the economic user discount
|
||||
$economic_user_global_discount = (new users_o())->getUserById($this->user_id)->getEconomicCustomerDiscountPercentage();
|
||||
// Get the category discount
|
||||
$sql = "SELECT * FROM $this->table WHERE user_id = " . $this->user_id . " AND is_category = 1 AND product_or_category_id = '" . $product->category->value() . "'";
|
||||
$result = $db->query($sql);
|
||||
if ($result->num_rows > 0) {
|
||||
$category_discount = $result->fetch_assoc()['percentage'];
|
||||
// If the category discount is higher than the product discount, return the category discount
|
||||
if ((int)$category_discount > (int)$percentage) {
|
||||
if ((int)$category_discount > (int)$percentage && (int)$category_discount > (int)$economic_user_global_discount) {
|
||||
return $category_discount;
|
||||
}
|
||||
}
|
||||
// If the economic user discount is higher than the product discount, return the economic user discount
|
||||
if ((int)$economic_user_global_discount > (int)$percentage) {
|
||||
return $economic_user_global_discount;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $percentage;
|
||||
@@ -127,6 +134,8 @@ class user_price_overrides_o extends db
|
||||
public function getAllPrices(): array
|
||||
{
|
||||
global $db;
|
||||
// Get the customers global discount
|
||||
$economic_user_global_discount = (new users_o())->getUserById($this->user_id)->getEconomicCustomerDiscountPercentage();
|
||||
// Get all the price overrides for the user
|
||||
$sql = "SELECT * FROM $this->table WHERE user_id = " . $this->user_id;
|
||||
$result = $db->query($sql);
|
||||
@@ -136,6 +145,18 @@ class user_price_overrides_o extends db
|
||||
$prices[] = $row;
|
||||
}
|
||||
}
|
||||
// If the user has a global discount, add it to the list
|
||||
if ($economic_user_global_discount > 0) {
|
||||
$prices[] = [
|
||||
'id' => "999999",
|
||||
'user_id' => "" . $this->user_id,
|
||||
'is_category' => "1",
|
||||
'product_or_category_id' => "global",
|
||||
'percentage' => "" . $economic_user_global_discount,
|
||||
'created_at' => "2021-01-01 00:00:00",
|
||||
'updated_at' => "2021-01-01 00:00:00"
|
||||
];
|
||||
}
|
||||
return $prices;
|
||||
}
|
||||
}
|
||||
+17
-2
@@ -103,9 +103,9 @@ class users_o extends db
|
||||
$customer_data = $economic->getCustomerId($customer_number);
|
||||
// DEBUG: Return the customer data
|
||||
// Check if the customer exists
|
||||
if (isset($customer_data[0])) {
|
||||
if ($customer_data) {
|
||||
// Avoid SQL injection
|
||||
$customer_number = $db->escape_string($customer_data[0]->customerNumber);
|
||||
$customer_number = $db->escape_string($customer_data->customerNumber);
|
||||
// Double check if the customer exists
|
||||
$sql = "SELECT * FROM $this->table WHERE customer_number = '$customer_number'";
|
||||
$result = $db->query($sql);
|
||||
@@ -669,4 +669,19 @@ class users_o extends db
|
||||
}
|
||||
return $listObjectsWithPaginationIfSet;
|
||||
}
|
||||
|
||||
public function getEconomicCustomerDiscountPercentage(): int
|
||||
{
|
||||
// Check if the discount percentage is cached
|
||||
$cached_discount_percentage = redis->get_economic_customer_discount_percentage($this->customer_number->value());
|
||||
if ($cached_discount_percentage !== null) {
|
||||
return $cached_discount_percentage;
|
||||
}
|
||||
// Get the discount percentage from the external source
|
||||
$economic = new economicCustomers();
|
||||
$discount_percentage = $economic->getCustomerDiscountPercentage($this->customer_number->value());
|
||||
// Cache the discount percentage
|
||||
redis->cache_economic_customer_discount_percentage($this->customer_number->value(), $discount_percentage);
|
||||
return $discount_percentage;
|
||||
}
|
||||
}
|
||||
@@ -25,16 +25,19 @@ class customerNotes
|
||||
// Get the query parameters from the URL
|
||||
$data = $_GET;
|
||||
// Check if the required fields are set
|
||||
if (!isset($data['customer_number']) && !isset($data['user_id'])) { $response->error('User ID or Customer Number is required', 400); }
|
||||
if (!isset($data['customer_number']) && !isset($data['user_id'])) {
|
||||
$response->error('User ID or Customer Number is required', 400);
|
||||
}
|
||||
// Log the incident
|
||||
(new logs_o())->add('customer_notes', 'global', 1, $user->id, 'LIST_CUSTOMER_NOTES', 'Successfully listed customer notes');
|
||||
// Check if the user exists
|
||||
if (!(new users_o())->automaticGetTargetUserFromRequest()->exists()) {
|
||||
$targetUser = (new users_o())->automaticGetTargetUserFromRequest();
|
||||
if (!$targetUser->exists()) {
|
||||
$response->error('Customer not found', 400);
|
||||
}
|
||||
// Return the list of customer notes
|
||||
$response->success(
|
||||
(new users_o())->automaticGetTargetUserFromRequest()->getNotes()
|
||||
($targetUser->getNotes())
|
||||
);
|
||||
} else {
|
||||
// Log the incident
|
||||
@@ -55,8 +58,12 @@ class customerNotes
|
||||
// Get the post data
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
// Check if the required fields are set
|
||||
if (!isset($data['user_id']) && !isset($data['customer_number'])) { $response->error('User ID or Customer Number is required', 400); }
|
||||
if (!isset($data['note'])) { $response->error('Note is required', 400); }
|
||||
if (!isset($data['user_id']) && !isset($data['customer_number'])) {
|
||||
$response->error('User ID or Customer Number is required', 400);
|
||||
}
|
||||
if (!isset($data['note'])) {
|
||||
$response->error('Note is required', 400);
|
||||
}
|
||||
// Add the note to the customer
|
||||
$customer = (new users_o())->automaticGetTargetUserFromRequest();
|
||||
// Check if the customer exists
|
||||
@@ -87,7 +94,9 @@ class customerNotes
|
||||
// Get the query parameters from the URL
|
||||
$data = $_GET;
|
||||
// Check if the required fields are set
|
||||
if (!isset($data['id'])) { $response->error('Note ID is required', 400); }
|
||||
if (!isset($data['id'])) {
|
||||
$response->error('Note ID is required', 400);
|
||||
}
|
||||
// Delete the note from the customer
|
||||
(new customer_notes_o())->delete((int)$data['id']);
|
||||
// Log the incident
|
||||
|
||||
@@ -55,11 +55,13 @@ class ordersRoute
|
||||
$response->error('Department not found', 400);
|
||||
}
|
||||
// Make sure the customer number set is valid
|
||||
if (!(new users_o())->getCustomerByIdOrCustomerNumber((int)$data['customer_id'])->exists() || empty($data['customer_id'])) {
|
||||
$response->error('Customer not found or invalid', 400);
|
||||
$targetUser = (new users_o())->getCustomerByIdOrCustomerNumber((int)$data['customer_id']);
|
||||
if (!$targetUser->exists()) {
|
||||
$response->error('Customer not found', 400);
|
||||
}
|
||||
|
||||
// Check if the user requires a reference
|
||||
if ((new users_o())->getCustomerByIdOrCustomerNumber((int)$data['customer_id'])->requiresReference() && empty($data['reference'])) {
|
||||
if ($targetUser->requiresReference() && empty($data['reference'])) {
|
||||
$response->error('Reference is required by the customer', 400);
|
||||
}
|
||||
// Get the registration number
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
// prevent direct access
|
||||
if (!defined('WD')) {
|
||||
exit;
|
||||
}
|
||||
global $REDIS_CONFIG;
|
||||
|
||||
function warn($message): void
|
||||
{
|
||||
echo "\n\033[33m$message\033[0m\n";
|
||||
}
|
||||
|
||||
// Check if the MINIO array is set
|
||||
if (!isset($REDIS_CONFIG)) {
|
||||
throw new Exception('REDIS array is not set in config.php');
|
||||
}
|
||||
// Check if the MINIO array has the required keys
|
||||
if (!isset($REDIS_CONFIG['host']) || !isset($REDIS_CONFIG['database']) || !isset($REDIS_CONFIG['password'])) {
|
||||
throw new Exception('REDIS array is missing required keys');
|
||||
}
|
||||
|
||||
// Create a new Redis object
|
||||
$logs_o = new objects\logs_o();
|
||||
$logs_o->syncLogsToDatabase();
|
||||
+103
-21
@@ -56,27 +56,6 @@ trait redis_t
|
||||
return $this->redis->exists($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value in the Redis server
|
||||
* @param string $key
|
||||
* @param string $value
|
||||
* @return redis|redis_t
|
||||
*/
|
||||
public function set(string $key, string $value): self
|
||||
{
|
||||
$this->redis->set($key, $value);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all keys from the Redis server
|
||||
* @return array
|
||||
*/
|
||||
public function keys(): array
|
||||
{
|
||||
return $this->redis->keys('*');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Redis client
|
||||
* @return PredisClient
|
||||
@@ -246,4 +225,107 @@ trait redis_t
|
||||
{
|
||||
$this->redis->disconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set array key in Redis
|
||||
* @param string $key
|
||||
* @param array $value
|
||||
* @return redis|redis_t
|
||||
*/
|
||||
public function set_array(string $key, array $value): self
|
||||
{
|
||||
$this->set($key, json_encode($value));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value in the Redis server
|
||||
* @param string $key
|
||||
* @param string $value
|
||||
* @return redis|redis_t
|
||||
*/
|
||||
public function set(string $key, string $value): self
|
||||
{
|
||||
$this->redis->set($key, $value);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear keys from Redis
|
||||
* @param array $keys
|
||||
* @return redis|redis_t
|
||||
*/
|
||||
public function clear_keys(array $keys): self
|
||||
{
|
||||
foreach ( $keys as $key ) {
|
||||
$this->delete($key);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get arrays from Redis
|
||||
* @param string $key The key to search for (supports wildcards)
|
||||
* @return array|null
|
||||
*/
|
||||
public function get_arrays(string $key): array|null
|
||||
{
|
||||
$keys = $this->get_keys($key);
|
||||
$arrays = [];
|
||||
foreach ( $keys as $key ) {
|
||||
$arrays[] = $this->get_array($key);
|
||||
}
|
||||
return $arrays;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get keys from Redis
|
||||
* @param string $key The key to search for (supports wildcards)
|
||||
* @return array
|
||||
*/
|
||||
public function get_keys(string $key): array
|
||||
{
|
||||
// Get all keys from the cache
|
||||
return $this->redis->keys($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all keys from the Redis server
|
||||
* @return array
|
||||
*/
|
||||
public function keys(): array
|
||||
{
|
||||
return $this->redis->keys('*');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get array key from Redis
|
||||
* @param string $key
|
||||
* @return array|null
|
||||
*/
|
||||
public function get_array(string $key): array|null
|
||||
{
|
||||
// Get the array from the cache
|
||||
$value = $this->get($key);
|
||||
// Check if the value is not null
|
||||
if ($value === null) {
|
||||
return null;
|
||||
}
|
||||
// Check if the value is not a valid JSON
|
||||
if (!self::is_json($value)) {
|
||||
return null;
|
||||
}
|
||||
return json_decode($value, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the value is a valid JSON
|
||||
* @param string $value
|
||||
* @return bool
|
||||
*/
|
||||
private function is_json(string $value): bool
|
||||
{
|
||||
json_decode($value);
|
||||
return json_last_error() === JSON_ERROR_NONE;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user