Add import tasks and new parsers to XL Vask module

- Introduced `runImportTasks` method for vehicle, user, and usage log imports.
- Added new product parsers: `ht_b_rstel_s`, `ht_turbo`, and `ikke_b_rster_p_kabinen`.
- Implemented simulation and duplicate detection for usage logs via order objects.
- Updated usage log handling to include default customer checks and user association.
- Enhanced request handling with fast-link functionality for usage orders.
This commit is contained in:
Jeppe Bundgaard
2025-07-21 10:32:56 +02:00
parent e057b225a6
commit af3b0666fb
15 changed files with 603 additions and 15 deletions
+137 -5
View File
@@ -493,11 +493,13 @@ class orders_o extends db
}
/**
* @param bool $cacheResult Whether to cache the result or not, this is used to prevent caching simulated orders
* @param bool $skipCache Whether to skip the cache or not, this is used to force a fresh result
* Convert the order object to an array
* @return array The order as an array
* @throws Exception
* Convert the order object to an array
*/
public function asArray(bool $skipCache = false): array
public function asArray(bool $skipCache = false, bool $cacheResult = true): array
{
self::requireSelected();
if (!$skipCache) {
@@ -520,7 +522,7 @@ class orders_o extends db
'completed_at' => $this->completed_at->value(),
'created_at' => $this->created_at->value(),
'deleted_at' => $this->deleted_at->value(),
'total_net_amount' => $this->getNetAmount(),
'total_net_amount' => $this->temporary_net_amount ?: $this->getNetAmount(),
'invoice_collection_id' => (int)$this->invoice_collection_id->value(),
'booking_id' => (int)$this->booking_id->value(),
'wash_id' => $this->wash_id->value(),
@@ -528,8 +530,10 @@ class orders_o extends db
'closed_at' => (int)$this->invoice_collection_id->value() ? (new collected_order_invoices_o())->select((int)$this->invoice_collection_id->value())->closed_at->value() : null,
];
// Cache the object
self::cache('asArray', $tmp, $this->id);
self::setCachedExpiration('asArray', self::$asArrayCacheExpiration, $this->id);
if ($cacheResult) {
self::cache('asArray', $tmp, $this->id);
self::setCachedExpiration('asArray', self::$asArrayCacheExpiration, $this->id);
}
return $tmp;
}
@@ -862,6 +866,51 @@ class orders_o extends db
return $this;
}
/**
* Generate a fake order from a usage log - Used to preview the order before it is created
* @param xlvask_usage_log $xlvask_usage_log The usage log to generate the order from
* @param bool $includeItems Whether to include the order items in the simulated order, together with the total net amount
* @returns array['order' => array, 'order_items' => array]
* @throws Exception
*/
public function simulateOrderFromXLVask(xlvask_usage_log $xlvask_usage_log, bool $includeItems = true): array
{
$this->id = self::generateFakeId(); // Set a negative ID to indicate this is a simulated order
$this->getObjectProperties();
$this->customer_id->set(($xlvask_usage_log->hasBillableCustomer() ? (int)$xlvask_usage_log->CustomerId : 12345679)); // Set the customer ID from the usage log, or 0 if not billable
$this->cashier_id->set(2285); // Set the cashier ID to a default value for simulation
$this->reference->set('Simulated Order from XL Vask');
$this->notes->set('This is a simulated order generated from an XL Vask usage log');
$this->department_id->set($xlvask_usage_log->getDepartment()->id); // Set a default department ID for simulation
$this->reg_1->set((string)$xlvask_usage_log->RegistrationNumber); // Set the registration number from the usage log
$this->reg_2->set('');
$this->reg_3->set('');
$this->completed_at->set(null); // Set completed_at to null for simulation
$this->created_at->set($xlvask_usage_log->getTimestampStart()); // Set the created_at to the start time of the usage log
$this->deleted_at->set(null); // Set deleted_at to null for simulation
$this->invoice_collection_id->set(null); // Set invoice_collection_id to null for simulation
$this->booking_id->set(null); // Set booking_id to null for simulation
$this->wash_id->set($xlvask_usage_log->WashId); // Set the wash ID from the usage log
$this->lane->set($xlvask_usage_log->getLane()); // Set lane to null for simulation
if ($includeItems) {
// If we are including items, simulate the order items from the usage log
$order_items = $this->simulateOrderItemsFromXLVask($xlvask_usage_log);
// Save the total net amount for the simulated order (this is the sum of all item prices)
$this->setTemporaryNetAmount(
array_sum(array_map(function ($item) {
return (int)$item['price'] * (int)$item['quantity'];
}, $order_items))
);
} else {
$order_items = []; // No items included in the simulated order
$this->setTemporaryNetAmount(0); // Set the temporary net amount to 0
}
return [
'order' => $this->asArray(true, false), // Return the simulated order as an array
'order_items' => $order_items, // Return the simulated order items
];
}
/**
* Get a list of customers who have placed orders within a specific date range
* @param string $dateFrom (E.g. "2023-01-01 00:00:00")
@@ -1048,4 +1097,87 @@ class orders_o extends db
// Set a temporary net amount for the order
$this->temporary_net_amount = $amount;
}
/**
* @param xlvask_usage_log $xlvask_usage_log
* @return array
* @throws Exception
*/
public function simulateOrderItemsFromXLVask(xlvask_usage_log $xlvask_usage_log): array
{
// Add the products to the simulated order
$firstItemId = null; // Initialize the first item ID to null
$current_item_id = null;
$order_items = []; // Initialize the order items array
/** @var xlvask_wash_item $washItem */
foreach ( $xlvask_usage_log->WashItems as $washItem ) {
// Check if the item should be included in the order
// Check if the product is with id 64 (irrelevant product, a bi product of the wash)
if ($washItem->getProduct($xlvask_usage_log)->id === 64) {
continue; // Skip items that should not be included in the order
}
if (!$washItem->shouldIncludeInOrder() || $washItem->getProduct($xlvask_usage_log)->id === 64) {
continue; // Skip items that should not be included in the order
}
$order_item = new order_items_o();
$order_item->id = self::generateFakeId(); // Set a negative ID to indicate this is a simulated order item
// If the id is positive, forcefully quit
if ($order_item->id > 0) {
throw new Exception('The order item ID must be negative for simulation');
}
$order_item->getObjectProperties();
$order_item->order_id->set($this->id); // Set the order ID to the simulated order ID
$order_item->product_id->set($washItem->getProduct($xlvask_usage_log)->id); // Set the product ID from the wash item
$order_item->reference->set('');
$order_item->notes->set(null); // Set notes for the simulated order item
$order_item->price->set((int)$washItem->getUnitPriceExVat() * (int)$washItem->Count); // Set the price based on the wash item
$order_item->quantity->set((int)$washItem->Count); // Set the quantity based on the wash item
$order_item->related_item_id->set($firstItemId === null ? null : $firstItemId); // Set the related item ID to the first item ID (if applicable)
$order_item->include_in_invoice->set(true); // Set include_in_invoice to true for the simulated order item
$order_item->cashier_id->set($this->cashier_id->value()); // Set the cashier ID to the simulated order's cashier ID
// Set the first item ID for the next item to link to (provided this is the first item)
if ($firstItemId === null) {
$firstItemId = $order_item->id; // Set the first item ID to the current item ID
}
$order_items[] = $order_item->getItemAsArray(); // Add the simulated order item to the order items array
// clear up memory
unset($order_item);
}
return $order_items;
}
public function getOrderPotentialDuplicatesIfFound(string $reg_1, string $reg_2, string $reg_3, int $department_id, string $created_at): array
{
global /** @var db $db */
$db;
// Validate the registration numbers
$reg_1 = $db->escape_string($reg_1);
$reg_2 = $db->escape_string($reg_2);
$reg_3 = $db->escape_string($reg_3);
// Strip any whitespace from the registration numbers
$reg_1 = trim($reg_1);
$reg_2 = trim($reg_2);
$reg_3 = trim($reg_3);
// Created at must be between:
$created_at_from = date('Y-m-d H:i:s', strtotime($created_at . ' - 24 hours'));
$created_at_to = date('Y-m-d H:i:s', strtotime($created_at . ' + 24 hours'));
// Validate the department ID
if ($department_id <= 0) {
throw new Exception('Invalid department ID provided');
}
// Select the unique order ids that match the registration numbers and department ID within the 24 hour range
$sql = "SELECT id FROM $this->table WHERE (reg_1 = '$reg_1' AND reg_2 = '$reg_2' AND reg_3 = '$reg_3') AND department_id = $department_id AND created_at BETWEEN '$created_at_from' AND '$created_at_to' AND deleted_at IS NULL";
// Execute the query
$result = $db->query($sql);
if ($result->num_rows === 0) {
return []; // No potential duplicates found
}
// Fetch all potential duplicates
$result = $db->fetch_all($result);
return array_map(function ($row) {
$order = new orders_o();
$order->select((int)$row['id']);
return [...$order->asArray(), 'order_items' => $order->getOrderItems($order->id)]; // Include order items in the result
}, $result); // Return the potential duplicates as an array of order arrays
}
}