Fix invoice period automatic flag cache misses

This commit is contained in:
Jeppe B
2026-06-01 23:25:54 +02:00
parent 7cb248a112
commit 0ae28af309
2 changed files with 42 additions and 22 deletions
@@ -525,16 +525,12 @@ class invoice_period_flag_service
try {
$flags = (new redis())->get_invoice_period_automatic_flags($dateFrom, $dateTo);
} catch (Throwable) {
return [];
$flags = null;
}
if (!is_array($flags)) {
// Cache miss — enqueue for warming on the next cron run
try {
(new redis())->enqueue_invoice_period_warming($dateFrom, $dateTo);
} catch (Throwable) {
}
return [];
$flags = $this->buildAutomaticFlagsForPeriod($dateFrom, $dateTo);
$this->cacheAutomaticFlagsForPeriod($dateFrom, $dateTo, $flags);
}
if ($onlyCustomerNumbers === null) {
@@ -548,18 +544,30 @@ class invoice_period_flag_service
}
public function warmAutomaticFlagsForPeriod(string $dateFrom, string $dateTo): void
{
$this->cacheAutomaticFlagsForPeriod(
$dateFrom,
$dateTo,
$this->buildAutomaticFlagsForPeriod($dateFrom, $dateTo)
);
}
private function buildAutomaticFlagsForPeriod(string $dateFrom, string $dateTo): array
{
$rows = $this->getPeriodOrderItemRows($dateFrom, $dateTo, null);
$attributes = $this->getCustomerAttributes(null);
$flags = array_merge(
return array_merge(
$this->detectCustomerRuleViolations($rows, $attributes),
$this->detectPriceMismatches($rows),
$this->detectAbnormalQuantities($rows, $dateFrom, $dateTo),
$this->detectVehicleTypeMismatches($rows, $dateFrom),
$this->detectMissingXlVaskLinks($dateFrom, $dateTo, null)
);
}
private function cacheAutomaticFlagsForPeriod(string $dateFrom, string $dateTo, array $flags): void
{
try {
(new redis())->cache_invoice_period_automatic_flags($dateFrom, $dateTo, $flags);
} catch (Throwable) {
@@ -606,11 +614,15 @@ class invoice_period_flag_service
try {
$rows = (new redis())->get_invoice_period_order_item_rows($dateFrom, $dateTo);
} catch (Throwable) {
return [];
$rows = null;
}
if (!is_array($rows)) {
return [];
$rows = $this->fetchOrderItemRowsFromDb($dateFrom, $dateTo);
try {
(new redis())->cache_invoice_period_order_item_rows($dateFrom, $dateTo, $rows);
} catch (Throwable) {
}
}
$this->seedOrderItemsPreviewCacheFromRows($rows);
@@ -1727,18 +1739,7 @@ class invoice_period_flag_service
if ($currentVehicleType === '' || $expectedVehicleType === '') {
return false;
}
if ($currentVehicleType === $expectedVehicleType) {
return true;
}
// Allow a match if one normalized name's tokens are a subset of the other.
// E.g. "Indvendig vask Kassevogn" → "kassevogn" is a subset of
// "Kassevogn/varevogn" → "kassevogn varevogn", meaning the same vehicle type.
$currentTokens = explode(' ', $currentVehicleType);
$expectedTokens = explode(' ', $expectedVehicleType);
if (count($currentTokens) <= count($expectedTokens)) {
return array_diff($currentTokens, $expectedTokens) === [];
}
return array_diff($expectedTokens, $currentTokens) === [];
return $currentVehicleType === $expectedVehicleType;
}
private function normalizePrimaryVehicleProductName(string $productName): string
@@ -628,6 +628,25 @@ it('does not report a price mismatch when a product-specific discount makes the
expect($flags)->toBe([]);
});
it('does not treat subset primary vehicle product names as equivalent', function (): void {
expect(invoice_period_flag_service_invoke('primaryVehicleProductsMatch', [5, 'Forvogn', 6, 'Forvogn med hænger']))
->toBeFalse()
->and(invoice_period_flag_service_invoke('primaryVehicleProductsMatch', [10, 'Indvendig vask Kassevogn', 11, 'Kassevogn']))
->toBeTrue();
});
it('rebuilds automatic invoice period data on cache misses instead of hiding warnings', function (): void {
$content = file_get_contents(app_path('classes/invoice_period_flag_service.php'));
expect($content)->not->toBeFalse();
$content = (string)$content;
expect($content)->toContain('$flags = $this->buildAutomaticFlagsForPeriod($dateFrom, $dateTo);');
expect($content)->toContain('$rows = $this->fetchOrderItemRowsFromDb($dateFrom, $dateTo);');
expect($content)->toContain('cache_invoice_period_order_item_rows($dateFrom, $dateTo, $rows)');
expect($content)->not->toContain('enqueue_invoice_period_warming($dateFrom, $dateTo)');
});
it('preloads and caches missing e-conomic discounts before price mismatch detection', function (): void {
$content = file_get_contents(app_path('classes/invoice_period_flag_service.php'));