summaryrefslogtreecommitdiff
path: root/lib/bidding/detail/service.ts
diff options
context:
space:
mode:
Diffstat (limited to 'lib/bidding/detail/service.ts')
-rw-r--r--lib/bidding/detail/service.ts101
1 files changed, 101 insertions, 0 deletions
diff --git a/lib/bidding/detail/service.ts b/lib/bidding/detail/service.ts
index 92be2eee..df8427da 100644
--- a/lib/bidding/detail/service.ts
+++ b/lib/bidding/detail/service.ts
@@ -2529,3 +2529,104 @@ export async function getBiddingDocumentsForPartners(biddingId: number) {
}
)()
}
+
+// =================================================
+// 입찰가 비교 분석 함수들
+// =================================================
+
+// 벤더별 입찰가 정보 조회 (캐시 적용)
+export async function getVendorPricesForBidding(biddingId: number) {
+ return unstable_cache(
+ async () => {
+ try {
+ // 각 회사의 입찰가 정보를 조회 - 본입찰 참여 업체들
+ const vendorPrices = await db
+ .select({
+ companyId: biddingCompanies.companyId,
+ companyName: vendors.vendorName,
+ biddingCompanyId: biddingCompanies.id,
+ currency: sql<string>`'KRW'`, // 기본값 KRW
+ finalQuoteAmount: biddingCompanies.finalQuoteAmount,
+ isBiddingParticipated: biddingCompanies.isBiddingParticipated,
+ })
+ .from(biddingCompanies)
+ .leftJoin(vendors, eq(biddingCompanies.companyId, vendors.id))
+ .where(and(
+ eq(biddingCompanies.biddingId, biddingId),
+ eq(biddingCompanies.isBiddingParticipated, true), // 본입찰 참여 업체만
+ sql`${biddingCompanies.finalQuoteAmount} IS NOT NULL` // 입찰가를 제출한 업체만
+ ))
+
+ console.log(`Found ${vendorPrices.length} vendors for bidding ${biddingId}`)
+
+ const result: any[] = []
+
+ for (const vendor of vendorPrices) {
+ try {
+ // 해당 회사의 품목별 입찰가 조회 (본입찰 데이터)
+ const itemPrices = await db
+ .select({
+ prItemId: companyPrItemBids.prItemId,
+ itemName: prItemsForBidding.itemInfo, // itemInfo 사용
+ itemNumber: prItemsForBidding.itemNumber, // itemNumber도 포함
+ quantity: prItemsForBidding.quantity,
+ quantityUnit: prItemsForBidding.quantityUnit,
+ weight: prItemsForBidding.totalWeight, // totalWeight 사용
+ weightUnit: prItemsForBidding.weightUnit,
+ unitPrice: companyPrItemBids.bidUnitPrice,
+ amount: companyPrItemBids.bidAmount,
+ proposedDeliveryDate: companyPrItemBids.proposedDeliveryDate,
+ })
+ .from(companyPrItemBids)
+ .leftJoin(prItemsForBidding, eq(companyPrItemBids.prItemId, prItemsForBidding.id))
+ .where(and(
+ eq(companyPrItemBids.biddingCompanyId, vendor.biddingCompanyId),
+ eq(companyPrItemBids.isPreQuote, false) // 본입찰 데이터만
+ ))
+ .orderBy(prItemsForBidding.id)
+
+ console.log(`Vendor ${vendor.companyName}: Found ${itemPrices.length} item prices`)
+
+ // 총 금액은 biddingCompanies.finalQuoteAmount 사용
+ const totalAmount = parseFloat(vendor.finalQuoteAmount || '0')
+
+ result.push({
+ companyId: vendor.companyId,
+ companyName: vendor.companyName || `Vendor ${vendor.companyId}`,
+ biddingCompanyId: vendor.biddingCompanyId,
+ totalAmount,
+ currency: vendor.currency,
+ itemPrices: itemPrices.map(item => ({
+ prItemId: item.prItemId,
+ itemName: item.itemName || item.itemNumber || `Item ${item.prItemId}`,
+ quantity: parseFloat(item.quantity || '0'),
+ quantityUnit: item.quantityUnit || 'ea',
+ weight: item.weight ? parseFloat(item.weight) : null,
+ weightUnit: item.weightUnit,
+ unitPrice: parseFloat(item.unitPrice || '0'),
+ amount: parseFloat(item.amount || '0'),
+ proposedDeliveryDate: item.proposedDeliveryDate ?
+ (typeof item.proposedDeliveryDate === 'string'
+ ? item.proposedDeliveryDate
+ : item.proposedDeliveryDate.toISOString().split('T')[0])
+ : null,
+ }))
+ })
+ } catch (vendorError) {
+ console.error(`Error processing vendor ${vendor.companyId}:`, vendorError)
+ // 벤더 처리 중 에러가 발생해도 다른 벤더들은 계속 처리
+ }
+ }
+
+ return result
+ } catch (error) {
+ console.error('Failed to get vendor prices for bidding:', error)
+ return []
+ }
+ },
+ [`bidding-vendor-prices-${biddingId}`],
+ {
+ tags: [`bidding-${biddingId}`, 'quotation-vendors', 'pr-items']
+ }
+ )()
+}