Merge pull request #74 from copenhagentruckwash/xl-vask-module
Xl vask module
This commit is contained in:
@@ -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'],
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
+26
@@ -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
|
||||
}
|
||||
}
|
||||
+26
@@ -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
|
||||
}
|
||||
}
|
||||
+26
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user