import { getForm16Config } from '../services/form16Config.service'; import { runForm16AlertSubmitJob, runForm16ReminderJob, runForm16Remind26AsUploadJob } from '../services/form16Notification.service'; import logger from '../utils/logger'; const TZ = process.env.TZ || 'Asia/Kolkata'; // 26AS reminder is quarter-based; we evaluate once daily at this fixed time. const RE_26AS_REMINDER_CHECK_TIME = '08:30'; /** Last date (YYYY-MM-DD) we ran the alert job in the configured timezone. */ let lastAlertRunDate: string | null = null; /** Last date (YYYY-MM-DD) we ran the reminder job in the configured timezone. */ let lastReminderRunDate: string | null = null; /** Last date (YYYY-MM-DD) we ran the 26AS upload reminder job in the configured timezone. */ let last26AsReminderRunDate: string | null = null; /** * Get current time in configured TZ as HH:mm (24h, zero-padded). */ function getCurrentTimeHHmm(): string { const now = new Date(); const str = now.toLocaleTimeString('en-CA', { hour: '2-digit', minute: '2-digit', hour12: false, timeZone: TZ }); const [h, m] = str.split(':').map((x) => parseInt(x, 10)); if (Number.isNaN(h) || Number.isNaN(m)) return '00:00'; return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}`; } /** * Get current date in configured TZ as YYYY-MM-DD. */ function getCurrentDateString(): string { const now = new Date(); const str = now.toLocaleDateString('en-CA', { timeZone: TZ }); return str; } /** * Tick: run every minute; if current time matches config run-at time and we haven't run today, run the job. */ async function form16NotificationTick(): Promise { try { const config = await getForm16Config(); const nowTime = getCurrentTimeHHmm(); const today = getCurrentDateString(); const alertTime = (config.alertSubmitForm16RunAtTime || '').trim(); if (config.alertSubmitForm16Enabled && alertTime && alertTime === nowTime && lastAlertRunDate !== today) { lastAlertRunDate = today; logger.info(`[Form16 Job] Running alert submit job (scheduled at ${alertTime})`); await runForm16AlertSubmitJob(); } const reminderTime = (config.reminderRunAtTime || '').trim(); if (config.reminderNotificationEnabled && reminderTime && reminderTime === nowTime && lastReminderRunDate !== today) { lastReminderRunDate = today; logger.info(`[Form16 Job] Running reminder job (scheduled at ${reminderTime})`); await runForm16ReminderJob(); } if (config.reminder26AsUploadEnabled && RE_26AS_REMINDER_CHECK_TIME === nowTime && last26AsReminderRunDate !== today) { last26AsReminderRunDate = today; logger.info(`[Form16 Job] Running 26AS upload reminder job (daily check at ${RE_26AS_REMINDER_CHECK_TIME})`); await runForm16Remind26AsUploadJob(); } } catch (e) { logger.error('[Form16 Job] Tick error:', e); } } /** * Start Form 16 scheduled notification jobs. * Schedule is read from Form 16 admin config (alertSubmitForm16RunAtTime, reminderRunAtTime). * A tick runs every minute; when server time (in configured TZ) matches the run-at time, the job runs once that day. */ export function startForm16NotificationJobs(): void { const cron = require('node-cron'); cron.schedule('* * * * *', () => { form16NotificationTick(); }, { timezone: TZ }); logger.info(`[Form16 Job] Form 16 notification jobs scheduled (config-driven run times, TZ: ${TZ})`); }