summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjoonhoekim <26rote@gmail.com>2025-06-05 01:49:13 +0000
committerjoonhoekim <26rote@gmail.com>2025-06-05 01:49:13 +0000
commitccd6515000e36b02a52c2f8cd26bcc553d5e7326 (patch)
tree62ccd3a27d3ddd1cbdebfcc29168a9e4a1060237
parent3ed13c5a2709b4410a09df56f1165d0e7dbfc29e (diff)
(김준회) 벤더 스키마를 MDG로부터 분리, Model Master 스키마 및 수신 route 추가
-rw-r--r--app/api/(S-ERP)/(MDG)/IF_MDZ_EVCP_MODEL_MASTER/route.ts927
-rw-r--r--db/schema/MDG/modelMaster.ts178
-rw-r--r--db/schema/index.ts5
-rw-r--r--db/schema/vendors.ts647
4 files changed, 1449 insertions, 308 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
new file mode 100644
index 00000000..6c73cf08
--- /dev/null
+++ b/app/api/(S-ERP)/(MDG)/IF_MDZ_EVCP_MODEL_MASTER/route.ts
@@ -0,0 +1,927 @@
+import { XMLParser } from "fast-xml-parser";
+import { readFileSync } from "fs";
+import { NextRequest, NextResponse } from "next/server";
+import { join } from "path";
+import db from "@/db/db";
+import { MATL, DESC, PLNT, UNIT, CLASSASGN, CHARASGN } from "@/db/schema/MDG/modelMaster";
+import { eq } from "drizzle-orm";
+
+// 요청 데이터 인터페이스 정의
+interface RequestData {
+ materials: Material[];
+}
+
+// 애플리케이션 내부 데이터 모델 (XML 필드와 1:1 매핑)
+interface Material {
+ matnr?: string; // Material Number
+ mbrsh?: string; // Industry Sector
+ mtart?: string; // Material Type
+ lvorm?: string; // Deletion flag
+ meins?: string; // Base Unit of Measure
+ matkl?: string; // Material Group
+ bismt?: string; // Old Material Number
+ spart?: string; // Division
+ prdha?: string; // Product Hierarchy
+ mstae?: string; // Cross-plant Material Status
+ mstde?: string; // Cross-distribution-chain Material Status
+ brgew?: string; // Gross Weight
+ gewei?: string; // Weight Unit
+ ntgew?: string; // Net Weight
+ volum?: string; // Volume
+ voleh?: string; // Volume Unit
+ groes?: string; // Size/dimensions
+ laeng?: string; // Length
+ breit?: string; // Width
+ hoehe?: string; // Height
+ meabm?: string; // Unit of Dimension
+ magrv?: string; // Material Group: Packaging Materials
+ vhart?: string; // Packaging Material Type
+ zzname?: string; // Material Name (Custom)
+ zzspec?: string; // Material Specification (Custom)
+ zzdesc?: string; // Material Description (Custom)
+ zzmmtyp?: string; // Material Type (Custom)
+ zzregdt?: string; // Registration Date (Custom)
+ zzregtm?: string; // Registration Time (Custom)
+ zzregus?: string; // Registration User (Custom)
+ zzappdt?: string; // Approval Date (Custom)
+ zzapptm?: string; // Approval Time (Custom)
+ zzappus?: string; // Approval User (Custom)
+ zzlamdt?: string; // Last Modified Date (Custom)
+ zzlamtm?: string; // Last Modified Time (Custom)
+ zzlamus?: string; // Last Modified User (Custom)
+ zzprflg?: string; // Process Flag (Custom)
+ zzdokar?: string; // Document Type (Custom)
+ zzdoknr?: string; // Document Number (Custom)
+ zzdoktl?: string; // Document Part (Custom)
+ zzdokvr?: string; // Document Version (Custom)
+ descriptions?: Description[];
+ plants?: Plant[];
+ units?: Unit[];
+ classAssignments?: ClassAssignment[];
+ characteristicAssignments?: CharacteristicAssignment[];
+}
+
+interface Description {
+ matnr?: string; // Material Number
+ spras?: string; // Language Key
+ maktx?: string; // Material Description
+}
+
+interface Plant {
+ matnr?: string; // Material Number
+ werks?: string; // Plant
+ lvorm?: string; // Deletion Flag
+ mmsta?: string; // Plant-specific Material Status
+ mmstd?: string; // Plant-specific Material Status Valid From
+ zzmtarp?: string; // Custom Field
+ zzregdt?: string; // Registration Date (Custom)
+ zzregtm?: string; // Registration Time (Custom)
+ zzregus?: string; // Registration User (Custom)
+ zzlamdt?: string; // Last Modified Date (Custom)
+ zzlamtm?: string; // Last Modified Time (Custom)
+ zzlamus?: string; // Last Modified User (Custom)
+ zzprflg?: string; // Process Flag (Custom)
+}
+
+interface Unit {
+ matnr?: string; // Material Number
+ meinh?: string; // Unit of Measure
+ umrez?: string; // Numerator for Conversion to Base UoM
+ umren?: string; // Denominator for Conversion to Base UoM
+ laeng?: string; // Length
+ breit?: string; // Width
+ hoehe?: string; // Height
+ meabm?: string; // Unit of Dimension
+ volum?: string; // Volume
+ voleh?: string; // Volume Unit
+ brgew?: string; // Gross Weight
+ gewei?: string; // Weight Unit
+}
+
+interface ClassAssignment {
+ matnr?: string; // Material Number
+ class?: string; // Class
+ klart?: string; // Class Type
+}
+
+interface CharacteristicAssignment {
+ matnr?: string; // Material Number
+ class?: string; // Class
+ klart?: string; // Class Type
+ atnam?: string; // Characteristic Name
+ atwrt?: string; // Characteristic Value
+ atflv?: string; // Value From
+ atawe?: string; // Value To
+ atflb?: string; // Description
+ ataw1?: string; // Additional Value
+ atbez?: string; // Characteristic Description
+ atwtb?: string; // Characteristic Value Description
+}
+
+// SOAP XML 데이터 구조 인터페이스
+// XML 기준 대문자 필드명 사용
+interface MatlXML {
+ MATNR?: string;
+ MBRSH?: string;
+ MTART?: string;
+ LVORM?: string;
+ MEINS?: string;
+ MATKL?: string;
+ BISMT?: string;
+ SPART?: string;
+ PRDHA?: string;
+ MSTAE?: string;
+ MSTDE?: string;
+ BRGEW?: string;
+ GEWEI?: string;
+ NTGEW?: string;
+ VOLUM?: string;
+ VOLEH?: string;
+ GROES?: string;
+ LAENG?: string;
+ BREIT?: string;
+ HOEHE?: string;
+ MEABM?: string;
+ MAGRV?: string;
+ VHART?: string;
+ ZZNAME?: string;
+ ZZSPEC?: string;
+ ZZDESC?: string;
+ ZZMMTYP?: string;
+ ZZREGDT?: string;
+ ZZREGTM?: string;
+ ZZREGUS?: string;
+ ZZAPPDT?: string;
+ ZZAPPTM?: string;
+ ZZAPPUS?: string;
+ ZZLAMDT?: string;
+ ZZLAMTM?: string;
+ ZZLAMUS?: string;
+ ZZPRFLG?: string;
+ ZZDOKAR?: string;
+ ZZDOKNR?: string;
+ ZZDOKTL?: string;
+ ZZDOKVR?: string;
+ DESC?: DescXML[];
+ PLNT?: PlntXML[];
+ UNIT?: UnitXML[];
+ CLASSASGN?: ClassAsgnXML[];
+ CHARASGN?: CharAsgnXML[];
+}
+
+interface DescXML {
+ MATNR?: string;
+ SPRAS?: string;
+ MAKTX?: string;
+}
+
+interface PlntXML {
+ MATNR?: string;
+ WERKS?: string;
+ LVORM?: string;
+ MMSTA?: string;
+ MMSTD?: string;
+ ZZMTARP?: string;
+ ZZREGDT?: string;
+ ZZREGTM?: string;
+ ZZREGUS?: string;
+ ZZLAMDT?: string;
+ ZZLAMTM?: string;
+ ZZLAMUS?: string;
+ ZZPRFLG?: string;
+}
+
+interface UnitXML {
+ MATNR?: string;
+ MEINH?: string;
+ UMREZ?: string;
+ UMREN?: string;
+ LAENG?: string;
+ BREIT?: string;
+ HOEHE?: string;
+ MEABM?: string;
+ VOLUM?: string;
+ VOLEH?: string;
+ BRGEW?: string;
+ GEWEI?: string;
+}
+
+interface ClassAsgnXML {
+ MATNR?: string;
+ CLASS?: string;
+ KLART?: string;
+}
+
+interface CharAsgnXML {
+ MATNR?: string;
+ CLASS?: string;
+ KLART?: string;
+ ATNAM?: string;
+ ATWRT?: string;
+ ATFLV?: string;
+ ATAWE?: string;
+ ATFLB?: string;
+ ATAW1?: string;
+ ATBEZ?: string;
+ ATWTB?: string;
+}
+
+// SOAP Body에 대한 데이터 타입 정의
+interface SoapBodyData {
+ [key: string]: unknown;
+ IF_MDZ_EVCP_MODEL_MASTERReq?: Record<string, unknown>;
+ 'tns:IF_MDZ_EVCP_MODEL_MASTERReq'?: Record<string, unknown>;
+ 'ns1:IF_MDZ_EVCP_MODEL_MASTERReq'?: Record<string, unknown>;
+ 'p0:IF_MDZ_EVCP_MODEL_MASTERReq'?: Record<string, unknown>;
+ MATL?: MatlXML[];
+}
+
+function serveWsdl() {
+ try {
+ const wsdlPath = join(process.cwd(), 'public', 'wsdl', 'IF_MDZ_EVCP_MODEL_MASTER.wsdl');
+ const wsdlContent = readFileSync(wsdlPath, 'utf-8');
+
+ return new NextResponse(wsdlContent, {
+ headers: {
+ 'Content-Type': 'text/xml; charset=utf-8',
+ },
+ });
+ } catch (error) {
+ console.error('Failed to read WSDL file:', error);
+ return new NextResponse('WSDL file not found', { status: 404 });
+ }
+}
+
+export async function GET(request: NextRequest) {
+ const url = new URL(request.url);
+ if (url.searchParams.has('wsdl')) {
+ return serveWsdl();
+ }
+
+ return new NextResponse('Method Not Allowed', { status: 405 });
+}
+
+// WSDL 기반의 SOAP 요청 (데이터 전송건) 처리하기 (HTTP)
+export async function POST(request: NextRequest) {
+ const url = new URL(request.url);
+ if (url.searchParams.has('wsdl')) {
+ return serveWsdl();
+ }
+
+ try {
+ // 요청 본문 (MDZ 데이터)를 가져오기
+ const body = await request.text();
+
+ // 요청 로깅
+ console.log('Request Body 일부:', body.substring(0, 200) + (body.length > 200 ? '...' : ''));
+
+ // XML 파서 설정하기
+ const parser = new XMLParser({
+ ignoreAttributes: false,
+ attributeNamePrefix: '@_',
+ parseAttributeValue: false, // 값 조작 방지
+ trimValues: true,
+ isArray: (name: string) => {
+ return ['MATL', 'DESC', 'PLNT', 'UNIT', 'CLASSASGN', 'CHARASGN'].includes(name);
+ },
+ parseTagValue: false, // 값 조작 방지
+ allowBooleanAttributes: true,
+ });
+
+ // XML 파싱하기
+ const parsedData = parser.parse(body);
+
+ // 디버깅용 - 최상위 구조 확인
+ console.log('XML root keys:', Object.keys(parsedData));
+
+ // 재할당 가능한 변수 선언
+ let requestData = null;
+
+ // 가능한 경로 확인
+ if (parsedData?.['soap:Envelope']?.['soap:Body']) {
+ const soapBody = parsedData['soap:Envelope']['soap:Body'];
+ requestData = extractRequestData(soapBody);
+ } else if (parsedData?.['SOAP:Envelope']?.['SOAP:Body']) {
+ const soapBody = parsedData['SOAP:Envelope']['SOAP:Body'];
+ requestData = extractRequestData(soapBody);
+ } else if (parsedData?.['Envelope']?.['Body']) {
+ const soapBody = parsedData['Envelope']['Body'];
+ requestData = extractRequestData(soapBody);
+ } else if (parsedData?.['soapenv:Envelope']?.['soapenv:Body']) {
+ const soapBody = parsedData['soapenv:Envelope']['soapenv:Body'];
+ requestData = extractRequestData(soapBody);
+ } else if (parsedData?.['IF_MDZ_EVCP_MODEL_MASTERReq']) {
+ requestData = parsedData['IF_MDZ_EVCP_MODEL_MASTERReq'];
+ console.log('Found direct IF_MDZ_EVCP_MODEL_MASTERReq data');
+ } else if (parsedData?.['ns1:IF_MDZ_EVCP_MODEL_MASTERReq']) {
+ requestData = parsedData['ns1:IF_MDZ_EVCP_MODEL_MASTERReq'];
+ console.log('Found direct ns1:IF_MDZ_EVCP_MODEL_MASTERReq data');
+ } else if (parsedData?.['p0:IF_MDZ_EVCP_MODEL_MASTERReq']) {
+ requestData = parsedData['p0:IF_MDZ_EVCP_MODEL_MASTERReq'];
+ console.log('Found direct p0:IF_MDZ_EVCP_MODEL_MASTERReq data');
+ } else {
+ // 루트 레벨에서 MATL을 직접 찾기
+ if (parsedData?.MATL) {
+ requestData = parsedData;
+ console.log('Found MATL data at root level');
+ } else {
+ // 다른 모든 키에 대해 확인
+ for (const key of Object.keys(parsedData)) {
+ const value = parsedData[key];
+ // 데이터 구조가 맞는지 확인 (MATL이 있는지)
+ if (value && value.MATL) {
+ requestData = value;
+ console.log(`Found data in root key: ${key}`);
+ break;
+ }
+
+ // 키 이름에 IF_MDZ_EVCP_MODEL_MASTERReq가 포함되어 있는지 확인
+ if (key.includes('IF_MDZ_EVCP_MODEL_MASTERReq')) {
+ requestData = value;
+ console.log(`Found data in root key with matching name: ${key}`);
+ break;
+ }
+ }
+ }
+ }
+
+ if (!requestData) {
+ console.error('Could not find valid request data in the received payload');
+ console.error('Received XML structure:', JSON.stringify(parsedData, null, 2));
+ throw new Error('Missing request data - could not find IF_MDZ_EVCP_MODEL_MASTERReq or MATL data');
+ }
+
+ // 데이터 유효성 검증
+ console.log('Validating request data structure:',
+ `MATL: ${requestData.MATL ? 'found' : 'not found'}`
+ );
+
+ // 샘플 데이터 로깅
+ if (requestData.MATL && Array.isArray(requestData.MATL) && requestData.MATL.length > 0) {
+ console.log('First MATL sample:', JSON.stringify(requestData.MATL[0], null, 2));
+ }
+
+ // 데이터 구조 정규화 - MDZ 데이터를 우리 애플리케이션 모델로 변환
+ const normalizedData: RequestData = {
+ materials: transformMatlData(requestData.MATL)
+ };
+
+ // 기본 유효성 검사 - 필수 필드 확인
+ for (const material of normalizedData.materials) {
+ if (!material.matnr) {
+ throw new Error('Missing required field: matnr in material');
+ }
+ }
+
+ // 데이터베이스 저장
+ await saveToDatabase(normalizedData);
+
+ console.log(`Processed ${normalizedData.materials.length} materials`);
+
+ // XML 응답 생성
+ const xmlResponse = `<?xml version="1.0" encoding="UTF-8"?>
+<soap:Envelope
+ xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
+ xmlns:tns="http://60.101.108.100/api/IF_MDZ_EVCP_MODEL_MASTER/">
+ <soap:Body>
+ </soap:Body>
+</soap:Envelope>`;
+
+ return new NextResponse(xmlResponse, {
+ headers: {
+ 'Content-Type': 'text/xml; charset=utf-8',
+ },
+ });
+ } catch (error: unknown) {
+ console.error('API Error:', error);
+
+ // XML 에러 응답
+ const errorResponse = `<?xml version="1.0" encoding="UTF-8"?>
+<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
+ <soap:Body>
+ <soap:Fault>
+ <faultcode>soap:Server</faultcode>
+ <faultstring>${error instanceof Error ? ('[from eVCP]: ' + error.message) : 'Unknown error'}</faultstring>
+ </soap:Fault>
+ </soap:Body>
+</soap:Envelope>`;
+
+ return new NextResponse(errorResponse, {
+ status: 500,
+ headers: {
+ 'Content-Type': 'text/xml; charset=utf-8',
+ },
+ });
+ }
+}
+
+// SOAP Body나 루트에서 요청 데이터 추출하는 헬퍼 함수
+function extractRequestData(data: SoapBodyData): Record<string, unknown> | null {
+ if (!data) return null;
+
+ if (data['IF_MDZ_EVCP_MODEL_MASTERReq']) {
+ return data['IF_MDZ_EVCP_MODEL_MASTERReq'] as Record<string, unknown>;
+ } else if (data['tns:IF_MDZ_EVCP_MODEL_MASTERReq']) {
+ return data['tns:IF_MDZ_EVCP_MODEL_MASTERReq'] as Record<string, unknown>;
+ } else if (data['ns1:IF_MDZ_EVCP_MODEL_MASTERReq']) {
+ return data['ns1:IF_MDZ_EVCP_MODEL_MASTERReq'] as Record<string, unknown>;
+ } else if (data['p0:IF_MDZ_EVCP_MODEL_MASTERReq']) {
+ return data['p0:IF_MDZ_EVCP_MODEL_MASTERReq'] as Record<string, unknown>;
+ }
+
+ // 다른 키 검색
+ for (const key of Object.keys(data)) {
+ if (key.includes('IF_MDZ_EVCP_MODEL_MASTERReq')) {
+ return data[key] as Record<string, unknown>;
+ }
+ }
+
+ // MATL이 직접 있는 경우
+ if (data.MATL && Array.isArray(data.MATL)) {
+ return data;
+ }
+
+ return null;
+}
+
+// XML MATL 데이터를 내부 Material 형식으로 변환하는 함수
+function transformMatlData(matlData: MatlXML[]): Material[] {
+ if (!matlData || !Array.isArray(matlData)) {
+ return [];
+ }
+
+ return matlData.map(matl => {
+ const material: Material = {
+ matnr: matl.MATNR,
+ mbrsh: matl.MBRSH,
+ mtart: matl.MTART,
+ lvorm: matl.LVORM,
+ meins: matl.MEINS,
+ matkl: matl.MATKL,
+ bismt: matl.BISMT,
+ spart: matl.SPART,
+ prdha: matl.PRDHA,
+ mstae: matl.MSTAE,
+ mstde: matl.MSTDE,
+ brgew: matl.BRGEW,
+ gewei: matl.GEWEI,
+ ntgew: matl.NTGEW,
+ volum: matl.VOLUM,
+ voleh: matl.VOLEH,
+ groes: matl.GROES,
+ laeng: matl.LAENG,
+ breit: matl.BREIT,
+ hoehe: matl.HOEHE,
+ meabm: matl.MEABM,
+ magrv: matl.MAGRV,
+ vhart: matl.VHART,
+ zzname: matl.ZZNAME,
+ zzspec: matl.ZZSPEC,
+ zzdesc: matl.ZZDESC,
+ zzmmtyp: matl.ZZMMTYP,
+ zzregdt: matl.ZZREGDT,
+ zzregtm: matl.ZZREGTM,
+ zzregus: matl.ZZREGUS,
+ zzappdt: matl.ZZAPPDT,
+ zzapptm: matl.ZZAPPTM,
+ zzappus: matl.ZZAPPUS,
+ zzlamdt: matl.ZZLAMDT,
+ zzlamtm: matl.ZZLAMTM,
+ zzlamus: matl.ZZLAMUS,
+ zzprflg: matl.ZZPRFLG,
+ zzdokar: matl.ZZDOKAR,
+ zzdoknr: matl.ZZDOKNR,
+ zzdoktl: matl.ZZDOKTL,
+ zzdokvr: matl.ZZDOKVR,
+ };
+
+ // DESC 항목 처리
+ if (matl.DESC && Array.isArray(matl.DESC)) {
+ material.descriptions = matl.DESC.map((desc: DescXML) => ({
+ matnr: desc.MATNR,
+ spras: desc.SPRAS,
+ maktx: desc.MAKTX
+ }));
+ }
+
+ // PLNT 항목 처리
+ if (matl.PLNT && Array.isArray(matl.PLNT)) {
+
+ material.plants = matl.PLNT.map((plnt: PlntXML) => ({
+ matnr: plnt.MATNR,
+ werks: plnt.WERKS,
+ lvorm: plnt.LVORM,
+ mmsta: plnt.MMSTA,
+ mmstd: plnt.MMSTD,
+ zzmtarp: plnt.ZZMTARP,
+ zzregdt: plnt.ZZREGDT,
+ zzregtm: plnt.ZZREGTM,
+ zzregus: plnt.ZZREGUS,
+ zzlamdt: plnt.ZZLAMDT,
+ zzlamtm: plnt.ZZLAMTM,
+ zzlamus: plnt.ZZLAMUS,
+ zzprflg: plnt.ZZPRFLG
+ }));
+ }
+
+ // UNIT 항목 처리
+ if (matl.UNIT && Array.isArray(matl.UNIT)) {
+ material.units = matl.UNIT.map((unit: UnitXML) => ({
+ matnr: unit.MATNR,
+ meinh: unit.MEINH,
+ umrez: unit.UMREZ,
+ umren: unit.UMREN,
+ laeng: unit.LAENG,
+ breit: unit.BREIT,
+ hoehe: unit.HOEHE,
+ meabm: unit.MEABM,
+ volum: unit.VOLUM,
+ voleh: unit.VOLEH,
+ brgew: unit.BRGEW,
+ gewei: unit.GEWEI
+ }));
+ }
+
+ // CLASSASGN 항목 처리
+ if (matl.CLASSASGN && Array.isArray(matl.CLASSASGN)) {
+ material.classAssignments = matl.CLASSASGN.map((cls: ClassAsgnXML) => ({
+ matnr: cls.MATNR,
+ class: cls.CLASS,
+ klart: cls.KLART
+ }));
+ }
+
+ // CHARASGN 항목 처리
+ if (matl.CHARASGN && Array.isArray(matl.CHARASGN)) {
+ material.characteristicAssignments = matl.CHARASGN.map((char: CharAsgnXML) => ({
+ matnr: char.MATNR,
+ class: char.CLASS,
+ klart: char.KLART,
+ atnam: char.ATNAM,
+ atwrt: char.ATWRT,
+ atflv: char.ATFLV,
+ atawe: char.ATAWE,
+ atflb: char.ATFLB,
+ ataw1: char.ATAW1,
+ atbez: char.ATBEZ,
+ atwtb: char.ATWTB
+ }));
+ }
+
+ return material;
+ });
+}
+
+// 데이터베이스 저장 함수
+async function saveToDatabase(data: RequestData) {
+ console.log(`데이터베이스 저장 함수가 호출됨. ${data.materials.length}개의 자재 데이터 수신.`);
+
+ try {
+ // 트랜잭션으로 모든 데이터 처리
+ await db.transaction(async (tx) => {
+ for (const material of data.materials) {
+ if (!material.matnr) {
+ console.warn('자재번호(MATNR)가 없는 항목 발견, 건너뜁니다.');
+ continue;
+ }
+
+ // 1. MATL 테이블 Upsert
+ await tx.insert(MATL)
+ .values({
+ MATNR: material.matnr,
+ MBRSH: material.mbrsh || null,
+ MTART: material.mtart || null,
+ LVORM: material.lvorm || null,
+ MEINS: material.meins || null,
+ MATKL: material.matkl || null,
+ BISMT: material.bismt || null,
+ SPART: material.spart || null,
+ PRDHA: material.prdha || null,
+ MSTAE: material.mstae || null,
+ MSTDE: material.mstde || null,
+ BRGEW: material.brgew || null,
+ GEWEI: material.gewei || null,
+ NTGEW: material.ntgew || null,
+ VOLUM: material.volum || null,
+ VOLEH: material.voleh || null,
+ GROES: material.groes || null,
+ LAENG: material.laeng || null,
+ BREIT: material.breit || null,
+ HOEHE: material.hoehe || null,
+ MEABM: material.meabm || null,
+ MAGRV: material.magrv || null,
+ VHART: material.vhart || null,
+ ZZNAME: material.zzname || null,
+ ZZSPEC: material.zzspec || null,
+ ZZDESC: material.zzdesc || null,
+ ZZMMTYP: material.zzmmtyp || null,
+ ZZREGDT: material.zzregdt || null,
+ ZZREGTM: material.zzregtm || null,
+ ZZREGUS: material.zzregus || null,
+ ZZAPPDT: material.zzappdt || null,
+ ZZAPPTM: material.zzapptm || null,
+ ZZAPPUS: material.zzappus || null,
+ ZZLAMDT: material.zzlamdt || null,
+ ZZLAMTM: material.zzlamtm || null,
+ ZZLAMUS: material.zzlamus || null,
+ ZZPRFLG: material.zzprflg || null,
+ ZZDOKAR: material.zzdokar || null,
+ ZZDOKNR: material.zzdoknr || null,
+ ZZDOKTL: material.zzdoktl || null,
+ ZZDOKVR: material.zzdokvr || null,
+ })
+ .onConflictDoUpdate({
+ target: MATL.MATNR,
+ set: {
+ MBRSH: material.mbrsh || null,
+ MTART: material.mtart || null,
+ LVORM: material.lvorm || null,
+ MEINS: material.meins || null,
+ MATKL: material.matkl || null,
+ BISMT: material.bismt || null,
+ SPART: material.spart || null,
+ PRDHA: material.prdha || null,
+ MSTAE: material.mstae || null,
+ MSTDE: material.mstde || null,
+ BRGEW: material.brgew || null,
+ GEWEI: material.gewei || null,
+ NTGEW: material.ntgew || null,
+ VOLUM: material.volum || null,
+ VOLEH: material.voleh || null,
+ GROES: material.groes || null,
+ LAENG: material.laeng || null,
+ BREIT: material.breit || null,
+ HOEHE: material.hoehe || null,
+ MEABM: material.meabm || null,
+ MAGRV: material.magrv || null,
+ VHART: material.vhart || null,
+ ZZNAME: material.zzname || null,
+ ZZSPEC: material.zzspec || null,
+ ZZDESC: material.zzdesc || null,
+ ZZMMTYP: material.zzmmtyp || null,
+ ZZREGDT: material.zzregdt || null,
+ ZZREGTM: material.zzregtm || null,
+ ZZREGUS: material.zzregus || null,
+ ZZAPPDT: material.zzappdt || null,
+ ZZAPPTM: material.zzapptm || null,
+ ZZAPPUS: material.zzappus || null,
+ ZZLAMDT: material.zzlamdt || null,
+ ZZLAMTM: material.zzlamtm || null,
+ ZZLAMUS: material.zzlamus || null,
+ ZZPRFLG: material.zzprflg || null,
+ ZZDOKAR: material.zzdokar || null,
+ ZZDOKNR: material.zzdoknr || null,
+ ZZDOKTL: material.zzdoktl || null,
+ ZZDOKVR: material.zzdokvr || null,
+ updatedAt: new Date(),
+ }
+ });
+
+ // 2. 하위 테이블 데이터 처리 (Upsert)
+ // DESC 테이블 데이터 처리
+ if (material.descriptions && material.descriptions.length > 0) {
+ // 기존 데이터 조회 (해당 자재의 모든 설명)
+ const existingDescs = await tx.select().from(DESC)
+ .where(eq(DESC.MATNR, material.matnr));
+
+ // 설명 데이터 매핑
+ const existingDescsMap = new Map(
+ existingDescs.map(desc => [`${desc.MATNR}-${desc.SPRAS}`, desc])
+ );
+
+ for (const desc of material.descriptions) {
+ if (!desc.matnr && !material.matnr) continue; // 자재번호 필수
+
+ const matnr = desc.matnr || material.matnr;
+ const spras = desc.spras || '';
+ const key = `${matnr}-${spras}`;
+
+ if (existingDescsMap.has(key)) {
+ // 기존 데이터 업데이트
+ await tx.update(DESC)
+ .set({
+ MAKTX: desc.maktx || null,
+ updatedAt: new Date()
+ })
+ .where(eq(DESC.id, existingDescsMap.get(key)!.id));
+ } else {
+ // 신규 데이터 삽입
+ await tx.insert(DESC).values({
+ MATNR: matnr,
+ SPRAS: desc.spras || null,
+ MAKTX: desc.maktx || null,
+ });
+ }
+ }
+ }
+
+ // PLNT 테이블 데이터 처리
+ if (material.plants && material.plants.length > 0) {
+ // 기존 데이터 조회
+ const existingPlants = await tx.select().from(PLNT)
+ .where(eq(PLNT.MATNR, material.matnr));
+
+ // 플랜트 데이터 매핑
+ const existingPlantsMap = new Map(
+ existingPlants.map(plant => [`${plant.MATNR}-${plant.WERKS}`, plant])
+ );
+
+ for (const plant of material.plants) {
+ if (!plant.matnr && !material.matnr) continue; // 자재번호 필수
+ if (!plant.werks) continue; // 플랜트 코드 필수
+
+ const matnr = plant.matnr || material.matnr;
+ const werks = plant.werks;
+ const key = `${matnr}-${werks}`;
+
+ if (existingPlantsMap.has(key)) {
+ // 기존 데이터 업데이트
+ await tx.update(PLNT)
+ .set({
+ LVORM: plant.lvorm || null,
+ MMSTA: plant.mmsta || null,
+ MMSTD: plant.mmstd || null,
+ ZZMTARP: plant.zzmtarp || null,
+ ZZREGDT: plant.zzregdt || null,
+ ZZREGTM: plant.zzregtm || null,
+ ZZREGUS: plant.zzregus || null,
+ ZZLAMDT: plant.zzlamdt || null,
+ ZZLAMTM: plant.zzlamtm || null,
+ ZZLAMUS: plant.zzlamus || null,
+ ZZPRFLG: plant.zzprflg || null,
+ updatedAt: new Date()
+ })
+ .where(eq(PLNT.id, existingPlantsMap.get(key)!.id));
+ } else {
+ // 신규 데이터 삽입
+ await tx.insert(PLNT).values({
+ MATNR: matnr,
+ WERKS: werks,
+ LVORM: plant.lvorm || null,
+ MMSTA: plant.mmsta || null,
+ MMSTD: plant.mmstd || null,
+ ZZMTARP: plant.zzmtarp || null,
+ ZZREGDT: plant.zzregdt || null,
+ ZZREGTM: plant.zzregtm || null,
+ ZZREGUS: plant.zzregus || null,
+ ZZLAMDT: plant.zzlamdt || null,
+ ZZLAMTM: plant.zzlamtm || null,
+ ZZLAMUS: plant.zzlamus || null,
+ ZZPRFLG: plant.zzprflg || null,
+ });
+ }
+ }
+ }
+
+ // UNIT 테이블 데이터 처리
+ if (material.units && material.units.length > 0) {
+ // 기존 데이터 조회
+ const existingUnits = await tx.select().from(UNIT)
+ .where(eq(UNIT.MATNR, material.matnr));
+
+ // 단위 데이터 매핑
+ const existingUnitsMap = new Map(
+ existingUnits.map(unit => [`${unit.MATNR}-${unit.MEINH}`, unit])
+ );
+
+ for (const unit of material.units) {
+ if (!unit.matnr && !material.matnr) continue; // 자재번호 필수
+ if (!unit.meinh) continue; // 단위 코드 필수
+
+ const matnr = unit.matnr || material.matnr;
+ const meinh = unit.meinh;
+ const key = `${matnr}-${meinh}`;
+
+ if (existingUnitsMap.has(key)) {
+ // 기존 데이터 업데이트
+ await tx.update(UNIT)
+ .set({
+ UMREZ: unit.umrez || null,
+ UMREN: unit.umren || null,
+ LAENG: unit.laeng || null,
+ BREIT: unit.breit || null,
+ HOEHE: unit.hoehe || null,
+ MEABM: unit.meabm || null,
+ VOLUM: unit.volum || null,
+ VOLEH: unit.voleh || null,
+ BRGEW: unit.brgew || null,
+ GEWEI: unit.gewei || null,
+ updatedAt: new Date()
+ })
+ .where(eq(UNIT.id, existingUnitsMap.get(key)!.id));
+ } else {
+ // 신규 데이터 삽입
+ await tx.insert(UNIT).values({
+ MATNR: matnr,
+ MEINH: meinh,
+ UMREZ: unit.umrez || null,
+ UMREN: unit.umren || null,
+ LAENG: unit.laeng || null,
+ BREIT: unit.breit || null,
+ HOEHE: unit.hoehe || null,
+ MEABM: unit.meabm || null,
+ VOLUM: unit.volum || null,
+ VOLEH: unit.voleh || null,
+ BRGEW: unit.brgew || null,
+ GEWEI: unit.gewei || null,
+ });
+ }
+ }
+ }
+
+ // CLASSASGN 테이블 데이터 처리
+ if (material.classAssignments && material.classAssignments.length > 0) {
+ // 기존 데이터 조회
+ const existingClassAsgns = await tx.select().from(CLASSASGN)
+ .where(eq(CLASSASGN.MATNR, material.matnr));
+
+ // 클래스 할당 데이터 매핑
+ const existingClassAsgnsMap = new Map(
+ existingClassAsgns.map(cls => [`${cls.MATNR}-${cls.CLASS}-${cls.KLART}`, cls])
+ );
+
+ for (const cls of material.classAssignments) {
+ if (!cls.matnr && !material.matnr) continue; // 자재번호 필수
+ if (!cls.class || !cls.klart) continue; // 클래스 및 유형 필수
+
+ const matnr = cls.matnr || material.matnr;
+ const clsVal = cls.class;
+ const klart = cls.klart;
+ const key = `${matnr}-${clsVal}-${klart}`;
+
+ if (!existingClassAsgnsMap.has(key)) {
+ // 클래스 할당은 기본키 자체가 변경되는 경우가 드물어 신규 삽입만 처리
+ await tx.insert(CLASSASGN).values({
+ MATNR: matnr,
+ CLASS: clsVal,
+ KLART: klart,
+ });
+ }
+ }
+ }
+
+ // CHARASGN 테이블 데이터 처리
+ if (material.characteristicAssignments && material.characteristicAssignments.length > 0) {
+ // 기존 데이터 조회
+ const existingCharAsgns = await tx.select().from(CHARASGN)
+ .where(eq(CHARASGN.MATNR, material.matnr));
+
+ // 특성 할당 데이터 매핑
+ const existingCharAsgnsMap = new Map(
+ existingCharAsgns.map(char =>
+ [`${char.MATNR}-${char.CLASS}-${char.KLART}-${char.ATNAM}`, char]
+ )
+ );
+
+ for (const char of material.characteristicAssignments) {
+ if (!char.matnr && !material.matnr) continue; // 자재번호 필수
+ if (!char.class || !char.klart || !char.atnam) continue; // 클래스, 유형, 특성명 필수
+
+ const matnr = char.matnr || material.matnr;
+ const clsVal = char.class;
+ const klart = char.klart;
+ const atnam = char.atnam;
+ const key = `${matnr}-${clsVal}-${klart}-${atnam}`;
+
+ if (existingCharAsgnsMap.has(key)) {
+ // 기존 데이터 업데이트
+ await tx.update(CHARASGN)
+ .set({
+ ATWRT: char.atwrt || null,
+ ATFLV: char.atflv || null,
+ ATAWE: char.atawe || null,
+ ATFLB: char.atflb || null,
+ ATAW1: char.ataw1 || null,
+ ATBEZ: char.atbez || null,
+ ATWTB: char.atwtb || null,
+ updatedAt: new Date()
+ })
+ .where(eq(CHARASGN.id, existingCharAsgnsMap.get(key)!.id));
+ } else {
+ // 신규 데이터 삽입
+ await tx.insert(CHARASGN).values({
+ MATNR: matnr,
+ CLASS: clsVal,
+ KLART: klart,
+ ATNAM: atnam,
+ ATWRT: char.atwrt || null,
+ ATFLV: char.atflv || null,
+ ATAWE: char.atawe || null,
+ ATFLB: char.atflb || null,
+ ATAW1: char.ataw1 || null,
+ ATBEZ: char.atbez || null,
+ ATWTB: char.atwtb || null,
+ });
+ }
+ }
+ }
+ }
+ });
+
+ console.log(`${data.materials.length}개의 자재 데이터 처리 완료.`);
+ return true;
+ } catch (error) {
+ console.error('데이터베이스 저장 중 오류 발생:', error);
+ throw error;
+ }
+}
diff --git a/db/schema/MDG/modelMaster.ts b/db/schema/MDG/modelMaster.ts
new file mode 100644
index 00000000..360989f9
--- /dev/null
+++ b/db/schema/MDG/modelMaster.ts
@@ -0,0 +1,178 @@
+import { pgTable, serial, varchar, timestamp } from "drizzle-orm/pg-core";
+import { relations } from "drizzle-orm";
+
+/**
+ * 접근법 1: WSDL과 동일하게 DB 테이블/컬럼명 및 변수 이름 만들기
+ * - 모든 테이블/컬럼명이 SAP 시스템의 네이밍을 그대로 유지
+ * - 개발자가 SAP 시스템에 익숙하다면 이해하기 쉬움
+ * - SAP 문서와 비교하기 쉬움
+ */
+
+// 자재 마스터 테이블 (MATL)
+export const MATL = pgTable("MATL", {
+ id: serial("id").primaryKey(),
+ MATNR: varchar("MATNR", { length: 18 }).notNull().unique(), // Material Number (자재 번호) (PK)
+ MBRSH: varchar("MBRSH", { length: 1 }), // Industry Sector (산업 부문)
+ MTART: varchar("MTART", { length: 4 }), // Material Type (자재 유형)
+ LVORM: varchar("LVORM", { length: 1 }), // Deletion flag (삭제 플래그)
+ MEINS: varchar("MEINS", { length: 3 }), // Base Unit of Measure (기본 단위)
+ MATKL: varchar("MATKL", { length: 9 }), // Material Group (자재 그룹)
+ BISMT: varchar("BISMT", { length: 18 }), // Old material number (기존 자재 번호)
+ SPART: varchar("SPART", { length: 2 }), // Division (부문)
+ PRDHA: varchar("PRDHA", { length: 18 }), // Product hierachy (제품 계층)
+ MSTAE: varchar("MSTAE", { length: 2 }), // Material Status (자재 상태)
+ MSTDE: varchar("MSTDE", { length: 8 }), // Date from which the cross-plant material status is (자재 상태 유효 날짜)
+ BRGEW: varchar("BRGEW", { length: 13 }), // Gross weight (총 중량)
+ GEWEI: varchar("GEWEI", { length: 3 }), // Weight Unit (중량 단위)
+ NTGEW: varchar("NTGEW", { length: 13 }), // Net Weight (순 중량)
+ VOLUM: varchar("VOLUM", { length: 13 }), // Volume (체적)
+ VOLEH: varchar("VOLEH", { length: 3 }), // Volume Unit (체적 단위)
+ GROES: varchar("GROES", { length: 32 }), // Size/dimensions (크기/치수)
+ LAENG: varchar("LAENG", { length: 13 }), // Length (길이)
+ BREIT: varchar("BREIT", { length: 13 }), // Width (너비)
+ HOEHE: varchar("HOEHE", { length: 13 }), // Height (높이)
+ MEABM: varchar("MEABM", { length: 3 }), // Unit of Dimension for Length/Width/Height (치수 단위)
+ MAGRV: varchar("MAGRV", { length: 4 }), // Material Group: Packaging Materials (포장 자재 그룹)
+ VHART: varchar("VHART", { length: 4 }), // Packaging Material Type (포장 자재 유형)
+ ZZNAME: varchar("ZZNAME", { length: 40 }), // Material Name (자재 이름)
+ ZZSPEC: varchar("ZZSPEC", { length: 255 }), // Specification (자재 사양)
+ ZZDESC: varchar("ZZDESC", { length: 255 }), // Description (자재 설명)
+ ZZMMTYP: varchar("ZZMMTYP", { length: 1 }), // Material Master Type (자재 마스터 유형)
+ ZZREGDT: varchar("ZZREGDT", { length: 8 }), // Registered Date (등록 날짜)
+ ZZREGTM: varchar("ZZREGTM", { length: 6 }), // Registered Time (등록 시간)
+ ZZREGUS: varchar("ZZREGUS", { length: 12 }), // Registerd User (등록 사용자)
+ ZZAPPDT: varchar("ZZAPPDT", { length: 8 }), // Approval Date (승인 날짜)
+ ZZAPPTM: varchar("ZZAPPTM", { length: 6 }), // Approval Time (승인 시간)
+ ZZAPPUS: varchar("ZZAPPUS", { length: 12 }), // Approval User (승인 사용자)
+ ZZLAMDT: varchar("ZZLAMDT", { length: 8 }), // Last Modified Date (최종 수정 날짜)
+ ZZLAMTM: varchar("ZZLAMTM", { length: 6 }), // Last Modified Time (최종 수정 시간)
+ ZZLAMUS: varchar("ZZLAMUS", { length: 12 }), // Last Modified User (최종 수정 사용자)
+ ZZPRFLG: varchar("ZZPRFLG", { length: 1 }), // CRUD Status (처리 플래그)
+ ZZDOKAR: varchar("ZZDOKAR", { length: 3 }), // Document Type (문서 유형)
+ ZZDOKNR: varchar("ZZDOKNR", { length: 25 }), // Document Number (문서 번호)
+ ZZDOKTL: varchar("ZZDOKTL", { length: 3 }), // Document Part (문서 부분)
+ ZZDOKVR: varchar("ZZDOKVR", { length: 2 }), // Document Version (문서 버전)
+ createdAt: timestamp("created_at").defaultNow().notNull(),
+ updatedAt: timestamp("updated_at").defaultNow().notNull(),
+});
+
+// 자재 설명 테이블 (DESC)
+export const DESC = pgTable("DESC", {
+ id: serial("id").primaryKey(),
+ MATNR: varchar("MATNR", { length: 18 }).notNull(), // Material Number (자재 번호) (FK)
+ SPRAS: varchar("SPRAS", { length: 1 }), // Language (언어)
+ MAKTX: varchar("MAKTX", { length: 40 }), // Material Description (Short Text) (자재 설명)
+ createdAt: timestamp("created_at").defaultNow().notNull(),
+ updatedAt: timestamp("updated_at").defaultNow().notNull(),
+});
+
+// 플랜트별 자재 데이터 테이블 (PLNT)
+export const PLNT = pgTable("PLNT", {
+ id: serial("id").primaryKey(),
+ MATNR: varchar("MATNR", { length: 18 }).notNull(), // Material Number (자재 번호) (FK)
+ WERKS: varchar("WERKS", { length: 4 }), // Plant (플랜트)
+ LVORM: varchar("LVORM", { length: 1 }), // Deletion Flag (삭제 플래그)
+ MMSTA: varchar("MMSTA", { length: 2 }), // Plant-Specific Material Status (플랜트별 자재 상태)
+ MMSTD: varchar("MMSTD", { length: 8 }), // Date from which the plant-specific material status (플랜트별 자재 상태 유효 날짜)
+ ZZMTARP: varchar("ZZMTARP", { length: 4 }), // Plant Material Type (플랜트 자재 유형)
+ ZZREGDT: varchar("ZZREGDT", { length: 8 }), // Registered Dated (등록 날짜)
+ ZZREGTM: varchar("ZZREGTM", { length: 6 }), // Registered Time (등록 시간)
+ ZZREGUS: varchar("ZZREGUS", { length: 12 }), // Registered USER (등록 사용자)
+ ZZLAMDT: varchar("ZZLAMDT", { length: 8 }), // Last Modified Date (최종 수정 날짜)
+ ZZLAMTM: varchar("ZZLAMTM", { length: 6 }), // Last Modified Time (최종 수정 시간)
+ ZZLAMUS: varchar("ZZLAMUS", { length: 12 }), // Last Modified User (최종 수정 사용자)
+ ZZPRFLG: varchar("ZZPRFLG", { length: 1 }), // CRUD Status (처리 플래그)
+ createdAt: timestamp("created_at").defaultNow().notNull(),
+ updatedAt: timestamp("updated_at").defaultNow().notNull(),
+});
+
+// 단위 테이블 (UNIT)
+export const UNIT = pgTable("UNIT", {
+ id: serial("id").primaryKey(),
+ MATNR: varchar("MATNR", { length: 18 }).notNull(), // Material Number (자재 번호) (FK)
+ MEINH: varchar("MEINH", { length: 3 }), // Alternative Unit of Measure for Stockkeeping Unit (대체 단위)
+ UMREZ: varchar("UMREZ", { length: 5 }), // Numerator for Conversion to Base Units of Measure (기본 단위 변환 분자)
+ UMREN: varchar("UMREN", { length: 5 }), // Denominator for conversion to base units of measure (기본 단위 변환 분모)
+ LAENG: varchar("LAENG", { length: 13 }), // Length (길이)
+ BREIT: varchar("BREIT", { length: 13 }), // Width (너비)
+ HOEHE: varchar("HOEHE", { length: 13 }), // Height (높이)
+ MEABM: varchar("MEABM", { length: 3 }), // Unit of Dimension for Length/Width/Height (치수 단위)
+ VOLUM: varchar("VOLUM", { length: 13 }), // Volume (체적)
+ VOLEH: varchar("VOLEH", { length: 3 }), // Volume unit (체적 단위)
+ BRGEW: varchar("BRGEW", { length: 13 }), // Gross Weight (총 중량)
+ GEWEI: varchar("GEWEI", { length: 3 }), // Weight Unit (중량 단위)
+ createdAt: timestamp("created_at").defaultNow().notNull(),
+ updatedAt: timestamp("updated_at").defaultNow().notNull(),
+});
+
+// 클래스 할당 테이블 (CLASSASGN)
+export const CLASSASGN = pgTable("CLASSASGN", {
+ id: serial("id").primaryKey(),
+ MATNR: varchar("MATNR", { length: 18 }).notNull(), // Material Number (자재 번호) (FK)
+ CLASS: varchar("CLASS", { length: 18 }), // Class number (클래스 번호)
+ KLART: varchar("KLART", { length: 3 }), // Class Type (클래스 유형)
+ createdAt: timestamp("created_at").defaultNow().notNull(),
+ updatedAt: timestamp("updated_at").defaultNow().notNull(),
+});
+
+// 특성 할당 테이블 (CHARASGN)
+export const CHARASGN = pgTable("CHARASGN", {
+ id: serial("id").primaryKey(),
+ MATNR: varchar("MATNR", { length: 18 }).notNull(), // Material Number (자재 번호) (FK)
+ CLASS: varchar("CLASS", { length: 18 }), // Class number (클래스 번호)
+ KLART: varchar("KLART", { length: 3 }), // Class Type (클래스 유형)
+ ATNAM: varchar("ATNAM", { length: 30 }), // Characteristic Name (특성 이름)
+ ATWRT: varchar("ATWRT", { length: 30 }), // Characteristic Value (특성 값)
+ ATFLV: varchar("ATFLV", { length: 16 }), // Internal floating point from (내부 실수값 시작)
+ ATAWE: varchar("ATAWE", { length: 3 }), // Unit of Measurement (측정 단위)
+ ATFLB: varchar("ATFLB", { length: 16 }), // Internal floating point value to (내부 실수값 끝)
+ ATAW1: varchar("ATAW1", { length: 3 }), // Unit of Measurement (측정 단위)
+ ATBEZ: varchar("ATBEZ", { length: 30 }), // 특성내역 (특성 설명)
+ ATWTB: varchar("ATWTB", { length: 30 }), // 특성값내역 (특성 값 설명)
+ createdAt: timestamp("created_at").defaultNow().notNull(),
+ updatedAt: timestamp("updated_at").defaultNow().notNull(),
+});
+
+// 관계 정의
+export const MATLRelations = relations(MATL, ({ many }) => ({
+ descriptions: many(DESC),
+ plants: many(PLNT),
+ units: many(UNIT),
+ classAssignments: many(CLASSASGN),
+ characteristicAssignments: many(CHARASGN),
+}));
+
+export const DESCRelations = relations(DESC, ({ one }) => ({
+ material: one(MATL, {
+ fields: [DESC.MATNR],
+ references: [MATL.MATNR],
+ }),
+}));
+
+export const PLNTRelations = relations(PLNT, ({ one }) => ({
+ material: one(MATL, {
+ fields: [PLNT.MATNR],
+ references: [MATL.MATNR],
+ }),
+}));
+
+export const UNITRelations = relations(UNIT, ({ one }) => ({
+ material: one(MATL, {
+ fields: [UNIT.MATNR],
+ references: [MATL.MATNR],
+ }),
+}));
+
+export const CLASSASGNRelations = relations(CLASSASGN, ({ one }) => ({
+ material: one(MATL, {
+ fields: [CLASSASGN.MATNR],
+ references: [MATL.MATNR],
+ }),
+}));
+
+export const CHARASGNRelations = relations(CHARASGN, ({ one }) => ({
+ material: one(MATL, {
+ fields: [CHARASGN.MATNR],
+ references: [MATL.MATNR],
+ }),
+}));
diff --git a/db/schema/index.ts b/db/schema/index.ts
index 309af050..01e0514b 100644
--- a/db/schema/index.ts
+++ b/db/schema/index.ts
@@ -14,4 +14,7 @@ export * from './logs';
export * from './basicContractDocumnet';
export * from './procurementRFQ';
export * from './setting';
-export * from './techSales'; \ No newline at end of file
+export * from './techSales';
+
+// MDG SOAP 수신용
+export * from './MDG/modelMaster' \ No newline at end of file
diff --git a/db/schema/vendors.ts b/db/schema/vendors.ts
index 60b40f21..9b860746 100644
--- a/db/schema/vendors.ts
+++ b/db/schema/vendors.ts
@@ -3,7 +3,6 @@ import { pgTable, serial, varchar, text, timestamp, boolean, integer ,pgView} f
import { items, materials } from "./items";
import { sql, eq, relations } from "drizzle-orm";
import { users } from "./users";
-import { vendorPQSubmissions } from "./pq";
// vendorTypes 테이블 생성
@@ -20,6 +19,7 @@ export const vendorTypes = pgTable("vendor_types", {
export const vendors = pgTable("vendors", {
id: serial("id").primaryKey(),
vendorName: varchar("vendor_name", { length: 255 }).notNull(),
+ // 벤더 코드 유니크 아니어도 괜찮은지?
vendorCode: varchar("vendor_code", { length: 100 }),
taxId: varchar("tax_id", { length: 100 }).notNull(),
address: text("address"),
@@ -65,301 +65,10 @@ export const vendors = pgTable("vendors", {
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at").defaultNow().notNull(),
- // --- [시작] Oracle DB 추가 필드들 (CMCTB_VENDOR_GENERAL 기준) ---
- accountGroup: varchar("account_group", { length: 4 }), // ACNT_GRP - 계정그룹
- accountGroupType: varchar("account_group_type", { length: 2 }), // ACNT_GRP_TP - 계정그룹종류
- customerCode: varchar("customer_code", { length: 10 }), // CSTM_CD - 고객코드
- postingHoldIndicator: varchar("posting_hold_indicator", { length: 1 }), // PST_HOLD_ORDR - 전기보류지시자
- purchaseHoldIndicator: varchar("purchase_hold_indicator", { length: 1 }), // PUR_HOLD_ORDR - 구매보류지시자
- holdReason: varchar("hold_reason", { length: 200 }), // HOLD_CAUS - 보류사유
- deleteIndicator: varchar("delete_indicator", { length: 1 }), // DEL_ORDR - 삭제지시자
- companyId: varchar("company_id", { length: 6 }), // CO_ID - 법인ID
- businessType: varchar("business_type", { length: 90 }), // BIZTP - 사업유형
- industryType: varchar("industry_type", { length: 90 }), // BIZCON - 산업유형
- registrationDate: varchar("registration_date", { length: 8 }), // REG_DT - 등록일자
- registrationTime: varchar("registration_time", { length: 6 }), // REG_DTM - 등록시간
- registrarId: varchar("registrar_id", { length: 13 }), // REGR_ID - 등록자
- approvalDate: varchar("approval_date", { length: 8 }), // AGR_DT - 승인일자
- approvalTime: varchar("approval_time", { length: 6 }), // AGR_TM - 승인시간
- approverId: varchar("approver_id", { length: 13 }), // AGR_R_ID - 승인자ID
- changeDate: varchar("change_date", { length: 8 }), // CHG_DT - 변경일자
- changeTime: varchar("change_time", { length: 6 }), // CHG_TM - 변경시간
- changerId: varchar("changer_id", { length: 13 }), // CHGR_ID - 변경자ID
- nationCode: varchar("nation_code", { length: 3 }), // NTN_CD - 국가코드
- representativeTelNumber: varchar("representative_tel_number", { length: 30 }), // REP_TEL_NO - 대표전화번호
- representativeFaxNumber: varchar("representative_fax_number", { length: 31 }), // REP_FAX_NO - 대표FAX번호
- businessRegistrationNumber: varchar("business_registration_number", { length: 10 }), // BIZR_NO - 사업자번호
- corporateRegistrationNumberOracle: varchar("corporate_registration_number_oracle", { length: 18 }), // CO_REG_NO - 법인등록번호
- taxCode4: varchar("tax_code_4", { length: 54 }), // TX_CD_4 - 세금번호4
- companyEstablishmentDate: varchar("company_establishment_date", { length: 8 }), // CO_INST_DT - 설립일자
- vendorType: varchar("vendor_type", { length: 2 }), // VNDR_TP - 구매처유형
- globalTopCode: varchar("global_top_code", { length: 11 }), // GBL_TOP_CD - GLOBALTOP코드
- globalTopName: varchar("global_top_name", { length: 120 }), // GBL_TOP_NM - GLOBALTOP명
- domesticTopCode: varchar("domestic_top_code", { length: 11 }), // DMST_TOP_CD - 국내TOP코드
- domesticTopName: varchar("domestic_top_name", { length: 120 }), // DMST_TOP_NM - 국내TOP명
- businessUnitCode: varchar("business_unit_code", { length: 11 }), // BIZ_UOM_CD - 사업단위코드
- businessUnitName: varchar("business_unit_name", { length: 120 }), // BIZ_UOM_NM - 사업단위명
- dunsNumber: varchar("duns_number", { length: 11 }), // DNS_NO - DUNS번호
- interfaceDate: varchar("interface_date", { length: 8 }), // IF_DT - 인터페이스일자
- interfaceTime: varchar("interface_time", { length: 6 }), // IF_TM - 인터페이스시간
- interfaceStatus: varchar("interface_status", { length: 1 }), // IF_STAT - 인터페이스상태
- interfaceMessage: varchar("interface_message", { length: 100 }), // IF_MSG - 인터페이스메시지
- title: varchar("title", { length: 45 }), // TTL - 타이틀
- vatRegistrationNumber: varchar("vat_registration_number", { length: 20 }), // VAT_REG_NO - 부가세등록번호
- giroVendorIndicator: varchar("giro_vendor_indicator", { length: 1 }), // GIRO_VNDR_ORDR - 지로VENDOR지시자
- vendorName1: varchar("vendor_name_1", { length: 120 }), // VNDRNM_1 - Vendor명1
- vendorName2: varchar("vendor_name_2", { length: 120 }), // VNDRNM_2 - VENDOR명2
- vendorName3: varchar("vendor_name_3", { length: 120 }), // VNDRNM_3 - VENDOR명3
- vendorName4: varchar("vendor_name_4", { length: 120 }), // VNDRNM_4 - VENDOR명4
- vendorNameAbbreviation1: varchar("vendor_name_abbreviation_1", { length: 60 }), // VNDRNM_ABRV_1 - VENDOR명약어1
- vendorNameAbbreviation2: varchar("vendor_name_abbreviation_2", { length: 60 }), // VNDRNM_ABRV_2 - VENDOR명약어2
- potentialVendorCode: varchar("potential_vendor_code", { length: 10 }), // PTNT_VNDRCD - 잠재VENDOR코드
- address1: varchar("address_1", { length: 120 }), // ADR_1 - 주소1
- address2: varchar("address_2", { length: 512 }), // ADR_2 - 주소2
- qualityManagerName: varchar("quality_manager_name", { length: 60 }), // QLT_CHRGR_NM - 품질담당자명
- qualityManagerTelNumber: varchar("quality_manager_tel_number", { length: 30 }), // QLT_CHRGR_TELNO - 품질담당자전화번호
- qualityManagerEmail: varchar("quality_manager_email", { length: 241 }), // QLT_CHRGR_EMAIL - 품질담당자이메일
- subWorkplaceSequence: varchar("sub_workplace_sequence", { length: 16 }), // SB_WKA_SEQ - SUB작업장순서
- overlapCauseCode: varchar("overlap_cause_code", { length: 2 }), // OVLAP_CAUS_CD - 중복사유코드
- documentType: varchar("document_type", { length: 3 }), // DOC_TP - 문서유형
- documentNumber: varchar("document_number", { length: 25 }), // DOC_NO - 문서번호
- partialDocument: varchar("partial_document", { length: 3 }), // PTN_DOC - 부분문서
- documentVersion: varchar("document_version", { length: 2 }), // DOC_VER - 문서버전
- inboundFlag: varchar("inbound_flag", { length: 1 }), // INB_FLAG - 인바운드플래그
- deleteHoldIndicator: varchar("delete_hold_indicator", { length: 1 }), // DEL_HOLD_ORDR - 삭제보류지시자
- purchaseHoldDate: varchar("purchase_hold_date", { length: 8 }), // PUR_HOLD_DT - 구매보류일자
- postBox: varchar("post_box", { length: 30 }), // POBX - 사서함
- internationalLocationCheckNumber: integer("international_location_check_number"), // INTL_LCTN_CHK_NUM - 국제LOCATION점검숫자
- withholdingTaxGenderKey: varchar("withholding_tax_gender_key", { length: 1 }), // SRCETX_RP_SEX_KEY - 원천세의무자성별키
- vendorContractManager1: varchar("vendor_contract_manager_1", { length: 105 }), // VNDR_CNRT_CHRGR_1 - VENDOR계약담당자1
- vendorContractManager2: varchar("vendor_contract_manager_2", { length: 105 }), // VNDR_CNRT_CHRGR_2 - VENDOR계약담당자2
- representativeResidentNumber: varchar("representative_resident_number", { length: 13 }), // REPR_RESNO - 대표생년월일
- companyVolume: varchar("company_volume", { length: 1 }), // CO_VLM - 기업규모
- // --- [끝] Oracle DB 추가 필드들 (CMCTB_VENDOR_GENERAL 기준) ---
-});
-
-// ------- [시작] MDZ 인터페이스 목적 테이블 추가 -------------
-
-// 벤더 업무그룹 테이블 (CMCTB_VENDOR_GRP 대응)
-export const vendorBusinessGroups = pgTable("vendor_business_groups", {
- id: serial("id").primaryKey(),
- vendorId: integer("vendor_id").notNull().references(() => vendors.id),
- businessGroupCode: varchar("business_group_code", { length: 3 }).notNull(), // BIZ_GRP_CD - 업무그룹코드
- createdDate: varchar("created_date", { length: 8 }), // CRTE_DT - 생성일자
- createdTime: varchar("created_time", { length: 6 }), // CRTE_TM - 생성시간
- creatorId: varchar("creator_id", { length: 13 }), // CRTER_ID - 생성자ID
- changeDate: varchar("change_date", { length: 8 }), // CHG_DT - 변경일자
- changeTime: varchar("change_time", { length: 6 }), // CHG_TM - 변경시간
- changerId: varchar("changer_id", { length: 13 }), // CHGR_ID - 변경자ID
- createdAt: timestamp("created_at").defaultNow().notNull(),
- updatedAt: timestamp("updated_at").defaultNow().notNull(),
-});
-
-// 사내협력사 벤더 테이블 (CMCTB_VENDOR_INCO 대응)
-export const vendorInternalPartners = pgTable("vendor_internal_partners", {
- id: serial("id").primaryKey(),
- vendorId: integer("vendor_id").notNull().references(() => vendors.id),
- vendorName: varchar("vendor_name", { length: 120 }), // VNDRNM - VENDOR코명
- representativeName: varchar("representative_name", { length: 30 }), // REPR_NM - 대표자명
- partnerType: varchar("partner_type", { length: 1 }), // PRTNR_GB - 협력사구분
- internalPartnerCode: varchar("internal_partner_code", { length: 3 }), // INCO_PRTNR_CD - 사내협력사코드
- internalPartnerWorkplace1: varchar("internal_partner_workplace_1", { length: 1 }), // INCO_PRTNR_WKA_1 - 사내협력사작업장1
- internalPartnerWorkplace2: varchar("internal_partner_workplace_2", { length: 1 }), // INCO_PRTNR_WKA_2 - 사내협력사작업장2
- internalPartnerWorkplace3: varchar("internal_partner_workplace_3", { length: 1 }), // INCO_PRTNR_WKA_3 - 사내협력사작업장3
- jobTypeCode: varchar("job_type_code", { length: 2 }), // JBTYPE_CD - 직종코드
- jobTypeCode2: varchar("job_type_code_2", { length: 2 }), // JBTYPE_CD_2 - 직종코드2
- individualCorporateType: varchar("individual_corporate_type", { length: 2 }), // INDV_CO_GB - 개인법인구분
- internalFoundationYn: varchar("internal_foundation_yn", { length: 1 }), // INCO_FOND_YN - 사내창립유무
- dockNumber: varchar("dock_number", { length: 25 }), // DOCK_NO - 도크번호
- companyInputDate: varchar("company_input_date", { length: 8 }), // OCMP_INP_DT - 당사투입일자
- internalWithdrawalDate: varchar("internal_withdrawal_date", { length: 8 }), // INCO_DUSE_DT - 사내철수일자
- industrialInsurancePremiumRate: integer("industrial_insurance_premium_rate"), // INDST_INS_PMRAT - 산재보험요율
- contractPerformanceGuarantee: integer("contract_performance_guarantee"), // CNRT_PFRM_GRAMT - 계약이행보증금
- wageRate: integer("wage_rate"), // WGE_RAT - 임금율
- correspondingDepartmentCode1: varchar("corresponding_department_code_1", { length: 30 }), // CRSPD_DEPTCD_1 - 해당부서코드1
- correspondingDepartmentCode2: varchar("corresponding_department_code_2", { length: 30 }), // CRSPD_DEPTCD_2 - 해당부서코드2
- correspondingTeamBelonging: varchar("corresponding_team_belonging", { length: 100 }), // CRSPD_TEAM_BLNG - 해당팀소속
- internalPartnerItem1: varchar("internal_partner_item_1", { length: 120 }), // INCO_PRTNR_ITM_1 - 사내협력사종목1
- internalPartnerItem2: varchar("internal_partner_item_2", { length: 120 }), // INCO_PRTNR_ITM_2 - 사내협력사종목2
- officeLocation: varchar("office_location", { length: 240 }), // OFC_LOC - 사무실위치
- representativeCompanyCareer: varchar("representative_company_career", { length: 300 }), // REP_OCMP_CARR - 대표당사경력
- internalWithdrawalReason: varchar("internal_withdrawal_reason", { length: 600 }), // INCO_DUSE_CAUS - 사내철수사유
- telephoneNumber: varchar("telephone_number", { length: 30 }), // TEL_NO - 전화번호
- address1: varchar("address_1", { length: 200 }), // ADR1 - 주소
- address2: varchar("address_2", { length: 200 }), // ADR2 - 상세주소
- oldVendorCode: varchar("old_vendor_code", { length: 10 }), // OLD_VNDRCD - 이전 VENDOR코드
- treeNumber: varchar("tree_number", { length: 1 }), // TREE_NUM - 하위 VENDOR 갯수
- createdDate: varchar("created_date", { length: 8 }), // CRTE_DT - 생성일자
- createdTime: varchar("created_time", { length: 6 }), // CRTE_TM - 생성시간
- createdUserId: varchar("created_user_id", { length: 13 }), // CRTE_USR_ID - 생성사용자ID
- changeDate: varchar("change_date", { length: 8 }), // CHG_DT - 수정일자
- changeTime: varchar("change_time", { length: 6 }), // CHG_TM - 수정시간
- changeUserId: varchar("change_user_id", { length: 13 }), // CHG_USR_ID - 수정사용자ID
- upperJobType: varchar("upper_job_type", { length: 2 }), // UPR_JBTYPE - 직종단가
- supplierBusinessPlaceCode: varchar("supplier_business_place_code", { length: 4 }), // ZBYBP - 공급받는자 종사업장 식별코드
- remark: varchar("remark", { length: 4000 }), // RMK - 비고
- withdrawalPlanYn: varchar("withdrawal_plan_yn", { length: 1 }), // WDL_PLN_YN - 철수예정유무
- wageDelayOccurrence: varchar("wage_delay_occurrence", { length: 8 }), // WGE_DELY_DVL - 임금체불발생
- escrowYn: varchar("escrow_yn", { length: 1 }), // ESCROW_YN - 에스크로가입유무
- createdAt: timestamp("created_at").defaultNow().notNull(),
- updatedAt: timestamp("updated_at").defaultNow().notNull(),
+ // VENDOR_GENERAL 테이블은 별도 테이블로 분리함
});
-// 벤더 구매조직 테이블 (CMCTB_VENDOR_PORG 대응)
-export const vendorPurchaseOrganizations = pgTable("vendor_purchase_organizations", {
- id: serial("id").primaryKey(),
- vendorId: integer("vendor_id").notNull().references(() => vendors.id),
- purchaseOrgCode: varchar("purchase_org_code", { length: 4 }).notNull(), // PUR_ORG_CD - 구매조직
- purchaseOrderCurrency: varchar("purchase_order_currency", { length: 5 }), // PUR_ORD_CUR - 구매오더통화
- paymentTerms: varchar("payment_terms", { length: 4 }), // SPLY_COND - 지급조건
- deliveryTerms1: varchar("delivery_terms_1", { length: 3 }), // DL_COND_1 - 인도조건1
- deliveryTerms2: varchar("delivery_terms_2", { length: 90 }), // DL_COND_2 - 인도조건2
- calculationSchemaGroup: varchar("calculation_schema_group", { length: 2 }), // CALC_SHM_GRP - 계산스키마그룹
- grBasedInvoiceVerification: varchar("gr_based_invoice_verification", { length: 1 }), // GR_BSE_INVC_VR - GR기준송장검증
- automaticPurchaseOrderIndicator: varchar("automatic_purchase_order_indicator", { length: 1 }), // AT_PUR_ORD_ORDR - 자동구매오더지시자
- purchaseHoldIndicator: varchar("purchase_hold_indicator", { length: 1 }), // PUR_HOLD_ORDR - 구매보류지시자
- deleteIndicator: varchar("delete_indicator", { length: 1 }), // DEL_ORDR - 삭제지시자
- interfaceDate: varchar("interface_date", { length: 8 }), // IF_DT - 인터페이스일자
- interfaceTime: varchar("interface_time", { length: 6 }), // IF_TM - 인터페이스시간
- interfaceStatus: varchar("interface_status", { length: 1 }), // IF_STAT - 인터페이스상태
- interfaceMessage: varchar("interface_message", { length: 100 }), // IF_MSG - 인터페이스메시지
- orderConfirmationRequestIndicator: varchar("order_confirmation_request_indicator", { length: 1 }), // ORD_CNFM_REQ_ORDR - 오더확인요청지시자
- salesManagerName: varchar("sales_manager_name", { length: 120 }), // SALE_CHRGR_NM - 영업담당자명
- vendorTelephoneNumber: varchar("vendor_telephone_number", { length: 30 }), // VNDR_TELNO - VENDOR전화번호
- confirmationControlKey: varchar("confirmation_control_key", { length: 4 }), // CNFM_CTL_KEY - 확정제어키
- purchaseHoldDate: varchar("purchase_hold_date", { length: 8 }), // PUR_HOLD_DT - 구매보류일자
- purchaseHoldReason: varchar("purchase_hold_reason", { length: 120 }), // PUR_HOLD_CAUS - 구매보류사유
- createdAt: timestamp("created_at").defaultNow().notNull(),
- updatedAt: timestamp("updated_at").defaultNow().notNull(),
-});
-
-// 벤더 대표자 이메일 테이블 (CMCTB_VENDOR_REPREMAIL 대응)
-export const vendorRepresentativeEmails = pgTable("vendor_representative_emails", {
- id: serial("id").primaryKey(),
- vendorId: integer("vendor_id").notNull().references(() => vendors.id),
- addressNumber: varchar("address_number", { length: 10 }), // ADR_NO - 주소번호
- representativeSequence: varchar("representative_sequence", { length: 3 }).notNull(), // REPR_SER - 대표자순번
- validStartDate: varchar("valid_start_date", { length: 8 }).notNull(), // VLD_ST_DT - 유효시작일자
- emailAddress: varchar("email_address", { length: 241 }), // EMAIL_ADR - 이메일주소
- interfaceDate: varchar("interface_date", { length: 8 }), // IF_DT - 인터페이스일자
- interfaceTime: varchar("interface_time", { length: 6 }), // IF_TM - 인터페이스시간
- interfaceStatus: varchar("interface_status", { length: 1 }), // IF_STAT - 인터페이스상태
- interfaceMessage: varchar("interface_message", { length: 100 }), // IF_MSG - 인터페이스메시지
- createdAt: timestamp("created_at").defaultNow().notNull(),
- updatedAt: timestamp("updated_at").defaultNow().notNull(),
-});
-
-// 벤더 대표자 팩스 테이블 (CMCTB_VENDOR_REPRFAX 대응)
-export const vendorRepresentativeFaxes = pgTable("vendor_representative_faxes", {
- id: serial("id").primaryKey(),
- vendorId: integer("vendor_id").notNull().references(() => vendors.id),
- addressNumber: varchar("address_number", { length: 10 }), // ADR_NO - 주소번호
- representativeSequence: varchar("representative_sequence", { length: 3 }).notNull(), // REPR_SER - 대표자순번
- validStartDate: varchar("valid_start_date", { length: 8 }).notNull(), // VLD_ST_DT - 유효시작일자
- nationCode: varchar("nation_code", { length: 3 }), // NTN_CD - 국가코드
- faxNumber: varchar("fax_number", { length: 30 }), // FAXNO - 팩스번호
- faxExtensionNumber: varchar("fax_extension_number", { length: 10 }), // FAX_ETS_NO - 팩스내선번호
- interfaceDate: varchar("interface_date", { length: 8 }), // IF_DT - 인터페이스일자
- interfaceTime: varchar("interface_time", { length: 6 }), // IF_TM - 인터페이스시간
- interfaceStatus: varchar("interface_status", { length: 1 }), // IF_STAT - 인터페이스상태
- interfaceMessage: varchar("interface_message", { length: 100 }), // IF_MSG - 인터페이스메시지
- createdAt: timestamp("created_at").defaultNow().notNull(),
- updatedAt: timestamp("updated_at").defaultNow().notNull(),
-});
-
-// 벤더 대표자 전화번호 테이블 (CMCTB_VENDOR_REPRTEL 대응)
-export const vendorRepresentativeTelephones = pgTable("vendor_representative_telephones", {
- id: serial("id").primaryKey(),
- vendorId: integer("vendor_id").notNull().references(() => vendors.id),
- addressNumber: varchar("address_number", { length: 10 }), // ADR_NO - 주소번호
- representativeSequence: varchar("representative_sequence", { length: 3 }).notNull(), // REPR_SER - 대표자순번
- validStartDate: varchar("valid_start_date", { length: 8 }).notNull(), // VLD_ST_DT - 유효시작일자
- nationCode: varchar("nation_code", { length: 3 }), // NTN_CD - 국가코드
- telephoneNumber: varchar("telephone_number", { length: 30 }), // TELNO - 전화번호
- extensionNumber: varchar("extension_number", { length: 10 }), // ETX_NO - 내선번호
- mobileIndicator: varchar("mobile_indicator", { length: 1 }), // HP_ORDR - 핸드폰지시자
- interfaceDate: varchar("interface_date", { length: 8 }), // IF_DT - 인터페이스일자
- interfaceTime: varchar("interface_time", { length: 6 }), // IF_TM - 인터페이스시간
- interfaceStatus: varchar("interface_status", { length: 1 }), // IF_STAT - 인터페이스상태
- interfaceMessage: varchar("interface_message", { length: 100 }), // IF_MSG - 인터페이스메시지
- createdAt: timestamp("created_at").defaultNow().notNull(),
- updatedAt: timestamp("updated_at").defaultNow().notNull(),
-});
-
-// 벤더 대표자 URL 테이블 (CMCTB_VENDOR_REPRURL 대응)
-export const vendorRepresentativeUrls = pgTable("vendor_representative_urls", {
- id: serial("id").primaryKey(),
- vendorId: integer("vendor_id").notNull().references(() => vendors.id),
- addressNumber: varchar("address_number", { length: 10 }), // ADR_NO - 주소번호
- representativeSequence: varchar("representative_sequence", { length: 3 }).notNull(), // REPR_SER - 대표자순번
- validStartDate: varchar("valid_start_date", { length: 8 }).notNull(), // VLD_ST_DT - 유효시작일자
- url: varchar("url", { length: 2048 }), // URL - URL
- interfaceDate: varchar("interface_date", { length: 8 }), // IF_DT - 인터페이스일자
- interfaceTime: varchar("interface_time", { length: 6 }), // IF_TM - 인터페이스시간
- interfaceStatus: varchar("interface_status", { length: 1 }), // IF_STAT - 인터페이스상태
- interfaceMessage: varchar("interface_message", { length: 100 }), // IF_MSG - 인터페이스메시지
- createdAt: timestamp("created_at").defaultNow().notNull(),
- updatedAt: timestamp("updated_at").defaultNow().notNull(),
-});
-
-// 벤더 세금번호 테이블 (CMCTB_VENDOR_TAXNUM 대응)
-export const vendorTaxNumbers = pgTable("vendor_tax_numbers", {
- id: serial("id").primaryKey(),
- vendorId: integer("vendor_id").notNull().references(() => vendors.id),
- taxNumberCategory: varchar("tax_number_category", { length: 4 }).notNull(), // TX_NO_CTG - 세금번호범주
- businessPartnerTaxNumber: varchar("business_partner_tax_number", { length: 20 }), // BIZ_PTNR_TX_NO - 사업파트너세금번호
- interfaceDate: varchar("interface_date", { length: 8 }), // IF_DT - 인터페이스일자
- interfaceTime: varchar("interface_time", { length: 6 }), // IF_TM - 인터페이스시간
- interfaceStatus: varchar("interface_status", { length: 1 }), // IF_STAT - 인터페이스상태
- interfaceMessage: varchar("interface_message", { length: 100 }), // IF_MSG - 인터페이스메시지
- createdAt: timestamp("created_at").defaultNow().notNull(),
- updatedAt: timestamp("updated_at").defaultNow().notNull(),
-});
-
-// 벤더 파트너역할 테이블 (CMCTB_VENDOR_VFPN 대응)
-export const vendorPartnerFunctions = pgTable("vendor_partner_functions", {
- id: serial("id").primaryKey(),
- vendorId: integer("vendor_id").notNull().references(() => vendors.id),
- purchaseOrgCode: varchar("purchase_org_code", { length: 4 }).notNull(), // PUR_ORG_CD - 구매조직
- vendorSubNumber: varchar("vendor_sub_number", { length: 6 }).notNull(), // VNDR_SUB_NO - VENDOR서브번호
- plantCode: varchar("plant_code", { length: 4 }).notNull(), // PLNT_CD - 플랜트코드
- partnerFunction: varchar("partner_function", { length: 2 }).notNull(), // PTNR_SKL - 파트너기능
- partnerCounter: varchar("partner_counter", { length: 3 }).notNull(), // PTNR_CNT - 파트너카운터
- otherReferenceVendorCode: varchar("other_reference_vendor_code", { length: 10 }), // ETC_REF_VNDRCD - 기타참조VENDOR코드
- defaultPartnerIndicator: varchar("default_partner_indicator", { length: 1 }), // BSE_PTNR_ORDR - 기본파트너지시자
- interfaceDate: varchar("interface_date", { length: 8 }), // IF_DT - 인터페이스일자
- interfaceTime: varchar("interface_time", { length: 6 }), // IF_TM - 인터페이스시간
- interfaceStatus: varchar("interface_status", { length: 1 }), // IF_STAT - 인터페이스상태
- interfaceMessage: varchar("interface_message", { length: 100 }), // IF_MSG - 인터페이스메시지
- createdAt: timestamp("created_at").defaultNow().notNull(),
- updatedAt: timestamp("updated_at").defaultNow().notNull(),
-});
-
-// 벤더 원천세 테이블 (CMCTB_VENDOR_WHTHX 대응)
-export const vendorWithholdingTax = pgTable("vendor_withholding_tax", {
- id: serial("id").primaryKey(),
- vendorId: integer("vendor_id").notNull().references(() => vendors.id),
- companyCode: varchar("company_code", { length: 4 }).notNull(), // CO_CD - 회사코드
- withholdingTaxType: varchar("withholding_tax_type", { length: 2 }).notNull(), // SRCE_TX_TP - 원천세유형
- withholdingTaxRelatedIndicator: varchar("withholding_tax_related_indicator", { length: 1 }), // SRCE_TX_REL_ORDR - 원천세관련지시자
- recipientType: varchar("recipient_type", { length: 2 }), // RECIP_TP - 수취인유형
- withholdingTaxIdentificationNumber: varchar("withholding_tax_identification_number", { length: 16 }), // SRCE_TX_IDENT_NO - 원천세식별번호
- withholdingTaxCode: varchar("withholding_tax_code", { length: 2 }), // SRCE_TX_NO - 원천세코드
- exemptionCertificateNumber: varchar("exemption_certificate_number", { length: 15 }), // DCHAG_CERT_NO - 면제증명서번호
- exemptionRate: integer("exemption_rate"), // DCHAG_RAT - 면제율
- exemptionStartDate: varchar("exemption_start_date", { length: 8 }), // DCHAG_ST_DT - 면제시작일자
- exemptionEndDate: varchar("exemption_end_date", { length: 8 }), // DCHAG_ED_DT - 면제종료일
- exemptionReason: varchar("exemption_reason", { length: 200 }), // DCHAG_CAUS - 면제사유
- interfaceDate: varchar("interface_date", { length: 8 }), // IF_DT - 인터페이스일자
- interfaceTime: varchar("interface_time", { length: 6 }), // IF_TM - 인터페이스시간
- interfaceStatus: varchar("interface_status", { length: 1 }), // IF_STAT - 인터페이스상태
- interfaceMessage: varchar("interface_message", { length: 100 }), // IF_MSG - 인터페이스메시지
- createdAt: timestamp("created_at").defaultNow().notNull(),
- updatedAt: timestamp("updated_at").defaultNow().notNull(),
-});
-
-// ------- [끝] MDZ 인터페이스 목적 테이블 추가 -------------
-
+// eVCP 내 연락처로 오라클 측과는 무관...
export const vendorContacts = pgTable("vendor_contacts", {
id: serial("id").primaryKey(),
vendorId: integer("vendor_id").notNull().references(() => vendors.id),
@@ -466,19 +175,6 @@ export type VendorWithAttachments = Vendor & {
export type VendorItemsView = typeof vendorItemsView.$inferSelect
export type VendorMaterialsView = typeof vendorMaterialsView.$inferSelect
-// ------- [시작] MDG 대응을 위한 새로운 테이블 타입 정의 -------------
-export type VendorBusinessGroup = typeof vendorBusinessGroups.$inferSelect
-export type VendorInternalPartner = typeof vendorInternalPartners.$inferSelect
-export type VendorPurchaseOrganization = typeof vendorPurchaseOrganizations.$inferSelect
-export type VendorRepresentativeEmail = typeof vendorRepresentativeEmails.$inferSelect
-export type VendorRepresentativeFax = typeof vendorRepresentativeFaxes.$inferSelect
-export type VendorRepresentativeTelephone = typeof vendorRepresentativeTelephones.$inferSelect
-export type VendorRepresentativeUrl = typeof vendorRepresentativeUrls.$inferSelect
-export type VendorTaxNumber = typeof vendorTaxNumbers.$inferSelect
-export type VendorPartnerFunction = typeof vendorPartnerFunctions.$inferSelect
-export type VendorWithholdingTax = typeof vendorWithholdingTax.$inferSelect
-// ------- [끝] MDG 대응을 위한 새로운 테이블 타입 정의 -------------
-
export const vendorCandidates = pgTable("vendor_candidates", {
id: serial("id").primaryKey(),
@@ -745,3 +441,340 @@ export const vendorsWithTypesView = pgView("vendors_with_types").as((qb) => {
// You can also create interfaces for the view
export type VendorWithType = typeof vendorsWithTypesView.$inferSelect;
+
+
+// ------------------------------------------------------------------------------------------------
+
+// ------- [시작] MDG 인터페이스 목적 테이블 추가 (이미 인터페이스한 레거시 DB에서 직접 가져옴) -------------
+
+export const vendorMdgGenerals = pgTable("vendor_mdg_generals", {
+ id: serial("id").primaryKey(),
+ vendorCode: varchar("vendor_code", { length: 100 }),
+ accountGroup: varchar("account_group", { length: 4 }), // ACNT_GRP - 계정그룹
+ accountGroupType: varchar("account_group_type", { length: 2 }), // ACNT_GRP_TP - 계정그룹종류
+ customerCode: varchar("customer_code", { length: 10 }), // CSTM_CD - 고객코드
+ postingHoldIndicator: varchar("posting_hold_indicator", { length: 1 }), // PST_HOLD_ORDR - 전기보류지시자
+ purchaseHoldIndicator: varchar("purchase_hold_indicator", { length: 1 }), // PUR_HOLD_ORDR - 구매보류지시자
+ holdReason: varchar("hold_reason", { length: 200 }), // HOLD_CAUS - 보류사유
+ deleteIndicator: varchar("delete_indicator", { length: 1 }), // DEL_ORDR - 삭제지시자
+ companyId: varchar("company_id", { length: 6 }), // CO_ID - 법인ID
+ businessType: varchar("business_type", { length: 90 }), // BIZTP - 사업유형
+ industryType: varchar("industry_type", { length: 90 }), // BIZCON - 산업유형
+ registrationDate: varchar("registration_date", { length: 8 }), // REG_DT - 등록일자
+ registrationTime: varchar("registration_time", { length: 6 }), // REG_DTM - 등록시간
+ registrarId: varchar("registrar_id", { length: 13 }), // REGR_ID - 등록자
+ approvalDate: varchar("approval_date", { length: 8 }), // AGR_DT - 승인일자
+ approvalTime: varchar("approval_time", { length: 6 }), // AGR_TM - 승인시간
+ approverId: varchar("approver_id", { length: 13 }), // AGR_R_ID - 승인자ID
+ changeDate: varchar("change_date", { length: 8 }), // CHG_DT - 변경일자
+ changeTime: varchar("change_time", { length: 6 }), // CHG_TM - 변경시간
+ changerId: varchar("changer_id", { length: 13 }), // CHGR_ID - 변경자ID
+ nationCode: varchar("nation_code", { length: 3 }), // NTN_CD - 국가코드
+ representativeTelNumber: varchar("representative_tel_number", { length: 30 }), // REP_TEL_NO - 대표전화번호
+ representativeFaxNumber: varchar("representative_fax_number", { length: 31 }), // REP_FAX_NO - 대표FAX번호
+ businessRegistrationNumber: varchar("business_registration_number", { length: 10 }), // BIZR_NO - 사업자번호
+ corporateRegistrationNumberOracle: varchar("corporate_registration_number_oracle", { length: 18 }), // CO_REG_NO - 법인등록번호
+ taxCode4: varchar("tax_code_4", { length: 54 }), // TX_CD_4 - 세금번호4
+ companyEstablishmentDate: varchar("company_establishment_date", { length: 8 }), // CO_INST_DT - 설립일자
+ vendorType: varchar("vendor_type", { length: 2 }), // VNDR_TP - 구매처유형
+ globalTopCode: varchar("global_top_code", { length: 11 }), // GBL_TOP_CD - GLOBALTOP코드
+ globalTopName: varchar("global_top_name", { length: 120 }), // GBL_TOP_NM - GLOBALTOP명
+ domesticTopCode: varchar("domestic_top_code", { length: 11 }), // DMST_TOP_CD - 국내TOP코드
+ domesticTopName: varchar("domestic_top_name", { length: 120 }), // DMST_TOP_NM - 국내TOP명
+ businessUnitCode: varchar("business_unit_code", { length: 11 }), // BIZ_UOM_CD - 사업단위코드
+ businessUnitName: varchar("business_unit_name", { length: 120 }), // BIZ_UOM_NM - 사업단위명
+ dunsNumber: varchar("duns_number", { length: 11 }), // DNS_NO - DUNS번호
+ interfaceDate: varchar("interface_date", { length: 8 }), // IF_DT - 인터페이스일자
+ interfaceTime: varchar("interface_time", { length: 6 }), // IF_TM - 인터페이스시간
+ interfaceStatus: varchar("interface_status", { length: 1 }), // IF_STAT - 인터페이스상태
+ interfaceMessage: varchar("interface_message", { length: 100 }), // IF_MSG - 인터페이스메시지
+ title: varchar("title", { length: 45 }), // TTL - 타이틀
+ vatRegistrationNumber: varchar("vat_registration_number", { length: 20 }), // VAT_REG_NO - 부가세등록번호
+ giroVendorIndicator: varchar("giro_vendor_indicator", { length: 1 }), // GIRO_VNDR_ORDR - 지로VENDOR지시자
+ vendorName1: varchar("vendor_name_1", { length: 120 }), // VNDRNM_1 - Vendor명1
+ vendorName2: varchar("vendor_name_2", { length: 120 }), // VNDRNM_2 - VENDOR명2
+ vendorName3: varchar("vendor_name_3", { length: 120 }), // VNDRNM_3 - VENDOR명3
+ vendorName4: varchar("vendor_name_4", { length: 120 }), // VNDRNM_4 - VENDOR명4
+ vendorNameAbbreviation1: varchar("vendor_name_abbreviation_1", { length: 60 }), // VNDRNM_ABRV_1 - VENDOR명약어1
+ vendorNameAbbreviation2: varchar("vendor_name_abbreviation_2", { length: 60 }), // VNDRNM_ABRV_2 - VENDOR명약어2
+ potentialVendorCode: varchar("potential_vendor_code", { length: 10 }), // PTNT_VNDRCD - 잠재VENDOR코드
+ address1: varchar("address_1", { length: 120 }), // ADR_1 - 주소1
+ address2: varchar("address_2", { length: 512 }), // ADR_2 - 주소2
+ qualityManagerName: varchar("quality_manager_name", { length: 60 }), // QLT_CHRGR_NM - 품질담당자명
+ qualityManagerTelNumber: varchar("quality_manager_tel_number", { length: 30 }), // QLT_CHRGR_TELNO - 품질담당자전화번호
+ qualityManagerEmail: varchar("quality_manager_email", { length: 241 }), // QLT_CHRGR_EMAIL - 품질담당자이메일
+ subWorkplaceSequence: varchar("sub_workplace_sequence", { length: 16 }), // SB_WKA_SEQ - SUB작업장순서
+ overlapCauseCode: varchar("overlap_cause_code", { length: 2 }), // OVLAP_CAUS_CD - 중복사유코드
+ documentType: varchar("document_type", { length: 3 }), // DOC_TP - 문서유형
+ documentNumber: varchar("document_number", { length: 25 }), // DOC_NO - 문서번호
+ partialDocument: varchar("partial_document", { length: 3 }), // PTN_DOC - 부분문서
+ documentVersion: varchar("document_version", { length: 2 }), // DOC_VER - 문서버전
+ inboundFlag: varchar("inbound_flag", { length: 1 }), // INB_FLAG - 인바운드플래그
+ deleteHoldIndicator: varchar("delete_hold_indicator", { length: 1 }), // DEL_HOLD_ORDR - 삭제보류지시자
+ purchaseHoldDate: varchar("purchase_hold_date", { length: 8 }), // PUR_HOLD_DT - 구매보류일자
+ postBox: varchar("post_box", { length: 30 }), // POBX - 사서함
+ internationalLocationCheckNumber: integer("international_location_check_number"), // INTL_LCTN_CHK_NUM - 국제LOCATION점검숫자
+ withholdingTaxGenderKey: varchar("withholding_tax_gender_key", { length: 1 }), // SRCETX_RP_SEX_KEY - 원천세의무자성별키
+ vendorContractManager1: varchar("vendor_contract_manager_1", { length: 105 }), // VNDR_CNRT_CHRGR_1 - VENDOR계약담당자1
+ vendorContractManager2: varchar("vendor_contract_manager_2", { length: 105 }), // VNDR_CNRT_CHRGR_2 - VENDOR계약담당자2
+ representativeResidentNumber: varchar("representative_resident_number", { length: 13 }), // REPR_RESNO - 대표생년월일
+ companyVolume: varchar("company_volume", { length: 1 }), // CO_VLM - 기업규모
+})
+
+// 벤더 업무그룹 테이블 (CMCTB_VENDOR_GRP 대응)
+export const vendorBusinessGroups = pgTable("vendor_business_groups", {
+ id: serial("id").primaryKey(), // postgres 인공키
+ vendorCode: varchar("vendor_code", { length: 10 }).notNull().references(() => vendors.vendorCode), // VNDRCD - 벤더코드 (키) 이고, SAP에서는 VARCHAR10 이다.
+ businessGroupCode: varchar("business_group_code", { length: 3 }).notNull(), // BIZ_GRP_CD - 업무그룹코드
+ createdDate: varchar("created_date", { length: 8 }), // CRTE_DT - 생성일자
+ createdTime: varchar("created_time", { length: 6 }), // CRTE_TM - 생성시간
+ creatorId: varchar("creator_id", { length: 13 }), // CRTER_ID - 생성자ID
+ createdAt: timestamp("created_at").defaultNow().notNull(),
+ updatedAt: timestamp("updated_at").defaultNow().notNull(),
+});
+
+// 사내협력사 벤더 테이블 (CMCTB_VENDOR_INCO 대응)
+export const vendorInternalPartners = pgTable("vendor_internal_partners", {
+ id: serial("id").primaryKey(),
+ vendorCode: varchar("vendor_code", { length: 10 }).notNull().references(() => vendors.vendorCode), // VNDRCD - 벤더코드 (키) 이고, SAP에서는 VARCHAR10 이다.
+ vendorName: varchar("vendor_name", { length: 120 }), // VNDRNM - VENDOR코명
+ representativeName: varchar("representative_name", { length: 30 }), // REPR_NM - 대표자명
+ partnerType: varchar("partner_type", { length: 1 }), // PRTNR_GB - 협력사구분
+ internalPartnerCode: varchar("internal_partner_code", { length: 3 }), // INCO_PRTNR_CD - 사내협력사코드
+ internalPartnerWorkplace1: varchar("internal_partner_workplace_1", { length: 1 }), // INCO_PRTNR_WKA_1 - 사내협력사작업장1
+ internalPartnerWorkplace2: varchar("internal_partner_workplace_2", { length: 1 }), // INCO_PRTNR_WKA_2 - 사내협력사작업장2
+ internalPartnerWorkplace3: varchar("internal_partner_workplace_3", { length: 1 }), // INCO_PRTNR_WKA_3 - 사내협력사작업장3
+ jobTypeCode: varchar("job_type_code", { length: 2 }), // JBTYPE_CD - 직종코드
+ jobTypeCode2: varchar("job_type_code_2", { length: 2 }), // JBTYPE_CD_2 - 직종코드2
+ individualCorporateType: varchar("individual_corporate_type", { length: 2 }), // INDV_CO_GB - 개인법인구분
+ internalFoundationYn: varchar("internal_foundation_yn", { length: 1 }), // INCO_FOND_YN - 사내창립유무
+ dockNumber: varchar("dock_number", { length: 25 }), // DOCK_NO - 도크번호
+ companyInputDate: varchar("company_input_date", { length: 8 }), // OCMP_INP_DT - 당사투입일자
+ internalWithdrawalDate: varchar("internal_withdrawal_date", { length: 8 }), // INCO_DUSE_DT - 사내철수일자
+ industrialInsurancePremiumRate: integer("industrial_insurance_premium_rate"), // INDST_INS_PMRAT - 산재보험요율
+ contractPerformanceGuarantee: integer("contract_performance_guarantee"), // CNRT_PFRM_GRAMT - 계약이행보증금
+ wageRate: integer("wage_rate"), // WGE_RAT - 임금율
+ correspondingDepartmentCode1: varchar("corresponding_department_code_1", { length: 30 }), // CRSPD_DEPTCD_1 - 해당부서코드1
+ correspondingDepartmentCode2: varchar("corresponding_department_code_2", { length: 30 }), // CRSPD_DEPTCD_2 - 해당부서코드2
+ correspondingTeamBelonging: varchar("corresponding_team_belonging", { length: 100 }), // CRSPD_TEAM_BLNG - 해당팀소속
+ internalPartnerItem1: varchar("internal_partner_item_1", { length: 120 }), // INCO_PRTNR_ITM_1 - 사내협력사종목1
+ internalPartnerItem2: varchar("internal_partner_item_2", { length: 120 }), // INCO_PRTNR_ITM_2 - 사내협력사종목2
+ officeLocation: varchar("office_location", { length: 240 }), // OFC_LOC - 사무실위치
+ representativeCompanyCareer: varchar("representative_company_career", { length: 300 }), // REP_OCMP_CARR - 대표당사경력
+ internalWithdrawalReason: varchar("internal_withdrawal_reason", { length: 600 }), // INCO_DUSE_CAUS - 사내철수사유
+ telephoneNumber: varchar("telephone_number", { length: 30 }), // TEL_NO - 전화번호
+ address1: varchar("address_1", { length: 200 }), // ADR1 - 주소
+ address2: varchar("address_2", { length: 200 }), // ADR2 - 상세주소
+ oldVendorCode: varchar("old_vendor_code", { length: 10 }), // OLD_VNDRCD - 이전 VENDOR코드
+ treeNumber: varchar("tree_number", { length: 1 }), // TREE_NUM - 하위 VENDOR 갯수
+ createdDate: varchar("created_date", { length: 8 }), // CRTE_DT - 생성일자
+ createdTime: varchar("created_time", { length: 6 }), // CRTE_TM - 생성시간
+ createdUserId: varchar("created_user_id", { length: 13 }), // CRTE_USR_ID - 생성사용자ID
+ changeDate: varchar("change_date", { length: 8 }), // CHG_DT - 수정일자
+ changeTime: varchar("change_time", { length: 6 }), // CHG_TM - 수정시간
+ changeUserId: varchar("change_user_id", { length: 13 }), // CHG_USR_ID - 수정사용자ID
+ upperJobType: varchar("upper_job_type", { length: 2 }), // UPR_JBTYPE - 직종단가
+ supplierBusinessPlaceCode: varchar("supplier_business_place_code", { length: 4 }), // ZBYBP - 공급받는자 종사업장 식별코드
+ remark: varchar("remark", { length: 4000 }), // RMK - 비고
+ withdrawalPlanYn: varchar("withdrawal_plan_yn", { length: 1 }), // WDL_PLN_YN - 철수예정유무
+ wageDelayOccurrence: varchar("wage_delay_occurrence", { length: 8 }), // WGE_DELY_DVL - 임금체불발생
+ escrowYn: varchar("escrow_yn", { length: 1 }), // ESCROW_YN - 에스크로가입유무
+ createdAt: timestamp("created_at").defaultNow().notNull(),
+ updatedAt: timestamp("updated_at").defaultNow().notNull(),
+});
+
+// 벤더 구매조직 테이블 (CMCTB_VENDOR_PORG 대응)
+export const vendorPurchaseOrganizations = pgTable("vendor_purchase_organizations", {
+ id: serial("id").primaryKey(),
+ vendorCode: varchar("vendor_code", { length: 10 }).notNull().references(() => vendors.vendorCode), // VNDRCD - 벤더코드 (키) 이고, SAP에서는 VARCHAR10 이다.
+ purchaseOrgCode: varchar("purchase_org_code", { length: 4 }).notNull(), // PUR_ORG_CD - 구매조직
+ purchaseOrderCurrency: varchar("purchase_order_currency", { length: 5 }), // PUR_ORD_CUR - 구매오더통화
+ paymentTerms: varchar("payment_terms", { length: 4 }), // SPLY_COND - 지급조건
+ deliveryTerms1: varchar("delivery_terms_1", { length: 3 }), // DL_COND_1 - 인도조건1
+ deliveryTerms2: varchar("delivery_terms_2", { length: 90 }), // DL_COND_2 - 인도조건2
+ calculationSchemaGroup: varchar("calculation_schema_group", { length: 2 }), // CALC_SHM_GRP - 계산스키마그룹
+ grBasedInvoiceVerification: varchar("gr_based_invoice_verification", { length: 1 }), // GR_BSE_INVC_VR - GR기준송장검증
+ automaticPurchaseOrderIndicator: varchar("automatic_purchase_order_indicator", { length: 1 }), // AT_PUR_ORD_ORDR - 자동구매오더지시자
+ purchaseHoldIndicator: varchar("purchase_hold_indicator", { length: 1 }), // PUR_HOLD_ORDR - 구매보류지시자
+ deleteIndicator: varchar("delete_indicator", { length: 1 }), // DEL_ORDR - 삭제지시자
+ interfaceDate: varchar("interface_date", { length: 8 }), // IF_DT - 인터페이스일자
+ interfaceTime: varchar("interface_time", { length: 6 }), // IF_TM - 인터페이스시간
+ interfaceStatus: varchar("interface_status", { length: 1 }), // IF_STAT - 인터페이스상태
+ interfaceMessage: varchar("interface_message", { length: 100 }), // IF_MSG - 인터페이스메시지
+ orderConfirmationRequestIndicator: varchar("order_confirmation_request_indicator", { length: 1 }), // ORD_CNFM_REQ_ORDR - 오더확인요청지시자
+ salesManagerName: varchar("sales_manager_name", { length: 120 }), // SALE_CHRGR_NM - 영업담당자명
+ vendorTelephoneNumber: varchar("vendor_telephone_number", { length: 30 }), // VNDR_TELNO - VENDOR전화번호
+ confirmationControlKey: varchar("confirmation_control_key", { length: 4 }), // CNFM_CTL_KEY - 확정제어키
+ purchaseHoldDate: varchar("purchase_hold_date", { length: 8 }), // PUR_HOLD_DT - 구매보류일자
+ purchaseHoldReason: varchar("purchase_hold_reason", { length: 120 }), // PUR_HOLD_CAUS - 구매보류사유
+ createdAt: timestamp("created_at").defaultNow().notNull(),
+ updatedAt: timestamp("updated_at").defaultNow().notNull(),
+});
+
+// 벤더 대표자 이메일 테이블 (CMCTB_VENDOR_REPREMAIL 대응)
+export const vendorRepresentativeEmails = pgTable("vendor_representative_emails", {
+ id: serial("id").primaryKey(),
+ vendorCode: varchar("vendor_code", { length: 10 }).notNull().references(() => vendors.vendorCode), // VNDRCD - 벤더코드 (키) 이고, SAP에서는 VARCHAR10 이다.
+ addressNumber: varchar("address_number", { length: 10 }), // ADR_NO - 주소번호
+ representativeSequence: varchar("representative_sequence", { length: 3 }).notNull(), // REPR_SER - 대표자순번
+ validStartDate: varchar("valid_start_date", { length: 8 }).notNull(), // VLD_ST_DT - 유효시작일자
+ emailAddress: varchar("email_address", { length: 241 }), // EMAIL_ADR - 이메일주소
+ interfaceDate: varchar("interface_date", { length: 8 }), // IF_DT - 인터페이스일자
+ interfaceTime: varchar("interface_time", { length: 6 }), // IF_TM - 인터페이스시간
+ interfaceStatus: varchar("interface_status", { length: 1 }), // IF_STAT - 인터페이스상태
+ interfaceMessage: varchar("interface_message", { length: 100 }), // IF_MSG - 인터페이스메시지
+ createdAt: timestamp("created_at").defaultNow().notNull(),
+ updatedAt: timestamp("updated_at").defaultNow().notNull(),
+});
+
+// 벤더 대표자 팩스 테이블 (CMCTB_VENDOR_REPRFAX 대응)
+export const vendorRepresentativeFaxes = pgTable("vendor_representative_faxes", {
+ id: serial("id").primaryKey(),
+ vendorCode: varchar("vendor_code", { length: 10 }).notNull().references(() => vendors.vendorCode), // VNDRCD - 벤더코드 (키) 이고, SAP에서는 VARCHAR10 이다.
+ addressNumber: varchar("address_number", { length: 10 }), // ADR_NO - 주소번호
+ representativeSequence: varchar("representative_sequence", { length: 3 }).notNull(), // REPR_SER - 대표자순번
+ validStartDate: varchar("valid_start_date", { length: 8 }).notNull(), // VLD_ST_DT - 유효시작일자
+ nationCode: varchar("nation_code", { length: 3 }), // NTN_CD - 국가코드
+ faxNumber: varchar("fax_number", { length: 30 }), // FAXNO - 팩스번호
+ faxExtensionNumber: varchar("fax_extension_number", { length: 10 }), // FAX_ETS_NO - 팩스내선번호
+ interfaceDate: varchar("interface_date", { length: 8 }), // IF_DT - 인터페이스일자
+ interfaceTime: varchar("interface_time", { length: 6 }), // IF_TM - 인터페이스시간
+ interfaceStatus: varchar("interface_status", { length: 1 }), // IF_STAT - 인터페이스상태
+ interfaceMessage: varchar("interface_message", { length: 100 }), // IF_MSG - 인터페이스메시지
+ createdAt: timestamp("created_at").defaultNow().notNull(),
+ updatedAt: timestamp("updated_at").defaultNow().notNull(),
+});
+
+// 벤더 대표자 전화번호 테이블 (CMCTB_VENDOR_REPRTEL 대응)
+export const vendorRepresentativeTelephones = pgTable("vendor_representative_telephones", {
+ id: serial("id").primaryKey(),
+ vendorCode: varchar("vendor_code", { length: 10 }).notNull().references(() => vendors.vendorCode), // VNDRCD - 벤더코드 (키) 이고, SAP에서는 VARCHAR10 이다.
+ addressNumber: varchar("address_number", { length: 10 }), // ADR_NO - 주소번호
+ representativeSequence: varchar("representative_sequence", { length: 3 }).notNull(), // REPR_SER - 대표자순번
+ validStartDate: varchar("valid_start_date", { length: 8 }).notNull(), // VLD_ST_DT - 유효시작일자
+ nationCode: varchar("nation_code", { length: 3 }), // NTN_CD - 국가코드
+ telephoneNumber: varchar("telephone_number", { length: 30 }), // TELNO - 전화번호
+ extensionNumber: varchar("extension_number", { length: 10 }), // ETX_NO - 내선번호
+ mobileIndicator: varchar("mobile_indicator", { length: 1 }), // HP_ORDR - 핸드폰지시자
+ interfaceDate: varchar("interface_date", { length: 8 }), // IF_DT - 인터페이스일자
+ interfaceTime: varchar("interface_time", { length: 6 }), // IF_TM - 인터페이스시간
+ interfaceStatus: varchar("interface_status", { length: 1 }), // IF_STAT - 인터페이스상태
+ interfaceMessage: varchar("interface_message", { length: 100 }), // IF_MSG - 인터페이스메시지
+ createdAt: timestamp("created_at").defaultNow().notNull(),
+ updatedAt: timestamp("updated_at").defaultNow().notNull(),
+});
+
+// 벤더 대표자 URL 테이블 (CMCTB_VENDOR_REPRURL 대응)
+export const vendorRepresentativeUrls = pgTable("vendor_representative_urls", {
+ id: serial("id").primaryKey(),
+ vendorCode: varchar("vendor_code", { length: 10 }).notNull().references(() => vendors.vendorCode), // VNDRCD - 벤더코드 (키) 이고, SAP에서는 VARCHAR10 이다.
+ addressNumber: varchar("address_number", { length: 10 }), // ADR_NO - 주소번호
+ representativeSequence: varchar("representative_sequence", { length: 3 }).notNull(), // REPR_SER - 대표자순번
+ validStartDate: varchar("valid_start_date", { length: 8 }).notNull(), // VLD_ST_DT - 유효시작일자
+ url: varchar("url", { length: 2048 }), // URL - URL
+ interfaceDate: varchar("interface_date", { length: 8 }), // IF_DT - 인터페이스일자
+ interfaceTime: varchar("interface_time", { length: 6 }), // IF_TM - 인터페이스시간
+ interfaceStatus: varchar("interface_status", { length: 1 }), // IF_STAT - 인터페이스상태
+ interfaceMessage: varchar("interface_message", { length: 100 }), // IF_MSG - 인터페이스메시지
+ createdAt: timestamp("created_at").defaultNow().notNull(),
+ updatedAt: timestamp("updated_at").defaultNow().notNull(),
+});
+
+// 벤더 세금번호 테이블 (CMCTB_VENDOR_TAXNUM 대응)
+export const vendorTaxNumbers = pgTable("vendor_tax_numbers", {
+ id: serial("id").primaryKey(),
+ vendorCode: varchar("vendor_code", { length: 10 }).notNull().references(() => vendors.vendorCode), // VNDRCD - 벤더코드 (키) 이고, SAP에서는 VARCHAR10 이다.
+ taxNumberCategory: varchar("tax_number_category", { length: 4 }).notNull(), // TX_NO_CTG - 세금번호범주
+ businessPartnerTaxNumber: varchar("business_partner_tax_number", { length: 20 }), // BIZ_PTNR_TX_NO - 사업파트너세금번호
+ interfaceDate: varchar("interface_date", { length: 8 }), // IF_DT - 인터페이스일자
+ interfaceTime: varchar("interface_time", { length: 6 }), // IF_TM - 인터페이스시간
+ interfaceStatus: varchar("interface_status", { length: 1 }), // IF_STAT - 인터페이스상태
+ interfaceMessage: varchar("interface_message", { length: 100 }), // IF_MSG - 인터페이스메시지
+ createdAt: timestamp("created_at").defaultNow().notNull(),
+ updatedAt: timestamp("updated_at").defaultNow().notNull(),
+});
+
+// 벤더 파트너역할 테이블 (CMCTB_VENDOR_VFPN 대응)
+export const vendorPartnerFunctions = pgTable("vendor_partner_functions", {
+ id: serial("id").primaryKey(),
+ vendorCode: varchar("vendor_code", { length: 10 }).notNull().references(() => vendors.vendorCode), // VNDRCD - 벤더코드 (키) 이고, SAP에서는 VARCHAR10 이다.
+ purchaseOrgCode: varchar("purchase_org_code", { length: 4 }).notNull(), // PUR_ORG_CD - 구매조직
+ vendorSubNumber: varchar("vendor_sub_number", { length: 6 }).notNull(), // VNDR_SUB_NO - VENDOR서브번호
+ plantCode: varchar("plant_code", { length: 4 }).notNull(), // PLNT_CD - 플랜트코드
+ partnerFunction: varchar("partner_function", { length: 2 }).notNull(), // PTNR_SKL - 파트너기능
+ partnerCounter: varchar("partner_counter", { length: 3 }).notNull(), // PTNR_CNT - 파트너카운터
+ otherReferenceVendorCode: varchar("other_reference_vendor_code", { length: 10 }), // ETC_REF_VNDRCD - 기타참조VENDOR코드
+ defaultPartnerIndicator: varchar("default_partner_indicator", { length: 1 }), // BSE_PTNR_ORDR - 기본파트너지시자
+ interfaceDate: varchar("interface_date", { length: 8 }), // IF_DT - 인터페이스일자
+ interfaceTime: varchar("interface_time", { length: 6 }), // IF_TM - 인터페이스시간
+ interfaceStatus: varchar("interface_status", { length: 1 }), // IF_STAT - 인터페이스상태
+ interfaceMessage: varchar("interface_message", { length: 100 }), // IF_MSG - 인터페이스메시지
+ createdAt: timestamp("created_at").defaultNow().notNull(),
+ updatedAt: timestamp("updated_at").defaultNow().notNull(),
+});
+
+// 벤더 원천세 테이블 (CMCTB_VENDOR_WHTHX 대응)
+export const vendorWithholdingTax = pgTable("vendor_withholding_tax", {
+ id: serial("id").primaryKey(),
+ vendorCode: varchar("vendor_code", { length: 10 }).notNull().references(() => vendors.vendorCode), // VNDRCD - 벤더코드 (키) 이고, SAP에서는 VARCHAR10 이다.
+ companyCode: varchar("company_code", { length: 4 }).notNull(), // CO_CD - 회사코드
+ withholdingTaxType: varchar("withholding_tax_type", { length: 2 }).notNull(), // SRCE_TX_TP - 원천세유형
+ withholdingTaxRelatedIndicator: varchar("withholding_tax_related_indicator", { length: 1 }), // SRCE_TX_REL_ORDR - 원천세관련지시자
+ recipientType: varchar("recipient_type", { length: 2 }), // RECIP_TP - 수취인유형
+ withholdingTaxIdentificationNumber: varchar("withholding_tax_identification_number", { length: 16 }), // SRCE_TX_IDENT_NO - 원천세식별번호
+ withholdingTaxCode: varchar("withholding_tax_code", { length: 2 }), // SRCE_TX_NO - 원천세코드
+ exemptionCertificateNumber: varchar("exemption_certificate_number", { length: 15 }), // DCHAG_CERT_NO - 면제증명서번호
+ exemptionRate: integer("exemption_rate"), // DCHAG_RAT - 면제율
+ exemptionStartDate: varchar("exemption_start_date", { length: 8 }), // DCHAG_ST_DT - 면제시작일자
+ exemptionEndDate: varchar("exemption_end_date", { length: 8 }), // DCHAG_ED_DT - 면제종료일
+ exemptionReason: varchar("exemption_reason", { length: 200 }), // DCHAG_CAUS - 면제사유
+ interfaceDate: varchar("interface_date", { length: 8 }), // IF_DT - 인터페이스일자
+ interfaceTime: varchar("interface_time", { length: 6 }), // IF_TM - 인터페이스시간
+ interfaceStatus: varchar("interface_status", { length: 1 }), // IF_STAT - 인터페이스상태
+ interfaceMessage: varchar("interface_message", { length: 100 }), // IF_MSG - 인터페이스메시지
+ createdAt: timestamp("created_at").defaultNow().notNull(),
+ updatedAt: timestamp("updated_at").defaultNow().notNull(),
+});
+
+// ------- [끝] MDG 인터페이스 목적 테이블 추가 -------------
+
+// ------- [시작] MDG 대응을 위한 새로운 테이블 타입 정의 -------------
+export type VendorBusinessGroup = typeof vendorBusinessGroups.$inferSelect
+export type VendorInternalPartner = typeof vendorInternalPartners.$inferSelect
+export type VendorPurchaseOrganization = typeof vendorPurchaseOrganizations.$inferSelect
+export type VendorRepresentativeEmail = typeof vendorRepresentativeEmails.$inferSelect
+export type VendorRepresentativeFax = typeof vendorRepresentativeFaxes.$inferSelect
+export type VendorRepresentativeTelephone = typeof vendorRepresentativeTelephones.$inferSelect
+export type VendorRepresentativeUrl = typeof vendorRepresentativeUrls.$inferSelect
+export type VendorTaxNumber = typeof vendorTaxNumbers.$inferSelect
+export type VendorPartnerFunction = typeof vendorPartnerFunctions.$inferSelect
+export type VendorWithholdingTax = typeof vendorWithholdingTax.$inferSelect
+// ------- [끝] MDG 대응을 위한 새로운 테이블 타입 정의 -------------
+
+// vendors 통합 뷰 - id 하나로 모든 마이그레이션 정보 확인
+export const vendorComprehensiveView = pgView("vendor_comprehensive_view").as((qb) => {
+ return qb
+ .select({
+ evcpId: vendors.id,
+ evcpVendorName: vendors.vendorName,
+ evcpTaxId: vendors.taxId,
+ mdgBusinessRegistrationNumber: vendorMdgGenerals.businessRegistrationNumber,
+
+
+ })
+ .from(vendors)
+ .leftJoin(vendorMdgGenerals, eq(vendors.vendorCode, vendorMdgGenerals.vendorCode))
+ .leftJoin(vendorBusinessGroups, eq(vendors.vendorCode, vendorBusinessGroups.vendorCode))
+ .leftJoin(vendorInternalPartners, eq(vendors.vendorCode, vendorInternalPartners.vendorCode))
+ .leftJoin(vendorPurchaseOrganizations, eq(vendors.vendorCode, vendorPurchaseOrganizations.vendorCode))
+ .leftJoin(vendorRepresentativeEmails, eq(vendors.vendorCode, vendorRepresentativeEmails.vendorCode))
+ .leftJoin(vendorRepresentativeFaxes, eq(vendors.vendorCode, vendorRepresentativeFaxes.vendorCode))
+ .leftJoin(vendorRepresentativeTelephones, eq(vendors.vendorCode, vendorRepresentativeTelephones.vendorCode))
+ .leftJoin(vendorRepresentativeUrls, eq(vendors.vendorCode, vendorRepresentativeUrls.vendorCode))
+ .leftJoin(vendorTaxNumbers, eq(vendors.vendorCode, vendorTaxNumbers.vendorCode))
+ .leftJoin(vendorPartnerFunctions, eq(vendors.vendorCode, vendorPartnerFunctions.vendorCode))
+ .leftJoin(vendorWithholdingTax, eq(vendors.vendorCode, vendorWithholdingTax.vendorCode))
+})
+
+export type VendorComprehensiveView = typeof vendorComprehensiveView.$inferSelect
+