"use server" import db from "@/db/db" import { eq, and } from "drizzle-orm" import { complianceResponses, redFlagManagers } from "@/db/schema/compliance" import { users } from "@/db/schema" import { basicContract } from "@/db/schema/basicContractDocumnet" import { vendors } from "@/db/schema/vendors" import { getServerSession } from "next-auth" import { authOptions } from "@/app/api/auth/[...nextauth]/route" import { submitApproval, createSubmitApprovalRequest, createApprovalLine, type ApprovalLine } from "@/lib/knox-api/approval/approval" import { getTriggeredRedFlagQuestions } from "./red-flag-notifier" import { revalidatePath } from "next/cache" /** * RED FLAG 해소요청 - 구매기획 담당자에게 합의 요청 */ export async function requestRedFlagResolution(contractIds: number[]): Promise<{ success: boolean message: string failed: number[] }> { try { const session = await getServerSession(authOptions) if (!session?.user) { return { success: false, message: "인증이 필요합니다.", failed: contractIds } } const currentUser = session.user const userId = currentUser.id const epId = currentUser.epId || "" const emailAddress = currentUser.email || "" if (!epId || !emailAddress) { return { success: false, message: "사용자 정보가 불완전합니다. epId와 email이 필요합니다.", failed: contractIds } } // 구매기획 담당자 조회 const managerRow = await db .select({ purchasingManagerId: redFlagManagers.purchasingManagerId, }) .from(redFlagManagers) .orderBy(redFlagManagers.createdAt) .limit(1) const purchasingManagerId = managerRow[0]?.purchasingManagerId if (!purchasingManagerId) { return { success: false, message: "구매기획 담당자가 설정되지 않았습니다.", failed: contractIds } } // 구매기획 담당자 정보 조회 const purchasingManager = await db .select({ id: users.id, name: users.name, email: users.email, epId: users.epId, }) .from(users) .where(eq(users.id, purchasingManagerId)) .limit(1) if (!purchasingManager[0] || !purchasingManager[0].epId || !purchasingManager[0].email) { return { success: false, message: "구매기획 담당자 정보를 찾을 수 없습니다.", failed: contractIds } } const pm = purchasingManager[0] // 각 계약서에 대해 RED FLAG 해소요청 처리 const failed: number[] = [] for (const contractId of contractIds) { try { // 계약서 정보 조회 const contractInfo = await db .select({ id: basicContract.id, vendorId: basicContract.vendorId, templateId: basicContract.templateId, vendorName: vendors.vendorName, vendorCode: vendors.vendorCode, }) .from(basicContract) .leftJoin(vendors, eq(basicContract.vendorId, vendors.id)) .where(eq(basicContract.id, contractId)) .limit(1) if (!contractInfo[0]) { failed.push(contractId) continue } const contract = contractInfo[0] // RED FLAG 발생 여부 확인 const triggeredFlags = await getTriggeredRedFlagQuestions(contractId) if (triggeredFlags.length === 0) { // RED FLAG가 없는 경우는 스킵 continue } // 이미 해소요청이 진행 중인지 확인 const existingResponse = await db .select() .from(complianceResponses) .where(eq(complianceResponses.basicContractId, contractId)) .limit(1) if (existingResponse[0]?.redFlagResolutionApprovalId) { // 이미 해소요청이 진행 중 continue } // 합의 요청 본문 생성 const triggeredQuestionsText = triggeredFlags .map((flag, idx) => `${idx + 1}. ${flag.questionText}`) .join("\n") const contents = ` RED FLAG 해소요청 계약서 ID: ${contractId} 업체명: ${contract.vendorName || "정보 없음"} 업체코드: ${contract.vendorCode || "정보 없음"} 발생한 RED FLAG 질문: ${triggeredQuestionsText} 위 RED FLAG에 대한 해소를 요청드립니다. 합의해 주시면 RED FLAG가 해제됩니다. `.trim() const subject = `[RED FLAG 해소요청] ${contract.vendorName || "협력업체"} - 계약서 ID: ${contractId}` // 결재 경로 생성 // 기안자: 현재 사용자 const drafterLine: ApprovalLine = await createApprovalLine( { epId, emailAddress }, "0", // 기안 "1" ) // 합의자: 구매기획 담당자 const approverLine: ApprovalLine = await createApprovalLine( { epId: pm.epId, emailAddress: pm.email }, "2", // 합의 "2" ) const approvalLines = [drafterLine, approverLine] // 결재 상신 요청 생성 const approvalRequest = await createSubmitApprovalRequest( contents, subject, approvalLines, { contentsType: "TEXT", docSecuType: "PERSONAL", notifyOption: "0", urgYn: "N", importantYn: "N", } ) // 결재 상신 const approvalResponse = await submitApproval( approvalRequest, { userId, epId, emailAddress, } ) if (approvalResponse.result === "success") { // compliance_responses 업데이트 (red_flag_resolution_approval_id 저장) if (existingResponse[0]) { await db .update(complianceResponses) .set({ redFlagResolutionApprovalId: approvalResponse.data.apInfId, updatedAt: new Date(), }) .where(eq(complianceResponses.id, existingResponse[0].id)) } else { // compliance_response가 없는 경우 생성 (템플릿 ID는 계약서에서 가져와야 함) // 이 경우는 실제로는 발생하지 않을 수 있지만, 안전을 위해 처리 console.warn(`Compliance response not found for contract ${contractId}`) } } else { failed.push(contractId) } } catch (error) { console.error(`Error processing contract ${contractId}:`, error) failed.push(contractId) } } revalidatePath("/evcp/basic-contract") if (failed.length === 0) { return { success: true, message: `${contractIds.length}건의 RED FLAG 해소요청이 완료되었습니다.`, failed: [] } } else if (failed.length < contractIds.length) { return { success: true, message: `${contractIds.length - failed.length}건 성공, ${failed.length}건 실패`, failed } } else { return { success: false, message: "모든 RED FLAG 해소요청이 실패했습니다.", failed } } } catch (error) { console.error("RED FLAG 해소요청 오류:", error) return { success: false, message: `RED FLAG 해소요청 중 오류가 발생했습니다: ${error instanceof Error ? error.message : "알 수 없는 오류"}`, failed: contractIds } } } /** * RED FLAG 해소 처리 (합의 완료 시 호출) */ export async function resolveRedFlag(contractId: number, approvalId: string): Promise<{ success: boolean message: string }> { try { // compliance_responses 조회 const response = await db .select() .from(complianceResponses) .where( and( eq(complianceResponses.basicContractId, contractId), eq(complianceResponses.redFlagResolutionApprovalId, approvalId) ) ) .limit(1) if (!response[0]) { return { success: false, message: "해소요청 정보를 찾을 수 없습니다.", } } // RED FLAG 해제 처리 await db .update(complianceResponses) .set({ redFlagResolvedAt: new Date(), updatedAt: new Date(), }) .where(eq(complianceResponses.id, response[0].id)) revalidatePath("/evcp/basic-contract") return { success: true, message: "RED FLAG가 해제되었습니다.", } } catch (error) { console.error("RED FLAG 해제 오류:", error) return { success: false, message: `RED FLAG 해제 중 오류가 발생했습니다: ${error instanceof Error ? error.message : "알 수 없는 오류"}`, } } }