diff options
Diffstat (limited to 'lib/bidding/detail/service.ts')
| -rw-r--r-- | lib/bidding/detail/service.ts | 225 |
1 files changed, 10 insertions, 215 deletions
diff --git a/lib/bidding/detail/service.ts b/lib/bidding/detail/service.ts index a603834c..9fb3d87f 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, users } from '@/db/schema' +import { biddings, prItemsForBidding, biddingDocuments, biddingCompanies, vendors, companyPrItemBids, companyConditionResponses, vendorSelectionResults, 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' @@ -34,7 +34,7 @@ export interface BiddingDetailData { } // getBiddingById 함수 임포트 (기존 함수 재사용) -import { getBiddingById, getPRDetailsAction } from '@/lib/bidding/service' +import { getBiddingById } from '@/lib/bidding/service' // Promise.all을 사용하여 모든 데이터를 병렬로 조회 (캐시 적용) export async function getBiddingDetailData(biddingId: number): Promise<BiddingDetailData> { @@ -674,216 +674,6 @@ 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) => { - // 0. 중복 체크 - 이미 해당 입찰에 참여중인 업체인지 확인 - const existingCompany = await tx - .select() - .from(biddingCompanies) - .where(sql`${biddingCompanies.biddingId} = ${input.biddingId} AND ${biddingCompanies.companyId} = ${input.companyId}`) - - if (existingCompany.length > 0) { - throw new Error('이미 등록된 업체입니다') - } - - // 1. biddingCompanies에 레코드 생성 - const biddingCompanyResult = await tx.insert(biddingCompanies).values({ - biddingId: input.biddingId, - companyId: input.vendorId, - finalQuoteAmount: input.quotationAmount?.toString(), - awardRatio: input.awardRatio?.toString(), - isWinner: null, // 미정 상태로 초기화 - contactPerson: input.contactPerson, - contactEmail: input.contactEmail, - contactPhone: input.contactPhone, - finalQuoteSubmittedAt: new Date(), - // 스키마에 createdBy, updatedBy 필드가 없으므로 제거 - }).returning({ id: biddingCompanies.id }) - - if (biddingCompanyResult.length === 0) { - throw new Error('협력업체 정보 저장에 실패했습니다.') - } - - const biddingCompanyId = biddingCompanyResult[0].id - - // 2. companyConditionResponses에 입찰 조건 생성 - await tx.insert(companyConditionResponses).values({ - biddingCompanyId: biddingCompanyId, - paymentTermsResponse: input.paymentTermsResponse || '', - taxConditionsResponse: input.taxConditionsResponse || '', - proposedContractDeliveryDate: input.proposedContractDeliveryDate || null, - priceAdjustmentResponse: input.priceAdjustmentResponse || false, - incotermsResponse: input.incotermsResponse || '', - proposedShippingPort: input.proposedShippingPort || '', - proposedDestinationPort: input.proposedDestinationPort || '', - sparePartResponse: input.sparePartResponse || '', - additionalProposals: input.additionalProposals || '', - isPreQuote: false, - submittedAt: new Date(), - createdAt: new Date(), - updatedAt: new Date(), - }) - - return biddingCompanyId - }) - - // 캐시 무효화 - revalidateTag(`bidding-${input.biddingId}`) - revalidateTag('quotation-vendors') - revalidateTag('quotation-details') - revalidatePath(`/evcp/bid/[id]`) - return { - success: true, - message: '협력업체 정보가 성공적으로 저장되었습니다.', - data: { id: result } - } - } catch (error) { - console.error('Failed to create quotation vendor:', error) - return { success: false, error: '협력업체 정보 저장에 실패했습니다.' } - } -} - -// 협력업체 정보 업데이트 -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 = {} - if (input.quotationAmount !== undefined) updateData.finalQuoteAmount = input.quotationAmount - 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?.toString() - // status 필드가 스키마에 없으므로 제거 - // updatedBy 필드가 스키마에 없으므로 제거 - updateData.updatedAt = new Date() - - if (Object.keys(updateData).length > 0) { - await tx.update(biddingCompanies) - .set(updateData) - .where(eq(biddingCompanies.id, id)) - } - - // 2. companyConditionResponses 테이블 업데이트 (입찰 조건들) - if (input.paymentTermsResponse !== undefined || - input.taxConditionsResponse !== undefined || - input.incotermsResponse !== undefined || - input.proposedContractDeliveryDate !== undefined || - input.proposedShippingPort !== undefined || - input.proposedDestinationPort !== undefined || - input.priceAdjustmentResponse !== undefined || - input.sparePartResponse !== undefined || - input.additionalProposals !== undefined) { - - const conditionsUpdateData: any = {} - if (input.paymentTermsResponse !== undefined) conditionsUpdateData.paymentTermsResponse = input.paymentTermsResponse - if (input.taxConditionsResponse !== undefined) conditionsUpdateData.taxConditionsResponse = input.taxConditionsResponse - if (input.incotermsResponse !== undefined) conditionsUpdateData.incotermsResponse = input.incotermsResponse - if (input.proposedContractDeliveryDate !== undefined) conditionsUpdateData.proposedContractDeliveryDate = input.proposedContractDeliveryDate || null - if (input.proposedShippingPort !== undefined) conditionsUpdateData.proposedShippingPort = input.proposedShippingPort - if (input.proposedDestinationPort !== undefined) conditionsUpdateData.proposedDestinationPort = input.proposedDestinationPort - if (input.priceAdjustmentResponse !== undefined) conditionsUpdateData.priceAdjustmentResponse = input.priceAdjustmentResponse - if (input.sparePartResponse !== undefined) conditionsUpdateData.sparePartResponse = input.sparePartResponse - if (input.additionalProposals !== undefined) conditionsUpdateData.additionalProposals = input.additionalProposals - conditionsUpdateData.updatedAt = new Date() - - await tx.update(companyConditionResponses) - .set(conditionsUpdateData) - .where(eq(companyConditionResponses.biddingCompanyId, id)) - } - - return true - }) - - // 캐시 무효화 (모든 입찰 관련 데이터 무효화) - revalidateTag('quotation-vendors') - revalidateTag('quotation-details') - revalidatePath(`/evcp/bid/[id]`) - return { - success: true, - message: '협력업체 정보가 성공적으로 업데이트되었습니다.', - } - } catch (error) { - console.error('Failed to update quotation vendor:', error) - return { success: false, error: '협력업체 정보 업데이트에 실패했습니다.' } - } -} - -// 협력업체 정보 삭제 -export async function deleteQuotationVendor(id: number) { - try { - // TODO: 실제로는 견적 시스템의 테이블에서 삭제 - console.log(`[TODO] 견적 시스템에서 협력업체 정보 ${id} 삭제 예정`) - - // 임시로 성공 응답 - return { success: true, message: '협력업체 정보가 성공적으로 삭제되었습니다.' } - } catch (error) { - console.error('Failed to delete quotation vendor:', error) - return { success: false, error: '협력업체 정보 삭제에 실패했습니다.' } - } -} - -// 낙찰 처리 -export async function selectWinner(biddingId: number, vendorId: number, awardRatio: number, userId: string) { - try { - // 트랜잭션으로 처리 - await db.transaction(async (tx) => { - // 기존 낙찰자 초기화 - await tx - .update(biddingCompanies) - .set({ - isWinner: false, - updatedAt: new Date() - }) - .where(eq(biddingCompanies.biddingId, biddingId)) - - // 새로운 낙찰자 설정 - const biddingCompany = await tx - .select() - .from(biddingCompanies) - .where(and( - eq(biddingCompanies.biddingId, biddingId), - eq(biddingCompanies.companyId, vendorId) - )) - .limit(1) - - if (biddingCompany.length > 0) { - await tx - .update(biddingCompanies) - .set({ - isWinner: true, - updatedAt: new Date() - }) - .where(eq(biddingCompanies.id, biddingCompany[0].id)) - } - - // biddings 테이블의 상태 업데이트 - await tx - .update(biddings) - .set({ - status: 'vendor_selected', - finalBidPrice: undefined, // TODO: 낙찰가 설정 로직 추가 - updatedAt: new Date() - }) - .where(eq(biddings.id, biddingId)) - }) - - // 캐시 무효화 - revalidateTag(`bidding-${biddingId}`) - revalidateTag('quotation-vendors') - revalidateTag('quotation-details') - revalidatePath(`/evcp/bid/${biddingId}`) - return { success: true, message: '낙찰 처리가 완료되었습니다.' } - } catch (error) { - console.error('Failed to select winner:', error) - return { success: false, error: '낙찰 처리에 실패했습니다.' } - } -} - // 유찰 처리 export async function markAsDisposal(biddingId: number, userId: string) { try { @@ -913,12 +703,14 @@ export async function markAsDisposal(biddingId: number, userId: string) { eq(biddingCompanies.biddingId, biddingId), eq(biddingCompanies.isBiddingParticipated, true) )) + const userName = await getUserNameById(userId) // 입찰 상태를 유찰로 변경 await db .update(biddings) .set({ status: 'bidding_disposal', + updatedBy: userName, updatedAt: new Date() }) .where(eq(biddings.id, biddingId)) @@ -996,12 +788,15 @@ export async function registerBidding(biddingId: number, userId: string) { const bidding = biddingInfo[0] + const userName = await getUserNameById(userId) + await db.transaction(async (tx) => { // 1. 입찰 상태를 오픈으로 변경 await tx .update(biddings) .set({ status: 'bidding_opened', + updatedBy: userName, updatedAt: new Date() }) .where(eq(biddings.id, biddingId)) @@ -1098,13 +893,14 @@ export async function createRebidding(biddingId: number, userId: string) { 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)) @@ -1721,6 +1517,7 @@ export interface PartnersBiddingListItem { submissionDate: Date | null // 입찰제출일 (submissionEndDate) } +// 협력업체용 입찰 목록 조회 (bidding_companies 기준) export async function getBiddingListForPartners(companyId: number): Promise<PartnersBiddingListItem[]> { try { const result = await db @@ -1821,7 +1618,6 @@ export async function getBiddingDetailsForPartners(biddingId: number, companyId: contractEndDate: biddings.contractEndDate, // 일정 정보 - preQuoteDate: biddings.preQuoteDate, biddingRegistrationDate: biddings.biddingRegistrationDate, submissionStartDate: biddings.submissionStartDate, submissionEndDate: biddings.submissionEndDate, @@ -1849,7 +1645,6 @@ export async function getBiddingDetailsForPartners(biddingId: number, companyId: isPreQuoteSelected: biddingCompanies.isPreQuoteSelected, isBiddingParticipated: biddingCompanies.isBiddingParticipated, isPreQuoteParticipated: biddingCompanies.isPreQuoteParticipated, - isBiddingParticipated: biddingCompanies.isBiddingParticipated, hasSpecificationMeeting: biddings.hasSpecificationMeeting, // 응답한 조건들 (company_condition_responses) - 제시된 조건과 응답 모두 여기서 관리 paymentTermsResponse: companyConditionResponses.paymentTermsResponse, |
