Seal live dashboard event gaps
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/../db_helpers.php';
|
||||
require_once __DIR__ . '/../notify_node.php';
|
||||
|
||||
/**
|
||||
* StockManager
|
||||
*
|
||||
@@ -856,6 +859,11 @@ class StockManager {
|
||||
(int)$inbound_row['id'], $inbound_row['source'] ?? '', (int)($inbound_row['source_id'] ?? 0), $inbound_row['date'] ?? '');
|
||||
}
|
||||
}
|
||||
|
||||
$notify_company_id = $this->company_id;
|
||||
db_after_commit(function() use ($warehouse_id, $type, $notify_company_id) {
|
||||
notify_node("stock_updated", ["warehouse_id" => $warehouse_id, "type" => $type], $notify_company_id);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -69,17 +69,43 @@ function db_check($sth, &$answer, $options = []) {
|
||||
|
||||
|
||||
|
||||
// Run a callback after the surrounding dbTransaction() commits. If no managed
|
||||
// transaction is active, run immediately. Used for non-authoritative side effects
|
||||
// such as live dashboard notifications.
|
||||
function db_after_commit(callable $callback): void {
|
||||
if (!isset($GLOBALS['_db_after_commit_stack']) || empty($GLOBALS['_db_after_commit_stack'])) {
|
||||
$callback();
|
||||
return;
|
||||
}
|
||||
|
||||
$idx = count($GLOBALS['_db_after_commit_stack']) - 1;
|
||||
$GLOBALS['_db_after_commit_stack'][$idx][] = $callback;
|
||||
}
|
||||
|
||||
// transaction wrapper with retry logic for deadlocks
|
||||
function dbTransaction($pdo, $callback, $maxRetries = 3) {
|
||||
for ($attempt = 0; $attempt < $maxRetries; $attempt++) {
|
||||
$GLOBALS['_db_after_commit_stack'][] = [];
|
||||
|
||||
try {
|
||||
$pdo->beginTransaction();
|
||||
$result = $callback($pdo);
|
||||
$pdo->commit();
|
||||
|
||||
$callbacks = array_pop($GLOBALS['_db_after_commit_stack']);
|
||||
foreach ($callbacks as $after_commit) {
|
||||
try {
|
||||
$after_commit();
|
||||
} catch (Throwable $e) {
|
||||
error_log("[AFTER COMMIT ERROR] " . $e->getMessage() . " | " . $e->getFile() . ":" . $e->getLine());
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
||||
} catch (PDOException $e) {
|
||||
$pdo->rollBack();
|
||||
if ($pdo->inTransaction()) $pdo->rollBack();
|
||||
array_pop($GLOBALS['_db_after_commit_stack']);
|
||||
|
||||
if ($e->getCode() == '40001' && $attempt < $maxRetries - 1) {
|
||||
usleep(600000 * ($attempt + 1));
|
||||
@@ -90,7 +116,8 @@ function dbTransaction($pdo, $callback, $maxRetries = 3) {
|
||||
throw $e;
|
||||
|
||||
} catch (Exception $e) {
|
||||
$pdo->rollBack();
|
||||
if ($pdo->inTransaction()) $pdo->rollBack();
|
||||
array_pop($GLOBALS['_db_after_commit_stack']);
|
||||
error_log("[ERROR] " . $e->getMessage() . " | " . $e->getFile() . ":" . $e->getLine());
|
||||
throw $e;
|
||||
}
|
||||
|
||||
@@ -34,3 +34,23 @@ function notify_node(string $event, array $data, int $company_id): void
|
||||
curl_exec($ch);
|
||||
curl_close($ch);
|
||||
}
|
||||
|
||||
function gl_posted_payload(string $doc_type, int $id, string $action, array $lines): array
|
||||
{
|
||||
$has_revenue = false;
|
||||
$has_expense = false;
|
||||
|
||||
foreach ($lines as $line) {
|
||||
$code = (int)($line['account_code'] ?? 0);
|
||||
if ($code >= 4000 && $code < 5000) $has_revenue = true;
|
||||
if ($code >= 5000) $has_expense = true;
|
||||
}
|
||||
|
||||
return [
|
||||
'doc_type' => $doc_type,
|
||||
'id' => $id,
|
||||
'action' => $action,
|
||||
'has_revenue' => $has_revenue,
|
||||
'has_expense' => $has_expense,
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user