From ac70d9f5daacdf83f24e45e7834ad6d3325c3cbb Mon Sep 17 00:00:00 2001 From: dujinkim Date: Thu, 20 Nov 2025 03:15:03 +0000 Subject: (최겸) 입찰 수정 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/bidding/detail/service.ts | 109 +-------------------- lib/bidding/list/biddings-table-columns.tsx | 4 +- lib/bidding/service.ts | 2 +- lib/bidding/vendor/partners-bidding-detail.tsx | 10 +- .../vendor/partners-bidding-list-columns.tsx | 40 ++++---- 5 files changed, 31 insertions(+), 134 deletions(-) diff --git a/lib/bidding/detail/service.ts b/lib/bidding/detail/service.ts index 6ab9270e..39bf0c46 100644 --- a/lib/bidding/detail/service.ts +++ b/lib/bidding/detail/service.ts @@ -918,114 +918,6 @@ export async function registerBidding(biddingId: number, userId: string) { } } -// 재입찰 생성 (기존 입찰의 revision 업데이트 + 메일 발송) -export async function createRebidding(biddingId: number, userId: string) { - try { - // 기존 입찰 정보 조회 - const bidding = await db - .select() - .from(biddings) - .where(eq(biddings.id, biddingId)) - .limit(1) - - if (bidding.length === 0) { - return { success: false, error: '입찰을 찾을 수 없습니다.' } - } - - const originalBidding = bidding[0] - - // 기존 입찰 참여 업체들 조회 - const participantCompanies = await db - .select({ - companyId: biddingCompanies.companyId, - companyName: vendors.vendorName, - contactEmail: vendors.email - }) - .from(biddingCompanies) - .leftJoin(vendors, eq(biddingCompanies.companyId, vendors.id)) - .where(and( - eq(biddingCompanies.biddingId, biddingId), - eq(biddingCompanies.isBiddingParticipated, true) - )) - const userName = await getUserNameById(userId) - // 기존 입찰의 revision 증가 및 상태 변경 - const updatedBidding = await db - .update(biddings) - .set({ - revision: (originalBidding.revision || 0) + 1, - status: 'bidding_opened', // 재입찰 시 다시 오픈 상태로 - updatedBy: userName, - updatedAt: new Date() - }) - .where(eq(biddings.id, biddingId)) - .returning({ - id: biddings.id, - biddingNumber: biddings.biddingNumber, - revision: biddings.revision - }) - - if (updatedBidding.length === 0) { - return { success: false, error: '재입찰 업데이트에 실패했습니다.' } - } - - // // 참여 업체들의 상태를 대기로 변경 - // await db - // .update(biddingCompanies) - // .set({ - // isBiddingParticipated: null, // 대기 상태로 변경 - // invitationStatus: 'sent', - // updatedAt: new Date() - // }) - // .where(and( - // eq(biddingCompanies.biddingId, biddingId), - // eq(biddingCompanies.isBiddingParticipated, true) - // )) - - // 재입찰 안내 메일 발송 - for (const company of participantCompanies) { - if (company.contactEmail) { - try { - await sendEmail({ - to: company.contactEmail, - template: 'rebidding-invitation', - context: { - companyName: company.companyName, - biddingNumber: updatedBidding[0].biddingNumber, - title: originalBidding.title, - projectName: originalBidding.projectName, - itemName: originalBidding.itemName, - biddingType: originalBidding.biddingType, - revision: updatedBidding[0].revision || 1, - submissionStartDate: originalBidding.submissionStartDate, - submissionEndDate: originalBidding.submissionEndDate, - biddingUrl: `${process.env.NEXT_PUBLIC_BASE_URL}/partners/bid/${biddingId}`, - bidPicName: originalBidding.bidPicName, - supplyPicName: originalBidding.supplyPicName, - language: 'ko' - } - }) - } catch (emailError) { - console.error(`Failed to send rebidding email to ${company.contactEmail}:`, emailError) - } - } - } - - // 캐시 무효화 - revalidateTag(`bidding-${biddingId}`) - revalidateTag('quotation-vendors') - revalidateTag('quotation-details') - revalidatePath('/evcp/bid') - revalidatePath(`/evcp/bid/${biddingId}`) - - return { - success: true, - message: `재입찰이 성공적으로 처리되었습니다. ${participantCompanies.length}개 업체에 안내 메일을 발송했습니다.` - } - } catch (error) { - console.error('Failed to create rebidding:', error) - return { success: false, error: '재입찰 처리에 실패했습니다.' } - } -} // 업체 선정 사유 업데이트 export async function updateVendorSelectionReason(biddingId: number, selectedCompanyId: number, selectionReason: string, userId: string) { @@ -1559,6 +1451,7 @@ export interface PartnersBiddingListItem { respondedAt: string | null finalQuoteAmount: number | null finalQuoteSubmittedAt: string | null + isFinalSubmission: boolean | null isWinner: boolean | null isAttendingMeeting: boolean | null isPreQuoteSelected: boolean | null diff --git a/lib/bidding/list/biddings-table-columns.tsx b/lib/bidding/list/biddings-table-columns.tsx index 48c32302..40c7f271 100644 --- a/lib/bidding/list/biddings-table-columns.tsx +++ b/lib/bidding/list/biddings-table-columns.tsx @@ -246,7 +246,7 @@ export function getBiddingsColumns({ setRowAction }: GetColumnsProps): ColumnDef size: 100, meta: { excelHeader: "입찰등록일" }, }, - + // ░░░ 입찰서제출기간 ░░░ { id: "submissionPeriod", header: ({ column }) => , @@ -263,7 +263,7 @@ export function getBiddingsColumns({ setRowAction }: GetColumnsProps): ColumnDef return (
- {formatDate(startDate, "KR")} ~ {formatDate(endDate, "KR")} + {new Date(startDate).toISOString().slice(0, 16).replace('T', ' ')} ~ {new Date(endDate).toISOString().slice(0, 16).replace('T', ' ')}
{isActive && ( 진행중 diff --git a/lib/bidding/service.ts b/lib/bidding/service.ts index 68ae016e..14bed105 100644 --- a/lib/bidding/service.ts +++ b/lib/bidding/service.ts @@ -1166,7 +1166,7 @@ export async function createBidding(input: CreateBiddingInput, userId: string) { .insert(biddings) .values({ biddingNumber, - originalBiddingNumber: null, // 원입찰번호는 단순 정보이므로 null + originalBiddingNumber: null, // 원입찰번호는 초기 생성이므로 아직 없음 revision: input.revision || 0, // 프로젝트 정보 (PR 아이템에서 설정됨) diff --git a/lib/bidding/vendor/partners-bidding-detail.tsx b/lib/bidding/vendor/partners-bidding-detail.tsx index fe254dad..66c90eaf 100644 --- a/lib/bidding/vendor/partners-bidding-detail.tsx +++ b/lib/bidding/vendor/partners-bidding-detail.tsx @@ -25,7 +25,7 @@ import { Calendar, ChevronDown } from 'lucide-react' - +import { format } from 'date-fns' import { formatDate } from '@/lib/utils' import { getBiddingDetailsForPartners, @@ -806,9 +806,9 @@ export function PartnersBiddingDetail({ biddingId, companyId }: PartnersBiddingD
- {formatDate(biddingDetail.contractStartDate, 'KR')} + {format(new Date(biddingDetail.contractStartDate), "yyyy-MM-dd")} ~ - {formatDate(biddingDetail.contractEndDate, 'KR')} + {format(new Date(biddingDetail.contractEndDate), "yyyy-MM-dd")}
@@ -874,12 +874,12 @@ export function PartnersBiddingDetail({ biddingId, companyId }: PartnersBiddingD
{biddingDetail.submissionStartDate && biddingDetail.submissionEndDate && (
- 응찰기간: {formatDate(biddingDetail.submissionStartDate, 'KR')} ~ {formatDate(biddingDetail.submissionEndDate, 'KR')} + 입찰서 제출기간: {new Date(biddingDetail.submissionStartDate).toISOString().slice(0, 16).replace('T', ' ')} ~ {new Date(biddingDetail.submissionEndDate).toISOString().slice(0, 16).replace('T', ' ')}
)} {biddingDetail.evaluationDate && (
- 평가일: {formatDate(biddingDetail.evaluationDate, 'KR')} + 평가일: {format(new Date(biddingDetail.evaluationDate), "yyyy-MM-dd HH:mm")}
)}
diff --git a/lib/bidding/vendor/partners-bidding-list-columns.tsx b/lib/bidding/vendor/partners-bidding-list-columns.tsx index d9058e97..ba8efae6 100644 --- a/lib/bidding/vendor/partners-bidding-list-columns.tsx +++ b/lib/bidding/vendor/partners-bidding-list-columns.tsx @@ -240,22 +240,6 @@ export function getPartnersBiddingListColumns({ setRowAction }: PartnersBiddingL }, }), - // 사전견적 참여의사 - columnHelper.accessor('isPreQuoteParticipated', { - header: '사전견적 참여의사', - cell: ({ row }) => { - const participated = row.original.isPreQuoteParticipated - if (participated === null) { - return 미결정 - } - return ( - - {participated ? '참여' : '미참여'} - - ) - }, - }), - // 입찰 참여의사 columnHelper.accessor('isBiddingParticipated', { header: '입찰 참여의사', @@ -272,6 +256,26 @@ export function getPartnersBiddingListColumns({ setRowAction }: PartnersBiddingL }, }), + // 입찰 제출여부 + columnHelper.display({ + id: 'biddingSubmissionStatus', + header: '입찰 제출여부', + cell: ({ row }) => { + const finalQuoteAmount = row.original.finalQuoteAmount + const isFinalSubmission = row.original.isFinalSubmission + + if (!finalQuoteAmount) { + return 미제출 + } + + if (isFinalSubmission) { + return 최종제출 + } + + return 제출 + }, + }), + // 계약구분 columnHelper.accessor('contractType', { header: '계약구분', @@ -291,9 +295,9 @@ export function getPartnersBiddingListColumns({ setRowAction }: PartnersBiddingL } return (
-
{format(new Date(startDate), "yyyy-MM-dd")}
+
{new Date(startDate).toISOString().slice(0, 16).replace('T', ' ')}
~
-
{format(new Date(endDate), "yyyy-MM-dd")}
+
{new Date(endDate).toISOString().slice(0, 16).replace('T', ' ')}
) }, -- cgit v1.2.3