import { debugLog, debugSuccess, debugError } from '@/lib/debug-utils'; import db from '@/db/db'; import { projects } from '@/db/schema/projects'; import { PROJECT_MASTER_CMCTB_PROJ_MAST } from '@/db/schema/MDG/mdg'; import { eq } from 'drizzle-orm'; // MDG 데이터 타입 정의 export type MDGProjectData = typeof PROJECT_MASTER_CMCTB_PROJ_MAST.$inferInsert; // 비즈니스 테이블 데이터 타입 정의 export type ProjectData = typeof projects.$inferInsert; /** * MDG 프로젝트 마스터 데이터를 비즈니스 테이블 projects에 매핑하여 저장 */ export async function mapAndSaveMDGProjectData( mdgProjects: MDGProjectData[] ): Promise<{ success: boolean; message: string; processedCount: number }> { try { debugLog('MDG 프로젝트 마스터 데이터 매핑 시작', { count: mdgProjects.length }); if (mdgProjects.length === 0) { return { success: true, message: '처리할 데이터가 없습니다', processedCount: 0 }; } const mappedProjects: ProjectData[] = []; let processedCount = 0; for (const mdgProject of mdgProjects) { try { // MDG 데이터를 projects 테이블 구조에 매핑 const mappedProject = mapMDGToProject(mdgProject); if (mappedProject) { mappedProjects.push(mappedProject); processedCount++; } } catch (error) { debugError('개별 프로젝트 매핑 중 오류', { project: mdgProject.PROJ_NO, error: error instanceof Error ? error.message : 'Unknown error' }); // 개별 오류는 로그만 남기고 계속 진행 continue; } } if (mappedProjects.length === 0) { return { success: false, message: '매핑된 프로젝트가 없습니다', processedCount: 0 }; } // 데이터베이스에 저장 await saveProjectsToDatabase(mappedProjects); debugSuccess('MDG 프로젝트 마스터 데이터 매핑 완료', { total: mdgProjects.length, processed: processedCount }); return { success: true, message: `${processedCount}개 프로젝트 매핑 및 저장 완료`, processedCount }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; debugError('MDG 프로젝트 마스터 데이터 매핑 중 오류 발생', { error: errorMessage }); return { success: false, message: `매핑 실패: ${errorMessage}`, processedCount: 0 }; } } /** * MDG 프로젝트 데이터를 비즈니스 테이블 projects 구조로 변환 * id: serial("id").primaryKey(), << 자동 code: varchar("code", { length: 50 }).notNull(), name: text("name").notNull(), type: varchar("type", { length: 20 }).default("ship").notNull(), pspid: char('pspid', { length: 24 }).unique(), // 프로젝트ID (ECC), TODO: 매핑 필요 createdAt: timestamp("created_at").defaultNow().notNull(), updatedAt: timestamp("updated_at").defaultNow().notNull(), */ function mapMDGToProject(mdgProject: MDGProjectData): ProjectData | null { try { // 필수 필드 검증 if (!mdgProject.PROJ_NO) { debugError('PROJ_NO가 없는 프로젝트 데이터', { project: mdgProject }); return null; } // 현재는 기본 구조만 제공 const mappedProject: ProjectData = { code: mdgProject.PROJ_NO || '', name: mdgProject.PROJ_DSC || '', type: checkProjectType(mdgProject.TYPE || ''), // 기본값, 필요시 매핑 로직 추가 // type 매핑 방법: TYPE 네임스페이스에서 null 값을 수신한 경우 조선(ship)이고, 그 외는 해양(plant)이다. // 수신할 수 있는 경우의 수는 H, T, H/T, null 인데, 필요시 hull / top 구분 처리하자. 현재는 조선/해양 구분만 필요하고, 기존 코드들도 plant 값인지 ship 값인지만 따지고 있다. // 의미상으로는 H = 해양 Hull, T = 해양 Top, H/T = 해양 Hull과 Top 둘 다 하는 프로젝트 인데, 일단은 조선/해양 구분만 ship/plant 값을 넣어주는 것으로 하자. // TODO: pspid를 구해야 하는데 mdg에서 안주는 것 같음. 나프로에게 문의함. pspid: mdgProject.PROJ_NO || null, // ECC 프로젝트 ID와 연결 // id, createdAt, updatedAt는 자동 생성 }; debugLog('프로젝트 매핑 완료', { original: mdgProject.PROJ_NO, mapped: mappedProject.code }); return mappedProject; } catch (error) { debugError('프로젝트 매핑 중 오류', { project: mdgProject.PROJ_NO, error: error instanceof Error ? error.message : 'Unknown error' }); return null; } } /** * 매핑된 프로젝트 데이터를 데이터베이스에 저장 */ async function saveProjectsToDatabase(mappedProjects: ProjectData[]): Promise { try { debugLog('프로젝트 데이터베이스 저장 시작', { count: mappedProjects.length }); await db.transaction(async (tx) => { // 기존 데이터와 중복 체크 및 UPSERT for (const project of mappedProjects) { if (project.pspid) { // pspid가 있는 경우 기존 데이터 확인 const existingProject = await tx .select({ id: projects.id }) .from(projects) .where(eq(projects.pspid, project.pspid)) .limit(1); if (existingProject.length > 0) { // 기존 데이터 업데이트 await tx .update(projects) .set({ code: project.code, name: project.name, type: project.type, updatedAt: new Date(), }) .where(eq(projects.pspid, project.pspid)); } else { // 새 데이터 삽입 await tx.insert(projects).values(project); } } else { // pspid가 없는 경우 새 데이터 삽입 await tx.insert(projects).values(project); } } }); debugSuccess('프로젝트 데이터베이스 저장 완료', { count: mappedProjects.length }); } catch (error) { debugError('프로젝트 데이터베이스 저장 중 오류', { error }); throw error; } } // === Utility Functions === function checkProjectType(type: string) { if (type == 'H' || type == 'T' || type == 'H/T') { return 'plant'; } else { return 'ship'; } }