'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 { 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 { debugLog(`🗺️ [MDG Mapper] 데이터 매핑 시작: ${vendor.vendorName}`) // 전화번호로 모바일 여부 판단 (+8210으로 시작하면 1, 아니면 0) const phoneStr = vendor.phone?.trim() || '' const isMobile = phoneStr.startsWith('+8210') ? '1' : '0' // 기본 매핑 (신규 벤더) const mapping: Record = { // === 필수 필드 (고정값) === 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 = {} Object.entries(mapping).forEach(([key, value]) => { if (value !== null && value !== undefined) { result[key] = String(value) } }) debugLog(`✅ [MDG Mapper] 매핑 완료: ${Object.keys(result).length}개 필드`) return result }