/** * 결재 워크플로우 사용 예시 (템플릿 기반) * * 이 파일은 실제 사용 방법을 보여주는 예시입니다. * 실제 구현 시 각 서버 액션에 적용하면 됩니다. * * 업데이트: 템플릿 및 변수 치환 지원 */ import { registerActionHandler, withApproval } from './approval-workflow'; import { htmlTableConverter, htmlDescriptionList, } from './template-utils'; // ============================================================================ // 1단계: 액션 핸들러 등록 // ============================================================================ /** * 실사 요청의 실제 비즈니스 로직 * 결재 승인 후 실행될 함수 */ async function createInvestigationInternal(payload: { vendorId: number; vendorName: string; reason: string; scheduledDate: Date; }) { // 실제 DB 작업 등 비즈니스 로직 console.log('Creating investigation:', payload); // const result = await db.insert(vendorInvestigations).values({ // vendorId: payload.vendorId, // reason: payload.reason, // scheduledDate: payload.scheduledDate, // status: 'scheduled', // }).returning(); return { success: true, investigationId: 123 }; } // 핸들러 등록 (앱 시작 시 한 번만 실행되면 됨) registerActionHandler('vendor_investigation_request', createInvestigationInternal); // ============================================================================ // 2단계: 결재가 필요한 서버 액션 작성 // ============================================================================ /** * 사용자가 호출하는 서버 액션 * 결재를 거쳐서 실사 요청을 생성 (템플릿 기반) */ export async function createInvestigationWithApproval(data: { vendorId: number; vendorName: string; reason: string; scheduledDate: Date; currentUser: { id: number; epId: string | null }; approvers?: string[]; // Knox EP ID 배열 }) { 'use server'; // Next.js 15 server action // 1. 템플릿 변수 생성 (HTML 변환 포함) const summaryTable: string = await htmlTableConverter( [ { 항목: '협력업체명', 내용: data.vendorName }, { 항목: '실사 사유', 내용: data.reason }, { 항목: '예정일', 내용: data.scheduledDate.toLocaleDateString('ko-KR') }, ], [ { key: '항목', label: '항목' }, { key: '내용', label: '내용' }, ] ); const basicInfo: string = await htmlDescriptionList([ { label: '협력업체명', value: data.vendorName }, { label: '실사 사유', value: data.reason }, ]); const variables: Record = { 수신자이름: '결재자', 협력업체명: data.vendorName, '실사의뢰 요약 테이블 1': summaryTable, '실사의뢰 기본정보': basicInfo, '실사의뢰 요약 문구': `${data.vendorName}에 대한 실사를 요청합니다.`, }; // 2. 결재 워크플로우 시작 (템플릿 사용) const result = await withApproval( 'vendor_investigation_request', { vendorId: data.vendorId, vendorName: data.vendorName, reason: data.reason, scheduledDate: data.scheduledDate, }, { title: `실사 요청 - ${data.vendorName}`, description: `협력업체 ${data.vendorName}에 대한 실사 요청`, templateName: '협력업체 실사 요청', // 한국어 템플릿명 variables, // 치환할 변수들 approvers: data.approvers, currentUser: data.currentUser, } ); return result; } // ============================================================================ // 3단계: UI에서 호출 // ============================================================================ /** * 클라이언트 컴포넌트에서 사용 예시 * * ```tsx * const handleSubmit = async (formData) => { * try { * const result = await createInvestigationWithApproval({ * vendorId: formData.vendorId, * vendorName: formData.vendorName, * reason: formData.reason, * scheduledDate: new Date(formData.scheduledDate), * currentUser: session.user, * approvers: selectedApprovers, // 결재선 * }); * * // 결재 상신 완료 * alert(`결재가 상신되었습니다. 결재 ID: ${result.approvalId}`); * * // 결재 현황 페이지로 이동하거나 대기 상태 표시 * router.push(`/approval/status/${result.approvalId}`); * } catch (error) { * console.error('Failed to submit approval:', error); * } * }; * ``` */ // ============================================================================ // 다른 액션 타입 예시 // ============================================================================ /** * 발주 요청 핸들러 */ async function createPurchaseOrderInternal(payload: { vendorId: number; items: Array<{ itemId: number; quantity: number }>; totalAmount: number; }) { console.log('Creating purchase order:', payload); return { success: true, orderId: 456 }; } registerActionHandler('purchase_order_request', createPurchaseOrderInternal); /** * 계약 승인 핸들러 */ async function approveContractInternal(payload: { contractId: number; approverComments: string; }) { console.log('Approving contract:', payload); return { success: true, contractId: payload.contractId }; } registerActionHandler('contract_approval', approveContractInternal); // ============================================================================ // 추가 유틸리티 // ============================================================================ /** * 결재 상태를 수동으로 확인 (UI에서 "새로고침" 버튼용) */ export async function refreshApprovalStatus(apInfId: string) { 'use server'; const { checkSingleApprovalStatus } = await import('./approval-polling-service'); return await checkSingleApprovalStatus(apInfId); }