diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-11-25 11:51:27 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-11-25 11:51:27 +0000 |
| commit | 835df8ddc115ffa74414db2a4fab7efc0d0056a9 (patch) | |
| tree | bfe814c7b51ee1541d84b6e2dee01f28594763ac /lib/bidding/handlers.ts | |
| parent | 6160e8bd61360ada9e8e0574671c38292eaba9e7 (diff) | |
(최겸) 구매 입찰 수정v2
Diffstat (limited to 'lib/bidding/handlers.ts')
| -rw-r--r-- | lib/bidding/handlers.ts | 130 |
1 files changed, 46 insertions, 84 deletions
diff --git a/lib/bidding/handlers.ts b/lib/bidding/handlers.ts index d55107c0..a5cc72ae 100644 --- a/lib/bidding/handlers.ts +++ b/lib/bidding/handlers.ts @@ -289,83 +289,47 @@ export async function mapBiddingInvitationToTemplateVariables(payload: { * @returns 템플릿 변수 객체 (Record<string, string>) */ export async function mapBiddingClosureToTemplateVariables(payload: { - biddingId: number; + bidding: { + id: number; + title: string; + biddingNumber: string; + projectName: string | null; + itemName: string | null; + biddingType: string; + bidPicName: string | null; + supplyPicName: string | null; + targetPrice: string | null; + }; + biddingItems: Array<{ + id: number; + materialCode: string | null; + materialCodeName: string | null; + quantity: string | null; + quantityUnit: string | null; + targetUnitPrice: string | null; + currency: string | null; + }>; + vendorSubmissions: Array<{ + vendorId: number | null; + vendorName: string | null; + vendorCode: string | null; + finalQuoteAmount: string | null; + submitted: boolean | null; + targetPrice: string | null; + }>; description: string; requestedAt: Date; }): Promise<Record<string, string>> { - const { biddingId, description, requestedAt } = payload; - - // 1. 입찰 정보 조회 - debugLog('[BiddingClosureMapper] 입찰 정보 조회 시작'); - const { default: db } = await import('@/db/db'); - const { biddings, prItemsForBidding, biddingCompanies, biddingVendorSubmissions } = await import('@/db/schema'); - const { eq, leftJoin } = await import('drizzle-orm'); - - const biddingInfo = await db - .select({ - id: biddings.id, - title: biddings.title, - biddingNumber: biddings.biddingNumber, - projectName: biddings.projectName, - itemName: biddings.itemName, - biddingType: biddings.biddingType, - bidPicName: biddings.bidPicName, - supplyPicName: biddings.supplyPicName, - targetPrice: biddings.targetPrice, - winnerCount: biddings.winnerCount, - }) - .from(biddings) - .where(eq(biddings.id, biddingId)) - .limit(1); - - if (biddingInfo.length === 0) { - debugError('[BiddingClosureMapper] 입찰 정보를 찾을 수 없음'); - throw new Error('입찰 정보를 찾을 수 없습니다'); - } - - const bidding = biddingInfo[0]; - - // 2. 입찰 대상 자재 정보 조회 - const biddingItemsInfo = await db - .select({ - id: prItemsForBidding.id, - materialCode: prItemsForBidding.materialNumber, - materialCodeName: prItemsForBidding.materialInfo, - quantity: prItemsForBidding.quantity, - quantityUnit: prItemsForBidding.quantityUnit, - targetUnitPrice: prItemsForBidding.targetUnitPrice, - currency: prItemsForBidding.targetCurrency, - }) - .from(prItemsForBidding) - .where(eq(prItemsForBidding.biddingId, biddingId)); - - // 3. 입찰 참여 업체 및 제출 정보 조회 - const vendorSubmissions = await db - .select({ - vendorId: biddingCompanies.vendorId, - vendorName: biddingCompanies.vendorName, - vendorCode: biddingCompanies.vendorCode, - targetPrice: biddingVendorSubmissions.targetPrice, - bidPrice: biddingVendorSubmissions.bidPrice, - submitted: biddingVendorSubmissions.submitted, - }) - .from(biddingCompanies) - .leftJoin(biddingVendorSubmissions, eq(biddingCompanies.id, biddingVendorSubmissions.biddingCompanyId)) - .where(eq(biddingCompanies.biddingId, biddingId)); - - debugLog('[BiddingClosureMapper] 입찰 정보 조회 완료', { - biddingId, - itemCount: biddingItemsInfo.length, - vendorCount: vendorSubmissions.length, - }); + const { bidding, biddingItems, vendorSubmissions, description, requestedAt } = payload; // 기본 정보 매핑 const title = bidding.title || '폐찰'; const biddingTitle = bidding.title || ''; const biddingNumber = bidding.biddingNumber || ''; - const winnerCount = (bidding.winnerCount || 1).toString(); + const winnerCount = '1'; // 기본값 const contractType = bidding.biddingType || ''; - const targetPrice = bidding.targetPrice ? bidding.targetPrice.toLocaleString() : ''; + const targetPriceNum = bidding.targetPrice ? parseFloat(bidding.targetPrice) : 0; + const targetPrice = targetPriceNum ? targetPriceNum.toLocaleString() : ''; const biddingManager = bidding.bidPicName || bidding.supplyPicName || ''; const biddingOverview = bidding.itemName || ''; @@ -374,36 +338,34 @@ export async function mapBiddingClosureToTemplateVariables(payload: { // 협력사별 입찰 현황 매핑 const vendorVariables: Record<string, string> = {}; - vendorSubmissions.forEach((vendor, index) => { + vendorSubmissions.filter(vendor => vendor.vendorId && vendor.vendorName).forEach((vendor, index) => { const num = index + 1; + const targetPriceNum = vendor.targetPrice ? parseFloat(vendor.targetPrice) : 0; + const finalQuoteAmountNum = vendor.finalQuoteAmount ? parseFloat(vendor.finalQuoteAmount) : 0; + vendorVariables[`협력사_코드_${num}`] = vendor.vendorCode || ''; vendorVariables[`협력사명_${num}`] = vendor.vendorName || ''; vendorVariables[`응찰유무_${num}`] = vendor.submitted ? '응찰' : '미응찰'; - vendorVariables[`내정가_${num}`] = vendor.targetPrice ? vendor.targetPrice.toLocaleString() : ''; - vendorVariables[`입찰가_${num}`] = vendor.bidPrice ? vendor.bidPrice.toLocaleString() : ''; - vendorVariables[`비율_${num}`] = (vendor.targetPrice && vendor.bidPrice && vendor.targetPrice > 0) - ? ((vendor.bidPrice / vendor.targetPrice) * 100).toFixed(2) + '%' + vendorVariables[`내정가_${num}`] = targetPriceNum ? targetPriceNum.toLocaleString() : ''; + vendorVariables[`입찰가_${num}`] = finalQuoteAmountNum ? finalQuoteAmountNum.toLocaleString() : ''; + vendorVariables[`비율_${num}`] = (targetPriceNum && finalQuoteAmountNum && targetPriceNum > 0) + ? ((finalQuoteAmountNum / targetPriceNum) * 100).toFixed(2) + '%' : ''; }); // 품목별 입찰 정보 매핑 (간소화 - 첫 번째 품목 기준으로 매핑) const materialVariables: Record<string, string> = {}; - biddingItemsInfo.forEach((item, index) => { + biddingItems.forEach((item, index) => { const num = index + 1; + const quantityNum = item.quantity ? parseFloat(item.quantity) : 0; + const targetUnitPriceNum = item.targetUnitPrice ? parseFloat(item.targetUnitPrice) : 0; + materialVariables[`품목코드_${num}`] = item.materialCode || ''; materialVariables[`품목명_${num}`] = item.materialCodeName || ''; - materialVariables[`수량_${num}`] = item.quantity ? item.quantity.toLocaleString() : ''; + materialVariables[`수량_${num}`] = quantityNum ? quantityNum.toString() : ''; materialVariables[`단위_${num}`] = item.quantityUnit || ''; materialVariables[`통화_${num}`] = item.currency || ''; - materialVariables[`내정가_${num}`] = item.targetUnitPrice ? item.targetUnitPrice.toLocaleString() : ''; - - // 각 품목에 대한 협력사별 입찰가 (간소화: 동일 품목에 대한 모든 업체 입찰가 표시) - vendorSubmissions.forEach((vendor, vendorIndex) => { - const vendorNum = vendorIndex + 1; - materialVariables[`협력사코드_${num}`] = vendor.vendorCode || ''; - materialVariables[`협력사명_${num}`] = vendor.vendorName || ''; - materialVariables[`입찰가_${num}`] = vendor.bidPrice ? vendor.bidPrice.toLocaleString() : ''; - }); + materialVariables[`내정가_${num}`] = targetUnitPriceNum ? targetUnitPriceNum.toString() : ''; }); return { |
