diff options
| -rw-r--r-- | lib/bidding/actions.ts | 52 | ||||
| -rw-r--r-- | lib/bidding/detail/service.ts | 30 | ||||
| -rw-r--r-- | lib/bidding/detail/table/bidding-invitation-dialog.tsx | 2 | ||||
| -rw-r--r-- | lib/bidding/service.ts | 2 |
4 files changed, 80 insertions, 6 deletions
diff --git a/lib/bidding/actions.ts b/lib/bidding/actions.ts index 3eadaace..df9d0dad 100644 --- a/lib/bidding/actions.ts +++ b/lib/bidding/actions.ts @@ -67,6 +67,17 @@ export async function transmitToContract(biddingId: number, userId: number) { throw new Error("낙찰된 업체가 없습니다.")
}
+ // 일반/매각 입찰의 경우 비율 합계 100% 검증
+ const contractType = biddingData.contractType
+ if (contractType === 'general' || contractType === 'sale') {
+ const totalRatio = winnerCompaniesData.reduce((sum, company) =>
+ sum + (Number(company.awardRatio) || 0), 0)
+
+ if (totalRatio !== 100) {
+ throw new Error(`일반/매각 입찰의 경우 비율 합계가 100%여야 합니다. 현재 합계: ${totalRatio}%`)
+ }
+ }
+
for (const winnerCompany of winnerCompaniesData) {
// winnerCompany에서 직접 정보 사용
const awardRatio = (Number(winnerCompany.awardRatio) || 100) / 100
@@ -116,7 +127,7 @@ export async function transmitToContract(biddingId: number, userId: number) { name: biddingData.title,
vendorId: winnerCompany.companyId,
linkedBidNumber: biddingData.biddingNumber,
- contractAmount: totalContractAmount || null, // 발주비율 계산된 최종 금액 사용
+ contractAmount: totalContractAmount ? totalContractAmount.toString() as any : null, // 발주비율 계산된 최종 금액 사용
startDate: biddingData.contractStartDate || null,
endDate: biddingData.contractEndDate || null,
currency: biddingData.currency || 'KRW',
@@ -154,7 +165,7 @@ export async function transmitToContract(biddingId: number, userId: number) { weightUnit: '', // 중량 단위 제외
contractDeliveryDate: bid.proposedDeliveryDate || null,
contractUnitPrice: bid.bidUnitPrice || null,
- contractAmount: finalAmount || null,
+ contractAmount: finalAmount ? finalAmount.toString() as any : null,
contractCurrency: bid.currency || biddingData.currency || 'KRW',
})
}
@@ -221,6 +232,17 @@ export async function transmitToPO(biddingId: number) { throw new Error("낙찰된 업체가 없습니다.")
}
+ // 일반/매각 입찰의 경우 비율 합계 100% 검증
+ const contractType = bidding.contractType
+ if (contractType === 'general' || contractType === 'sale') {
+ const totalRatio = winnerCompaniesRaw.reduce((sum, company) =>
+ sum + (Number(company.awardRatio) || 0), 0)
+
+ if (totalRatio !== 100) {
+ throw new Error(`일반/매각 입찰의 경우 비율 합계가 100%여야 합니다. 현재 합계: ${totalRatio}%`)
+ }
+ }
+
// 4. 낙찰된 업체들의 입찰 데이터 조회 (발주비율 적용)
type POItem = {
prItemId: number
@@ -339,7 +361,19 @@ export async function transmitToPO(biddingId: number) { // 낙찰된 업체들의 상세 정보 조회 (발주비율에 따른 계산 포함)
export async function getWinnerDetails(biddingId: number) {
try {
- // 1. 낙찰된 업체들 조회
+ // 1. 입찰 정보 조회 (contractType 포함)
+ const biddingInfo = await db.select({
+ contractType: biddings.contractType,
+ })
+ .from(biddings)
+ .where(eq(biddings.id, biddingId))
+ .limit(1)
+
+ if (!biddingInfo || biddingInfo.length === 0) {
+ return { success: false, error: '입찰 정보를 찾을 수 없습니다.' }
+ }
+
+ // 2. 낙찰된 업체들 조회
const winnerCompanies = await db.select({
id: biddingCompanies.id,
companyId: biddingCompanies.companyId,
@@ -347,6 +381,7 @@ export async function getWinnerDetails(biddingId: number) { awardRatio: biddingCompanies.awardRatio,
vendorName: vendors.vendorName,
vendorCode: vendors.vendorCode,
+ contractType: biddingInfo[0].contractType,
})
.from(biddingCompanies)
.leftJoin(vendors, eq(biddingCompanies.companyId, vendors.id))
@@ -361,6 +396,17 @@ export async function getWinnerDetails(biddingId: number) { return { success: false, error: '낙찰된 업체가 없습니다.' }
}
+ // 일반/매각 입찰의 경우 비율 합계 100% 검증
+ const contractType = biddingInfo[0].contractType
+ if (contractType === 'general' || contractType === 'sale') {
+ const totalRatio = winnerCompanies.reduce((sum, company) =>
+ sum + (Number(company.awardRatio) || 0), 0)
+
+ if (totalRatio !== 100) {
+ return { success: false, error: `일반/매각 입찰의 경우 비율 합계가 100%여야 합니다. 현재 합계: ${totalRatio}%` }
+ }
+ }
+
// 2. 각 낙찰 업체의 입찰 품목 정보 조회
const winnerDetails = []
diff --git a/lib/bidding/detail/service.ts b/lib/bidding/detail/service.ts index 9fb3d87f..645ebeac 100644 --- a/lib/bidding/detail/service.ts +++ b/lib/bidding/detail/service.ts @@ -1158,6 +1158,23 @@ export async function deleteAwardDocument(documentId: number, biddingId: number, export async function awardBidding(biddingId: number, selectionReason: string, userId: string) { try { const userName = await getUserNameById(userId) + + // 입찰 정보 조회 (contractType 포함) + const biddingInfo = await db + .select({ + contractType: biddings.contractType, + status: biddings.status + }) + .from(biddings) + .where(eq(biddings.id, biddingId)) + .limit(1) + + if (biddingInfo.length === 0) { + return { success: false, error: '입찰 정보를 찾을 수 없습니다.' } + } + + const bidding = biddingInfo[0] + // 낙찰된 업체들 조회 (isWinner가 true인 업체들) const awardedCompanies = await db .select({ @@ -1170,11 +1187,22 @@ export async function awardBidding(biddingId: number, selectionReason: string, u eq(biddingCompanies.biddingId, biddingId), eq(biddingCompanies.isWinner, true) )) - + if (awardedCompanies.length === 0) { return { success: false, error: '낙찰된 업체가 없습니다. 먼저 발주비율을 산정해주세요.' } } + // 일반/매각 입찰의 경우 비율 합계 100% 검증 + const contractType = bidding.contractType + if (contractType === 'general' || contractType === 'sale') { + const totalRatio = awardedCompanies.reduce((sum, company) => + sum + (Number(company.awardRatio) || 0), 0) + + if (totalRatio !== 100) { + return { success: false, error: `일반/매각 입찰의 경우 비율 합계가 100%여야 합니다. 현재 합계: ${totalRatio}%` } + } + } + // 최종입찰가 계산 (낙찰된 업체의 견적금액 * 발주비율의 합) let finalBidPrice = 0 for (const company of awardedCompanies) { diff --git a/lib/bidding/detail/table/bidding-invitation-dialog.tsx b/lib/bidding/detail/table/bidding-invitation-dialog.tsx index 48b235f9..cd79850a 100644 --- a/lib/bidding/detail/table/bidding-invitation-dialog.tsx +++ b/lib/bidding/detail/table/bidding-invitation-dialog.tsx @@ -666,7 +666,7 @@ export function BiddingInvitationDialog({ {isGeneratingPdfs ? ( <> <RefreshCw className="w-4 h-4 mr-2 animate-spin" /> - 계약서 생성중... ({Math.round(pdfGenerationProgress)}%) + 입찰 초대중... ({Math.round(pdfGenerationProgress)}%) </> ) : isPending ? ( <> diff --git a/lib/bidding/service.ts b/lib/bidding/service.ts index 89e4f80f..68efe165 100644 --- a/lib/bidding/service.ts +++ b/lib/bidding/service.ts @@ -420,7 +420,7 @@ export interface UpdateBiddingInput extends UpdateBiddingSchema { } // 자동 입찰번호 생성 -async function generateBiddingNumber( +export async function generateBiddingNumber( userId?: string, tx?: any, maxRetries: number = 5 |
