summaryrefslogtreecommitdiff
path: root/lib/bidding/detail/service.ts
diff options
context:
space:
mode:
Diffstat (limited to 'lib/bidding/detail/service.ts')
-rw-r--r--lib/bidding/detail/service.ts234
1 files changed, 233 insertions, 1 deletions
diff --git a/lib/bidding/detail/service.ts b/lib/bidding/detail/service.ts
index 025b9eac..92be2eee 100644
--- a/lib/bidding/detail/service.ts
+++ b/lib/bidding/detail/service.ts
@@ -1701,6 +1701,7 @@ export interface PartnersBiddingListItem {
managerPhone: string | null
currency: string
budget: number | null
+ isUrgent: boolean | null // 긴급여부
// 계산된 필드
responseDeadline: Date | null // 참여회신 마감일 (submissionStartDate 전 3일)
@@ -1747,6 +1748,7 @@ export async function getBiddingListForPartners(companyId: number): Promise<Part
managerPhone: biddings.managerPhone,
currency: biddings.currency,
budget: biddings.budget,
+ isUrgent: biddings.isUrgent,
hasSpecificationMeeting: biddings.hasSpecificationMeeting,
})
.from(biddingCompanies)
@@ -1814,6 +1816,7 @@ export async function getBiddingDetailsForPartners(biddingId: number, companyId:
// 상태 및 담당자
status: biddings.status,
+ isUrgent: biddings.isUrgent,
managerName: biddings.managerName,
managerEmail: biddings.managerEmail,
managerPhone: biddings.managerPhone,
@@ -2278,7 +2281,7 @@ export async function getPriceAdjustmentForm(companyConditionResponseId: number)
}
}
-// 입찰업체 ID로 연동제 정보 조회
+// 입찰업체 ID로 연동제 정보 조회
export async function getPriceAdjustmentFormByBiddingCompanyId(biddingCompanyId: number) {
try {
const result = await db
@@ -2297,3 +2300,232 @@ export async function getPriceAdjustmentFormByBiddingCompanyId(biddingCompanyId:
return null
}
}
+
+// =================================================
+// 입찰 문서 관리 함수들 (발주처 문서용)
+// =================================================
+
+// 입찰 문서 업로드 (발주처 문서용 - companyId: null)
+export async function uploadBiddingDocument(
+ biddingId: number,
+ file: File,
+ documentType: string,
+ title: string,
+ description: string,
+ userId: string
+) {
+ try {
+ const userName = await getUserNameById(userId)
+
+ // 파일 저장
+ const saveResult = await saveFile({
+ file,
+ directory: `bidding/${biddingId}/documents`,
+ originalName: file.name,
+ userId
+ })
+
+ if (!saveResult.success) {
+ return {
+ success: false,
+ error: saveResult.error || '파일 저장에 실패했습니다.'
+ }
+ }
+
+ // 데이터베이스에 문서 정보 저장 (companyId는 null로 설정)
+ const result = await db.insert(biddingDocuments)
+ .values({
+ biddingId,
+ companyId: null, // 발주처 문서
+ documentType: documentType as any,
+ fileName: saveResult.fileName!,
+ originalFileName: file.name,
+ fileSize: file.size,
+ mimeType: file.type,
+ filePath: saveResult.publicPath!, // publicPath 사용 (웹 접근 가능한 경로)
+ title,
+ description,
+ isPublic: true, // 발주처 문서는 기본적으로 공개
+ isRequired: false,
+ uploadedBy: userName,
+ uploadedAt: new Date()
+ })
+ .returning()
+
+ // 캐시 무효화
+ revalidateTag(`bidding-${biddingId}`)
+ revalidateTag('bidding-documents')
+
+ return {
+ success: true,
+ message: '문서가 성공적으로 업로드되었습니다.',
+ documentId: result[0].id
+ }
+ } catch (error) {
+ console.error('Failed to upload bidding document:', error)
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : '문서 업로드에 실패했습니다.'
+ }
+ }
+}
+
+// 업로드된 입찰 문서 목록 조회 (발주처 문서용)
+export async function getBiddingDocuments(biddingId: number) {
+ try {
+ const documents = await db
+ .select({
+ id: biddingDocuments.id,
+ biddingId: biddingDocuments.biddingId,
+ companyId: biddingDocuments.companyId,
+ documentType: biddingDocuments.documentType,
+ fileName: biddingDocuments.fileName,
+ originalFileName: biddingDocuments.originalFileName,
+ fileSize: biddingDocuments.fileSize,
+ filePath: biddingDocuments.filePath,
+ title: biddingDocuments.title,
+ description: biddingDocuments.description,
+ uploadedAt: biddingDocuments.uploadedAt,
+ uploadedBy: biddingDocuments.uploadedBy
+ })
+ .from(biddingDocuments)
+ .where(
+ and(
+ eq(biddingDocuments.biddingId, biddingId),
+ sql`${biddingDocuments.companyId} IS NULL` // 발주처 문서만
+ )
+ )
+ .orderBy(desc(biddingDocuments.uploadedAt))
+
+ return documents
+ } catch (error) {
+ console.error('Failed to get bidding documents:', error)
+ return []
+ }
+}
+
+// 입찰 문서 다운로드용 정보 조회
+export async function getBiddingDocumentForDownload(documentId: number, biddingId: number) {
+ try {
+ const documents = await db
+ .select()
+ .from(biddingDocuments)
+ .where(
+ and(
+ eq(biddingDocuments.id, documentId),
+ eq(biddingDocuments.biddingId, biddingId),
+ sql`${biddingDocuments.companyId} IS NULL` // 발주처 문서만
+ )
+ )
+ .limit(1)
+
+ if (documents.length === 0) {
+ return {
+ success: false,
+ error: '문서를 찾을 수 없습니다.'
+ }
+ }
+
+ return {
+ success: true,
+ document: documents[0]
+ }
+ } catch (error) {
+ console.error('Failed to get bidding document for download:', error)
+ return {
+ success: false,
+ error: '문서 다운로드 준비에 실패했습니다.'
+ }
+ }
+}
+
+// 입찰 문서 삭제 (발주처 문서용)
+export async function deleteBiddingDocument(documentId: number, biddingId: number, userId: string) {
+ try {
+ const userName = await getUserNameById(userId)
+
+ // 문서 정보 조회 (업로더 확인)
+ const documents = await db
+ .select()
+ .from(biddingDocuments)
+ .where(
+ and(
+ eq(biddingDocuments.id, documentId),
+ eq(biddingDocuments.biddingId, biddingId),
+ sql`${biddingDocuments.companyId} IS NULL`, // 발주처 문서만
+ eq(biddingDocuments.uploadedBy, userName)
+ )
+ )
+ .limit(1)
+
+ if (documents.length === 0) {
+ return {
+ success: false,
+ error: '삭제할 수 있는 문서가 없습니다.'
+ }
+ }
+
+ // DB에서 삭제
+ await db
+ .delete(biddingDocuments)
+ .where(eq(biddingDocuments.id, documentId))
+
+ // 캐시 무효화
+ revalidateTag(`bidding-${biddingId}`)
+ revalidateTag('bidding-documents')
+
+ return {
+ success: true,
+ message: '문서가 성공적으로 삭제되었습니다.'
+ }
+ } catch (error) {
+ console.error('Failed to delete bidding document:', error)
+ return {
+ success: false,
+ error: '문서 삭제에 실패했습니다.'
+ }
+ }
+}
+
+// 협력업체용 발주처 문서 조회 (캐시 적용)
+export async function getBiddingDocumentsForPartners(biddingId: number) {
+ return unstable_cache(
+ async () => {
+ try {
+ const documents = await db
+ .select({
+ id: biddingDocuments.id,
+ biddingId: biddingDocuments.biddingId,
+ companyId: biddingDocuments.companyId,
+ documentType: biddingDocuments.documentType,
+ fileName: biddingDocuments.fileName,
+ originalFileName: biddingDocuments.originalFileName,
+ fileSize: biddingDocuments.fileSize,
+ filePath: biddingDocuments.filePath,
+ title: biddingDocuments.title,
+ description: biddingDocuments.description,
+ uploadedAt: biddingDocuments.uploadedAt,
+ uploadedBy: biddingDocuments.uploadedBy
+ })
+ .from(biddingDocuments)
+ .where(
+ and(
+ eq(biddingDocuments.biddingId, biddingId),
+ sql`${biddingDocuments.companyId} IS NULL`, // 발주처 문서만
+ eq(biddingDocuments.isPublic, true) // 공개 문서만
+ )
+ )
+ .orderBy(desc(biddingDocuments.uploadedAt))
+
+ return documents
+ } catch (error) {
+ console.error('Failed to get bidding documents for partners:', error)
+ return []
+ }
+ },
+ [`bidding-documents-partners-${biddingId}`],
+ {
+ tags: [`bidding-${biddingId}`, 'bidding-documents']
+ }
+ )()
+}