diff options
Diffstat (limited to 'app/api/vendor-responses')
| -rw-r--r-- | app/api/vendor-responses/update-comment/route.ts | 60 | ||||
| -rw-r--r-- | app/api/vendor-responses/update/route.ts | 121 | ||||
| -rw-r--r-- | app/api/vendor-responses/upload/route.ts | 105 | ||||
| -rw-r--r-- | app/api/vendor-responses/waive/route.ts | 69 |
4 files changed, 355 insertions, 0 deletions
diff --git a/app/api/vendor-responses/update-comment/route.ts b/app/api/vendor-responses/update-comment/route.ts new file mode 100644 index 00000000..212173d7 --- /dev/null +++ b/app/api/vendor-responses/update-comment/route.ts @@ -0,0 +1,60 @@ +// app/api/vendor-responses/update-comment/route.ts +import { NextRequest, NextResponse } from "next/server"; +import db from "@/db/db"; +import { vendorAttachmentResponses } from "@/db/schema"; + +import { getServerSession } from "next-auth/next" +import { authOptions } from "@/app/api/auth/[...nextauth]/route" + +export async function POST(request: NextRequest) { + try { + // 인증 확인 + const session = await getServerSession(authOptions); + if (!session?.user?.id) { + return NextResponse.json( + { message: "인증이 필요합니다." }, + { status: 401 } + ); + } + + const body = await request.json(); + const { responseId, responseComment, vendorComment } = body; + + if (!responseId) { + return NextResponse.json( + { message: "응답 ID가 필요합니다." }, + { status: 400 } + ); + } + + // 코멘트만 업데이트 + const [updatedResponse] = await db + .update(vendorAttachmentResponses) + .set({ + responseComment, + vendorComment, + updatedAt: new Date(), + }) + .where(eq(vendorAttachmentResponses.id, parseInt(responseId))) + .returning(); + + if (!updatedResponse) { + return NextResponse.json( + { message: "응답을 찾을 수 없습니다." }, + { status: 404 } + ); + } + + return NextResponse.json({ + message: "코멘트가 성공적으로 업데이트되었습니다.", + response: updatedResponse, + }); + + } catch (error) { + console.error("Comment update error:", error); + return NextResponse.json( + { message: "코멘트 업데이트 중 오류가 발생했습니다." }, + { status: 500 } + ); + } +}
\ No newline at end of file diff --git a/app/api/vendor-responses/update/route.ts b/app/api/vendor-responses/update/route.ts new file mode 100644 index 00000000..8771b062 --- /dev/null +++ b/app/api/vendor-responses/update/route.ts @@ -0,0 +1,121 @@ +// app/api/vendor-responses/update/route.ts +import { NextRequest, NextResponse } from "next/server"; +import db from "@/db/db"; +import { vendorAttachmentResponses } from "@/db/schema"; +import { eq } from "drizzle-orm"; +import { getServerSession } from "next-auth/next" +import { authOptions } from "@/app/api/auth/[...nextauth]/route" + +// 리비전 번호를 증가시키는 헬퍼 함수 +function getNextRevision(currentRevision?: string): string { + if (!currentRevision) { + return "Rev.1"; // 첫 번째 응답 + } + + // "Rev.1" -> 1, "Rev.2" -> 2 형태로 숫자 추출 + const match = currentRevision.match(/Rev\.(\d+)/); + if (match) { + const currentNumber = parseInt(match[1]); + return `Rev.${currentNumber + 1}`; + } + + // 형식이 다르면 기본값 반환 + return "Rev.1"; +} + +export async function POST(request: NextRequest) { + try { + // 인증 확인 + const session = await getServerSession(authOptions); + if (!session?.user?.id) { + return NextResponse.json( + { message: "인증이 필요합니다." }, + { status: 401 } + ); + } + + const body = await request.json(); + const { + responseId, + responseStatus, + responseComment, + vendorComment, + respondedAt, + } = body; + + if (!responseId) { + return NextResponse.json( + { message: "응답 ID가 필요합니다." }, + { status: 400 } + ); + } + + // 1. 기존 응답 정보 조회 (현재 respondedRevision 확인) + const existingResponse = await db + .select() + .from(vendorAttachmentResponses) + .where(eq(vendorAttachmentResponses.id, parseInt(responseId))) + .limit(1); + + if (!existingResponse || existingResponse.length === 0) { + return NextResponse.json( + { message: "응답을 찾을 수 없습니다." }, + { status: 404 } + ); + } + + const currentResponse = existingResponse[0]; + + // 2. 벤더 응답 리비전 결정 + let nextRespondedRevision: string; + + if (responseStatus === "RESPONDED") { + // 새로운 응답이거나 수정 응답인 경우 리비전 증가 + if (currentResponse.responseStatus === "NOT_RESPONDED" || + currentResponse.responseStatus === "REVISION_REQUESTED") { + // 첫 응답이거나 수정 요청 후 재응답인 경우 리비전 증가 + nextRespondedRevision = getNextRevision(currentResponse.respondedRevision); + } else { + // 이미 응답된 상태에서 다시 업데이트하는 경우 (코멘트 수정 등) + nextRespondedRevision = currentResponse.respondedRevision || "Rev.1"; + } + } else { + // WAIVED 등 다른 상태는 기존 리비전 유지 + nextRespondedRevision = currentResponse.respondedRevision || ""; + } + + // 3. vendor response 업데이트 + const [updatedResponse] = await db + .update(vendorAttachmentResponses) + .set({ + responseStatus, + respondedRevision: nextRespondedRevision, + responseComment, + vendorComment, + respondedAt: respondedAt ? new Date(respondedAt) : null, + updatedAt: new Date(), + }) + .where(eq(vendorAttachmentResponses.id, parseInt(responseId))) + .returning(); + + if (!updatedResponse) { + return NextResponse.json( + { message: "응답 업데이트에 실패했습니다." }, + { status: 500 } + ); + } + + return NextResponse.json({ + message: "응답이 성공적으로 업데이트되었습니다.", + response: updatedResponse, + newRevision: nextRespondedRevision, // 새로운 리비전 정보 반환 + }); + + } catch (error) { + console.error("Response update error:", error); + return NextResponse.json( + { message: "응답 업데이트 중 오류가 발생했습니다." }, + { status: 500 } + ); + } +}
\ No newline at end of file diff --git a/app/api/vendor-responses/upload/route.ts b/app/api/vendor-responses/upload/route.ts new file mode 100644 index 00000000..111e4bd4 --- /dev/null +++ b/app/api/vendor-responses/upload/route.ts @@ -0,0 +1,105 @@ +// app/api/vendor-response-attachments/upload/route.ts +import { NextRequest, NextResponse } from "next/server"; +import { writeFile, mkdir } from "fs/promises"; +import { existsSync } from "fs"; +import path from "path"; +import db from "@/db/db"; +import { vendorResponseAttachmentsB } from "@/db/schema"; +import { getServerSession } from "next-auth/next" +import { authOptions } from "@/app/api/auth/[...nextauth]/route" + +export async function POST(request: NextRequest) { + try { + // 인증 확인 + const session = await getServerSession(authOptions); + if (!session?.user?.id) { + return NextResponse.json( + { message: "인증이 필요합니다." }, + { status: 401 } + ); + } + + const formData = await request.formData(); + const responseId = formData.get("responseId") as string; + const file = formData.get("file") as File; + const description = formData.get("description") as string; + + if (!responseId) { + return NextResponse.json( + { message: "응답 ID가 필요합니다." }, + { status: 400 } + ); + } + + if (!file) { + return NextResponse.json( + { message: "파일이 선택되지 않았습니다." }, + { status: 400 } + ); + } + + // 파일 크기 검증 (10MB) + if (file.size > 10 * 1024 * 1024) { + return NextResponse.json( + { message: "파일이 너무 큽니다. (최대 10MB)" }, + { status: 400 } + ); + } + + // 업로드 디렉토리 생성 + const uploadDir = path.join( + process.cwd(), + "public", + "uploads", + "vendor-responses", + responseId + ); + + if (!existsSync(uploadDir)) { + await mkdir(uploadDir, { recursive: true }); + } + + // 고유한 파일명 생성 + const timestamp = Date.now(); + const sanitizedName = file.name.replace(/[^a-zA-Z0-9.-]/g, "_"); + const fileName = `${timestamp}_${sanitizedName}`; + const filePath = `/uploads/vendor-responses/${responseId}/${fileName}`; + const fullPath = path.join(uploadDir, fileName); + + // 파일 저장 + const buffer = Buffer.from(await file.arrayBuffer()); + await writeFile(fullPath, buffer); + + // DB에 파일 정보 저장 + const [insertedFile] = await db + .insert(vendorResponseAttachmentsB) + .values({ + vendorResponseId: parseInt(responseId), + fileName, + originalFileName: file.name, + filePath, + fileSize: file.size, + fileType: file.type || path.extname(file.name).slice(1), + description: description || null, + uploadedBy: parseInt(session.user.id), + }) + .returning(); + + return NextResponse.json({ + id: insertedFile.id, + fileName, + originalFileName: file.name, + filePath, + fileSize: file.size, + fileType: file.type || path.extname(file.name).slice(1), + message: "파일이 성공적으로 업로드되었습니다.", + }); + + } catch (error) { + console.error("File upload error:", error); + return NextResponse.json( + { message: "파일 업로드 중 오류가 발생했습니다." }, + { status: 500 } + ); + } +}
\ No newline at end of file diff --git a/app/api/vendor-responses/waive/route.ts b/app/api/vendor-responses/waive/route.ts new file mode 100644 index 00000000..e732e8d2 --- /dev/null +++ b/app/api/vendor-responses/waive/route.ts @@ -0,0 +1,69 @@ +// app/api/vendor-responses/waive/route.ts +import { NextRequest, NextResponse } from "next/server"; +import db from "@/db/db"; +import { getServerSession } from "next-auth/next" +import { authOptions } from "@/app/api/auth/[...nextauth]/route" +import { eq } from "drizzle-orm"; +import { vendorAttachmentResponses } from "@/db/schema"; + +export async function POST(request: NextRequest) { + try { + // 인증 확인 + const session = await getServerSession(authOptions); + if (!session?.user?.id) { + return NextResponse.json( + { message: "인증이 필요합니다." }, + { status: 401 } + ); + } + + const body = await request.json(); + const { responseId, responseComment, vendorComment } = body; + + if (!responseId) { + return NextResponse.json( + { message: "응답 ID가 필요합니다." }, + { status: 400 } + ); + } + + if (!responseComment) { + return NextResponse.json( + { message: "포기 사유를 입력해주세요." }, + { status: 400 } + ); + } + + // vendor response를 WAIVED 상태로 업데이트 + const [updatedResponse] = await db + .update(vendorAttachmentResponses) + .set({ + responseStatus: "WAIVED", + responseComment, + vendorComment, + respondedAt: new Date(), + updatedAt: new Date(), + }) + .where(eq(vendorAttachmentResponses.id, parseInt(responseId))) + .returning(); + + if (!updatedResponse) { + return NextResponse.json( + { message: "응답을 찾을 수 없습니다." }, + { status: 404 } + ); + } + + return NextResponse.json({ + message: "응답이 성공적으로 포기 처리되었습니다.", + response: updatedResponse, + }); + + } catch (error) { + console.error("Waive response error:", error); + return NextResponse.json( + { message: "응답 포기 처리 중 오류가 발생했습니다." }, + { status: 500 } + ); + } +}
\ No newline at end of file |
