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.ts97
1 files changed, 96 insertions, 1 deletions
diff --git a/lib/bidding/detail/service.ts b/lib/bidding/detail/service.ts
index 17ea8f28..4ef48d33 100644
--- a/lib/bidding/detail/service.ts
+++ b/lib/bidding/detail/service.ts
@@ -64,6 +64,12 @@ export async function getBiddingDetailData(biddingId: number): Promise<BiddingDe
awardRatio: biddingCompanies.awardRatio,
isBiddingParticipated: biddingCompanies.isBiddingParticipated,
invitationStatus: biddingCompanies.invitationStatus,
+ // 연동제 관련 필드
+ isPriceAdjustmentApplicableQuestion: biddingCompanies.isPriceAdjustmentApplicableQuestion,
+ priceAdjustmentResponse: companyConditionResponses.priceAdjustmentResponse, // 벤더가 응답한 연동제 적용 여부
+ shiPriceAdjustmentApplied: biddingCompanies.shiPriceAdjustmentApplied,
+ priceAdjustmentNote: biddingCompanies.priceAdjustmentNote,
+ hasChemicalSubstance: biddingCompanies.hasChemicalSubstance,
// Contact info from biddingCompaniesContacts
contactPerson: biddingCompaniesContacts.contactName,
contactEmail: biddingCompaniesContacts.contactEmail,
@@ -75,6 +81,10 @@ export async function getBiddingDetailData(biddingId: number): Promise<BiddingDe
eq(biddingCompaniesContacts.biddingId, biddingId),
eq(biddingCompaniesContacts.vendorId, biddingCompanies.companyId)
))
+ .leftJoin(companyConditionResponses, and(
+ eq(companyConditionResponses.biddingCompanyId, biddingCompanies.id),
+ eq(companyConditionResponses.isPreQuote, false) // 본입찰 데이터만
+ ))
.where(and(
eq(biddingCompanies.biddingId, biddingId),
eq(biddingCompanies.isBiddingParticipated, true)
@@ -102,6 +112,12 @@ export async function getBiddingDetailData(biddingId: number): Promise<BiddingDe
awardRatio: curr.awardRatio ? Number(curr.awardRatio) : null,
isBiddingParticipated: curr.isBiddingParticipated,
invitationStatus: curr.invitationStatus,
+ // 연동제 관련 필드
+ isPriceAdjustmentApplicableQuestion: curr.isPriceAdjustmentApplicableQuestion,
+ priceAdjustmentResponse: curr.priceAdjustmentResponse, // 벤더가 응답한 연동제 적용 여부
+ shiPriceAdjustmentApplied: curr.shiPriceAdjustmentApplied,
+ priceAdjustmentNote: curr.priceAdjustmentNote,
+ hasChemicalSubstance: curr.hasChemicalSubstance,
documents: [],
})
}
@@ -148,6 +164,12 @@ export interface QuotationVendor {
awardRatio: number | null // 발주비율
isBiddingParticipated: boolean | null // 본입찰 참여여부
invitationStatus: 'pending' | 'pre_quote_sent' | 'pre_quote_accepted' | 'pre_quote_declined' | 'pre_quote_submitted' | 'bidding_sent' | 'bidding_accepted' | 'bidding_declined' | 'bidding_cancelled' | 'bidding_submitted'
+ // 연동제 관련 필드
+ isPriceAdjustmentApplicableQuestion: boolean | null // SHI가 요청한 연동제 요청 여부
+ priceAdjustmentResponse: boolean | null // 벤더가 응답한 연동제 적용 여부 (companyConditionResponses.priceAdjustmentResponse)
+ shiPriceAdjustmentApplied: boolean | null // SHI 연동제 적용여부
+ priceAdjustmentNote: string | null // 연동제 Note
+ hasChemicalSubstance: boolean | null // 화학물질여부
documents: Array<{
id: number
fileName: string
@@ -818,11 +840,52 @@ export async function registerBidding(biddingId: number, userId: string) {
await db.transaction(async (tx) => {
debugLog('registerBidding: Transaction started')
- // 1. 입찰 상태를 오픈으로 변경
+
+ // 0. 입찰서 제출기간 계산 (오프셋 기반)
+ const { submissionStartOffset, submissionDurationDays, submissionStartDate, submissionEndDate } = bidding
+
+ let calculatedStartDate = bidding.submissionStartDate
+ let calculatedEndDate = bidding.submissionEndDate
+
+ // 오프셋 값이 있으면 날짜 계산
+ if (submissionStartOffset !== null && submissionDurationDays !== null) {
+ // 시간 추출 (기본값: 시작 09:00, 마감 18:00)
+ const startTime = submissionStartDate
+ ? { hours: submissionStartDate.getUTCHours(), minutes: submissionStartDate.getUTCMinutes() }
+ : { hours: 9, minutes: 0 }
+ const endTime = submissionEndDate
+ ? { hours: submissionEndDate.getUTCHours(), minutes: submissionEndDate.getUTCMinutes() }
+ : { hours: 18, minutes: 0 }
+
+ // baseDate = 현재일 날짜만 (00:00:00)
+ const baseDate = new Date()
+ baseDate.setHours(0, 0, 0, 0)
+
+ // 시작일 = baseDate + offset일 + 시작시간
+ calculatedStartDate = new Date(baseDate)
+ calculatedStartDate.setDate(calculatedStartDate.getDate() + submissionStartOffset)
+ calculatedStartDate.setHours(startTime.hours, startTime.minutes, 0, 0)
+
+ // 마감일 = 시작일(날짜만) + duration일 + 마감시간
+ calculatedEndDate = new Date(calculatedStartDate)
+ calculatedEndDate.setHours(0, 0, 0, 0)
+ calculatedEndDate.setDate(calculatedEndDate.getDate() + submissionDurationDays)
+ calculatedEndDate.setHours(endTime.hours, endTime.minutes, 0, 0)
+
+ debugLog('registerBidding: Submission dates calculated', {
+ baseDate: baseDate.toISOString(),
+ calculatedStartDate: calculatedStartDate.toISOString(),
+ calculatedEndDate: calculatedEndDate.toISOString(),
+ })
+ }
+
+ // 1. 입찰 상태를 오픈으로 변경 + 제출기간 업데이트
await tx
.update(biddings)
.set({
status: 'bidding_opened',
+ submissionStartDate: calculatedStartDate,
+ submissionEndDate: calculatedEndDate,
updatedBy: userName,
updatedAt: new Date()
})
@@ -2617,3 +2680,35 @@ export async function setSpecificationMeetingParticipation(biddingCompanyId: num
return { success: false, error: '사양설명회 참여상태 업데이트에 실패했습니다.' }
}
}
+
+// 연동제 정보 업데이트
+export async function updatePriceAdjustmentInfo(params: {
+ biddingCompanyId: number
+ shiPriceAdjustmentApplied: boolean | null
+ priceAdjustmentNote: string | null
+ hasChemicalSubstance: boolean | null
+}): Promise<{ success: boolean; error?: string }> {
+ try {
+ const result = await db.update(biddingCompanies)
+ .set({
+ shiPriceAdjustmentApplied: params.shiPriceAdjustmentApplied,
+ priceAdjustmentNote: params.priceAdjustmentNote,
+ hasChemicalSubstance: params.hasChemicalSubstance,
+ updatedAt: new Date(),
+ })
+ .where(eq(biddingCompanies.id, params.biddingCompanyId))
+ .returning({ biddingId: biddingCompanies.biddingId })
+
+ if (result.length > 0) {
+ const biddingId = result[0].biddingId
+ revalidateTag(`bidding-${biddingId}`)
+ revalidateTag('quotation-vendors')
+ revalidatePath(`/evcp/bid/${biddingId}`)
+ }
+
+ return { success: true }
+ } catch (error) {
+ console.error('Failed to update price adjustment info:', error)
+ return { success: false, error: '연동제 정보 업데이트에 실패했습니다.' }
+ }
+}