"use server"; import db from "@/db/db"; import { rfqsLast, rfqLastDetails } from "@/db/schema"; import { eq, and } from "drizzle-orm"; import { revalidatePath } from "next/cache"; // ===== PO (SAP) 생성 ===== interface CreatePOParams { rfqId: number; vendorId: number; vendorName: string; totalAmount: number; currency: string; selectionReason?: string; } export async function createPO(params: CreatePOParams) { try { const userId = 1; // TODO: 실제 사용자 ID 가져오기 // 1. 선정된 업체 확인 const [selectedVendor] = await db .select() .from(rfqLastDetails) .where( and( eq(rfqLastDetails.rfqsLastId, params.rfqId), eq(rfqLastDetails.vendorsId, params.vendorId), eq(rfqLastDetails.isSelected, true), eq(rfqLastDetails.isLatest, true) ) ); if (!selectedVendor) { throw new Error("선정된 업체 정보를 찾을 수 없습니다."); } // 2. SAP 연동 로직 (TODO: 실제 구현 필요) // - SAP API 호출 // - PO 번호 생성 // - 아이템 정보 전송 // - 결재 라인 설정 // 3. 계약 상태 업데이트 await db.transaction(async (tx) => { // rfqLastDetails에 계약 정보 업데이트 await tx .update(rfqLastDetails) .set({ contractStatus: "진행중", contractCreatedAt: new Date(), contractNo: `PO-${Date.now()}`, // TODO: 실제 PO 번호로 변경 updatedAt: new Date(), updatedBy: userId, }) .where( and( eq(rfqLastDetails.rfqsLastId, params.rfqId), eq(rfqLastDetails.vendorsId, params.vendorId), eq(rfqLastDetails.isSelected, true) ) ); // RFQ 상태 업데이트 await tx .update(rfqsLast) .set({ status: "PO 생성 완료", updatedAt: new Date(), }) .where(eq(rfqsLast.id, params.rfqId)); }); revalidatePath(`/rfq/${params.rfqId}`); revalidatePath("/rfq"); return { success: true, message: "PO가 성공적으로 생성되었습니다.", poNumber: `PO-${Date.now()}`, // TODO: 실제 PO 번호 반환 }; } catch (error) { console.error("PO 생성 오류:", error); return { success: false, error: error instanceof Error ? error.message : "PO 생성 중 오류가 발생했습니다." }; } } // ===== 일반계약 생성 ===== interface CreateGeneralContractParams { rfqId: number; vendorId: number; vendorName: string; totalAmount: number; currency: string; contractType?: string; contractStartDate?: Date; contractEndDate?: Date; contractTerms?: string; } export async function createGeneralContract(params: CreateGeneralContractParams) { try { const userId = 1; // TODO: 실제 사용자 ID 가져오기 // 1. 선정된 업체 확인 const [selectedVendor] = await db .select() .from(rfqLastDetails) .where( and( eq(rfqLastDetails.rfqsLastId, params.rfqId), eq(rfqLastDetails.vendorsId, params.vendorId), eq(rfqLastDetails.isSelected, true), eq(rfqLastDetails.isLatest, true) ) ); if (!selectedVendor) { throw new Error("선정된 업체 정보를 찾을 수 없습니다."); } // 2. 계약 생성 로직 (TODO: 실제 구현 필요) // - 계약서 템플릿 선택 // - 계약 조건 설정 // - 계약서 문서 생성 // - 전자서명 프로세스 시작 // 3. 계약 상태 업데이트 await db.transaction(async (tx) => { // rfqLastDetails에 계약 정보 업데이트 await tx .update(rfqLastDetails) .set({ contractStatus: "진행중", contractCreatedAt: new Date(), contractNo: `CONTRACT-${Date.now()}`, // TODO: 실제 계약번호로 변경 updatedAt: new Date(), updatedBy: userId, }) .where( and( eq(rfqLastDetails.rfqsLastId, params.rfqId), eq(rfqLastDetails.vendorsId, params.vendorId), eq(rfqLastDetails.isSelected, true) ) ); // RFQ 상태 업데이트 await tx .update(rfqsLast) .set({ status: "일반계약 진행중", updatedAt: new Date(), }) .where(eq(rfqsLast.id, params.rfqId)); }); revalidatePath(`/rfq/${params.rfqId}`); revalidatePath("/rfq"); return { success: true, message: "일반계약이 성공적으로 생성되었습니다.", contractNumber: `CONTRACT-${Date.now()}`, // TODO: 실제 계약번호 반환 }; } catch (error) { console.error("일반계약 생성 오류:", error); return { success: false, error: error instanceof Error ? error.message : "일반계약 생성 중 오류가 발생했습니다." }; } } // ===== 입찰 생성 ===== interface CreateBiddingParams { rfqId: number; vendorId: number; vendorName: string; totalAmount: number; currency: string; biddingType?: string; // 공개입찰, 제한입찰 등 biddingStartDate?: Date; biddingEndDate?: Date; biddingRequirements?: string; } export async function createBidding(params: CreateBiddingParams) { try { const userId = 1; // TODO: 실제 사용자 ID 가져오기 // 1. 선정된 업체 확인 const [selectedVendor] = await db .select() .from(rfqLastDetails) .where( and( eq(rfqLastDetails.rfqsLastId, params.rfqId), eq(rfqLastDetails.vendorsId, params.vendorId), eq(rfqLastDetails.isSelected, true), eq(rfqLastDetails.isLatest, true) ) ); if (!selectedVendor) { throw new Error("선정된 업체 정보를 찾을 수 없습니다."); } // 2. 입찰 생성 로직 (TODO: 실제 구현 필요) // - 입찰 공고 생성 // - 입찰 참가자격 설정 // - 입찰 일정 등록 // - 평가 기준 설정 // - 입찰 시스템 등록 // 3. 입찰 상태 업데이트 await db.transaction(async (tx) => { // rfqLastDetails에 입찰 정보 업데이트 await tx .update(rfqLastDetails) .set({ contractStatus: "입찰진행중", contractCreatedAt: new Date(), contractNo: `BID-${Date.now()}`, // TODO: 실제 입찰번호로 변경 updatedAt: new Date(), updatedBy: userId, }) .where( and( eq(rfqLastDetails.rfqsLastId, params.rfqId), eq(rfqLastDetails.vendorsId, params.vendorId), eq(rfqLastDetails.isSelected, true) ) ); // RFQ 상태 업데이트 await tx .update(rfqsLast) .set({ status: "입찰 진행중", updatedAt: new Date(), }) .where(eq(rfqsLast.id, params.rfqId)); }); revalidatePath(`/rfq/${params.rfqId}`); revalidatePath("/rfq"); return { success: true, message: "입찰이 성공적으로 생성되었습니다.", biddingNumber: `BID-${Date.now()}`, // TODO: 실제 입찰번호 반환 }; } catch (error) { console.error("입찰 생성 오류:", error); return { success: false, error: error instanceof Error ? error.message : "입찰 생성 중 오류가 발생했습니다." }; } } // ===== 계약 타입 확인 ===== export async function checkContractStatus(rfqId: number) { try { const [detail] = await db .select({ contractStatus: rfqLastDetails.contractStatus, contractNo: rfqLastDetails.contractNo, contractCreatedAt: rfqLastDetails.contractCreatedAt, }) .from(rfqLastDetails) .where( and( eq(rfqLastDetails.rfqsLastId, rfqId), eq(rfqLastDetails.isSelected, true), eq(rfqLastDetails.isLatest, true) ) ); return { success: true, data: detail, hasContract: !!detail?.contractNo, }; } catch (error) { console.error("계약 상태 확인 오류:", error); return { success: false, error: error instanceof Error ? error.message : "계약 상태 확인 중 오류가 발생했습니다." }; } }