diff options
Diffstat (limited to 'lib/rfq-last/vendor/rfq-vendor-table.tsx')
| -rw-r--r-- | lib/rfq-last/vendor/rfq-vendor-table.tsx | 234 |
1 files changed, 227 insertions, 7 deletions
diff --git a/lib/rfq-last/vendor/rfq-vendor-table.tsx b/lib/rfq-last/vendor/rfq-vendor-table.tsx index 29aa5f09..fc98785d 100644 --- a/lib/rfq-last/vendor/rfq-vendor-table.tsx +++ b/lib/rfq-last/vendor/rfq-vendor-table.tsx @@ -58,6 +58,11 @@ import { AddVendorDialog } from "./add-vendor-dialog"; import { BatchUpdateConditionsDialog } from "./batch-update-conditions-dialog"; import { SendRfqDialog } from "./send-rfq-dialog"; import { CancelVendorResponseDialog } from "./cancel-vendor-response-dialog"; +import { ApprovalPreviewDialog } from "@/lib/approval/client"; +import { requestRfqSendWithApproval } from "../approval-actions"; +import { mapRfqSendToTemplateVariables } from "../approval-handlers"; +import { useSession } from "next-auth/react"; +import { ApplicationReasonDialog } from "./application-reason-dialog"; import { getRfqSendData, @@ -293,6 +298,22 @@ export function RfqVendorTable({ vendorName: string; } | null>(null); const [isCancelDialogOpen, setIsCancelDialogOpen] = React.useState(false); + + // 결재 관련 상태 + const [showApplicationReasonDialog, setShowApplicationReasonDialog] = React.useState(false); + const [showApprovalPreview, setShowApprovalPreview] = React.useState(false); + const [approvalPreviewData, setApprovalPreviewData] = React.useState<{ + vendors: any[]; + attachments: any[]; + attachmentIds: number[]; + message?: string; + generatedPdfs?: any[]; + hasToSendEmail?: boolean; + templateVariables?: Record<string, string>; + applicationReason?: string; + } | null>(null); + + const { data: session } = useSession(); // AVL 연동 핸들러 const handleAvlIntegration = React.useCallback(() => { @@ -419,6 +440,57 @@ export function RfqVendorTable({ return; } + const hasAttachments = rfqSendData.attachments && rfqSendData.attachments.length > 0; + + // 🔹 첨부파일이 있는 경우: 결재 프로세스 시작 + if (hasAttachments) { + // Knox EP ID 확인 + if (!session?.user?.epId) { + toast.error("Knox EP ID가 없습니다. 시스템 관리자에게 문의하세요."); + setIsLoadingSendData(false); + return; + } + + // 첨부파일 정보 변환 + const attachmentsForApproval = rfqSendData.attachments.map((att: any) => ({ + fileName: att.fileName, + fileSize: att.fileSize, + })); + + // 결재 데이터 임시 저장 (신청사유 입력 전) + setApprovalPreviewData({ + vendors: vendorEmailInfos.map(v => ({ + vendorId: v.vendorId, + vendorName: v.vendorName, + vendorCode: v.vendorCode, + vendorCountry: v.vendorCountry, + selectedMainEmail: v.primaryEmail || v.vendorEmail || '', + additionalEmails: [], + customEmails: [], + currency: v.currency, + contractRequirements: { + ndaYn: v.ndaYn || false, + generalGtcYn: v.generalGtcYn || false, + projectGtcYn: v.projectGtcYn || false, + agreementYn: v.agreementYn || false, + }, + isResend: v.sendVersion ? v.sendVersion > 0 : false, + sendVersion: v.sendVersion, + })), + attachments: attachmentsForApproval, + attachmentIds: rfqSendData.attachments.map((att: any) => att.id), + message: undefined, + generatedPdfs: undefined, + hasToSendEmail: true, + }); + + // 신청사유 입력 다이얼로그 먼저 열기 + setShowApplicationReasonDialog(true); + setIsLoadingSendData(false); + return; + } + + // 🔹 첨부파일이 없는 경우: 기존 로직 (바로 발송) // 다이얼로그 데이터 설정 setSendDialogData({ rfqInfo: rfqSendData.rfqInfo, @@ -450,7 +522,82 @@ export function RfqVendorTable({ } finally { setIsLoadingSendData(false); } - }, [selectedRows, rfqId]); + }, [selectedRows, rfqId, session]); + + // 신청사유 입력 완료 핸들러 + const handleApplicationReasonConfirm = React.useCallback(async (reason: string) => { + if (!approvalPreviewData) { + toast.error("결재 데이터가 없습니다."); + return; + } + + try { + // 템플릿 변수 생성 (신청사유 포함) + const templateVariables = await mapRfqSendToTemplateVariables({ + attachments: approvalPreviewData.attachments, + vendorNames: approvalPreviewData.vendors.map(v => v.vendorName), + applicationReason: reason, + }); + + // 결재 미리보기 데이터 업데이트 + setApprovalPreviewData({ + ...approvalPreviewData, + templateVariables, + applicationReason: reason, + }); + + // 신청사유 다이얼로그 닫고 결재 미리보기 열기 + setShowApplicationReasonDialog(false); + setShowApprovalPreview(true); + } catch (error) { + console.error("템플릿 변수 생성 실패:", error); + toast.error("결재 문서 생성에 실패했습니다."); + } + }, [approvalPreviewData]); + + // 결재 미리보기 확인 핸들러 + const handleApprovalConfirm = React.useCallback(async (approvalData: { + approvers: string[]; + title: string; + description?: string; + }) => { + if (!approvalPreviewData || !session?.user) { + toast.error("결재 데이터가 없습니다."); + return; + } + + try { + const result = await requestRfqSendWithApproval({ + rfqId, + rfqCode, + vendors: approvalPreviewData.vendors, + attachmentIds: approvalPreviewData.attachmentIds, + attachments: approvalPreviewData.attachments, + message: approvalPreviewData.message, + generatedPdfs: approvalPreviewData.generatedPdfs, + hasToSendEmail: approvalPreviewData.hasToSendEmail, + applicationReason: approvalPreviewData.applicationReason || '', + currentUser: { + id: Number(session.user.id), + epId: session.user.epId || null, + name: session.user.name || undefined, + email: session.user.email || undefined, + }, + approvers: approvalData.approvers, + }); + + if (result.success) { + toast.success(result.message); + setShowApprovalPreview(false); + setApprovalPreviewData(null); + setSelectedRows([]); + router.refresh(); + } + } catch (error) { + console.error("결재 상신 실패:", error); + toast.error(error instanceof Error ? error.message : "결재 상신에 실패했습니다."); + } + }, [approvalPreviewData, session, rfqId, rfqCode, router]); // RFQ 발송 핸들러 const handleSendRfq = React.useCallback(async (data: { @@ -589,6 +736,53 @@ export function RfqVendorTable({ return; } + const hasAttachments = rfqSendData.attachments && rfqSendData.attachments.length > 0; + + // 🔹 첨부파일이 있는 경우: 결재 프로세스 + if (hasAttachments) { + if (!session?.user?.epId) { + toast.error("Knox EP ID가 없습니다. 시스템 관리자에게 문의하세요."); + setIsLoadingSendData(false); + return; + } + + const attachmentsForApproval = rfqSendData.attachments.map((att: any) => ({ + fileName: att.fileName, + fileSize: att.fileSize, + })); + + setApprovalPreviewData({ + vendors: vendorEmailInfos.map(v => ({ + vendorId: v.vendorId, + vendorName: v.vendorName, + vendorCode: v.vendorCode, + vendorCountry: v.vendorCountry, + selectedMainEmail: v.primaryEmail || v.vendorEmail || '', + additionalEmails: [], + customEmails: [], + currency: v.currency, + contractRequirements: { + ndaYn: v.ndaYn || false, + generalGtcYn: v.generalGtcYn || false, + projectGtcYn: v.projectGtcYn || false, + agreementYn: v.agreementYn || false, + }, + isResend: v.sendVersion ? v.sendVersion > 0 : false, + sendVersion: v.sendVersion, + })), + attachments: attachmentsForApproval, + attachmentIds: rfqSendData.attachments.map((att: any) => att.id), + message: undefined, + generatedPdfs: undefined, + hasToSendEmail: true, + }); + + setShowApplicationReasonDialog(true); + setIsLoadingSendData(false); + return; + } + + // 🔹 첨부파일이 없는 경우: 기존 로직 setSendDialogData({ rfqInfo: rfqSendData.rfqInfo, attachments: rfqSendData.attachments || [], @@ -1843,16 +2037,11 @@ export function RfqVendorTable({ /> )} - {/* AVL 벤더 연동 다이얼로그 */} + {/* AVL 벤더 조회 다이얼로그 */} <AvlVendorDialog open={isAvlDialogOpen} onOpenChange={setIsAvlDialogOpen} rfqId={rfqId} - rfqCode={rfqCode} - onSuccess={() => { - setIsAvlDialogOpen(false); - router.refresh(); - }} /> {/* 연동제 정보 다이얼로그 */} @@ -1888,6 +2077,37 @@ export function RfqVendorTable({ toast.success("RFQ 취소가 완료되었습니다."); }} /> + + {/* 신청사유 입력 다이얼로그 */} + {approvalPreviewData && ( + <ApplicationReasonDialog + open={showApplicationReasonDialog} + onOpenChange={setShowApplicationReasonDialog} + onConfirm={handleApplicationReasonConfirm} + vendorCount={approvalPreviewData.vendors.length} + attachmentCount={approvalPreviewData.attachmentIds.length} + /> + )} + + {/* 결재 미리보기 다이얼로그 */} + {approvalPreviewData && session?.user?.epId && approvalPreviewData.templateVariables && ( + <ApprovalPreviewDialog + open={showApprovalPreview} + onOpenChange={setShowApprovalPreview} + templateName="암호화해제 신청" + variables={approvalPreviewData.templateVariables} + title={`암호화해제 신청 - ${rfqCode || 'RFQ'}`} + currentUser={{ + id: Number(session.user.id), + epId: session.user.epId, + name: session.user.name || undefined, + email: session.user.email || undefined, + }} + onConfirm={handleApprovalConfirm} + allowTitleEdit={false} + allowDescriptionEdit={false} + /> + )} </> ); }
\ No newline at end of file |
