diff options
| author | joonhoekim <26rote@gmail.com> | 2025-10-17 14:02:09 +0900 |
|---|---|---|
| committer | joonhoekim <26rote@gmail.com> | 2025-10-17 14:02:09 +0900 |
| commit | 776699c13e967dd9db61571bb917f4a4f7aa618d (patch) | |
| tree | 0abb6659cb1af6dc150b0a2d5abd0c3a21659762 /app | |
| parent | 0ee0f102634dd703aea7ad0b8a338eb5e9bdadab (diff) | |
(김준회) RFQ/Bidding ECC 삭제 요청 처리 대응, 생성/삭제 모두 트랜잭션 처리
Diffstat (limited to 'app')
| -rw-r--r-- | app/api/(S-ERP)/(ECC)/IF_ECC_EVCP_PR_INFORMATION/route.ts | 197 |
1 files changed, 161 insertions, 36 deletions
diff --git a/app/api/(S-ERP)/(ECC)/IF_ECC_EVCP_PR_INFORMATION/route.ts b/app/api/(S-ERP)/(ECC)/IF_ECC_EVCP_PR_INFORMATION/route.ts index 012f47fc..3cee4b42 100644 --- a/app/api/(S-ERP)/(ECC)/IF_ECC_EVCP_PR_INFORMATION/route.ts +++ b/app/api/(S-ERP)/(ECC)/IF_ECC_EVCP_PR_INFORMATION/route.ts @@ -1,9 +1,12 @@ import { NextRequest } from 'next/server'; import db from '@/db/db'; +import { eq } from 'drizzle-orm'; import { PR_INFORMATION_T_BID_HEADER, PR_INFORMATION_T_BID_ITEM, } from '@/db/schema/ECC/ecc'; +import { rfqsLast, rfqPrItems } from '@/db/schema/rfqLast'; +import { biddings, prItemsForBidding, prDocuments } from '@/db/schema/bidding'; import { ToXMLFields, serveWsdl, @@ -19,10 +22,12 @@ import { bulkReplaceSubTableData } from "@/lib/soap/batch-utils"; import { - mapAndSaveECCRfqData + mapAndSaveECCRfqData, + deleteECCRfqData } from "@/lib/soap/ecc/mapper/rfq-and-pr-mapper"; import { - mapAndSaveECCBiddingData + mapAndSaveECCBiddingData, + deleteECCBiddingData } from "@/lib/soap/ecc/mapper/bidding-and-pr-mapper"; @@ -94,45 +99,165 @@ export async function POST(request: NextRequest) { } } - // 5) 원본 ECC 데이터 저장 (기존 로직 유지) - await saveToDatabase(processedData); + // 5) CHG_GB에 따라 Create/Delete 분기 처리 + // 전체 처리를 하나의 트랜잭션으로 묶어서 하나라도 실패하면 전부 롤백 + const chgGb = requestData.CHG_GB || 'C'; // 기본값은 Create + + await db.transaction(async (tx) => { + if (chgGb === 'D') { + // Delete 처리 + console.log('삭제 모드로 데이터 처리 시작 (트랜잭션)'); + + // ZBSART에 따라 삭제할 데이터 분류 + const anHeaders: BidHeaderData[] = []; + const abHeaders: BidHeaderData[] = []; + + for (const prData of processedData) { + if (prData.bidHeader.ZBSART === 'AN') { + anHeaders.push(prData.bidHeader); + } else if (prData.bidHeader.ZBSART === 'AB') { + abHeaders.push(prData.bidHeader); + } + } - // 6) ZBSART에 따라 비즈니스 테이블 분기 처리 - const anHeaders: BidHeaderData[] = []; - const abHeaders: BidHeaderData[] = []; - const anItems: BidItemData[] = []; - const abItems: BidItemData[] = []; + let deletedRfqCount = 0; + let deletedBiddingCount = 0; + + // AN (RFQ) 데이터 삭제 - 트랜잭션 내에서 직접 처리 + if (anHeaders.length > 0) { + for (const eccHeader of anHeaders) { + const anfnr = eccHeader.ANFNR; + if (!anfnr) { + console.error('삭제할 ANFNR이 없음', { eccHeader }); + continue; + } + + // 해당 ANFNR의 RFQ 찾기 + const existingRfq = await tx + .select({ id: rfqsLast.id, rfqCode: rfqsLast.rfqCode }) + .from(rfqsLast) + .where(eq(rfqsLast.ANFNR, anfnr)) + .limit(1); + + if (existingRfq.length === 0) { + console.log(`ANFNR ${anfnr}에 해당하는 RFQ가 존재하지 않음`); + continue; + } + + const rfqId = existingRfq[0].id; + const rfqCode = existingRfq[0].rfqCode; + + if (!rfqCode) { + console.error('RFQ 코드가 없는 데이터는 건너뜀', { rfqId }); + continue; + } + + // rfqPrItems 삭제 + await tx + .delete(rfqPrItems) + .where(eq(rfqPrItems.rfqsLastId, rfqId)); + + // rfqsLast 삭제 + await tx + .delete(rfqsLast) + .where(eq(rfqsLast.id, rfqId)); + + deletedRfqCount++; + console.log(`RFQ ${rfqCode} 삭제 완료`); + } + } - // ZBSART에 따라 데이터 분류 - for (const prData of processedData) { - if (prData.bidHeader.ZBSART === 'AN') { - anHeaders.push(prData.bidHeader); - anItems.push(...prData.bidItems); - } else if (prData.bidHeader.ZBSART === 'AB') { - abHeaders.push(prData.bidHeader); - abItems.push(...prData.bidItems); - } - } + // AB (Bidding) 데이터 삭제 - 트랜잭션 내에서 직접 처리 + if (abHeaders.length > 0) { + for (const eccHeader of abHeaders) { + const anfnr = eccHeader.ANFNR; + if (!anfnr) { + console.error('삭제할 ANFNR이 없음', { eccHeader }); + continue; + } + + // 해당 ANFNR의 Bidding 찾기 + const existingBidding = await tx + .select({ id: biddings.id, biddingNumber: biddings.biddingNumber }) + .from(biddings) + .where(eq(biddings.ANFNR, anfnr)) + .limit(1); + + if (existingBidding.length === 0) { + console.log(`ANFNR ${anfnr}에 해당하는 Bidding이 존재하지 않음`); + continue; + } + + const biddingId = existingBidding[0].id; + const biddingNumber = existingBidding[0].biddingNumber; + + // prItemsForBidding 삭제 + await tx + .delete(prItemsForBidding) + .where(eq(prItemsForBidding.biddingId, biddingId)); + + // prDocuments 삭제 + await tx + .delete(prDocuments) + .where(eq(prDocuments.biddingId, biddingId)); + + // biddings 삭제 + await tx + .delete(biddings) + .where(eq(biddings.id, biddingId)); + + deletedBiddingCount++; + console.log(`Bidding ${biddingNumber} 삭제 완료`); + } + } - // AN (RFQ) 데이터 처리 - rfqsLast 테이블 - let rfqMappingResult: { success: boolean; message: string; processedCount: number } | null = null; - if (anHeaders.length > 0) { - rfqMappingResult = await mapAndSaveECCRfqData(anHeaders, anItems); - if (!rfqMappingResult.success) { - throw new Error(`RFQ 비즈니스 테이블 매핑 실패: ${rfqMappingResult.message}`); - } - } + console.log(`🗑️ 삭제 완료 (트랜잭션): ${processedData.length}개 PR 데이터, ${deletedRfqCount}개 RFQ 삭제, ${deletedBiddingCount}개 Bidding 삭제`); + + } else { + // Create/Update 처리 (기존 로직) + console.log('생성/업데이트 모드로 데이터 처리 시작 (트랜잭션)'); + + // 5) 원본 ECC 데이터 저장 (기존 로직 유지) + await saveToDatabase(processedData); + + // 6) ZBSART에 따라 비즈니스 테이블 분기 처리 + const anHeaders: BidHeaderData[] = []; + const abHeaders: BidHeaderData[] = []; + const anItems: BidItemData[] = []; + const abItems: BidItemData[] = []; + + // ZBSART에 따라 데이터 분류 + for (const prData of processedData) { + if (prData.bidHeader.ZBSART === 'AN') { + anHeaders.push(prData.bidHeader); + anItems.push(...prData.bidItems); + } else if (prData.bidHeader.ZBSART === 'AB') { + abHeaders.push(prData.bidHeader); + abItems.push(...prData.bidItems); + } + } - // AB (Bidding) 데이터 처리 - let biddingMappingResult: { success: boolean; message: string; processedCount: number } | null = null; - if (abHeaders.length > 0) { - biddingMappingResult = await mapAndSaveECCBiddingData(abHeaders, abItems); - if (!biddingMappingResult.success) { - throw new Error(`Bidding 비즈니스 테이블 매핑 실패: ${biddingMappingResult.message}`); - } - } + // AN (RFQ) 데이터 처리 - rfqsLast 테이블 + let rfqMappingResult: { success: boolean; message: string; processedCount: number } | null = null; + if (anHeaders.length > 0) { + rfqMappingResult = await mapAndSaveECCRfqData(anHeaders, anItems); + if (!rfqMappingResult.success) { + throw new Error(`RFQ 비즈니스 테이블 매핑 실패: ${rfqMappingResult.message}`); + } + } - console.log(`🎉 처리 완료: ${processedData.length}개 PR 데이터, ${rfqMappingResult?.processedCount || 0}개 RFQ 매핑, ${biddingMappingResult?.processedCount || 0}개 Bidding 매핑`); + // AB (Bidding) 데이터 처리 + let biddingMappingResult: { success: boolean; message: string; processedCount: number } | null = null; + if (abHeaders.length > 0) { + biddingMappingResult = await mapAndSaveECCBiddingData(abHeaders, abItems); + if (!biddingMappingResult.success) { + throw new Error(`Bidding 비즈니스 테이블 매핑 실패: ${biddingMappingResult.message}`); + } + } + + console.log(`🎉 처리 완료 (트랜잭션): ${processedData.length}개 PR 데이터, ${rfqMappingResult?.processedCount || 0}개 RFQ 매핑, ${biddingMappingResult?.processedCount || 0}개 Bidding 매핑`); + } + }); // 6) 성공 응답 반환 return createSoapResponse('http://60.101.108.100/', { |
