summaryrefslogtreecommitdiff
path: root/lib/soap/mdg
diff options
context:
space:
mode:
Diffstat (limited to 'lib/soap/mdg')
-rw-r--r--lib/soap/mdg/send/vendor-master/action.ts193
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 '&lt;';
- case '>': return '&gt;';
- case '&': return '&amp;';
- case '"': return '&quot;';
- case "'": return '&apos;';
- 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',
+ };
+ }
+}