Merge pull request #74 from copenhagentruckwash/xl-vask-module

Xl vask module
This commit is contained in:
Jeppe B
2025-07-14 14:26:53 +02:00
committed by GitHub
16 changed files with 440 additions and 56 deletions
+1 -1
View File
@@ -40,7 +40,7 @@ class response implements response_i
}
}
// If the debug mode is enabled, add the debug data to the response
if ($DEBUG) {
if ($DEBUG && false) {
$this->add_include('debug', [
'memory' => memory_get_usage(),
'time' => microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'],
+3 -3
View File
@@ -25,9 +25,9 @@ if (php_sapi_name() === 'cli') {
// Set the max execution time to 0
// This is used to prevent the script from timing out
// when running for a long time
set_time_limit(0);
// Set the memory limit to unlimited
ini_set('memory_limit', '-1');
set_time_limit(10 * 60); // 10 minutes
// Set the memory limit to 16 GB
ini_set('memory_limit', '16G');
// If the first argument is 'run', switch to the second argument
+3 -3
View File
@@ -42,7 +42,7 @@ $cron_tasks = [
'function' => 'syncLogsToDatabase',
],
'SyncUserEconomicCustomerDiscounts' => [
'interval' => 60, // 1 minute
'interval' => 180, // 3 minutes
'last_run' => 0,
'next_run' => 0,
'function' => 'SyncUserEconomicCustomerDiscounts',
@@ -60,13 +60,13 @@ $cron_tasks = [
'function' => 'backup',
],
'SyncEconomicInvoiceStatus' => [
'interval' => 60, // 1 minute
'interval' => 120, // 2 minutes
'last_run' => 0,
'next_run' => 0,
'function' => 'SyncEconomicInvoiceStatus',
],
'SyncXLVaskModuleCron' => [
'interval' => 600, // 10 minutes
'interval' => 3600, // 1 hour
'last_run' => 0,
'next_run' => 0,
'function' => 'SyncXLVaskModuleCron',
@@ -0,0 +1,26 @@
<?php
namespace helpers;
use Exception;
use objects\products_o;
class xlvask_parser_ht_dysebom extends xlvask_product_parser
{
use xlvask_product_parser_t;
public function __construct()
{
$this->setup('ht_dysebom');
}
/**
* @inheritDoc
* @throws Exception
*/
protected function parse(xlvask_wash_item $wash_item, xlvask_usage_log $xlvask_usage_log): products_o
{
return (new products_o())->select(64); // Other irrelevant product ID
}
}
@@ -0,0 +1,26 @@
<?php
namespace helpers;
use Exception;
use objects\products_o;
class xlvask_parser_ikke_b_rster_mellom_bil_og_trailer extends xlvask_product_parser
{
use xlvask_product_parser_t;
public function __construct()
{
$this->setup('ikke_b_rster_mellom_bil_og_trailer');
}
/**
* @inheritDoc
* @throws Exception
*/
protected function parse(xlvask_wash_item $wash_item, xlvask_usage_log $xlvask_usage_log): products_o
{
return (new products_o())->select(64); // Irrelevant product ID
}
}
@@ -0,0 +1,26 @@
<?php
namespace helpers;
use Exception;
use objects\products_o;
class xlvask_parser_ikke_ht_dysebom_mellom_bil_trailer extends xlvask_product_parser
{
use xlvask_product_parser_t;
public function __construct()
{
$this->setup('ikke_ht_dysebom_mellom_bil_trailer');
}
/**
* @inheritDoc
* @throws Exception
*/
protected function parse(xlvask_wash_item $wash_item, xlvask_usage_log $xlvask_usage_log): products_o
{
return (new products_o())->select(64); // Irrelevant product ID
}
}
@@ -0,0 +1,26 @@
<?php
namespace helpers;
use Exception;
use objects\products_o;
class xlvask_parser_ingen_b_rster_foran_no_brush_wash_front extends xlvask_product_parser
{
use xlvask_product_parser_t;
public function __construct()
{
$this->setup('ingen_b_rster_foran_no_brush_wash_front');
}
/**
* @inheritDoc
* @throws Exception
*/
protected function parse(xlvask_wash_item $wash_item, xlvask_usage_log $xlvask_usage_log): products_o
{
return (new products_o())->select(64); // Other irrelevant product ID
}
}
@@ -0,0 +1,26 @@
<?php
namespace helpers;
use Exception;
use objects\products_o;
class xlvask_parser_s_be_dysebom_tak extends xlvask_product_parser
{
use xlvask_product_parser_t;
public function __construct()
{
$this->setup('s_be_dysebom_tak');
}
/**
* @inheritDoc
* @throws Exception
*/
protected function parse(xlvask_wash_item $wash_item, xlvask_usage_log $xlvask_usage_log): products_o
{
return (new products_o())->select(64); // Irrelevant product ID
}
}
@@ -41,7 +41,6 @@ class xlvask_tasks
};
}
/**
* Run the synchronize users task
* This task fetches the users from XL Vask, and synchronizes them with this system.
@@ -187,8 +186,10 @@ class xlvask_tasks
* @return array|null
* @throws Exception
*/
public function runSyncUsage(): array|null
public function runSyncUsage(string $dateFrom = null, string $dateTo = null): array|null
{
// TODO: Remove this, this is just for testing purposes
return null;
// Define the XL Vask object
$xlvask = new \classes\xlvask();
// Require the module to be enabled
@@ -197,10 +198,29 @@ class xlvask_tasks
if (!$xlvask->config->synchronization_enabled->isTrue()) {
throw new Exception('XL Vask synchronization is not enabled.');
}
// TODO: Remove this, this is just for testing purposes:
$dateFrom = "2025-06-01 00:00:00";
$dateTo = "2025-07-01 00:00:00";
// Set the date from which to fetch the usage data
// Since this is a cron task, we will fetch the usage data from the last 24 hours
$minutes = 24 * 60; // 24 hours in minutes
$dateFrom = date('Y-m-d\TH:i:s.000', strtotime('-' . $minutes . ' minutes'));
// TODO: Remove this, this is just for testing purposes:
$minutes = $minutes * 20;
// If dateFrom is not set, set it to 24 hours ago
if (empty($dateFrom)) {
$dateFrom = date('Y-m-d\TH:i:s.000', strtotime('-' . $minutes . ' minutes'));
} else {
// If dateFrom is set, make sure it is in the correct format
$dateFrom = date('Y-m-d\TH:i:s.000', strtotime($dateFrom));
}
// If dateTo is not set, set it to now
if (empty($dateTo)) {
$dateTo = date('Y-m-d\TH:i:s.000'); // Current time in ISO 8601 format
} else {
// If dateTo is set, make sure it is in the correct format
$dateTo = date('Y-m-d\TH:i:s.000', strtotime($dateTo));
}
echo 'Fetching usage data from: ' . $dateFrom . ' to: ' . $dateTo . PHP_EOL;
//echo $dateFrom; (E.g. 2025-06-11T12:13:16.000)
@@ -210,6 +230,139 @@ class xlvask_tasks
// Get the cached customers
$customers = $xlvask->getCache()->getAllCachedCustomers();
// Get all the usage logs from XL Vask
$debug_usage_logs = $xlvask->getUsageLog(
$dateFrom,
null, // regNr
null, // vehicleId
null // customerId
);
$debug_usage_logs = self::formatUsageLogs($debug_usage_logs);
// Filter out the logs that are after the dateTo
$debug_usage_logs = array_filter($debug_usage_logs, function ($log) use ($dateTo) {
/** @var xlvask_usage_log $log */
return strtotime($log->getFormattedDate()) <= strtotime($dateTo);
});
echo 'Found ' . count($debug_usage_logs) . ' usage logs in the date range from ' . $dateFrom . ' to ' . $dateTo . PHP_EOL;
echo "Prepaid: " . count(array_filter($debug_usage_logs, function ($log) {
/** @var xlvask_usage_log $log */
return $log->isPrepaid();
})) . PHP_EOL;
echo "Finished: " . count(array_filter($debug_usage_logs, function ($log) {
/** @var xlvask_usage_log $log */
return $log->isCompleted();
})) . PHP_EOL;
echo 'Not finished (skipped): ' . count(array_filter($debug_usage_logs, function ($log) {
/** @var xlvask_usage_log $log */
return !$log->isCompleted();
})) . PHP_EOL;
echo 'Billed to default customer (skipped): ' . count(array_filter($debug_usage_logs, function ($log) {
/** @var xlvask_usage_log $log */
return $log->hasDefaultCustomer();
})) . PHP_EOL;
echo 'Unique customers: ' . count(array_unique(array_map(function ($log) {
/** @var xlvask_usage_log $log */
return $log->CustomerId;
}, $debug_usage_logs))) . PHP_EOL;
$linked_orders = (new orders_o())->getFieldsWhere([
'wash_id' => array_map(function ($log) {
/** @var xlvask_usage_log $log */
return $log->WashId;
}, $debug_usage_logs),
'deleted_at' => null,
], [
'id',
'wash_id',
]);
echo "Linked to orders: " . count($linked_orders) . PHP_EOL;
$eligible_for_automatic_continuance = array_filter($debug_usage_logs, function ($log) {
/** @var xlvask_usage_log $log */
return $log->isEligibleForAutomaticContinuance(true);
});
$eligible_for_automatic_continuance_without_prepaid = array_filter($debug_usage_logs, function ($log) {
/** @var xlvask_usage_log $log */
return $log->isEligibleForAutomaticContinuance(false);
});
echo "Eligible for automatic continuance: " . count($eligible_for_automatic_continuance) . " (" . count($eligible_for_automatic_continuance_without_prepaid) . " without prepaid)" . PHP_EOL;
// Print a list of customers that do not have an external ID
$customers_without_external_id = array_filter($debug_usage_logs, function ($log) {
/** @var xlvask_usage_log $log */
return !$log->hasExternalId() && !$log->hasDefaultCustomer();
});
echo "Without billable customer: " . count(array_filter($debug_usage_logs, function ($log) {
/** @var xlvask_usage_log $log */
return !$log->hasBillableCustomer();
})) . " (" . count(array_filter($debug_usage_logs, function ($log) {
/** @var xlvask_usage_log $log */
return !$log->hasBillableCustomer() && !$log->hasDefaultCustomer() && !$log->hasExternalId();
})) . " without external ID)" . PHP_EOL;
foreach ( self::sortLogsByDate($customers_without_external_id) as $customer ) {
/** @var xlvask_usage_log $customer */
echo ' - ' . $customer->getFormattedDate() . ' - ' . $customer->Customer . ' - ' . $customer->getDepartment()->name->value() . ', ' . $customer->getLane() . ' - ' . $customer->getTotalPrice() . ' DKK' . ' ( ' . ($customer->isCompleted() ? 'Finished' : 'Not finished') . ', ' . ($customer->isPrepaid() ? 'Prepaid' : 'Not prepaid') . ' )' . PHP_EOL;
}
// Get all unique external IDs from the customers
$unique_external_customer_ids = array_unique(array_map(function ($customer) {
/** @var xlvask_usage_log $customer */
return $customer->CustomerId;
}, $debug_usage_logs));
// Remove the external IDs that are not numeric or empty
$unique_external_customer_ids = array_filter($unique_external_customer_ids, function ($id) {
return !empty($id) && is_numeric($id);
});
echo "Unique external customer IDs: " . count($unique_external_customer_ids) . PHP_EOL;
foreach ( $unique_external_customer_ids as $customer_id ) {
$doesCustomerExistInArray = array_filter($customers, function ($customer) use ($customer_id) {
/** @var xlvask_customer $customer */
return $customer->externId === $customer_id;
});
$tmp_does_customer_exist = count($doesCustomerExistInArray) > 0;
if (!$tmp_does_customer_exist) {
echo ' - ' . $customer_id . ' does not exist in the system (skipped)' . PHP_EOL;
continue; // Skip customers that do not exist in the system
}
$tmp_customer_object = reset($doesCustomerExistInArray); // Get the first customer object that matches the external ID
/** @var xlvask_customer $tmp_customer_object */
echo ' - ' . $tmp_customer_object->name . ' (' . $tmp_customer_object->externId . ') - ' . $tmp_customer_object->customerId . PHP_EOL;
echo " - # Washes: " . count(array_filter($debug_usage_logs, function ($log) use ($tmp_customer_object) {
/** @var xlvask_usage_log $log */
return $log->CustomerId === $tmp_customer_object->externId;
})) . PHP_EOL;
// Echo the eligible for automatic continuance logs
foreach ( self::sortLogsByDate(array_filter($debug_usage_logs, function ($log) use ($tmp_customer_object) {
/** @var xlvask_usage_log $log */
return $log->CustomerId === $tmp_customer_object->externId && $log->isEligibleForAutomaticContinuance(false);
})) as $log ) {
/** @var xlvask_usage_log $log */
$tmp_linked_to_order = array_filter($linked_orders, function ($order) use ($log) {
/** @var array $order */
return $order['wash_id'] === $log->WashId;
});
echo ' - - ' . $log->getFormattedDate() . ' - ' . $log->getDepartment()->name->value() . ', ' . $log->getLane() . ' - ' . $log->getTotalPrice() . ' DKK' . ' ( ' . ($log->isCompleted() ? 'Finished' : 'Not finished') . ', ' . ($log->isPrepaid() ? 'Prepaid' : 'Not prepaid') . ', ' . ($tmp_linked_to_order ? 'Linked to order' : 'Not linked to order') . ' )' . PHP_EOL;
}
// Echo the ineligible for automatic continuance logs
echo " - # Not eligible for automatic continuance: " . count(array_filter($debug_usage_logs, function ($log) use ($tmp_customer_object) {
/** @var xlvask_usage_log $log */
return $log->CustomerId === $tmp_customer_object->externId && !$log->isEligibleForAutomaticContinuance(false);
})) . PHP_EOL;
foreach ( self::sortLogsByDate(array_filter($debug_usage_logs, function ($log) use ($tmp_customer_object) {
/** @var xlvask_usage_log $log */
return $log->CustomerId === $tmp_customer_object->externId && !$log->isEligibleForAutomaticContinuance(false);
})) as $log ) {
/** @var xlvask_usage_log $log */
echo ' - - ' . $log->getFormattedDate() . ' - ' . $log->getDepartment()->name->value() . ', ' . $log->getLane() . ' - ' . $log->getTotalPrice() . ' DKK' . ' ( ' . ($log->isCompleted() ? 'Finished' : 'Not finished') . ', ' . ($log->isPrepaid() ? 'Prepaid' : 'Not prepaid') . ' )' . PHP_EOL;
}
}
echo 'Customers:';
print_r($customers);
echo 'Eligible for automatic continuance:';
print_r($eligible_for_automatic_continuance);
exit;
// Loop through the customers and check if there's any new usage data
foreach ( $customers as $customer ) {
/** @var xlvask_customer $customer */
@@ -330,6 +483,17 @@ class xlvask_tasks
}, $getUsageLog);
}
private static function sortLogsByDate(array $logs): array
{
// Sort the logs by date
usort($logs, function ($a, $b) {
/** @var xlvask_usage_log $a */
/** @var xlvask_usage_log $b */
return strtotime($a->getFormattedDate()) - strtotime($b->getFormattedDate());
});
return $logs; // Return the sorted logs
}
/**
* @throws Exception If the log is not completed, or if the customer does not have an externId, or if the customer does not exist in this system.
*/
@@ -393,41 +393,6 @@ class xlvask_usage_log extends xlvask_helper
return '';
}
/**
* Get the total price of the wash.
* This method calculates the total price of the wash by summing up the prices of all wash items.
* @return float The total price of the wash.
* @throws Exception If any of the wash items do not have a valid price.
*/
public function getTotalPrice(): float
{
// Calculate the total price of the wash by summing up the prices of all wash items
$totalPrice = 0.0;
foreach ( $this->WashItems as $item ) {
/** @var xlvask_wash_item $item */
if (isset($item->PriceIncVat) && is_numeric($item->PriceIncVat)) {
// The reason why we use the PriceIncVat is that it is the final price, and the price without VAT is not always available / correct.
$totalPrice += ((float)$item->PriceIncVat - (float)$item->Vat);
} else {
//print_r($item);
throw new Exception("Invalid price for wash item: " . json_encode($item));
}
}
return $totalPrice;
}
/**
* Check if the wash is completed.
* @note This method checks the FinishStatus property to determine if the wash is completed.
* * A wash is considered completed if the FinishStatus is set to 1.
* @return bool
*/
public function isCompleted(): bool
{
// Check if the wash is completed based on the FinishStatus
return $this->FinishStatus === 1; // Assuming 1 indicates a completed wash
}
/**
* Get the primary wash item from the usage log.
* This method returns the first wash item in the WashItems array as the primary item.
@@ -553,4 +518,90 @@ class xlvask_usage_log extends xlvask_helper
// If no order is found, return null
return null;
}
public function getTimestampStart(): string
{
// Return the start time as a timestamp
return date('Y-m-d H:i:s', strtotime($this->StartTime));
}
public function isEligibleForAutomaticContinuance(bool $allowPrepaid = false): bool
{
// Check if the wash is eligible for automatic continuance
// This can be based on various criteria, such as the finish status or other business rules
return
$this->isCompleted() && // Ensure the wash is completed
$this->hasBillableCustomer() && // Ensure the wash has a billable customer
(
$this->getTotalPrice() > 0 || $allowPrepaid
// Allow washes with a total price greater than 0 or allow prepaid washes if $allowPrepaid is true
) &&
(
!$this->isPrepaid() || $allowPrepaid
); // Allow prepaid washes if $allowPrepaid is true)
}
/**
* Check if the wash is completed.
* @note This method checks the FinishStatus property to determine if the wash is completed.
* * A wash is considered completed if the FinishStatus is set to 1.
* @return bool
*/
public function isCompleted(): bool
{
// Check if the wash is completed based on the FinishStatus
return $this->FinishStatus === 1; // Assuming 1 indicates a completed wash
}
public function hasBillableCustomer(): bool
{
// Check if the wash has a non-default customer with a valid external ID
return !$this->hasDefaultCustomer() && $this->hasExternalId();
}
public function hasDefaultCustomer(): bool
{
// Check if the customer is a default customer (e.g., "Unknown" or similar)
$default_customers = [
'CTW',
'Personalebiler Truckwash ', // The space at the end is intentional
'XL Gønge Transport ApS', // This is a test customer
];
return in_array($this->Customer, $default_customers, true);
}
public function hasExternalId(): bool
{
// Check if the wash has an external ID (e.g., CustomerId)
return !empty($this->CustomerId) && $this->CustomerId !== '0';
}
/**
* Get the total price of the wash.
* This method calculates the total price of the wash by summing up the prices of all wash items.
* @return float The total price of the wash.
* @throws Exception If any of the wash items do not have a valid price.
*/
public function getTotalPrice(): float
{
// Calculate the total price of the wash by summing up the prices of all wash items
$totalPrice = 0.0;
foreach ( $this->WashItems as $item ) {
/** @var xlvask_wash_item $item */
if (isset($item->PriceIncVat) && is_numeric($item->PriceIncVat)) {
// The reason why we use the PriceIncVat is that it is the final price, and the price without VAT is not always available / correct.
$totalPrice += ((float)$item->PriceIncVat - (float)$item->Vat);
} else {
//print_r($item);
throw new Exception("Invalid price for wash item: " . json_encode($item));
}
}
return $totalPrice;
}
public function isPrepaid(): bool
{
// Check if the wash is prepaid
return !empty($this->Prepaid) && $this->Prepaid === 1; // Assuming 1 indicates a prepaid wash
}
}
@@ -50,6 +50,11 @@ require_once WD . '/modules/xlvask/helpers/xlvask_parser_ikke_ht_dysebom_p_tag.p
require_once WD . '/modules/xlvask/helpers/xlvask_parser_ht_osc_sider.php';
require_once WD . '/modules/xlvask/helpers/xlvask_parser_kun_b_rster_ved_hytten.php';
require_once WD . '/modules/xlvask/helpers/xlvask_parser_h_nger.php';
require_once WD . '/modules/xlvask/helpers/xlvask_parser_ikke_ht_dysebom_mellom_bil_trailer.php';
require_once WD . '/modules/xlvask/helpers/xlvask_parser_ikke_b_rster_mellom_bil_og_trailer.php';
require_once WD . '/modules/xlvask/helpers/xlvask_parser_s_be_dysebom_tak.php';
require_once WD . '/modules/xlvask/helpers/xlvask_parser_ingen_b_rster_foran_no_brush_wash_front.php';
require_once WD . '/modules/xlvask/helpers/xlvask_parser_ht_dysebom.php';
use helpers\xlvask_cache;
use helpers\xlvask_create_customer;
+29 -8
View File
@@ -806,8 +806,12 @@ class orders_o extends db
(int)$xlvask_usage_log->getDepartment()->id,
$xlvask_usage_log->RegistrationNumber,
);
// Set the wash ID for the order
$this->wash_id->set($xlvask_usage_log->WashId);
// Set the lane used for the order (if applicable)
$this->lane->set($xlvask_usage_log->getLane());
// Set the timestamp for the order creation to the time the wash was performed
$this->created_at->set($xlvask_usage_log->getTimestampStart());
// Add the products to the order
$firstItemId = null;
/** @var xlvask_wash_item $washItem */
@@ -824,8 +828,8 @@ class orders_o extends db
'',
'', //$washItem->OriginalProductName,
2285,
(int)$washItem->getUnitPriceExVat(),
(int)$washItem->Count,
(int)((float)$washItem->getUnitPriceExVat() * (float)$washItem->Count),
(int)1,
$firstItemId === null ? null : $firstItemId, // Set the first item as the parent item (if applicable)
);
// Set the first item ID for the next item to link to (provided this is the first item)
@@ -836,10 +840,22 @@ class orders_o extends db
// Validate the order matches the desired total
$total = $this->getNetAmount();
if ($total !== $xlvask_usage_log->getTotalPrice()) {
echo "Order ID: " . $this->id . "\n";
echo "Customer: " . $user->customer_number->value() . "\n";
echo "Registration Number: " . $xlvask_usage_log->RegistrationNumber . "\n";
echo "Wash Items: \n";
foreach ( $xlvask_usage_log->WashItems as $item ) {
echo "- " . $item->getProduct($xlvask_usage_log)->name . " (Count: " . $item->Count . ", Price: " . $item->getUnitPriceExVat() . ")\n";
}
echo "Expected Total Price: " . $xlvask_usage_log->getTotalPrice() . "\n";
echo "Actual Total Price: $total\n";
echo "Order Items: \n";
foreach ( $this->getOrderItems($this->id) as $order_item ) {
echo "- " . $order_item['product']['name'] . " (Count: " . $order_item['quantity'] . ", Price: " . $order_item['product']['price'] . ")\n";
}
echo "Total: $total, Expected: " . $xlvask_usage_log->getTotalPrice() . "\n";
throw new Exception('The total amount of the order does not match the expected total. Expected: ' . $xlvask_usage_log->getTotalPrice() . ', Actual: ' . $total);
}
// Set the wash ID for the order
$this->wash_id->set($xlvask_usage_log->WashId);
// Save the order
$this->objectChanged();
// Return the order object
@@ -971,7 +987,7 @@ class orders_o extends db
// Prepare the SQL query to find orders with possible duplicates in the date range
$dateFrom = $db->escape_string($dateFrom);
$dateTo = $db->escape_string($dateTo);
$sql = "SELECT id, customer_id, reg_1, created_at FROM $this->table WHERE created_at BETWEEN '$dateFrom' AND '$dateTo' AND deleted_at IS NULL";
$sql = "SELECT id, customer_id, reg_1, reg_2, reg_3, created_at FROM $this->table WHERE created_at BETWEEN '$dateFrom' AND '$dateTo' AND deleted_at IS NULL";
$result = $db->query($sql);
if ($result->num_rows === 0) {
return []; // No orders found in the date range
@@ -981,30 +997,35 @@ class orders_o extends db
$tmp = [
'id' => (int)$row['id'],
'reg_1' => (string)$row['reg_1'],
'reg_2' => (string)$row['reg_2'] ?? '',
'reg_3' => (string)$row['reg_3'] ?? '',
'created_at' => (string)$row['created_at'],
];
// Add the order to the list
$orders[$tmp['reg_1']][] = [
'id' => $tmp['id'],
'reg_1' => $tmp['reg_1'],
'reg_2' => (string)$row['reg_2'] ?? '',
'reg_3' => (string)$row['reg_3'] ?? '',
'created_at' => $tmp['created_at'],
'object' => (new orders_o())->select((int)$tmp['id'])
];
}
// Filter out orders with more than one entry for the same registration number (in a 24 hour period)
// Filter out orders with more than one entry for the same registration numbers (in a 24 hour period)
$possibleDuplicates = [];
// Loop through the registration numbers
foreach ( $orders as $reg_1 => $orderList ) {
// If there are more than one order for the same registration number, add it to the possible duplicates
if (count($orderList) > 1) {
// Loop through the orders and check if they are within 24 hours of each other
$filteredOrders = [];
foreach ( $orderList as $order ) {
// Check if the order is within 24 hours of the first order
// Check if the order is within 24 hours of the previous order (if any)
if (empty($filteredOrders)) {
$filteredOrders[] = $order; // Add the first order
} else {
// Check if the order is within 24 hours of the first order
// Check if the order is within 24 hours of the previous order
$firstOrderTime = strtotime($filteredOrders[0]['created_at']);
$currentOrderTime = strtotime($order['created_at']);
if ($currentOrderTime - $firstOrderTime <= 86400) { // 86400 seconds = 24 hours
@@ -500,7 +500,7 @@ class InvoicingPeriodRoute
// Construct the transaction object from the order
return $transaction['object'];
}, $order),
true, // Requires action because there are possible duplicates
false, // Requires action because there are possible duplicates
$customer['id'] ?? null // Use the id from the customer object if available
);
}
@@ -34,6 +34,8 @@ class moduleXLVaskRoute
$params[$key] = $this->getParameter($key);
}
}
// Set the memory limit to 5120MB
ini_set('memory_limit', '5120M');
// Create the xlvask object
$xlvask = new xlvask();
$result = $xlvask->getUsageLog(...$params);
@@ -173,7 +175,11 @@ class moduleXLVaskRoute
$this->get('/modules/xlvask/tasks/sync-usage', function () {
global $response;
self::requirePermission('modules_xlvask_sync_usage');
//self::requirePermission('modules_xlvask_sync_usage');
// Remove the memory limit
// ini_set('memory_limit', '-1');
// Remove the execution time limit
// set_time_limit(300);
// Create the xlvask tasks object
$xlvask = new xlvask();
// Run the sync usage task
@@ -287,6 +287,8 @@ class vehiclesRoute
self::requireType($reg, self::type_string());
self::requireMinLength('reg', 2);
self::requireMaxLength('reg', 12);
// Strip the registration number of whitespace
$reg = preg_replace('/\s+/', '', $reg);
// Set the registration number
$vehicle->reg->set($reg);
}
+6 -1
View File
@@ -7,6 +7,9 @@ events {
}
http {
# Add rate limiting to prevent abuse
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
limit_req_status 429;
# Include additional configuration files
include /etc/nginx/mime.types;
default_type application/octet-stream;
@@ -71,7 +74,7 @@ http {
include fastcgi_params;
fastcgi_pass php:9000;
fastcgi_index index.php;
fastcgi_read_timeout 600;
fastcgi_read_timeout 60;
fastcgi_param SCRIPT_FILENAME index.php;
}
@@ -119,4 +122,6 @@ http {
# Additional server blocks can be added here
# Restrict access to the server, if the
}