Wire XL Vask usage-log sync, order linking, and order creation (#353)
Wires the three broken paths in the cron-driven XL Vask integration: - runSyncUsage() now calls the revision-aware importUsageLogsWithSummary() on xlvask_usage_logs_o (was a no-op stub; the upstream API was never queried for washes). - linkImportedUsageLogsToOrders() persists xlvask_potential_order_matches rows so the accept/compare/link/deny UI has data to render. - When automatic_order_creation_enabled is on and the wash qualifies, falls through to createOrderFromWash() → orders_o::addXLVaskOrder(). - Removes the obsolete TODO in RunXLVaskModuleCron.php. - Returns linked + orders_created alongside the existing counters so ops can observe the pipeline.
This commit is contained in:
@@ -19,7 +19,6 @@ $xlvask = new xlvask;
|
|||||||
try {
|
try {
|
||||||
if ($xlvask->config->enabled->isTrue() && $xlvask->config->synchronization_enabled->isTrue()) {
|
if ($xlvask->config->enabled->isTrue() && $xlvask->config->synchronization_enabled->isTrue()) {
|
||||||
$xlvask->getTasks()->runCronTasks();
|
$xlvask->getTasks()->runCronTasks();
|
||||||
// TODO: Add synchronization for usage logs and vehicles.
|
|
||||||
}
|
}
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
// This is automatically running, but an XL Vask module failure here
|
// This is automatically running, but an XL Vask module failure here
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use objects\plate_scanners_o;
|
|||||||
use objects\users_o;
|
use objects\users_o;
|
||||||
use objects\xlvask_customers_o;
|
use objects\xlvask_customers_o;
|
||||||
use objects\xlvask_potential_order_matches_o;
|
use objects\xlvask_potential_order_matches_o;
|
||||||
|
use objects\xlvask_usage_logs_o;
|
||||||
use objects\xlvask_vehicles_o;
|
use objects\xlvask_vehicles_o;
|
||||||
|
|
||||||
class xlvask_tasks
|
class xlvask_tasks
|
||||||
@@ -271,11 +272,127 @@ class xlvask_tasks
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Usage synchronization is intentionally disabled until the XL Vask integration is completed.
|
* Synchronize XL Vask usage logs.
|
||||||
|
*
|
||||||
|
* Pulls finished washes from XL Vask for the given window and persists them
|
||||||
|
* via the revision-aware {@see xlvask_usage_logs_o::importUsageLogsWithSummary()}.
|
||||||
|
* Potential order matches are also recorded so the linked-order UI has the
|
||||||
|
* data it needs to offer accept/deny actions.
|
||||||
|
*
|
||||||
|
* @param string|null $dateFrom Optional import start date or date-time modifier. Defaults to the last 7 days.
|
||||||
|
* @param string|null $dateTo Optional inclusive import end date.
|
||||||
|
* @return array{
|
||||||
|
* fetched:int,
|
||||||
|
* new:int,
|
||||||
|
* updated:int,
|
||||||
|
* unchanged:int,
|
||||||
|
* invalid:int,
|
||||||
|
* errors:array<int,array<string,string>>,
|
||||||
|
* linked:int,
|
||||||
|
* orders_created:int
|
||||||
|
* } Summary of the import run.
|
||||||
|
* @throws Exception If the XL Vask module is not enabled.
|
||||||
*/
|
*/
|
||||||
public function runSyncUsage(?string $dateFrom = null, ?string $dateTo = null): void
|
public function runSyncUsage(?string $dateFrom = null, ?string $dateTo = null): array
|
||||||
{
|
{
|
||||||
unset($dateFrom, $dateTo);
|
$xlvask = new \classes\xlvask();
|
||||||
|
$xlvask->requireModuleEnabled();
|
||||||
|
if (!$xlvask->config->synchronization_enabled->isTrue()) {
|
||||||
|
return [
|
||||||
|
'fetched' => 0, 'new' => 0, 'updated' => 0, 'unchanged' => 0,
|
||||||
|
'invalid' => 0, 'errors' => [], 'linked' => 0, 'orders_created' => 0,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$summary = (new xlvask_usage_logs_o())->importUsageLogsWithSummary($dateFrom, $dateTo);
|
||||||
|
$linkSummary = $this->linkImportedUsageLogsToOrders($dateFrom, $dateTo);
|
||||||
|
|
||||||
|
return [
|
||||||
|
...$summary,
|
||||||
|
'linked' => $linkSummary['linked'],
|
||||||
|
'orders_created' => $linkSummary['orders_created'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find imported XL Vask usage logs that look like they belong to an existing order
|
||||||
|
* (same registration, department, and a window around the wash time) and record
|
||||||
|
* them as potential order matches so they show up in the linking UI.
|
||||||
|
*
|
||||||
|
* Optionally creates the missing order when automatic order creation is enabled,
|
||||||
|
* the customer has an external ID, and the wash qualifies for automatic continuance.
|
||||||
|
*
|
||||||
|
* @return array{linked:int, orders_created:int}
|
||||||
|
*/
|
||||||
|
private function linkImportedUsageLogsToOrders(?string $dateFrom, ?string $dateTo): array
|
||||||
|
{
|
||||||
|
global $db;
|
||||||
|
$xlvask = new \classes\xlvask();
|
||||||
|
$orders_o = new orders_o();
|
||||||
|
$matches = new xlvask_potential_order_matches_o();
|
||||||
|
$linked = 0;
|
||||||
|
$ordersCreated = 0;
|
||||||
|
|
||||||
|
$dateFromSql = $dateFrom !== null && $dateFrom !== ''
|
||||||
|
? "'" . $db->escape_string(xlvask_usage_logs_o::formatImportDateFrom($dateFrom)) . "'"
|
||||||
|
: 'DATE_SUB(NOW(), INTERVAL 7 DAY)';
|
||||||
|
$dateToSql = $dateTo !== null && $dateTo !== ''
|
||||||
|
? "'" . $db->escape_string((string)$dateTo) . " 23:59:59'"
|
||||||
|
: 'NOW()';
|
||||||
|
|
||||||
|
$sql = "SELECT * FROM xlvask_usage_logs
|
||||||
|
WHERE StartTime >= {$dateFromSql}
|
||||||
|
AND StartTime <= {$dateToSql}
|
||||||
|
AND FinishStatus = 1
|
||||||
|
AND WashId IS NOT NULL AND TRIM(WashId) <> ''
|
||||||
|
ORDER BY id ASC";
|
||||||
|
$result = $db->query($sql);
|
||||||
|
if ($result === false || $result->num_rows === 0) {
|
||||||
|
return ['linked' => 0, 'orders_created' => 0];
|
||||||
|
}
|
||||||
|
$rows = $db->fetch_all($result);
|
||||||
|
|
||||||
|
$createEnabled = $xlvask->config->automatic_order_creation_enabled->isTrue();
|
||||||
|
|
||||||
|
foreach ($rows as $row) {
|
||||||
|
$log = (new $xlvask->helpers->xlvask_usage_log())->setProperties($row);
|
||||||
|
$washId = (string)$log->WashId;
|
||||||
|
if ($washId === '' || $log->hasDefaultCustomer() || !$log->hasExternalId()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($matches->doesWashPotentialOrderMatchExist($washId)) {
|
||||||
|
continue; // already linked or explicitly ignored
|
||||||
|
}
|
||||||
|
|
||||||
|
$existingOrder = $log->getPotentialOrder();
|
||||||
|
if ($existingOrder !== null && (int)$existingOrder->id > 0) {
|
||||||
|
$matches->add(
|
||||||
|
$washId,
|
||||||
|
(int)$existingOrder->id,
|
||||||
|
(string)$log->CustomerId,
|
||||||
|
(int)$log->CustomerId,
|
||||||
|
(int)$log->getDepartment()->id,
|
||||||
|
);
|
||||||
|
$linked++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No matching order — try to create one if automatic creation is on.
|
||||||
|
if (!$createEnabled || !$log->isEligibleForAutomaticContinuance(false)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$customer = $log->getCustomer();
|
||||||
|
$order = (new self())->createOrderFromWash($log, $customer);
|
||||||
|
if ($order !== null) {
|
||||||
|
$ordersCreated++;
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log('[xlvask-tasks] auto-create order failed for wash ' . $washId . ': ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ['linked' => $linked, 'orders_created' => $ordersCreated];
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function formatUsageLogs(array $getUsageLog): array
|
private static function formatUsageLogs(array $getUsageLog): array
|
||||||
|
|||||||
Reference in New Issue
Block a user