diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-09-03 10:35:57 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-09-03 10:35:57 +0000 |
| commit | a2bc455f654e011c53968b0d3a14389d7259847e (patch) | |
| tree | 6ff60b8ef0880aaa4cf2c9d4f234772fb0a74537 /lib/bidding/detail/service.ts | |
| parent | bfe354f7633f62350e61eb784cbf1926079339d1 (diff) | |
(최겸) 구매 입찰 개발(벤더 응찰 개발 및 기본계약 요청 개발 필)
Diffstat (limited to 'lib/bidding/detail/service.ts')
| -rw-r--r-- | lib/bidding/detail/service.ts | 174 |
1 files changed, 162 insertions, 12 deletions
diff --git a/lib/bidding/detail/service.ts b/lib/bidding/detail/service.ts index 2ce17713..c811f46d 100644 --- a/lib/bidding/detail/service.ts +++ b/lib/bidding/detail/service.ts @@ -1,7 +1,8 @@ 'use server' import db from '@/db/db' -import { biddings, prItemsForBidding, biddingDocuments, biddingCompanies, vendors, companyPrItemBids, companyConditionResponses, vendorSelectionResults, BiddingListItem, biddingConditions } from '@/db/schema' +import { biddings, prItemsForBidding, biddingDocuments, biddingCompanies, vendors, companyPrItemBids, companyConditionResponses, vendorSelectionResults, BiddingListItem, biddingConditions, priceAdjustmentForms } from '@/db/schema' +import { specificationMeetings } from '@/db/schema/bidding' import { eq, and, sql, desc, ne } from 'drizzle-orm' import { revalidatePath } from 'next/cache' @@ -224,6 +225,7 @@ export async function getQuotationVendors(biddingId: number): Promise<QuotationV proposedShippingPort: companyConditionResponses.proposedShippingPort, proposedDestinationPort: companyConditionResponses.proposedDestinationPort, priceAdjustmentResponse: companyConditionResponses.priceAdjustmentResponse, + isInitialResponse: companyConditionResponses.isInitialResponse, sparePartResponse: companyConditionResponses.sparePartResponse, additionalProposals: companyConditionResponses.additionalProposals, }) @@ -256,6 +258,7 @@ export async function getQuotationVendors(biddingId: number): Promise<QuotationV proposedShippingPort: vendor.proposedShippingPort || '', proposedDestinationPort: vendor.proposedDestinationPort || '', priceAdjustmentResponse: vendor.priceAdjustmentResponse || false, + isInitialResponse: vendor.isInitialResponse || false, sparePartResponse: vendor.sparePartResponse || '', additionalProposals: vendor.additionalProposals || '', documents: [] // TODO: 문서 정보 조회 로직 추가 @@ -828,6 +831,7 @@ export async function getBiddingDetailsForPartners(biddingId: number, companyId: proposedShippingPort: companyConditionResponses.proposedShippingPort, proposedDestinationPort: companyConditionResponses.proposedDestinationPort, priceAdjustmentResponse: companyConditionResponses.priceAdjustmentResponse, + isInitialResponse: companyConditionResponses.isInitialResponse, sparePartResponse: companyConditionResponses.sparePartResponse, additionalProposals: companyConditionResponses.additionalProposals, responseSubmittedAt: companyConditionResponses.submittedAt, @@ -859,9 +863,27 @@ export async function submitPartnerResponse( proposedShippingPort?: string proposedDestinationPort?: string priceAdjustmentResponse?: boolean + isInitialResponse?: boolean sparePartResponse?: string additionalProposals?: string finalQuoteAmount?: number + priceAdjustmentForm?: { + itemName?: string + adjustmentReflectionPoint?: string + majorApplicableRawMaterial?: string + adjustmentFormula?: string + rawMaterialPriceIndex?: string + referenceDate?: string + comparisonDate?: string + adjustmentRatio?: number + notes?: string + adjustmentConditions?: string + majorNonApplicableRawMaterial?: string + adjustmentPeriod?: string + contractorWriter?: string + adjustmentDate?: string + nonApplicableReason?: string + } }, userId: string ) { @@ -876,6 +898,7 @@ export async function submitPartnerResponse( proposedShippingPort: response.proposedShippingPort, proposedDestinationPort: response.proposedDestinationPort, priceAdjustmentResponse: response.priceAdjustmentResponse, + isInitialResponse: response.isInitialResponse, sparePartResponse: response.sparePartResponse, additionalProposals: response.additionalProposals, submittedAt: new Date(), @@ -889,20 +912,67 @@ export async function submitPartnerResponse( .where(eq(companyConditionResponses.biddingCompanyId, biddingCompanyId)) .limit(1) + let companyConditionResponseId: number + if (existingResponse.length > 0) { // 업데이트 await tx .update(companyConditionResponses) .set(responseData) .where(eq(companyConditionResponses.biddingCompanyId, biddingCompanyId)) + + companyConditionResponseId = existingResponse[0].id } else { // 새로 생성 - await tx + const [newResponse] = await tx .insert(companyConditionResponses) .values({ biddingCompanyId, ...responseData, }) + .returning({ id: companyConditionResponses.id }) + + companyConditionResponseId = newResponse.id + } + + // 3. 연동제 정보 저장 (연동제 적용이 true이고 연동제 정보가 있는 경우) + if (response.priceAdjustmentResponse && response.priceAdjustmentForm) { + const priceAdjustmentData = { + companyConditionResponsesId: companyConditionResponseId, + itemName: response.priceAdjustmentForm.itemName, + adjustmentReflectionPoint: response.priceAdjustmentForm.adjustmentReflectionPoint, + majorApplicableRawMaterial: response.priceAdjustmentForm.majorApplicableRawMaterial, + adjustmentFormula: response.priceAdjustmentForm.adjustmentFormula, + rawMaterialPriceIndex: response.priceAdjustmentForm.rawMaterialPriceIndex, + referenceDate: response.priceAdjustmentForm.referenceDate ? new Date(response.priceAdjustmentForm.referenceDate) : null, + comparisonDate: response.priceAdjustmentForm.comparisonDate ? new Date(response.priceAdjustmentForm.comparisonDate) : null, + adjustmentRatio: response.priceAdjustmentForm.adjustmentRatio, + notes: response.priceAdjustmentForm.notes, + adjustmentConditions: response.priceAdjustmentForm.adjustmentConditions, + majorNonApplicableRawMaterial: response.priceAdjustmentForm.majorNonApplicableRawMaterial, + adjustmentPeriod: response.priceAdjustmentForm.adjustmentPeriod, + contractorWriter: response.priceAdjustmentForm.contractorWriter, + adjustmentDate: response.priceAdjustmentForm.adjustmentDate ? new Date(response.priceAdjustmentForm.adjustmentDate) : null, + nonApplicableReason: response.priceAdjustmentForm.nonApplicableReason, + } + + // 기존 연동제 정보가 있는지 확인 + const existingPriceAdjustment = await tx + .select() + .from(priceAdjustmentForms) + .where(eq(priceAdjustmentForms.companyConditionResponsesId, companyConditionResponseId)) + .limit(1) + + if (existingPriceAdjustment.length > 0) { + // 업데이트 + await tx + .update(priceAdjustmentForms) + .set(priceAdjustmentData) + .where(eq(priceAdjustmentForms.companyConditionResponsesId, companyConditionResponseId)) + } else { + // 새로 생성 + await tx.insert(priceAdjustmentForms).values(priceAdjustmentData) + } } // 2. biddingCompanies 테이블에 견적 금액과 상태 업데이트 @@ -940,6 +1010,26 @@ export async function submitPartnerResponse( // 사양설명회 정보 조회 (협력업체용) export async function getSpecificationMeetingForPartners(biddingId: number) { try { + // specification_meetings 테이블에서 사양설명회 정보 조회 + const specMeeting = await db + .select({ + id: specificationMeetings.id, + meetingDate: specificationMeetings.meetingDate, + meetingTime: specificationMeetings.meetingTime, + location: specificationMeetings.location, + address: specificationMeetings.address, + contactPerson: specificationMeetings.contactPerson, + contactPhone: specificationMeetings.contactPhone, + contactEmail: specificationMeetings.contactEmail, + agenda: specificationMeetings.agenda, + materials: specificationMeetings.materials, + notes: specificationMeetings.notes, + isRequired: specificationMeetings.isRequired, + }) + .from(specificationMeetings) + .where(eq(specificationMeetings.biddingId, biddingId)) + .limit(1) + // bidding_documents에서 사양설명회 관련 문서 조회 const documents = await db .select({ @@ -956,17 +1046,12 @@ export async function getSpecificationMeetingForPartners(biddingId: number) { eq(biddingDocuments.documentType, 'specification_meeting') )) - // biddings 테이블에서 사양설명회 기본 정보 조회 + // 기본 입찰 정보도 가져오기 (제목, 입찰번호 등) const bidding = await db .select({ id: biddings.id, title: biddings.title, biddingNumber: biddings.biddingNumber, - preQuoteDate: biddings.preQuoteDate, - biddingRegistrationDate: biddings.biddingRegistrationDate, - managerName: biddings.managerName, - managerEmail: biddings.managerEmail, - managerPhone: biddings.managerPhone, }) .from(biddings) .where(eq(biddings.id, biddingId)) @@ -976,15 +1061,44 @@ export async function getSpecificationMeetingForPartners(biddingId: number) { return { success: false, error: '입찰 정보를 찾을 수 없습니다.' } } + // 사양설명회 정보가 없는 경우 + if (specMeeting.length === 0) { + return { + success: true, + data: { + ...bidding[0], + documents, + meetingDate: null, + meetingTime: null, + location: null, + address: null, + contactPerson: null, + contactPhone: null, + contactEmail: null, + agenda: null, + materials: null, + notes: null, + isRequired: false, + } + } + } + return { success: true, data: { ...bidding[0], documents, - meetingDate: bidding[0].preQuoteDate ? bidding[0].preQuoteDate.toISOString().split('T')[0] : null, - contactPerson: bidding[0].managerName, - contactEmail: bidding[0].managerEmail, - contactPhone: bidding[0].managerPhone, + meetingDate: specMeeting[0].meetingDate ? specMeeting[0].meetingDate.toISOString().split('T')[0] : null, + meetingTime: specMeeting[0].meetingTime, + location: specMeeting[0].location, + address: specMeeting[0].address, + contactPerson: specMeeting[0].contactPerson, + contactPhone: specMeeting[0].contactPhone, + contactEmail: specMeeting[0].contactEmail, + agenda: specMeeting[0].agenda, + materials: specMeeting[0].materials, + notes: specMeeting[0].notes, + isRequired: specMeeting[0].isRequired, } } } catch (error) { @@ -1094,3 +1208,39 @@ export async function updatePartnerAttendance( return { success: false, error: '참석 여부 업데이트에 실패했습니다.' } } } + +// 연동제 정보 조회 +export async function getPriceAdjustmentForm(companyConditionResponseId: number) { + try { + const priceAdjustment = await db + .select() + .from(priceAdjustmentForms) + .where(eq(priceAdjustmentForms.companyConditionResponsesId, companyConditionResponseId)) + .limit(1) + + return priceAdjustment[0] || null + } catch (error) { + console.error('Failed to get price adjustment form:', error) + return null + } +} + +// 입찰업체 ID로 연동제 정보 조회 +export async function getPriceAdjustmentFormByBiddingCompanyId(biddingCompanyId: number) { + try { + const result = await db + .select({ + priceAdjustmentForm: priceAdjustmentForms, + companyConditionResponse: companyConditionResponses, + }) + .from(companyConditionResponses) + .leftJoin(priceAdjustmentForms, eq(companyConditionResponses.id, priceAdjustmentForms.companyConditionResponsesId)) + .where(eq(companyConditionResponses.biddingCompanyId, biddingCompanyId)) + .limit(1) + + return result[0]?.priceAdjustmentForm || null + } catch (error) { + console.error('Failed to get price adjustment form by bidding company id:', error) + return null + } +} |
