From 9a79b7eb866806b7e9a982d084e584605721336e Mon Sep 17 00:00:00 2001 From: enlineawork Date: Mon, 7 Sep 2026 21:02:44 -0300 Subject: [PATCH] feat(f4): implement JEFE deadline policy and calendar administration --- .../inspection-deadline-admin.service.ts | 160 ++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 api-v3/src/inspection-reports/inspection-deadline-admin.service.ts diff --git a/api-v3/src/inspection-reports/inspection-deadline-admin.service.ts b/api-v3/src/inspection-reports/inspection-deadline-admin.service.ts new file mode 100644 index 0000000..d4e62aa --- /dev/null +++ b/api-v3/src/inspection-reports/inspection-deadline-admin.service.ts @@ -0,0 +1,160 @@ +import { Injectable } from '@nestjs/common'; +import { DataSource } from 'typeorm'; +import { administrationAuditContext } from '../administration/common/administration-audit'; +import { AuditService } from '../audit/audit.service'; +import type { AuthPrincipal, RequestWithContext } from '../common/http/request-context'; +import { AuditAction } from '../database/entities'; +import type { UpdateDeadlinePolicyDto, UpsertBusinessCalendarDayDto } from './dto/update-deadline-policy.dto'; + +@Injectable() +export class InspectionDeadlineAdminService { + constructor( + private readonly dataSource: DataSource, + private readonly audit: AuditService, + ) {} + + async policy() { + const [row] = await this.dataSource.query(` + SELECT id, + urgent_days AS "urgentDays", + urgent_day_type AS "urgentDayType", + non_urgent_days AS "nonUrgentDays", + non_urgent_day_type AS "nonUrgentDayType", + updated_by AS "updatedBy", + updated_at AS "updatedAt" + FROM inspection_deadline_policies + ORDER BY created_at + LIMIT 1 + `); + return row ?? { + urgentDays: 5, + urgentDayType: 'BUSINESS', + nonUrgentDays: 10, + nonUrgentDayType: 'BUSINESS', + }; + } + + async updatePolicy( + dto: UpdateDeadlinePolicyDto, + principal: AuthPrincipal, + request: RequestWithContext, + ) { + const before = await this.policy(); + const [existing] = await this.dataSource.query(` + SELECT id FROM inspection_deadline_policies ORDER BY created_at LIMIT 1 + `) as Array<{ id: string }>; + if (existing) { + await this.dataSource.query(` + UPDATE inspection_deadline_policies + SET urgent_days=$2, + urgent_day_type=$3, + non_urgent_days=$4, + non_urgent_day_type=$5, + updated_by=$6, + updated_at=CURRENT_TIMESTAMP + WHERE id=$1 + `, [ + existing.id, + dto.urgentDays, + dto.urgentDayType, + dto.nonUrgentDays, + dto.nonUrgentDayType, + principal.userId, + ]); + } else { + await this.dataSource.query(` + INSERT INTO inspection_deadline_policies( + urgent_days,urgent_day_type,non_urgent_days,non_urgent_day_type,updated_by + ) VALUES($1,$2,$3,$4,$5) + `, [ + dto.urgentDays, + dto.urgentDayType, + dto.nonUrgentDays, + dto.nonUrgentDayType, + principal.userId, + ]); + } + const after = await this.policy(); + await this.audit.record({ + ...administrationAuditContext(principal, request), + action: AuditAction.INSPECTION_DEADLINE_POLICY_UPDATED, + entityType: 'inspection_deadline_policy', + entityId: String((after as { id?: string }).id ?? 'singleton'), + beforeData: before as Record, + afterData: after as Record, + metadata: { + appliesOnlyToFutureLockedActs: true, + historicalActsKeepSnapshot: true, + }, + }); + return after; + } + + async calendar() { + const data = await this.dataSource.query(` + SELECT id,date,is_business_day AS "isBusinessDay",label, + updated_by AS "updatedBy",created_at AS "createdAt",updated_at AS "updatedAt" + FROM inspection_business_calendar_days + ORDER BY date + `); + return { data }; + } + + async upsertCalendarDay( + dto: UpsertBusinessCalendarDayDto, + principal: AuthPrincipal, + request: RequestWithContext, + ) { + const [before] = await this.dataSource.query(` + SELECT id,date,is_business_day AS "isBusinessDay",label + FROM inspection_business_calendar_days WHERE date=$1::date + `, [dto.date]); + await this.dataSource.query(` + INSERT INTO inspection_business_calendar_days(date,is_business_day,label,updated_by) + VALUES($1::date,$2,$3,$4) + ON CONFLICT(date) DO UPDATE SET + is_business_day=EXCLUDED.is_business_day, + label=EXCLUDED.label, + updated_by=EXCLUDED.updated_by, + updated_at=CURRENT_TIMESTAMP + `, [dto.date, dto.isBusinessDay, dto.label, principal.userId]); + const [after] = await this.dataSource.query(` + SELECT id,date,is_business_day AS "isBusinessDay",label, + updated_by AS "updatedBy",updated_at AS "updatedAt" + FROM inspection_business_calendar_days WHERE date=$1::date + `, [dto.date]); + await this.audit.record({ + ...administrationAuditContext(principal, request), + action: AuditAction.INSPECTION_BUSINESS_CALENDAR_UPDATED, + entityType: 'inspection_business_calendar_day', + entityId: String(after.id), + beforeData: before ?? null, + afterData: after, + }); + return after; + } + + async removeCalendarDay( + date: string, + principal: AuthPrincipal, + request: RequestWithContext, + ) { + const [before] = await this.dataSource.query(` + SELECT id,date,is_business_day AS "isBusinessDay",label + FROM inspection_business_calendar_days WHERE date=$1::date + `, [date]); + if (before) { + await this.dataSource.query(`DELETE FROM inspection_business_calendar_days WHERE id=$1`, [before.id]); + await this.audit.record({ + ...administrationAuditContext(principal, request), + action: AuditAction.INSPECTION_BUSINESS_CALENDAR_UPDATED, + entityType: 'inspection_business_calendar_day', + entityId: String(before.id), + beforeData: before, + afterData: null, + metadata: { removed: true }, + }); + } + return { removed: Boolean(before), date }; + } +}