diff options
Diffstat (limited to 'app/api/(S-ERP)/(MDG)/IF_MDZ_EVCP_EQUP_MASTER/route.ts')
| -rw-r--r-- | app/api/(S-ERP)/(MDG)/IF_MDZ_EVCP_EQUP_MASTER/route.ts | 173 |
1 files changed, 79 insertions, 94 deletions
diff --git a/app/api/(S-ERP)/(MDG)/IF_MDZ_EVCP_EQUP_MASTER/route.ts b/app/api/(S-ERP)/(MDG)/IF_MDZ_EVCP_EQUP_MASTER/route.ts index 358e9c62..97c2e636 100644 --- a/app/api/(S-ERP)/(MDG)/IF_MDZ_EVCP_EQUP_MASTER/route.ts +++ b/app/api/(S-ERP)/(MDG)/IF_MDZ_EVCP_EQUP_MASTER/route.ts @@ -123,58 +123,68 @@ export async function POST(request: NextRequest) { } // XML 데이터를 DB 삽입 가능한 형태로 변환 +/** + * EQUP 마스터 데이터 변환 함수 + * + * 데이터 처리 아키텍처: + * 1. 최상위 테이블 (EQUP_MASTER_MATL) + * - MATNR이 unique 필드로 충돌 시 upsert 처리 + * + * 2. 하위 테이블들 (DESC, PLNT, UNIT, CLASSASGN, CHARASGN) + * - FK(MATNR)로 연결 + * - 별도 필수 필드 없음 (스키마에서 notNull() 제거 예정) + * - 전체 데이터셋 기반 삭제 후 재삽입 처리 + * + * XML 패턴: + * - EQUP 인터페이스는 XML에 MATNR이 이미 포함된 패턴 + * - 하위 테이블에도 MATNR 필드가 있어서 XML 값 우선 사용됨 + * + * @param matlData XML에서 파싱된 EQUP 데이터 + * @returns 처리된 EQUP 데이터 구조 + */ function transformMatlData(matlData: MatlXML[]): ProcessedMaterialData[] { if (!matlData || !Array.isArray(matlData)) { return []; } return matlData.map(matl => { - // 메인 Material 데이터 변환 (자동) + const matnrKey = matl.MATNR || ''; + const fkData = { MATNR: matnrKey }; + + // 1단계: MATL (루트 - unique 필드: MATNR) const material = convertXMLToDBData<MatlData>( - matl as Record<string, string | undefined>, - ['MATNR'] + matl as Record<string, string | undefined>, + fkData ); - // 필수 필드 보정 (MATNR이 빈 문자열이면 안됨) - if (!material.MATNR) { - material.MATNR = ''; - } - - // FK 데이터 준비 - const fkData = { MATNR: matl.MATNR || '' }; - - // Description 데이터 변환 (자동) + // 2단계: 하위 테이블들 (FK: MATNR) const descriptions = processNestedArray( matl.DESC, - (desc) => convertXMLToDBData<MatlDescData>(desc, ['MATNR'], fkData), + (desc) => convertXMLToDBData<MatlDescData>(desc as Record<string, string | undefined>, fkData), fkData ); - // Plant 데이터 변환 (자동) const plants = processNestedArray( matl.PLNT, - (plnt) => convertXMLToDBData<MatlPlntData>(plnt, ['MATNR'], fkData), + (plnt) => convertXMLToDBData<MatlPlntData>(plnt as Record<string, string | undefined>, fkData), fkData ); - // Unit 데이터 변환 (자동) const units = processNestedArray( matl.UNIT, - (unit) => convertXMLToDBData<MatlUnitData>(unit, ['MATNR'], fkData), + (unit) => convertXMLToDBData<MatlUnitData>(unit as Record<string, string | undefined>, fkData), fkData ); - // Class Assignment 데이터 변환 (자동) const classAssignments = processNestedArray( matl.CLASSASGN, - (cls) => convertXMLToDBData<MatlClassAsgnData>(cls, ['MATNR'], fkData), + (cls) => convertXMLToDBData<MatlClassAsgnData>(cls as Record<string, string | undefined>, fkData), fkData ); - // Characteristic Assignment 데이터 변환 (자동) const characteristicAssignments = processNestedArray( matl.CHARASGN, - (char) => convertXMLToDBData<MatlCharAsgnData>(char, ['MATNR'], fkData), + (char) => convertXMLToDBData<MatlCharAsgnData>(char as Record<string, string | undefined>, fkData), fkData ); @@ -190,82 +200,57 @@ function transformMatlData(matlData: MatlXML[]): ProcessedMaterialData[] { } // 데이터베이스 저장 함수 +/** + * 처리된 EQUP 데이터를 데이터베이스에 저장 + * + * 저장 전략: + * 1. 최상위 테이블: MATNR 기준 upsert (충돌 시 업데이트) + * 2. 하위 테이블들: FK(MATNR) 기준 전체 삭제 후 재삽입 + * - 송신 XML이 전체 데이터셋을 포함하므로 부분 업데이트 불필요 + * - 데이터 일관성과 단순성 확보 + * + * @param processedMaterials 변환된 EQUP 데이터 배열 + */ async function saveToDatabase(processedMaterials: ProcessedMaterialData[]) { - console.log(`Starting database save for ${processedMaterials.length} equipment materials`); + console.log(`데이터베이스 저장 시작: ${processedMaterials.length}개 장비 데이터`); - await db.transaction(async (tx) => { - for (const materialData of processedMaterials) { - const { material, descriptions, plants, units, classAssignments, characteristicAssignments } = materialData; - - if (!material.MATNR) { - console.warn('Skipping material without MATNR'); - continue; - } - - console.log(`Processing MATNR: ${material.MATNR}`); - - // 1. MATL 테이블 Upsert (최상위 테이블) - await tx.insert(EQUP_MASTER_MATL) - .values(material) - .onConflictDoUpdate({ - target: EQUP_MASTER_MATL.MATNR, - set: { - ...material, - updatedAt: new Date(), - } - }); - - // 2. 하위 테이블 데이터 처리 - FK 기준으로 전체 삭제 후 재삽입 (병렬 처리) - await Promise.all([ - // DESC 테이블 처리 - replaceSubTableData( - tx, - EQUP_MASTER_MATL_DESC, - descriptions, - 'MATNR', - material.MATNR - ), - - // PLNT 테이블 처리 - replaceSubTableData( - tx, - EQUP_MASTER_MATL_PLNT, - plants, - 'MATNR', - material.MATNR - ), - - // UNIT 테이블 처리 - replaceSubTableData( - tx, - EQUP_MASTER_MATL_UNIT, - units, - 'MATNR', - material.MATNR - ), - - // CLASSASGN 테이블 처리 - replaceSubTableData( - tx, - EQUP_MASTER_MATL_CLASSASGN, - classAssignments, - 'MATNR', - material.MATNR - ), + try { + await db.transaction(async (tx) => { + for (const materialData of processedMaterials) { + const { material, descriptions, plants, units, classAssignments, characteristicAssignments } = materialData; - // CHARASGN 테이블 처리 - replaceSubTableData( - tx, - EQUP_MASTER_MATL_CHARASGN, - characteristicAssignments, - 'MATNR', - material.MATNR - ) - ]); + if (!material.MATNR) { + console.warn('자재번호(MATNR)가 없는 항목 발견, 건너뜁니다.'); + continue; + } - console.log(`Successfully processed MATNR: ${material.MATNR}`); - } - }); + // 1. MATL 테이블 Upsert (최상위 테이블 - unique 필드: MATNR) + await tx.insert(EQUP_MASTER_MATL) + .values(material) + .onConflictDoUpdate({ + target: EQUP_MASTER_MATL.MATNR, + set: { + ...material, + updatedAt: new Date(), + } + }); - console.log(`Database save completed for ${processedMaterials.length} equipment materials`); + // 2. 하위 테이블들 처리 - FK(MATNR) 기준 전체 삭제 후 재삽입 + // 전체 데이터셋 기반 처리로 데이터 일관성 확보 + await Promise.all([ + replaceSubTableData(tx, EQUP_MASTER_MATL_DESC, descriptions, 'MATNR', material.MATNR), + replaceSubTableData(tx, EQUP_MASTER_MATL_PLNT, plants, 'MATNR', material.MATNR), + replaceSubTableData(tx, EQUP_MASTER_MATL_UNIT, units, 'MATNR', material.MATNR), + replaceSubTableData(tx, EQUP_MASTER_MATL_CLASSASGN, classAssignments, 'MATNR', material.MATNR), + replaceSubTableData(tx, EQUP_MASTER_MATL_CHARASGN, characteristicAssignments, 'MATNR', material.MATNR) + ]); + } + }); + + console.log(`데이터베이스 저장 완료: ${processedMaterials.length}개 장비`); + return true; + } catch (error) { + console.error('데이터베이스 저장 중 오류 발생:', error); + throw error; + } }
\ No newline at end of file |
