100 lines
3.0 KiB
TypeScript
100 lines
3.0 KiB
TypeScript
import { query, execute, insertReturning } from './db'
|
|
import { getLastWeekInfo, formatDate } from './week-calc'
|
|
|
|
let isRunning = false
|
|
|
|
/**
|
|
* 주간보고 취합 실행
|
|
*/
|
|
export async function aggregateWeeklyReports(targetYear?: number, targetWeek?: number) {
|
|
const weekInfo = targetYear && targetWeek
|
|
? { year: targetYear, week: targetWeek }
|
|
: getLastWeekInfo()
|
|
|
|
console.log(`[Aggregator] 취합 시작: ${weekInfo.year}-W${weekInfo.week}`)
|
|
|
|
// 해당 주차에 제출된 보고서가 있는 프로젝트 조회
|
|
const projects = await query<any>(`
|
|
SELECT DISTINCT project_id
|
|
FROM wr_weekly_report_detail
|
|
WHERE report_year = $1 AND report_week = $2 AND report_status = 'SUBMITTED'
|
|
`, [weekInfo.year, weekInfo.week])
|
|
|
|
let aggregatedCount = 0
|
|
|
|
for (const { project_id } of projects) {
|
|
// 해당 프로젝트의 제출된 보고서들
|
|
const reports = await query<any>(`
|
|
SELECT report_id, work_hours
|
|
FROM wr_weekly_report_detail
|
|
WHERE project_id = $1 AND report_year = $2 AND report_week = $3
|
|
AND report_status = 'SUBMITTED'
|
|
`, [project_id, weekInfo.year, weekInfo.week])
|
|
|
|
const reportIds = reports.map((r: any) => r.report_id)
|
|
const totalHours = reports.reduce((sum: number, r: any) => sum + (parseFloat(r.work_hours) || 0), 0)
|
|
|
|
// 주차 날짜 계산
|
|
const jan4 = new Date(weekInfo.year, 0, 4)
|
|
const firstMonday = new Date(jan4)
|
|
firstMonday.setDate(jan4.getDate() - ((jan4.getDay() + 6) % 7))
|
|
const targetMonday = new Date(firstMonday)
|
|
targetMonday.setDate(firstMonday.getDate() + (weekInfo.week - 1) * 7)
|
|
const targetSunday = new Date(targetMonday)
|
|
targetSunday.setDate(targetMonday.getDate() + 6)
|
|
|
|
// UPSERT 취합 보고서
|
|
await execute(`
|
|
INSERT INTO wr_aggregated_report_summary (
|
|
project_id, report_year, report_week,
|
|
week_start_date, week_end_date,
|
|
report_ids, member_count, total_work_hours
|
|
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
|
ON CONFLICT (project_id, report_year, report_week)
|
|
DO UPDATE SET
|
|
report_ids = $6,
|
|
member_count = $7,
|
|
total_work_hours = $8,
|
|
aggregated_at = NOW(),
|
|
updated_at = NOW()
|
|
`, [
|
|
project_id,
|
|
weekInfo.year,
|
|
weekInfo.week,
|
|
formatDate(targetMonday),
|
|
formatDate(targetSunday),
|
|
reportIds,
|
|
reportIds.length,
|
|
totalHours || null
|
|
])
|
|
|
|
// 개별 보고서 상태 변경
|
|
await execute(`
|
|
UPDATE wr_weekly_report_detail SET
|
|
report_status = 'AGGREGATED',
|
|
updated_at = NOW()
|
|
WHERE report_id = ANY($1)
|
|
`, [reportIds])
|
|
|
|
aggregatedCount++
|
|
console.log(`[Aggregator] 프로젝트 ${project_id}: ${reportIds.length}건 취합`)
|
|
}
|
|
|
|
console.log(`[Aggregator] 취합 완료: ${aggregatedCount}개 프로젝트`)
|
|
|
|
return {
|
|
year: weekInfo.year,
|
|
week: weekInfo.week,
|
|
projectCount: aggregatedCount
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 스케줄러 상태
|
|
*/
|
|
export function getSchedulerStatus() {
|
|
return {
|
|
isRunning
|
|
}
|
|
}
|