diff options
Diffstat (limited to 'lib/basic-contract/actions/check-gtc-comments.ts')
| -rw-r--r-- | lib/basic-contract/actions/check-gtc-comments.ts | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/lib/basic-contract/actions/check-gtc-comments.ts b/lib/basic-contract/actions/check-gtc-comments.ts new file mode 100644 index 00000000..1ce998bc --- /dev/null +++ b/lib/basic-contract/actions/check-gtc-comments.ts @@ -0,0 +1,239 @@ +"use server"; + +import db from "@/db/db"; +import { eq, and, desc, isNull, isNotNull, ne, or } from "drizzle-orm"; +import { + gtcDocuments, + gtcVendorDocuments, + gtcVendorClauses, + gtcNegotiationHistory, + projects, + BasicContractView +} from "@/db/schema"; + +/** + * 템플릿 이름에서 프로젝트 코드 추출 + */ +function extractProjectCodeFromTemplateName(templateName: string): string | null { + // "SN2319 GTC" -> "SN2319" + // "General GTC" -> null + const words = templateName.trim().split(/\s+/); + if (words.length === 0) return null; + + const firstWord = words[0]; + if (firstWord.toLowerCase() === 'general' || firstWord.toLowerCase() === 'gtc') { + return null; + } + + // 프로젝트 코드는 보통 첫 번째 단어 + if (words.length > 1 && words[words.length - 1].toLowerCase() === 'gtc') { + return words[words.length - 1]; + } + + return null; +} + +/** + * 단일 contract에 대한 GTC 정보 확인 + */ +async function checkGTCCommentsForContract( + templateName: string, + vendorId: number, + basicContractId?: number +): Promise<{ gtcDocumentId: number | null; hasComments: boolean }> { + try { + const projectCode = extractProjectCodeFromTemplateName(templateName); + let gtcDocumentId: number | null = null; + + console.log(projectCode,"projectCode") + + // 1. GTC Document ID 찾기 + if (projectCode && projectCode.trim() !== '') { + // Project GTC인 경우 + const project = await db + .select({ id: projects.id }) + .from(projects) + .where(eq(projects.code, projectCode.trim())) + .limit(1) + + if (project.length > 0) { + const projectGtcDoc = await db + .select({ id: gtcDocuments.id }) + .from(gtcDocuments) + .where( + and( + eq(gtcDocuments.projectId, project[0].id), + eq(gtcDocuments.isActive, true) + ) + ) + .orderBy(desc(gtcDocuments.revision)) + .limit(1) + + if (projectGtcDoc.length > 0) { + gtcDocumentId = projectGtcDoc[0].id + } + } + } else { + // Standard GTC인 경우 (general 포함하거나 project code가 없는 경우) + console.log(`🔍 [checkGTCCommentsForContract] Standard GTC 조회 중...`); + const standardGtcDoc = await db + .select({ id: gtcDocuments.id }) + .from(gtcDocuments) + .where( + and( + eq(gtcDocuments.type, "standard"), + eq(gtcDocuments.isActive, true), + isNull(gtcDocuments.projectId) + ) + ) + .orderBy(desc(gtcDocuments.revision)) + .limit(1) + + console.log(`📊 [checkGTCCommentsForContract] Standard GTC 조회 결과: ${standardGtcDoc.length}개`); + + if (standardGtcDoc.length > 0) { + gtcDocumentId = standardGtcDoc[0].id + console.log(`✅ [checkGTCCommentsForContract] Standard GTC 찾음: ${gtcDocumentId}`); + } else { + console.log(`❌ [checkGTCCommentsForContract] Standard GTC 없음 - gtc_documents 테이블에 standard 타입의 활성 문서가 없습니다`); + } + } + + console.log(`🎯 [checkGTCCommentsForContract] 최종 gtcDocumentId: ${gtcDocumentId}`) + + // 🔥 중요: basicContractId가 있으면 먼저 agreement_comments 테이블 확인 + // gtcDocumentId가 없어도 새로운 코멘트 시스템은 작동해야 함 + if (basicContractId) { + console.log(`🔍 [checkGTCCommentsForContract] basicContractId: ${basicContractId} 로 코멘트 조회`); + const { agreementComments } = await import("@/db/schema"); + const newComments = await db + .select({ id: agreementComments.id }) + .from(agreementComments) + .where( + and( + eq(agreementComments.basicContractId, basicContractId), + eq(agreementComments.isDeleted, false) + ) + ) + .limit(1); + + console.log(`📊 [checkGTCCommentsForContract] basicContractId ${basicContractId}: 코멘트 ${newComments.length}개 발견`); + + if (newComments.length > 0) { + console.log(`✅ [checkGTCCommentsForContract] basicContractId ${basicContractId}: hasComments = true 반환`); + return { + gtcDocumentId, // null일 수 있음 + hasComments: true + }; + } + + console.log(`⚠️ [checkGTCCommentsForContract] basicContractId ${basicContractId}: agreementComments 없음`); + } + + // GTC Document를 찾지 못한 경우 (기존 방식도 체크할 수 없음) + if (!gtcDocumentId) { + console.log(`⚠️ [checkGTCCommentsForContract] gtcDocumentId null - 기존 방식 체크 불가`); + return { gtcDocumentId: null, hasComments: false }; + } + + // 2-2. 기존 방식: gtcDocumentId로 해당 벤더의 vendor documents 찾기 + const vendorDocuments = await db + .select({ id: gtcVendorDocuments.id }) + .from(gtcVendorDocuments) + .where( + and( + eq(gtcVendorDocuments.baseDocumentId, gtcDocumentId), + eq(gtcVendorDocuments.vendorId, vendorId), + eq(gtcVendorDocuments.isActive, true) + ) + ) + .limit(1) + + if (vendorDocuments.length === 0) { + return { gtcDocumentId, hasComments: false }; + } + + // vendor document에 연결된 clauses에서 negotiation history 확인 + const commentsExist = await db + .select({ count: gtcNegotiationHistory.id }) + .from(gtcNegotiationHistory) + .innerJoin( + gtcVendorClauses, + eq(gtcNegotiationHistory.vendorClauseId, gtcVendorClauses.id) + ) + .where( + and( + eq(gtcVendorClauses.vendorDocumentId, vendorDocuments[0].id), + eq(gtcVendorClauses.isActive, true), + isNotNull(gtcNegotiationHistory.comment), + ne(gtcNegotiationHistory.comment, '') + ) + ) + .limit(1) + + return { + gtcDocumentId, + hasComments: commentsExist.length > 0 + }; + + } catch (error) { + console.error('Error checking GTC comments for contract:', error); + return { gtcDocumentId: null, hasComments: false }; + } +} + +/** + * 전체 contract 리스트에 대해 GTC document ID와 comment 정보 수집 + */ +export async function checkGTCCommentsForContracts( + contracts: BasicContractView[] +): Promise<Record<number, { gtcDocumentId: number | null; hasComments: boolean }>> { + const gtcData: Record<number, { gtcDocumentId: number | null; hasComments: boolean }> = {}; + + // GTC가 포함된 contract만 필터링 + const gtcContracts = contracts.filter(contract => + contract.templateName?.includes('GTC') + ); + + if (gtcContracts.length === 0) { + return gtcData; + } + + // Promise.all을 사용해서 병렬 처리 + const checkPromises = gtcContracts.map(async (contract) => { + try { + console.log(`🔄 [checkGTCCommentsForContracts] 계약서 ${contract.id} 체크 시작 - 템플릿: ${contract.templateName}, 벤더: ${contract.vendorName} (${contract.vendorId})`); + const result = await checkGTCCommentsForContract( + contract.templateName!, + contract.vendorId!, + contract.id // basicContractId 전달 + ); + + console.log(`📌 [checkGTCCommentsForContracts] 계약서 ${contract.id} 결과 - hasComments: ${result.hasComments}, gtcDocumentId: ${result.gtcDocumentId}`); + + return { + contractId: contract.id, + gtcDocumentId: result.gtcDocumentId, + hasComments: result.hasComments + }; + } catch (error) { + console.error(`Error checking GTC for contract ${contract.id}:`, error); + return { + contractId: contract.id, + gtcDocumentId: null, + hasComments: false + }; + } + }); + + const results = await Promise.all(checkPromises); + + // 결과를 Record 형태로 변환 + results.forEach(({ contractId, gtcDocumentId, hasComments }) => { + gtcData[contractId] = { gtcDocumentId, hasComments }; + }); + + return gtcData; +} + + |
