summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/[lng]/evcp/(evcp)/vendor-regular-registrations/page.tsx6
-rw-r--r--app/[lng]/partners/(partners)/document-list-only/[contractId]/page.tsx21
-rw-r--r--app/[lng]/partners/(partners)/document-list-only/page.tsx16
-rw-r--r--app/[lng]/partners/(partners)/document-list/page.tsx16
-rw-r--r--app/[lng]/partners/(partners)/registration-status/page.tsx24
-rw-r--r--app/[lng]/partners/(partners)/vendor-data/layout.tsx7
-rw-r--r--app/[lng]/partners/(partners)/vendor-data/page.tsx9
-rw-r--r--app/api/attachment-delete/route.ts76
-rw-r--r--app/api/files/[...path]/route.ts1
-rw-r--r--app/api/revision-attachment/route.ts102
-rw-r--r--app/api/revision-upload-ship/route.ts17
-rw-r--r--app/api/sync/batches/route.ts2
-rw-r--r--app/api/sync/config/route.ts8
-rw-r--r--app/api/sync/status/route.ts2
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 }
)
}