/** * 일반계약 관련 결재 액션 핸들러 * * 실제 비즈니스 로직만 포함 (결재 로직은 approval-workflow에서 처리) */ 'use server'; import { sendContractApprovalRequest } from './service'; import { debugLog, debugError, debugSuccess } from '@/lib/debug-utils'; import db from '@/db/db'; import { eq } from 'drizzle-orm'; import { generalContracts } from '@/db/schema/generalContract'; interface ContractSummary { basicInfo: Record; items: Record[]; subcontractChecklist: Record | null; storageInfo?: Record[]; } /** * 일반계약 승인 핸들러 (결재 승인 후 계약승인요청 전송 실행) * * 결재 승인 후 자동으로 계약승인요청을 전송함 * 이 함수는 직접 호출하지 않고, 결재 워크플로우에서 자동으로 호출됨 * * @param payload - withApproval()에서 전달한 actionPayload */ export async function approveContractInternal(payload: { contractId: number; contractSummary: ContractSummary; currentUser?: { id: string | number; name?: string | null; email?: string | null; nonsapUserId?: string | null; }; }) { debugLog('[ContractApprovalHandler] 일반계약 승인 핸들러 시작', { contractId: payload.contractId, contractNumber: payload.contractSummary.basicInfo?.contractNumber, contractName: payload.contractSummary.basicInfo?.name, hasCurrentUser: !!payload.currentUser, }); try { // 1. 계약 정보 확인 const [contract] = await db .select() .from(generalContracts) .where(eq(generalContracts.id, payload.contractId)) .limit(1); if (!contract) { throw new Error('계약을 찾을 수 없습니다.'); } // 2. 계약승인요청 전송 debugLog('[ContractApprovalHandler] sendContractApprovalRequest 호출'); // PDF 경로에서 PDF 버퍼 읽기 const pdfPath = (payload.contractSummary as any).pdfPath; if (!pdfPath) { throw new Error('PDF 경로가 없습니다.'); } // PDF 파일 읽기 const fs = await import('fs/promises'); const path = await import('path'); const nasPath = process.env.NAS_PATH || "/evcp_nas"; const isProduction = process.env.NODE_ENV === "production"; const baseDir = isProduction ? nasPath : path.join(process.cwd(), "public"); // publicPath에서 실제 파일 경로로 변환 const actualPath = pdfPath.startsWith('/') ? path.join(baseDir, pdfPath) : path.join(baseDir, 'generalContracts', pdfPath); let pdfBuffer: Uint8Array; try { const fileBuffer = await fs.readFile(actualPath); pdfBuffer = new Uint8Array(fileBuffer); } catch (error) { debugError('[ContractApprovalHandler] PDF 파일 읽기 실패', error); throw new Error('PDF 파일을 읽을 수 없습니다.'); } // 기본계약서는 클라이언트에서 이미 생성되었을 것으로 가정 const generatedBasicContracts: Array<{ key: string; buffer: number[]; fileName: string }> = (payload.contractSummary as any).basicContractPdfs || []; const userId = payload.currentUser?.id ? String(payload.currentUser.id) : String(contract.registeredById); const result = await sendContractApprovalRequest( payload.contractSummary, pdfBuffer, 'contractDocument', userId, generatedBasicContracts ); if (!result.success) { debugError('[ContractApprovalHandler] 계약승인요청 전송 실패', result.error); // 전송 실패 시 상태를 원래대로 되돌림 await db.update(generalContracts) .set({ status: 'Draft', lastUpdatedAt: new Date() }) .where(eq(generalContracts.id, payload.contractId)); throw new Error(result.error || '계약승인요청 전송에 실패했습니다.'); } // 3. 전송 성공 시 상태를 'Contract Accept Request'로 변경 debugLog('[ContractApprovalHandler] 계약승인요청 전송 성공, 상태를 Contract Accept Request로 변경'); await db.update(generalContracts) .set({ status: 'Contract Accept Request', lastUpdatedAt: new Date() }) .where(eq(generalContracts.id, payload.contractId)); debugSuccess('[ContractApprovalHandler] 일반계약 승인 완료', { contractId: payload.contractId, result: result }); return { success: true, message: '계약승인요청이 전송되었습니다.', result: result }; } catch (error) { debugError('[ContractApprovalHandler] 일반계약 승인 중 에러', error); // 에러 발생 시 상태를 원래대로 되돌림 try { await db.update(generalContracts) .set({ status: 'Draft', lastUpdatedAt: new Date() }) .where(eq(generalContracts.id, payload.contractId)); } catch (updateError) { debugError('[ContractApprovalHandler] 상태 업데이트 실패', updateError); } throw error; } }