"use server"; import { sql } from "drizzle-orm"; import db from "@/db/db"; import { MATERIAL_MASTER_PART_MATL, MATERIAL_MASTER_PART_MATL_DESC, MATERIAL_GROUP_MASTER } from "@/db/schema/MDG/mdg"; export interface SyncResult { success: boolean; message: string; data?: { totalProcessed: number; newRecords: number; updatedRecords: number; skippedRecords: number; }; } /** * 기존 MDG 데이터로부터 MATERIAL_GROUP_MASTER 테이블을 동기화하는 함수 * * 로직: * 1. MATERIAL_MASTER_PART_MATL에서 MATKL(자재그룹코드)가 있는 레코드 조회 * 2. 각 MATKL에 대해 MATERIAL_MASTER_PART_MATL_DESC에서 SPRAS='E'인 MAKTX 찾기 * 3. MATERIAL_GROUP_MASTER에 UPSERT (MATKL 기준으로 중복 제거) */ export async function syncMaterialGroupMaster(): Promise { try { console.log("📊 자재그룹 마스터 동기화 시작..."); const result = await db.transaction(async (tx) => { // 1단계: 기존 MDG 테이블에서 MATKL별 영어 설명 조회 const materialGroupData = await tx .select({ MATKL: MATERIAL_MASTER_PART_MATL.MATKL, MAKTX: sql` ( SELECT ${MATERIAL_MASTER_PART_MATL_DESC.MAKTX} FROM ${MATERIAL_MASTER_PART_MATL_DESC} WHERE ${MATERIAL_MASTER_PART_MATL_DESC.MATNR} = ${MATERIAL_MASTER_PART_MATL.MATNR} AND ${MATERIAL_MASTER_PART_MATL_DESC.SPRAS} = 'E' AND ${MATERIAL_MASTER_PART_MATL_DESC.MAKTX} IS NOT NULL AND ${MATERIAL_MASTER_PART_MATL_DESC.MAKTX} != '' LIMIT 1 ) `.as("MAKTX") }) .from(MATERIAL_MASTER_PART_MATL) .where(sql` ${MATERIAL_MASTER_PART_MATL.MATKL} IS NOT NULL AND ${MATERIAL_MASTER_PART_MATL.MATKL} != '' `) .groupBy(MATERIAL_MASTER_PART_MATL.MATKL); // MATKL별 중복 제거 console.log(`🔍 발견된 고유 자재그룹코드: ${materialGroupData.length}개`); // 2단계: MAKTX가 있는 레코드만 필터링 const validData = materialGroupData.filter(item => item.MAKTX && item.MAKTX.trim() !== '' ); console.log(`✅ 유효한 자재그룹 데이터: ${validData.length}개`); if (validData.length === 0) { return { totalProcessed: 0, newRecords: 0, updatedRecords: 0, skippedRecords: materialGroupData.length }; } // 3단계: 기존 MATERIAL_GROUP_MASTER의 모든 MATKL 조회 const existingRecords = await tx .select({ MATKL: MATERIAL_GROUP_MASTER.MATKL }) .from(MATERIAL_GROUP_MASTER); const existingMatkls = new Set(existingRecords.map(r => r.MATKL)); // 4단계: 신규/업데이트 데이터 분류 const newRecords = validData.filter(item => !existingMatkls.has(item.MATKL)); const updateRecords = validData.filter(item => existingMatkls.has(item.MATKL)); let insertedCount = 0; let updatedCount = 0; // 5단계: 신규 레코드 삽입 (배치 처리) if (newRecords.length > 0) { await tx .insert(MATERIAL_GROUP_MASTER) .values( newRecords.map(item => ({ MATKL: item.MATKL, MAKTX: item.MAKTX })) ); insertedCount = newRecords.length; console.log(`➕ 신규 삽입: ${insertedCount}개`); } // 6단계: 기존 레코드 업데이트 (배치 처리) if (updateRecords.length > 0) { // PostgreSQL의 UPDATE ... FROM 구문 사용 await tx.execute(sql` UPDATE ${MATERIAL_GROUP_MASTER} SET ${MATERIAL_GROUP_MASTER.MAKTX} = temp_data.maktx, ${MATERIAL_GROUP_MASTER.updatedAt} = NOW() FROM ( VALUES ${sql.join( updateRecords.map(item => sql`(${item.MATKL}, ${item.MAKTX})` ), sql`, ` )} ) AS temp_data(matkl, maktx) WHERE ${MATERIAL_GROUP_MASTER.MATKL} = temp_data.matkl `); updatedCount = updateRecords.length; console.log(`🔄 업데이트: ${updatedCount}개`); } return { totalProcessed: validData.length, newRecords: insertedCount, updatedRecords: updatedCount, skippedRecords: materialGroupData.length - validData.length }; }); console.log("✅ 자재그룹 마스터 동기화 완료"); return { success: true, message: `동기화 완료: 신규 ${result.newRecords}개, 업데이트 ${result.updatedRecords}개, 건너뜀 ${result.skippedRecords}개`, data: result }; } catch (error) { console.error("❌ 자재그룹 마스터 동기화 오류:", error); return { success: false, message: `동기화 실패: ${error instanceof Error ? error.message : '알 수 없는 오류'}` }; } } /** * 동기화 상태 확인 함수 */ export async function getMaterialGroupSyncStatus(): Promise<{ success: boolean; data?: { totalMDGRecords: number; totalMasterRecords: number; lastSyncDate?: string; }; }> { try { const [mdgCount, masterCount] = await Promise.all([ // MDG에서 유효한 MATKL 개수 db .select({ count: sql`count(distinct ${MATERIAL_MASTER_PART_MATL.MATKL})` }) .from(MATERIAL_MASTER_PART_MATL) .where(sql` ${MATERIAL_MASTER_PART_MATL.MATKL} IS NOT NULL AND ${MATERIAL_MASTER_PART_MATL.MATKL} != '' `), // MATERIAL_GROUP_MASTER 개수 db .select({ count: sql`count(*)` }) .from(MATERIAL_GROUP_MASTER) ]); // 최근 업데이트 시간 조회 const lastUpdated = await db .select({ lastUpdate: sql`max(${MATERIAL_GROUP_MASTER.updatedAt})` }) .from(MATERIAL_GROUP_MASTER); return { success: true, data: { totalMDGRecords: mdgCount[0]?.count || 0, totalMasterRecords: masterCount[0]?.count || 0, lastSyncDate: lastUpdated[0]?.lastUpdate || undefined } }; } catch (error) { console.error("동기화 상태 확인 오류:", error); return { success: false }; } }