summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorjoonhoekim <26rote@gmail.com>2025-11-10 18:21:59 +0900
committerjoonhoekim <26rote@gmail.com>2025-11-10 18:21:59 +0900
commitd83863f2da22a070459cdc0649580ea55fa40170 (patch)
tree1f97b1e8f7b70bea5375ba5a269f4d6eebbd302e /lib
parent64b16282fea10ed94dc1c4f1b81703c4875d9f7e (diff)
(김준회) 신규등록/정규등록 후 MDG벤더마스터 수신시 Update하도록 중복검출 로직 추가(벤더코드>사업자번호>이름+국가)
Diffstat (limited to 'lib')
-rw-r--r--lib/soap/mdg/mapper/vendor-mapper.ts191
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
});
}