diff options
| author | joonhoekim <26rote@gmail.com> | 2025-10-23 18:13:41 +0900 |
|---|---|---|
| committer | joonhoekim <26rote@gmail.com> | 2025-10-23 18:13:41 +0900 |
| commit | 78c471eec35182959e0029ded18f144974ccaca2 (patch) | |
| tree | 914cdf1c8f406ca3e2aa639b8bb774f7f4e87023 /lib/approval/example-usage.ts | |
| parent | 0be8940580c4a4a4e098b649d198160f9b60420c (diff) | |
(김준회) 결재 템플릿 에디터 및 결재 워크플로 공통함수 작성, 실사의뢰 결재 연결 예시 작성
Diffstat (limited to 'lib/approval/example-usage.ts')
| -rw-r--r-- | lib/approval/example-usage.ts | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/lib/approval/example-usage.ts b/lib/approval/example-usage.ts new file mode 100644 index 00000000..357f3ef1 --- /dev/null +++ b/lib/approval/example-usage.ts @@ -0,0 +1,187 @@ +/** + * 결재 워크플로우 사용 예시 (템플릿 기반) + * + * 이 파일은 실제 사용 방법을 보여주는 예시입니다. + * 실제 구현 시 각 서버 액션에 적용하면 됩니다. + * + * 업데이트: 템플릿 및 변수 치환 지원 + */ + +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<string, string> = { + 수신자이름: '결재자', + 협력업체명: 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); +} + |
