"use server" import db from '@/db/db'; import { ApprovalLine } from "./approval"; import { approvalLogs } from '@/db/schema/knox/approvals'; import { eq, and } from 'drizzle-orm'; // ========== 데이터베이스 서비스 함수들 ========== /** * 결재 상신 데이터를 데이터베이스에 저장 (upsert) * 상신, 상세조회 업데이트, 리스트조회 상태 업데이트 시 모두 사용 */ export async function saveApprovalToDatabase( apInfId: string, userId: string, epId: string, emailAddress: string, subject: string, content: string, aplns: ApprovalLine[], additionalData?: { contentsType?: string; urgYn?: string; importantYn?: string; docSecuType?: string; notifyOption?: string; docMngSaveCode?: string; sbmLang?: string; timeZone?: string; sbmDt?: string; status?: string; // 상태 업데이트를 위한 옵션 } ): Promise { try { const now = new Date(); const dataToUpsert = { apInfId, userId, epId, emailAddress, subject, content, contentsType: additionalData?.contentsType || 'HTML', status: additionalData?.status || '1', // 기본값: 진행중 urgYn: additionalData?.urgYn || 'N', importantYn: additionalData?.importantYn || 'N', docSecuType: additionalData?.docSecuType || 'PERSONAL', notifyOption: additionalData?.notifyOption || '0', docMngSaveCode: additionalData?.docMngSaveCode || '0', sbmLang: additionalData?.sbmLang || 'ko', timeZone: additionalData?.timeZone || 'GMT+9', sbmDt: additionalData?.sbmDt, aplns, isDeleted: false, updatedAt: now, }; await db.insert(approvalLogs) .values({ ...dataToUpsert, createdAt: now, }) .onConflictDoUpdate({ target: approvalLogs.apInfId, set: { ...dataToUpsert, // createdAt은 업데이트하지 않음 (최초 생성 시점 유지) } }); } catch (error) { console.error('결재 데이터 저장 실패:', error); throw new Error( '결재 데이터를 데이터베이스에 저장하는 중 오류가 발생했습니다.' ); } } /** * 결재 상태만 업데이트 (기존 레코드가 있는 경우에만) */ export async function updateApprovalStatus( apInfId: string, status: string ): Promise { try { await db .update(approvalLogs) .set({ status, updatedAt: new Date(), }) .where(eq(approvalLogs.apInfId, apInfId)); } catch (error) { console.error('결재 상태 업데이트 실패:', error); throw new Error('결재 상태를 업데이트하는 중 오류가 발생했습니다.'); } } /** * 결재 상태를 upsert로 업데이트 (상세정보 없이 상태만 알고 있는 경우) * Knox API에서 상태 조회 시 상세정보가 없을 때 사용 */ export async function upsertApprovalStatus( apInfId: string, status: string, fallbackData?: { userId?: string; epId?: string; emailAddress?: string; subject?: string; content?: string; } ): Promise { try { const now = new Date(); // 먼저 기존 레코드 조회 const existingRecord = await getApprovalFromDatabase(apInfId, true); if (existingRecord) { // 기존 레코드가 있으면 상태만 업데이트 await updateApprovalStatus(apInfId, status); } else if (fallbackData?.userId && fallbackData?.epId && fallbackData?.emailAddress) { // 기존 레코드가 없고 fallback 데이터가 있으면 새로 생성 await db.insert(approvalLogs).values({ apInfId, userId: fallbackData.userId, epId: fallbackData.epId, emailAddress: fallbackData.emailAddress, subject: fallbackData.subject || `결재 ${apInfId}`, content: fallbackData.content || `상태 동기화로 생성된 결재`, contentsType: 'TEXT', status, urgYn: 'N', importantYn: 'N', docSecuType: 'PERSONAL', notifyOption: '0', docMngSaveCode: '0', sbmLang: 'ko', timeZone: 'GMT+9', aplns: [], isDeleted: false, createdAt: now, updatedAt: now, }); } else { console.warn(`결재 상태 업데이트 건너뜀: ${apInfId} - 기존 레코드 없음, fallback 데이터 부족`); } } catch (error) { console.error('결재 상태 upsert 실패:', error); throw new Error('결재 상태를 upsert하는 중 오류가 발생했습니다.'); } } /** * 결재 상세 정보 조회 */ export async function getApprovalFromDatabase( apInfId: string, includeDeleted: boolean = false ): Promise { try { const whereCondition = includeDeleted ? eq(approvalLogs.apInfId, apInfId) : and(eq(approvalLogs.apInfId, apInfId), eq(approvalLogs.isDeleted, false)); const result = await db .select() .from(approvalLogs) .where(whereCondition) .limit(1); return result[0] || null; } catch (error) { console.error('결재 데이터 조회 실패:', error); throw new Error('결재 데이터를 조회하는 중 오류가 발생했습니다.'); } } /** * 사용자별 결재 목록 조회 */ export async function getApprovalsByUser( userId: string, limit: number = 50, offset: number = 0, includeDeleted: boolean = false ): Promise { try { const whereCondition = includeDeleted ? eq(approvalLogs.userId, userId) : and(eq(approvalLogs.userId, userId), eq(approvalLogs.isDeleted, false)); const result = await db .select() .from(approvalLogs) .where(whereCondition) .orderBy(approvalLogs.createdAt) .limit(limit) .offset(offset); return result; } catch (error) { console.error('사용자 결재 목록 조회 실패:', error); throw new Error('사용자 결재 목록을 조회하는 중 오류가 발생했습니다.'); } } /** * 결재 삭제 (상신 취소 시) - Soft Delete */ export async function deleteApprovalFromDatabase( apInfId: string ): Promise { try { await db .update(approvalLogs) .set({ isDeleted: true, updatedAt: new Date(), }) .where(eq(approvalLogs.apInfId, apInfId)); } catch (error) { console.error('결재 데이터 삭제 실패:', error); throw new Error('결재 데이터를 삭제하는 중 오류가 발생했습니다.'); } }