diff options
Diffstat (limited to 'lib/soap')
| -rw-r--r-- | lib/soap/mdg/send/vendor-master/action.ts | 193 |
1 files changed, 142 insertions, 51 deletions
diff --git a/lib/soap/mdg/send/vendor-master/action.ts b/lib/soap/mdg/send/vendor-master/action.ts index 34ce242c..e96b93fc 100644 --- a/lib/soap/mdg/send/vendor-master/action.ts +++ b/lib/soap/mdg/send/vendor-master/action.ts @@ -18,11 +18,17 @@ import { } from "@/db/schema/MDG/mdg"; import { eq, sql, desc } from "drizzle-orm"; import { withSoapLogging } from "../../utils"; +import * as soap from 'soap'; import fs from 'fs'; import path from 'path'; -// WSDL 엔드포인트 URL (WSDL에서 추출) -const MDG_ENDPOINT_URL = "http://shii8dvddb01.hec.serp.shi.samsung.net:50000/sap/xi/engine?type=entry&version=3.0&Sender.Service=P2038_D&Interface=http%3A%2F%2Fshi.samsung.co.kr%2FP2_MD%2FMDZ%5EP2MD3007_AO&QualityOfService=ExactlyOnce"; +// WSDL 파일 경로 +const WSDL_PATH = path.join(process.cwd(), 'public', 'wsdl', 'P2MD3007_AO.wsdl'); + +// 환경변수에서 인증 정보 가져오기 +const MDG_SOAP_USERNAME = process.env.MDG_SOAP_USERNAME; +const MDG_SOAP_PASSWORD = process.env.MDG_SOAP_PASSWORD; +const MDG_SOAP_AUTH_TYPE = process.env.MDG_SOAP_AUTH_TYPE || 'basic'; // 'basic' | 'wssecurity' // CSV 파싱 및 필드 정의 ------------------------------------------------ interface CsvField { @@ -53,17 +59,57 @@ try { console.error('CSV 로딩 실패:', e); } -// XML escape helper -const escapeXml = (unsafe: string) => unsafe.replace(/[<>&'"']/g, (c) => { - switch (c) { - case '<': return '<'; - case '>': return '>'; - case '&': return '&'; - case '"': return '"'; - case "'": return '''; - default: return c; - } -}); +// SOAP 클라이언트 생성 및 인증 설정 함수 +async function createSoapClient(): Promise<soap.Client> { + return new Promise((resolve, reject) => { + soap.createClient(WSDL_PATH, (err, client) => { + if (err) { + reject(err); + return; + } + + if (!client) { + reject(new Error('SOAP 클라이언트 생성 실패')); + return; + } + + // 인증 설정 + if (MDG_SOAP_USERNAME && MDG_SOAP_PASSWORD) { + try { + if (MDG_SOAP_AUTH_TYPE === 'wssecurity') { + // WS-Security 인증 설정 + const wsSecurity = new soap.WSSecurity(MDG_SOAP_USERNAME, MDG_SOAP_PASSWORD); + client.setSecurity(wsSecurity); + console.log('🔐 WS-Security 인증 설정 완료'); + } else { + // Basic Authentication 설정 (기본값) + const basicAuth = new soap.BasicAuthSecurity(MDG_SOAP_USERNAME, MDG_SOAP_PASSWORD); + client.setSecurity(basicAuth); + console.log('🔐 Basic Authentication 설정 완료'); + } + } catch (authError) { + console.warn('⚠️ 인증 설정 중 오류:', authError); + } + } else { + console.warn('⚠️ MDG SOAP 인증 정보가 환경변수에 설정되지 않았습니다.'); + } + + resolve(client); + }); + }); +} + +// SOAP 응답 타입 정의 +interface SoapResponse { + [key: string]: unknown; +} + +// SOAP 오류 타입 정의 +interface SoapError { + message: string; + body?: string; + statusCode?: number; +} // VENDOR 마스터 데이터를 MDG로 송신하는 액션 export async function sendVendorMasterToMDG(vendorCodes: string[]): Promise<{ @@ -93,39 +139,29 @@ export async function sendVendorMasterToMDG(vendorCodes: string[]): Promise<{ continue; } - // XML 생성 - const soapXml = buildSoapXML(vendorData); - console.log(`📄 VENDOR ${vendorCode} XML 생성 완료`); + // SOAP 요청 데이터 생성 + const soapData = buildSoapData(vendorData); + console.log(`📄 VENDOR ${vendorCode} SOAP 데이터 생성 완료`); - // SOAP 요청 전송 + // SOAP 클라이언트로 요청 전송 await withSoapLogging( 'OUTBOUND', 'MDG', 'IF_MDZ_EVCP_VENDOR_MASTER', - soapXml, + JSON.stringify(soapData), async () => { - const response = await fetch(MDG_ENDPOINT_URL, { - method: 'POST', - headers: { - 'Content-Type': 'text/xml; charset=utf-8', - 'SOAPAction': 'http://sap.com/xi/WebService/soap1.1', - }, - body: soapXml, - }); - - if (!response.ok) { - throw new Error(`HTTP ${response.status}: ${response.statusText}`); - } + const client = await createSoapClient(); - const responseText = await response.text(); - console.log(`✅ VENDOR ${vendorCode} MDG 전송 성공`); - - // SOAP Fault 체크 - if (responseText.includes('soap:Fault') || responseText.includes('SOAP:Fault')) { - throw new Error(`MDG SOAP Fault: ${responseText}`); - } - - return responseText; + return new Promise<SoapResponse>((resolve, reject) => { + client.P2MD3007_AO(soapData, (err: SoapError | null, result: SoapResponse) => { + if (err) { + reject(err); + } else { + console.log(`✅ VENDOR ${vendorCode} MDG 전송 성공`); + resolve(result); + } + }); + }); } ); @@ -229,8 +265,8 @@ async function fetchVendorData(vendorCode: string) { } } -// SOAP XML 생성 (WSDL 구조에 맞춤) -function buildSoapXML(vendorData: NonNullable<Awaited<ReturnType<typeof fetchVendorData>>>): string { +// SOAP 데이터 생성 (WSDL 구조에 맞춤) +function buildSoapData(vendorData: NonNullable<Awaited<ReturnType<typeof fetchVendorData>>>) { const { vendorHeader, addresses, adEmails, adFaxes, adPostals, adTels, adUrls, bpTaxnums, bpVengens } = vendorData; // 값 추출 매핑 ------------------------------------ @@ -262,7 +298,7 @@ function buildSoapXML(vendorData: NonNullable<Awaited<ReturnType<typeof fetchVen // Default others can be added as needed }; - // 필드 순서에 따라 XML 생성 + // 필드 순서에 따라 데이터 생성 const seen = new Set<string>(); const uniqueFields = CSV_FIELDS.filter(f => { if (seen.has(f.field)) return false; @@ -270,16 +306,17 @@ function buildSoapXML(vendorData: NonNullable<Awaited<ReturnType<typeof fetchVen return true; }); - const fieldXml = uniqueFields.map(f => { - const val = mapping[f.field] ?? ''; - return `<${f.field}>${escapeXml(val ?? '')}</${f.field}>`; - }).join('\n '); - - const supplierMasterXml = `<SUPPLIER_MASTER>\n ${fieldXml}\n </SUPPLIER_MASTER>`; - - const soapEnvelope = `<?xml version="1.0" encoding="UTF-8"?>\n<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:p1="http://shi.samsung.co.kr/P2_MD/MDZ">\n <soap:Header/>\n <soap:Body>\n <p1:MT_P2MD3007_S>\n <P2MD3007_S>\n ${supplierMasterXml}\n </P2MD3007_S>\n </p1:MT_P2MD3007_S>\n </soap:Body>\n</soap:Envelope>`; + const supplierMaster: Record<string, any> = {}; + uniqueFields.forEach(f => { + supplierMaster[f.field] = mapping[f.field] ?? ''; + }); - return soapEnvelope.trim(); + // SOAP 요청 구조 생성 + return { + P2MD3007_S: { + SUPPLIER_MASTER: supplierMaster + } + }; } // 특정 VENDOR만 송신하는 유틸리티 함수 @@ -582,3 +619,57 @@ export async function getVendorSendStatistics(): Promise<{ throw error; } } + +// 직접 XML 전송 함수 (기존 호환성 유지) +export async function sendVendorEnvelopeToMDG(envelope: string): Promise<{ + success: boolean; + message: string; + responseText?: string; +}> { + try { + const responseText = await withSoapLogging( + 'OUTBOUND', + 'MDG', + 'IF_MDZ_EVCP_VENDOR_MASTER_TEST', // 테스트용 인터페이스명 + envelope, + async () => { + // 직접 XML 전송의 경우 기존 fetch 방식 유지 + const MDG_ENDPOINT_URL = "http://shii8dvddb01.hec.serp.shi.samsung.net:50000/sap/xi/engine?type=entry&version=3.0&Sender.Service=P2038_D&Interface=http%3A%2F%2Fshi.samsung.co.kr%2FP2_MD%2FMDZ%5EP2MD3007_AO&QualityOfService=ExactlyOnce"; + + const res = await fetch(MDG_ENDPOINT_URL, { + method: 'POST', + headers: { + 'Content-Type': 'text/xml; charset=utf-8', + 'SOAPAction': 'http://sap.com/xi/WebService/soap1.1', + }, + body: envelope, + }); + + const text = await res.text(); + + if (!res.ok) { + throw new Error(`HTTP ${res.status}: ${res.statusText}`); + } + + // SOAP Fault 검사 + if (text.includes('soap:Fault') || text.includes('SOAP:Fault')) { + throw new Error(`MDG SOAP Fault: ${text}`); + } + + return text; + } + ); + + return { + success: true, + message: '전송 성공', + responseText, + }; + } catch (error) { + console.error('XML 전송 실패:', error); + return { + success: false, + message: error instanceof Error ? error.message : 'Unknown error', + }; + } +} |
