diff options
Diffstat (limited to 'lib/vendor-document-list')
| -rw-r--r-- | lib/vendor-document-list/dolce-upload-service.ts | 184 |
1 files changed, 143 insertions, 41 deletions
diff --git a/lib/vendor-document-list/dolce-upload-service.ts b/lib/vendor-document-list/dolce-upload-service.ts index 35058a65..8c66f234 100644 --- a/lib/vendor-document-list/dolce-upload-service.ts +++ b/lib/vendor-document-list/dolce-upload-service.ts @@ -1,9 +1,8 @@ // lib/vendor-document-list/dolce-upload-service.ts import db from "@/db/db" import { documents, revisions, documentAttachments, contracts, projects, vendors, issueStages } from "@/db/schema" -import { eq, and, desc, sql, inArray, min } from "drizzle-orm" +import { eq, and, 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" @@ -59,13 +58,65 @@ interface DOLCEDocument { RegCompanyCode: string } +interface RevisionAttachment { + id: number + uploadId: string | null + fileId: string | null + fileName: string + filePath: string + fileType: string | null + fileSize: number | null + createdAt: Date +} + +interface RevisionWithAttachments { + id: number + registerId: string | number | null + revision: string + revisionStatus: string | null + uploaderId: string | number | null + uploaderName: string | null + submittedDate: string | null + comment: string | null + usage: string | null + usageType: string | null + externalUploadId: string | null + externalRegisterId: number + externalSentAt: string | null + serialNo: number | null + issueStageId: number + stageName: string | null + documentId: number + documentNo: string + documentName: string + drawingKind: string | null + drawingMoveGbn: string | null + discipline: string | null + registerGroupId: number | null + category?: string | null + cGbn: string | null + dGbn: string | null + degreeGbn: string | null + deptGbn: string | null + jGbn: string | null + sGbn: string | null + manager: string | null + managerENM: string | null + managerNo: string | null + shiDrawingNo: string | null + externalDocumentId: string | null + externalSystemType: string | null + externalSyncedAt: Date | null + attachments: RevisionAttachment[] +} + interface DOLCEFileMapping { - CGbn?: string - Category?: string + CGbn?: string | null + Category?: string | null CheckBox: string - DGbn?: string - DegreeGbn?: string - DeptGbn?: string + DGbn?: string | null + DegreeGbn?: string | null + DeptGbn?: string | null Discipline: string DrawingKind: string DrawingMoveGbn: string @@ -73,7 +124,7 @@ interface DOLCEFileMapping { DrawingNo: string DrawingUsage: string FileNm: string - JGbn?: string + JGbn?: string | null Manager: string MappingYN: string NewOrNot: string @@ -82,8 +133,8 @@ interface DOLCEFileMapping { RegisterGroupId: number RegisterKindCode: string RegisterSerialNo: number - RevNo?: string - SGbn?: string + RevNo?: string | null + SGbn?: string | null UploadId: string } @@ -115,19 +166,24 @@ class DOLCEUploadService { async uploadToDoLCE( projectId: number, revisionIds: number[], - userId: string, - userName?: string + userId: string ): Promise<DOLCEUploadResult> { try { console.log(`Starting DOLCE upload for contract ${projectId}, revisions: ${revisionIds.join(', ')}`) - // 1. 계약 정보 조회 (프로젝트 코드, 벤더 코드 등) + // 1. 사용자 정보 조회 (DOLCE API에 필요한 정보) + const userInfo = await this.getUserInfo(userId) + if (!userInfo) { + throw new Error(`User info not found for ID: ${userId}`) + } + + // 2. 계약 정보 조회 (프로젝트 코드, 벤더 코드 등) const contractInfo = await this.getContractInfo(projectId) if (!contractInfo) { throw new Error(`Contract info not found for ID: ${projectId}`) } - // 2. 업로드할 리비전 정보 조회 + // 3. 업로드할 리비전 정보 조회 const revisionsToUpload = await this.getRevisionsForUpload(revisionIds) if (revisionsToUpload.length === 0) { return { @@ -138,7 +194,7 @@ class DOLCEUploadService { } let uploadedDocuments = 0 - let uploadedFiles = 0 + const uploadedFiles = 0 const errors: string[] = [] const results: any = { documentResults: [], @@ -146,19 +202,19 @@ class DOLCEUploadService { mappingResults: [] } - // 3. 각 리비전별로 처리 + // 4. 각 리비전별로 처리 for (const revision of revisionsToUpload) { try { console.log(`Processing revision ${revision.revision} for document ${revision.documentNo}`) - // 3-1. UploadId 미리 생성 (파일이 있는 경우에만) + // 4-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 포함) + // 4-2. 문서 정보 업로드 (UploadId 포함) const dolceDoc = this.transformToDoLCEDocument( revision, contractInfo, @@ -166,7 +222,13 @@ class DOLCEUploadService { contractInfo.vendorCode, ) - const docResult = await this.uploadDocument([dolceDoc], userId) + const docResult = await this.uploadDocument( + [dolceDoc], + userInfo.userId, + userInfo.userName, + userInfo.vendorCode, + userInfo.userEmail + ) if (!docResult.success) { errors.push(`Document upload failed for ${revision.documentNo}: ${docResult.error}`) continue // 문서 업로드 실패 시 다음 리비전으로 넘어감 @@ -176,11 +238,11 @@ class DOLCEUploadService { results.documentResults.push(docResult) console.log(`✅ Document uploaded successfully: ${revision.documentNo}`) - // 3-3. 파일 업로드 (이미 생성된 UploadId 사용) + // 4-3. 파일 업로드 (이미 생성된 UploadId 사용) if (uploadId && revision.attachments && revision.attachments.length > 0) { try { // 파일 업로드 시 이미 생성된 UploadId 사용 - const fileUploadResults = await this.uploadFiles( + await this.uploadFiles( revision.attachments, userId, uploadId // 이미 생성된 UploadId 전달 @@ -192,7 +254,7 @@ class DOLCEUploadService { } } - // 3-5. 성공한 리비전의 상태 업데이트 + // 4-4. 성공한 리비전의 상태 업데이트 await this.updateRevisionStatus(revision.id, 'SUBMITTED', uploadId) } catch (error) { @@ -245,6 +307,41 @@ class DOLCEUploadService { : null } + /** + * 사용자 정보 조회 (DOLCE 업로드에 필요한 정보) + */ + private async getUserInfo(userId: string): Promise<{ + userId: string; + userName: string; + userEmail: string; + vendorCode: string; + } | null> { + const { users, vendors } = await import("@/db/schema") + + const [result] = await db + .select({ + userId: users.id, + userName: users.name, + userEmail: users.email, + vendorCode: vendors.vendorCode + }) + .from(users) + .innerJoin(vendors, eq(users.companyId, vendors.id)) + .where(eq(users.id, Number(userId))) + .limit(1) + + if (!result) { + return null + } + + return { + userId: String(result.userId), + userName: result.userName, + userEmail: result.userEmail, + vendorCode: result.vendorCode || "" + } + } + /** * 각 issueStageId별로 첫 번째 revision 정보를 조회 @@ -272,7 +369,7 @@ class DOLCEUploadService { /** * 업로드할 리비전 정보 조회 (문서 정보 및 첨부파일 포함) */ - private async getRevisionsForUpload(revisionIds: number[]) { + private async getRevisionsForUpload(revisionIds: number[]): Promise<RevisionWithAttachments[]> { // revisions → issueStages → documents 순서로 join하여 정보 조회 const revisionResults = await db .select({ @@ -333,7 +430,7 @@ class DOLCEUploadService { .where(inArray(revisions.id, revisionIds)) // 각 리비전의 첨부파일 정보도 조회 - const revisionsWithAttachments = [] + const revisionsWithAttachments: RevisionWithAttachments[] = [] for (const revision of revisionResults) { const attachments = await db .select({ @@ -365,11 +462,11 @@ class DOLCEUploadService { * @param uploadId 이미 생성된 UploadId (문서 업로드 시 생성됨) */ private async uploadFiles( - attachments: any[], + attachments: RevisionAttachment[], userId: string, uploadId: string // 이미 생성된 UploadId를 매개변수로 받음 ): Promise<Array<{ uploadId: string, fileId: string, filePath: string }>> { - const uploadResults = [] + const uploadResults: Array<{ uploadId: string, fileId: string, filePath: string }> = [] const resultDataArray: ResultData[] = [] for (let i = 0; i < attachments.length; i++) { @@ -516,7 +613,7 @@ class DOLCEUploadService { private async getFileStats(filePath: string): Promise<{ size: number, birthtime: Date, mtime: Date }> { try { // Node.js 환경이라면 fs.stat 사용 - const fs = require('fs').promises + const fs = await import('fs/promises') const stats = await fs.stat(filePath) return { @@ -524,7 +621,7 @@ class DOLCEUploadService { birthtime: stats.birthtime, mtime: stats.mtime } - } catch (error) { + } catch { console.warn(`Could not get file stats for ${filePath}, using defaults`) // 파일 정보를 가져올 수 없는 경우 기본값 사용 const now = new Date() @@ -539,13 +636,22 @@ class DOLCEUploadService { /** * 문서 정보 업로드 (DetailDwgReceiptMgmtEdit) */ - private async uploadDocument(dwgList: DOLCEDocument[], userId: string): Promise<{ success: boolean, error?: string, data?: any }> { + private async uploadDocument( + dwgList: DOLCEDocument[], + userId: string, + userName: string, + vendorCode: string, + email: string + ): Promise<{ success: boolean, error?: string, data?: any }> { try { const endpoint = `${this.BASE_URL}/Services/VDCSWebService.svc/DetailDwgReceiptMgmtEdit` const requestBody = { DwgList: dwgList, - UserID: userId + UserID: userId, + UserNM: userName, + VENDORCODE: vendorCode, + EMAIL: email } console.log('Uploading documents to DOLCE:', JSON.stringify(requestBody, null, 2)) @@ -623,12 +729,9 @@ class DOLCEUploadService { /** * 리비전 데이터를 DOLCE 문서 형태로 변환 (업데이트된 스키마 사용) */ - /** - * 리비전 데이터를 DOLCE 문서 형태로 변환 (업데이트된 스키마 사용) - */ private transformToDoLCEDocument( - revision: any, - contractInfo: any, + revision: RevisionWithAttachments, + contractInfo: { projectCode: string; vendorCode: string }, uploadId?: string, vendorCode?: string, ): DOLCEDocument { @@ -750,7 +853,7 @@ class DOLCEUploadService { Mode: mode, // Status: revision.revisionStatus || "Standby", Status: "Standby", - RegisterId: revision.registerId || 0, // registerId가 없으면 0 (ADD 모드) + RegisterId: revision.registerId ? (typeof revision.registerId === 'string' ? parseInt(revision.registerId) : revision.registerId) : 0, // registerId가 없으면 0 (ADD 모드) ProjectNo: contractInfo.projectCode, Discipline: revision.discipline || "DL", DrawingKind: revision.drawingKind || "B3", @@ -772,8 +875,8 @@ class DOLCEUploadService { * 파일 매핑 데이터 변환 */ private transformToFileMapping( - revision: any, - contractInfo: any, + revision: RevisionWithAttachments, + contractInfo: { projectCode: string; vendorCode: string }, uploadId: string, fileName: string ): DOLCEFileMapping { @@ -1008,8 +1111,7 @@ export const dolceUploadService = new DOLCEUploadService() export async function uploadRevisionsToDOLCE( projectId: number, revisionIds: number[], - userId: string, - userName?: string + userId: string ): Promise<DOLCEUploadResult> { - return dolceUploadService.uploadToDoLCE(projectId, revisionIds, userId, userName) + return dolceUploadService.uploadToDoLCE(projectId, revisionIds, userId) }
\ No newline at end of file |
