summaryrefslogtreecommitdiff
path: root/lib/approval/example-usage.ts
diff options
context:
space:
mode:
authorjoonhoekim <26rote@gmail.com>2025-10-23 18:13:41 +0900
committerjoonhoekim <26rote@gmail.com>2025-10-23 18:13:41 +0900
commit78c471eec35182959e0029ded18f144974ccaca2 (patch)
tree914cdf1c8f406ca3e2aa639b8bb774f7f4e87023 /lib/approval/example-usage.ts
parent0be8940580c4a4a4e098b649d198160f9b60420c (diff)
(김준회) 결재 템플릿 에디터 및 결재 워크플로 공통함수 작성, 실사의뢰 결재 연결 예시 작성
Diffstat (limited to 'lib/approval/example-usage.ts')
-rw-r--r--lib/approval/example-usage.ts187
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);
+}
+