import { Injectable, Inject, Logger } from '@nestjs/common'; import { Cron, CronExpression } from '@nestjs/schedule'; import { IReportDefinitionRepository, REPORT_DEFINITION_REPOSITORY, } from '../../domain/repositories'; import { GenerateReportHandler } from '../commands/generate-report/generate-report.handler'; import { GenerateReportCommand } from '../commands/generate-report/generate-report.command'; import { DateRange, ReportPeriod } from '../../domain/value-objects'; @Injectable() export class ReportGenerationScheduler { private readonly logger = new Logger(ReportGenerationScheduler.name); constructor( @Inject(REPORT_DEFINITION_REPOSITORY) private readonly definitionRepo: IReportDefinitionRepository, private readonly generateReportHandler: GenerateReportHandler, ) {} @Cron(CronExpression.EVERY_DAY_AT_1AM) async generateDailyReports(): Promise { this.logger.log('Starting daily report generation...'); try { const definitions = await this.definitionRepo.findScheduled(); const yesterday = this.getYesterday(); const dateRange = DateRange.create(yesterday.start, yesterday.end); for (const definition of definitions) { try { const command = new GenerateReportCommand( definition.reportCode, ReportPeriod.DAILY, yesterday.start, yesterday.end, ); await this.generateReportHandler.execute(command); this.logger.log(`Daily report generated: ${definition.reportCode}`); } catch (error) { this.logger.error( `Failed to generate daily report: ${definition.reportCode}`, error, ); } } this.logger.log('Daily report generation completed'); } catch (error) { this.logger.error('Daily report generation failed', error); } } @Cron(CronExpression.EVERY_WEEK) async generateWeeklyReports(): Promise { this.logger.log('Starting weekly report generation...'); try { const definitions = await this.definitionRepo.findScheduled(); const lastWeek = this.getLastWeek(); for (const definition of definitions) { try { const command = new GenerateReportCommand( definition.reportCode, ReportPeriod.WEEKLY, lastWeek.start, lastWeek.end, ); await this.generateReportHandler.execute(command); this.logger.log(`Weekly report generated: ${definition.reportCode}`); } catch (error) { this.logger.error( `Failed to generate weekly report: ${definition.reportCode}`, error, ); } } this.logger.log('Weekly report generation completed'); } catch (error) { this.logger.error('Weekly report generation failed', error); } } @Cron('0 0 1 * *') // First day of month at midnight async generateMonthlyReports(): Promise { this.logger.log('Starting monthly report generation...'); try { const definitions = await this.definitionRepo.findScheduled(); const lastMonth = this.getLastMonth(); for (const definition of definitions) { try { const command = new GenerateReportCommand( definition.reportCode, ReportPeriod.MONTHLY, lastMonth.start, lastMonth.end, ); await this.generateReportHandler.execute(command); this.logger.log(`Monthly report generated: ${definition.reportCode}`); } catch (error) { this.logger.error( `Failed to generate monthly report: ${definition.reportCode}`, error, ); } } this.logger.log('Monthly report generation completed'); } catch (error) { this.logger.error('Monthly report generation failed', error); } } private getYesterday(): { start: Date; end: Date } { const now = new Date(); const yesterday = new Date(now); yesterday.setDate(yesterday.getDate() - 1); const start = new Date( yesterday.getFullYear(), yesterday.getMonth(), yesterday.getDate(), 0, 0, 0, ); const end = new Date( yesterday.getFullYear(), yesterday.getMonth(), yesterday.getDate(), 23, 59, 59, 999, ); return { start, end }; } private getLastWeek(): { start: Date; end: Date } { const now = new Date(); const dayOfWeek = now.getDay(); const diffToLastMonday = dayOfWeek === 0 ? -13 : -6 - dayOfWeek; const start = new Date(now); start.setDate(now.getDate() + diffToLastMonday); start.setHours(0, 0, 0, 0); const end = new Date(start); end.setDate(start.getDate() + 6); end.setHours(23, 59, 59, 999); return { start, end }; } private getLastMonth(): { start: Date; end: Date } { const now = new Date(); const start = new Date(now.getFullYear(), now.getMonth() - 1, 1, 0, 0, 0); const end = new Date(now.getFullYear(), now.getMonth(), 0, 23, 59, 59, 999); return { start, end }; } }