Add caching methods for invoice period flags and cron jobs for warming caches
- Introduced methods for caching, retrieving, and clearing manual and automatic invoice period flags, as well as order item rows, using the Redis interface. - Implemented `warmManualFlagsCache` and `warmAutomaticFlagsForPeriod` methods in `invoice_period_flag_service` to enhance performance by loading flags and order items into cache. - Added new cron jobs `WarmInvoicePeriodManualFlagsCron` and `WarmInvoicePeriodAutomaticFlagsCron` to regularly update cached data for improved access speeds.
This commit is contained in:
@@ -25,6 +25,7 @@ class invoice_period_flag_service
|
||||
private array $economicCustomerDiscountCache = [];
|
||||
private array $userDisplayNameCache = [];
|
||||
private array $orderItemsPreviewCache = [];
|
||||
private ?array $manualFlagsInstanceCache = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
@@ -186,6 +187,7 @@ class invoice_period_flag_service
|
||||
*/
|
||||
public function applyFlagsToPeriodTypes(array $types, string $dateFrom, string $dateTo, ?array $onlyCustomerNumbers = null): array
|
||||
{
|
||||
global $response;
|
||||
$context = $this->buildPeriodContext($types, $dateFrom, $dateTo, $onlyCustomerNumbers);
|
||||
$manualFlags = $this->getManualFlagsForPeriod($context, $dateFrom, $dateTo, $onlyCustomerNumbers);
|
||||
$automaticFlags = $this->getAutomaticFlagsForPeriod($dateFrom, $dateTo, $onlyCustomerNumbers);
|
||||
@@ -317,6 +319,30 @@ class invoice_period_flag_service
|
||||
return $this->formatStoredFlag($row);
|
||||
}
|
||||
|
||||
public function warmManualFlagsCache(): void
|
||||
{
|
||||
global $db;
|
||||
|
||||
$result = $db->query(
|
||||
"SELECT * FROM invoice_period_flags
|
||||
WHERE source = '" . self::SOURCE_MANUAL . "'
|
||||
AND status = '" . self::STATUS_ACTIVE . "'
|
||||
ORDER BY created_at ASC, id ASC"
|
||||
);
|
||||
|
||||
$flags = [];
|
||||
if ($result) {
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$flags[] = $this->formatStoredFlag($row);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
(new redis())->cache_invoice_period_manual_flags($flags);
|
||||
} catch (Throwable) {
|
||||
}
|
||||
}
|
||||
|
||||
private function formatStoredFlag(array $row): array
|
||||
{
|
||||
$context = [];
|
||||
@@ -353,6 +379,23 @@ class invoice_period_flag_service
|
||||
];
|
||||
}
|
||||
|
||||
private function getCachedManualFlags(): array
|
||||
{
|
||||
try {
|
||||
$flags = (new redis())->get_invoice_period_manual_flags();
|
||||
} catch (Throwable) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!is_array($flags)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return array_values(array_filter($flags, static function ($flag): bool {
|
||||
return is_array($flag);
|
||||
}));
|
||||
}
|
||||
|
||||
private function buildPeriodContext(array $types, string $dateFrom, string $dateTo, ?array $onlyCustomerNumbers): array
|
||||
{
|
||||
$customerNumbers = [];
|
||||
@@ -398,16 +441,11 @@ class invoice_period_flag_service
|
||||
|
||||
private function getManualFlagsForPeriod(array $context, string $dateFrom, string $dateTo, ?array $onlyCustomerNumbers): array
|
||||
{
|
||||
global $db;
|
||||
|
||||
$result = $db->query(
|
||||
"SELECT * FROM invoice_period_flags
|
||||
WHERE source = '" . self::SOURCE_MANUAL . "'
|
||||
AND status = '" . self::STATUS_ACTIVE . "'
|
||||
ORDER BY created_at ASC, id ASC"
|
||||
);
|
||||
|
||||
if (!$result || $result->num_rows === 0) {
|
||||
if ($this->manualFlagsInstanceCache === null) {
|
||||
$this->manualFlagsInstanceCache = $this->getCachedManualFlags();
|
||||
}
|
||||
$cachedFlags = $this->manualFlagsInstanceCache;
|
||||
if (empty($cachedFlags)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -424,7 +462,7 @@ class invoice_period_flag_service
|
||||
}
|
||||
|
||||
$flags = [];
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
foreach ($cachedFlags as $row) {
|
||||
$targetType = (string)$row['target_type'];
|
||||
$targetId = (int)$row['target_id'];
|
||||
$customerNumber = null;
|
||||
@@ -464,7 +502,7 @@ class invoice_period_flag_service
|
||||
continue;
|
||||
}
|
||||
|
||||
$flag = $this->formatStoredFlag($row);
|
||||
$flag = $row;
|
||||
$flag['customer_number'] = $customerNumber;
|
||||
$flag['message'] = (string)$flag['reason'];
|
||||
$flags[] = $flag;
|
||||
@@ -475,16 +513,43 @@ class invoice_period_flag_service
|
||||
|
||||
private function getAutomaticFlagsForPeriod(string $dateFrom, string $dateTo, ?array $onlyCustomerNumbers): array
|
||||
{
|
||||
$rows = $this->getPeriodOrderItemRows($dateFrom, $dateTo, $onlyCustomerNumbers);
|
||||
$attributes = $this->getCustomerAttributes($onlyCustomerNumbers);
|
||||
try {
|
||||
$flags = (new redis())->get_invoice_period_automatic_flags($dateFrom, $dateTo);
|
||||
} catch (Throwable) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return array_merge(
|
||||
if (!is_array($flags)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if ($onlyCustomerNumbers === null) {
|
||||
return $flags;
|
||||
}
|
||||
|
||||
$allowed = array_fill_keys(array_map('intval', $onlyCustomerNumbers), true);
|
||||
return array_values(array_filter($flags, static function (array $flag) use ($allowed): bool {
|
||||
return isset($allowed[(int)($flag['customer_number'] ?? 0)]);
|
||||
}));
|
||||
}
|
||||
|
||||
public function warmAutomaticFlagsForPeriod(string $dateFrom, string $dateTo): void
|
||||
{
|
||||
$rows = $this->getPeriodOrderItemRows($dateFrom, $dateTo, null);
|
||||
$attributes = $this->getCustomerAttributes(null);
|
||||
|
||||
$flags = array_merge(
|
||||
$this->detectCustomerRuleViolations($rows, $attributes),
|
||||
$this->detectPriceMismatches($rows),
|
||||
$this->detectAbnormalQuantities($rows, $dateFrom, $dateTo),
|
||||
$this->detectVehicleTypeMismatches($rows, $dateFrom),
|
||||
$this->detectMissingXlVaskLinks($dateFrom, $dateTo, $onlyCustomerNumbers)
|
||||
$this->detectMissingXlVaskLinks($dateFrom, $dateTo, null)
|
||||
);
|
||||
|
||||
try {
|
||||
(new redis())->cache_invoice_period_automatic_flags($dateFrom, $dateTo, $flags);
|
||||
} catch (Throwable) {
|
||||
}
|
||||
}
|
||||
|
||||
private function filterSuppressedAutomaticFlags(array $flags): array
|
||||
@@ -523,12 +588,44 @@ class invoice_period_flag_service
|
||||
}
|
||||
|
||||
private function getPeriodOrderItemRows(string $dateFrom, string $dateTo, ?array $onlyCustomerNumbers): array
|
||||
{
|
||||
try {
|
||||
$rows = (new redis())->get_invoice_period_order_item_rows($dateFrom, $dateTo);
|
||||
} catch (Throwable) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!is_array($rows)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$this->seedOrderItemsPreviewCacheFromRows($rows);
|
||||
|
||||
if ($onlyCustomerNumbers === null) {
|
||||
return $rows;
|
||||
}
|
||||
|
||||
$allowed = array_fill_keys(array_map('intval', $onlyCustomerNumbers), true);
|
||||
return array_values(array_filter($rows, static function (array $row) use ($allowed): bool {
|
||||
return isset($allowed[(int)($row['customer_number'] ?? 0)]);
|
||||
}));
|
||||
}
|
||||
|
||||
public function warmOrderItemRowsForPeriod(string $dateFrom, string $dateTo): void
|
||||
{
|
||||
$rows = $this->fetchOrderItemRowsFromDb($dateFrom, $dateTo);
|
||||
try {
|
||||
(new redis())->cache_invoice_period_order_item_rows($dateFrom, $dateTo, $rows);
|
||||
} catch (Throwable) {
|
||||
}
|
||||
}
|
||||
|
||||
private function fetchOrderItemRowsFromDb(string $dateFrom, string $dateTo): array
|
||||
{
|
||||
global $db;
|
||||
|
||||
$customerFilter = $this->customerFilterSql('o.customer_id', $onlyCustomerNumbers);
|
||||
$dateFrom = $db->escape_string($dateFrom);
|
||||
$dateTo = $db->escape_string($dateTo);
|
||||
$escapedDateFrom = $db->escape_string($dateFrom);
|
||||
$escapedDateTo = $db->escape_string($dateTo);
|
||||
|
||||
$sql = "
|
||||
SELECT
|
||||
@@ -593,9 +690,8 @@ class invoice_period_flag_service
|
||||
) category_discount
|
||||
ON category_discount.customer_number = o.customer_id
|
||||
AND category_discount.product_or_category_id = p.category
|
||||
WHERE o.created_at BETWEEN '{$dateFrom}' AND '{$dateTo}'
|
||||
WHERE o.created_at BETWEEN '{$escapedDateFrom}' AND '{$escapedDateTo}'
|
||||
AND o.deleted_at IS NULL
|
||||
{$customerFilter}
|
||||
ORDER BY o.customer_id, o.id, oi.id";
|
||||
|
||||
$result = $db->query($sql);
|
||||
|
||||
@@ -364,6 +364,89 @@ class redis implements redis_i
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function cache_invoice_period_manual_flags(array $flags): self
|
||||
{
|
||||
$this->set_array('invoice_period_manual_flags', $flags);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function get_invoice_period_manual_flags(): array|null
|
||||
{
|
||||
return $this->get_array('invoice_period_manual_flags');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function clear_invoice_period_manual_flags(): self
|
||||
{
|
||||
$this->delete('invoice_period_manual_flags');
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function invoicePeriodCacheKey(string $prefix, string $dateFrom, string $dateTo): string
|
||||
{
|
||||
return $prefix . ':' . $dateFrom . ':' . $dateTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function cache_invoice_period_automatic_flags(string $dateFrom, string $dateTo, array $flags): self
|
||||
{
|
||||
$this->set_array($this->invoicePeriodCacheKey('invoice_period_automatic_flags', $dateFrom, $dateTo), $flags);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function get_invoice_period_automatic_flags(string $dateFrom, string $dateTo): array|null
|
||||
{
|
||||
return $this->get_array($this->invoicePeriodCacheKey('invoice_period_automatic_flags', $dateFrom, $dateTo));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function clear_invoice_period_automatic_flags(string $dateFrom, string $dateTo): self
|
||||
{
|
||||
$this->delete($this->invoicePeriodCacheKey('invoice_period_automatic_flags', $dateFrom, $dateTo));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function cache_invoice_period_order_item_rows(string $dateFrom, string $dateTo, array $rows): self
|
||||
{
|
||||
$this->set_array($this->invoicePeriodCacheKey('invoice_period_order_item_rows', $dateFrom, $dateTo), $rows);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function get_invoice_period_order_item_rows(string $dateFrom, string $dateTo): array|null
|
||||
{
|
||||
return $this->get_array($this->invoicePeriodCacheKey('invoice_period_order_item_rows', $dateFrom, $dateTo));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function clear_invoice_period_order_item_rows(string $dateFrom, string $dateTo): self
|
||||
{
|
||||
$this->delete($this->invoicePeriodCacheKey('invoice_period_order_item_rows', $dateFrom, $dateTo));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
use classes\backup_store;
|
||||
use classes\economic;
|
||||
use classes\economic_transfer_queue;
|
||||
use classes\invoice_period_flag_service;
|
||||
use classes\system_search_cache;
|
||||
use classes\system_search_document_index;
|
||||
use classes\system_search_economic_customer_index;
|
||||
@@ -135,8 +136,38 @@ $cron_tasks = [
|
||||
'next_run' => 0,
|
||||
'function' => 'PruneSystemSessionActivityCron',
|
||||
],
|
||||
'WarmInvoicePeriodManualFlagsCron' => [
|
||||
'interval' => 300, // 5 minutes
|
||||
'last_run' => 0,
|
||||
'next_run' => 0,
|
||||
'function' => 'WarmInvoicePeriodManualFlagsCron',
|
||||
],
|
||||
'WarmInvoicePeriodAutomaticFlagsCron' => [
|
||||
'interval' => 300, // 5 minutes
|
||||
'last_run' => 0,
|
||||
'next_run' => 0,
|
||||
'function' => 'WarmInvoicePeriodAutomaticFlagsCron',
|
||||
],
|
||||
];
|
||||
|
||||
function WarmInvoicePeriodManualFlagsCron(): void
|
||||
{
|
||||
(new invoice_period_flag_service())->warmManualFlagsCache();
|
||||
}
|
||||
|
||||
function WarmInvoicePeriodAutomaticFlagsCron(): void
|
||||
{
|
||||
$service = new invoice_period_flag_service();
|
||||
$now = new DateTime();
|
||||
$previousMonth = new DateTime('first day of previous month');
|
||||
foreach ([$now, $previousMonth] as $date) {
|
||||
$dateFrom = $date->format('Y-m-01');
|
||||
$dateTo = $date->format('Y-m-t');
|
||||
$service->warmOrderItemRowsForPeriod($dateFrom, $dateTo);
|
||||
$service->warmAutomaticFlagsForPeriod($dateFrom, $dateTo);
|
||||
}
|
||||
}
|
||||
|
||||
function checkUnfulfilledBookings(): void
|
||||
{
|
||||
// This is deactivated for now, as it is not wanted.
|
||||
|
||||
@@ -290,6 +290,75 @@ interface redis_i
|
||||
*/
|
||||
public function clear_auth_session(string $token): self;
|
||||
|
||||
/**
|
||||
* Cache invoice period manual flags payload
|
||||
* @param array $flags
|
||||
* @return self
|
||||
*/
|
||||
public function cache_invoice_period_manual_flags(array $flags): self;
|
||||
|
||||
/**
|
||||
* Get cached invoice period manual flags payload
|
||||
* @return array|null
|
||||
*/
|
||||
public function get_invoice_period_manual_flags(): array|null;
|
||||
|
||||
/**
|
||||
* Clear cached invoice period manual flags payload
|
||||
* @return self
|
||||
*/
|
||||
public function clear_invoice_period_manual_flags(): self;
|
||||
|
||||
/**
|
||||
* Cache invoice period automatic flags payload for a date range
|
||||
* @param string $dateFrom
|
||||
* @param string $dateTo
|
||||
* @param array $flags
|
||||
* @return self
|
||||
*/
|
||||
public function cache_invoice_period_automatic_flags(string $dateFrom, string $dateTo, array $flags): self;
|
||||
|
||||
/**
|
||||
* Get cached invoice period automatic flags payload for a date range
|
||||
* @param string $dateFrom
|
||||
* @param string $dateTo
|
||||
* @return array|null
|
||||
*/
|
||||
public function get_invoice_period_automatic_flags(string $dateFrom, string $dateTo): array|null;
|
||||
|
||||
/**
|
||||
* Clear cached invoice period automatic flags payload for a date range
|
||||
* @param string $dateFrom
|
||||
* @param string $dateTo
|
||||
* @return self
|
||||
*/
|
||||
public function clear_invoice_period_automatic_flags(string $dateFrom, string $dateTo): self;
|
||||
|
||||
/**
|
||||
* Cache invoice period order item rows for a date range
|
||||
* @param string $dateFrom
|
||||
* @param string $dateTo
|
||||
* @param array $rows
|
||||
* @return self
|
||||
*/
|
||||
public function cache_invoice_period_order_item_rows(string $dateFrom, string $dateTo, array $rows): self;
|
||||
|
||||
/**
|
||||
* Get cached invoice period order item rows for a date range
|
||||
* @param string $dateFrom
|
||||
* @param string $dateTo
|
||||
* @return array|null
|
||||
*/
|
||||
public function get_invoice_period_order_item_rows(string $dateFrom, string $dateTo): array|null;
|
||||
|
||||
/**
|
||||
* Clear cached invoice period order item rows for a date range
|
||||
* @param string $dateFrom
|
||||
* @param string $dateTo
|
||||
* @return self
|
||||
*/
|
||||
public function clear_invoice_period_order_item_rows(string $dateFrom, string $dateTo): self;
|
||||
|
||||
/**
|
||||
* Cache a permission evaluation
|
||||
* @param string $cache_key
|
||||
|
||||
Reference in New Issue
Block a user