diff options
Diffstat (limited to 'lib/soap/ecc')
| -rw-r--r-- | lib/soap/ecc/mapper/bidding-and-pr-mapper.ts | 6 | ||||
| -rw-r--r-- | lib/soap/ecc/mapper/common-mapper-utils.ts | 35 | ||||
| -rw-r--r-- | lib/soap/ecc/mapper/rfq-and-pr-mapper.ts | 33 |
3 files changed, 61 insertions, 13 deletions
diff --git a/lib/soap/ecc/mapper/bidding-and-pr-mapper.ts b/lib/soap/ecc/mapper/bidding-and-pr-mapper.ts index 4ab9a745..adbb3e1e 100644 --- a/lib/soap/ecc/mapper/bidding-and-pr-mapper.ts +++ b/lib/soap/ecc/mapper/bidding-and-pr-mapper.ts @@ -29,6 +29,7 @@ import { findMaterialNameByMATNR, parseSAPDateTime, parseSAPDateToString, + findSpecificationByMATNR, } from './common-mapper-utils'; // Note: POS 파일은 온디맨드 방식으로 다운로드됩니다. // 자동 동기화 관련 import는 제거되었습니다. @@ -267,6 +268,9 @@ export async function mapECCBiddingItemToPrItemForBidding( // PSPID(Project Code)로 프로젝트 ID 조회 const projectId = await findProjectIdByPSPID(eccItem.PSPID || null); + // Specification 조회 (MATNR 기반) + const specification = await findSpecificationByMATNR(eccItem.MATNR || null); + const mappedData: PrItemForBiddingData = { biddingId, // 부모 Bidding ID itemNumber: eccItem.ANFPS || null, // 아이템 번호 @@ -305,12 +309,14 @@ export async function mapECCBiddingItemToPrItemForBidding( prNumber: eccItem.BANFN || null, // PR번호 hasSpecDocument: false, // 기본값 false + specification, // MATNR로 조회한 Specification }; debugSuccess('ECC Bidding 아이템 매핑 완료', { itemNumber: eccItem.ANFPS, prNumber: eccItem.BANFN, projectId, + specification, }); return mappedData; } diff --git a/lib/soap/ecc/mapper/common-mapper-utils.ts b/lib/soap/ecc/mapper/common-mapper-utils.ts index ed655e0e..9141a29f 100644 --- a/lib/soap/ecc/mapper/common-mapper-utils.ts +++ b/lib/soap/ecc/mapper/common-mapper-utils.ts @@ -14,7 +14,7 @@ import { debugLog, debugSuccess, debugError } from '@/lib/debug-utils'; import db from '@/db/db'; import { users, vendors } from '@/db/schema'; import { projects } from '@/db/schema/projects'; -import { EQUP_MASTER_MATL_CHARASGN } from '@/db/schema/MDG/mdg'; +import { EQUP_MASTER_MATL_CHARASGN, MATERIAL_MASTER_PART_MATL } from '@/db/schema/MDG/mdg'; import { eq } from 'drizzle-orm'; import { oracleKnex } from '@/lib/oracle-db/db'; @@ -386,4 +386,37 @@ export async function findVendorIdByLIFNR(lifnr: string | null | undefined): Pro debugError('Vendor 조회 중 오류 발생', { lifnr, error }); return null; } +} + +/** + * Specification 조회 함수 (MATNR 기반) + * MATNR을 기반으로 MATERIAL_MASTER_PART_MATL 테이블에서 ZZSPEC 조회 + */ +export async function findSpecificationByMATNR(MATNR: string | null): Promise<string | null> { + try { + debugLog('Specification 조회 시작', { MATNR }); + + if (!MATNR) { + debugError('MATNR이 null 또는 undefined', { MATNR }); + return null; + } + + const specResult = await db + .select({ ZZSPEC: MATERIAL_MASTER_PART_MATL.ZZSPEC }) + .from(MATERIAL_MASTER_PART_MATL) + .where(eq(MATERIAL_MASTER_PART_MATL.MATNR, MATNR)) + .limit(1); + + if (specResult.length === 0) { + debugLog('MATNR에 해당하는 Specification을 찾을 수 없음', { MATNR }); + return null; + } + + const specification = specResult[0].ZZSPEC; + debugSuccess('Specification 조회 완료', { MATNR, specification }); + return specification; + } catch (error) { + debugError('Specification 조회 중 오류 발생', { MATNR, error }); + return null; + } }
\ No newline at end of file diff --git a/lib/soap/ecc/mapper/rfq-and-pr-mapper.ts b/lib/soap/ecc/mapper/rfq-and-pr-mapper.ts index d08bc5fb..c0557d0c 100644 --- a/lib/soap/ecc/mapper/rfq-and-pr-mapper.ts +++ b/lib/soap/ecc/mapper/rfq-and-pr-mapper.ts @@ -25,6 +25,7 @@ import { findProjectInfoByPSPID, parseSAPDateTime, findUserInfoByPERNR, + findSpecificationByMATNR, } from './common-mapper-utils'; // ECC 데이터 타입 정의 @@ -241,11 +242,11 @@ export async function mapECCRfqHeaderToRfqLast( /** * ECC RFQ 아이템 데이터를 rfqPrItems 테이블로 매핑 */ -export function mapECCRfqItemToRfqPrItem( +export async function mapECCRfqItemToRfqPrItem( eccItem: ECCBidItem, rfqId: number, isMajor: boolean = false -): RfqPrItemData { +): Promise<RfqPrItemData> { debugLog('ECC RFQ 아이템 매핑 시작', { anfnr: eccItem.ANFNR, anfps: eccItem.ANFPS, @@ -269,6 +270,9 @@ export function mapECCRfqItemToRfqPrItem( } } + // Specification 조회 (MATNR 기반) + const specification = await findSpecificationByMATNR(eccItem.MATNR || null); + const mappedData: RfqPrItemData = { rfqsLastId: rfqId, // 부모 RFQ ID rfqItem: eccItem.ANFPS || null, // RFQ Item 번호 @@ -286,6 +290,7 @@ export function mapECCRfqItemToRfqPrItem( gwUom: eccItem.GEWEI || null, // 중량단위 specNo: null, // ECC에서 제공되지 않음 specUrl: null, // ECC에서 제공되지 않음 + specification, // MATNR로 조회한 Specification trackingNo: null, // ECC에서 제공되지 않음 majorYn: isMajor, // ZCON_NO_PO와 BANFN이 같은 경우 true projectDef: eccItem.PSPID || null, // 프로젝트 정의 @@ -299,6 +304,7 @@ export function mapECCRfqItemToRfqPrItem( debugSuccess('ECC RFQ 아이템 매핑 완료', { rfqItem: eccItem.ANFPS, materialCode: eccItem.MATNR, + specification, }); return mappedData; } @@ -363,7 +369,7 @@ export async function mapAndSaveECCRfqDataToRfqLast( // 4) 모든 새로 삽입된 레코드의 ID 매핑은 이미 완료됨 - // 5) 모든 아이템을 한 번에 생성할 데이터로 변환 + // 5) 모든 아이템을 한 번에 생성할 데이터로 변환 (async 함수로 병렬 처리) const allItemsToInsert: RfqPrItemData[] = []; for (const group of rfqGroups) { const rfqCode = group.rfqCode; @@ -374,15 +380,18 @@ export async function mapAndSaveECCRfqDataToRfqLast( throw new Error(`RFQ ID를 찾을 수 없습니다: ${rfqCode}`); } - for (const eccItem of group.relatedItems) { - // ZCON_NO_PO와 BANFN이 같은 경우 majorYn을 true로 설정 - const isMajor: boolean = !!(eccItem.ZCON_NO_PO && - eccItem.ZCON_NO_PO.trim() && - eccItem.BANFN === eccItem.ZCON_NO_PO.trim()); - - const itemData = mapECCRfqItemToRfqPrItem(eccItem, rfqId, isMajor); - allItemsToInsert.push(itemData); - } + // 각 아이템을 병렬로 매핑 (async 함수로 변경되었으므로) + const itemsData = await Promise.all( + group.relatedItems.map(async eccItem => { + // ZCON_NO_PO와 BANFN이 같은 경우 majorYn을 true로 설정 + const isMajor: boolean = !!(eccItem.ZCON_NO_PO && + eccItem.ZCON_NO_PO.trim() && + eccItem.BANFN === eccItem.ZCON_NO_PO.trim()); + + return await mapECCRfqItemToRfqPrItem(eccItem, rfqId, isMajor); + }) + ); + allItemsToInsert.push(...itemsData); } // 5) 아이템 일괄 삽입 (chunk 처리로 파라미터 제한 회피) |
