diff options
Diffstat (limited to 'lib/dolce/actions.ts')
| -rw-r--r-- | lib/dolce/actions.ts | 258 |
1 files changed, 220 insertions, 38 deletions
diff --git a/lib/dolce/actions.ts b/lib/dolce/actions.ts index 552a9a6a..8c5dfa1b 100644 --- a/lib/dolce/actions.ts +++ b/lib/dolce/actions.ts @@ -172,7 +172,7 @@ async function dolceApiCall<T>(endpoint: string, body: Record<string, unknown>): }); if (!response.ok) { - throw new Error(`DOLCE API 오류 (${endpoint}): ${response.status} ${response.statusText}`); + throw new Error(`DOLCE API error (${endpoint}): ${response.status} ${response.statusText}`); } const data = await response.json(); @@ -356,7 +356,7 @@ export async function downloadDolceFile(params: { if (!response.ok) { const errorText = await response.text(); console.error("[DOLCE] 에러 응답:", errorText); - throw new Error(`파일 다운로드 실패: ${response.status} - ${errorText}`); + throw new Error(`File download failed: ${response.status} - ${errorText}`); } // HTML/텍스트 응답인 경우 에러일 수 있음 @@ -364,7 +364,7 @@ export async function downloadDolceFile(params: { if (contentType.includes("text") || contentType.includes("html")) { const errorText = await response.text(); console.error("[DOLCE] 텍스트 응답 (에러):", errorText); - throw new Error(`예상치 못한 응답: ${errorText.substring(0, 200)}`); + throw new Error(`Unexpected response: ${errorText.substring(0, 200)}`); } const blob = await response.blob(); @@ -387,7 +387,7 @@ export async function getVendorSessionInfo() { try { const session = await getServerSession(authOptions); if (!session?.user) { - throw new Error("로그인이 필요합니다"); + throw new Error("Login required"); } // DB에서 사용자 정보 조회 @@ -403,7 +403,7 @@ export async function getVendorSessionInfo() { }); if (!userInfo || !userInfo.companyId) { - throw new Error("벤더 정보를 찾을 수 없습니다"); + throw new Error("Vendor information not found"); } // 벤더 정보 조회 @@ -417,7 +417,7 @@ export async function getVendorSessionInfo() { }); if (!vendorInfo) { - throw new Error("벤더 정보를 찾을 수 없습니다"); + throw new Error("Vendor information not found"); } // GTT 벤더 확인 (A0016193) @@ -582,7 +582,7 @@ export async function uploadFilesToDetailDrawing( const fileCount = parseInt(formData.get("fileCount") as string); if (!uploadId || !userId || !fileCount) { - throw new Error("필수 파라미터가 누락되었습니다"); + throw new Error("Required parameters are missing"); } const uploadResults: Array<{ @@ -629,7 +629,7 @@ export async function uploadFilesToDetailDrawing( if (!uploadResponse.ok) { throw new Error( - `파일 업로드 실패: ${uploadResponse.status} ${uploadResponse.statusText}` + `File upload failed: ${uploadResponse.status} ${uploadResponse.statusText}` ); } @@ -661,13 +661,13 @@ export async function uploadFilesToDetailDrawing( if (!resultResponse.ok) { throw new Error( - `업로드 완료 통지 실패: ${resultResponse.status} ${resultResponse.statusText}` + `Upload notification failed: ${resultResponse.status} ${resultResponse.statusText}` ); } const resultText = await resultResponse.text(); if (resultText !== "Success") { - throw new Error(`업로드 완료 통지 실패: ${resultText}`); + throw new Error(`Upload notification failed: ${resultText}`); } return { @@ -678,7 +678,7 @@ export async function uploadFilesToDetailDrawing( console.error("파일 업로드 실패:", error); return { success: false, - error: error instanceof Error ? error.message : "알 수 없는 오류", + error: error instanceof Error ? error.message : "Unknown error", }; } } @@ -747,7 +747,7 @@ async function parseB4FileName(fileName: string): Promise<{ try { const lastDotIndex = fileName.lastIndexOf("."); if (lastDotIndex === -1) { - return { valid: false, error: "파일 확장자가 없습니다" }; + return { valid: false, error: "File extension is missing" }; } const nameWithoutExt = fileName.substring(0, lastDotIndex); @@ -756,7 +756,7 @@ async function parseB4FileName(fileName: string): Promise<{ if (parts.length < 3) { return { valid: false, - error: `공백이 최소 2개 있어야 합니다 (현재: ${parts.length - 1}개)`, + error: `At least 2 spaces required (current: ${parts.length - 1})`, }; } @@ -765,30 +765,212 @@ async function parseB4FileName(fileName: string): Promise<{ const drawingNo = drawingTokens.join("-"); if (!drawingNo || !revNo) { - return { valid: false, error: "도면번호 또는 리비전번호가 비어있습니다" }; + return { valid: false, error: "Drawing number or revision number is empty" }; } return { valid: true, drawingNo: drawingNo.trim(), revNo: revNo.trim() }; } catch (error) { return { valid: false, - error: error instanceof Error ? error.message : "알 수 없는 오류", + error: error instanceof Error ? error.message : "Unknown error", }; } } /** - * B4 파일 일괄 업로드 V2 + * B4 일괄 업로드를 위한 상세도면 준비 (V2) * - * MatchBatchFileDwg/MatchBatchFileDwgEdit API 대신 - * DetailDwgReceiptMgmtEdit API와 업로드 서비스만 사용 + * 반환값: DrawingNo + RevNo별 UploadId 정보 + * 파일 업로드는 클라이언트에서 직접 처리 + */ +export interface B4DetailDrawingInfo { + drawingNo: string; + revNo: string; + uploadId: string; + isNew: boolean; // 새로 생성된 상세도면인지 여부 + drawingName?: string; + discipline?: string; +} + +export async function prepareB4DetailDrawingsV2(params: { + projectNo: string; + userId: string; + userNm: string; + email: string; + vendorCode: string; + registerKind: string; + drawingRevisions: Array<{ drawingNo: string; revNo: string }>; +}): Promise<{ + success: boolean; + detailDrawings?: B4DetailDrawingInfo[]; + error?: string; +}> { + try { + console.log("[V2 Prepare] 상세도면 준비 시작"); + + const { projectNo, userId, userNm, email, vendorCode, registerKind, drawingRevisions } = params; + + const detailDrawings: B4DetailDrawingInfo[] = []; + + // 중복 제거: 동일한 DrawingNo + RevNo 조합은 1번만 처리 + const uniqueRevisions = Array.from( + new Map( + drawingRevisions.map((r) => [`${r.drawingNo}_${r.revNo}`, r]) + ).values() + ); + + if (uniqueRevisions.length !== drawingRevisions.length) { + console.warn( + `[V2 Prepare] 중복 제거: ${drawingRevisions.length}개 → ${uniqueRevisions.length}개` + ); + } + + console.log(`[V2 Prepare] 처리할 리비전: ${uniqueRevisions.length}개`); + + // DrawingNo별로 그룹화 + const drawingNoSet = new Set(uniqueRevisions.map((r) => r.drawingNo)); + const drawingInfoMap = new Map<string, GttDwgReceiptItem>(); + + // 1. 기본 도면 정보 조회 + for (const drawingNo of drawingNoSet) { + try { + const dwgList = await fetchDwgReceiptList({ + project: projectNo, + drawingKind: "B4", + drawingMoveGbn: "도면입수", + drawingNo: drawingNo, + }); + + const dwgInfo = dwgList.find( + (d) => (d as GttDwgReceiptItem).DrawingNo === drawingNo + ) as GttDwgReceiptItem | undefined; + + if (dwgInfo) { + drawingInfoMap.set(drawingNo, dwgInfo); + } + } catch (error) { + console.error(`[V2 Prepare] 도면 정보 조회 실패: ${drawingNo}`, error); + } + } + + // 2. 각 RevNo별로 상세도면 확인/생성 (중복 제거된 리스트 사용) + for (const { drawingNo, revNo } of uniqueRevisions) { + try { + const drawingInfo = drawingInfoMap.get(drawingNo); + if (!drawingInfo) { + throw new Error(`Drawing information not found: ${drawingNo}`); + } + + console.log(`[V2 Prepare] 처리 중: ${drawingNo} Rev.${revNo}`); + + // 기존 상세도면 조회 + const detailDwgList = await fetchDetailDwgReceiptList({ + project: projectNo, + drawingNo: drawingNo, + discipline: drawingInfo.Discipline, + drawingKind: "B4", + userId: userId, + }); + + // 해당 RevNo의 상세도면 찾기 + const existingDetail = detailDwgList.find( + (d) => d.DrawingRevNo === revNo + ); + + let uploadId: string; + let isNew = false; + + if (existingDetail) { + // 1. 기존 상세도면이 있는 경우: 해당 uploadId 재사용 + uploadId = existingDetail.UploadId; + isNew = false; + console.log( + `[V2 Prepare] ✓ 기존 상세도면 재사용: ${drawingNo} Rev.${revNo}, UploadId: ${uploadId}` + ); + } else { + // 2. 상세도면이 없는 경우: 새로 1번만 생성 + uploadId = crypto.randomUUID(); + isNew = true; + console.log( + `[V2 Prepare] ✓ 새 상세도면 생성: ${drawingNo} Rev.${revNo}, UploadId: ${uploadId}` + ); + + const category = detailDwgList.length > 0 ? detailDwgList[0].Category : "NORM"; + + const addRequest: DetailDwgEditRequest = { + Mode: "ADD", + Status: "01", + RegisterId: 0, + ProjectNo: projectNo, + Discipline: drawingInfo.Discipline, + DrawingKind: "B4", + DrawingNo: drawingNo, + DrawingName: drawingInfo.DrawingName, + RegisterGroupId: drawingInfo.RegisterGroupId, + RegisterSerialNo: drawingInfo.RegisterGroup, + RegisterKind: registerKind, + DrawingRevNo: revNo, + Category: category, + Receiver: null, + Manager: drawingInfo.Manager || "970043", + RegisterDesc: "", + UploadId: uploadId, + RegCompanyCode: vendorCode, + }; + + await editDetailDwgReceipt({ + dwgList: [addRequest], + userId: userId, + userNm: userNm, + vendorCode: vendorCode, + email: email, + }); + + console.log(`[V2 Prepare] ✓ DetailDwgReceiptMgmtEdit 호출 완료`); + } + + detailDrawings.push({ + drawingNo, + revNo, + uploadId, + isNew, + drawingName: drawingInfo.DrawingName, + discipline: drawingInfo.Discipline, + }); + } catch (error) { + console.error( + `[V2 Prepare] ✗ 상세도면 준비 실패: ${drawingNo} Rev.${revNo}`, + error + ); + throw error; + } + } + + const newCount = detailDrawings.filter((d) => d.isNew).length; + const existingCount = detailDrawings.length - newCount; + + console.log( + `[V2 Prepare] ✓ 완료: 총 ${detailDrawings.length}개 (신규: ${newCount}개, 기존: ${existingCount}개)` + ); + + return { + success: true, + detailDrawings, + }; + } catch (error) { + console.error("[V2 Prepare] 실패:", error); + return { + success: false, + error: error instanceof Error ? error.message : "Unknown error", + }; + } +} + +/** + * B4 파일 일괄 업로드 V2 (레거시 - 사용 안 함) * - * 프로세스: - * 1. 파일명 파싱하여 DrawingNo, RevNo 추출 - * 2. 기존 도면 정보 조회 (fetchDwgReceiptList) - * 3. 기존 상세도면 조회 (fetchDetailDwgReceiptList) - * 4. 없으면 ADD, 있으면 기존 UploadId 사용 - * 5. 파일 업로드 (/api/dolce/upload-files) + * @deprecated 서버 액션에서 fetch 호출 시 상대 경로 문제로 사용 중단 + * 대신 prepareB4DetailDrawingsV2 + 클라이언트 uploadFilesWithProgress 사용 */ export async function bulkUploadB4FilesV2( formData: FormData @@ -806,7 +988,7 @@ export async function bulkUploadB4FilesV2( const fileCount = parseInt(formData.get("fileCount") as string); if (!projectNo || !userId || !userNm || !email || !vendorCode || !registerKind || !fileCount) { - throw new Error("필수 파라미터가 누락되었습니다"); + throw new Error("Required parameters are missing"); } console.log(`[V2] 프로젝트: ${projectNo}, 사용자: ${userId}, 파일 수: ${fileCount}`); @@ -843,7 +1025,7 @@ export async function bulkUploadB4FilesV2( revNo: "", fileName: file.name, success: false, - error: parseResult.error || "파일명 파싱 실패", + error: parseResult.error || "Failed to parse filename", }); failCount++; continue; @@ -922,7 +1104,7 @@ export async function bulkUploadB4FilesV2( // 도면 정보가 없으면 실패 if (!drawingInfo) { - throw new Error(`도면 정보를 찾을 수 없습니다: ${drawingNo}`); + throw new Error(`Drawing information not found: ${drawingNo}`); } // 4-1. 기존 상세도면 조회 @@ -1009,13 +1191,13 @@ export async function bulkUploadB4FilesV2( if (!uploadResponse.ok) { const errorData = await uploadResponse.json(); - throw new Error(errorData.error || `파일 업로드 실패: ${uploadResponse.status}`); + throw new Error(errorData.error || `File upload failed: ${uploadResponse.status}`); } const uploadResult = await uploadResponse.json(); if (!uploadResult.success) { - throw new Error(uploadResult.error || "파일 업로드 실패"); + throw new Error(uploadResult.error || "File upload failed"); } console.log(`[V2] 파일 업로드 완료: ${groupKey}`); @@ -1033,7 +1215,7 @@ export async function bulkUploadB4FilesV2( } catch (error) { // 실패 처리 const errorMessage = - error instanceof Error ? error.message : "알 수 없는 오류"; + error instanceof Error ? error.message : "Unknown error"; console.error(`[V2] 그룹 처리 실패: ${groupKey}`, error); @@ -1062,7 +1244,7 @@ export async function bulkUploadB4FilesV2( console.error("[V2] 일괄 업로드 실패:", error); return { success: false, - error: error instanceof Error ? error.message : "알 수 없는 오류", + error: error instanceof Error ? error.message : "Unknown error", }; } } @@ -1082,7 +1264,7 @@ export async function bulkUploadB4Files( const registerKind = formData.get("registerKind") as string; if (!projectNo || !userId || !fileCount || !registerKind) { - throw new Error("필수 파라미터가 누락되었습니다"); + throw new Error("Required parameters are missing"); } const results: Array<{ @@ -1176,7 +1358,7 @@ export async function bulkUploadB4Files( if (!uploadResponse.ok) { throw new Error( - `파일 업로드 실패: ${uploadResponse.status} ${uploadResponse.statusText}` + `File upload failed: ${uploadResponse.status} ${uploadResponse.statusText}` ); } @@ -1208,13 +1390,13 @@ export async function bulkUploadB4Files( if (!resultResponse.ok) { throw new Error( - `업로드 완료 통지 실패: ${resultResponse.status} ${resultResponse.statusText}` + `Upload notification failed: ${resultResponse.status} ${resultResponse.statusText}` ); } const resultText = await resultResponse.text(); if (resultText !== "Success") { - throw new Error(`업로드 완료 통지 실패: ${resultText}`); + throw new Error(`Upload notification failed: ${resultText}`); } // 4. 매핑 현황 재조회 (MatchBatchFileDwg) @@ -1228,7 +1410,7 @@ export async function bulkUploadB4Files( const mappingData = mappingCheckResults[0]; if (!mappingData || mappingData.RegisterGroupId === 0) { - throw new Error("매핑 정보를 찾을 수 없습니다"); + throw new Error("Mapping information not found"); } // 5. 매핑 정보 저장 (MatchBatchFileDwgEdit) @@ -1278,7 +1460,7 @@ export async function bulkUploadB4Files( } catch (error) { // 실패 처리 const errorMessage = - error instanceof Error ? error.message : "알 수 없는 오류"; + error instanceof Error ? error.message : "Unknown error"; for (const fileInfo of files) { results.push({ @@ -1303,7 +1485,7 @@ export async function bulkUploadB4Files( console.error("일괄 업로드 실패:", error); return { success: false, - error: error instanceof Error ? error.message : "알 수 없는 오류", + error: error instanceof Error ? error.message : "Unknown error", }; } } |
