diff options
Diffstat (limited to 'lib/vendor-document-list/import-service.ts')
| -rw-r--r-- | lib/vendor-document-list/import-service.ts | 288 |
1 files changed, 247 insertions, 41 deletions
diff --git a/lib/vendor-document-list/import-service.ts b/lib/vendor-document-list/import-service.ts index 4a152299..d2a14980 100644 --- a/lib/vendor-document-list/import-service.ts +++ b/lib/vendor-document-list/import-service.ts @@ -37,10 +37,23 @@ interface DOLCEDocument { DrawingNo: string GTTInput_PlanDate?: string GTTInput_ResultDate?: string + AppDwg_PlanDate?: string + AppDwg_ResultDate?: string + WorDwg_PlanDate?: string + WorDwg_ResultDate?: string + + GTTPreDwg_PlanDate?: string GTTPreDwg_ResultDate?: string GTTWorkingDwg_PlanDate?: string GTTWorkingDwg_ResultDate?: string + + FMEAFirst_PlanDate?: string + FMEAFirst_ResultDate?: string + FMEASecond_PlanDate?: string + FMEASecond_ResultDate?: string + + JGbn?: string Manager: string ManagerENM: string @@ -72,12 +85,12 @@ class ImportService { // 2. 각 drawingKind별로 데이터 조회 const allDocuments: DOLCEDocument[] = [] const drawingKinds = ['B3', 'B4', 'B5'] - + for (const drawingKind of drawingKinds) { try { const documents = await this.fetchFromDOLCE( - contractInfo.projectCode, - contractInfo.vendorCode, + contractInfo.projectCode, + contractInfo.vendorCode, drawingKind ) allDocuments.push(...documents) @@ -87,7 +100,7 @@ class ImportService { // 개별 drawingKind 실패는 전체 실패로 처리하지 않음 } } - + if (allDocuments.length === 0) { return { success: true, @@ -107,13 +120,22 @@ class ImportService { for (const dolceDoc of allDocuments) { try { const result = await this.syncSingleDocument(contractId, dolceDoc, sourceSystem) - + if (result === 'NEW') { newCount++ // B4 문서의 경우 이슈 스테이지 자동 생성 if (dolceDoc.DrawingKind === 'B4') { await this.createIssueStagesForB4Document(dolceDoc.DrawingNo, contractId, dolceDoc) } + + if (dolceDoc.DrawingKind === 'B3') { + await this.createIssueStagesForB3Document(dolceDoc.DrawingNo, contractId, dolceDoc) + } + + + if (dolceDoc.DrawingKind === 'B5') { + await this.createIssueStagesForB5Document(dolceDoc.DrawingNo, contractId, dolceDoc) + } } else if (result === 'UPDATED') { updatedCount++ } else { @@ -151,7 +173,7 @@ class ImportService { vendorCode: string; } | null> { const [result] = await db - .select({ + .select({ projectCode: projects.code, vendorCode: vendors.vendorCode }) @@ -162,7 +184,7 @@ class ImportService { .limit(1) - return result?.projectCode && result?.vendorCode + return result?.projectCode && result?.vendorCode ? { projectCode: result.projectCode, vendorCode: result.vendorCode } : null } @@ -172,15 +194,15 @@ class ImportService { */ private async fetchFromDOLCE( projectCode: string, - vendorCode: string, + vendorCode: string, drawingKind: string ): Promise<DOLCEDocument[]> { const endpoint = process.env.DOLCE_DOC_LIST_API_URL || 'http://60.100.99.217:1111/Services/VDCSWebService.svc/DwgReceiptMgmt' - + const requestBody = { project: projectCode, drawingKind: drawingKind, // B3, B4, B5 - drawingMoveGbn: "", + drawingMoveGbn: "", drawingNo: "", drawingName: "", drawingVendor: vendorCode @@ -204,14 +226,32 @@ class ImportService { } const data = await response.json() - - // 응답 구조에 따라 조정 필요 (실제 API 응답 구조 확인 후) - if (Array.isArray(data)) { - return data as DOLCEDocument[] - } else if (data.documents && Array.isArray(data.documents)) { - return data.documents as DOLCEDocument[] - } else if (data.data && Array.isArray(data.data)) { - return data.data as DOLCEDocument[] + + // DOLCE API 응답 구조에 맞게 처리 + if (data.DwgReceiptMgmtResult) { + const result = data.DwgReceiptMgmtResult + + // drawingKind에 따라 적절한 배열에서 데이터 추출 + let documents: DOLCEDocument[] = [] + + switch (drawingKind) { + case 'B3': + documents = result.VendorDwgList || [] + break + case 'B4': + documents = result.GTTDwgList || [] + break + case 'B5': + documents = result.FMEADwgList || [] + break + default: + console.warn(`Unknown drawingKind: ${drawingKind}`) + documents = [] + } + + console.log(`Found ${documents.length} documents for ${drawingKind} in ${drawingKind === 'B3' ? 'VendorDwgList' : drawingKind === 'B4' ? 'GTTDwgList' : 'FMEADwgList'}`) + return documents as DOLCEDocument[] + } else { console.warn(`Unexpected DOLCE response structure:`, data) return [] @@ -222,7 +262,6 @@ class ImportService { throw error } } - /** * 단일 문서 동기화 */ @@ -247,17 +286,17 @@ class ImportService { docNumber: dolceDoc.DrawingNo, title: dolceDoc.DrawingName, status: 'ACTIVE', - + // DOLCE 전용 필드들 drawingKind: dolceDoc.DrawingKind, drawingMoveGbn: dolceDoc.DrawingMoveGbn, discipline: dolceDoc.Discipline, - + // 외부 시스템 정보 externalDocumentId: dolceDoc.DrawingNo, // DOLCE에서는 DrawingNo가 ID 역할 externalSystemType: sourceSystem, externalSyncedAt: new Date(), - + // B4 전용 필드들 cGbn: dolceDoc.CGbn, dGbn: dolceDoc.DGbn, @@ -265,7 +304,7 @@ class ImportService { deptGbn: dolceDoc.DeptGbn, jGbn: dolceDoc.JGbn, sGbn: dolceDoc.SGbn, - + // 추가 정보 shiDrawingNo: dolceDoc.SHIDrawingNo, manager: dolceDoc.Manager, @@ -273,19 +312,19 @@ class ImportService { managerNo: dolceDoc.ManagerNo, registerGroup: dolceDoc.RegisterGroup, registerGroupId: dolceDoc.RegisterGroupId, - + // 생성자 정보 createUserNo: dolceDoc.CreateUserNo, createUserId: dolceDoc.CreateUserId, createUserENM: dolceDoc.CreateUserENM, - + updatedAt: new Date() } if (existingDoc.length > 0) { // 업데이트 필요 여부 확인 const existing = existingDoc[0] - const hasChanges = + const hasChanges = existing.title !== documentData.title || existing.drawingMoveGbn !== documentData.drawingMoveGbn || existing.manager !== documentData.manager @@ -316,6 +355,36 @@ class ImportService { } } + private convertDolceDateToDate(dolceDate: string | undefined | null): Date | null { + if (!dolceDate || dolceDate.trim() === '') { + return null + } + + // "20250204" 형태의 문자열을 "2025-02-04" 형태로 변환 + if (dolceDate.length === 8 && /^\d{8}$/.test(dolceDate)) { + const year = dolceDate.substring(0, 4) + const month = dolceDate.substring(4, 6) + const day = dolceDate.substring(6, 8) + + try { + const date = new Date(`${year}-${month}-${day}`) + // 유효한 날짜인지 확인 + if (isNaN(date.getTime())) { + console.warn(`Invalid date format: ${dolceDate}`) + return null + } + return date + } catch (error) { + console.warn(`Failed to parse date: ${dolceDate}`, error) + return null + } + } + + console.warn(`Unexpected date format: ${dolceDate}`) + return null +} + + /** * B4 문서용 이슈 스테이지 자동 생성 */ @@ -353,23 +422,25 @@ class ImportService { if (!existingStageNames.includes('For Pre')) { await db.insert(issueStages).values({ documentId: documentId, - stageName: 'For Pre', - planDate: dolceDoc.GTTPreDwg_PlanDate ? dolceDoc.GTTPreDwg_PlanDate : null, - actualDate: dolceDoc.GTTPreDwg_ResultDate ? dolceDoc.GTTPreDwg_ResultDate : null, - stageStatus: dolceDoc.GTTPreDwg_ResultDate ? 'COMPLETED' : 'PLANNED', + stageName: 'GTT → SHI (For Pre.DWG)', + planDate: this.convertDolceDateToDate(dolceDoc.GTTPreDwg_PlanDate), + actualDate: this.convertDolceDateToDate(dolceDoc.GTTPreDwg_ResultDate), + stageStatus: 'PLANNED', stageOrder: 1, + priority: 'MEDIUM', // 기본값 + reminderDays: 3, // 기본값 description: 'GTT 예비 도면 단계' }) } // For Working 스테이지 생성 (GTTWorkingDwg) - if (!existingStageNames.includes('For Working')) { + if (!existingStageNames.includes('For Work')) { await db.insert(issueStages).values({ documentId: documentId, - stageName: 'For Working', - planDate: dolceDoc.GTTWorkingDwg_PlanDate ? dolceDoc.GTTWorkingDwg_PlanDate : null, - actualDate: dolceDoc.GTTWorkingDwg_ResultDate ? dolceDoc.GTTWorkingDwg_ResultDate : null, - stageStatus: dolceDoc.GTTWorkingDwg_ResultDate ? 'COMPLETED' : 'PLANNED', + stageName: 'GTT → SHI (For Work.DWG)', + planDate: this.convertDolceDateToDate(dolceDoc.GTTWorkingDwg_PlanDate), + actualDate: this.convertDolceDateToDate(dolceDoc.GTTWorkingDwg_ResultDate), + stageStatus: 'PLANNED', stageOrder: 2, description: 'GTT 작업 도면 단계' }) @@ -383,6 +454,141 @@ class ImportService { } } + private async createIssueStagesForB3Document( + drawingNo: string, + contractId: number, + dolceDoc: DOLCEDocument + ): Promise<void> { + try { + // 문서 ID 조회 + const [document] = await db + .select({ id: documents.id }) + .from(documents) + .where(and( + eq(documents.contractId, contractId), + eq(documents.docNumber, drawingNo) + )) + .limit(1) + + if (!document) { + throw new Error(`Document not found: ${drawingNo}`) + } + + const documentId = document.id + + // 기존 이슈 스테이지 확인 + const existingStages = await db + .select() + .from(issueStages) + .where(eq(issueStages.documentId, documentId)) + + const existingStageNames = existingStages.map(stage => stage.stageName) + + // For Pre 스테이지 생성 (GTTPreDwg) + if (!existingStageNames.includes('Approval')) { + await db.insert(issueStages).values({ + documentId: documentId, + stageName: 'Vendor → SHI (For Approval)', + + planDate: this.convertDolceDateToDate(dolceDoc.AppDwg_PlanDate), + actualDate: this.convertDolceDateToDate(dolceDoc.AppDwg_ResultDate), + + stageStatus: 'PLANNED', + stageOrder: 1, + description: 'Vendor 승인 도면 단계' + }) + } + + // For Working 스테이지 생성 (GTTWorkingDwg) + if (!existingStageNames.includes('Working')) { + await db.insert(issueStages).values({ + documentId: documentId, + stageName: 'Vendor → SHI (For Working)', + + planDate: this.convertDolceDateToDate(dolceDoc.WorDwg_PlanDate), + actualDate: this.convertDolceDateToDate(dolceDoc.WorDwg_ResultDate), + + stageStatus: 'PLANNED', + stageOrder: 2, + description: 'Vendor 작업 도면 단계' + }) + } + + console.log(`Created issue stages for B4 document: ${drawingNo}`) + + } catch (error) { + console.error(`Failed to create issue stages for ${drawingNo}:`, error) + // 이슈 스테이지 생성 실패는 전체 문서 생성을 막지 않음 + } + } + + private async createIssueStagesForB5Document( + drawingNo: string, + contractId: number, + dolceDoc: DOLCEDocument + ): Promise<void> { + try { + // 문서 ID 조회 + const [document] = await db + .select({ id: documents.id }) + .from(documents) + .where(and( + eq(documents.contractId, contractId), + eq(documents.docNumber, drawingNo) + )) + .limit(1) + + if (!document) { + throw new Error(`Document not found: ${drawingNo}`) + } + + const documentId = document.id + + // 기존 이슈 스테이지 확인 + const existingStages = await db + .select() + .from(issueStages) + .where(eq(issueStages.documentId, documentId)) + + const existingStageNames = existingStages.map(stage => stage.stageName) + + // For Pre 스테이지 생성 (GTTPreDwg) + if (!existingStageNames.includes('Approval')) { + await db.insert(issueStages).values({ + documentId: documentId, + stageName: 'Vendor → SHI (For Approval)', + + planDate: this.convertDolceDateToDate(dolceDoc.FMEAFirst_PlanDate), + actualDate: this.convertDolceDateToDate(dolceDoc.FMEAFirst_ResultDate), + + stageStatus: 'PLANNED', + stageOrder: 1, + description: 'FMEA 예비 도면 단계' + }) + } + + // For Working 스테이지 생성 (GTTWorkingDwg) + if (!existingStageNames.includes('Working')) { + await db.insert(issueStages).values({ + documentId: documentId, + stageName: 'Vendor → SHI (For Working)', + planDate: dolceDoc.FMEASecond_PlanDate ? dolceDoc.FMEASecond_PlanDate : null, + actualDate: dolceDoc.FMEASecond_ResultDate ? dolceDoc.FMEASecond_ResultDate : null, + stageStatus: 'PLANNED', + stageOrder: 2, + description: 'FMEA 작업 도면 단계' + }) + } + + console.log(`Created issue stages for B4 document: ${drawingNo}`) + + } catch (error) { + console.error(`Failed to create issue stages for ${drawingNo}:`, error) + // 이슈 스테이지 생성 실패는 전체 문서 생성을 막지 않음 + } + } + + /** * 가져오기 상태 조회 */ @@ -393,8 +599,8 @@ class ImportService { try { // 마지막 가져오기 시간 조회 const [lastImport] = await db - .select({ - lastSynced: sql<string>`MAX(${documents.externalSyncedAt})` + .select({ + lastSynced: sql<string>`MAX(${documents.externalSyncedAt})` }) .from(documents) .where(and( @@ -405,7 +611,7 @@ class ImportService { // 프로젝트 코드와 벤더 코드 조회 const contractInfo = await this.getContractInfoById(contractId) - console.log(contractInfo,"contractInfo") + console.log(contractInfo, "contractInfo") if (!contractInfo?.projectCode || !contractInfo?.vendorCode) { throw new Error(`Project code or vendor code not found for contract ${contractId}`) @@ -418,12 +624,12 @@ class ImportService { try { // 각 drawingKind별로 확인 const drawingKinds = ['B3', 'B4', 'B5'] - + for (const drawingKind of drawingKinds) { try { const externalDocs = await this.fetchFromDOLCE( - contractInfo.projectCode, - contractInfo.vendorCode, + contractInfo.projectCode, + contractInfo.vendorCode, drawingKind ) availableDocuments += externalDocs.length |
