summaryrefslogtreecommitdiff
path: root/lib/vendor-document-list/dolce-upload-service.ts
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-08-14 11:54:47 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-08-14 11:54:47 +0000
commit969c25b56f6d29d7ffa4bc2ce04c5fb4e5846b34 (patch)
tree551d335e850e6163792ded0e7a75fa41d96d612a /lib/vendor-document-list/dolce-upload-service.ts
parentdd20ba9785cdbd3d61f6b014d003d3bd9646ad13 (diff)
(대표님) 정규벤더등록, 벤더문서관리, 벤더데이터입력, 첨부파일관리
Diffstat (limited to 'lib/vendor-document-list/dolce-upload-service.ts')
-rw-r--r--lib/vendor-document-list/dolce-upload-service.ts606
1 files changed, 318 insertions, 288 deletions
diff --git a/lib/vendor-document-list/dolce-upload-service.ts b/lib/vendor-document-list/dolce-upload-service.ts
index 2d6a83c6..84ae4525 100644
--- a/lib/vendor-document-list/dolce-upload-service.ts
+++ b/lib/vendor-document-list/dolce-upload-service.ts
@@ -5,6 +5,8 @@ import { eq, and, desc, sql, inArray, min } from "drizzle-orm"
import { v4 as uuidv4 } from "uuid"
import path from "path"
import * as crypto from "crypto"
+import { getServerSession } from "next-auth/next"
+import { authOptions } from "@/app/api/auth/[...nextauth]/route"
export interface DOLCEUploadResult {
success: boolean
@@ -87,7 +89,7 @@ interface DOLCEFileMapping {
function getFileReaderConfig(): FileReaderConfig {
const isProduction = process.env.NODE_ENV === "production";
-
+
if (isProduction) {
return {
baseDir: process.env.NAS_PATH || "/evcp_nas", // NAS 기본 경로
@@ -118,13 +120,13 @@ class DOLCEUploadService {
): Promise<DOLCEUploadResult> {
try {
console.log(`Starting DOLCE upload for contract ${projectId}, revisions: ${revisionIds.join(', ')}`)
-
+
// 1. 계약 정보 조회 (프로젝트 코드, 벤더 코드 등)
const contractInfo = await this.getContractInfo(projectId)
if (!contractInfo) {
throw new Error(`Contract info not found for ID: ${projectId}`)
}
-
+
// 2. 업로드할 리비전 정보 조회
const revisionsToUpload = await this.getRevisionsForUpload(revisionIds)
if (revisionsToUpload.length === 0) {
@@ -134,7 +136,7 @@ class DOLCEUploadService {
uploadedFiles: 0
}
}
-
+
let uploadedDocuments = 0
let uploadedFiles = 0
const errors: string[] = []
@@ -143,19 +145,19 @@ class DOLCEUploadService {
fileResults: [],
mappingResults: []
}
-
+
// 3. 각 리비전별로 처리
for (const revision of revisionsToUpload) {
try {
console.log(`Processing revision ${revision.revision} for document ${revision.documentNo}`)
-
+
// 3-1. UploadId 미리 생성 (파일이 있는 경우에만)
let uploadId: string | undefined
if (revision.attachments && revision.attachments.length > 0) {
uploadId = uuidv4() // 문서 업로드 시 사용할 UploadId 미리 생성
console.log(`Generated UploadId for document upload: ${uploadId}`)
}
-
+
// 3-2. 문서 정보 업로드 (UploadId 포함)
const dolceDoc = this.transformToDoLCEDocument(
revision,
@@ -163,43 +165,43 @@ class DOLCEUploadService {
uploadId, // 미리 생성된 UploadId 사용
contractInfo.vendorCode,
)
-
+
const docResult = await this.uploadDocument([dolceDoc], userId)
if (!docResult.success) {
errors.push(`Document upload failed for ${revision.documentNo}: ${docResult.error}`)
continue // 문서 업로드 실패 시 다음 리비전으로 넘어감
}
-
+
uploadedDocuments++
results.documentResults.push(docResult)
console.log(`✅ Document uploaded successfully: ${revision.documentNo}`)
-
+
// 3-3. 파일 업로드 (이미 생성된 UploadId 사용)
if (uploadId && revision.attachments && revision.attachments.length > 0) {
try {
// 파일 업로드 시 이미 생성된 UploadId 사용
const fileUploadResults = await this.uploadFiles(
- revision.attachments,
- userId,
+ revision.attachments,
+ userId,
uploadId // 이미 생성된 UploadId 전달
)
-
+
} catch (fileError) {
errors.push(`File upload failed for ${revision.documentNo}: ${fileError instanceof Error ? fileError.message : 'Unknown error'}`)
console.error(`❌ File upload failed for ${revision.documentNo}:`, fileError)
}
}
-
+
// 3-5. 성공한 리비전의 상태 업데이트
await this.updateRevisionStatus(revision.id, 'SUBMITTED', uploadId)
-
+
} catch (error) {
const errorMessage = `Failed to process revision ${revision.revision}: ${error instanceof Error ? error.message : 'Unknown error'}`
errors.push(errorMessage)
console.error(errorMessage, error)
}
}
-
+
return {
success: errors.length === 0,
uploadedDocuments,
@@ -207,7 +209,7 @@ class DOLCEUploadService {
errors: errors.length > 0 ? errors : undefined,
results
}
-
+
} catch (error) {
console.error('DOLCE upload failed:', error)
throw error
@@ -216,22 +218,34 @@ class DOLCEUploadService {
/**
* 계약 정보 조회
*/
- private async getContractInfo(projectId: number) {
+ private async getContractInfo(projectId: number): Promise<{
+ projectCode: string;
+ vendorCode: string;
+ } | null> {
+
+ const session = await getServerSession(authOptions)
+ if (!session?.user?.companyId) {
+ throw new Error("인증이 필요합니다.")
+ }
+
+
const [result] = await db
.select({
projectCode: projects.code,
- vendorCode: vendors.vendorCode,
- contractNo: contracts.contractNo
+ vendorCode: vendors.vendorCode
})
.from(contracts)
.innerJoin(projects, eq(contracts.projectId, projects.id))
.innerJoin(vendors, eq(contracts.vendorId, vendors.id))
- .where(eq(contracts.projectId, projectId))
+ .where(and(eq(contracts.projectId, projectId), eq(contracts.vendorId, Number(session.user.companyId))))
.limit(1)
- return result
+ return result?.projectCode && result?.vendorCode
+ ? { projectCode: result.projectCode, vendorCode: result.vendorCode }
+ : null
}
+
/**
* 각 issueStageId별로 첫 번째 revision 정보를 조회
*/
@@ -264,7 +278,7 @@ class DOLCEUploadService {
.select({
// revision 테이블 정보
id: revisions.id,
- registerId:revisions.registerId,
+ registerId: revisions.registerId,
revision: revisions.revision, // revisionNo가 아니라 revision
revisionStatus: revisions.revisionStatus,
uploaderId: revisions.uploaderId,
@@ -341,181 +355,181 @@ class DOLCEUploadService {
return revisionsWithAttachments
}
-/**
- * 파일 업로드 (PWPUploadService.ashx) - 수정된 버전
- * @param attachments 업로드할 첨부파일 목록
- * @param userId 사용자 ID
- * @param uploadId 이미 생성된 UploadId (문서 업로드 시 생성됨)
- */
-private async uploadFiles(
- attachments: any[],
- userId: string,
- uploadId: string // 이미 생성된 UploadId를 매개변수로 받음
-): Promise<Array<{ uploadId: string, fileId: string, filePath: string }>> {
- const uploadResults = []
- const resultDataArray: ResultData[] = []
+ /**
+ * 파일 업로드 (PWPUploadService.ashx) - 수정된 버전
+ * @param attachments 업로드할 첨부파일 목록
+ * @param userId 사용자 ID
+ * @param uploadId 이미 생성된 UploadId (문서 업로드 시 생성됨)
+ */
+ private async uploadFiles(
+ attachments: any[],
+ userId: string,
+ uploadId: string // 이미 생성된 UploadId를 매개변수로 받음
+ ): Promise<Array<{ uploadId: string, fileId: string, filePath: string }>> {
+ const uploadResults = []
+ const resultDataArray: ResultData[] = []
- for (let i = 0; i < attachments.length; i++) {
- const attachment = attachments[i]
- try {
- // FileId만 새로 생성 (UploadId는 이미 생성된 것 사용)
- const fileId = uuidv4()
+ for (let i = 0; i < attachments.length; i++) {
+ const attachment = attachments[i]
+ try {
+ // FileId만 새로 생성 (UploadId는 이미 생성된 것 사용)
+ const fileId = uuidv4()
- console.log(`Uploading file with predefined UploadId: ${uploadId}, FileId: ${fileId}`)
+ console.log(`Uploading file with predefined UploadId: ${uploadId}, FileId: ${fileId}`)
- // 파일 데이터 읽기
- const fileBuffer = await this.getFileBuffer(attachment.filePath)
+ // 파일 데이터 읽기
+ const fileBuffer = await this.getFileBuffer(attachment.filePath)
- const uploadUrl = `${this.UPLOAD_SERVICE_URL}?UploadId=${uploadId}&FileId=${fileId}`
+ const uploadUrl = `${this.UPLOAD_SERVICE_URL}?UploadId=${uploadId}&FileId=${fileId}`
- const response = await fetch(uploadUrl, {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/octet-stream',
- },
- body: fileBuffer
- })
+ const response = await fetch(uploadUrl, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/octet-stream',
+ },
+ body: fileBuffer
+ })
- if (!response.ok) {
- const errorText = await response.text()
- throw new Error(`File upload failed: HTTP ${response.status} - ${errorText}`)
- }
+ if (!response.ok) {
+ const errorText = await response.text()
+ throw new Error(`File upload failed: HTTP ${response.status} - ${errorText}`)
+ }
- const dolceFilePath = await response.text() // DOLCE에서 반환하는 파일 경로
-
- // 업로드 성공 후 documentAttachments 테이블 업데이트
- await db
- .update(documentAttachments)
- .set({
- uploadId: uploadId, // 이미 생성된 UploadId 사용
- fileId: fileId,
- uploadedBy: userId,
- dolceFilePath: dolceFilePath,
- uploadedAt: new Date(),
- updatedAt: new Date()
+ const dolceFilePath = await response.text() // DOLCE에서 반환하는 파일 경로
+
+ // 업로드 성공 후 documentAttachments 테이블 업데이트
+ await db
+ .update(documentAttachments)
+ .set({
+ uploadId: uploadId, // 이미 생성된 UploadId 사용
+ fileId: fileId,
+ uploadedBy: userId,
+ dolceFilePath: dolceFilePath,
+ uploadedAt: new Date(),
+ updatedAt: new Date()
+ })
+ .where(eq(documentAttachments.id, attachment.id))
+
+ uploadResults.push({
+ uploadId,
+ fileId,
+ filePath: dolceFilePath
})
- .where(eq(documentAttachments.id, attachment.id))
- uploadResults.push({
- uploadId,
- fileId,
- filePath: dolceFilePath
- })
-
- // ResultData 객체 생성 (PWPUploadResultService 호출용)
- const fileStats = await this.getFileStats(attachment.filePath) // 파일 통계 정보 조회
-
- const resultData: ResultData = {
- FileId: fileId,
- UploadId: uploadId,
- FileSeq: i + 1, // 1부터 시작하는 시퀀스
- FileName: attachment.fileName,
- FileRelativePath: dolceFilePath,
- FileSize: fileStats.size,
- FileCreateDT: fileStats.birthtime.toISOString(),
- FileWriteDT: fileStats.mtime.toISOString(),
- OwnerUserId: userId
- }
+ // ResultData 객체 생성 (PWPUploadResultService 호출용)
+ const fileStats = await this.getFileStats(attachment.filePath) // 파일 통계 정보 조회
+
+ const resultData: ResultData = {
+ FileId: fileId,
+ UploadId: uploadId,
+ FileSeq: i + 1, // 1부터 시작하는 시퀀스
+ FileName: attachment.fileName,
+ FileRelativePath: dolceFilePath,
+ FileSize: fileStats.size,
+ FileCreateDT: fileStats.birthtime.toISOString(),
+ FileWriteDT: fileStats.mtime.toISOString(),
+ OwnerUserId: userId
+ }
- resultDataArray.push(resultData)
+ resultDataArray.push(resultData)
- console.log(`✅ File uploaded successfully: ${attachment.fileName} -> ${dolceFilePath}`)
- console.log(`✅ DB updated for attachment ID: ${attachment.id}`)
+ console.log(`✅ File uploaded successfully: ${attachment.fileName} -> ${dolceFilePath}`)
+ console.log(`✅ DB updated for attachment ID: ${attachment.id}`)
- // 🧪 DOLCE 업로드 확인 테스트
- try {
- const testResult = await this.testDOLCEFileDownload(fileId, userId, attachment.fileName)
- if (testResult.success) {
- console.log(`✅ DOLCE 업로드 확인 성공: ${attachment.fileName}`)
- } else {
- console.warn(`⚠️ DOLCE 업로드 확인 실패: ${attachment.fileName} - ${testResult.error}`)
+ // 🧪 DOLCE 업로드 확인 테스트
+ try {
+ const testResult = await this.testDOLCEFileDownload(fileId, userId, attachment.fileName)
+ if (testResult.success) {
+ console.log(`✅ DOLCE 업로드 확인 성공: ${attachment.fileName}`)
+ } else {
+ console.warn(`⚠️ DOLCE 업로드 확인 실패: ${attachment.fileName} - ${testResult.error}`)
+ }
+ } catch (testError) {
+ console.warn(`⚠️ DOLCE 업로드 확인 중 오류: ${attachment.fileName}`, testError)
}
- } catch (testError) {
- console.warn(`⚠️ DOLCE 업로드 확인 중 오류: ${attachment.fileName}`, testError)
- }
- } catch (error) {
- console.error(`❌ File upload failed for ${attachment.fileName}:`, error)
- throw error
+ } catch (error) {
+ console.error(`❌ File upload failed for ${attachment.fileName}:`, error)
+ throw error
+ }
}
- }
- // 모든 파일 업로드가 완료된 후 PWPUploadResultService 호출
- if (resultDataArray.length > 0) {
- try {
- await this.finalizeUploadResult(resultDataArray)
- console.log(`✅ Upload result finalized for UploadId: ${uploadId}`)
- } catch (error) {
- console.error(`❌ Failed to finalize upload result for UploadId: ${uploadId}`, error)
- // 파일 업로드는 성공했지만 결과 저장 실패 - 로그만 남기고 계속 진행
+ // 모든 파일 업로드가 완료된 후 PWPUploadResultService 호출
+ if (resultDataArray.length > 0) {
+ try {
+ await this.finalizeUploadResult(resultDataArray)
+ console.log(`✅ Upload result finalized for UploadId: ${uploadId}`)
+ } catch (error) {
+ console.error(`❌ Failed to finalize upload result for UploadId: ${uploadId}`, error)
+ // 파일 업로드는 성공했지만 결과 저장 실패 - 로그만 남기고 계속 진행
+ }
}
+
+ return uploadResults
}
- return uploadResults
-}
+ private async finalizeUploadResult(resultDataArray: ResultData[]): Promise<void> {
+ const url = `${this.BASE_URL}/PWPUploadResultService.ashx?`
-private async finalizeUploadResult(resultDataArray: ResultData[]): Promise<void> {
- const url = `${this.BASE_URL}/PWPUploadResultService.ashx?`
-
- try {
- const jsonData = JSON.stringify(resultDataArray)
- const dataBuffer = Buffer.from(jsonData, 'utf-8')
+ try {
+ const jsonData = JSON.stringify(resultDataArray)
+ const dataBuffer = Buffer.from(jsonData, 'utf-8')
- console.log(`Calling PWPUploadResultService with ${resultDataArray.length} files`)
- console.log('ResultData:', JSON.stringify(resultDataArray, null, 2))
+ console.log(`Calling PWPUploadResultService with ${resultDataArray.length} files`)
+ console.log('ResultData:', JSON.stringify(resultDataArray, null, 2))
- const response = await fetch(url, {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: dataBuffer
- })
+ const response = await fetch(url, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: dataBuffer
+ })
- if (!response.ok) {
- const errorText = await response.text()
- throw new Error(`PWPUploadResultService failed: HTTP ${response.status} - ${errorText}`)
- }
+ if (!response.ok) {
+ const errorText = await response.text()
+ throw new Error(`PWPUploadResultService failed: HTTP ${response.status} - ${errorText}`)
+ }
- const result = await response.text()
-
- if (result !== 'Success') {
- console.log(result,"돌체 업로드 실패")
- throw new Error(`PWPUploadResultService returned unexpected result: ${result}`)
- }
+ const result = await response.text()
- console.log('✅ PWPUploadResultService call successful')
+ if (result !== 'Success') {
+ console.log(result, "돌체 업로드 실패")
+ throw new Error(`PWPUploadResultService returned unexpected result: ${result}`)
+ }
- } catch (error) {
- console.error('❌ PWPUploadResultService call failed:', error)
- throw error
- }
-}
+ console.log('✅ PWPUploadResultService call successful')
-// 파일 통계 정보 조회 헬퍼 메서드 (파일시스템에서 파일 정보를 가져옴)
-private async getFileStats(filePath: string): Promise<{ size: number, birthtime: Date, mtime: Date }> {
- try {
- // Node.js 환경이라면 fs.stat 사용
- const fs = require('fs').promises
- const stats = await fs.stat(filePath)
-
- return {
- size: stats.size,
- birthtime: stats.birthtime,
- mtime: stats.mtime
+ } catch (error) {
+ console.error('❌ PWPUploadResultService call failed:', error)
+ throw error
}
- } catch (error) {
- console.warn(`Could not get file stats for ${filePath}, using defaults`)
- // 파일 정보를 가져올 수 없는 경우 기본값 사용
- const now = new Date()
- return {
- size: 0,
- birthtime: now,
- mtime: now
+ }
+
+ // 파일 통계 정보 조회 헬퍼 메서드 (파일시스템에서 파일 정보를 가져옴)
+ private async getFileStats(filePath: string): Promise<{ size: number, birthtime: Date, mtime: Date }> {
+ try {
+ // Node.js 환경이라면 fs.stat 사용
+ const fs = require('fs').promises
+ const stats = await fs.stat(filePath)
+
+ return {
+ size: stats.size,
+ birthtime: stats.birthtime,
+ mtime: stats.mtime
+ }
+ } catch (error) {
+ console.warn(`Could not get file stats for ${filePath}, using defaults`)
+ // 파일 정보를 가져올 수 없는 경우 기본값 사용
+ const now = new Date()
+ return {
+ size: 0,
+ birthtime: now,
+ mtime: now
+ }
}
}
-}
/**
* 문서 정보 업로드 (DetailDwgReceiptMgmtEdit)
@@ -604,125 +618,125 @@ private async getFileStats(filePath: string): Promise<{ size: number, birthtime:
/**
* 리비전 데이터를 DOLCE 문서 형태로 변환 (업데이트된 스키마 사용)
*/
-/**
- * 리비전 데이터를 DOLCE 문서 형태로 변환 (업데이트된 스키마 사용)
- */
-private transformToDoLCEDocument(
- revision: any,
- contractInfo: any,
- uploadId?: string,
- vendorCode?: string,
-): DOLCEDocument {
- // Mode 결정: registerId가 있으면 MOD, 없으면 ADD
- let mode: "ADD" | "MOD" = "ADD" // 기본값은 ADD
-
- if (revision.registerId) {
- mode = "MOD"
- } else {
- mode = "ADD"
- }
+ /**
+ * 리비전 데이터를 DOLCE 문서 형태로 변환 (업데이트된 스키마 사용)
+ */
+ private transformToDoLCEDocument(
+ revision: any,
+ contractInfo: any,
+ uploadId?: string,
+ vendorCode?: string,
+ ): DOLCEDocument {
+ // Mode 결정: registerId가 있으면 MOD, 없으면 ADD
+ let mode: "ADD" | "MOD" = "ADD" // 기본값은 ADD
+
+ if (revision.registerId) {
+ mode = "MOD"
+ } else {
+ mode = "ADD"
+ }
- // RegisterKind 결정: usage와 usageType에 따라 설정
- let registerKind = "APPR" // 기본값
-
- if (revision.usage && revision.usage !== 'DEFAULT') {
- switch (revision.usage) {
- case "APPROVAL":
- if (revision.usageType === "Full") {
- registerKind = "APPR"
- } else if (revision.usageType === "Partial") {
- registerKind = "APPR-P"
- } else {
- registerKind = "APPR" // 기본값
- }
- break
-
- case "WORKING":
- if (revision.usageType === "Full") {
- registerKind = "WORK"
- } else if (revision.usageType === "Partial") {
- registerKind = "WORK-P"
- } else {
- registerKind = "WORK" // 기본값
- }
- break
+ // RegisterKind 결정: usage와 usageType에 따라 설정
+ let registerKind = "APPR" // 기본값
+
+ if (revision.usage && revision.usage !== 'DEFAULT') {
+ switch (revision.usage) {
+ case "APPROVAL":
+ if (revision.usageType === "Full") {
+ registerKind = "APPR"
+ } else if (revision.usageType === "Partial") {
+ registerKind = "APPR-P"
+ } else {
+ registerKind = "APPR" // 기본값
+ }
+ break
+
+ case "WORKING":
+ if (revision.usageType === "Full") {
+ registerKind = "WORK"
+ } else if (revision.usageType === "Partial") {
+ registerKind = "WORK-P"
+ } else {
+ registerKind = "WORK" // 기본값
+ }
+ break
- case "The 1st":
- registerKind = "FMEA-1"
- break
+ case "The 1st":
+ registerKind = "FMEA-1"
+ break
- case "The 2nd":
- registerKind = "FMEA-2"
- break
+ case "The 2nd":
+ registerKind = "FMEA-2"
+ break
- case "Pre":
- registerKind = "RECP"
- break
+ case "Pre":
+ registerKind = "RECP"
+ break
- case "Working":
- registerKind = "RECW"
- break
+ case "Working":
+ registerKind = "RECW"
+ break
- case "Mark-Up":
- registerKind = "CMTM"
- break
+ case "Mark-Up":
+ registerKind = "CMTM"
+ break
- default:
- console.warn(`Unknown usage type: ${revision.usage}, using default APPR`)
- registerKind = "APPR" // 기본값
- break
+ default:
+ console.warn(`Unknown usage type: ${revision.usage}, using default APPR`)
+ registerKind = "APPR" // 기본값
+ break
+ }
+ } else {
+ console.warn(`No usage specified for revision ${revision.revision}, using default APPR`)
}
- } else {
- console.warn(`No usage specified for revision ${revision.revision}, using default APPR`)
- }
- // Serial Number 계산 함수
- const getSerialNumber = (revisionValue: string): number => {
- if (!revisionValue) {
- return 1
- }
+ // Serial Number 계산 함수
+ const getSerialNumber = (revisionValue: string): number => {
+ if (!revisionValue) {
+ return 1
+ }
- // 먼저 숫자인지 확인
- const numericValue = parseInt(revisionValue)
- if (!isNaN(numericValue)) {
- return numericValue
- }
+ // 먼저 숫자인지 확인
+ const numericValue = parseInt(revisionValue)
+ if (!isNaN(numericValue)) {
+ return numericValue
+ }
- // 문자인 경우 (a=1, b=2, c=3, ...)
- if (typeof revisionValue === 'string' && revisionValue.length === 1) {
- const charCode = revisionValue.toLowerCase().charCodeAt(0)
- if (charCode >= 97 && charCode <= 122) { // a-z
- return charCode - 96 // a=1, b=2, c=3, ...
+ // 문자인 경우 (a=1, b=2, c=3, ...)
+ if (typeof revisionValue === 'string' && revisionValue.length === 1) {
+ const charCode = revisionValue.toLowerCase().charCodeAt(0)
+ if (charCode >= 97 && charCode <= 122) { // a-z
+ return charCode - 96 // a=1, b=2, c=3, ...
+ }
}
+
+ // 기본값
+ return 1
}
- // 기본값
- return 1
- }
+ console.log(`Transform to DOLCE: Mode=${mode}, RegisterKind=${registerKind}, Usage=${revision.usage}, UsageType=${revision.usageType}`)
- console.log(`Transform to DOLCE: Mode=${mode}, RegisterKind=${registerKind}, Usage=${revision.usage}, UsageType=${revision.usageType}`)
-
- return {
- Mode: mode,
- Status: revision.revisionStatus || "Standby",
- RegisterId: revision.registerId || 0, // registerId가 없으면 0 (ADD 모드)
- ProjectNo: contractInfo.projectCode,
- Discipline: revision.discipline || "DL",
- DrawingKind: revision.drawingKind || "B3",
- DrawingNo: revision.documentNo,
- DrawingName: revision.documentName,
- RegisterGroupId: revision.registerGroupId || 0,
- RegisterSerialNo: getSerialNumber(revision.revision || "1"),
- RegisterKind: registerKind, // usage/usageType에 따라 동적 설정
- DrawingRevNo: revision.revision || "-",
- Category: revision.category || "TS",
- Receiver: null,
- Manager: revision.managerNo || "202206", // 담당자 번호 사용
- RegisterDesc: revision.comment || "System upload",
- UploadId: uploadId,
- RegCompanyCode: vendorCode || "A0005531" // 벤더 코드
+ return {
+ Mode: mode,
+ Status: revision.revisionStatus || "Standby",
+ RegisterId: revision.registerId || 0, // registerId가 없으면 0 (ADD 모드)
+ ProjectNo: contractInfo.projectCode,
+ Discipline: revision.discipline || "DL",
+ DrawingKind: revision.drawingKind || "B3",
+ DrawingNo: revision.documentNo,
+ DrawingName: revision.documentName,
+ RegisterGroupId: revision.registerGroupId || 0,
+ RegisterSerialNo: getSerialNumber(revision.revision || "1"),
+ RegisterKind: registerKind, // usage/usageType에 따라 동적 설정
+ DrawingRevNo: revision.revision || "-",
+ Category: revision.category || "TS",
+ Receiver: null,
+ Manager: revision.managerNo || "202206", // 담당자 번호 사용
+ RegisterDesc: revision.comment || "System upload",
+ UploadId: uploadId,
+ RegCompanyCode: vendorCode || "A0005531" // 벤더 코드
+ }
}
-}
/**
* 파일 매핑 데이터 변환
*/
@@ -769,28 +783,28 @@ private transformToDoLCEDocument(
private async getFileBuffer(filePath: string): Promise<ArrayBuffer> {
try {
console.log(`📂 파일 읽기 요청: ${filePath}`);
-
+
if (filePath.startsWith('http')) {
// ✅ URL인 경우 직접 다운로드 (기존과 동일)
console.log(`🌐 HTTP URL에서 파일 다운로드: ${filePath}`);
-
+
const response = await fetch(filePath);
if (!response.ok) {
throw new Error(`파일 다운로드 실패: ${response.status}`);
}
-
+
const arrayBuffer = await response.arrayBuffer();
console.log(`✅ HTTP 다운로드 완료: ${arrayBuffer.byteLength} bytes`);
-
+
return arrayBuffer;
} else {
// ✅ 로컬/NAS 파일 경로 처리 (환경별 분기)
const fs = await import('fs');
const path = await import('path');
const config = getFileReaderConfig();
-
+
let actualFilePath: string;
-
+
// 경로 형태별 처리
if (filePath.startsWith('/documents/')) {
// ✅ DB에 저장된 경로 형태: "/documents/[uuid].ext"
@@ -798,32 +812,48 @@ private transformToDoLCEDocument(
// 프로덕션: /evcp_nas/documents/[uuid].ext
actualFilePath = path.join(config.baseDir, 'public', filePath.substring(1)); // 앞의 '/' 제거
console.log(`📁 documents 경로 처리: ${filePath} → ${actualFilePath}`);
- }
-
+ }
+ else if (filePath.startsWith('/api/files')) {
+
+ actualFilePath = `${process.env.NEXT_PUBLIC_URL}${filePath}`
+
+
+ const response = await fetch(actualFilePath);
+ if (!response.ok) {
+ throw new Error(`파일 다운로드 실패: ${response.status}`);
+ }
+
+ const arrayBuffer = await response.arrayBuffer();
+ console.log(`✅ HTTP 다운로드 완료: ${arrayBuffer.byteLength} bytes`);
+
+ return arrayBuffer;
+
+ }
+
else {
// ✅ 상대 경로는 현재 디렉토리 기준
actualFilePath = filePath;
console.log(`📂 상대 경로 사용: ${actualFilePath}`);
}
-
+
console.log(`🔍 실제 파일 경로: ${actualFilePath}`);
console.log(`🏠 환경: ${config.isProduction ? 'PRODUCTION (NAS)' : 'DEVELOPMENT (public)'}`);
-
+
// 파일 존재 여부 확인
if (!fs.existsSync(actualFilePath)) {
console.error(`❌ 파일 없음: ${actualFilePath}`);
throw new Error(`파일을 찾을 수 없습니다: ${actualFilePath}`);
}
-
+
// 파일 읽기
const fileBuffer = fs.readFileSync(actualFilePath);
console.log(`✅ 파일 읽기 성공: ${actualFilePath} (${fileBuffer.length} bytes)`);
-
+
// ✅ Buffer를 ArrayBuffer로 정확히 변환
const arrayBuffer = new ArrayBuffer(fileBuffer.length);
const uint8Array = new Uint8Array(arrayBuffer);
uint8Array.set(fileBuffer);
-
+
return arrayBuffer;
}
} catch (error) {
@@ -881,19 +911,19 @@ private transformToDoLCEDocument(
try {
// DES 암호화 (C# DESCryptoServiceProvider 호환)
const DES_KEY = Buffer.from("4fkkdijg", "ascii")
-
+
// 암호화 문자열 생성: FileId↔UserId↔FileName
const encryptString = `${fileId}↔${userId}↔${fileName}`
-
+
// DES 암호화 (createCipheriv 사용)
const cipher = crypto.createCipheriv('des-ecb', DES_KEY, '')
cipher.setAutoPadding(true)
let encrypted = cipher.update(encryptString, 'utf8', 'base64')
encrypted += cipher.final('base64')
const encryptedKey = encrypted.replace(/\+/g, '|||')
-
+
const downloadUrl = `${process.env.DOLCE_DOWNLOAD_URL}?key=${encryptedKey}` || `http://60.100.99.217:1111/Download.aspx?key=${encryptedKey}`
-
+
console.log(`🧪 DOLCE 파일 다운로드 테스트:`)
console.log(` 파일명: ${fileName}`)
console.log(` FileId: ${fileId}`)
@@ -919,7 +949,7 @@ private transformToDoLCEDocument(
const buffer = Buffer.from(await response.arrayBuffer())
console.log(`✅ DOLCE 파일 다운로드 테스트 성공: ${fileName} (${buffer.length} bytes)`)
-
+
return {
success: true,
downloadUrl