cron low stock - overdue invoice
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/**
|
||||
* alert_low_stock.php — Called by Node.js scheduler daily at 8am.
|
||||
* Returns companies that have one or more SKUs below their min_stock threshold.
|
||||
* Response: { success: 1, alerts: [{ company_id, count }] }
|
||||
*/
|
||||
require __DIR__ . '/../assets/utils/cron_auth.php';
|
||||
|
||||
$sth = $pdo1->query(
|
||||
"SELECT e.company_id, COUNT(*) AS count
|
||||
FROM etl_stock_summary e
|
||||
JOIN md_product p
|
||||
ON p.product_sku = e.product_sku
|
||||
AND p.company_id = e.company_id
|
||||
AND p.status = 1
|
||||
WHERE e.company_id > 0
|
||||
AND p.min_stock > 0
|
||||
AND (e.total_in - e.total_out) < p.min_stock
|
||||
GROUP BY e.company_id
|
||||
HAVING count > 0"
|
||||
);
|
||||
|
||||
$answer['success'] = 1;
|
||||
$answer['alerts'] = $sth->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
exit(json_encode($answer));
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/**
|
||||
* alert_overdue_invoices.php — Called by Node.js scheduler daily at 9am.
|
||||
* Returns companies that have one or more issued sales invoices past their due date.
|
||||
* status = 1 means issued but not fully settled. status = 2 means fully settled.
|
||||
* Response: { success: 1, alerts: [{ company_id, count }] }
|
||||
*/
|
||||
require __DIR__ . '/../assets/utils/cron_auth.php';
|
||||
|
||||
$sth = $pdo1->query(
|
||||
"SELECT company_id, COUNT(*) AS count
|
||||
FROM td_invoice
|
||||
WHERE company_id > 0
|
||||
AND doc_type = 'invoice'
|
||||
AND status = 1
|
||||
AND due_date IS NOT NULL
|
||||
AND due_date < CURDATE()
|
||||
GROUP BY company_id
|
||||
HAVING count > 0"
|
||||
);
|
||||
|
||||
$answer['success'] = 1;
|
||||
$answer['alerts'] = $sth->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
exit(json_encode($answer));
|
||||
+55
-1
@@ -6,6 +6,7 @@ const http = require('http');
|
||||
const PHP_BASE = process.env.PHP_BASE_URL || 'http://127.0.0.1';
|
||||
const PHP_WEBROOT = process.env.PHP_WEBROOT || '/mn3wms/app';
|
||||
const SECRET = process.env.EMIT_SECRET || '';
|
||||
const NODE_PORT = process.env.PORT || 3000;
|
||||
|
||||
function callPhp(path, body) {
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -39,6 +40,25 @@ function callPhp(path, body) {
|
||||
});
|
||||
}
|
||||
|
||||
function callEmit(company_id, event, data) {
|
||||
const payload = JSON.stringify({ event, data, company_id });
|
||||
const options = {
|
||||
hostname: '127.0.0.1',
|
||||
port: NODE_PORT,
|
||||
path: '/emit',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Length': Buffer.byteLength(payload),
|
||||
'x-emit-secret': SECRET,
|
||||
},
|
||||
};
|
||||
const req = http.request(options);
|
||||
req.on('error', (e) => console.error(`[alert] emit failed company=${company_id}:`, e.message));
|
||||
req.write(payload);
|
||||
req.end();
|
||||
}
|
||||
|
||||
// ── ETL GL Summary maintenance — runs every hour ─────────────────────────────
|
||||
// Checks and repairs etl_gl_summary (GL aggregation table).
|
||||
// Each company has a fixed slot = company_id % 24 — load is spread across 24 hours.
|
||||
@@ -88,4 +108,38 @@ cron.schedule('30 * * * *', async () => {
|
||||
}
|
||||
});
|
||||
|
||||
console.log('[scheduler] running — etl_gl_maintenance + etl_stock_maintenance wired (hourly, slot-based)');
|
||||
// ── Low stock alert — runs daily at 08:00 ────────────────────────────────────
|
||||
cron.schedule('0 8 * * *', async () => {
|
||||
console.log('[scheduler] alert_low_stock running');
|
||||
try {
|
||||
const result = await callPhp('/cron/alert_low_stock.php', {});
|
||||
for (const { company_id, count } of (result.alerts || [])) {
|
||||
const msg = count === 1
|
||||
? '1 product is below minimum stock level.'
|
||||
: `${count} products are below minimum stock level.`;
|
||||
callEmit(parseInt(company_id), 'notification', { message: msg, type: 'warning' });
|
||||
console.log(`[alert] low_stock company=${company_id} count=${count}`);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[scheduler] alert_low_stock failed:', e.message);
|
||||
}
|
||||
});
|
||||
|
||||
// ── Overdue invoice alert — runs daily at 09:00 ───────────────────────────────
|
||||
cron.schedule('0 9 * * *', async () => {
|
||||
console.log('[scheduler] alert_overdue_invoices running');
|
||||
try {
|
||||
const result = await callPhp('/cron/alert_overdue_invoices.php', {});
|
||||
for (const { company_id, count } of (result.alerts || [])) {
|
||||
const msg = count === 1
|
||||
? '1 invoice is overdue and awaiting payment.'
|
||||
: `${count} invoices are overdue and awaiting payment.`;
|
||||
callEmit(parseInt(company_id), 'notification', { message: msg, type: 'danger' });
|
||||
console.log(`[alert] overdue_invoices company=${company_id} count=${count}`);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[scheduler] alert_overdue_invoices failed:', e.message);
|
||||
}
|
||||
});
|
||||
|
||||
console.log('[scheduler] running — etl_gl + etl_stock (hourly) | low_stock + overdue_invoices alerts (daily)');
|
||||
|
||||
Reference in New Issue
Block a user