import { NextRequest } from 'next/server'; import db from '@/db/db'; import { T_CHANGE_PR } from '@/db/schema/ECC/ecc'; import { ToXMLFields, serveWsdl, createXMLParser, extractRequestData, convertXMLToDBData, createSoapResponse, withSoapLogging, } from '@/lib/soap/utils'; // 단일 테이블 insert이므로 batch-utils는 불필요 type ChangeData = typeof T_CHANGE_PR.$inferInsert; // GET 요청 처리는 ?wsdl 달고 있으면 WSDL 서비스 제공 export async function GET(request: NextRequest) { const url = new URL(request.url); if (url.searchParams.has('wsdl')) { return serveWsdl('IF_ECC_EVCP_REJECT_FOR_REVISED_PR.wsdl'); } return new Response('Method Not Allowed', { status: 405 }); } // POST 요청이 데이터 적재 요구 (SOAP) export async function POST(request: NextRequest) { const url = new URL(request.url); if (url.searchParams.has('wsdl')) { return serveWsdl('IF_ECC_EVCP_REJECT_FOR_REVISED_PR.wsdl'); } const body = await request.text(); // SOAP 로깅 래퍼 함수 사용 return withSoapLogging( 'INBOUND', 'ECC', 'IF_ECC_EVCP_REJECT_FOR_REVISED_PR', body, async () => { console.log('🚀 REJECT_FOR_REVISED_PR 수신 시작, 데이터 길이:', body.length); // 1) XML 파싱 const parser = createXMLParser(['T_CHANGE_PR']); const parsedData = parser.parse(body); // 2) SOAP Body 또는 루트에서 요청 데이터 추출 const requestData = extractRequestData(parsedData, 'IF_ECC_EVCP_REJECT_FOR_REVISED_PRReq'); if (!requestData) { console.error('유효한 요청 데이터를 찾을 수 없습니다'); throw new Error('Missing request data - IF_ECC_EVCP_REJECT_FOR_REVISED_PRReq not found'); } // 3) XML 데이터를 DB 삽입 가능한 형태로 변환 const processedData = transformRejectData(requestData as RejectRequestXML); // 4) 필수 필드 검증 for (const changeData of processedData) { if (!changeData.BANFN || !changeData.BANPO || !changeData.ZCHG_NO) { throw new Error('Missing required fields: BANFN, BANPO, ZCHG_NO'); } } // 5) 데이터베이스 저장 await saveToDatabase(processedData); console.log(`🎉 처리 완료: ${processedData.length}개 PR 거부 데이터`); // 6) 성공 응답 반환 return createSoapResponse('http://60.101.108.100/', { 'tns:IF_ECC_EVCP_REJECT_FOR_REVISED_PRRes': { EV_TYPE: 'S', EV_MESSAGE: 'Success', }, }); } ).catch((error) => { // withSoapLogging에서 이미 에러 로그를 처리하므로, 여기서는 응답만 생성 return createSoapResponse('http://60.101.108.100/', { 'tns:IF_ECC_EVCP_REJECT_FOR_REVISED_PRRes': { EV_TYPE: 'E', EV_MESSAGE: error instanceof Error ? error.message.slice(0, 100) : 'Unknown error', }, }); }); } // ----------------------------------------------------------------------------- // 데이터 변환 및 저장 관련 유틸리티 // ----------------------------------------------------------------------------- // XML 구조 타입 정의 type ChangeDataXML = ToXMLFields>; // Root XML Request 타입 type RejectRequestXML = { IV_ERDAT?: string; // Reject Date (메타데이터, 저장하지 않음) IV_ERZET?: string; // Reject Time (메타데이터, 저장하지 않음) T_CHANGE_PR?: ChangeDataXML[]; }; // XML -> DB 데이터 변환 함수 function transformRejectData(requestData: RejectRequestXML): ChangeData[] { const changeItems = requestData.T_CHANGE_PR || []; return changeItems.map((item) => { // Change 데이터 변환 (단일 테이블이므로 간단함) const changeDataConverted = convertXMLToDBData( item as Record, undefined // 단일 테이블이므로 FK 데이터 불필요 ); return changeDataConverted; }); } // 데이터베이스 저장 함수 async function saveToDatabase(processedChanges: ChangeData[]) { console.log(`데이터베이스(배치) 저장 시작: ${processedChanges.length}개 PR 거부 데이터`); try { await db.transaction(async (tx) => { // 필수 키 필드가 있는 데이터만 필터링 const validChangeRows = processedChanges.filter((change): change is ChangeData => !!change.BANFN && !!change.BANPO && !!change.ZCHG_NO ); // T_CHANGE_PR 테이블에 UPSERT (배치) // BANFN + BANPO + ZCHG_NO 조합을 unique 키로 사용 if (validChangeRows.length > 0) { await tx.insert(T_CHANGE_PR).values(validChangeRows); } }); console.log(`데이터베이스(배치) 저장 완료: ${processedChanges.length}개 PR 거부`); return true; } catch (error) { console.error('데이터베이스(배치) 저장 중 오류 발생:', error); throw error; } }