summaryrefslogtreecommitdiff
path: root/lib/bidding/pre-quote
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-09-16 09:20:58 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-09-16 09:20:58 +0000
commit6c11fccc84f4c84fa72ee01f9caad9f76f35cea2 (patch)
treefa88d10ea7d21fe6b59ed0c1569856a73d56547a /lib/bidding/pre-quote
parent14e3990aba7e1ad1cdd0965cbd167c50230cbfbf (diff)
(대표님, 최겸) 계약, 업로드 관련, 메뉴처리, 입찰, 프리쿼트, rfqLast관련, tbeLast관련
Diffstat (limited to 'lib/bidding/pre-quote')
-rw-r--r--lib/bidding/pre-quote/service.ts60
-rw-r--r--lib/bidding/pre-quote/table/bidding-pre-quote-vendor-create-dialog.tsx4
2 files changed, 37 insertions, 27 deletions
diff --git a/lib/bidding/pre-quote/service.ts b/lib/bidding/pre-quote/service.ts
index 7f054a66..cad77a6b 100644
--- a/lib/bidding/pre-quote/service.ts
+++ b/lib/bidding/pre-quote/service.ts
@@ -6,12 +6,12 @@ import { basicContractTemplates } from '@/db/schema'
import { vendors } from '@/db/schema/vendors'
import { users } from '@/db/schema'
import { sendEmail } from '@/lib/mail/sendEmail'
-import { eq, inArray, and, ilike } from 'drizzle-orm'
+import { eq, inArray, and, ilike, sql } from 'drizzle-orm'
import { mkdir, writeFile } from 'fs/promises'
import path from 'path'
import { revalidateTag, revalidatePath } from 'next/cache'
import { basicContract } from '@/db/schema/basicContractDocumnet'
-import { saveFile ,saveBuffer} from '@/lib/file-stroage'
+import { saveFile } from '@/lib/file-stroage'
// userId를 user.name으로 변환하는 유틸리티 함수
async function getUserNameById(userId: string): Promise<string> {
@@ -69,6 +69,15 @@ interface PreQuoteDocumentUpload {
export async function createBiddingCompany(input: CreateBiddingCompanyInput) {
try {
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,
@@ -1225,7 +1234,10 @@ export async function sendBiddingBasicContracts(
const results = []
const savedContracts = []
- // 트랜잭션 시작 - contractsDir 제거 (saveBuffer가 처리)
+ // 트랜잭션 시작
+ const contractsDir = path.join(process.cwd(), `${process.env.NAS_PATH}`, "contracts", "generated");
+ await mkdir(contractsDir, { recursive: true });
+
const result = await db.transaction(async (tx) => {
// 각 벤더별로 기본계약 생성 및 이메일 발송
for (const vendor of vendorData) {
@@ -1285,7 +1297,6 @@ export async function sendBiddingBasicContracts(
if (vendor.contractRequirements.projectGtcYn) contractTypes.push({ type: 'Project_GTC', templateName: '기술' })
if (vendor.contractRequirements.agreementYn) contractTypes.push({ type: '기술자료', templateName: '기술자료' })
console.log("contractTypes", contractTypes)
-
for (const contractType of contractTypes) {
// PDF 데이터 찾기 (include를 사용하여 유연하게 찾기)
console.log("generatedPdfs", generatedPdfs.map(pdf => pdf.key))
@@ -1299,22 +1310,11 @@ export async function sendBiddingBasicContracts(
continue
}
- // 파일 저장 - saveBuffer 사용
+ // 파일 저장 (rfq-last 방식)
const fileName = `${contractType.type}_${vendor.vendorCode || vendor.vendorId}_${vendor.biddingCompanyId}_${Date.now()}.pdf`
-
- const saveResult = await saveBuffer({
- buffer: Buffer.from(pdfData.buffer),
- fileName: fileName,
- directory: 'contracts/generated',
- originalName: fileName,
- userId: currentUser.id
- })
+ const filePath = path.join(contractsDir, fileName);
- // 저장 실패 시 처리
- if (!saveResult.success) {
- console.error(`PDF 저장 실패: ${saveResult.error}`)
- continue
- }
+ await writeFile(filePath, Buffer.from(pdfData.buffer));
// 템플릿 정보 조회 (rfq-last 방식)
const [template] = await db
@@ -1352,8 +1352,8 @@ export async function sendBiddingBasicContracts(
.set({
requestedBy: currentUser.id,
status: "PENDING", // 재발송 상태
- fileName: saveResult.originalName || fileName, // 원본 파일명
- filePath: saveResult.publicPath, // saveBuffer가 반환한 공개 경로
+ fileName: fileName,
+ filePath: `/contracts/generated/${fileName}`,
deadline: new Date(Date.now() + 10 * 24 * 60 * 60 * 1000),
updatedAt: new Date(),
})
@@ -1373,8 +1373,8 @@ export async function sendBiddingBasicContracts(
generalContractId: null,
requestedBy: currentUser.id,
status: 'PENDING',
- fileName: saveResult.originalName || fileName, // 원본 파일명
- filePath: saveResult.publicPath, // saveBuffer가 반환한 공개 경로
+ fileName: fileName,
+ filePath: `/contracts/generated/${fileName}`,
deadline: new Date(Date.now() + 10 * 24 * 60 * 60 * 1000), // 10일 후
createdAt: new Date(),
updatedAt: new Date(),
@@ -1389,10 +1389,19 @@ export async function sendBiddingBasicContracts(
vendorName: vendor.vendorName,
contractId: contractRecord.id,
contractType: contractType.type,
- fileName: saveResult.originalName || fileName,
- filePath: saveResult.publicPath,
- hashedFileName: saveResult.fileName, // 실제 저장된 파일명 (디버깅용)
+ fileName: fileName,
+ filePath: `/contracts/generated/${fileName}`,
})
+
+ // savedContracts에 추가 (rfq-last 방식)
+ // savedContracts.push({
+ // vendorId: vendor.vendorId,
+ // vendorName: vendor.vendorName,
+ // templateName: contractType.templateName,
+ // contractId: contractRecord.id,
+ // fileName: fileName,
+ // isUpdated: !!existingContract, // 업데이트 여부 표시
+ // })
}
// 이메일 발송 (선택사항)
@@ -1439,6 +1448,7 @@ export async function sendBiddingBasicContracts(
)
}
}
+
// 기존 기본계약 조회 (서버 액션)
export async function getExistingBasicContractsForBidding(biddingId: number) {
try {
diff --git a/lib/bidding/pre-quote/table/bidding-pre-quote-vendor-create-dialog.tsx b/lib/bidding/pre-quote/table/bidding-pre-quote-vendor-create-dialog.tsx
index e2a38547..bc233e77 100644
--- a/lib/bidding/pre-quote/table/bidding-pre-quote-vendor-create-dialog.tsx
+++ b/lib/bidding/pre-quote/table/bidding-pre-quote-vendor-create-dialog.tsx
@@ -26,7 +26,7 @@ import {
import { Check, ChevronsUpDown } from 'lucide-react'
import { cn } from '@/lib/utils'
import { createBiddingCompany } from '@/lib/bidding/pre-quote/service'
-import { searchVendors } from '@/lib/vendors/service'
+import { searchVendorsForBidding } from '@/lib/bidding/service'
import { useToast } from '@/hooks/use-toast'
import { useTransition } from 'react'
@@ -69,7 +69,7 @@ export function BiddingPreQuoteVendorCreateDialog({
}
try {
- const result = await searchVendors(vendorSearchValue.trim(), 10)
+ const result = await searchVendorsForBidding(vendorSearchValue.trim(), biddingId, 10)
setVendors(result)
} catch (error) {
console.error('Vendor search failed:', error)