summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-10-03 04:48:47 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-10-03 04:48:47 +0000
commitdefda07c0bb4b0bd444ca8dc4fd3f89322bda0ce (patch)
treed7f257781f107d7ec2fd4ef76cb4f840f5065a06 /app
parent00743c8b4190fac9117c2d9c08981bbfdce576de (diff)
(대표님) edp, tbe, dolce 등
Diffstat (limited to 'app')
-rw-r--r--app/[lng]/evcp/(evcp)/(procurement)/pq_new/[vendorId]/[submissionId]/page.tsx48
-rw-r--r--app/api/revisions/max-serial-no/route.ts175
2 files changed, 199 insertions, 24 deletions
diff --git a/app/[lng]/evcp/(evcp)/(procurement)/pq_new/[vendorId]/[submissionId]/page.tsx b/app/[lng]/evcp/(evcp)/(procurement)/pq_new/[vendorId]/[submissionId]/page.tsx
index c8b0e9b8..c63cf4df 100644
--- a/app/[lng]/evcp/(evcp)/(procurement)/pq_new/[vendorId]/[submissionId]/page.tsx
+++ b/app/[lng]/evcp/(evcp)/(procurement)/pq_new/[vendorId]/[submissionId]/page.tsx
@@ -36,14 +36,37 @@ export default async function PQReviewPage(props: PQReviewPageProps) {
const params = await props.params
const vendorId = parseInt(params.vendorId, 10)
const submissionId = parseInt(params.submissionId, 10)
-
+
+ // 파라미터 유효성 검증
+ if (isNaN(vendorId) || isNaN(submissionId)) {
+ return (
+ <div className="container mx-auto p-6">
+ <div className="text-center">
+ <h1 className="text-2xl font-bold text-red-600">잘못된 접근</h1>
+ <p className="text-gray-600 mt-2">유효하지 않은 파라미터입니다.</p>
+ </div>
+ </div>
+ )
+ }
+
try {
// PQ Submission 정보 조회
const pqSubmission = await getPQById(submissionId, vendorId)
// PQ 데이터 조회 (질문과 답변)
const pqData = await getPQDataByVendorId(vendorId, pqSubmission.projectId || undefined)
-
+
+ // 협력업체 정보 (pqSubmission에 이미 포함되어 있음)
+ const vendorInfo = {
+ vendorName: pqSubmission.vendorName,
+ vendorCode: pqSubmission.vendorCode,
+ vendorStatus: pqSubmission.vendorStatus,
+ vendorCountry: pqSubmission.vendorCountry,
+ vendorEmail: pqSubmission.vendorEmail,
+ vendorPhone: pqSubmission.vendorPhone,
+ vendorFax: pqSubmission.vendorFax,
+ }
+
// 프로젝트 정보 (프로젝트 PQ인 경우)
const projectInfo = pqSubmission.projectId ? {
id: pqSubmission.projectId,
@@ -60,9 +83,6 @@ export default async function PQReviewPage(props: PQReviewPageProps) {
const statusLabel = getStatusLabel(pqSubmission.status)
const statusVariant = getStatusVariant(pqSubmission.status)
- // 수정 가능 여부 (SUBMITTED 상태일 때만 가능)
- const canReview = pqSubmission.status === "SUBMITTED"
-
return (
<Shell className="gap-6 max-w-5xl">
<div className="flex items-center justify-between">
@@ -136,7 +156,7 @@ export default async function PQReviewPage(props: PQReviewPageProps) {
pqData={pqData}
vendorId={vendorId}
pqSubmission={pqSubmission}
- canReview={canReview}
+ vendorInfo={vendorInfo}
/>
</TabsContent>
@@ -156,7 +176,21 @@ export default async function PQReviewPage(props: PQReviewPageProps) {
<p className="text-sm font-medium text-muted-foreground">상태</p>
<p>{pqSubmission.vendorStatus}</p>
</div>
- {/* 필요시 추가 정보 표시 */}
+ <div>
+ <p className="text-sm font-medium text-muted-foreground">국가</p>
+ <p>{pqSubmission.vendorCountry}</p>
+ </div>
+ <div>
+ <p className="text-sm font-medium text-muted-foreground">이메일</p>
+ <p>{pqSubmission.vendorEmail}</p>
+ </div>
+ <div>
+ <p className="text-sm font-medium text-muted-foreground">전화번호</p>
+ <p>{pqSubmission.vendorPhone}</p>
+ </div>
+
+
+ {/* 필요시 추가 정보 표시 */}
</div>
</div>
</TabsContent>
diff --git a/app/api/revisions/max-serial-no/route.ts b/app/api/revisions/max-serial-no/route.ts
index c0bfe5c3..0681b66d 100644
--- a/app/api/revisions/max-serial-no/route.ts
+++ b/app/api/revisions/max-serial-no/route.ts
@@ -1,10 +1,16 @@
import { NextRequest, NextResponse } from 'next/server'
import db from '@/db/db'
-import { revisions, issueStages } from '@/db/schema/vendorDocu'
+import { revisions, issueStages, documents, projects } from '@/db/schema'
import { eq, sql } from 'drizzle-orm'
import { alias } from 'drizzle-orm/pg-core'
import { debugLog, debugError, debugSuccess } from '@/lib/debug-utils'
+// DOLCE Detail Document 타입 정의
+interface DOLCEDetailDocument {
+ RegisterSerialNoMax?: string | number
+ // 다른 필드들도 필요시 추가
+}
+
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url)
@@ -23,7 +29,7 @@ export async function GET(request: NextRequest) {
const parsedDocumentId = parseInt(documentId)
debugLog('3. Parsed documentId:', parsedDocumentId)
- // 해당 document의 모든 issueStages와 연결된 revisions에서 최대 serialNo 조회
+ // 1. 내부 DB에서 최대 serialNo 조회
const r = alias(revisions, 'r')
const is = alias(issueStages, 'is')
@@ -45,30 +51,114 @@ export async function GET(request: NextRequest) {
)
.where(eq(is.documentId, parsedDocumentId))
- debugLog('5. Query result:', maxSerialResult)
- debugLog('6. Query result length:', maxSerialResult.length)
- debugLog('7. First result item:', maxSerialResult[0])
+ debugLog('5. Internal DB query result:', maxSerialResult)
+
+ const internalMaxSerial = maxSerialResult[0]?.maxSerial || 0
+ const internalMaxRegisterSerial = maxSerialResult[0]?.maxRegisterSerial || 0
+ const internalMaxSerialNo = Math.max(internalMaxSerial, internalMaxRegisterSerial)
+
+ debugLog('6. Internal maxSerialNo:', internalMaxSerialNo)
+
+ // 2. Document 정보 조회 (DOLCE API 호출을 위해)
+ const documentInfo = await db
+ .select({
+ docNumber: documents.docNumber,
+ drawingKind: documents.drawingKind,
+ discipline: documents.discipline,
+ projectId: documents.projectId,
+ projectCode: projects.code
+ })
+ .from(documents)
+ .leftJoin(projects, eq(documents.projectId, projects.id))
+ .where(eq(documents.id, parsedDocumentId))
+ .limit(1)
+
+ debugLog('7. Document info:', documentInfo[0])
+
+ if (!documentInfo[0]) {
+ debugError('Document not found for id:', parsedDocumentId)
+ return NextResponse.json(
+ { error: 'Document not found' },
+ { status: 404 }
+ )
+ }
+
+ const { docNumber, drawingKind, discipline, projectCode } = documentInfo[0]
+
+ // 필수 필드 검증
+ if (!projectCode || !docNumber || !discipline || !drawingKind) {
+ debugLog('8. Missing required fields for DOLCE API')
+ debugLog(' - projectCode:', projectCode)
+ debugLog(' - docNumber:', docNumber)
+ debugLog(' - discipline:', discipline)
+ debugLog(' - drawingKind:', drawingKind)
+
+ // DOLCE API 호출 불가능한 경우, 내부 DB 값만 사용
+ return NextResponse.json({
+ maxSerialNo: internalMaxSerialNo,
+ nextSerialNo: internalMaxSerialNo + 1,
+ documentId: documentId,
+ source: 'internal_only',
+ debug: {
+ parsedDocumentId,
+ internalMaxSerialNo,
+ missingFields: {
+ projectCode: !projectCode,
+ docNumber: !docNumber,
+ discipline: !discipline,
+ drawingKind: !drawingKind
+ }
+ }
+ })
+ }
+
+ // 3. DOLCE API 호출
+ let dolceMaxSerialNo = 0
+ try {
+ debugLog('9. Calling DOLCE API...')
+ const dolceDocuments = await fetchDetailFromDOLCE(
+ projectCode,
+ docNumber,
+ discipline,
+ drawingKind
+ )
- const maxSerialValue = maxSerialResult[0]?.maxSerial || 0
- const maxRegisterSerialValue = maxSerialResult[0]?.maxRegisterSerial || 0
+ debugLog('10. DOLCE API response:', dolceDocuments)
- debugLog('8. maxSerial value:', maxSerialValue)
- debugLog('9. maxRegisterSerial value:', maxRegisterSerialValue)
+ if (dolceDocuments && dolceDocuments.length > 0) {
+ // 첫 번째 문서의 RegisterSerialNoMax 값 사용
+ const firstDoc = dolceDocuments[0]
+ if (firstDoc.RegisterSerialNoMax) {
+ dolceMaxSerialNo = parseInt(String(firstDoc.RegisterSerialNoMax)) || 0
+ debugLog('11. DOLCE maxSerialNo:', dolceMaxSerialNo)
+ }
+ }
+ } catch (error) {
+ debugError('DOLCE API call failed:', error)
+ // DOLCE API 실패 시에도 내부 DB 값은 사용
+ }
- const maxSerialNo = Math.max(maxSerialValue, maxRegisterSerialValue)
+ // 4. 내부 DB와 DOLCE 값 중 최대값 선택
+ const finalMaxSerialNo = Math.max(internalMaxSerialNo, dolceMaxSerialNo)
- debugSuccess('10. Final maxSerialNo:', maxSerialNo)
- debugSuccess('11. Next serialNo:', maxSerialNo + 1)
+ debugSuccess('12. Final maxSerialNo:', finalMaxSerialNo)
+ debugSuccess('13. Next serialNo:', finalMaxSerialNo + 1)
return NextResponse.json({
- maxSerialNo,
- nextSerialNo: maxSerialNo + 1,
+ maxSerialNo: finalMaxSerialNo,
+ nextSerialNo: finalMaxSerialNo + 1,
documentId: documentId,
+ source: dolceMaxSerialNo > internalMaxSerialNo ? 'dolce' : 'internal',
debug: {
parsedDocumentId,
- queryResult: maxSerialResult,
- maxSerialValue,
- maxRegisterSerialValue
+ internalMaxSerialNo,
+ dolceMaxSerialNo,
+ documentInfo: {
+ projectCode,
+ docNumber,
+ discipline,
+ drawingKind
+ }
}
})
} catch (error) {
@@ -79,4 +169,55 @@ export async function GET(request: NextRequest) {
{ status: 500 }
)
}
+}
+
+// DOLCE Detail API 호출 함수
+async function fetchDetailFromDOLCE(
+ projectCode: string,
+ drawingNo: string,
+ discipline: string,
+ drawingKind: string
+): Promise<DOLCEDetailDocument[]> {
+ const endpoint = process.env.DOLCE_DOC_DETAIL_API_URL || 'http://60.100.99.217:1111/Services/VDCSWebService.svc/DetailDwgReceiptMgmt'
+
+ const requestBody = {
+ project: projectCode,
+ drawingNo: drawingNo,
+ discipline: discipline,
+ drawingKind: drawingKind
+ }
+
+ console.log(`Fetching detail from DOLCE: ${projectCode} - ${drawingNo}`)
+ console.log('Request body:', requestBody)
+
+ try {
+ const response = await fetch(endpoint, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(requestBody)
+ })
+
+ if (!response.ok) {
+ const errorText = await response.text()
+ throw new Error(`DOLCE Detail API failed: HTTP ${response.status} - ${errorText}`)
+ }
+
+ const data = await response.json()
+
+ // DOLCE Detail API 응답 구조에 맞게 처리
+ if (data.DetailDwgReceiptMgmtResult) {
+ const documents = data.DetailDwgReceiptMgmtResult as DOLCEDetailDocument[]
+ console.log(`Found ${documents.length} detail records for ${drawingNo}`)
+ return documents
+ } else {
+ console.warn(`Unexpected DOLCE Detail response structure:`, data)
+ return []
+ }
+
+ } catch (error) {
+ console.error(`DOLCE Detail API call failed for ${drawingNo}:`, error)
+ throw error
+ }
} \ No newline at end of file