diff options
Diffstat (limited to 'lib/vendor-rfq-response/service.ts')
| -rw-r--r-- | lib/vendor-rfq-response/service.ts | 181 |
1 files changed, 172 insertions, 9 deletions
diff --git a/lib/vendor-rfq-response/service.ts b/lib/vendor-rfq-response/service.ts index cba6c414..8f2954d7 100644 --- a/lib/vendor-rfq-response/service.ts +++ b/lib/vendor-rfq-response/service.ts @@ -1,10 +1,14 @@ -import { unstable_cache } from "next/cache"; +'use server' + +import { revalidateTag, unstable_cache } from "next/cache"; import db from "@/db/db"; import { and, desc, eq, inArray, isNull, or, sql } from "drizzle-orm"; -import { rfqAttachments, rfqComments, rfqItems } from "@/db/schema/rfq"; +import { rfqAttachments, rfqComments, rfqItems, vendorResponses } from "@/db/schema/rfq"; import { vendorResponsesView, vendorTechnicalResponses, vendorCommercialResponses, vendorResponseAttachments } from "@/db/schema/rfq"; import { items } from "@/db/schema/items"; import { GetRfqsForVendorsSchema } from "../rfqs/validations"; +import { ItemData } from "./vendor-cbe-table/rfq-items-table/rfq-items-table"; +import * as z from "zod" @@ -27,7 +31,7 @@ export async function getRfqResponsesForVendor(input: GetRfqsForVendorsSchema, v ); } - // 벤더 ID 필터링 + // 협력업체 ID 필터링 const mainWhere = and(eq(vendorResponsesView.vendorId, vendorId), globalWhere); // 정렬: 응답 시간순 @@ -75,7 +79,7 @@ export async function getRfqResponsesForVendor(input: GetRfqsForVendorsSchema, v .leftJoin(items, eq(rfqItems.itemCode, items.itemCode)) .where(inArray(rfqItems.rfqId, distinctRfqs)); - // 3-B) RFQ 첨부 파일 (벤더용) + // 3-B) RFQ 첨부 파일 (협력업체용) const attachAll = await db .select() .from(rfqAttachments) @@ -101,7 +105,7 @@ export async function getRfqResponsesForVendor(input: GetRfqsForVendorsSchema, v ); - // 3-E) 벤더 응답 상세 - 기술 + // 3-E) 협력업체 응답 상세 - 기술 const technicalResponsesAll = await db .select() .from(vendorTechnicalResponses) @@ -112,7 +116,7 @@ export async function getRfqResponsesForVendor(input: GetRfqsForVendorsSchema, v ) ); - // 3-F) 벤더 응답 상세 - 상업 + // 3-F) 협력업체 응답 상세 - 상업 const commercialResponsesAll = await db .select() .from(vendorCommercialResponses) @@ -123,7 +127,7 @@ export async function getRfqResponsesForVendor(input: GetRfqsForVendorsSchema, v ) ); - // 3-G) 벤더 응답 첨부 파일 + // 3-G) 협력업체 응답 첨부 파일 const responseAttachmentsAll = await db .select() .from(vendorResponseAttachments) @@ -257,7 +261,7 @@ export async function getRfqResponsesForVendor(input: GetRfqsForVendorsSchema, v projectCode: row.projectCode, projectName: row.projectName, - // 벤더 정보 + // 협력업체 정보 vendorId: row.vendorId, vendorName: row.vendorName, vendorCode: row.vendorCode, @@ -277,7 +281,7 @@ export async function getRfqResponsesForVendor(input: GetRfqsForVendorsSchema, v result: row.cbeResult, } : null, - // 벤더 응답 상세 + // 협력업체 응답 상세 technicalResponse: techResponseByResponseId.get(row.responseId) || null, commercialResponse: commResponseByResponseId.get(row.responseId) || null, responseAttachments: respAttachByResponseId.get(row.responseId) || [], @@ -298,4 +302,163 @@ export async function getRfqResponsesForVendor(input: GetRfqsForVendorsSchema, v tags: ["rfqs-vendor", `vendor-${vendorId}`], } )(); +} + + +export async function getItemsByRfqId(rfqId: number): Promise<ResponseType> { + try { + if (!rfqId || isNaN(Number(rfqId))) { + return { + success: false, + error: "Invalid RFQ ID provided", + } + } + + // Query the database to get all items for the given RFQ ID + const items = await db + .select() + .from(rfqItems) + .where(eq(rfqItems.rfqId, rfqId)) + .orderBy(rfqItems.itemCode) + + + return { + success: true, + data: items as ItemData[], + } + } catch (error) { + console.error("Error fetching RFQ items:", error) + + return { + success: false, + error: error instanceof Error ? error.message : "Unknown error occurred when fetching RFQ items", + } + } +} + + +// Define the schema for validation +const commercialResponseSchema = z.object({ + responseId: z.number(), + vendorId: z.number(), // Added vendorId field + responseStatus: z.enum(["PENDING", "IN_PROGRESS", "SUBMITTED", "REJECTED", "ACCEPTED"]), + totalPrice: z.number().optional(), + currency: z.string().default("USD"), + paymentTerms: z.string().optional(), + incoterms: z.string().optional(), + deliveryPeriod: z.string().optional(), + warrantyPeriod: z.string().optional(), + validityPeriod: z.string().optional(), + priceBreakdown: z.string().optional(), + commercialNotes: z.string().optional(), +}) + +type CommercialResponseInput = z.infer<typeof commercialResponseSchema> + +interface ResponseType { + success: boolean + error?: string + data?: any +} + +export async function updateCommercialResponse(input: CommercialResponseInput): Promise<ResponseType> { + try { + // Validate input data + const validated = commercialResponseSchema.parse(input) + + // Check if a commercial response already exists for this responseId + const existingResponse = await db + .select() + .from(vendorCommercialResponses) + .where(eq(vendorCommercialResponses.responseId, validated.responseId)) + .limit(1) + + const now = new Date() + + if (existingResponse.length > 0) { + // Update existing record + await db + .update(vendorCommercialResponses) + .set({ + responseStatus: validated.responseStatus, + totalPrice: validated.totalPrice, + currency: validated.currency, + paymentTerms: validated.paymentTerms, + incoterms: validated.incoterms, + deliveryPeriod: validated.deliveryPeriod, + warrantyPeriod: validated.warrantyPeriod, + validityPeriod: validated.validityPeriod, + priceBreakdown: validated.priceBreakdown, + commercialNotes: validated.commercialNotes, + updatedAt: now, + }) + .where(eq(vendorCommercialResponses.responseId, validated.responseId)) + + } else { + // Return error instead of creating a new record + return { + success: false, + error: "해당 응답 ID에 대한 상업 응답 정보를 찾을 수 없습니다." + } + } + + // Also update the main vendor response status if submitted + if (validated.responseStatus === "SUBMITTED") { + // Get the vendor response + const vendorResponseResult = await db + .select() + .from(vendorResponses) + .where(eq(vendorResponses.id, validated.responseId)) + .limit(1) + + if (vendorResponseResult.length > 0) { + // Update the main response status to RESPONDED + await db + .update(vendorResponses) + .set({ + responseStatus: "RESPONDED", + updatedAt: now, + }) + .where(eq(vendorResponses.id, validated.responseId)) + } + } + + // Use vendorId for revalidateTag + revalidateTag(`cbe-vendor-${validated.vendorId}`) + + return { + success: true, + data: { responseId: validated.responseId } + } + + } catch (error) { + console.error("Error updating commercial response:", error) + + if (error instanceof z.ZodError) { + return { + success: false, + error: "유효하지 않은 데이터가 제공되었습니다." + } + } + + return { + success: false, + error: error instanceof Error ? error.message : "Unknown error occurred" + } + } +} +// Helper function to get responseId from rfqId and vendorId +export async function getCommercialResponseByResponseId(responseId: number): Promise<any | null> { + try { + const response = await db + .select() + .from(vendorCommercialResponses) + .where(eq(vendorCommercialResponses.responseId, responseId)) + .limit(1) + + return response.length > 0 ? response[0] : null + } catch (error) { + console.error("Error getting commercial response:", error) + return null + } }
\ No newline at end of file |
