summaryrefslogtreecommitdiff
path: root/lib/bidding/detail/service.ts
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-09-11 11:21:35 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-09-11 11:21:35 +0000
commit47e527f5f763658600696ee58451fb666e692f5a (patch)
tree67f159fd0cbad5e0553c7958caa3075127121e76 /lib/bidding/detail/service.ts
parentee77f36b1ceece1236d45fba102c3ea410acebc1 (diff)
(최겸) 구매 입찰 세부기능 수정
Diffstat (limited to 'lib/bidding/detail/service.ts')
-rw-r--r--lib/bidding/detail/service.ts65
1 files changed, 44 insertions, 21 deletions
diff --git a/lib/bidding/detail/service.ts b/lib/bidding/detail/service.ts
index d9bcb255..e22331bb 100644
--- a/lib/bidding/detail/service.ts
+++ b/lib/bidding/detail/service.ts
@@ -1,7 +1,7 @@
'use server'
import db from '@/db/db'
-import { biddings, prItemsForBidding, biddingDocuments, biddingCompanies, vendors, companyPrItemBids, companyConditionResponses, vendorSelectionResults, BiddingListItem, biddingConditions, priceAdjustmentForms } from '@/db/schema'
+import { biddings, prItemsForBidding, biddingDocuments, biddingCompanies, vendors, companyPrItemBids, companyConditionResponses, vendorSelectionResults, BiddingListItem, biddingConditions, priceAdjustmentForms, users } from '@/db/schema'
import { specificationMeetings } from '@/db/schema/bidding'
import { eq, and, sql, desc, ne } from 'drizzle-orm'
import { revalidatePath, revalidateTag } from 'next/cache'
@@ -9,6 +9,22 @@ import { unstable_cache } from "@/lib/unstable-cache";
import { sendEmail } from '@/lib/mail/sendEmail'
import { saveFile } from '@/lib/file-stroage'
+// userId를 user.name으로 변환하는 유틸리티 함수
+async function getUserNameById(userId: string): Promise<string> {
+ try {
+ const user = await db
+ .select({ name: users.name })
+ .from(users)
+ .where(eq(users.id, parseInt(userId)))
+ .limit(1)
+
+ return user[0]?.name || userId // user.name이 없으면 userId를 그대로 반환
+ } catch (error) {
+ console.error('Failed to get user name:', error)
+ return userId // 에러 시 userId를 그대로 반환
+ }
+}
+
// 데이터 조회 함수들
export interface BiddingDetailData {
bidding: Awaited<ReturnType<typeof getBiddingById>>
@@ -266,6 +282,7 @@ export async function getQuotationVendors(biddingId: number): Promise<QuotationV
awardRatio: vendor.awardRatio ? Number(vendor.awardRatio) : null,
isBiddingParticipated: vendor.isBiddingParticipated,
status: vendor.status as 'pending' | 'submitted' | 'selected' | 'rejected',
+ documents: [], // 빈 배열로 초기화
}))
} catch (error) {
console.error('Failed to get quotation vendors:', error)
@@ -664,22 +681,20 @@ export async function createBiddingDetailVendor(
// 협력업체 정보 저장 - biddingCompanies와 companyConditionResponses 테이블에 레코드 생성
export async function createQuotationVendor(input: any, userId: string) {
try {
+ const userName = await getUserNameById(userId)
const result = await db.transaction(async (tx) => {
// 1. biddingCompanies에 레코드 생성
const biddingCompanyResult = await tx.insert(biddingCompanies).values({
biddingId: input.biddingId,
companyId: input.vendorId,
- quotationAmount: input.quotationAmount,
- currency: input.currency,
- status: input.status,
- awardRatio: input.awardRatio,
+ finalQuoteAmount: input.quotationAmount?.toString(),
+ awardRatio: input.awardRatio?.toString(),
isWinner: false,
contactPerson: input.contactPerson,
contactEmail: input.contactEmail,
contactPhone: input.contactPhone,
- submissionDate: new Date(),
- createdBy: userId,
- updatedBy: userId,
+ finalQuoteSubmittedAt: new Date(),
+ // 스키마에 createdBy, updatedBy 필드가 없으므로 제거
}).returning({ id: biddingCompanies.id })
if (biddingCompanyResult.length === 0) {
@@ -728,6 +743,7 @@ export async function createQuotationVendor(input: any, userId: string) {
// 협력업체 정보 업데이트
export async function updateQuotationVendor(id: number, input: any, userId: string) {
try {
+ const userName = await getUserNameById(userId)
const result = await db.transaction(async (tx) => {
// 1. biddingCompanies 테이블 업데이트
const updateData: any = {}
@@ -735,9 +751,9 @@ export async function updateQuotationVendor(id: number, input: any, userId: stri
if (input.contactPerson !== undefined) updateData.contactPerson = input.contactPerson
if (input.contactEmail !== undefined) updateData.contactEmail = input.contactEmail
if (input.contactPhone !== undefined) updateData.contactPhone = input.contactPhone
- if (input.awardRatio !== undefined) updateData.awardRatio = input.awardRatio
- if (input.status !== undefined) updateData.status = input.status
- updateData.updatedBy = userId
+ if (input.awardRatio !== undefined) updateData.awardRatio = input.awardRatio?.toString()
+ // status 필드가 스키마에 없으므로 제거
+ // updatedBy 필드가 스키마에 없으므로 제거
updateData.updatedAt = new Date()
if (Object.keys(updateData).length > 0) {
@@ -1031,8 +1047,10 @@ export async function registerBidding(biddingId: number, userId: string) {
// 캐시 무효화
revalidateTag(`bidding-${biddingId}`)
+ revalidateTag('bidding-detail')
revalidateTag('quotation-vendors')
revalidateTag('quotation-details')
+ revalidateTag('pr-items')
revalidatePath(`/evcp/bid/${biddingId}`)
return {
@@ -1157,6 +1175,7 @@ export async function createRebidding(biddingId: number, userId: string) {
// 업체 선정 사유 업데이트
export async function updateVendorSelectionReason(biddingId: number, selectedCompanyId: number, selectionReason: string, userId: string) {
try {
+ const userName = await getUserNameById(userId)
// vendorSelectionResults 테이블에 삽입 또는 업데이트
await db
.insert(vendorSelectionResults)
@@ -1164,7 +1183,7 @@ export async function updateVendorSelectionReason(biddingId: number, selectedCom
biddingId,
selectedCompanyId,
selectionReason,
- selectedBy: userId,
+ selectedBy: userName,
selectedAt: new Date(),
createdAt: new Date(),
updatedAt: new Date()
@@ -1174,7 +1193,7 @@ export async function updateVendorSelectionReason(biddingId: number, selectedCom
set: {
selectedCompanyId,
selectionReason,
- selectedBy: userId,
+ selectedBy: userName,
selectedAt: new Date(),
updatedAt: new Date()
}
@@ -1194,6 +1213,7 @@ export async function updateVendorSelectionReason(biddingId: number, selectedCom
// 낙찰용 문서 업로드
export async function uploadAwardDocument(biddingId: number, file: File, userId: string) {
try {
+ const userName = await getUserNameById(userId)
const saveResult = await saveFile({
file,
directory: `biddings/${biddingId}/award`,
@@ -1211,10 +1231,9 @@ export async function uploadAwardDocument(biddingId: number, file: File, userId:
documentType: 'other',
title: '낙찰 관련 문서',
description: '낙찰 관련 첨부파일',
- uploadedBy: userId,
+ uploadedBy: userName,
uploadedAt: new Date(),
- createdAt: new Date(),
- updatedAt: new Date()
+ // createdAt, updatedAt 필드가 스키마에 없으므로 제거
}).returning()
return {
@@ -1292,6 +1311,7 @@ export async function getAwardDocumentForDownload(documentId: number, biddingId:
// 낙찰용 문서 삭제
export async function deleteAwardDocument(documentId: number, biddingId: number, userId: string) {
try {
+ const userName = await getUserNameById(userId)
// 문서 정보 조회
const documents = await db
.select()
@@ -1300,7 +1320,7 @@ export async function deleteAwardDocument(documentId: number, biddingId: number,
eq(biddingDocuments.id, documentId),
eq(biddingDocuments.biddingId, biddingId),
eq(biddingDocuments.documentType, 'other'),
- eq(biddingDocuments.uploadedBy, userId)
+ eq(biddingDocuments.uploadedBy, userName)
))
.limit(1)
@@ -1335,6 +1355,7 @@ export async function deleteAwardDocument(documentId: number, biddingId: number,
// 낙찰 처리 (발주비율과 함께)
export async function awardBidding(biddingId: number, selectionReason: string, userId: string) {
try {
+ const userName = await getUserNameById(userId)
// 낙찰된 업체들 조회 (isWinner가 true인 업체들)
const awardedCompanies = await db
.select({
@@ -1388,7 +1409,7 @@ export async function awardBidding(biddingId: number, selectionReason: string, u
.set({
selectedCompanyId: firstAwardedCompany.companyId,
selectionReason,
- selectedBy: userId,
+ selectedBy: userName,
selectedAt: new Date(),
updatedAt: new Date()
})
@@ -1401,7 +1422,7 @@ export async function awardBidding(biddingId: number, selectionReason: string, u
biddingId,
selectedCompanyId: firstAwardedCompany.companyId,
selectionReason,
- selectedBy: userId,
+ selectedBy: userName,
selectedAt: new Date(),
createdAt: new Date(),
updatedAt: new Date()
@@ -1532,6 +1553,7 @@ export async function saveBiddingDraft(
userId: string
) {
try {
+ const userName = await getUserNameById(userId)
let totalAmount = 0
await db.transaction(async (tx) => {
@@ -1668,7 +1690,7 @@ export interface PartnersBiddingListItem {
// biddings 정보
biddingId: number
biddingNumber: string
- revision: number
+ revision: number | null
projectName: string
itemName: string
title: string
@@ -1883,6 +1905,7 @@ export async function submitPartnerResponse(
userId: string
) {
try {
+ const userName = await getUserNameById(userId)
const result = await db.transaction(async (tx) => {
// 0. 품목별 견적 정보 최종 저장 (본입찰 제출) - Upsert 방식
if (response.prItemQuotations && response.prItemQuotations.length > 0) {
@@ -1981,7 +2004,7 @@ export async function submitPartnerResponse(
const companyUpdateData: any = {
respondedAt: new Date(),
updatedAt: new Date(),
- // updatedBy: userId, // 이 필드가 존재하지 않음
+ // updatedBy: userName, // 이 필드가 존재하지 않음
}
if (response.finalQuoteAmount !== undefined) {