diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-09-17 10:40:12 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-09-17 10:40:12 +0000 |
| commit | 10cb50753ccf318024c4394282f9e8d968dcd1a5 (patch) | |
| tree | cf4edb96aa172c3b90d88532aff1f536944a2283 /lib/bidding/detail/table | |
| parent | f7117370b9cc0c7b96bd1eb23a1b9f5b16cc8ceb (diff) | |
(최겸) 구매 입찰 오류 수정 및 선적지,하역지 연동,TO Cont, TO PO 개발
Diffstat (limited to 'lib/bidding/detail/table')
3 files changed, 56 insertions, 52 deletions
diff --git a/lib/bidding/detail/table/bidding-detail-vendor-columns.tsx b/lib/bidding/detail/table/bidding-detail-vendor-columns.tsx index cbdf79c2..3b42cc88 100644 --- a/lib/bidding/detail/table/bidding-detail-vendor-columns.tsx +++ b/lib/bidding/detail/table/bidding-detail-vendor-columns.tsx @@ -142,7 +142,7 @@ export function getBiddingDetailVendorColumns({ status === 'rejected' ? 'destructive' : 'outline' const label = status === 'selected' ? '선정' : - status === 'submitted' ? '제출' : + status === 'submitted' ? '견적 제출' : status === 'rejected' ? '거절' : '대기' return <Badge variant={variant}>{label}</Badge> diff --git a/lib/bidding/detail/table/bidding-detail-vendor-toolbar-actions.tsx b/lib/bidding/detail/table/bidding-detail-vendor-toolbar-actions.tsx index 893fb185..eec44bb1 100644 --- a/lib/bidding/detail/table/bidding-detail-vendor-toolbar-actions.tsx +++ b/lib/bidding/detail/table/bidding-detail-vendor-toolbar-actions.tsx @@ -68,6 +68,14 @@ export function BiddingDetailVendorToolbarActions({ } const handleRegister = () => { + if (bidding.status !== 'set_target_price') { + toast({ + title: '오류', + description: '내정가 산정이 완료되어야 입찰 등록을 할 수 있습니다.', + variant: 'destructive', + }) + return + } // 본입찰 초대 다이얼로그 열기 setIsBiddingInvitationDialogOpen(true) } diff --git a/lib/bidding/detail/table/bidding-invitation-dialog.tsx b/lib/bidding/detail/table/bidding-invitation-dialog.tsx index 031231a1..48b235f9 100644 --- a/lib/bidding/detail/table/bidding-invitation-dialog.tsx +++ b/lib/bidding/detail/table/bidding-invitation-dialog.tsx @@ -159,7 +159,7 @@ export function BiddingInvitationDialog({ try { const [contractsResult, templatesData] = await Promise.all([ getSelectedVendorsForBidding(biddingId), - getActiveContractTemplates() + getActiveContractTemplates(), ]); // 기존 계약 조회 (사전견적에서 보낸 기본계약 확인) - 서버 액션 사용 @@ -184,7 +184,6 @@ export function BiddingInvitationDialog({ checked: false })); setSelectedContracts(initialSelected); - } catch (error) { console.error('초기 데이터 로드 실패:', error); toast({ @@ -318,36 +317,34 @@ export function BiddingInvitationDialog({ const handleSendInvitation = () => { const selectedContractTemplates = selectedContracts.filter(c => c.checked); - if (selectedContractTemplates.length === 0) { - toast({ - title: '알림', - description: '발송할 기본계약서를 선택해주세요.', - variant: 'default', - }) - return - } - startTransition(async () => { try { - // 선택된 템플릿에 따라 PDF 생성 - setIsGeneratingPdfs(true) - setPdfGenerationProgress(0) + let generatedPdfs: Array<{ + key: string + buffer: number[] + fileName: string + }> = [] const generatedPdfsMap = new Map<string, { buffer: number[], fileName: string }>() - let generatedCount = 0; - for (const vendor of selectedVendors) { - // 사전견적에서 이미 기본계약을 보낸 벤더인지 확인 - const hasExistingContract = existingContracts.some((ec: any) => - ec.vendorId === vendor.vendorId && ec.biddingCompanyId === vendor.biddingCompanyId - ); - - if (hasExistingContract) { - console.log(`벤더 ${vendor.vendorName}는 사전견적에서 이미 기본계약을 받았으므로 건너뜁니다.`); - generatedCount++; - setPdfGenerationProgress((generatedCount / selectedVendors.length) * 100); - continue; - } + // 선택된 템플릿이 있는 경우에만 PDF 생성 + if (selectedContractTemplates.length > 0) { + setIsGeneratingPdfs(true) + setPdfGenerationProgress(0) + + let generatedCount = 0; + for (const vendor of selectedVendors) { + // 사전견적에서 이미 기본계약을 보낸 벤더인지 확인 + const hasExistingContract = existingContracts.some((ec: any) => + ec.vendorId === vendor.vendorId && ec.biddingCompanyId === vendor.biddingCompanyId + ); + + if (hasExistingContract) { + console.log(`벤더 ${vendor.vendorName}는 사전견적에서 이미 기본계약을 받았으므로 건너뜁니다.`); + generatedCount++; + setPdfGenerationProgress((generatedCount / selectedVendors.length) * 100); + continue; + } for (const contract of selectedContractTemplates) { setCurrentGeneratingContract(`${vendor.vendorName} - ${contract.templateName}`); @@ -374,7 +371,16 @@ export function BiddingInvitationDialog({ setPdfGenerationProgress((generatedCount / selectedVendors.length) * 100); } - setIsGeneratingPdfs(false); + setIsGeneratingPdfs(false); + + const pdfsArray = Array.from(generatedPdfsMap.entries()).map(([key, data]) => ({ + key, + buffer: data.buffer, + fileName: data.fileName, + })); + + generatedPdfs = pdfsArray; + } const vendorData = selectedVendors.map(vendor => { const hasExistingContract = existingContracts.some((ec: any) => @@ -400,15 +406,9 @@ export function BiddingInvitationDialog({ }; }); - const pdfsArray = Array.from(generatedPdfsMap.entries()).map(([key, data]) => ({ - key, - buffer: data.buffer, - fileName: data.fileName, - })); - await onSend({ vendors: vendorData, - generatedPdfs: pdfsArray, + generatedPdfs: generatedPdfs, message: additionalMessage }); @@ -428,7 +428,7 @@ export function BiddingInvitationDialog({ return ( <Dialog open={open} onOpenChange={handleOpenChange}> - <DialogContent className="sm:max-w-[700px] max-h-[90vh] flex flex-col"> + <DialogContent className="sm:max-w-[800px] max-h-[90vh] flex flex-col" style={{width:900, maxWidth:900}}> <DialogHeader> <DialogTitle className="flex items-center gap-2"> <Mail className="w-5 h-5" /> @@ -448,7 +448,7 @@ export function BiddingInvitationDialog({ <AlertTitle className="text-orange-800">기존 계약 정보</AlertTitle> <AlertDescription className="text-orange-700"> 사전견적에서 이미 기본계약을 받은 업체가 있습니다. - 해당 업체들은 계약서 재생성을 건너뜁니다. + 해당 업체들은 계약서 재생성을 건너뜁니다. (본입찰 초대는 정상 진행됩니다) </AlertDescription> </Alert> )} @@ -494,18 +494,21 @@ export function BiddingInvitationDialog({ <div> <h4 className="text-sm font-medium text-orange-700 mb-2 flex items-center gap-2"> <X className="h-4 w-4 text-orange-600" /> - 기존 계약 존재 (건너뜀) ({vendorsWithExistingContracts.length}개) + 기존 계약 존재 (계약서 재생성 건너뜀) ({vendorsWithExistingContracts.length}개) </h4> <div className="space-y-2 max-h-32 overflow-y-auto"> {vendorsWithExistingContracts.map((vendor) => ( - <div key={vendor.vendorId} className="flex items-center gap-2 text-sm p-2 bg-orange-50 rounded border border-orange-200 opacity-75"> + <div key={vendor.vendorId} className="flex items-center gap-2 text-sm p-2 bg-orange-50 rounded border border-orange-200"> <X className="h-4 w-4 text-orange-600" /> - <span className="text-muted-foreground">{vendor.vendorName}</span> + <span className="font-medium">{vendor.vendorName}</span> <Badge variant="outline" className="text-xs"> {vendor.vendorCode} </Badge> - <Badge variant="secondary" className="text-xs"> - 계약 존재 + <Badge variant="secondary" className="text-xs bg-orange-100 text-orange-800"> + 계약 존재 (재생성 건너뜀) + </Badge> + <Badge variant="outline" className="text-xs border-green-500 text-green-700"> + 본입찰 초대 </Badge> </div> ))} @@ -522,7 +525,7 @@ export function BiddingInvitationDialog({ <CardHeader className="pb-3"> <CardTitle className="flex items-center gap-2 text-base"> <FileText className="h-5 w-5 text-blue-600" /> - 기본계약 선택 + 기본계약 선택 (선택사항) </CardTitle> </CardHeader> <CardContent className="space-y-4"> @@ -657,7 +660,7 @@ export function BiddingInvitationDialog({ </Button> <Button onClick={handleSendInvitation} - disabled={isPending || selectedContractCount === 0 || isGeneratingPdfs} + disabled={isPending || selectedVendors.length === 0 || isGeneratingPdfs} className="w-full sm:w-auto" > {isGeneratingPdfs ? ( @@ -678,13 +681,6 @@ export function BiddingInvitationDialog({ )} </Button> </div> - {/* {(selectedContractCount > 0) && ( - <div className="mt-4 sm:mt-0 text-sm text-muted-foreground"> - <p> - {selectedVendors.length}개 업체에 <strong>{selectedContractCount}개</strong>의 기본계약서를 발송합니다. - </p> - </div> - )} */} </DialogFooter> </DialogContent> </Dialog> |
