summaryrefslogtreecommitdiff
path: root/lib/bidding/service.ts
diff options
context:
space:
mode:
Diffstat (limited to 'lib/bidding/service.ts')
-rw-r--r--lib/bidding/service.ts137
1 files changed, 91 insertions, 46 deletions
diff --git a/lib/bidding/service.ts b/lib/bidding/service.ts
index a7cd8286..b60fc73d 100644
--- a/lib/bidding/service.ts
+++ b/lib/bidding/service.ts
@@ -33,6 +33,11 @@ import {
like,
notInArray
} from 'drizzle-orm'
+import { revalidatePath } from 'next/cache'
+import { filterColumns } from '@/lib/filter-columns'
+import { GetBiddingsSchema } from './validation'
+
+
// 사용자 이메일로 사용자 코드 조회
export async function getUserCodeByEmail(email: string): Promise<string | null> {
@@ -49,9 +54,6 @@ export async function getUserCodeByEmail(email: string): Promise<string | null>
return null
}
}
-import { revalidatePath } from 'next/cache'
-import { filterColumns } from '@/lib/filter-columns'
-import { CreateBiddingSchema, GetBiddingsSchema, UpdateBiddingSchema } from './validation'
import { saveFile } from '../file-stroage'
// userId를 user.name으로 변환하는 유틸리티 함수
@@ -973,6 +975,74 @@ function generateNextSequence(currentMax: string | null): string {
return result.padStart(4, '0');
}
+// 입찰 참여 현황 카운트 계산 함수
+export async function getParticipantCountsForBidding(biddingId: number) {
+ try {
+ // 전체 참여자 수 (예상 참여자)
+ const expectedResult = await db
+ .select({ count: count() })
+ .from(biddingCompanies)
+ .where(eq(biddingCompanies.biddingId, biddingId))
+
+ const expected = expectedResult[0]?.count || 0
+
+ // 참여 완료 수
+ const participatedResult = await db
+ .select({ count: count() })
+ .from(biddingCompanies)
+ .where(and(
+ eq(biddingCompanies.biddingId, biddingId),
+ eq(biddingCompanies.invitationStatus, 'bidding_submitted')
+ ))
+
+ const participated = participatedResult[0]?.count || 0
+
+ // 거부/취소 수
+ const declinedResult = await db
+ .select({ count: count() })
+ .from(biddingCompanies)
+ .where(and(
+ eq(biddingCompanies.biddingId, biddingId),
+ or(
+ eq(biddingCompanies.invitationStatus, 'bidding_declined'),
+ eq(biddingCompanies.invitationStatus, 'bidding_cancelled')
+ )
+ ))
+
+ const declined = declinedResult[0]?.count || 0
+
+ // 대기중 수
+ const pendingResult = await db
+ .select({ count: count() })
+ .from(biddingCompanies)
+ .where(and(
+ eq(biddingCompanies.biddingId, biddingId),
+ or(
+ eq(biddingCompanies.invitationStatus, 'pending'),
+ eq(biddingCompanies.invitationStatus, 'bidding_sent'),
+ eq(biddingCompanies.invitationStatus, 'bidding_accepted')
+ )
+ ))
+
+ const pending = pendingResult[0]?.count || 0
+
+ return {
+ participantExpected: expected,
+ participantParticipated: participated,
+ participantDeclined: declined,
+ participantPending: pending
+ }
+ } catch (error) {
+ console.error('Error in getParticipantCountsForBidding:', error)
+ return {
+ participantExpected: 0,
+ participantParticipated: 0,
+ participantDeclined: 0,
+ participantPending: 0
+ }
+ }
+}
+
// 자동 입찰번호 생성
export async function generateBiddingNumber(
contractType: string,
@@ -982,9 +1052,9 @@ export async function generateBiddingNumber(
): Promise<string> {
// 계약 타입별 접두사 설정
const typePrefix = {
- 'general': 'E',
- 'unit_price': 'F',
- 'sale': 'G'
+ 'general': 'E', // 일반계약
+ 'unit_price': 'F', // 단가계약
+ 'sale': 'G', // 매각계약
};
const prefix = typePrefix[contractType as keyof typeof typePrefix] || 'E';
@@ -3163,8 +3233,8 @@ export async function increaseRoundOrRebid(biddingId: number, userId: string | u
prNumber: existingBidding.prNumber,
hasPrDocument: existingBidding.hasPrDocument,
- // 상태는 내정가 산정으로 초기화
- status: 'set_target_price',
+ // 상태는 입찰생성으로 초기화
+ status: 'bidding_generated',
isPublic: existingBidding.isPublic,
isUrgent: existingBidding.isUrgent,
@@ -3530,8 +3600,8 @@ export async function getBiddingsForReceive(input: GetBiddingsSchema) {
orderByColumns.push(desc(biddings.createdAt))
}
- // bid-receive 페이지용 데이터 조회 (필요한 컬럼만 선택)
- const data = await db
+ // bid-receive 페이지용 데이터 조회 (참여 현황 제외하고 기본 정보만)
+ const biddingData = await db
.select({
// 기본 입찰 정보
id: biddings.id,
@@ -3549,42 +3619,6 @@ export async function getBiddingsForReceive(input: GetBiddingsSchema) {
createdAt: biddings.createdAt,
updatedAt: biddings.updatedAt,
- // 참여 현황 집계
- participantExpected: sql<number>`
- COALESCE((
- SELECT count(*)
- FROM bidding_companies
- WHERE bidding_id = ${biddings.id}
- ), 0)
- `.as('participant_expected'),
-
- participantParticipated: sql<number>`
- COALESCE((
- SELECT count(*)
- FROM bidding_companies
- WHERE bidding_id = ${biddings.id}
- AND invitation_status = 'bidding_submitted'
- ), 0)
- `.as('participant_participated'),
-
- participantDeclined: sql<number>`
- COALESCE((
- SELECT count(*)
- FROM bidding_companies
- WHERE bidding_id = ${biddings.id}
- AND invitation_status IN ('bidding_declined', 'bidding_cancelled')
- ), 0)
- `.as('participant_declined'),
-
- participantPending: sql<number>`
- COALESCE((
- SELECT count(*)
- FROM bidding_companies
- WHERE bidding_id = ${biddings.id}
- AND invitation_status IN ('pending', 'bidding_sent', 'bidding_accepted')
- ), 0)
- `.as('participant_pending'),
-
// 개찰 정보
openedAt: biddings.openedAt,
openedBy: biddings.openedBy,
@@ -3595,6 +3629,17 @@ export async function getBiddingsForReceive(input: GetBiddingsSchema) {
.limit(input.perPage)
.offset(offset)
+ // 각 입찰에 대한 참여 현황 카운트 계산
+ const data = await Promise.all(
+ biddingData.map(async (bidding) => {
+ const participantCounts = await getParticipantCountsForBidding(bidding.id)
+ return {
+ ...bidding,
+ ...participantCounts
+ }
+ })
+ )
+
const pageCount = Math.ceil(total / input.perPage)
return { data, pageCount, total }