import config from "./config/config"; import logging from "./config/logging"; import * as Xcron from "node-cron"; import { getListOutbox, sendToQontak, uploadFileCdn, changeStatusOutbox, } from "./lib-inject"; export const NAME_SPACE = "WA_GATEWAY"; const VERSION = "1.1"; let isRunning = false; logging.info(NAME_SPACE, "Starting. Ver:", `${VERSION}`); type MessageType = "mcu" | "payment"; const on_init = async () => { logging.info( NAME_SPACE, "-------------------- ON INIT START --------------------" ); // Process both message types await processMessageType("mcu"); await processMessageType("payment"); logging.info( NAME_SPACE, "-------------------- ON INIT END --------------------" ); }; on_init(); async function processMessageType(messageType: MessageType) { logging.info( NAME_SPACE, `Processing ${config.messageTypes[messageType].name} messages` ); await main(messageType, "N"); await main(messageType, "E"); await main(messageType, "R"); } async function processOutboxItem( messageType: MessageType, outbox: any, status: string, retry: number ) { if (outbox.fileUrl == null) { const uploadResult = await uploadFile(messageType, outbox); logging.info( NAME_SPACE, `\t Uploading File to CDN [${config.messageTypes[messageType].name}]:`, uploadResult ); await delay(1000); if (uploadResult === "OK") { logging.info(NAME_SPACE, "\t File Uploaded"); const response = await sentMsg(messageType, outbox, status, retry); await delay(1000); logging.info( NAME_SPACE, `\t Resp Qontak [${config.messageTypes[messageType].name}]:`, response ); } else { await changeStatus(messageType, outbox, "E", retry); } } else { const response = await sentMsg(messageType, outbox, status, retry); await delay(1000); logging.info( NAME_SPACE, `\t Resp Qontak [${config.messageTypes[messageType].name}]:`, response ); } } async function main(messageType: MessageType, status: string) { if (isRunning) { logging.info(NAME_SPACE, "Process is running. Skip this run."); return; } isRunning = true; try { logging.info( NAME_SPACE, `Process is running. Start to get list outbox for ${config.messageTypes[messageType].name}.` ); const outboxs = await getLists(messageType, status); switch (status) { case "N": logging.info( NAME_SPACE, `GET Processed (N) Message - ${config.messageTypes[messageType].name}` ); for (const outbox of outboxs) { await processOutboxItem( messageType, outbox, status, outbox.XWaOutboxIsRetry ); } break; case "E": logging.info( NAME_SPACE, `GET Error (E) Message - ${config.messageTypes[messageType].name}` ); for (const outbox of outboxs) { const retry = outbox.XWaOutboxIsRetry; if (retry >= 5) { logging.info( NAME_SPACE, "\t Retry count more than 5. Skip this message." ); continue; } await processOutboxItem( messageType, outbox, status, retry + 1 ); } break; case "R": logging.info( NAME_SPACE, `GET Rejected (R) Message - ${config.messageTypes[messageType].name}` ); for (const outbox of outboxs) { await processOutboxItem( messageType, outbox, status, outbox.XWaOutboxIsRetry ); } break; } logging.info( NAME_SPACE, `End Job Get Order - ${config.messageTypes[messageType].name}` ); } catch (e) { if (e instanceof Error) { logging.error(NAME_SPACE, e.message); } else { logging.error(NAME_SPACE, "Unknown error"); } } finally { isRunning = false; } } async function getLists(messageType: MessageType, status: string) { const { startDate, endDate } = config; const resp = await getListOutbox(messageType, status, startDate, endDate); if (resp?.status !== "OK") { logging.error(NAME_SPACE, "\t Error get outbox data", resp); return []; } logging.info( NAME_SPACE, `\t Success get order data found [${config.messageTypes[messageType].name}]`, resp.data?.length || 0 ); return typeof resp.data === "string" ? JSON.parse(resp.data) : resp.data || []; } async function sentMsg( messageType: MessageType, item: any, status: string, retry: number ) { const payload = { orderID: item.orderID, orderDate: item.orderDate, patientDOB: item.patientDOB, patientName: item.patientName, patientHp: item.patientHp, corpName: item.CorporateName, fileName: item.fileName, statusOutbox: status, retryOutbox: retry, sendWaID: item.sendWaID, }; return await sendToQontak(messageType, payload); } async function uploadFile(messageType: MessageType, item: any) { const payload = { fileName: item.fileName, rptUrl: item.localUrl, mime: "application/pdf", XWaOutboxID: item.sendWaID, }; return await uploadFileCdn(messageType, payload); } async function changeStatus( messageType: MessageType, item: any, status: string, retry: number ) { const payload = { toStatus: status, XWaOutboxID: item.sendWaID, retry: retry, }; return await changeStatusOutbox(messageType, payload); } async function delay(ms: number) { return new Promise(resolve => setTimeout(resolve, ms)); } // Schedule both message types for (const sched of config.schedule) { Xcron.schedule( sched, async () => { logging.info( NAME_SPACE, " -------------------- ON INIT SCHEDULE --------------------" ); await processMessageType("mcu"); await processMessageType("payment"); logging.info( NAME_SPACE, "-------------------- END SCHEDULE --------------------" ); }, { timezone: "Asia/Jakarta", } ); }