diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-08-14 11:54:47 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-08-14 11:54:47 +0000 |
| commit | 969c25b56f6d29d7ffa4bc2ce04c5fb4e5846b34 (patch) | |
| tree | 551d335e850e6163792ded0e7a75fa41d96d612a /app | |
| parent | dd20ba9785cdbd3d61f6b014d003d3bd9646ad13 (diff) | |
(대표님) 정규벤더등록, 벤더문서관리, 벤더데이터입력, 첨부파일관리
Diffstat (limited to 'app')
| -rw-r--r-- | app/[lng]/evcp/(evcp)/vendor-regular-registrations/page.tsx | 6 | ||||
| -rw-r--r-- | app/[lng]/partners/(partners)/document-list-only/[contractId]/page.tsx | 21 | ||||
| -rw-r--r-- | app/[lng]/partners/(partners)/document-list-only/page.tsx | 16 | ||||
| -rw-r--r-- | app/[lng]/partners/(partners)/document-list/page.tsx | 16 | ||||
| -rw-r--r-- | app/[lng]/partners/(partners)/registration-status/page.tsx | 24 | ||||
| -rw-r--r-- | app/[lng]/partners/(partners)/vendor-data/layout.tsx | 7 | ||||
| -rw-r--r-- | app/[lng]/partners/(partners)/vendor-data/page.tsx | 9 | ||||
| -rw-r--r-- | app/api/attachment-delete/route.ts | 76 | ||||
| -rw-r--r-- | app/api/files/[...path]/route.ts | 1 | ||||
| -rw-r--r-- | app/api/revision-attachment/route.ts | 102 | ||||
| -rw-r--r-- | app/api/revision-upload-ship/route.ts | 17 | ||||
| -rw-r--r-- | app/api/sync/batches/route.ts | 2 | ||||
| -rw-r--r-- | app/api/sync/config/route.ts | 8 | ||||
| -rw-r--r-- | app/api/sync/status/route.ts | 2 |
14 files changed, 234 insertions, 73 deletions
diff --git a/app/[lng]/evcp/(evcp)/vendor-regular-registrations/page.tsx b/app/[lng]/evcp/(evcp)/vendor-regular-registrations/page.tsx index 2260396c..e8433c55 100644 --- a/app/[lng]/evcp/(evcp)/vendor-regular-registrations/page.tsx +++ b/app/[lng]/evcp/(evcp)/vendor-regular-registrations/page.tsx @@ -1,5 +1,7 @@ import * as React from "react"
+export const dynamic = "force-dynamic"
+
import { Skeleton } from "@/components/ui/skeleton"
import { DataTableSkeleton } from "@/components/data-table/data-table-skeleton"
@@ -27,9 +29,9 @@ export default async function VendorRegularRegistrationsPage() { </h2>
<InformationButton pagePath="evcp/vendor-regular-registrations" />
</div>
- <p className="text-muted-foreground">
+ {/* <p className="text-muted-foreground">
정규업체 등록 현황을 확인하세요. 구매담당자가 정규업체 등록을 위한 현황 조회 및 협력업체에게 누락자료 요청하는 화면입니다.
- </p>
+ </p> */}
</div>
</div>
</div>
diff --git a/app/[lng]/partners/(partners)/document-list-only/[contractId]/page.tsx b/app/[lng]/partners/(partners)/document-list-only/[contractId]/page.tsx index e3cda9b4..7c38d5cf 100644 --- a/app/[lng]/partners/(partners)/document-list-only/[contractId]/page.tsx +++ b/app/[lng]/partners/(partners)/document-list-only/[contractId]/page.tsx @@ -6,6 +6,7 @@ import { type SearchParams } from "@/types/table" import { getValidFilters } from "@/lib/data-table" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Progress } from "@/components/ui/progress" +import { useTranslation } from "@/i18n" import { TrendingUp, AlertTriangle, @@ -22,6 +23,7 @@ import { getDocumentProgressStats, getDocumentStagesOnly } from "@/lib/vendor-do interface DocumentStagesManagementPageProps { params: { + lng?: string contractId: string } searchParams: Promise<SearchParams> @@ -29,14 +31,15 @@ interface DocumentStagesManagementPageProps { // 전체 진행률 카드 컴포넌트 -async function ProgressCard({ contractId }: { contractId: number }) { +async function ProgressCard({ contractId, lng }: { contractId: number, lng: string }) { const stats = await getDocumentProgressStats(contractId) + const { t } = await useTranslation(lng, 'engineering') return ( <Card> <CardHeader> <div className="flex items-center justify-between"> - <CardTitle className="text-lg">전체 진행률</CardTitle> + <CardTitle className="text-lg">{t('vendorDocuments.progress.overallProgress')}</CardTitle> <div className="flex items-center gap-2"> </div> </div> @@ -44,7 +47,7 @@ async function ProgressCard({ contractId }: { contractId: number }) { <CardContent> <div className="space-y-4"> <div className="flex justify-between text-sm"> - <span>평균 진행률</span> + <span>{t('vendorDocuments.progress.averageProgress')}</span> <span className="font-medium">{stats.avgProgress}%</span> </div> <Progress value={stats.avgProgress} className="w-full" /> @@ -52,19 +55,19 @@ async function ProgressCard({ contractId }: { contractId: number }) { <div className="grid grid-cols-2 md:grid-cols-4 gap-4 text-sm"> <div className="text-center p-2 bg-gray-50 rounded"> <div className="font-medium text-lg text-gray-900">{stats.totalDocuments}</div> - <div className="text-gray-600">전체</div> + <div className="text-gray-600">{t('vendorDocuments.progress.total')}</div> </div> <div className="text-center p-2 bg-green-50 rounded"> <div className="font-medium text-lg text-green-600">{stats.completedDocuments}</div> - <div className="text-green-600">완료</div> + <div className="text-green-600">{t('vendorDocuments.progress.completed')}</div> </div> <div className="text-center p-2 bg-blue-50 rounded"> <div className="font-medium text-lg text-blue-600">{stats.inProgressDocuments}</div> - <div className="text-blue-600">진행중</div> + <div className="text-blue-600">{t('vendorDocuments.progress.inProgress')}</div> </div> <div className="text-center p-2 bg-red-50 rounded"> <div className="font-medium text-lg text-red-600">{stats.overdueDocuments}</div> - <div className="text-red-600">지연</div> + <div className="text-red-600">{t('vendorDocuments.progress.overdue')}</div> </div> </div> </div> @@ -139,14 +142,16 @@ export default async function DocumentStagesManagementPage({ searchParams }: DocumentStagesManagementPageProps) { const resolvedParams = await params + const lng = resolvedParams?.lng || 'ko' const contractId = Number(resolvedParams.contractId) const resolvedSearchParams = await searchParams + const { t } = await useTranslation(lng, 'engineering') // 프로젝트 타입 결정 (실제로는 계약 정보에서 가져와야 함) const projectType = resolvedSearchParams.projectType === "plant" ? "plant" : "ship" if (isNaN(contractId)) { - throw new Error("유효하지 않은 계약 ID입니다") + throw new Error(t('vendorDocuments.errors.invalidContractId')) } return ( diff --git a/app/[lng]/partners/(partners)/document-list-only/page.tsx b/app/[lng]/partners/(partners)/document-list-only/page.tsx index 721eb408..fe7cf47a 100644 --- a/app/[lng]/partners/(partners)/document-list-only/page.tsx +++ b/app/[lng]/partners/(partners)/document-list-only/page.tsx @@ -1,18 +1,24 @@ // app/vendor-data/page.tsx import * as React from "react" import { Separator } from "@/components/ui/separator" +import { useTranslation } from "@/i18n" -export default async function IndexPage() { +interface Props { + params: { lng?: string } +} + +export default async function IndexPage({ params }: Props) { + const { lng } = await params + const language = lng || 'ko' + const { t } = await useTranslation(language, 'engineering') return ( <div className="space-y-6"> <div className="grid gap-4"> <div className="rounded-lg border p-4"> - <h4 className="text-sm font-medium">시작하는 방법</h4> + <h4 className="text-sm font-medium">{t('vendorDocuments.gettingStarted.title')}</h4> <p className="text-sm text-muted-foreground mt-1"> - 오른쪽 상단에서 프로젝트/계약을 선택하세요.<br /> - - + {t('vendorDocuments.gettingStarted.selectProject')} </p> </div> </div> diff --git a/app/[lng]/partners/(partners)/document-list/page.tsx b/app/[lng]/partners/(partners)/document-list/page.tsx index 721eb408..fe7cf47a 100644 --- a/app/[lng]/partners/(partners)/document-list/page.tsx +++ b/app/[lng]/partners/(partners)/document-list/page.tsx @@ -1,18 +1,24 @@ // app/vendor-data/page.tsx import * as React from "react" import { Separator } from "@/components/ui/separator" +import { useTranslation } from "@/i18n" -export default async function IndexPage() { +interface Props { + params: { lng?: string } +} + +export default async function IndexPage({ params }: Props) { + const { lng } = await params + const language = lng || 'ko' + const { t } = await useTranslation(language, 'engineering') return ( <div className="space-y-6"> <div className="grid gap-4"> <div className="rounded-lg border p-4"> - <h4 className="text-sm font-medium">시작하는 방법</h4> + <h4 className="text-sm font-medium">{t('vendorDocuments.gettingStarted.title')}</h4> <p className="text-sm text-muted-foreground mt-1"> - 오른쪽 상단에서 프로젝트/계약을 선택하세요.<br /> - - + {t('vendorDocuments.gettingStarted.selectProject')} </p> </div> </div> diff --git a/app/[lng]/partners/(partners)/registration-status/page.tsx b/app/[lng]/partners/(partners)/registration-status/page.tsx new file mode 100644 index 00000000..21bcea59 --- /dev/null +++ b/app/[lng]/partners/(partners)/registration-status/page.tsx @@ -0,0 +1,24 @@ +import * as React from "react"
+import { Suspense } from "react"
+
+import { Skeleton } from "@/components/ui/skeleton"
+import { Shell } from "@/components/shell"
+import { VendorRegistrationStatusView } from "@/lib/vendor-registration-status/vendor-registration-status-view"
+
+export default async function VendorRegistrationStatusPage() {
+ return (
+ <Shell className="gap-4">
+ <Suspense
+ fallback={
+ <div className="space-y-4">
+ <Skeleton className="h-10 w-full" />
+ <Skeleton className="h-64 w-full" />
+ <Skeleton className="h-32 w-full" />
+ </div>
+ }
+ >
+ <VendorRegistrationStatusView />
+ </Suspense>
+ </Shell>
+ )
+}
diff --git a/app/[lng]/partners/(partners)/vendor-data/layout.tsx b/app/[lng]/partners/(partners)/vendor-data/layout.tsx index 9621d23f..c37a983a 100644 --- a/app/[lng]/partners/(partners)/vendor-data/layout.tsx +++ b/app/[lng]/partners/(partners)/vendor-data/layout.tsx @@ -11,7 +11,7 @@ import { useTranslation } from "@/i18n" interface VendorDataLayoutProps { children: React.ReactNode - params?: { locale?: string } + params: { lng?: string } } // Layout 컴포넌트는 서버 컴포넌트입니다 @@ -20,8 +20,9 @@ export default async function VendorDataLayout({ params, }: VendorDataLayoutProps) { // 기본 언어는 'ko'로 설정, params.locale이 있으면 사용 - const lng = params?.locale || 'ko' - const { t } = await useTranslation(lng, 'engineering') + const { lng } = await params; + const language = lng || 'en' + const { t } = await useTranslation(language, 'engineering') const session = await getServerSession(authOptions) const vendorId = session?.user.companyId diff --git a/app/[lng]/partners/(partners)/vendor-data/page.tsx b/app/[lng]/partners/(partners)/vendor-data/page.tsx index db032377..0fbb6f0a 100644 --- a/app/[lng]/partners/(partners)/vendor-data/page.tsx +++ b/app/[lng]/partners/(partners)/vendor-data/page.tsx @@ -3,13 +3,14 @@ import { Separator } from "@/components/ui/separator" import { useTranslation } from "@/i18n" interface Props { - params: { locale?: string } + params: { lng?: string } } export default async function VendorDataPage({ params }: Props) { - // 기본 언어는 'ko'로 설정, params.locale이 있으면 사용 - const lng = params?.locale || 'ko' - const { t } = await useTranslation(lng, 'engineering') + // 기본 언어는 'ko'로 설정, params.lng이 있으면 사용 + const { lng } = await params + const language = lng || 'en' + const { t } = await useTranslation(language, 'engineering') return ( <div className="space-y-6"> diff --git a/app/api/attachment-delete/route.ts b/app/api/attachment-delete/route.ts new file mode 100644 index 00000000..254c579f --- /dev/null +++ b/app/api/attachment-delete/route.ts @@ -0,0 +1,76 @@ +// /api/attachment-delete/route.ts + +import { NextRequest, NextResponse } from 'next/server' +import db from '@/db/db' +import { documentAttachments } from '@/db/schema' // 실제 스키마에 맞게 수정 +import { eq, and } from 'drizzle-orm' +import fs from 'fs/promises' +import path from 'path' + +export async function DELETE(request: NextRequest) { + try { + const { attachmentId, revisionId } = await request.json() + + if (!attachmentId || !revisionId) { + return NextResponse.json( + { error: 'attachmentId and revisionId are required' }, + { status: 400 } + ) + } + + // 1. 데이터베이스에서 첨부파일 정보 조회 + const attachment = await db + .select() + .from(documentAttachments) + .where( + and( + eq(documentAttachments.id, attachmentId), + eq(documentAttachments.revisionId, revisionId) + ) + ) + .limit(1) + + if (!attachment || attachment.length === 0) { + return NextResponse.json( + { error: 'Attachment not found' }, + { status: 404 } + ) + } + + const attachmentData = attachment[0] + + // 2. dolceFilePath 체크 - 있으면 삭제 불가 + if (attachmentData.dolceFilePath && attachmentData.dolceFilePath.trim() !== '') { + return NextResponse.json( + { error: 'Cannot delete processed file' }, + { status: 403 } + ) + } + + // 4. 데이터베이스에서 첨부파일 레코드 삭제 + await db + .delete(documentAttachments) + .where( + and( + eq(documentAttachments.id, attachmentId), + eq(documentAttachments.revisionId, revisionId) + ) + ) + + return NextResponse.json({ + success: true, + message: 'Attachment deleted successfully', + deletedAttachmentId: attachmentId + }) + + } catch (error) { + console.error('Attachment deletion error:', error) + return NextResponse.json( + { + error: 'Internal server error', + details: error instanceof Error ? error.message : 'Unknown error' + }, + { status: 500 } + ) + } +}
\ No newline at end of file diff --git a/app/api/files/[...path]/route.ts b/app/api/files/[...path]/route.ts index 5eab8210..9ef11bc7 100644 --- a/app/api/files/[...path]/route.ts +++ b/app/api/files/[...path]/route.ts @@ -36,6 +36,7 @@ const isAllowedPath = (requestedPath: string): boolean => { 'vendorFormReportSample', 'vendorFormData', 'uploads', + 'documents', 'tech-sales', 'techsales-rfq', 'tech-vendors', diff --git a/app/api/revision-attachment/route.ts b/app/api/revision-attachment/route.ts index 092eed8d..46c2e9c9 100644 --- a/app/api/revision-attachment/route.ts +++ b/app/api/revision-attachment/route.ts @@ -1,8 +1,4 @@ import { NextRequest, NextResponse } from "next/server" -import { writeFile } from "fs/promises" -import { join } from "path" -import { v4 as uuidv4 } from "uuid" -import path from "path" import { revalidateTag } from "next/cache" import db from "@/db/db" @@ -14,6 +10,9 @@ import { } from "@/db/schema/vendorDocu" import { eq } from "drizzle-orm" +/* 보안 강화된 파일 저장 유틸리티 */ +import { saveFile, SaveFileResult, saveFileStream } from "@/lib/file-stroage" + /* change log 유틸 */ import { logAttachmentChange, @@ -35,13 +34,16 @@ export async function POST(request: NextRequest) { if (!attachmentFiles.length) return NextResponse.json({ error: "No files provided" }, { status: 400 }) - const MAX = 50 * 1024 * 1024 // 50MB - for (const f of attachmentFiles) - if (f.size > MAX) + // 기본 파일 크기 검증 (보안 함수에서도 검증하지만 조기 체크) + const MAX = 1024 * 1024 * 1024 // 1GB로 증가 (첫 번째 파일과 동일) + for (const f of attachmentFiles) { + if (f.size > MAX) { return NextResponse.json( - { error: `${f.name} exceeds 50MB limit` }, + { error: `${f.name} exceeds 1GB limit` }, { status: 400 } ) + } + } /* ------- 리비전 및 계약 정보 확보 ------- */ const [revisionInfo] = await db @@ -52,6 +54,7 @@ export async function POST(request: NextRequest) { usageType: revisions.usageType, issueStageId: revisions.issueStageId, projectId: documents.projectId, + vendorId: documents.vendorId, }) .from(revisions) .innerJoin(issueStages, eq(revisions.issueStageId, issueStages.id)) @@ -63,41 +66,60 @@ export async function POST(request: NextRequest) { return NextResponse.json({ error: "Revision not found" }, { status: 404 }) } + // vendorId가 null인 경우 처리 + if (!revisionInfo.vendorId) { + return NextResponse.json({ + error: "Revision must have a valid vendor ID for synchronization" + }, { status: 400 }) + } + /* ------- 트랜잭션 ------- */ const result = await db.transaction(async (tx) => { - /* 첨부파일 처리 */ + /* ------- 보안 강화된 첨부파일 처리 ------- */ const uploadedFiles: any[] = [] - const baseDir = join(process.cwd(), "public", "documents") + const securityFailures: string[] = [] for (const file of attachmentFiles) { - const ext = path.extname(file.name) - const fname = uuidv4() + ext - const dest = join(baseDir, fname) - - await writeFile(dest, Buffer.from(await file.arrayBuffer())) - + console.log(`🔐 보안 검증 시작: ${file.name}`) + + // 보안 강화된 파일 저장 + const saveResult = file.size > 100 * 1024 * 1024 + ? await saveFileStream({ file, directory: "documents", userId: uploaderName || "" }) + : await saveFile({ file, directory: "documents", userId: uploaderName || "" }) + + if (!saveResult.success) { + console.error(`❌ 파일 보안 검증 실패: ${file.name} - ${saveResult.error}`) + securityFailures.push(`${file.name}: ${saveResult.error}`) + continue // 실패한 파일은 건너뛰고 계속 진행 + } + + console.log(`✅ 파일 보안 검증 통과: ${file.name}`) + console.log(`📁 저장된 경로: ${saveResult.publicPath}`) + + // DB에 첨부파일 정보 저장 const [att] = await tx.insert(documentAttachments) .values({ revisionId, - fileName: file.name, - filePath: "/documents/" + fname, - fileSize: file.size, - fileType: ext.slice(1).toLowerCase() || undefined, + fileName: saveResult.originalName!, // 원본 파일명 + filePath: saveResult.publicPath!, // 웹 접근 경로 + fileSize: saveResult.fileSize!, + fileType: saveResult.fileName!.split('.').pop()?.toLowerCase() || undefined, updatedAt: new Date(), }) .returning() uploadedFiles.push({ id: att.id, - fileName: file.name, - fileSize: file.size, - filePath: att.filePath, - fileType: ext.slice(1).toLowerCase() || null, + fileName: saveResult.originalName, + fileSize: saveResult.fileSize, + filePath: saveResult.publicPath, + fileType: saveResult.fileName!.split('.').pop()?.toLowerCase() || null, + securityChecks: saveResult.securityChecks, // 보안 검증 결과 }) // change_logs: attachment CREATE await logAttachmentChange( - revisionInfo.projectId, + revisionInfo.vendorId!, att.id, "CREATE", att, @@ -108,6 +130,16 @@ export async function POST(request: NextRequest) { ) } + // 보안 검증 실패한 파일이 있으면 경고 반환 + if (securityFailures.length > 0) { + console.warn(`⚠️ 일부 파일의 보안 검증 실패:`, securityFailures) + + // 모든 파일이 실패한 경우 에러 반환 + if (uploadedFiles.length === 0) { + throw new Error(`모든 파일의 보안 검증이 실패했습니다: ${securityFailures.join(', ')}`) + } + } + /* 리비전 updatedAt 업데이트 */ await tx.update(revisions) .set({ updatedAt: new Date() }) @@ -119,30 +151,36 @@ export async function POST(request: NextRequest) { usage: revisionInfo.usage, usageType: revisionInfo.usageType, uploadedFiles, - projectId: revisionInfo.projectId + vendorId: revisionInfo.vendorId, + securityFailures // 보안 실패 정보 포함 } }) // 캐시 무효화 try { - // revalidateTag(`enhanced-documents-${result.projectId}`) - revalidateTag(`sync-status-${result.projectId}`) - - console.log(`✅ Cache invalidated for contract ${result.projectId}`) + revalidateTag(`sync-status-${result.vendorId}`) + console.log(`✅ Cache invalidated for contract ${result.vendorId}`) } catch (cacheError) { console.warn('⚠️ Cache invalidation failed:', cacheError) } + // 응답 메시지 구성 + let message = `${result.uploadedFiles.length}개 첨부파일이 추가되었습니다` + if (result.securityFailures.length > 0) { + message += ` (일부 파일 보안 검증 실패: ${result.securityFailures.length}개)` + } + return NextResponse.json({ success: true, - message: `${result.uploadedFiles.length}개 첨부파일이 추가되었습니다`, + message, data: { revisionId: result.revisionId, revision: result.revision, usage: result.usage, usageType: result.usageType, uploadedFiles: result.uploadedFiles, - filesCount: result.uploadedFiles.length + filesCount: result.uploadedFiles.length, + securityFailures: result.securityFailures, // 클라이언트에 보안 실패 정보 전달 }, }) } catch (e) { diff --git a/app/api/revision-upload-ship/route.ts b/app/api/revision-upload-ship/route.ts index 671b8bac..b07a3d9c 100644 --- a/app/api/revision-upload-ship/route.ts +++ b/app/api/revision-upload-ship/route.ts @@ -56,7 +56,8 @@ export async function POST(request: NextRequest) { const [docInfo] = await db .select({ contractId: documents.contractId, - projectId: documents.projectId + projectId: documents.projectId , + vendorId: documents.vendorId , }) .from(documents) .where(eq(documents.id, docId)) @@ -67,7 +68,7 @@ export async function POST(request: NextRequest) { } // projectId가 null인 경우 처리 - if (!docInfo.projectId) { + if (!docInfo.vendorId) { return NextResponse.json({ error: "Document must have a valid project ID for synchronization" }, { status: 400 }) @@ -158,7 +159,7 @@ export async function POST(request: NextRequest) { revisionData = updated await logRevisionChange( - docInfo.projectId!, // null 체크 후이므로 non-null assertion 사용 + docInfo.vendorId!, // null 체크 후이므로 non-null assertion 사용 revisionId, "UPDATE", updated, @@ -188,7 +189,7 @@ export async function POST(request: NextRequest) { revisionData = newRev await logRevisionChange( - docInfo.projectId!, // null 체크 후이므로 non-null assertion 사용 + docInfo.vendorId!, // null 체크 후이므로 non-null assertion 사용 revisionId, "CREATE", newRev, @@ -243,7 +244,7 @@ export async function POST(request: NextRequest) { // change_logs: attachment CREATE await logAttachmentChange( - docInfo.projectId!, + docInfo.vendorId!, att.id, "CREATE", att, @@ -275,7 +276,7 @@ export async function POST(request: NextRequest) { stage, revision, uploadedFiles, - contractId: docInfo.contractId, + vendorId: docInfo.vendorId, usage, usageType, securityFailures // 보안 실패 정보 포함 @@ -284,8 +285,8 @@ export async function POST(request: NextRequest) { // 캐시 무효화 try { - revalidateTag(`sync-status-${result.contractId}`) - console.log(`✅ Cache invalidated for contract ${result.contractId}`) + revalidateTag(`sync-status-${result.vendorId}`) + console.log(`✅ Cache invalidated for contract ${result.vendorId}`) } catch (cacheError) { console.warn('⚠️ Cache invalidation failed:', cacheError) } diff --git a/app/api/sync/batches/route.ts b/app/api/sync/batches/route.ts index 7a72530d..1f37d6e6 100644 --- a/app/api/sync/batches/route.ts +++ b/app/api/sync/batches/route.ts @@ -10,7 +10,7 @@ export async function GET(request: NextRequest) { if (!projectId) { return NextResponse.json( - { error: 'Contract ID is required' }, + { error: 'Vendor ID is required' }, { status: 400 } ) } diff --git a/app/api/sync/config/route.ts b/app/api/sync/config/route.ts index db5d17ca..2e9a073a 100644 --- a/app/api/sync/config/route.ts +++ b/app/api/sync/config/route.ts @@ -6,10 +6,10 @@ import { authOptions } from "@/app/api/auth/[...nextauth]/route" export async function GET(request: NextRequest) { try { const { searchParams } = new URL(request.url) - const projectId = searchParams.get('projectId') + const vendorId = searchParams.get('vendorId') const targetSystem = searchParams.get('targetSystem') || 'SHI' - if (!projectId) { + if (!vendorId) { return NextResponse.json( { error: 'Contract ID is required' }, { status: 400 } @@ -17,7 +17,7 @@ export async function GET(request: NextRequest) { } const config = await syncService.getSyncConfig( - parseInt(projectId), + parseInt(vendorId), targetSystem ) @@ -65,7 +65,7 @@ export async function POST(request: NextRequest) { } await syncService.upsertSyncConfig({ - projectId, + vendorId, targetSystem, endpointUrl, authToken, diff --git a/app/api/sync/status/route.ts b/app/api/sync/status/route.ts index b4b18577..05101d2b 100644 --- a/app/api/sync/status/route.ts +++ b/app/api/sync/status/route.ts @@ -38,7 +38,7 @@ export async function GET(request: NextRequest) { if (!projectId) { return NextResponse.json( - { error: 'Project ID is required' }, + { error: 'project ID is required' }, { status: 400 } ) } |
