summaryrefslogtreecommitdiff
path: root/lib/vendor-investigation/approval-actions.ts
diff options
context:
space:
mode:
Diffstat (limited to 'lib/vendor-investigation/approval-actions.ts')
-rw-r--r--lib/vendor-investigation/approval-actions.ts248
1 files changed, 248 insertions, 0 deletions
diff --git a/lib/vendor-investigation/approval-actions.ts b/lib/vendor-investigation/approval-actions.ts
new file mode 100644
index 00000000..a75b9b70
--- /dev/null
+++ b/lib/vendor-investigation/approval-actions.ts
@@ -0,0 +1,248 @@
+/**
+ * PQ 실사 관련 결재 서버 액션
+ *
+ * 사용자가 UI에서 호출하는 함수들
+ * withApproval()을 사용하여 결재 프로세스를 시작
+ */
+
+'use server';
+
+import { withApproval } from '@/lib/approval/approval-workflow';
+import { mapPQInvestigationToTemplateVariables } from './handlers';
+import { debugLog, debugError, debugSuccess } from '@/lib/debug-utils';
+
+/**
+ * 결재를 거쳐 PQ 실사 의뢰를 생성하는 서버 액션
+ *
+ * 사용법 (클라이언트 컴포넌트에서):
+ * ```typescript
+ * const result = await requestPQInvestigationWithApproval({
+ * pqSubmissionIds: [1, 2, 3],
+ * vendorNames: "협력사A, 협력사B",
+ * qmManagerId: 123,
+ * qmManagerName: "홍길동",
+ * forecastedAt: new Date('2025-11-01'),
+ * investigationAddress: "경기도 ...",
+ * investigationNotes: "...",
+ * currentUser: { id: 1, epId: 'EP001', email: 'user@example.com' },
+ * approvers: ['EP002', 'EP003']
+ * });
+ *
+ * if (result.status === 'pending_approval') {
+ * console.log('결재 ID:', result.approvalId);
+ * }
+ * ```
+ */
+export async function requestPQInvestigationWithApproval(data: {
+ pqSubmissionIds: number[];
+ vendorNames: string; // 여러 업체명 (쉼표로 구분)
+ qmManagerId: number;
+ qmManagerName: string;
+ qmManagerEmail?: string;
+ forecastedAt: Date;
+ investigationAddress: string;
+ investigationNotes?: string;
+ currentUser: { id: number; epId: string | null; email?: string };
+ approvers?: string[]; // Knox EP ID 배열 (결재선)
+}) {
+ debugLog('[PQInvestigationApproval] 실사 의뢰 결재 서버 액션 시작', {
+ pqCount: data.pqSubmissionIds.length,
+ vendorNames: data.vendorNames,
+ qmManagerId: data.qmManagerId,
+ qmManagerName: data.qmManagerName,
+ hasQmEmail: !!data.qmManagerEmail,
+ userId: data.currentUser.id,
+ hasEpId: !!data.currentUser.epId,
+ });
+
+ // 입력 검증
+ if (!data.currentUser.epId) {
+ debugError('[PQInvestigationApproval] Knox EP ID 없음');
+ throw new Error('Knox EP ID가 필요합니다');
+ }
+
+ if (data.pqSubmissionIds.length === 0) {
+ debugError('[PQInvestigationApproval] PQ 제출 ID 없음');
+ throw new Error('실사 의뢰할 PQ를 선택해주세요');
+ }
+
+ // 1. 템플릿 변수 매핑
+ debugLog('[PQInvestigationApproval] 템플릿 변수 매핑 시작');
+ const requestedAt = new Date();
+ const variables = await mapPQInvestigationToTemplateVariables({
+ vendorNames: data.vendorNames,
+ qmManagerName: data.qmManagerName,
+ qmManagerEmail: data.qmManagerEmail,
+ forecastedAt: data.forecastedAt,
+ investigationAddress: data.investigationAddress,
+ investigationNotes: data.investigationNotes,
+ requestedAt,
+ });
+ debugLog('[PQInvestigationApproval] 템플릿 변수 매핑 완료', {
+ variableKeys: Object.keys(variables),
+ });
+
+ // 2. 결재 워크플로우 시작 (템플릿 기반)
+ debugLog('[PQInvestigationApproval] withApproval 호출');
+ const result = await withApproval(
+ // actionType: 핸들러를 찾을 때 사용할 키
+ 'pq_investigation_request',
+
+ // actionPayload: 결재 승인 후 핸들러에 전달될 데이터
+ {
+ pqSubmissionIds: data.pqSubmissionIds,
+ qmManagerId: data.qmManagerId,
+ qmManagerName: data.qmManagerName,
+ forecastedAt: data.forecastedAt,
+ investigationAddress: data.investigationAddress,
+ investigationNotes: data.investigationNotes,
+ vendorNames: data.vendorNames,
+ },
+
+ // approvalConfig: 결재 상신 정보 (템플릿 포함)
+ {
+ title: `Vendor 실사의뢰 - ${data.vendorNames}`,
+ description: `${data.vendorNames}에 대한 실사 의뢰`,
+ templateName: 'Vendor 실사의뢰', // 한국어 템플릿명
+ variables, // 치환할 변수들
+ approvers: data.approvers,
+ currentUser: data.currentUser,
+ }
+ );
+
+ debugSuccess('[PQInvestigationApproval] 결재 워크플로우 완료', {
+ approvalId: result.approvalId,
+ pendingActionId: result.pendingActionId,
+ status: result.status,
+ });
+
+ return result;
+}
+
+/**
+ * 결재를 거쳐 PQ 실사 재의뢰를 처리하는 서버 액션
+ *
+ * 사용법 (클라이언트 컴포넌트에서):
+ * ```typescript
+ * const result = await reRequestPQInvestigationWithApproval({
+ * investigationIds: [1, 2, 3],
+ * vendorNames: "협력사A, 협력사B",
+ * currentUser: { id: 1, epId: 'EP001', email: 'user@example.com' },
+ * approvers: ['EP002', 'EP003'],
+ * reason: '재의뢰 사유...'
+ * });
+ *
+ * if (result.status === 'pending_approval') {
+ * console.log('결재 ID:', result.approvalId);
+ * }
+ * ```
+ */
+export async function reRequestPQInvestigationWithApproval(data: {
+ investigationIds: number[];
+ vendorNames: string; // 여러 업체명 (쉼표로 구분)
+ currentUser: { id: number; epId: string | null; email?: string };
+ approvers?: string[]; // Knox EP ID 배열 (결재선)
+ reason?: string; // 재의뢰 사유
+}) {
+ debugLog('[PQReRequestApproval] 실사 재의뢰 결재 서버 액션 시작', {
+ investigationCount: data.investigationIds.length,
+ vendorNames: data.vendorNames,
+ userId: data.currentUser.id,
+ hasEpId: !!data.currentUser.epId,
+ hasReason: !!data.reason,
+ });
+
+ // 입력 검증
+ if (!data.currentUser.epId) {
+ debugError('[PQReRequestApproval] Knox EP ID 없음');
+ throw new Error('Knox EP ID가 필요합니다');
+ }
+
+ if (data.investigationIds.length === 0) {
+ debugError('[PQReRequestApproval] 실사 ID 없음');
+ throw new Error('재의뢰할 실사를 선택해주세요');
+ }
+
+ // 1. 기존 실사 정보 조회 (첫 번째 실사 기준)
+ debugLog('[PQReRequestApproval] 기존 실사 정보 조회');
+ const { default: db } = await import('@/db/db');
+ const { vendorInvestigations, users } = await import('@/db/schema');
+ const { eq } = await import('drizzle-orm');
+
+ const results = await db
+ .select({
+ id: vendorInvestigations.id,
+ forecastedAt: vendorInvestigations.forecastedAt,
+ investigationAddress: vendorInvestigations.investigationAddress,
+ qmManagerId: vendorInvestigations.qmManagerId,
+ qmManagerName: users.name,
+ qmManagerEmail: users.email,
+ })
+ .from(vendorInvestigations)
+ .leftJoin(users, eq(vendorInvestigations.qmManagerId, users.id))
+ .where(eq(vendorInvestigations.id, data.investigationIds[0]))
+ .limit(1);
+
+ const existingInvestigation = results[0];
+
+ if (!existingInvestigation) {
+ debugError('[PQReRequestApproval] 기존 실사 정보를 찾을 수 없음');
+ throw new Error('기존 실사 정보를 찾을 수 없습니다.');
+ }
+
+ debugLog('[PQReRequestApproval] 기존 실사 정보 조회 완료', {
+ investigationId: existingInvestigation.id,
+ qmManagerName: existingInvestigation.qmManagerName,
+ forecastedAt: existingInvestigation.forecastedAt,
+ });
+
+ // 2. 템플릿 변수 매핑
+ debugLog('[PQReRequestApproval] 템플릿 변수 매핑 시작');
+ const reRequestedAt = new Date();
+ const { mapPQReRequestToTemplateVariables } = await import('./handlers');
+ const variables = await mapPQReRequestToTemplateVariables({
+ vendorNames: data.vendorNames,
+ investigationCount: data.investigationIds.length,
+ reRequestedAt,
+ reason: data.reason,
+ // 기존 실사 정보 전달
+ forecastedAt: existingInvestigation.forecastedAt || undefined,
+ investigationAddress: existingInvestigation.investigationAddress || undefined,
+ qmManagerName: existingInvestigation.qmManagerName || undefined,
+ qmManagerEmail: existingInvestigation.qmManagerEmail || undefined,
+ });
+ debugLog('[PQReRequestApproval] 템플릿 변수 매핑 완료', {
+ variableKeys: Object.keys(variables),
+ });
+
+ // 2. 결재 워크플로우 시작 (템플릿 기반)
+ debugLog('[PQReRequestApproval] withApproval 호출');
+ const result = await withApproval(
+ // actionType: 핸들러를 찾을 때 사용할 키
+ 'pq_investigation_rerequest',
+
+ // actionPayload: 결재 승인 후 핸들러에 전달될 데이터
+ {
+ investigationIds: data.investigationIds,
+ vendorNames: data.vendorNames,
+ },
+
+ // approvalConfig: 결재 상신 정보 (템플릿 포함)
+ {
+ title: `Vendor 실사 재의뢰 - ${data.vendorNames}`,
+ description: `${data.vendorNames}에 대한 실사 재의뢰`,
+ templateName: 'Vendor 실사 재의뢰', // 한국어 템플릿명
+ variables, // 치환할 변수들
+ approvers: data.approvers,
+ currentUser: data.currentUser,
+ }
+ );
+
+ debugSuccess('[PQReRequestApproval] 재의뢰 결재 워크플로우 완료', {
+ approvalId: result.approvalId,
+ pendingActionId: result.pendingActionId,
+ status: result.status,
+ });
+
+ return result;
+}