summaryrefslogtreecommitdiff
path: root/lib/bidding/detail/service.ts
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-09-09 10:34:05 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-09-09 10:34:05 +0000
commit86b1fd1cc801f45642f84d24c0b5c84368454ff0 (patch)
tree63176d1feb6d3fbbb71d942343056ba6d793b586 /lib/bidding/detail/service.ts
parentc62ec046327fd388ebce04571b55910747e69a3b (diff)
(최겸) 구매 입찰 사전견적, 입찰, 낙찰, 유찰, 재입찰 기능 개발
Diffstat (limited to 'lib/bidding/detail/service.ts')
-rw-r--r--lib/bidding/detail/service.ts62
1 files changed, 41 insertions, 21 deletions
diff --git a/lib/bidding/detail/service.ts b/lib/bidding/detail/service.ts
index 956c1798..d9bcb255 100644
--- a/lib/bidding/detail/service.ts
+++ b/lib/bidding/detail/service.ts
@@ -71,7 +71,7 @@ export interface QuotationVendor {
quotationAmount: number // 견적금액
currency: string
submissionDate: string // 제출일
- isWinner: boolean // 낙찰여부
+ isWinner: boolean | null // 낙찰여부 (null: 미정, true: 낙찰, false: 탈락)
awardRatio: number | null // 발주비율
isBiddingParticipated: boolean | null // 본입찰 참여여부
status: 'pending' | 'submitted' | 'selected' | 'rejected'
@@ -262,7 +262,7 @@ export async function getQuotationVendors(biddingId: number): Promise<QuotationV
quotationAmount: Number(vendor.quotationAmount) || 0,
currency: vendor.currency,
submissionDate: vendor.submissionDate ? (vendor.submissionDate instanceof Date ? vendor.submissionDate.toISOString().split('T')[0] : String(vendor.submissionDate).split('T')[0]) : '',
- isWinner: vendor.isWinner || false,
+ isWinner: vendor.isWinner,
awardRatio: vendor.awardRatio ? Number(vendor.awardRatio) : null,
isBiddingParticipated: vendor.isBiddingParticipated,
status: vendor.status as 'pending' | 'submitted' | 'selected' | 'rejected',
@@ -1208,7 +1208,7 @@ export async function uploadAwardDocument(biddingId: number, file: File, userId:
originalFileName: file.name,
filePath: saveResult.filePath,
fileSize: file.size,
- documentType: 'award',
+ documentType: 'other',
title: '낙찰 관련 문서',
description: '낙찰 관련 첨부파일',
uploadedBy: userId,
@@ -1347,7 +1347,7 @@ export async function awardBidding(biddingId: number, selectionReason: string, u
eq(biddingCompanies.biddingId, biddingId),
eq(biddingCompanies.isWinner, true)
))
-
+
if (awardedCompanies.length === 0) {
return { success: false, error: '낙찰된 업체가 없습니다. 먼저 발주비율을 산정해주세요.' }
}
@@ -1373,27 +1373,40 @@ export async function awardBidding(biddingId: number, selectionReason: string, u
// 2. 선정 사유 저장 (첫 번째 낙찰 업체 기준으로 저장)
const firstAwardedCompany = awardedCompanies[0]
- await tx
- .insert(vendorSelectionResults)
- .values({
- biddingId,
- selectedCompanyId: firstAwardedCompany.companyId,
- selectionReason,
- selectedBy: userId,
- selectedAt: new Date(),
- createdAt: new Date(),
- updatedAt: new Date()
- })
- .onConflictDoUpdate({
- target: [vendorSelectionResults.biddingId],
- set: {
+
+ // 기존 선정 결과 확인
+ const existingResult = await tx
+ .select()
+ .from(vendorSelectionResults)
+ .where(eq(vendorSelectionResults.biddingId, biddingId))
+ .limit(1)
+
+ if (existingResult.length > 0) {
+ // 업데이트
+ await tx
+ .update(vendorSelectionResults)
+ .set({
selectedCompanyId: firstAwardedCompany.companyId,
selectionReason,
selectedBy: userId,
selectedAt: new Date(),
updatedAt: new Date()
- }
- })
+ })
+ .where(eq(vendorSelectionResults.biddingId, biddingId))
+ } else {
+ // 삽입
+ await tx
+ .insert(vendorSelectionResults)
+ .values({
+ biddingId,
+ selectedCompanyId: firstAwardedCompany.companyId,
+ selectionReason,
+ selectedBy: userId,
+ selectedAt: new Date(),
+ createdAt: new Date(),
+ updatedAt: new Date()
+ })
+ }
})
@@ -1644,12 +1657,14 @@ export interface PartnersBiddingListItem {
isWinner: boolean | null
isAttendingMeeting: boolean | null
isPreQuoteSelected: boolean | null
+ isPreQuoteParticipated: boolean | null
+ preQuoteDeadline: Date | null
isBiddingInvited: boolean | null
notes: string | null
createdAt: Date
updatedAt: Date
// updatedBy: string | null
-
+ hasSpecificationMeeting: boolean | null
// biddings 정보
biddingId: number
biddingNumber: string
@@ -1688,6 +1703,8 @@ export async function getBiddingListForPartners(companyId: number): Promise<Part
isWinner: biddingCompanies.isWinner,
isAttendingMeeting: biddingCompanies.isAttendingMeeting,
isPreQuoteSelected: biddingCompanies.isPreQuoteSelected,
+ isPreQuoteParticipated: biddingCompanies.isPreQuoteParticipated,
+ preQuoteDeadline: biddingCompanies.preQuoteDeadline,
isBiddingInvited: biddingCompanies.isBiddingInvited,
notes: biddingCompanies.notes,
createdAt: biddingCompanies.createdAt,
@@ -1712,6 +1729,7 @@ export async function getBiddingListForPartners(companyId: number): Promise<Part
managerPhone: biddings.managerPhone,
currency: biddings.currency,
budget: biddings.budget,
+ hasSpecificationMeeting: biddings.hasSpecificationMeeting,
})
.from(biddingCompanies)
.innerJoin(biddings, eq(biddingCompanies.biddingId, biddings.id))
@@ -1791,6 +1809,8 @@ export async function getBiddingDetailsForPartners(biddingId: number, companyId:
isAttendingMeeting: biddingCompanies.isAttendingMeeting,
isPreQuoteSelected: biddingCompanies.isPreQuoteSelected,
isBiddingParticipated: biddingCompanies.isBiddingParticipated,
+ isPreQuoteParticipated: biddingCompanies.isPreQuoteParticipated,
+ hasSpecificationMeeting: biddings.hasSpecificationMeeting,
// 응답한 조건들 (company_condition_responses) - 제시된 조건과 응답 모두 여기서 관리
paymentTermsResponse: companyConditionResponses.paymentTermsResponse,
taxConditionsResponse: companyConditionResponses.taxConditionsResponse,