From 58d700b925967bfe470c944b380b02b2140cab8a Mon Sep 17 00:00:00 2001 From: dujinkim Date: Mon, 24 Nov 2025 02:52:34 +0000 Subject: (최겸) 구매 기술영업 결재 개발, 입찰 수정 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/techsales-rfq/approval-handlers.ts | 10 +-- lib/techsales-rfq/service.ts | 76 +++++++++++----------- .../table/detail-table/rfq-detail-table.tsx | 62 +++++++++++++----- 3 files changed, 87 insertions(+), 61 deletions(-) (limited to 'lib/techsales-rfq') diff --git a/lib/techsales-rfq/approval-handlers.ts b/lib/techsales-rfq/approval-handlers.ts index 6ffd9fb4..0d4629e4 100644 --- a/lib/techsales-rfq/approval-handlers.ts +++ b/lib/techsales-rfq/approval-handlers.ts @@ -98,15 +98,7 @@ export async function sendTechSalesRfqWithApprovalInternal(payload: { } } - // 2. RFQ 상태를 "RFQ Sent"로 변경 - await db.update(techSalesRfqs) - .set({ - status: TECH_SALES_RFQ_STATUSES.RFQ_SENT, - updatedAt: new Date(), - }) - .where(eq(techSalesRfqs.id, payload.rfqId)); - - // 3. 실제 RFQ 발송 실행 + // 2. 실제 RFQ 발송 실행 (상태 변경과 이메일 발송은 sendTechSalesRfqToVendors에서 처리) const sendResult = await sendTechSalesRfqToVendors({ rfqId: payload.rfqId, vendorIds: payload.vendorIds, diff --git a/lib/techsales-rfq/service.ts b/lib/techsales-rfq/service.ts index dc5950e0..ed3472b1 100644 --- a/lib/techsales-rfq/service.ts +++ b/lib/techsales-rfq/service.ts @@ -501,8 +501,46 @@ export async function getTechSalesRfqVendors(rfqId: number) { } } +/** + * 기술영업 RFQ 첨부파일 중 DRM 해제 여부 확인 + */ +export async function checkTechSalesRfqHasDrmAttachments(rfqId: number) { + unstable_noStore(); + try { + const attachments = await db.query.techSalesAttachments.findMany({ + where: eq(techSalesAttachments.techSalesRfqId, rfqId), + columns: { + id: true, + drmEncrypted: true, + fileName: true, + fileSize: true, + originalFileName: true, + } + }); + + const drmAttachments = attachments.filter(att => att.drmEncrypted === true); + + return { + hasDrm: drmAttachments.length > 0, + drmAttachmentIds: drmAttachments.map(att => att.id), + drmAttachments: drmAttachments.map(att => ({ + fileName: att.originalFileName || att.fileName, + fileSize: att.fileSize, + })), + }; + } catch (err) { + console.error("기술영업 RFQ DRM 첨부파일 확인 오류:", err); + return { + hasDrm: false, + drmAttachmentIds: [], + drmAttachments: [], + }; + } +} + /** * 기술영업 RFQ 발송 (선택된 벤더들의 선택된 contact들에게) + * DRM 해제가 필요없는 경우에만 사용 (결재 프로세스 없이 바로 발송) */ export async function sendTechSalesRfqToVendors(input: { rfqId: number; @@ -559,7 +597,7 @@ export async function sendTechSalesRfqToVendors(input: { }; } - // 발송 가능한 상태인지 확인 (결재 진행중 상태는 제외) + // 발송 가능한 상태인지 확인 (결재 진행중 상태 포함 - 결재 승인 후 발송 가능) if (rfq.status !== TECH_SALES_RFQ_STATUSES.RFQ_VENDOR_ASSIGNED && rfq.status !== TECH_SALES_RFQ_STATUSES.RFQ_SENT && rfq.status !== TECH_SALES_RFQ_STATUSES.APPROVAL_IN_PROGRESS) { @@ -568,14 +606,6 @@ export async function sendTechSalesRfqToVendors(input: { message: "벤더가 할당된 RFQ 또는 이미 전송된 RFQ만 다시 전송할 수 있습니다", }; } - - // 결재 진행중 상태에서는 결재 승인 후처리 핸들러에서만 발송 가능 - if (rfq.status === TECH_SALES_RFQ_STATUSES.APPROVAL_IN_PROGRESS) { - return { - success: false, - message: "결재 진행 중인 RFQ는 결재 승인 후 자동으로 발송됩니다", - }; - } const isResend = rfq.status === TECH_SALES_RFQ_STATUSES.RFQ_SENT; @@ -626,34 +656,6 @@ export async function sendTechSalesRfqToVendors(input: { }; } - // RFQ 첨부파일 중 DRM 파일 확인 - const attachments = await db.query.techSalesAttachments.findMany({ - where: eq(techSalesAttachments.techSalesRfqId, input.rfqId), - columns: { - id: true, - drmEncrypted: true, - fileName: true, - fileSize: true, - originalFileName: true, - } - }); - - const drmAttachments = attachments.filter(att => att.drmEncrypted === true); - - // DRM 파일이 있으면 결재 프로세스 필요 (이 함수는 직접 발송하지 않고 결재 필요 신호 반환) - if (drmAttachments.length > 0) { - return { - success: false, - requiresApproval: true, - message: "DRM 파일이 포함되어 있어 결재가 필요합니다", - drmAttachmentIds: drmAttachments.map(att => att.id), - drmAttachments: drmAttachments.map(att => ({ - fileName: att.originalFileName || att.fileName, - fileSize: att.fileSize, - })), - }; - } - // 트랜잭션 시작 await db.transaction(async (tx) => { // 1. RFQ 상태 업데이트 (최초 발송인 경우 rfqSendDate 설정) diff --git a/lib/techsales-rfq/table/detail-table/rfq-detail-table.tsx b/lib/techsales-rfq/table/detail-table/rfq-detail-table.tsx index 52758412..db2331af 100644 --- a/lib/techsales-rfq/table/detail-table/rfq-detail-table.tsx +++ b/lib/techsales-rfq/table/detail-table/rfq-detail-table.tsx @@ -259,26 +259,20 @@ export function RfqDetailTables({ selectedRfq, maxHeight }: RfqDetailTablesProps try { setIsSendingRfq(true); - // 기술영업 RFQ 발송 서비스 함수 호출 (contact 정보 포함) - const vendorIds = selectedRows.map(row => row.vendorId).filter(Boolean); - const { sendTechSalesRfqToVendors } = await import("@/lib/techsales-rfq/service"); + // DRM 해제 여부 확인 + const { checkTechSalesRfqHasDrmAttachments, sendTechSalesRfqToVendors } = await import("@/lib/techsales-rfq/service"); + const drmCheck = await checkTechSalesRfqHasDrmAttachments(selectedRfqId); - const result = await sendTechSalesRfqToVendors({ - rfqId: selectedRfqId, - vendorIds: vendorIds as number[], - selectedContacts: selectedContacts - }); - - // DRM 파일이 있어서 결재가 필요한 경우 - if (!result.success && result.requiresApproval) { + // DRM 파일이 걸려있으면 결재 프로세스 진행 + if (drmCheck.hasDrm) { // 결재 데이터 저장 setApprovalPreviewData({ vendors: selectedRows.map(row => ({ vendorId: row.vendorId!, vendorName: row.vendorName || "", })), - drmAttachments: result.drmAttachments || [], - drmAttachmentIds: result.drmAttachmentIds || [], + drmAttachments: drmCheck.drmAttachments, + drmAttachmentIds: drmCheck.drmAttachmentIds, selectedContacts: selectedContacts, }); @@ -288,6 +282,14 @@ export function RfqDetailTables({ selectedRfq, maxHeight }: RfqDetailTablesProps return; } + // DRM 해제가 안 걸려있으면 바로 발송 + const vendorIds = selectedRows.map(row => row.vendorId).filter(Boolean); + const result = await sendTechSalesRfqToVendors({ + rfqId: selectedRfqId, + vendorIds: vendorIds as number[], + selectedContacts: selectedContacts + }); + if (result.success) { toast.success(result.message || `${selectedContacts.length}명의 연락처에게 RFQ가 발송되었습니다.`); } else { @@ -483,8 +485,7 @@ export function RfqDetailTables({ selectedRfq, maxHeight }: RfqDetailTablesProps applicationReason: reason, }); - // 신청사유 다이얼로그 닫고 결재 미리보기 열기 - setShowApplicationReasonDialog(false); + // 결재 미리보기 열기 setShowApprovalPreview(true); } catch (error) { console.error("템플릿 변수 생성 실패:", error); @@ -936,6 +937,37 @@ export function RfqDetailTables({ selectedRfq, maxHeight }: RfqDetailTablesProps quotationId={selectedQuotationForContacts?.id || null} vendorName={selectedQuotationForContacts?.vendorName} /> + + {/* 신청사유 입력 다이얼로그 */} + {approvalPreviewData && ( + + )} + + {/* 결재 미리보기 다이얼로그 */} + {approvalPreviewData && approvalPreviewData.templateVariables && ( + + )} ) } \ No newline at end of file -- cgit v1.2.3