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:
- Justification: ${title}
- Task Type: OPEN
- Status: ${statusLabel}
${notesLine} - Sent By: ${priorName}
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
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
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}' 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 };