const http = require('http'); const db = require('./config/dbproc.js'); const ALLOWED_EMAILS = new Set([ 'david.rodriques@telin.net', 'syam.thasya@telin.net', ]); function buildHtml(approverName, title, priorName, idxjustification, remark, status) { const url = status === 'RETURNED' ? `https://e-portal.telkomcel.tl/app/ext/eproc/justifikasi/${idxjustification}/edit` : `https://e-portal.telkomcel.tl/app/ext/eproc/circulation/${idxjustification}`; const statusLabel = status || 'READY FOR APPROVAL'; const notesLine = remark ? `
  • Notes: ${remark}
  • \n` : ''; return `

    Dear ${approverName},

    A new workflow task requires your review and approval. Please find the details regarding this justification below:

    Action Required:
    Please access the document and complete the approval via the E-Procurement Portal using the link below:
    ${url}

    If you have any questions or require further clarification, please do not hesitate to contact the Procurement Division.

    Thank you for your attention and cooperation.

    Best regards,
    Procurement Division
    Finance Business Partner Unit

    `; } function logEmail(trxId, toEmail, subject, html, fromEmail, status, requestPayload, responseMessage) { const qry = ` INSERT INTO email_logs (trx_id, to_email, subject, body, from_email, is_attachment, status, request_payload, response_message, created_at) VALUES (?, ?, ?, ?, ?, 0, ?, ?, ?, NOW()) `; db.query(qry, [trxId, toEmail, subject, html, fromEmail, status, requestPayload, responseMessage], function(err) { if (err) console.error('[email-notif] logEmail failed:', err.message); }); } function postEmail(toEmail, approverName, title, priorName, idxjustification, remark, status) { if (!ALLOWED_EMAILS.has(toEmail)) { console.log('[email-notif] skipped (not in allowed list):', toEmail); return; } const subject = status === 'RETURNED' ? `[Returned] Justification for ${title}` : `[Approval Required] Justification for ${title}`; const html = buildHtml(approverName, title, priorName, idxjustification, remark, status); const payload = JSON.stringify({ to: [toEmail], cc: [], bcc: [], subject, html }); const req = http.request({ hostname: 'localhost', port: 7004, path: '/api/email/send-telkomcel', method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) } }, (res) => { let body = ''; res.on('data', (chunk) => { body += chunk; }); res.on('end', () => { let trxId = ''; let responseMessage = body; try { const parsed = JSON.parse(body); trxId = parsed?.data?.trx_id || ''; responseMessage = JSON.stringify(parsed); } catch (_) {} const logStatus = res.statusCode >= 200 && res.statusCode < 300 ? 'success' : 'failed'; console.log('[email-notif] sent, status:', res.statusCode, '| trxId:', trxId, '| to:', toEmail); logEmail(trxId, toEmail, subject, html, '', logStatus, payload, responseMessage); }); }); req.on('error', (err) => { console.error('[email-notif] failed:', err.message); logEmail('', toEmail, subject, html, '', 'failed', payload, err.message); }); req.write(payload); req.end(); } /** * Notify first approver when justification is submitted. */ function notifyOnSubmit(idxjustification) { const qryJustification = ` select j.title, j.remark, e.fullname as creator_name from tbl_justification j join dbssotcel.tbl_employee e on e.nik = j.iby where j._idx = '${idxjustification}' limit 1 `; db.query(qryJustification, [], function(err, rows) { if (err || rows.length === 0) { console.error('[email-notif] notifyOnSubmit: failed to get justification data', err); return; } const title = rows[0].title; const remark = rows[0].remark || ''; const creatorName = rows[0].creator_name; const qryApprover = ` select t.nik, e.fullname, e.email from tbl_justificationttd t join dbssotcel.tbl_employee e on e.nik = t.nik AND email != '-' where t.idxjustification = '${idxjustification}' and t.issigned = 0 and t.isdeleted = 0 order by t._idx asc limit 1 `; db.query(qryApprover, [], function(err2, rows2) { if (err2 || rows2.length === 0) { console.error('[email-notif] notifyOnSubmit: no approver found', err2); return; } postEmail(rows2[0].email, rows2[0].fullname, title, creatorName, idxjustification, remark); }); }); } /** * Notify next approver after someone signs. */ function notifyOnSigned(idxjustification, signerNik) { const qryTitle = `select title, remark from tbl_justification where _idx = '${idxjustification}' limit 1`; db.query(qryTitle, [], function(err, rows) { if (err || rows.length === 0) { console.error('[email-notif] notifyOnSigned: failed to get justification title', err); return; } const title = rows[0].title; const remark = rows[0].remark || ''; const qrySigner = `select fullname from dbssotcel.tbl_employee where nik = '${signerNik}' limit 1`; db.query(qrySigner, [], function(err2, rows2) { if (err2 || rows2.length === 0) { console.error('[email-notif] notifyOnSigned: failed to get signer name', err2); return; } const signerName = rows2[0].fullname; const qryNext = ` select t.nik, e.fullname, e.email from tbl_justificationttd t join dbssotcel.tbl_employee e on e.nik = t.nik AND email != '-' where t.idxjustification = '${idxjustification}' and t.issigned = 0 and t.isdeleted = 0 order by t._idx asc limit 1 `; db.query(qryNext, [], function(err3, rows3) { if (err3 || rows3.length === 0) { console.log('[email-notif] notifyOnSigned: no more approvers to notify'); return; } postEmail(rows3[0].email, rows3[0].fullname, title, signerName, idxjustification, remark); }); }); }); } /** * Notify creator when justification is returned. */ function notifyOnReturn(idxjustification, returnerNik) { const qryJustification = ` select j.title, j.remark, e.fullname as creator_name, e.email as creator_email from tbl_justification j join dbssotcel.tbl_employee e on e.nik = j.iby where j._idx = '${idxjustification}' limit 1 `; db.query(qryJustification, [], function(err, rows) { if (err || rows.length === 0) { console.error('[email-notif] notifyOnReturn: failed to get justification data', err); return; } const title = rows[0].title; const remark = rows[0].remark || ''; const creatorName = rows[0].creator_name; const creatorEmail = rows[0].creator_email; const qryReturner = `select fullname from dbssotcel.tbl_employee where nik = '${returnerNik}' AND email != '-' limit 1`; db.query(qryReturner, [], function(err2, rows2) { if (err2 || rows2.length === 0) { console.error('[email-notif] notifyOnReturn: failed to get returner name', err2); return; } const returnerName = rows2[0].fullname; postEmail(creatorEmail, creatorName, title, returnerName, idxjustification, remark, 'RETURNED'); }); }); } module.exports = { notifyOnSubmit, notifyOnSigned, notifyOnReturn };