diff options
Diffstat (limited to 'lib/soap')
| -rw-r--r-- | lib/soap/mdg/mapper/vendor-mapper.ts | 191 |
1 files changed, 131 insertions, 60 deletions
diff --git a/lib/soap/mdg/mapper/vendor-mapper.ts b/lib/soap/mdg/mapper/vendor-mapper.ts index c9824785..c463e76b 100644 --- a/lib/soap/mdg/mapper/vendor-mapper.ts +++ b/lib/soap/mdg/mapper/vendor-mapper.ts @@ -9,7 +9,7 @@ import { VENDOR_MASTER_BP_HEADER_ADDRESS_AD_EMAIL, VENDOR_MASTER_BP_HEADER_ADDRESS_AD_URL } from '@/db/schema/MDG/mdg'; -import { eq } from 'drizzle-orm'; +import { eq, and } from 'drizzle-orm'; /** * 벤더 매퍼 @@ -193,10 +193,12 @@ async function fetchMDGVendorData(vndrCodes: string[]): Promise<MDGVendorData[]> .where(eq(VENDOR_MASTER_BP_HEADER_BP_TAXNUM.VNDRCD, vndrCode)) .limit(1); - debugLog('BP_TAXNUM 조회 완료', { + debugLog('BP_TAXNUM 조회 완료 (상세)', { vndrCode, found: bpTaxnumData.length > 0, - taxId: bpTaxnumData[0]?.BIZ_PTNR_TX_NO || null + taxId: bpTaxnumData[0]?.BIZ_PTNR_TX_NO || null, + TX_NO_CTG: bpTaxnumData[0]?.TX_NO_CTG || null, + rawData: bpTaxnumData[0] || null }); // 3. BP_POSTAL 테이블에서 주소 정보 조회 @@ -272,10 +274,12 @@ async function fetchMDGVendorData(vndrCodes: string[]): Promise<MDGVendorData[]> CO_VLM: vengenData.CO_VLM || undefined, }; - debugSuccess('MDG 벤더 데이터 병합 완료', { + debugSuccess('MDG 벤더 데이터 병합 완료 (상세)', { vndrCode, hasVendorName: !!mdgVendorData.VNDRNM_1, hasTaxId: !!mdgVendorData.BIZ_PTNR_TX_NO, + taxId: mdgVendorData.BIZ_PTNR_TX_NO, // ⚠️ 사업자번호 + representativeBirth: mdgVendorData.REPR_RESNO, // ⚠️ 대표자 주민번호 mergedData: mdgVendorData }); @@ -375,10 +379,18 @@ function mapMDGToVendor(mdgVendorData: MDGVendorData): VendorData | null { ? mdgVendorData.REPR_RESNO.substring(0, 6) : undefined; + debugLog('⚠️ 필드 매핑 상세 (문제2 확인용)', { + vndrCode: mdgVendorData.VNDRCD, + 'BIZ_PTNR_TX_NO(사업자번호 원본)': mdgVendorData.BIZ_PTNR_TX_NO, + 'REPR_RESNO(대표자주민번호 원본)': mdgVendorData.REPR_RESNO, + 'taxId(매핑될 사업자번호)': mdgVendorData.BIZ_PTNR_TX_NO, + 'representativeBirth(매핑될 대표자생년월일)': representativeBirth, + }); + const mappedVendor: VendorData = { vendorCode: mdgVendorData.VNDRCD, vendorName: mdgVendorData.VNDRNM_1, - taxId: mdgVendorData.BIZ_PTNR_TX_NO, + taxId: mdgVendorData.BIZ_PTNR_TX_NO, // ⚠️ 사업자번호 (BIZ_PTNR_TX_NO에서 가져옴) address: mdgVendorData.ETC_ADR_1 || undefined, addressDetail: addressDetail, postalCode: mdgVendorData.CITY_ZIP_NO || undefined, @@ -389,7 +401,7 @@ function mapMDGToVendor(mdgVendorData: MDGVendorData): VendorData | null { status: 'ACTIVE', // 매핑 규칙에 따라 항상 'ACTIVE' vendorTypeId: undefined, // 매핑 규칙에 따라 null representativeName: mdgVendorData.REPR_NM || undefined, - representativeBirth: representativeBirth, + representativeBirth: representativeBirth, // ⚠️ 대표자 생년월일 (REPR_RESNO에서 가져옴) representativeEmail: mdgVendorData.REPR_EMAIL || undefined, // email과 동일한 값 representativePhone: mdgVendorData.REP_TEL_NO || undefined, representativeWorkExpirence: undefined, // 매핑 규칙에 따라 null @@ -400,6 +412,8 @@ function mapMDGToVendor(mdgVendorData: MDGVendorData): VendorData | null { debugLog('벤더 매핑 완료 - 매핑된 데이터 상세', { vndrCode: mdgVendorData.VNDRCD, + taxId: mappedVendor.taxId, + representativeBirth: mappedVendor.representativeBirth, mappedVendor: mappedVendor }); @@ -416,6 +430,10 @@ function mapMDGToVendor(mdgVendorData: MDGVendorData): VendorData | null { /** * 매핑된 벤더 데이터를 데이터베이스에 저장 + * + * 수정사항: + * - vendorCode뿐만 아니라 taxId(사업자번호)로도 기존 벤더 검색 + * - MDG에서 vendorCode를 최초로 받는 경우, taxId로 매칭하여 기존 벤더에 vendorCode 업데이트 */ async function saveVendorsToDatabase(mappedVendors: VendorData[]): Promise<void> { try { @@ -431,81 +449,134 @@ async function saveVendorsToDatabase(mappedVendors: VendorData[]): Promise<void> try { debugLog('벤더 저장 시도', { vendorCode: vendor.vendorCode, + taxId: vendor.taxId, vendorName: vendor.vendorName }); + let existingVendor: { id: number; vendorCode: string | null; taxId: string | null }[] = []; + + // 1차: vendorCode로 기존 벤더 검색 if (vendor.vendorCode) { - // vendorCode가 있는 경우 기존 데이터 확인 - const existingVendor = await tx - .select({ id: vendors.id }) + existingVendor = await tx + .select({ id: vendors.id, vendorCode: vendors.vendorCode, taxId: vendors.taxId }) .from(vendors) .where(eq(vendors.vendorCode, vendor.vendorCode)) .limit(1); - debugLog('기존 벤더 조회 결과', { + debugLog('1차: vendorCode로 기존 벤더 조회', { vendorCode: vendor.vendorCode, - exists: existingVendor.length > 0, - existingId: existingVendor.length > 0 ? existingVendor[0].id : null + found: existingVendor.length > 0 }); + } - if (existingVendor.length > 0) { - // 기존 데이터 업데이트 - debugLog('기존 벤더 업데이트 시작', { - vendorCode: vendor.vendorCode, + // 2차: vendorCode로 못 찾았고 taxId가 있으면, taxId로 검색 + if (existingVendor.length === 0 && vendor.taxId) { + existingVendor = await tx + .select({ id: vendors.id, vendorCode: vendors.vendorCode, taxId: vendors.taxId }) + .from(vendors) + .where(eq(vendors.taxId, vendor.taxId)) + .limit(1); + + debugLog('2차: taxId로 기존 벤더 조회', { + taxId: vendor.taxId, + found: existingVendor.length > 0, + existingVendorCode: existingVendor.length > 0 ? existingVendor[0].vendorCode : null + }); + + if (existingVendor.length > 0 && !existingVendor[0].vendorCode && vendor.vendorCode) { + debugSuccess('기존 벤더에 MDG vendorCode 매핑 발견 (taxId 매칭)', { + taxId: vendor.taxId, + newVendorCode: vendor.vendorCode, existingId: existingVendor[0].id }); + } + } - await tx - .update(vendors) - .set({ - vendorName: vendor.vendorName, - taxId: vendor.taxId, - address: vendor.address, - addressDetail: vendor.addressDetail, - postalCode: vendor.postalCode, - country: vendor.country, - phone: vendor.phone, - email: vendor.email, - website: vendor.website, - status: vendor.status, - representativeName: vendor.representativeName, - representativeBirth: vendor.representativeBirth, - representativeEmail: vendor.representativeEmail, - representativePhone: vendor.representativePhone, - corporateRegistrationNumber: vendor.corporateRegistrationNumber, - businessSize: vendor.businessSize, - updatedAt: new Date(), - }) - .where(eq(vendors.vendorCode, vendor.vendorCode)); - - updateCount++; - debugSuccess('벤더 업데이트 완료', { - vendorCode: vendor.vendorCode, - vendorName: vendor.vendorName - }); - } else { - // 새 데이터 삽입 - debugLog('신규 벤더 삽입 시작', { - vendorCode: vendor.vendorCode, - vendorData: vendor - }); + // 3차: vendorName AND country로 검색 + if (existingVendor.length === 0 && vendor.vendorName && vendor.country) { + existingVendor = await tx + .select({ id: vendors.id, vendorCode: vendors.vendorCode, taxId: vendors.taxId }) + .from(vendors) + .where( + and( + eq(vendors.vendorName, vendor.vendorName), + eq(vendors.country, vendor.country) + ) + ) + .limit(1); + + debugLog('3차: vendorName + country로 기존 벤더 조회', { + vendorName: vendor.vendorName, + country: vendor.country, + found: existingVendor.length > 0, + existingVendorCode: existingVendor.length > 0 ? existingVendor[0].vendorCode : null, + existingTaxId: existingVendor.length > 0 ? existingVendor[0].taxId : null + }); - await tx.insert(vendors).values(vendor); - - insertCount++; - debugSuccess('벤더 삽입 완료', { - vendorCode: vendor.vendorCode, - vendorName: vendor.vendorName + if (existingVendor.length > 0) { + debugSuccess('기존 벤더 매칭 발견 (이름+국가 매칭)', { + vendorName: vendor.vendorName, + country: vendor.country, + newVendorCode: vendor.vendorCode || 'null', + newTaxId: vendor.taxId || 'null', + existingId: existingVendor[0].id }); } + } + + if (existingVendor.length > 0) { + // 기존 데이터 업데이트 + debugLog('기존 벤더 업데이트 시작', { + existingId: existingVendor[0].id, + vendorCode: vendor.vendorCode, + taxId: vendor.taxId + }); + + await tx + .update(vendors) + .set({ + vendorCode: vendor.vendorCode, // ⚠️ MDG에서 최초로 vendorCode를 받는 경우 업데이트 + vendorName: vendor.vendorName, + taxId: vendor.taxId, + address: vendor.address, + addressDetail: vendor.addressDetail, + postalCode: vendor.postalCode, + country: vendor.country, + phone: vendor.phone, + email: vendor.email, + website: vendor.website, + status: vendor.status, + representativeName: vendor.representativeName, + representativeBirth: vendor.representativeBirth, + representativeEmail: vendor.representativeEmail, + representativePhone: vendor.representativePhone, + corporateRegistrationNumber: vendor.corporateRegistrationNumber, + businessSize: vendor.businessSize, + updatedAt: new Date(), + }) + .where(eq(vendors.id, existingVendor[0].id)); + + updateCount++; + debugSuccess('벤더 업데이트 완료', { + id: existingVendor[0].id, + vendorCode: vendor.vendorCode, + taxId: vendor.taxId, + vendorName: vendor.vendorName + }); } else { - // vendorCode가 없는 경우 새 데이터 삽입 - debugLog('vendorCode 없는 벤더 삽입 시작', { vendorData: vendor }); - + // 새 데이터 삽입 + debugLog('신규 벤더 삽입 시작', { + vendorCode: vendor.vendorCode, + taxId: vendor.taxId, + vendorData: vendor + }); + await tx.insert(vendors).values(vendor); insertCount++; - debugSuccess('vendorCode 없는 벤더 삽입 완료', { + debugSuccess('벤더 삽입 완료', { + vendorCode: vendor.vendorCode, + taxId: vendor.taxId, vendorName: vendor.vendorName }); } |
