fix login and configurations
This commit is contained in:
@@ -22,6 +22,33 @@ if(true){
|
|||||||
$time_zone = "Asia/Bangkok";
|
$time_zone = "Asia/Bangkok";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Real-time Node.js server ─────────────────────────────────────────────────
|
||||||
|
// Base URL the browser uses to reach nodejs/server.js (Socket.IO). Must match
|
||||||
|
// PORT in nodejs/.env.
|
||||||
|
if (!defined('NODE_PUBLIC_URL')) {
|
||||||
|
define('NODE_PUBLIC_URL', 'http://localhost:3000');
|
||||||
|
}
|
||||||
|
// Server-to-server calls (PHP → Node /emit, and Node scheduler → PHP cron
|
||||||
|
// endpoints) authenticate with this shared secret — must match EMIT_SECRET
|
||||||
|
// in nodejs/.env exactly.
|
||||||
|
if (!defined('NODE_EMIT_URL')) {
|
||||||
|
define('NODE_EMIT_URL', 'http://127.0.0.1:3000/emit');
|
||||||
|
}
|
||||||
|
if (!defined('NODE_EMIT_SECRET')) {
|
||||||
|
define('NODE_EMIT_SECRET', 'YOUR_NODE_EMIT_SECRET'); // must match nodejs/.env EMIT_SECRET
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Usage packages ───────────────────────────────────────────────────────────
|
||||||
|
// Keyed by company_list.package (defaults to 'starter'). Read by UsageGuard to
|
||||||
|
// enforce daily/weekly action limits and which features lock once exceeded.
|
||||||
|
$packages = [
|
||||||
|
'starter' => [
|
||||||
|
'daily_limit' => 30,
|
||||||
|
'weekly_limit' => 100,
|
||||||
|
'lock_on_limit' => ['dashboard'],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// unique key — used for SMTP password encryption, keep consistent across deploys
|
// unique key — used for SMTP password encryption, keep consistent across deploys
|
||||||
|
|||||||
@@ -24,9 +24,10 @@
|
|||||||
* Fail either → return "Wrong OTP! Please try again."
|
* Fail either → return "Wrong OTP! Please try again."
|
||||||
* 5. On success:
|
* 5. On success:
|
||||||
* a. Concurrent-session check — if the account already has a session_token
|
* a. Concurrent-session check — if the account already has a session_token
|
||||||
* set and session_last_seen is within the last hour, the login is blocked
|
* set and session_last_seen is within SESSION_ACTIVE_GRACE_SECONDS
|
||||||
* with "already signed in on another device." A stale or NULL token allows
|
* (see below), the login is blocked with "already signed in on another
|
||||||
* the login (user closed browser without logging out, or used back.php).
|
* device." A stale or NULL token allows the login (previous session
|
||||||
|
* expired naturally, or the user used back.php to log out explicitly).
|
||||||
* b. session_regenerate_id(true) — prevents session fixation attack by
|
* b. session_regenerate_id(true) — prevents session fixation attack by
|
||||||
* issuing a new session ID and deleting the old one.
|
* issuing a new session ID and deleting the old one.
|
||||||
* c. Generate a fresh CSRF token and store in session.
|
* c. Generate a fresh CSRF token and store in session.
|
||||||
@@ -109,22 +110,46 @@ if (empty($_SESSION['skip_otp'])) {
|
|||||||
|
|
||||||
// ── Step 4b: Concurrent session check ────────────────────────────────────────
|
// ── Step 4b: Concurrent session check ────────────────────────────────────────
|
||||||
// Block the login if this account already has an active session.
|
// Block the login if this account already has an active session.
|
||||||
// "Active" = session_token is set AND session_last_seen is within the last hour.
|
// "Active" = session_token is set AND session_last_seen is within the last
|
||||||
// A stale last_seen (user closed browser without logging out) expires after 1 h,
|
// SESSION_ACTIVE_GRACE_SECONDS. db_auth.php refreshes session_last_seen on every
|
||||||
// matching the PHP session GC maxlifetime configured in session.php.
|
// authenticated request (throttled to once per 60s), so a session that is truly
|
||||||
|
// still in use on another device keeps re-touching this timestamp well within
|
||||||
|
// the grace window below. A session that has actually ended — browser/tab closed,
|
||||||
|
// cookie lost, PHP session GC'd — stops refreshing it and goes stale quickly.
|
||||||
|
//
|
||||||
|
// This window must stay well above the 60s throttle in db_auth.php (otherwise a
|
||||||
|
// live second session could go stale between its own refreshes and let a login
|
||||||
|
// through) but short enough that a real re-login isn't blocked for long after the
|
||||||
|
// previous session actually ended. It intentionally does NOT match PHP's
|
||||||
|
// session.gc_maxlifetime (3600s) — that timeout is about when PHP reclaims the
|
||||||
|
// session file on disk, not about how quickly this check should stop treating a
|
||||||
|
// dead session as "still active".
|
||||||
// An explicit logout clears session_token to NULL, so back.php bypasses this.
|
// An explicit logout clears session_token to NULL, so back.php bypasses this.
|
||||||
|
//
|
||||||
|
// The staleness comparison is done entirely in SQL (session_last_seen vs MySQL's
|
||||||
|
// own NOW()), not in PHP. session_last_seen is written with MySQL's NOW(), and
|
||||||
|
// the MySQL server here runs on Asia/Bangkok time while PHP's default timezone is
|
||||||
|
// UTC (config.php's $time_zone is never applied via date_default_timezone_set()).
|
||||||
|
// Pulling the timestamp into PHP and comparing with strtotime()/time() silently
|
||||||
|
// misreads that Bangkok wall-clock string as UTC — 7 hours in the future — which
|
||||||
|
// made idle_seconds permanently negative and this check block every login,
|
||||||
|
// regardless of window size. Comparing inside MySQL sidesteps the mismatch
|
||||||
|
// without touching PHP's global timezone (which would ripple into every other
|
||||||
|
// date()/time() call in the app).
|
||||||
|
define('SESSION_ACTIVE_GRACE_SECONDS', 120);
|
||||||
|
|
||||||
$sth_active = $pdo1->prepare(
|
$sth_active = $pdo1->prepare(
|
||||||
"SELECT session_token, session_last_seen FROM user WHERE user_id = :uid LIMIT 1"
|
"SELECT session_token,
|
||||||
|
(session_last_seen IS NOT NULL
|
||||||
|
AND session_last_seen > (NOW() - INTERVAL " . SESSION_ACTIVE_GRACE_SECONDS . " SECOND)) AS is_active
|
||||||
|
FROM user WHERE user_id = :uid LIMIT 1"
|
||||||
);
|
);
|
||||||
$sth_active->execute([':uid' => $user_id]);
|
$sth_active->execute([':uid' => $user_id]);
|
||||||
$active_row = $sth_active->fetch(PDO::FETCH_ASSOC);
|
$active_row = $sth_active->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
if (!empty($active_row['session_token']) && !empty($active_row['session_last_seen'])) {
|
if (!empty($active_row['session_token']) && !empty($active_row['is_active'])) {
|
||||||
$idle_seconds = time() - strtotime($active_row['session_last_seen']);
|
|
||||||
if ($idle_seconds < 3600) {
|
|
||||||
$answer['message'] = 'This account is currently signed in on another device. Please sign out from that session first.';
|
$answer['message'] = 'This account is currently signed in on another device. Please sign out from that session first.';
|
||||||
exit(json_encode($answer));
|
exit(json_encode($answer));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Step 4c: Claim session ────────────────────────────────────────────────────
|
// ── Step 4c: Claim session ────────────────────────────────────────────────────
|
||||||
|
|||||||
@@ -342,7 +342,20 @@ if (password_verify(trim($data["password"]), $temp["password"])) {
|
|||||||
"company_id" => $default_company,
|
"company_id" => $default_company,
|
||||||
"smtp" => $smtp_config,
|
"smtp" => $smtp_config,
|
||||||
"subject" => "One Time Password (OTP) For reference number " . $reference_number,
|
"subject" => "One Time Password (OTP) For reference number " . $reference_number,
|
||||||
"message" => "Your OTP is " . $otp . " for reference number " . $reference_number,
|
"message" => implode("\n", [
|
||||||
|
"Dear WMS user,",
|
||||||
|
"",
|
||||||
|
"You requested a One-Time Password (OTP) to log in to WMS.",
|
||||||
|
"",
|
||||||
|
"Please use the OTP below to complete your request:",
|
||||||
|
"• OTP code: " . $otp,
|
||||||
|
"• Reference number: " . $reference_number,
|
||||||
|
"",
|
||||||
|
"Please note:",
|
||||||
|
"• This code will expire in 3 minutes. Please complete your action promptly.",
|
||||||
|
"• Do not share this code with anyone to keep your account secure.",
|
||||||
|
"• If you did not request this code, please ignore this email.",
|
||||||
|
]),
|
||||||
"channel_name" => "WMS LOGIN OTP",
|
"channel_name" => "WMS LOGIN OTP",
|
||||||
"to" => $user_email,
|
"to" => $user_email,
|
||||||
"key" => $pinkey,
|
"key" => $pinkey,
|
||||||
|
|||||||
@@ -115,7 +115,20 @@ if (password_verify(trim($data["password"]), $temp["password"])) {
|
|||||||
"company_id" => 0,
|
"company_id" => 0,
|
||||||
"smtp" => $SMTP,
|
"smtp" => $SMTP,
|
||||||
"subject" => "One Time Password (OTP) For reference number " . $reference_number,
|
"subject" => "One Time Password (OTP) For reference number " . $reference_number,
|
||||||
"message" => "Your OTP is " . $otp . " for reference number " . $reference_number,
|
"message" => implode("\n", [
|
||||||
|
"Dear WMS user,",
|
||||||
|
"",
|
||||||
|
"You requested a One-Time Password (OTP) to log in to WMS.",
|
||||||
|
"",
|
||||||
|
"Please use the OTP below to complete your request:",
|
||||||
|
"• OTP code: " . $otp,
|
||||||
|
"• Reference number: " . $reference_number,
|
||||||
|
"",
|
||||||
|
"Please note:",
|
||||||
|
"• This code will expire in 3 minutes. Please complete your action promptly.",
|
||||||
|
"• Do not share this code with anyone to keep your account secure.",
|
||||||
|
"• If you did not request this code, please ignore this email.",
|
||||||
|
]),
|
||||||
"channel_name" => "WMS LOGIN OTP ",
|
"channel_name" => "WMS LOGIN OTP ",
|
||||||
"to" => $user_email,
|
"to" => $user_email,
|
||||||
"key" => $pinkey,
|
"key" => $pinkey,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
require __DIR__ . '/app/config.php';
|
require __DIR__ . '/app/config.php';
|
||||||
header('Location: ' . $base_url . 'landing/');
|
header('Location: ' . $base_url . 'app/');
|
||||||
exit;
|
exit;
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
2026-07-22T14:37:48: [2026-07-22T07:37:48.626Z] [PID: 505] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Wed Jul 22 2026 14:30:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-07-23T15:14:43: [2026-07-23T08:14:43.767Z] [PID: 451] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Thu Jul 23 2026 15:00:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-07-23T20:39:04: [2026-07-23T13:39:04.943Z] [PID: 451] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Thu Jul 23 2026 17:00:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-07-23T20:39:04: [2026-07-23T13:39:04.953Z] [PID: 451] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Thu Jul 23 2026 18:00:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-07-23T20:39:04: [2026-07-23T13:39:04.959Z] [PID: 451] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Thu Jul 23 2026 19:00:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-07-23T20:39:04: [2026-07-23T13:39:04.965Z] [PID: 451] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Thu Jul 23 2026 20:00:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-07-23T21:02:17: [2026-07-23T14:02:17.033Z] [PID: 451] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Thu Jul 23 2026 21:00:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-07-23T21:11:21: [2026-07-23T14:11:21.977Z] [PID: 451] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Thu Jul 23 2026 17:30:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-07-23T21:11:21: [2026-07-23T14:11:21.982Z] [PID: 451] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Thu Jul 23 2026 18:30:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-07-23T21:11:21: [2026-07-23T14:11:21.985Z] [PID: 451] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Thu Jul 23 2026 19:30:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-07-23T21:11:21: [2026-07-23T14:11:21.987Z] [PID: 451] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Thu Jul 23 2026 20:30:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-07-25T14:44:32: [2026-07-25T07:44:32.121Z] [PID: 476] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Sat Jul 25 2026 13:30:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-07-25T14:44:32: [2026-07-25T07:44:32.127Z] [PID: 476] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Sat Jul 25 2026 14:30:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-07-25T15:24:00: [2026-07-25T08:24:00.029Z] [PID: 476] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Sat Jul 25 2026 14:00:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-07-25T15:24:00: [2026-07-25T08:24:00.032Z] [PID: 476] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Sat Jul 25 2026 15:00:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-08-03T10:11:12: [2026-08-03T03:11:12.241Z] [PID: 477] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Mon Aug 03 2026 10:00:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-08-03T10:31:46: [2026-08-03T03:31:46.573Z] [PID: 477] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Mon Aug 03 2026 10:30:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-08-03T11:08:26: [2026-08-03T04:08:26.686Z] [PID: 477] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Mon Aug 03 2026 11:00:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
2026-07-20T17:35:51: [scheduler] running — etl_gl + etl_stock (hourly) | low_stock + overdue_invoices alerts (daily)
|
||||||
|
2026-07-20T21:00:00: [scheduler] etl_gl slot=21
|
||||||
|
2026-07-20T21:00:00: [scheduler] etl_gl slot=21 — no companies
|
||||||
|
2026-07-21T16:06:58: [scheduler] running — etl_gl + etl_stock (hourly) | low_stock + overdue_invoices alerts (daily)
|
||||||
|
2026-07-22T13:08:58: [scheduler] running — etl_gl + etl_stock (hourly) | low_stock + overdue_invoices alerts (daily)
|
||||||
|
2026-07-22T14:37:48: [2026-07-22T07:37:48.626Z] [PID: 505] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Wed Jul 22 2026 14:30:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-07-22T15:00:00: [scheduler] etl_gl slot=15
|
||||||
|
2026-07-22T15:00:00: [scheduler] etl_gl slot=15 — no companies
|
||||||
|
2026-07-22T15:30:00: [scheduler] etl_stock slot=15
|
||||||
|
2026-07-22T15:30:00: [scheduler] etl_stock slot=15 — no companies
|
||||||
|
2026-07-22T16:00:00: [scheduler] etl_gl slot=16
|
||||||
|
2026-07-22T16:00:00: [scheduler] etl_gl slot=16 — no companies
|
||||||
|
2026-07-23T12:11:51: [scheduler] running — etl_gl + etl_stock (hourly) | low_stock + overdue_invoices alerts (daily)
|
||||||
|
2026-07-23T12:30:00: [scheduler] etl_stock slot=12
|
||||||
|
2026-07-23T12:30:00: [scheduler] etl_stock slot=12 — no companies
|
||||||
|
2026-07-23T13:36:04: [scheduler] running — etl_gl + etl_stock (hourly) | low_stock + overdue_invoices alerts (daily)
|
||||||
|
2026-07-23T15:14:43: [2026-07-23T08:14:43.767Z] [PID: 451] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Thu Jul 23 2026 15:00:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-07-23T15:30:00: [scheduler] etl_stock slot=15
|
||||||
|
2026-07-23T15:30:00: [scheduler] etl_stock slot=15 — no companies
|
||||||
|
2026-07-23T16:00:00: [scheduler] etl_gl slot=16
|
||||||
|
2026-07-23T16:00:00: [scheduler] etl_gl slot=16 — no companies
|
||||||
|
2026-07-23T16:30:00: [scheduler] etl_stock slot=16
|
||||||
|
2026-07-23T16:30:00: [scheduler] etl_stock slot=16 — no companies
|
||||||
|
2026-07-23T20:39:04: [2026-07-23T13:39:04.943Z] [PID: 451] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Thu Jul 23 2026 17:00:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-07-23T20:39:04: [2026-07-23T13:39:04.953Z] [PID: 451] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Thu Jul 23 2026 18:00:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-07-23T20:39:04: [2026-07-23T13:39:04.959Z] [PID: 451] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Thu Jul 23 2026 19:00:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-07-23T20:39:04: [2026-07-23T13:39:04.965Z] [PID: 451] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Thu Jul 23 2026 20:00:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-07-23T21:02:17: [2026-07-23T14:02:17.033Z] [PID: 451] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Thu Jul 23 2026 21:00:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-07-23T21:11:21: [2026-07-23T14:11:21.977Z] [PID: 451] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Thu Jul 23 2026 17:30:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-07-23T21:11:21: [2026-07-23T14:11:21.982Z] [PID: 451] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Thu Jul 23 2026 18:30:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-07-23T21:11:21: [2026-07-23T14:11:21.985Z] [PID: 451] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Thu Jul 23 2026 19:30:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-07-23T21:11:21: [2026-07-23T14:11:21.987Z] [PID: 451] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Thu Jul 23 2026 20:30:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-07-23T21:30:00: [scheduler] etl_stock slot=21
|
||||||
|
2026-07-23T21:30:00: [scheduler] etl_stock slot=21 — no companies
|
||||||
|
2026-07-25T12:19:55: [scheduler] running — etl_gl + etl_stock (hourly) | low_stock + overdue_invoices alerts (daily)
|
||||||
|
2026-07-25T12:30:00: [scheduler] etl_stock slot=12
|
||||||
|
2026-07-25T12:30:00: [scheduler] etl_stock slot=12 — no companies
|
||||||
|
2026-07-25T13:00:00: [scheduler] etl_gl slot=13
|
||||||
|
2026-07-25T13:00:00: [scheduler] etl_gl slot=13 — no companies
|
||||||
|
2026-07-25T14:44:32: [2026-07-25T07:44:32.121Z] [PID: 476] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Sat Jul 25 2026 13:30:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-07-25T14:44:32: [2026-07-25T07:44:32.127Z] [PID: 476] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Sat Jul 25 2026 14:30:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-07-25T15:24:00: [2026-07-25T08:24:00.029Z] [PID: 476] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Sat Jul 25 2026 14:00:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-07-25T15:24:00: [2026-07-25T08:24:00.032Z] [PID: 476] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Sat Jul 25 2026 15:00:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-08-03T08:52:15: [scheduler] running — etl_gl + etl_stock (hourly) | low_stock + overdue_invoices alerts (daily)
|
||||||
|
2026-08-03T09:00:00: [scheduler] etl_gl slot=9
|
||||||
|
2026-08-03T09:00:00: [scheduler] alert_overdue_invoices running
|
||||||
|
2026-08-03T09:00:00: [scheduler] etl_gl slot=9 — no companies
|
||||||
|
2026-08-03T10:11:12: [2026-08-03T03:11:12.241Z] [PID: 477] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Mon Aug 03 2026 10:00:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-08-03T10:31:46: [2026-08-03T03:31:46.573Z] [PID: 477] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Mon Aug 03 2026 10:30:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
|
2026-08-03T11:08:26: [2026-08-03T04:08:26.686Z] [PID: 477] [32m[NODE-CRON][32m [33m[WARN][0m missed execution at Mon Aug 03 2026 11:00:00 GMT+0700 (Indochina Time)! Possible blocking IO or high CPU user at the same process used by node-cron.
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
2026-07-20T17:35:51: Node.js real-time server running on port 3000
|
||||||
|
2026-07-21T16:06:58: Node.js real-time server running on port 3000
|
||||||
|
2026-07-22T13:08:58: Node.js real-time server running on port 3000
|
||||||
|
2026-07-22T13:10:29: [connect] socket=0-LquhazY9eKKN7LAAAB company=1 user=1 role=owner
|
||||||
|
2026-07-22T13:15:09: [disconnect] socket=0-LquhazY9eKKN7LAAAB
|
||||||
|
2026-07-22T13:15:12: [connect] socket=P4rxlPGuHWMqT35XAAAD company=1 user=1 role=owner
|
||||||
|
2026-07-22T13:26:21: [disconnect] socket=P4rxlPGuHWMqT35XAAAD
|
||||||
|
2026-07-22T13:26:23: [connect] socket=EBxi3tj8fNMUmyoyAAAF company=1 user=1 role=owner
|
||||||
|
2026-07-22T13:30:24: [disconnect] socket=EBxi3tj8fNMUmyoyAAAF
|
||||||
|
2026-07-22T13:30:25: [connect] socket=SJtRh1L6usnHrWebAAAH company=1 user=1 role=owner
|
||||||
|
2026-07-22T13:31:59: [disconnect] socket=SJtRh1L6usnHrWebAAAH
|
||||||
|
2026-07-22T13:31:59: [connect] socket=xvRdZhqqg-soDWr7AAAJ company=1 user=1 role=owner
|
||||||
|
2026-07-22T13:41:17: [disconnect] socket=xvRdZhqqg-soDWr7AAAJ
|
||||||
|
2026-07-22T13:41:17: [connect] socket=QZkAkh2pHOGltp-0AAAL company=1 user=1 role=owner
|
||||||
|
2026-07-22T13:42:28: [disconnect] socket=QZkAkh2pHOGltp-0AAAL
|
||||||
|
2026-07-22T13:42:28: [connect] socket=0Vb5YTMHDs1gOC47AAAN company=1 user=1 role=owner
|
||||||
|
2026-07-22T13:42:36: [disconnect] socket=0Vb5YTMHDs1gOC47AAAN
|
||||||
|
2026-07-22T13:42:36: [connect] socket=idQO9l1OGLiXPyEoAAAP company=1 user=1 role=owner
|
||||||
|
2026-07-22T13:42:43: [disconnect] socket=idQO9l1OGLiXPyEoAAAP
|
||||||
|
2026-07-22T13:42:43: [connect] socket=nvfS_4EF_3kF5PGsAAAR company=1 user=1 role=owner
|
||||||
|
2026-07-22T13:47:25: [disconnect] socket=nvfS_4EF_3kF5PGsAAAR
|
||||||
|
2026-07-22T13:47:27: [connect] socket=yytX3fzh594f9phBAAAT company=1 user=1 role=owner
|
||||||
|
2026-07-22T13:50:19: [emit] company=1 event=stock_updated { warehouse_id: 1, type: 'in' }
|
||||||
|
2026-07-22T13:50:19: [emit] company=1 event=stock_updated { warehouse_id: 1, type: 'in' }
|
||||||
|
2026-07-22T13:50:19: [emit] company=1 event=stock_updated { warehouse_id: 1, type: 'in' }
|
||||||
|
2026-07-22T13:50:19: [emit] company=1 event=stock_updated { warehouse_id: 1, type: 'in' }
|
||||||
|
2026-07-22T13:50:19: [emit] company=1 event=stock_updated { warehouse_id: 1, type: 'in' }
|
||||||
|
2026-07-22T13:59:42: [emit] company=1 event=stock_updated { warehouse_id: 2, type: 'in' }
|
||||||
|
2026-07-22T13:59:42: [emit] company=1 event=stock_updated { warehouse_id: 2, type: 'in' }
|
||||||
|
2026-07-22T13:59:43: [emit] company=1 event=stock_updated { warehouse_id: 2, type: 'in' }
|
||||||
|
2026-07-22T13:59:43: [emit] company=1 event=stock_updated { warehouse_id: 2, type: 'in' }
|
||||||
|
2026-07-22T13:59:43: [emit] company=1 event=stock_updated { warehouse_id: 2, type: 'in' }
|
||||||
|
2026-07-22T13:59:43: [emit] company=1 event=stock_updated { warehouse_id: 2, type: 'in' }
|
||||||
|
2026-07-22T13:59:43: [emit] company=1 event=stock_updated { warehouse_id: 2, type: 'in' }
|
||||||
|
2026-07-22T13:59:43: [emit] company=1 event=stock_updated { warehouse_id: 2, type: 'in' }
|
||||||
|
2026-07-22T13:59:43: [emit] company=1 event=stock_updated { warehouse_id: 2, type: 'in' }
|
||||||
|
2026-07-22T13:59:43: [emit] company=1 event=stock_updated { warehouse_id: 2, type: 'in' }
|
||||||
|
2026-07-22T14:03:26: [disconnect] socket=yytX3fzh594f9phBAAAT
|
||||||
|
2026-07-22T14:03:28: [connect] socket=waEM4mo4V099RHhAAAAV company=1 user=1 role=owner
|
||||||
|
2026-07-22T14:03:30: [emit] company=1 event=stock_updated { warehouse_id: 3, type: 'in' }
|
||||||
|
2026-07-22T14:03:30: [emit] company=1 event=stock_updated { warehouse_id: 3, type: 'in' }
|
||||||
|
2026-07-22T14:03:30: [emit] company=1 event=stock_updated { warehouse_id: 3, type: 'in' }
|
||||||
|
2026-07-22T14:03:30: [emit] company=1 event=stock_updated { warehouse_id: 3, type: 'in' }
|
||||||
|
2026-07-22T14:03:30: [emit] company=1 event=stock_updated { warehouse_id: 3, type: 'in' }
|
||||||
|
2026-07-22T14:03:30: [emit] company=1 event=stock_updated { warehouse_id: 3, type: 'in' }
|
||||||
|
2026-07-22T14:03:30: [emit] company=1 event=stock_updated { warehouse_id: 3, type: 'in' }
|
||||||
|
2026-07-22T14:03:30: [emit] company=1 event=stock_updated { warehouse_id: 3, type: 'in' }
|
||||||
|
2026-07-22T14:03:30: [emit] company=1 event=stock_updated { warehouse_id: 3, type: 'in' }
|
||||||
|
2026-07-22T14:03:30: [emit] company=1 event=stock_updated { warehouse_id: 3, type: 'in' }
|
||||||
|
2026-07-22T14:03:30: [emit] company=1 event=stock_updated { warehouse_id: 3, type: 'out' }
|
||||||
|
2026-07-22T14:03:30: [emit] company=1 event=stock_updated { warehouse_id: 3, type: 'out' }
|
||||||
|
2026-07-22T14:03:30: [emit] company=1 event=stock_updated { warehouse_id: 3, type: 'out' }
|
||||||
|
2026-07-22T14:03:30: [emit] company=1 event=stock_updated { warehouse_id: 3, type: 'out' }
|
||||||
|
2026-07-22T14:03:30: [emit] company=1 event=stock_updated { warehouse_id: 3, type: 'out' }
|
||||||
|
2026-07-22T14:11:10: [disconnect] socket=waEM4mo4V099RHhAAAAV
|
||||||
|
2026-07-22T14:35:14: [connect] socket=ZSmIs38dJh1u4If4AAAX company=1 user=1 role=owner
|
||||||
|
2026-07-22T14:35:49: [disconnect] socket=ZSmIs38dJh1u4If4AAAX
|
||||||
|
2026-07-22T14:35:49: [connect] socket=1bcHdQOC7cBTftxyAAAZ company=1 user=1 role=owner
|
||||||
|
2026-07-22T14:36:37: [disconnect] socket=1bcHdQOC7cBTftxyAAAZ
|
||||||
|
2026-07-22T14:36:38: [connect] socket=fMazKVGWKhaTm7OUAAAb company=1 user=1 role=owner
|
||||||
|
2026-07-22T14:36:46: [disconnect] socket=fMazKVGWKhaTm7OUAAAb
|
||||||
|
2026-07-22T14:36:46: [connect] socket=VfqVaEiOI3NTCA7fAAAd company=1 user=1 role=owner
|
||||||
|
2026-07-22T14:36:48: [disconnect] socket=VfqVaEiOI3NTCA7fAAAd
|
||||||
|
2026-07-22T14:36:48: [connect] socket=DAww8irzEgS7j7JLAAAf company=1 user=1 role=owner
|
||||||
|
2026-07-22T14:36:49: [disconnect] socket=DAww8irzEgS7j7JLAAAf
|
||||||
|
2026-07-22T14:36:49: [connect] socket=WgF3HArg1rthWkktAAAh company=1 user=1 role=owner
|
||||||
|
2026-07-22T14:37:05: [disconnect] socket=WgF3HArg1rthWkktAAAh
|
||||||
|
2026-07-22T14:37:05: [connect] socket=pfMLLNR0x-qoq485AAAj company=1 user=1 role=owner
|
||||||
|
2026-07-22T14:37:08: [disconnect] socket=pfMLLNR0x-qoq485AAAj
|
||||||
|
2026-07-22T14:37:09: [connect] socket=7ZtkCaJZqcYXBSZWAAAl company=1 user=1 role=owner
|
||||||
|
2026-07-22T14:37:14: [disconnect] socket=7ZtkCaJZqcYXBSZWAAAl
|
||||||
|
2026-07-22T14:37:14: [connect] socket=F6_OvPrmc-vv_KoqAAAn company=1 user=1 role=owner
|
||||||
|
2026-07-22T14:37:18: [disconnect] socket=F6_OvPrmc-vv_KoqAAAn
|
||||||
|
2026-07-22T14:37:18: [connect] socket=gdlZxPbkkcdkdE2AAAAp company=1 user=1 role=owner
|
||||||
|
2026-07-22T14:40:08: [disconnect] socket=gdlZxPbkkcdkdE2AAAAp
|
||||||
|
2026-07-22T14:40:09: [connect] socket=c8j8ybp-e7MPpa6cAAAr company=1 user=1 role=owner
|
||||||
|
2026-07-22T14:40:13: [disconnect] socket=c8j8ybp-e7MPpa6cAAAr
|
||||||
|
2026-07-22T14:40:13: [connect] socket=D36DmJgraENmU5xsAAAt company=1 user=1 role=owner
|
||||||
|
2026-07-22T14:40:20: [disconnect] socket=D36DmJgraENmU5xsAAAt
|
||||||
|
2026-07-22T14:40:21: [connect] socket=saY0q6gBioHWgq7RAAAv company=1 user=1 role=owner
|
||||||
|
2026-07-22T14:40:25: [disconnect] socket=saY0q6gBioHWgq7RAAAv
|
||||||
|
2026-07-22T14:40:25: [connect] socket=o9h4_9i-KOjDfVmrAAAx company=1 user=1 role=owner
|
||||||
|
2026-07-22T14:40:27: [disconnect] socket=o9h4_9i-KOjDfVmrAAAx
|
||||||
|
2026-07-22T14:40:27: [connect] socket=aIM89idl78lyhTbNAAAz company=1 user=1 role=owner
|
||||||
|
2026-07-22T14:56:05: [emit] company=1 event=stock_updated { warehouse_id: 3, type: 'in' }
|
||||||
|
2026-07-22T14:56:05: [emit] company=1 event=stock_updated { warehouse_id: 3, type: 'in' }
|
||||||
|
2026-07-22T14:56:06: [emit] company=1 event=stock_updated { warehouse_id: 3, type: 'out' }
|
||||||
|
2026-07-22T14:56:06: [emit] company=1 event=stock_updated { warehouse_id: 3, type: 'out' }
|
||||||
|
2026-07-22T15:21:05: [emit] company=1 event=stock_updated { warehouse_id: 3, type: 'transfer' }
|
||||||
|
2026-07-22T15:28:23: [disconnect] socket=aIM89idl78lyhTbNAAAz
|
||||||
|
2026-07-22T15:43:35: [connect] socket=q1N4BECKfiomOEfyAAA1 company=1 user=1 role=owner
|
||||||
|
2026-07-22T15:43:38: [disconnect] socket=q1N4BECKfiomOEfyAAA1
|
||||||
|
2026-07-22T15:43:38: [connect] socket=yM_0j72uX0V2b-GuAAA3 company=1 user=1 role=owner
|
||||||
|
2026-07-22T15:43:43: [disconnect] socket=yM_0j72uX0V2b-GuAAA3
|
||||||
|
2026-07-22T15:43:43: [connect] socket=dvzUKq0p7lXQMuSLAAA5 company=1 user=1 role=owner
|
||||||
|
2026-07-22T15:43:45: [disconnect] socket=dvzUKq0p7lXQMuSLAAA5
|
||||||
|
2026-07-22T15:43:45: [connect] socket=TYvNpQgcOHR5-V1RAAA7 company=1 user=1 role=owner
|
||||||
|
2026-07-22T15:43:46: [disconnect] socket=TYvNpQgcOHR5-V1RAAA7
|
||||||
|
2026-07-22T15:43:46: [connect] socket=waNTeqU5sAu8W2jqAAA9 company=1 user=1 role=owner
|
||||||
|
2026-07-22T16:05:01: [disconnect] socket=waNTeqU5sAu8W2jqAAA9
|
||||||
|
2026-07-23T12:11:51: Node.js real-time server running on port 3000
|
||||||
|
2026-07-23T12:13:27: [connect] socket=NYO9Tg4V6Cqp3e4cAAAB company=1 user=1 role=owner
|
||||||
|
2026-07-23T12:33:05: [disconnect] socket=NYO9Tg4V6Cqp3e4cAAAB
|
||||||
|
2026-07-23T12:33:06: [connect] socket=pEDe8Dms2dU7gdhCAAAD company=1 user=1 role=owner
|
||||||
|
2026-07-23T12:34:13: [disconnect] socket=pEDe8Dms2dU7gdhCAAAD
|
||||||
|
2026-07-23T12:34:17: [connect] socket=vaGUT12vPXkqH_7kAAAF company=1 user=1 role=owner
|
||||||
|
2026-07-23T12:55:49: [disconnect] socket=vaGUT12vPXkqH_7kAAAF
|
||||||
|
2026-07-23T13:36:04: Node.js real-time server running on port 3000
|
||||||
|
2026-07-23T13:36:55: [connect] socket=nVGY71aXPas0zYS_AAAB company=1 user=1 role=owner
|
||||||
|
2026-07-23T13:51:36: [disconnect] socket=nVGY71aXPas0zYS_AAAB
|
||||||
|
2026-07-23T13:51:36: [connect] socket=5peGIWbSaRCxnlYBAAAD company=1 user=1 role=owner
|
||||||
|
2026-07-23T13:51:38: [disconnect] socket=5peGIWbSaRCxnlYBAAAD
|
||||||
|
2026-07-23T13:51:38: [connect] socket=fGwRmZaYGzedlqqRAAAF company=1 user=1 role=owner
|
||||||
|
2026-07-23T13:51:40: [disconnect] socket=fGwRmZaYGzedlqqRAAAF
|
||||||
|
2026-07-23T13:51:40: [connect] socket=YZk7xLKHpmi29ykIAAAH company=1 user=1 role=owner
|
||||||
|
2026-07-23T13:51:41: [disconnect] socket=YZk7xLKHpmi29ykIAAAH
|
||||||
|
2026-07-23T13:51:41: [connect] socket=f078x01mtX2eGd2HAAAJ company=1 user=1 role=owner
|
||||||
|
2026-07-23T13:57:26: [disconnect] socket=f078x01mtX2eGd2HAAAJ
|
||||||
|
2026-07-23T13:57:28: [connect] socket=vToy_ZVIAk6w9099AAAL company=1 user=1 role=owner
|
||||||
|
2026-07-23T14:17:58: [disconnect] socket=vToy_ZVIAk6w9099AAAL
|
||||||
|
2026-07-23T14:18:00: [connect] socket=7yHLdkKxBAAO_nF4AAAN company=1 user=1 role=owner
|
||||||
|
2026-07-23T16:25:41: [disconnect] socket=7yHLdkKxBAAO_nF4AAAN
|
||||||
|
2026-07-25T12:19:55: Node.js real-time server running on port 3000
|
||||||
|
2026-08-03T08:52:15: Node.js real-time server running on port 3000
|
||||||
|
2026-08-03T10:17:41: [connect] socket=kNyFq-T_JVC3-_WLAAAB company=1 user=1 role=owner
|
||||||
|
2026-08-03T10:18:50: [disconnect] socket=kNyFq-T_JVC3-_WLAAAB
|
||||||
|
2026-08-03T10:18:50: [connect] socket=efcou9_hk0YUTnvQAAAD company=1 user=1 role=owner
|
||||||
|
2026-08-03T10:18:59: [disconnect] socket=efcou9_hk0YUTnvQAAAD
|
||||||
|
2026-08-03T10:18:59: [connect] socket=PmKuy_3CCIDze4P3AAAF company=1 user=1 role=owner
|
||||||
|
2026-08-03T10:32:14: [disconnect] socket=PmKuy_3CCIDze4P3AAAF
|
||||||
|
2026-08-03T10:32:18: [connect] socket=-ZlIPBBmpRazD30gAAAH company=1 user=1 role=owner
|
||||||
|
2026-08-03T10:49:23: [disconnect] socket=-ZlIPBBmpRazD30gAAAH
|
||||||
|
2026-08-03T10:49:26: [connect] socket=Azbj9ipTPqb3aOW3AAAJ company=1 user=1 role=owner
|
||||||
|
2026-08-03T10:54:19: [disconnect] socket=Azbj9ipTPqb3aOW3AAAJ
|
||||||
|
2026-08-03T10:54:19: [connect] socket=FMnx-fmSk96rxIfwAAAL company=1 user=1 role=owner
|
||||||
|
2026-08-03T11:13:57: [disconnect] socket=FMnx-fmSk96rxIfwAAAL
|
||||||
|
2026-08-03T11:13:59: [connect] socket=LgVxBoN_6JuJtxHyAAAN company=1 user=1 role=owner
|
||||||
Generated
+11
-11
@@ -260,9 +260,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/engine.io": {
|
"node_modules/engine.io": {
|
||||||
"version": "6.6.8",
|
"version": "6.6.9",
|
||||||
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.8.tgz",
|
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.9.tgz",
|
||||||
"integrity": "sha512-2agL3ueZhqxoVrfmntO8yuVj+uNSlIOnhykYHk3Cq0ShYPdUjjUiSJrQvXjq01I9jAuI0Zl2YO8Evv5Mqytm5g==",
|
"integrity": "sha512-clKkw4C7nJ22mGgoVcCg6V/W/TxdNyIOTr89k2ONZu81qqkddPFDF0LXcbAwhzPD8DjkiRCjzuiO6Y+fkpD4vg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/cors": "^2.8.12",
|
"@types/cors": "^2.8.12",
|
||||||
@@ -274,7 +274,7 @@
|
|||||||
"cors": "~2.8.5",
|
"cors": "~2.8.5",
|
||||||
"debug": "~4.4.1",
|
"debug": "~4.4.1",
|
||||||
"engine.io-parser": "~5.2.1",
|
"engine.io-parser": "~5.2.1",
|
||||||
"ws": "~8.20.1"
|
"ws": "~8.21.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.2.0"
|
"node": ">=10.2.0"
|
||||||
@@ -929,13 +929,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/socket.io-adapter": {
|
"node_modules/socket.io-adapter": {
|
||||||
"version": "2.5.7",
|
"version": "2.5.8",
|
||||||
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.7.tgz",
|
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.8.tgz",
|
||||||
"integrity": "sha512-e0LyK91f3cUxTmv95/KzoLg47+zF+s/sbxRGDNsyG4dmIP8ZSX8ax6byOxfJXeNNtS/8AZlfD+uP7gBeR7DLlg==",
|
"integrity": "sha512-6Oy52pbg+kvdCVvjcN+FnY7BvxZ7cIHNScbvztT/It5d0vbwoJoVZmF2gjJmnV0/4WlXRfG15zc45ySk9Ah8bw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"debug": "~4.4.1",
|
"debug": "~4.4.1",
|
||||||
"ws": "~8.20.1"
|
"ws": "~8.21.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/socket.io-adapter/node_modules/debug": {
|
"node_modules/socket.io-adapter/node_modules/debug": {
|
||||||
@@ -1085,9 +1085,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ws": {
|
"node_modules/ws": {
|
||||||
"version": "8.20.1",
|
"version": "8.21.1",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.21.1.tgz",
|
||||||
"integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==",
|
"integrity": "sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.0.0"
|
"node": ">=10.0.0"
|
||||||
|
|||||||
@@ -269,7 +269,7 @@ run($pdo, "
|
|||||||
CREATE TABLE IF NOT EXISTS `md_bin` (
|
CREATE TABLE IF NOT EXISTS `md_bin` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
`company_id` int(11) NOT NULL,
|
`company_id` int(11) NOT NULL,
|
||||||
`td_stock_id` int(11) NOT NULL DEFAULT 0,
|
`td_stock_id` int(11) DEFAULT NULL,
|
||||||
`warehouse` int(11) NOT NULL,
|
`warehouse` int(11) NOT NULL,
|
||||||
`storage_id` int(11) NOT NULL DEFAULT 0,
|
`storage_id` int(11) NOT NULL DEFAULT 0,
|
||||||
`zone` varchar(10) NOT NULL,
|
`zone` varchar(10) NOT NULL,
|
||||||
@@ -283,6 +283,15 @@ CREATE TABLE IF NOT EXISTS `md_bin` (
|
|||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
", 'md_bin');
|
", 'md_bin');
|
||||||
|
|
||||||
|
// Column made nullable — WarehouseManager::releaseBin() does `SET td_stock_id =
|
||||||
|
// NULL` to mark a bin empty (mirroring product_sku on the same row), but the
|
||||||
|
// column was NOT NULL DEFAULT 0. Under strict SQL mode this made releaseBin()
|
||||||
|
// fail with "Column 'td_stock_id' cannot be null" on every supplier return,
|
||||||
|
// every fully-depleted stock-out, and every stock transfer. Every read site
|
||||||
|
// (getBinStock(), occupyBin()) already treats 0 and NULL as equivalent "empty"
|
||||||
|
// (`if (!$td_stock_id)`), so this is a safe, behavior-preserving widening.
|
||||||
|
run($pdo, "ALTER TABLE `md_bin` MODIFY `td_stock_id` int(11) DEFAULT NULL", 'md_bin.td_stock_id nullable');
|
||||||
|
|
||||||
run($pdo, "
|
run($pdo, "
|
||||||
CREATE TABLE IF NOT EXISTS `td_bin_log` (
|
CREATE TABLE IF NOT EXISTS `td_bin_log` (
|
||||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
@@ -513,7 +522,7 @@ CREATE TABLE IF NOT EXISTS `td_stock` (
|
|||||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`ref_id` int(11) unsigned NOT NULL DEFAULT 0,
|
`ref_id` int(11) unsigned NOT NULL DEFAULT 0,
|
||||||
`company_id` int(11) NOT NULL DEFAULT 0,
|
`company_id` int(11) NOT NULL DEFAULT 0,
|
||||||
`uuid` varchar(20) NOT NULL,
|
`uuid` varchar(64) NOT NULL,
|
||||||
`type` varchar(20) NOT NULL,
|
`type` varchar(20) NOT NULL,
|
||||||
`ref_warehouse` varchar(20) NOT NULL DEFAULT '',
|
`ref_warehouse` varchar(20) NOT NULL DEFAULT '',
|
||||||
`date` datetime DEFAULT NULL,
|
`date` datetime DEFAULT NULL,
|
||||||
@@ -540,6 +549,22 @@ CREATE TABLE IF NOT EXISTS `td_stock` (
|
|||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
|
||||||
", 'td_stock (base template)');
|
", 'td_stock (base template)');
|
||||||
|
|
||||||
|
// Column widened for db_auth.php's 32-char $uuid (bin2hex(random_bytes(16))) plus
|
||||||
|
// manager-appended suffixes (e.g. "_ret_0", "_srn_0", "_3") — varchar(20) was too
|
||||||
|
// narrow and caused "Data too long for column 'uuid'" on every real stock movement
|
||||||
|
// (PO receipt, order confirm, return confirm, stock transfer) under strict SQL mode.
|
||||||
|
run($pdo, "ALTER TABLE `td_stock` MODIFY `uuid` varchar(64) NOT NULL", 'td_stock.uuid width');
|
||||||
|
|
||||||
|
// Per-warehouse td_stock_<id> tables are cloned from td_stock at warehouse-creation
|
||||||
|
// time (WarehouseManager::createStockTableForWarehouse()) and are NOT otherwise
|
||||||
|
// tracked by this script — widen uuid on every one that already exists so
|
||||||
|
// previously-created warehouses get the same fix. New warehouses get it for free
|
||||||
|
// from the template above.
|
||||||
|
$stockTables = $pdo->query("SHOW TABLES LIKE 'td\\_stock\\_%'")->fetchAll(PDO::FETCH_COLUMN);
|
||||||
|
foreach ($stockTables as $t) {
|
||||||
|
run($pdo, "ALTER TABLE `{$t}` MODIFY `uuid` varchar(64) NOT NULL", "{$t}.uuid width");
|
||||||
|
}
|
||||||
|
|
||||||
run($pdo, "
|
run($pdo, "
|
||||||
CREATE TABLE IF NOT EXISTS `etl_stock_summary` (
|
CREATE TABLE IF NOT EXISTS `etl_stock_summary` (
|
||||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
@@ -558,6 +583,24 @@ CREATE TABLE IF NOT EXISTS `etl_stock_summary` (
|
|||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
|
||||||
", 'etl_stock_summary');
|
", 'etl_stock_summary');
|
||||||
|
|
||||||
|
run($pdo, "
|
||||||
|
CREATE TABLE IF NOT EXISTS `etl_gl_summary` (
|
||||||
|
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`company_id` int(11) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`acc_code` int(11) NOT NULL DEFAULT 0,
|
||||||
|
`period` varchar(7) NOT NULL,
|
||||||
|
`debit` decimal(18,4) NOT NULL DEFAULT 0.0000,
|
||||||
|
`credit` decimal(18,4) NOT NULL DEFAULT 0.0000,
|
||||||
|
`count` int(11) NOT NULL DEFAULT 0,
|
||||||
|
`source_updated_at` datetime DEFAULT NULL,
|
||||||
|
`updated_at` datetime DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `company_id_acc_code_period` (`company_id`,`acc_code`,`period`),
|
||||||
|
KEY `company_id` (`company_id`),
|
||||||
|
KEY `period` (`period`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
|
||||||
|
", 'etl_gl_summary');
|
||||||
|
|
||||||
// ── Transactions ──────────────────────────────────────────────────────────────
|
// ── Transactions ──────────────────────────────────────────────────────────────
|
||||||
run($pdo, "
|
run($pdo, "
|
||||||
CREATE TABLE IF NOT EXISTS `td_gl` (
|
CREATE TABLE IF NOT EXISTS `td_gl` (
|
||||||
@@ -795,6 +838,7 @@ CREATE TABLE IF NOT EXISTS `td_return` (
|
|||||||
`tax` decimal(18,4) NOT NULL DEFAULT 0.0000,
|
`tax` decimal(18,4) NOT NULL DEFAULT 0.0000,
|
||||||
`tax_adjustment` decimal(8,2) NOT NULL DEFAULT 0.00,
|
`tax_adjustment` decimal(8,2) NOT NULL DEFAULT 0.00,
|
||||||
`notes` text NOT NULL DEFAULT '',
|
`notes` text NOT NULL DEFAULT '',
|
||||||
|
`formula_id` int(11) DEFAULT NULL,
|
||||||
`log` mediumtext NOT NULL DEFAULT '{}',
|
`log` mediumtext NOT NULL DEFAULT '{}',
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `company_id` (`company_id`),
|
KEY `company_id` (`company_id`),
|
||||||
@@ -806,6 +850,12 @@ CREATE TABLE IF NOT EXISTS `td_return` (
|
|||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
|
||||||
", 'td_return');
|
", 'td_return');
|
||||||
|
|
||||||
|
// Column added for ReturnManager::saveFormula() / custom credit-note GL formula
|
||||||
|
// selection — was missing from the original table (unlike td_invoice/td_receipt/
|
||||||
|
// td_payment, which all have formula_id). Without it, ReturnManager::saveReturn()
|
||||||
|
// fails on every insert.
|
||||||
|
run($pdo, "ALTER TABLE `td_return` ADD COLUMN `formula_id` int(11) DEFAULT NULL AFTER `notes`", 'td_return.formula_id');
|
||||||
|
|
||||||
run($pdo, "
|
run($pdo, "
|
||||||
CREATE TABLE IF NOT EXISTS `td_return_item` (
|
CREATE TABLE IF NOT EXISTS `td_return_item` (
|
||||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
@@ -1135,7 +1185,7 @@ CREATE TABLE IF NOT EXISTS `td_payment_item` (
|
|||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
|
||||||
", 'td_payment_item');
|
", 'td_payment_item');
|
||||||
|
|
||||||
run_ddl("
|
run($pdo, "
|
||||||
CREATE TABLE IF NOT EXISTS `document_types` (
|
CREATE TABLE IF NOT EXISTS `document_types` (
|
||||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`company_id` int(11) NOT NULL DEFAULT 0,
|
`company_id` int(11) NOT NULL DEFAULT 0,
|
||||||
@@ -1152,7 +1202,7 @@ CREATE TABLE IF NOT EXISTS `document_types` (
|
|||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
|
||||||
", 'document_types');
|
", 'document_types');
|
||||||
|
|
||||||
run_ddl("
|
run($pdo, "
|
||||||
CREATE TABLE IF NOT EXISTS `document_number_sequences` (
|
CREATE TABLE IF NOT EXISTS `document_number_sequences` (
|
||||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`company_id` int(11) NOT NULL DEFAULT 0,
|
`company_id` int(11) NOT NULL DEFAULT 0,
|
||||||
|
|||||||
Reference in New Issue
Block a user