summaryrefslogtreecommitdiff
path: root/app/api/(S-ERP)/(MDG)/IF_MDZ_EVCP_MODEL_MASTER/route.ts
diff options
context:
space:
mode:
Diffstat (limited to 'app/api/(S-ERP)/(MDG)/IF_MDZ_EVCP_MODEL_MASTER/route.ts')
-rw-r--r--app/api/(S-ERP)/(MDG)/IF_MDZ_EVCP_MODEL_MASTER/route.ts121
1 files changed, 52 insertions, 69 deletions
diff --git a/app/api/(S-ERP)/(MDG)/IF_MDZ_EVCP_MODEL_MASTER/route.ts b/app/api/(S-ERP)/(MDG)/IF_MDZ_EVCP_MODEL_MASTER/route.ts
index cb8de491..4e7cdf35 100644
--- a/app/api/(S-ERP)/(MDG)/IF_MDZ_EVCP_MODEL_MASTER/route.ts
+++ b/app/api/(S-ERP)/(MDG)/IF_MDZ_EVCP_MODEL_MASTER/route.ts
@@ -122,58 +122,68 @@ export async function POST(request: NextRequest) {
}
// XML 데이터를 DB 삽입 가능한 형태로 변환
+/**
+ * MODEL 마스터 데이터 변환 함수
+ *
+ * 데이터 처리 아키텍처:
+ * 1. 최상위 테이블 (MODEL_MASTER_MATL)
+ * - MATNR이 unique 필드로 충돌 시 upsert 처리
+ *
+ * 2. 하위 테이블들 (DESC, PLNT, UNIT, CLASSASGN, CHARASGN)
+ * - FK(MATNR)로 연결
+ * - 별도 필수 필드 없음 (스키마에서 notNull() 제거 예정)
+ * - 전체 데이터셋 기반 삭제 후 재삽입 처리
+ *
+ * XML 패턴:
+ * - MODEL 인터페이스는 XML에 MATNR이 이미 포함된 패턴
+ * - 하위 테이블에도 MATNR 필드가 있어서 XML 값 우선 사용됨
+ *
+ * @param matlData XML에서 파싱된 MODEL 데이터
+ * @returns 처리된 MODEL 데이터 구조
+ */
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
);
@@ -189,8 +199,19 @@ function transformMatlData(matlData: MatlXML[]): ProcessedMaterialData[] {
}
// 데이터베이스 저장 함수
+/**
+ * 처리된 MODEL 데이터를 데이터베이스에 저장
+ *
+ * 저장 전략:
+ * 1. 최상위 테이블: MATNR 기준 upsert (충돌 시 업데이트)
+ * 2. 하위 테이블들: FK(MATNR) 기준 전체 삭제 후 재삽입
+ * - 송신 XML이 전체 데이터셋을 포함하므로 부분 업데이트 불필요
+ * - 데이터 일관성과 단순성 확보
+ *
+ * @param processedMaterials 변환된 MODEL 데이터 배열
+ */
async function saveToDatabase(processedMaterials: ProcessedMaterialData[]) {
- console.log(`데이터베이스 저장 함수가 호출됨. ${processedMaterials.length}개의 자재 데이터 수신.`);
+ console.log(`데이터베이스 저장 시작: ${processedMaterials.length}개 모델 데이터`);
try {
await db.transaction(async (tx) => {
@@ -202,7 +223,7 @@ async function saveToDatabase(processedMaterials: ProcessedMaterialData[]) {
continue;
}
- // 1. MATL 테이블 Upsert (최상위 테이블)
+ // 1. MATL 테이블 Upsert (최상위 테이블 - unique 필드: MATNR)
await tx.insert(MODEL_MASTER_MATL)
.values(material)
.onConflictDoUpdate({
@@ -213,57 +234,19 @@ async function saveToDatabase(processedMaterials: ProcessedMaterialData[]) {
}
});
- // 2. 하위 테이블 데이터 처리 - FK 기준으로 전체 삭제 후 재삽입
+ // 2. 하위 테이블들 처리 - FK(MATNR) 기준 전체 삭제 후 재삽입
+ // 전체 데이터셋 기반 처리로 데이터 일관성 확보
await Promise.all([
- // DESC 테이블 처리
- replaceSubTableData(
- tx,
- MODEL_MASTER_MATL_DESC,
- descriptions,
- 'MATNR',
- material.MATNR
- ),
-
- // PLNT 테이블 처리
- replaceSubTableData(
- tx,
- MODEL_MASTER_MATL_PLNT,
- plants,
- 'MATNR',
- material.MATNR
- ),
-
- // UNIT 테이블 처리
- replaceSubTableData(
- tx,
- MODEL_MASTER_MATL_UNIT,
- units,
- 'MATNR',
- material.MATNR
- ),
-
- // CLASSASGN 테이블 처리
- replaceSubTableData(
- tx,
- MODEL_MASTER_MATL_CLASSASGN,
- classAssignments,
- 'MATNR',
- material.MATNR
- ),
-
- // CHARASGN 테이블 처리
- replaceSubTableData(
- tx,
- MODEL_MASTER_MATL_CHARASGN,
- characteristicAssignments,
- 'MATNR',
- material.MATNR
- )
+ replaceSubTableData(tx, MODEL_MASTER_MATL_DESC, descriptions, 'MATNR', material.MATNR),
+ replaceSubTableData(tx, MODEL_MASTER_MATL_PLNT, plants, 'MATNR', material.MATNR),
+ replaceSubTableData(tx, MODEL_MASTER_MATL_UNIT, units, 'MATNR', material.MATNR),
+ replaceSubTableData(tx, MODEL_MASTER_MATL_CLASSASGN, classAssignments, 'MATNR', material.MATNR),
+ replaceSubTableData(tx, MODEL_MASTER_MATL_CHARASGN, characteristicAssignments, 'MATNR', material.MATNR)
]);
}
});
- console.log(`${processedMaterials.length}개의 자재 데이터 처리 완료.`);
+ console.log(`데이터베이스 저장 완료: ${processedMaterials.length}개 모델`);
return true;
} catch (error) {
console.error('데이터베이스 저장 중 오류 발생:', error);