/** * RFQ 발송 결재 핸들러 * * 첨부파일이 있는 RFQ 발송 시 결재 승인 후 실제 발송을 처리하는 핸들러 */ 'use server'; import { sendRfqToVendors } from './service'; /** * RFQ 발송 핸들러 (결재 승인 후 자동 실행) * * @param payload - 결재 상신 시 저장한 RFQ 발송 데이터 */ export async function sendRfqWithApprovalInternal(payload: { rfqId: number; rfqCode?: string; vendors: Array<{ vendorId: number; vendorName: string; vendorCode?: string | null; vendorCountry?: string | null; selectedMainEmail: string; additionalEmails: string[]; customEmails?: Array<{ email: string; name?: string }>; currency?: string | null; contractRequirements?: { ndaYn: boolean; generalGtcYn: boolean; projectGtcYn: boolean; agreementYn: boolean; projectCode?: string; }; isResend: boolean; sendVersion?: number; }>; attachmentIds: number[]; message?: string; generatedPdfs?: Array<{ key: string; buffer: number[]; fileName: string; }>; hasToSendEmail?: boolean; currentUser: { // cronjob 환경을 위한 필수 정보 id: string | number; name?: string | null; email?: string | null; epId?: string | null; }; }) { console.log('[RFQ Approval Handler] Starting RFQ send after approval'); console.log('[RFQ Approval Handler] RFQ ID:', payload.rfqId); console.log('[RFQ Approval Handler] Vendors count:', payload.vendors.length); console.log('[RFQ Approval Handler] Attachments count:', payload.attachmentIds.length); console.log('[RFQ Approval Handler] User ID:', payload.currentUser.id); try { // 결재 승인 후 실제 RFQ 발송 처리 // currentUser를 payload에서 전달 (cronjob 환경에서는 session 없음) const result = await sendRfqToVendors({ rfqId: payload.rfqId, rfqCode: payload.rfqCode, vendors: payload.vendors, attachmentIds: payload.attachmentIds, message: payload.message, generatedPdfs: payload.generatedPdfs, hasToSendEmail: payload.hasToSendEmail ?? true, currentUser: payload.currentUser, // ✅ payload의 currentUser 전달 }); console.log('[RFQ Approval Handler] ✅ RFQ sent successfully'); console.log('[RFQ Approval Handler] Total sent:', result.totalSent); console.log('[RFQ Approval Handler] Total contracts:', result.totalContracts); return { success: true, ...result, }; } catch (error) { console.error('[RFQ Approval Handler] ❌ Failed to send RFQ:', error); throw new Error( error instanceof Error ? `RFQ 발송 실패: ${error.message}` : 'RFQ 발송 중 오류가 발생했습니다.' ); } } /** * 템플릿 변수 매핑 함수 * RFQ 발송 정보를 결재 템플릿 변수로 변환 */ export async function mapRfqSendToTemplateVariables(data: { attachments: Array<{ fileName?: string | null; fileSize?: number | null; }>; vendorNames: string[]; applicationReason: string; }) { const { htmlTableConverter, htmlListConverter } = await import('@/lib/approval/template-utils'); // 파일 크기를 읽기 쉬운 형식으로 변환 const formatFileSize = (bytes?: number | null): string => { if (!bytes || bytes === 0) return '-'; const units = ['B', 'KB', 'MB', 'GB']; let size = bytes; let unitIndex = 0; while (size >= 1024 && unitIndex < units.length - 1) { size /= 1024; unitIndex++; } return `${size.toFixed(2)} ${units[unitIndex]}`; }; // 첨부파일 테이블 데이터 준비 (순번, 파일명, 파일크기만) const attachmentTableData = data.attachments.map((att, index) => ({ '순번': String(index + 1), '파일명': att.fileName || '-', '파일 크기': formatFileSize(att.fileSize), })); // 첨부파일 테이블 HTML 생성 const attachmentTableHtml = await htmlTableConverter( attachmentTableData.length > 0 ? attachmentTableData : [], [ { key: '순번', label: '순번' }, { key: '파일명', label: '파일명' }, { key: '파일 크기', label: '파일 크기' }, ] ); // 제출처 (벤더 이름들) HTML 생성 const vendorListHtml = await htmlListConverter( data.vendorNames.length > 0 ? data.vendorNames : ['제출처가 없습니다.'] ); return { '파일 테이블': attachmentTableHtml, '제출처': vendorListHtml, '신청사유': data.applicationReason || '사유 없음', }; }