/** * 정규업체 등록 관련 결재 서버 액션 * * 사용자가 UI에서 호출하는 함수들 * withApproval()을 사용하여 결재 프로세스를 시작 */ 'use server'; import { ApprovalSubmissionSaga } from '@/lib/approval'; import { mapRegistrationToTemplateVariables } from './handlers'; import { debugLog, debugError, debugSuccess } from '@/lib/debug-utils'; import type { RegistrationRequestData } from '@/components/vendor-regular-registrations/registration-request-dialog'; import db from '@/db/db'; import { eq } from 'drizzle-orm'; import { vendorRegularRegistrations } from '@/db/schema/vendorRegistrations'; import { users } from '@/db/schema'; /** * 결재를 거쳐 정규업체 등록을 처리하는 서버 액션 * * 사용법 (클라이언트 컴포넌트에서): * ```typescript * const result = await registerVendorWithApproval({ * registrationId: 123, * requestData: registrationData, * currentUser: { id: 1, epId: 'EP001', email: 'user@example.com' }, * approvers: ['EP002', 'EP003'], * attachments: [file1, file2] // 선택사항 * }); * * if (result.status === 'pending_approval') { * console.log('결재 ID:', result.approvalId); * } * ``` */ export async function registerVendorWithApproval(data: { registrationId: number; requestData: RegistrationRequestData; vendorId?: number; // vendors 테이블에서 정보를 가져오기 위한 vendorId currentUser: { id: number; epId: string | null; email?: string }; approvers?: string[]; // Knox EP ID 배열 (결재선) attachments?: File[]; // 첨부파일 (선택사항) title?: string; // 결재 제목 (선택사항, 미지정 시 자동 생성) }) { debugLog('[VendorRegistrationApproval] 정규업체 등록 결재 서버 액션 시작', { registrationId: data.registrationId, companyName: data.requestData.companyNameKor, businessNumber: data.requestData.businessNumber, userId: data.currentUser.id, hasEpId: !!data.currentUser.epId, }); // 입력 검증 if (!data.currentUser.epId) { debugError('[VendorRegistrationApproval] Knox EP ID 없음'); throw new Error('Knox EP ID가 필요합니다'); } if (!data.registrationId) { debugError('[VendorRegistrationApproval] 등록 ID 없음'); throw new Error('등록 ID가 필요합니다'); } // 1. 유저의 nonsapUserId 조회 (Cronjob 환경을 위해) debugLog('[VendorRegistrationApproval] nonsapUserId 조회'); const userResult = await db.query.users.findFirst({ where: eq(users.id, data.currentUser.id), columns: { nonsapUserId: true } }); const nonsapUserId = userResult?.nonsapUserId || null; debugLog('[VendorRegistrationApproval] nonsapUserId 조회 완료', { nonsapUserId }); // 2. 템플릿 변수 매핑 debugLog('[VendorRegistrationApproval] 템플릿 변수 매핑 시작'); const requestedAt = new Date(); const variables = await mapRegistrationToTemplateVariables({ requestData: data.requestData, requestedAt, vendorId: data.vendorId, }); debugLog('[VendorRegistrationApproval] 템플릿 변수 매핑 완료', { variableKeys: Object.keys(variables), }); // 3. 결재 워크플로우 시작 (Saga 패턴) debugLog('[VendorRegistrationApproval] ApprovalSubmissionSaga 생성', { hasAttachments: !!data.attachments, attachmentCount: data.attachments?.length || 0, }); const saga = new ApprovalSubmissionSaga( // actionType: 핸들러를 찾을 때 사용할 키 'vendor_regular_registration', // actionPayload: 결재 승인 후 핸들러에 전달될 데이터 { registrationId: data.registrationId, requestData: data.requestData, currentUser: { // ⚠️ Cronjob 환경을 위한 유저 정보 포함 (headers() 대신) id: data.currentUser.id, email: data.currentUser.email, nonsapUserId: nonsapUserId, // ⚠️ 미리 조회한 nonsapUserId 전달 }, }, // approvalConfig: 결재 상신 정보 (템플릿 포함) { title: data.title || `정규업체 등록 - ${data.requestData.companyNameKor}`, description: `${data.requestData.companyNameKor} 정규업체 등록 요청`, templateName: '정규업체 등록', // 한국어 템플릿명 variables, // 치환할 변수들 approvers: data.approvers, currentUser: data.currentUser, attachments: data.attachments, // 첨부파일 전달 } ); debugLog('[VendorRegistrationApproval] Saga 실행 시작'); const result = await saga.execute(); // 4. 결재 상신 성공 시 상태를 pending_approval로 변경 if (result.status === 'pending_approval') { debugLog('[VendorRegistrationApproval] 상태를 pending_approval로 변경'); await db.update(vendorRegularRegistrations) .set({ status: 'pending_approval', updatedAt: new Date() }) .where(eq(vendorRegularRegistrations.id, data.registrationId)); } debugSuccess('[VendorRegistrationApproval] 결재 워크플로우 완료', { approvalId: result.approvalId, status: result.status, }); return result; }