summaryrefslogtreecommitdiff
path: root/lib/soap/mdg
diff options
context:
space:
mode:
Diffstat (limited to 'lib/soap/mdg')
-rw-r--r--lib/soap/mdg/mapper/project-mapper.ts169
-rw-r--r--lib/soap/mdg/send/vendor-master/action.ts2
-rw-r--r--lib/soap/mdg/send/vendor-master/csv-fields.ts12
3 files changed, 176 insertions, 7 deletions
diff --git a/lib/soap/mdg/mapper/project-mapper.ts b/lib/soap/mdg/mapper/project-mapper.ts
new file mode 100644
index 00000000..112dd4f5
--- /dev/null
+++ b/lib/soap/mdg/mapper/project-mapper.ts
@@ -0,0 +1,169 @@
+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 구조로 변환
+ * TODO: 실제 매핑 로직은 사용자가 추가할 예정
+ *
+ 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;
+ }
+
+ // TODO: 사용자가 실제 매핑 로직을 추가할 예정
+ // 현재는 기본 구조만 제공
+ const mappedProject: ProjectData = {
+ code: mdgProject.PROJ_NO || '',
+ name: mdgProject.PROJ_NM || mdgProject.PROJ_NO || '',
+ type: 'ship', // 기본값, 필요시 매핑 로직 추가
+ 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<void> {
+ 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;
+ }
+}
diff --git a/lib/soap/mdg/send/vendor-master/action.ts b/lib/soap/mdg/send/vendor-master/action.ts
index d35d7a76..a7b4d8a4 100644
--- a/lib/soap/mdg/send/vendor-master/action.ts
+++ b/lib/soap/mdg/send/vendor-master/action.ts
@@ -17,7 +17,7 @@ import {
VENDOR_MASTER_BP_HEADER_BP_VENGEN_BP_PORG_ZVPFN
} from "@/db/schema/MDG/mdg";
import { eq, sql, desc } from "drizzle-orm";
-import { withSoapLogging } from "../../../utils";
+import { withSoapLogging } from "@/lib/soap/utils";
import { XMLBuilder } from 'fast-xml-parser';
import { CSV_FIELDS } from './csv-fields';
diff --git a/lib/soap/mdg/send/vendor-master/csv-fields.ts b/lib/soap/mdg/send/vendor-master/csv-fields.ts
index 335bd905..8d5af41d 100644
--- a/lib/soap/mdg/send/vendor-master/csv-fields.ts
+++ b/lib/soap/mdg/send/vendor-master/csv-fields.ts
@@ -31,25 +31,25 @@ export const CSV_FIELDS: CsvField[] = [
{ table: 'SUPPLIER_MASTER', field: 'ZZVNDTYP', mandatory: false },
{ table: 'SUPPLIER_MASTER', field: 'ZZREQID', mandatory: true },
{ table: 'SUPPLIER_MASTER', field: 'ZZIND01', mandatory: false },
- { table: 'SUPPLIER_MASTER', field: 'ADDRNO', mandatory: true },
+ { table: 'SUPPLIER_MASTER', field: 'ADDRNO', mandatory: false },
{ table: 'SUPPLIER_MASTER', field: 'NATION', mandatory: false },
{ table: 'SUPPLIER_MASTER', field: 'COUNTRY', mandatory: true },
{ table: 'SUPPLIER_MASTER', field: 'LANGU', mandatory: false },
- { table: 'SUPPLIER_MASTER', field: 'POST_CODE1', mandatory: true },
- { table: 'SUPPLIER_MASTER', field: 'CITY1', mandatory: true },
+ { table: 'SUPPLIER_MASTER', field: 'POST_CODE1', mandatory: true }, // 우편번호 (postal_code)
+ { table: 'SUPPLIER_MASTER', field: 'CITY1', mandatory: true }, // 주소 (address)
{ table: 'SUPPLIER_MASTER', field: 'CITY2', mandatory: false },
{ table: 'SUPPLIER_MASTER', field: 'REGION', mandatory: false },
- { table: 'SUPPLIER_MASTER', field: 'STREET', mandatory: true },
+ { table: 'SUPPLIER_MASTER', field: 'STREET', mandatory: true }, // 상세주소 (address_detail)
{ table: 'SUPPLIER_MASTER', field: 'CONSNUMBER', mandatory: false },
{ table: 'SUPPLIER_MASTER', field: 'TEL_NUMBER', mandatory: false },
{ table: 'SUPPLIER_MASTER', field: 'TEL_EXTENS', mandatory: false },
- { table: 'SUPPLIER_MASTER', field: 'R3_USER', mandatory: true },
+ { table: 'SUPPLIER_MASTER', field: 'R3_USER', mandatory: true }, // 모바일여부 010 시작이면 1
{ table: 'SUPPLIER_MASTER', field: 'FAX_NUMBER', mandatory: false },
{ table: 'SUPPLIER_MASTER', field: 'FAX_EXTENS', mandatory: false },
{ table: 'SUPPLIER_MASTER', field: 'URI_ADDR', mandatory: false },
{ table: 'SUPPLIER_MASTER', field: 'SMTP_ADDR', mandatory: false },
{ table: 'SUPPLIER_MASTER', field: 'TAXTYPE', mandatory: true },
- { table: 'SUPPLIER_MASTER', field: 'TAXNUM', mandatory: false },
+ { table: 'SUPPLIER_MASTER', field: 'TAXNUM', mandatory: false }, // 한국이면 KR2
{ table: 'SUPPLIER_MASTER', field: 'BP_TX_TYP', mandatory: false },
{ table: 'SUPPLIER_MASTER', field: 'STCD3', mandatory: false },
{ table: 'SUPPLIER_MASTER', field: 'ZZIND03', mandatory: false }