import { WorkflowRequest } from '@models/WorkflowRequest'; import { Op } from 'sequelize'; import logger from './logger'; /** * Generate request number in format: REQ-YYYY-MM-XXXX * Counter resets every month * Example: REQ-2025-11-0001 */ export const generateRequestNumber = async (): Promise => { const now = new Date(); const year = now.getFullYear(); const month = (now.getMonth() + 1).toString().padStart(2, '0'); // Month is 0-indexed, so add 1 // Build the prefix pattern for current year-month const prefix = `REQ-${year}-${month}-`; try { // Find the highest counter for the current year-month const existingRequests = await WorkflowRequest.findAll({ where: { requestNumber: { [Op.like]: `${prefix}%` } }, attributes: ['requestNumber'], order: [['requestNumber', 'DESC']], limit: 1 }); let counter = 1; if (existingRequests.length > 0) { // Extract the counter from the last request number const lastRequestNumber = (existingRequests[0] as any).requestNumber; const lastCounter = parseInt(lastRequestNumber.replace(prefix, ''), 10); if (!isNaN(lastCounter)) { counter = lastCounter + 1; } } // Format counter as 4-digit number (0001, 0002, etc.) const counterStr = counter.toString().padStart(4, '0'); return `${prefix}${counterStr}`; } catch (error) { // Fallback to timestamp-based counter if database query fails logger.error('Error generating request number:', error); const fallbackCounter = Date.now().toString().slice(-4); return `${prefix}${fallbackCounter}`; } }; export const calculateTATDays = (tatHours: number): number => { return Math.ceil(tatHours / 24); }; export const calculateElapsedHours = (startTime: Date, endTime?: Date): number => { const end = endTime || new Date(); const diffMs = end.getTime() - startTime.getTime(); return Math.round((diffMs / (1000 * 60 * 60)) * 100) / 100; // Round to 2 decimal places }; export const calculateTATPercentage = (elapsedHours: number, totalTatHours: number): number => { if (totalTatHours === 0) return 0; return Math.min(Math.round((elapsedHours / totalTatHours) * 100), 100); }; export const isTATBreached = (elapsedHours: number, totalTatHours: number): boolean => { return elapsedHours > totalTatHours; }; export const isTATApproaching = (elapsedHours: number, totalTatHours: number, threshold: number = 80): boolean => { const percentage = calculateTATPercentage(elapsedHours, totalTatHours); return percentage >= threshold && percentage < 100; }; export const formatDate = (date: Date): string => { return date.toISOString().split('T')[0]; }; export const formatDateTime = (date: Date): string => { return date.toISOString(); }; export const isValidEmail = (email: string): boolean => { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return emailRegex.test(email); }; export const isValidUUID = (uuid: string): boolean => { const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; return uuidRegex.test(uuid); }; export const sanitizeString = (str: string): string => { return str.trim().replace(/[<>]/g, ''); }; export const generateChecksum = (data: string): string => { const crypto = require('crypto'); return crypto.createHash('sha256').update(data).digest('hex'); }; export const sleep = (ms: number): Promise => { return new Promise(resolve => setTimeout(resolve, ms)); };