Dealer_Onboarding_Backend/src/services/SLAService.ts

88 lines
3.6 KiB
TypeScript

import db from '../database/models/index.js';
const { SLATracking, SLAConfiguration, SLABreach, Application, User } = db;
import { Op } from 'sequelize';
import { NotificationService } from './NotificationService.js';
export class SLAService {
/**
* Periodically check for SLA breaches across all active tracking records
*/
static async checkBreaches() {
console.log('[SLA Service] Starting breach check...');
// Find all active tracking records that are still 'In Progress' (not concluded)
const activeTracking = await SLATracking.findAll({
where: { isActive: true, isBreached: false, endTime: null },
include: [
{ model: Application, as: 'application' }
]
});
const now = new Date();
for (const track of activeTracking) {
// Fetch SLA configuration for this specific stage and entity type
const config = await SLAConfiguration.findOne({
where: {
stageName: track.stageName,
entityType: track.entityType,
isActive: true
}
});
if (!config) continue;
const startTime = new Date(track.startTime);
const slaHours = config.slaHours;
const deadline = new Date(startTime.getTime() + (slaHours * 60 * 60 * 1000));
if (now > deadline) {
// BREACH DETECTED
console.log(`[SLA Service] Breach detected for ${track.entityType}: ${track.application?.applicationId || track.entityId}, Stage: ${track.stageName}`);
// Update tracking record
await track.update({ isBreached: true });
// Create Breach Record
await SLABreach.create({
trackingId: track.id,
applicationId: track.applicationId,
stageCode: track.stageName,
breachedAt: now,
severity: 'High',
status: 'Open'
});
// Notify Stakeholders (Escalation)
await this.notifyEscalated(track);
}
}
console.log(`[SLA Service] Breach check completed at ${now.toISOString()}`);
}
private static async notifyEscalated(track: any) {
// Find the assigned user to notify them and potentially their manager
const application = await Application.findByPk(track.applicationId, {
include: [{ model: User, as: 'assignedToUser' }]
});
if (application?.assignedToUser) {
const portalBase = process.env.FRONTEND_URL || 'http://localhost:5173';
await NotificationService.notify(application.assignedTo, application.assignedToUser.email, {
title: `SLA BREACH: ${track.stageName}`,
message: `The application ${application.applicationId} has breached the SLA for ${track.stageName}. Current stage: ${application.currentStage}.`,
channels: ['email', 'system'],
templateCode: 'SLA_BREACH_WARNING',
placeholders: {
applicationId: application.applicationId || String(application.id),
stageName: track.stageName,
currentStage: application.currentStage || '',
link: `${portalBase}/applications/${application.id}`,
ctaLabel: 'Open application'
},
metadata: { type: 'error', applicationId: application.id }
});
}
}
}