Fix XLVask usage import dates
Fix XLVask usage-log import metadata and period-scoped Selvvask automation.
This commit is contained in:
@@ -1246,19 +1246,20 @@ class xlvask_automation_service
|
||||
{
|
||||
global $db;
|
||||
(new xlvask_usage_logs_o())->structure();
|
||||
$startTimeExpression = "STR_TO_DATE(REPLACE(SUBSTRING(StartTime, 1, 19), 'T', ' '), '%Y-%m-%d %H:%i:%s')";
|
||||
$where = [
|
||||
'FinishStatus = 1',
|
||||
'(ignored_at IS NULL OR ignored_at = "")',
|
||||
];
|
||||
|
||||
if ($dateFrom !== null && strtotime($dateFrom) !== false) {
|
||||
$where[] = "StartTime >= '" . $db->escape_string(date('Y-m-d 00:00:00', strtotime($dateFrom))) . "'";
|
||||
$where[] = "{$startTimeExpression} >= '" . $db->escape_string(date('Y-m-d 00:00:00', strtotime($dateFrom))) . "'";
|
||||
} else {
|
||||
$where[] = "StartTime >= '" . $db->escape_string(date('Y-m-d H:i:s', strtotime('-7 days'))) . "'";
|
||||
$where[] = "{$startTimeExpression} >= '" . $db->escape_string(date('Y-m-d H:i:s', strtotime('-7 days'))) . "'";
|
||||
}
|
||||
|
||||
if ($dateTo !== null && strtotime($dateTo) !== false) {
|
||||
$where[] = "StartTime <= '" . $db->escape_string(date('Y-m-d 23:59:59', strtotime($dateTo))) . "'";
|
||||
$where[] = "{$startTimeExpression} <= '" . $db->escape_string(date('Y-m-d 23:59:59', strtotime($dateTo))) . "'";
|
||||
}
|
||||
|
||||
$limit = max(1, min(500, $limit));
|
||||
|
||||
@@ -379,6 +379,10 @@ class xlvask_usage_log extends xlvask_helper
|
||||
|
||||
private function unsetNullifiableProperties(): void
|
||||
{
|
||||
$nullable_review_metadata = [
|
||||
'ignored_at',
|
||||
'ignored_reason',
|
||||
];
|
||||
// Unset properties that are null or empty strings
|
||||
$properties = [
|
||||
'WashId', 'CustomerId', 'Customer', 'VatNumber', 'Location',
|
||||
@@ -391,7 +395,10 @@ class xlvask_usage_log extends xlvask_helper
|
||||
if ($this->isEmptyOrDefault($this->{$property})) {
|
||||
$tmp_value = $this->{$property};
|
||||
if ($tmp_value === $this->default_string || $tmp_value === $this->default_string_nullable) {
|
||||
$this->{$property} = ''; // Set to null if it matches the default string
|
||||
$this->{$property} = (
|
||||
$tmp_value === $this->default_string_nullable
|
||||
&& in_array($property, $nullable_review_metadata, true)
|
||||
) ? null : '';
|
||||
} elseif ($tmp_value === $this->default_int || $tmp_value === $this->default_int_nullable) {
|
||||
if ($tmp_value === $this->default_int_nullable) {
|
||||
$this->{$property} = null; // Set to null if it matches the default int nullable
|
||||
|
||||
@@ -82,7 +82,7 @@ class xlvask_usage_logs_o extends db
|
||||
$this->CustomerGuid = new object_property($this->table, $this->id, 'CustomerGuid', 'string', false);
|
||||
$this->VehicleId = new object_property($this->table, $this->id, 'VehicleId', 'string', false);
|
||||
$this->WashItems = new object_property($this->table, $this->id, 'WashItems', 'string', false);
|
||||
$this->ignored_at = new object_property($this->table, $this->id, 'ignored_at', 'string', false);
|
||||
$this->ignored_at = new object_property($this->table, $this->id, 'ignored_at', 'datetime', false);
|
||||
$this->ignored_by = new object_property($this->table, $this->id, 'ignored_by', 'int', false);
|
||||
$this->ignored_reason = new object_property($this->table, $this->id, 'ignored_reason', 'string', false);
|
||||
}
|
||||
@@ -195,18 +195,20 @@ class xlvask_usage_logs_o extends db
|
||||
|
||||
/**
|
||||
* Import the usage logs from XL Vask
|
||||
* @param string $dateTimeModifier A date time modifier to use for the import, defaults to '-7 days'
|
||||
* @param string|null $dateFrom Optional import start date or date-time modifier. Defaults to '-7 days'.
|
||||
* @param string|null $dateTo Optional inclusive import end date.
|
||||
* @throws Exception If the objects were not successfully added.
|
||||
* @returns void
|
||||
*/
|
||||
public function importUsageLogs(string $dateTimeModifier = '-7 days'): void
|
||||
public function importUsageLogs(?string $dateFrom = null, ?string $dateTo = null): void
|
||||
{
|
||||
if (!empty($this->id)) {
|
||||
throw new Exception('To prevent issues, having a selected object is not allowed.');
|
||||
}
|
||||
$usage_logs = $this->getUsageLogsFromXLVask(
|
||||
date('Y-m-d\TH:i:s.000', strtotime($dateTimeModifier)) // Example: '2025-05-01T00:00:00.000'
|
||||
self::formatImportDateFrom($dateFrom) // Example: '2025-05-01T00:00:00.000'
|
||||
);
|
||||
$usage_logs = self::filterUsageLogsUntil($usage_logs, $dateTo);
|
||||
/** @var string[] $known_usage_logIds The XL Vask usage logIds currently known */
|
||||
$known_usage_logIds = array_map(function ($log) {
|
||||
return $log['WashId'];
|
||||
@@ -236,6 +238,46 @@ class xlvask_usage_logs_o extends db
|
||||
unset($new_usage_logs);
|
||||
}
|
||||
|
||||
private static function formatImportDateFrom(?string $dateFrom): string
|
||||
{
|
||||
$dateFrom = trim((string)($dateFrom ?? ''));
|
||||
$timestamp = strtotime($dateFrom === '' ? '-7 days' : $dateFrom);
|
||||
|
||||
if ($timestamp === false) {
|
||||
throw new Exception('Invalid XL Vask usage import dateFrom');
|
||||
}
|
||||
|
||||
return date('Y-m-d\TH:i:s.000', $timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param xlvask_usage_log[] $usageLogs
|
||||
* @return xlvask_usage_log[]
|
||||
* @throws Exception
|
||||
*/
|
||||
private static function filterUsageLogsUntil(array $usageLogs, ?string $dateTo): array
|
||||
{
|
||||
$dateTo = trim((string)($dateTo ?? ''));
|
||||
if ($dateTo === '') {
|
||||
return $usageLogs;
|
||||
}
|
||||
|
||||
$dateToTimestamp = strtotime($dateTo);
|
||||
if ($dateToTimestamp === false) {
|
||||
throw new Exception('Invalid XL Vask usage import dateTo');
|
||||
}
|
||||
|
||||
$inclusiveEndTimestamp = strtotime(date('Y-m-d 23:59:59', $dateToTimestamp));
|
||||
if ($inclusiveEndTimestamp === false) {
|
||||
throw new Exception('Invalid XL Vask usage import dateTo');
|
||||
}
|
||||
|
||||
return array_values(array_filter($usageLogs, function (xlvask_usage_log $log) use ($inclusiveEndTimestamp) {
|
||||
$startTimestamp = strtotime((string)$log->StartTime);
|
||||
return $startTimestamp !== false && $startTimestamp <= $inclusiveEndTimestamp;
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* This function retrieves the usage logs from XL Vask
|
||||
* @param string $fromDate The date from which to retrieve the usage logs, in ISO 8601 format (e.g., '2025-05-01T00:00:00.000')
|
||||
|
||||
@@ -255,11 +255,13 @@ class moduleXLVaskRoute
|
||||
$this->get('/modules/xlvask/tasks/import-usage', function () {
|
||||
global $response;
|
||||
self::requirePermission('modules_xlvask_import_usage');
|
||||
$dateFrom = $this->isParametersSet(['dateFrom']) ? trim((string)$this->getParameter('dateFrom')) : null;
|
||||
$dateTo = $this->isParametersSet(['dateTo']) ? trim((string)$this->getParameter('dateTo')) : null;
|
||||
// Create the xlvask_usage_logs_o object
|
||||
$xlvask_usage_logs_o = new \objects\xlvask_usage_logs_o();
|
||||
// Import usage logs
|
||||
$xlvask_usage_logs_o->importUsageLogs();
|
||||
(new xlvask_automation_service())->runPending(null, null, [], 100, null);
|
||||
$xlvask_usage_logs_o->importUsageLogs($dateFrom, $dateTo);
|
||||
(new xlvask_automation_service())->runPending($dateFrom, $dateTo, [], 100, null);
|
||||
// Response
|
||||
$response->success(
|
||||
'Usage logs imported',
|
||||
|
||||
@@ -3,6 +3,20 @@
|
||||
use helpers\xlvask_usage_log;
|
||||
use objects\xlvask_usage_logs_o;
|
||||
|
||||
it('serializes empty ignore metadata as SQL null values for new usage logs', function (): void {
|
||||
$log = new xlvask_usage_log();
|
||||
$data = $log->toArray();
|
||||
|
||||
expect($data)
|
||||
->toHaveKey('ignored_at')
|
||||
->toHaveKey('ignored_by')
|
||||
->toHaveKey('ignored_reason')
|
||||
->and($data['ignored_at'])->toBeNull()
|
||||
->and($data['ignored_by'])->toBeNull()
|
||||
->and($data['ignored_reason'])->toBeNull()
|
||||
->and($data['Updated'])->toBe('');
|
||||
});
|
||||
|
||||
it('accepts persisted ignore metadata from xlvask usage log rows', function (): void {
|
||||
$log = new xlvask_usage_log();
|
||||
|
||||
@@ -57,3 +71,21 @@ it('calculates XL Vask amount summaries without hydrating order item previews',
|
||||
'primary_product_name' => 'Stor bil',
|
||||
]);
|
||||
});
|
||||
|
||||
it('formats date-only XL Vask usage import start dates for the upstream API', function (): void {
|
||||
$method = new ReflectionMethod(xlvask_usage_logs_o::class, 'formatImportDateFrom');
|
||||
|
||||
expect($method->invoke(null, '2026-03-01'))->toBe('2026-03-01T00:00:00.000');
|
||||
});
|
||||
|
||||
it('filters fetched XL Vask usage logs inclusively to the requested import end date', function (): void {
|
||||
$keep = new xlvask_usage_log(['StartTime' => '2026-03-31T23:59:59.000']);
|
||||
$drop = new xlvask_usage_log(['StartTime' => '2026-04-01T00:00:00.000']);
|
||||
$method = new ReflectionMethod(xlvask_usage_logs_o::class, 'filterUsageLogsUntil');
|
||||
|
||||
$result = $method->invoke(null, [$keep, $drop], '2026-03-31');
|
||||
|
||||
expect($result)
|
||||
->toHaveCount(1)
|
||||
->and($result[0])->toBe($keep);
|
||||
});
|
||||
|
||||
@@ -43,3 +43,22 @@ it('returns cached amount summaries on XL Vask usage order rows without widening
|
||||
->and($route)->toContain("\$tmp_res['order']['xlvask_primary_product_name'] = \$amount_summary['primary_product_name']")
|
||||
->and($route)->toContain("\$tmp_res['order']['xlvask_amount_cached'] = \$amount_summary['cached']");
|
||||
});
|
||||
|
||||
it('scopes manual XL Vask usage import and automation to optional period dates', function (): void {
|
||||
$route = file_get_contents(WD . '/routes/moduleXLVaskRoute.php');
|
||||
$automation = file_get_contents(WD . '/classes/xlvask_automation_service.php');
|
||||
|
||||
expect($route)
|
||||
->not->toBeFalse()
|
||||
->and($automation)->not->toBeFalse();
|
||||
|
||||
$route = (string)$route;
|
||||
$automation = (string)$automation;
|
||||
|
||||
expect($route)
|
||||
->toContain("getParameter('dateFrom')")
|
||||
->toContain("getParameter('dateTo')")
|
||||
->toContain('$xlvask_usage_logs_o->importUsageLogs($dateFrom, $dateTo)')
|
||||
->toContain('runPending($dateFrom, $dateTo, [], 100, null)')
|
||||
->and($automation)->toContain("STR_TO_DATE(REPLACE(SUBSTRING(StartTime, 1, 19), 'T', ' '), '%Y-%m-%d %H:%i:%s')");
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user