diff options
Diffstat (limited to 'lib/general-contracts/approval-actions.ts')
| -rw-r--r-- | lib/general-contracts/approval-actions.ts | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/lib/general-contracts/approval-actions.ts b/lib/general-contracts/approval-actions.ts new file mode 100644 index 00000000..e75d6cd6 --- /dev/null +++ b/lib/general-contracts/approval-actions.ts @@ -0,0 +1,136 @@ +/** + * 일반계약 관련 결재 서버 액션 + * + * 사용자가 UI에서 호출하는 함수들 + * ApprovalSubmissionSaga를 사용하여 결재 프로세스를 시작 + */ + +'use server'; + +import { ApprovalSubmissionSaga } from '@/lib/approval'; +import { mapContractToApprovalTemplateVariables } from './approval-template-variables'; +import { debugLog, debugError, debugSuccess } from '@/lib/debug-utils'; +import db from '@/db/db'; +import { eq } from 'drizzle-orm'; +import { generalContracts } from '@/db/schema/generalContract'; +import { users } from '@/db/schema'; + +interface ContractSummary { + basicInfo: Record<string, unknown>; + items: Record<string, unknown>[]; + subcontractChecklist: Record<string, unknown> | null; + storageInfo?: Record<string, unknown>[]; + pdfPath?: string; + basicContractPdfs?: Array<{ key: string; buffer: number[]; fileName: string }>; +} + +/** + * 결재를 거쳐 일반계약 승인 요청을 처리하는 서버 액션 + * + * 사용법 (클라이언트 컴포넌트에서): + * ```typescript + * const result = await requestContractApprovalWithApproval({ + * contractId: 123, + * contractSummary: summaryData, + * currentUser: { id: 1, epId: 'EP001', email: 'user@example.com' }, + * approvers: ['EP002', 'EP003'], + * title: '계약 체결 진행 품의 요청서' + * }); + * + * if (result.status === 'pending_approval') { + * console.log('결재 ID:', result.approvalId); + * } + * ``` + */ +export async function requestContractApprovalWithApproval(data: { + contractId: number; + contractSummary: ContractSummary; + currentUser: { id: number; epId: string | null; email?: string }; + approvers?: string[]; // Knox EP ID 배열 (결재선) + title?: string; // 결재 제목 (선택사항, 미지정 시 자동 생성) +}) { + debugLog('[ContractApproval] 일반계약 승인 요청 결재 서버 액션 시작', { + contractId: data.contractId, + contractNumber: data.contractSummary.basicInfo?.contractNumber, + contractName: data.contractSummary.basicInfo?.name, + userId: data.currentUser.id, + hasEpId: !!data.currentUser.epId, + }); + + // 입력 검증 + if (!data.currentUser.epId) { + debugError('[ContractApproval] Knox EP ID 없음'); + throw new Error('Knox EP ID가 필요합니다'); + } + + if (!data.contractId) { + debugError('[ContractApproval] 계약 ID 없음'); + throw new Error('계약 ID가 필요합니다'); + } + + // 1. 유저의 nonsapUserId 조회 (Cronjob 환경을 위해) + debugLog('[ContractApproval] nonsapUserId 조회'); + const userResult = await db.query.users.findFirst({ + where: eq(users.id, data.currentUser.id), + columns: { nonsapUserId: true } + }); + const nonsapUserId = userResult?.nonsapUserId || null; + debugLog('[ContractApproval] nonsapUserId 조회 완료', { nonsapUserId }); + + // 2. 템플릿 변수 매핑 + debugLog('[ContractApproval] 템플릿 변수 매핑 시작'); + const variables = await mapContractToApprovalTemplateVariables(data.contractSummary); + debugLog('[ContractApproval] 템플릿 변수 매핑 완료', { + variableKeys: Object.keys(variables), + }); + + // 3. 결재 워크플로우 시작 (Saga 패턴) + debugLog('[ContractApproval] ApprovalSubmissionSaga 생성'); + const saga = new ApprovalSubmissionSaga( + // actionType: 핸들러를 찾을 때 사용할 키 + 'general_contract_approval', + + // actionPayload: 결재 승인 후 핸들러에 전달될 데이터 + { + contractId: data.contractId, + contractSummary: data.contractSummary, + currentUser: { + id: data.currentUser.id, + email: data.currentUser.email, + nonsapUserId: nonsapUserId, + }, + }, + + // approvalConfig: 결재 상신 정보 (템플릿 포함) + { + title: data.title || `계약 체결 진행 품의 요청서 - ${data.contractSummary.basicInfo?.contractNumber || data.contractId}`, + description: `${data.contractSummary.basicInfo?.name || '일반계약'} 계약 체결 진행 품의 요청`, + templateName: '일반계약 결재', // 한국어 템플릿명 + variables, // 치환할 변수들 + approvers: data.approvers, + currentUser: data.currentUser, + } + ); + + debugLog('[ContractApproval] Saga 실행 시작'); + const result = await saga.execute(); + + // 4. 결재 상신 성공 시 상태를 'approval_in_progress'로 변경 + if (result.status === 'pending_approval') { + debugLog('[ContractApproval] 상태를 approval_in_progress로 변경'); + await db.update(generalContracts) + .set({ + status: 'approval_in_progress', + lastUpdatedAt: new Date() + }) + .where(eq(generalContracts.id, data.contractId)); + } + + debugSuccess('[ContractApproval] 결재 워크플로우 완료', { + approvalId: result.approvalId, + status: result.status, + }); + + return result; +} + |
