From 93cc002186d3816d991925e57d44e0586dba2e75 Mon Sep 17 00:00:00 2001 From: dujinkim Date: Wed, 26 Nov 2025 09:55:47 +0000 Subject: (최겸) 구매 입찰 수정 v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/bidding/approval-actions.ts | 53 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) (limited to 'lib/bidding/approval-actions.ts') diff --git a/lib/bidding/approval-actions.ts b/lib/bidding/approval-actions.ts index 06f5c206..dd88164d 100644 --- a/lib/bidding/approval-actions.ts +++ b/lib/bidding/approval-actions.ts @@ -478,12 +478,48 @@ export async function requestBiddingClosureWithApproval(data: { * } * ``` */ +/** + * 낙찰할 업체 정보 조회 헬퍼 함수 + */ +export async function getAwardedCompaniesForApproval(biddingId: number) { + const { default: db } = await import('@/db/db'); + const { biddingCompanies, vendors } = await import('@/db/schema'); + const { eq, and } = await import('drizzle-orm'); + + const awardedCompanies = await db + .select({ + companyId: biddingCompanies.companyId, + companyName: vendors.vendorName, + finalQuoteAmount: biddingCompanies.finalQuoteAmount, + awardRatio: biddingCompanies.awardRatio + }) + .from(biddingCompanies) + .leftJoin(vendors, eq(biddingCompanies.companyId, vendors.id)) + .where(and( + eq(biddingCompanies.biddingId, biddingId), + eq(biddingCompanies.isWinner, true) + )); + + return awardedCompanies.map(company => ({ + companyId: company.companyId, + companyName: company.companyName || '', + finalQuoteAmount: parseFloat(company.finalQuoteAmount?.toString() || '0'), + awardRatio: parseFloat(company.awardRatio?.toString() || '0') + })); +} + /** * 낙찰 결재를 위한 공통 데이터 준비 헬퍼 함수 */ export async function prepareBiddingAwardApprovalData(data: { biddingId: number; selectionReason: string; + awardedCompanies?: Array<{ + companyId: number; + companyName: string | null; + finalQuoteAmount: number; + awardRatio: number; + }>; }) { // 1. 입찰 정보 조회 (템플릿 변수용) debugLog('[BiddingAwardApproval] 입찰 정보 조회 시작'); @@ -510,6 +546,14 @@ export async function prepareBiddingAwardApprovalData(data: { title: biddingInfo[0].title, }); + // 낙찰할 업체 정보 조회 (파라미터로 제공되지 않은 경우) + const awardedCompanies = data.awardedCompanies || await getAwardedCompaniesForApproval(data.biddingId); + + if (awardedCompanies.length === 0) { + debugError('[BiddingAwardApproval] 낙찰된 업체가 없습니다.'); + throw new Error('낙찰된 업체가 없습니다. 먼저 발주비율을 산정해주세요.'); + } + // 2. 템플릿 변수 매핑 debugLog('[BiddingAwardApproval] 템플릿 변수 매핑 시작'); const requestedAt = new Date(); @@ -518,6 +562,7 @@ export async function prepareBiddingAwardApprovalData(data: { biddingId: data.biddingId, selectionReason: data.selectionReason, requestedAt, + awardedCompanies, // 낙찰 업체 정보 전달 }); debugLog('[BiddingAwardApproval] 템플릿 변수 매핑 완료', { variableKeys: Object.keys(variables), @@ -532,6 +577,12 @@ export async function prepareBiddingAwardApprovalData(data: { export async function requestBiddingAwardWithApproval(data: { biddingId: number; selectionReason: string; + awardedCompanies: Array<{ + companyId: number; + companyName: string | null; + finalQuoteAmount: number; + awardRatio: number; + }>; currentUser: { id: number; epId: string | null; email?: string }; approvers?: string[]; // Knox EP ID 배열 (결재선) }) { @@ -577,6 +628,7 @@ export async function requestBiddingAwardWithApproval(data: { const { bidding, variables } = await prepareBiddingAwardApprovalData({ biddingId: data.biddingId, selectionReason: data.selectionReason, + awardedCompanies: data.awardedCompanies, }); // 4. 결재 워크플로우 시작 (Saga 패턴) @@ -589,6 +641,7 @@ export async function requestBiddingAwardWithApproval(data: { { biddingId: data.biddingId, selectionReason: data.selectionReason, + awardedCompanies: data.awardedCompanies, // ✅ 결재 상신 시점의 낙찰 대상 정보 currentUserId: data.currentUser.id, // ✅ 결재 승인 후 핸들러 실행 시 필요 }, -- cgit v1.2.3