summaryrefslogtreecommitdiff
path: root/lib/soap/mdg/send/vendor-master/send-single-vendor.ts
diff options
context:
space:
mode:
Diffstat (limited to 'lib/soap/mdg/send/vendor-master/send-single-vendor.ts')
-rw-r--r--lib/soap/mdg/send/vendor-master/send-single-vendor.ts238
1 files changed, 238 insertions, 0 deletions
diff --git a/lib/soap/mdg/send/vendor-master/send-single-vendor.ts b/lib/soap/mdg/send/vendor-master/send-single-vendor.ts
new file mode 100644
index 00000000..d10792b7
--- /dev/null
+++ b/lib/soap/mdg/send/vendor-master/send-single-vendor.ts
@@ -0,0 +1,238 @@
+'use server'
+
+import db from "@/db/db"
+import { vendors, vendorTypes } from "@/db/schema/vendors"
+import { eq } from "drizzle-orm"
+import { sendVendorMasterToMDGInternal } from "./action"
+import { debugLog, debugError, debugSuccess } from '@/lib/debug-utils'
+import { oracleKnex } from '@/lib/oracle-db/db'
+
+/**
+ * Oracle DB에서 ZZREQID 값 조회
+ *
+ * @returns ZZREQID 값 (조회 실패 시 기본값 'HUIUN84.KIM')
+ */
+async function getZZREQID(): Promise<string> {
+ const DEFAULT_ZZREQID = 'HUIUN84.KIM'
+
+ try {
+ debugLog(`🔍 [ZZREQID] Oracle DB에서 ZZREQID 조회 시작`)
+
+ const query = `
+ SELECT CDNM
+ FROM CMCTB_CDNM
+ WHERE CD_CLF = :cd_clf
+ AND CD = :cd
+ AND ROWNUM <= 1
+ `
+
+ const results = await oracleKnex.raw(query, {
+ cd_clf: 'SRM0BN',
+ cd: '001'
+ })
+
+ debugLog(`🗄️ [ZZREQID] Oracle 쿼리 결과:`, {
+ resultType: typeof results,
+ isArray: Array.isArray(results),
+ })
+
+ // Oracle 결과 파싱 (여러 형태 처리)
+ let rows
+ if (Array.isArray(results)) {
+ // [rows, metaData] 형태 또는 바로 데이터 배열
+ if (results.length > 0 && typeof results[0] === 'object' && !Array.isArray(results[0])) {
+ rows = results // 바로 데이터 배열
+ } else {
+ rows = results[0] || [] // [rows, metaData] 형태
+ }
+ } else if (results && typeof results === 'object' && results.rows) {
+ rows = results.rows || []
+ } else {
+ rows = []
+ }
+
+ if (!Array.isArray(rows) || rows.length === 0) {
+ debugError(`⚠️ [ZZREQID] Oracle 조회 결과 없음, 기본값 사용: ${DEFAULT_ZZREQID}`)
+ return DEFAULT_ZZREQID
+ }
+
+ const cdnm = rows[0]?.CDNM || rows[0]?.[0]
+
+ if (!cdnm) {
+ debugError(`⚠️ [ZZREQID] CDNM 컬럼 값 없음, 기본값 사용: ${DEFAULT_ZZREQID}`)
+ return DEFAULT_ZZREQID
+ }
+
+ debugSuccess(`✅ [ZZREQID] Oracle 조회 성공: ${cdnm}`)
+ return String(cdnm)
+
+ } catch (error) {
+ debugError(`❌ [ZZREQID] Oracle 조회 실패, 기본값 사용:`, {
+ error: error instanceof Error ? error.message : '알 수 없는 오류',
+ defaultValue: DEFAULT_ZZREQID
+ })
+ return DEFAULT_ZZREQID
+ }
+}
+
+/**
+ * 개별 벤더 데이터를 MDG로 전송
+ *
+ * @param input.vendorId - vendors 테이블의 ID
+ * @param input.mode - 'NEW_VENDOR' (신규) 또는 'REGULAR_VENDOR' (정규)
+ * @returns 전송 결과
+ */
+export async function sendSingleVendorToMDG(input: {
+ vendorId: number
+ mode: 'NEW_VENDOR' | 'REGULAR_VENDOR'
+}): Promise<{
+ success: boolean
+ message: string
+ vendorId: number
+ responseText?: string
+ requestXml?: string
+}> {
+ try {
+ debugLog(`📤 [MDG Single] 벤더 ID ${input.vendorId} 전송 시작 (모드: ${input.mode})`)
+
+ // 1. 벤더 데이터 조회 (vendor_types 조인)
+ const [vendorData] = await db
+ .select({
+ vendor: vendors,
+ vendorTypeName: vendorTypes.nameKo,
+ })
+ .from(vendors)
+ .leftJoin(vendorTypes, eq(vendors.vendorTypeId, vendorTypes.id))
+ .where(eq(vendors.id, input.vendorId))
+ .limit(1)
+
+ if (!vendorData) {
+ throw new Error(`벤더를 찾을 수 없습니다: ID ${input.vendorId}`)
+ }
+
+ const vendor = vendorData.vendor
+ const vendorTypeName = vendorData.vendorTypeName
+
+ debugLog(`📋 [MDG Single] 벤더 조회 완료: ${vendor.vendorName} (업체 유형: ${vendorTypeName || '없음'})`)
+
+ // 2. Oracle DB에서 ZZREQID 조회
+ const zzreqid = await getZZREQID()
+ debugLog(`🔑 [MDG Single] ZZREQID 값: ${zzreqid}`)
+
+ // 3. MDG 포맷으로 데이터 매핑
+ const supplierMaster = mapVendorToMDGFormat(vendor, vendorTypeName, zzreqid, input.mode)
+
+ debugLog(`🔄 [MDG Single] 데이터 매핑 완료 (${Object.keys(supplierMaster).length}개 필드)`)
+
+ // 3. MDG로 전송
+ const result = await sendVendorMasterToMDGInternal(supplierMaster)
+
+ if (!result.success) {
+ debugError(`❌ [MDG Single] 전송 실패: ${result.message}`)
+ throw new Error(`MDG 전송 실패: ${result.message}`)
+ }
+
+ debugSuccess(`✅ [MDG Single] 전송 성공: ${vendor.vendorName}`)
+
+ return {
+ success: true,
+ message: `벤더 '${vendor.vendorName}' MDG 전송 완료`,
+ vendorId: input.vendorId,
+ responseText: result.responseText,
+ requestXml: result.requestXml,
+ }
+
+ } catch (error) {
+ debugError(`❌ [MDG Single] 전송 중 오류:`, error)
+ return {
+ success: false,
+ message: error instanceof Error ? error.message : 'Unknown error',
+ vendorId: input.vendorId,
+ }
+ }
+}
+
+/**
+ * Vendor DB 데이터를 MDG SUPPLIER_MASTER 포맷으로 매핑
+ */
+function mapVendorToMDGFormat(
+ vendor: typeof vendors.$inferSelect,
+ vendorTypeName: string | null,
+ zzreqid: string,
+ mode: 'NEW_VENDOR' | 'REGULAR_VENDOR'
+): Record<string, string> {
+ debugLog(`🗺️ [MDG Mapper] 데이터 매핑 시작: ${vendor.vendorName}`)
+
+ // 전화번호로 모바일 여부 판단 (+8210으로 시작하면 1, 아니면 0)
+ const phoneStr = vendor.phone?.trim() || ''
+ const isMobile = phoneStr.startsWith('+8210') ? '1' : '0'
+
+ // 기본 매핑 (신규 벤더)
+ const mapping: Record<string, string> = {
+ // === 필수 필드 (고정값) ===
+ BP_HEADER: `evcp${vendor.id}`, // 벤더 ID (evcp + ID)
+ ZZSRMCD: `evcp${vendor.id}`, // SRM 코드 (evcp + ID)
+ KTOKK: 'LIEF', // 고정값: Vendor account group
+ MASTERFLAG: 'V', // 고정값
+ IBND_TYPE: 'I', // 고정값
+ CONSNUMBER: '1', // 고정값: 단건 전송
+
+ // === 업체 기본 정보 ===
+ SORT1: vendor.vendorName || '', // 검색어 (업체명과 동일)
+ NAME1: vendor.vendorName || '', // 업체명
+
+ // === 대표자 정보 ===
+ J_1KFREPRE: vendor.representativeName || '', // 대표자명
+ J_1KFTBUS: vendorTypeName || '', // 사업유형 (vendor_types의 name_ko)
+ J_1KFTIND: vendorTypeName || '', // 산업유형 (vendor_types의 name_ko)
+
+ // === 요청자 정보 ===
+ ZZREQID: zzreqid, // Oracle DB에서 동적 조회 (CMCTB_CDNM 테이블)
+
+ // === 주소 정보 ===
+ ADDRNO: '', // 빈 문자열 (보내면 안됨)
+ NATION: '', // 빈 문자열 (보내면 안됨)
+ COUNTRY: vendor.country || 'KR', // 국가코드 (기본값 KR)
+ POST_CODE1: vendor.postalCode || '00000', // 우편번호 (없으면 00000)
+ CITY1: vendor.addressDetail || '', // 상세주소
+ STREET: vendor.address || '', // 기본주소
+
+ // === 연락처 정보 ===
+ TEL_NUMBER: vendor.phone || '', // 전화번호
+ R3_USER: isMobile, // 모바일 여부 (0: 일반전화, 1: +8210 시작)
+ URI_ADDR: vendor.website || '', // 홈페이지 주소
+ SMTP_ADDR: vendor.representativeEmail || '', // 대표자 이메일
+
+ // === 세금 정보 ===
+ TAXTYPE: 'KR2', // 고정값 (한국)
+ TAXNUM: vendor.taxId?.replace(/-/g, '') || '', // 사업자번호 (하이픈 제거)
+ BP_TX_TYP: 'KR2', // 고정값 (한국)
+ STCD3: vendor.corporateRegistrationNumber?.replace(/-/g, '') || '', // 법인등록번호 (하이픈 제거)
+
+ // === 기업 정보 ===
+ ZZIND03: vendor.businessSize || '', // 기업규모 (A=대기업, B=중견기업, C=중소기업, D=소기업)
+
+ // === 무시할 필드들 (빈 문자열) ===
+ LANGU: '', // 언어 키 (무시)
+ }
+
+ // 정규 벤더의 경우 추가 필드 매핑 가능
+ if (mode === 'REGULAR_VENDOR') {
+ // TODO: 정규 벤더 전송 시 추가 필드 매핑
+ // 현재는 신규와 동일하게 처리
+ debugLog(`ℹ️ [MDG Mapper] 정규 벤더 모드 (추가 필드 없음)`)
+ }
+
+ // 빈 문자열인 필드만 포함 (null/undefined는 제외)
+ const result: Record<string, string> = {}
+ Object.entries(mapping).forEach(([key, value]) => {
+ if (value !== null && value !== undefined) {
+ result[key] = String(value)
+ }
+ })
+
+ debugLog(`✅ [MDG Mapper] 매핑 완료: ${Object.keys(result).length}개 필드`)
+
+ return result
+}
+