feat: notifikasi admin/monitoring via Telegram (WA fallback); alert staff dialihkan ke Telegram

This commit is contained in:
oxpoe committed 2026-10-09 09:23:06 +07:00
1 parent 52f6be26d1
commit e838645531
7 files changed
+35 -9

No files matched your search

+1 -1
View File
@@ -470,7 +470,7 @@ async function notifyAdminUnmatchedPayment(amount, rawText, service) {
'', '',
'Belum ada tagihan yang cocok. Cocokkan jam notif dengan bukti transfer pelanggan, lalu tandai lunas manual.' 'Belum ada tagihan yang cocok. Cocokkan jam notif dengan bukti transfer pelanggan, lalu tandai lunas manual.'
]; ];
await waNotify.sendToStaff(lines.join('\n')); await waNotify.notifyAdmin(lines.join('\n'));
} catch (e) {} } catch (e) {}
} }
+1 -1
View File
@@ -265,7 +265,7 @@ let sendMonitoringAlert = null;
(async () => { (async () => {
try { try {
const whatsappBot = await import('../services/whatsappBot.mjs'); const whatsappBot = await import('../services/whatsappBot.mjs');
sendMonitoringAlert = whatsappBot.sendMonitoringAlert; sendMonitoringAlert = require('../services/waNotifyService').notifyAdmin;
logger.info('[GenieACS] WhatsApp monitoring alert integration loaded'); logger.info('[GenieACS] WhatsApp monitoring alert integration loaded');
} catch (error) { } catch (error) {
logger.warn('[GenieACS] WhatsApp bot not available for monitoring alerts'); logger.warn('[GenieACS] WhatsApp bot not available for monitoring alerts');
+3 -3
View File
@@ -2144,7 +2144,7 @@ router.post('/customers/:id/generate-pppoe', requireAdminSession, async (req, re
'🔒 *PPPoE Pass:* *' + g.password + '*\n' + '🔒 *PPPoE Pass:* *' + g.password + '*\n' +
'📍 *Alamat:* ' + ((cust && cust.address) || '-') + '\n\n' + '📍 *Alamat:* ' + ((cust && cust.address) || '-') + '\n\n' +
'Silakan konfigurasi perangkat pelanggan dengan data di atas.'; 'Silakan konfigurasi perangkat pelanggan dengan data di atas.';
await waNotify.sendToStaff(credMsg); await waNotify.notifyAdmin(credMsg);
} catch (e) {} } catch (e) {}
req.session._msg = { type: 'success', text: 'Akun PPPoE dibuat: ' + g.username + ' / ' + g.password + ' (kredensial dikirim ke admin & teknisi).' }; req.session._msg = { type: 'success', text: 'Akun PPPoE dibuat: ' + g.username + ' / ' + g.password + ' (kredensial dikirim ke admin & teknisi).' };
} catch (e) { req.session._msg = { type: 'error', text: 'Gagal generate PPPoE: ' + e.message }; } } catch (e) { req.session._msg = { type: 'error', text: 'Gagal generate PPPoE: ' + e.message }; }
@@ -4119,7 +4119,7 @@ router.post('/registrations/:id/approve', requireAdminSession, express.urlencode
'🔒 *PPPoE Pass:* *' + (pppoePass || '-') + '*\n' + '🔒 *PPPoE Pass:* *' + (pppoePass || '-') + '*\n' +
'📍 *Alamat:* ' + (cust.address || '-') + '\n\n' + '📍 *Alamat:* ' + (cust.address || '-') + '\n\n' +
'Silakan konfigurasi perangkat pelanggan dengan data di atas.'; 'Silakan konfigurasi perangkat pelanggan dengan data di atas.';
await waNotify.sendToStaff(credMsg); await waNotify.notifyAdmin(credMsg);
} }
} catch (e) { try { logger.error('[RegApprove] staff cred error: ' + e.message); } catch (_) {} } } catch (e) { try { logger.error('[RegApprove] staff cred error: ' + e.message); } catch (_) {} }
@@ -6749,7 +6749,7 @@ router.post('/whatsapp/preview/send', requireAdminSession, express.urlencoded({
if (!m) throw new Error('Pesan tidak ditemukan'); if (!m) throw new Error('Pesan tidak ditemukan');
const waNotify = require('../services/waNotifyService'); const waNotify = require('../services/waNotifyService');
const txt = '[CONTOH] ' + m.title + '\n\n' + m.text; const txt = '[CONTOH] ' + m.title + '\n\n' + m.text;
const r = await waNotify.sendToStaff(txt); const r = await waNotify.notifyAdmin(txt);
return res.json({ ok: true, message: 'Contoh "' + m.title + '" terkirim ke WA admin (sent=' + ((r && r.sent) || 0) + ').' }); return res.json({ ok: true, message: 'Contoh "' + m.title + '" terkirim ke WA admin (sent=' + ((r && r.sent) || 0) + ').' });
} catch (e) { } catch (e) {
return res.status(500).json({ ok: false, message: e.message }); return res.status(500).json({ ok: false, message: e.message });
+1 -1
View File
@@ -824,7 +824,7 @@ async function sendAutoLunasRecap(pMonth, pYear) {
const list = rows.map(function (r) { return '• ' + r.name + ' (Rp ' + Number(r.amount || 0).toLocaleString('id-ID') + ')'; }).join('\n'); const list = rows.map(function (r) { return '• ' + r.name + ' (Rp ' + Number(r.amount || 0).toLocaleString('id-ID') + ')'; }).join('\n');
const total = rows.reduce(function (s, r) { return s + Number(r.amount || 0); }, 0); const total = rows.reduce(function (s, r) { return s + Number(r.amount || 0); }, 0);
const msg = '📋 *REKAP AUTO-LUNAS — Periode ' + m + '/' + y + '*\n\nJumlah : *' + rows.length + ' pelanggan*\nNominal : *Rp ' + total.toLocaleString('id-ID') + '*\n\nDaftar:\n' + list + '\n\nWaktu : ' + now.toLocaleString('id-ID'); const msg = '📋 *REKAP AUTO-LUNAS — Periode ' + m + '/' + y + '*\n\nJumlah : *' + rows.length + ' pelanggan*\nNominal : *Rp ' + total.toLocaleString('id-ID') + '*\n\nDaftar:\n' + list + '\n\nWaktu : ' + now.toLocaleString('id-ID');
const to = await waNotify.sendToStaff(msg); const to = await waNotify.notifyAdmin(msg);
logger.info('[CRON] Rekap auto-lunas ' + m + '/' + y + ' terkirim ke admin (' + rows.length + ' pelanggan).'); logger.info('[CRON] Rekap auto-lunas ' + m + '/' + y + ' terkirim ke admin (' + rows.length + ' pelanggan).');
return { sent: true, count: rows.length, period: m + '/' + y, to: to }; return { sent: true, count: rows.length, period: m + '/' + y, to: to };
} catch (e) { logger.error('[CRON] rekap auto-lunas error: ' + (e && e.message)); return { sent: false, error: e && e.message }; } } catch (e) { logger.error('[CRON] rekap auto-lunas error: ' + (e && e.message)); return { sent: false, error: e && e.message }; }
+1 -1
View File
@@ -943,7 +943,7 @@ async function autoDeactivateOverdueCustomers(months = 3, actor = null) {
const parts = []; const parts = [];
if (processed) parts.push(`${processed} pelanggan NONAKTIF (menunggak ${m} bln)`); if (processed) parts.push(`${processed} pelanggan NONAKTIF (menunggak ${m} bln)`);
if (removed.length) parts.push(`${removed.length} pelanggan DIHAPUS (menunggak > ${m} bln)`); if (removed.length) parts.push(`${removed.length} pelanggan DIHAPUS (menunggak > ${m} bln)`);
await waNotify.sendToStaff(`📋 *Auto-Tunggakan* await waNotify.notifyAdmin(`📋 *Auto-Tunggakan*
${parts.join('; ')}. ${parts.join('; ')}.
Nonaktif: ${names.join(', ') || '-'} Nonaktif: ${names.join(', ') || '-'}
+15 -1
View File
@@ -998,4 +998,18 @@ function initTelegram() {
} }
// Export for manual re-init from settings // Export for manual re-init from settings
module.exports = { initTelegram }; async function notifyAdmin(text) {
try {
const adminId = String(getSetting('telegram_admin_id', '') || '').trim();
if (!bot || !adminId || !text) return false;
const ids = adminId.split(/[,s]+/).filter(Boolean);
let ok = false;
for (const id of ids) {
try { await bot.sendMessage(id, text, { parse_mode: 'Markdown' }); ok = true; }
catch (e) { try { await bot.sendMessage(id, String(text)); ok = true; } catch (e2) {} }
}
return ok;
} catch (e) { return false; }
}
module.exports = { initTelegram, notifyAdmin };
+13 -1
View File
@@ -154,4 +154,16 @@ async function isConnected() {
return val; return val;
} }
module.exports = { sendText, sendImage, sendDocument, sendToStaff, isConnected, gateway }; // Notifikasi untuk ADMIN/monitoring → Telegram (utama). WA (sendToStaff) sebagai fallback.
async function notifyAdmin(text) {
try {
const tg = require('./telegramBot');
if (tg && typeof tg.notifyAdmin === 'function') {
const ok = await tg.notifyAdmin(text);
if (ok) return true;
}
} catch (e) {}
return sendToStaff(text);
}
module.exports = { sendText, sendImage, sendDocument, sendToStaff, notifyAdmin, isConnected, gateway };