import { WorkflowTemplate } from '../models/WorkflowTemplate'; import { WorkflowRequest } from '../models/WorkflowRequest'; import { User } from '../models/User'; import { Op } from 'sequelize'; import logger from '../utils/logger'; /** * Template Service * Handles CRUD operations for workflow templates */ export class TemplateService { /** * Create a new workflow template */ async createTemplate( userId: string, templateData: { templateName: string; templateCode?: string; templateDescription?: string; templateCategory?: string; workflowType?: string; approvalLevelsConfig?: any; defaultTatHours?: number; formStepsConfig?: any; userFieldMappings?: any; dynamicApproverConfig?: any; isActive?: boolean; } ): Promise { try { // Validate template code uniqueness if provided if (templateData.templateCode) { const existing = await WorkflowTemplate.findOne({ where: { templateCode: templateData.templateCode } }); if (existing) { throw new Error(`Template code '${templateData.templateCode}' already exists`); } } const template = await WorkflowTemplate.create({ templateName: templateData.templateName, templateCode: templateData.templateCode, templateDescription: templateData.templateDescription, templateCategory: templateData.templateCategory, workflowType: templateData.workflowType || templateData.templateCode?.toUpperCase(), approvalLevelsConfig: templateData.approvalLevelsConfig, defaultTatHours: templateData.defaultTatHours || 24, formStepsConfig: templateData.formStepsConfig, userFieldMappings: templateData.userFieldMappings, dynamicApproverConfig: templateData.dynamicApproverConfig, isActive: templateData.isActive !== undefined ? templateData.isActive : true, isSystemTemplate: false, // Admin-created templates are not system templates usageCount: 0, createdBy: userId, }); logger.info(`[TemplateService] Created template: ${template.templateId}`); return template; } catch (error) { logger.error('[TemplateService] Error creating template:', error); throw error; } } /** * Get template by ID */ async getTemplate(templateId: string): Promise { try { return await WorkflowTemplate.findByPk(templateId, { include: [{ model: User, as: 'creator' }] }); } catch (error) { logger.error('[TemplateService] Error getting template:', error); throw error; } } /** * Get template by code */ async getTemplateByCode(templateCode: string): Promise { try { return await WorkflowTemplate.findOne({ where: { templateCode }, include: [{ model: User, as: 'creator' }] }); } catch (error) { logger.error('[TemplateService] Error getting template by code:', error); throw error; } } /** * List all templates with filters */ async listTemplates(filters?: { category?: string; workflowType?: string; isActive?: boolean; isSystemTemplate?: boolean; search?: string; }): Promise { try { const where: any = {}; if (filters?.category) { where.templateCategory = filters.category; } if (filters?.workflowType) { where.workflowType = filters.workflowType; } if (filters?.isActive !== undefined) { where.isActive = filters.isActive; } if (filters?.isSystemTemplate !== undefined) { where.isSystemTemplate = filters.isSystemTemplate; } if (filters?.search) { where[Op.or] = [ { templateName: { [Op.iLike]: `%${filters.search}%` } }, { templateCode: { [Op.iLike]: `%${filters.search}%` } }, { templateDescription: { [Op.iLike]: `%${filters.search}%` } } ]; } return await WorkflowTemplate.findAll({ where, include: [{ model: User, as: 'creator' }], order: [['createdAt', 'DESC']] }); } catch (error) { logger.error('[TemplateService] Error listing templates:', error); throw error; } } /** * Update template */ async updateTemplate( templateId: string, userId: string, updateData: { templateName?: string; templateDescription?: string; templateCategory?: string; approvalLevelsConfig?: any; defaultTatHours?: number; formStepsConfig?: any; userFieldMappings?: any; dynamicApproverConfig?: any; isActive?: boolean; } ): Promise { try { const template = await WorkflowTemplate.findByPk(templateId); if (!template) { throw new Error('Template not found'); } // Check if template is system template (system templates should not be modified) if (template.isSystemTemplate && updateData.approvalLevelsConfig) { throw new Error('Cannot modify approval levels of system templates'); } await template.update(updateData); logger.info(`[TemplateService] Updated template: ${templateId}`); return template; } catch (error) { logger.error('[TemplateService] Error updating template:', error); throw error; } } /** * Delete template (soft delete by setting isActive to false) */ async deleteTemplate(templateId: string): Promise { try { const template = await WorkflowTemplate.findByPk(templateId); if (!template) { throw new Error('Template not found'); } // Check if template is in use const usageCount = await WorkflowRequest.count({ where: { templateId } }); if (usageCount > 0) { throw new Error(`Cannot delete template: ${usageCount} request(s) are using this template`); } // System templates cannot be deleted if (template.isSystemTemplate) { throw new Error('Cannot delete system templates'); } // Soft delete by deactivating await template.update({ isActive: false }); logger.info(`[TemplateService] Deleted (deactivated) template: ${templateId}`); } catch (error) { logger.error('[TemplateService] Error deleting template:', error); throw error; } } /** * Get active templates for workflow creation */ async getActiveTemplates(): Promise { try { return await WorkflowTemplate.findAll({ where: { isActive: true }, order: [['templateName', 'ASC']] }); } catch (error) { logger.error('[TemplateService] Error getting active templates:', error); throw error; } } /** * Increment usage count when template is used */ async incrementUsageCount(templateId: string): Promise { try { await WorkflowTemplate.increment('usageCount', { where: { templateId } }); } catch (error) { logger.error('[TemplateService] Error incrementing usage count:', error); // Don't throw - this is not critical } } }