From 088a161f8852dd7566619baca93257c0ccd901b7 Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Thu, 20 Nov 2025 02:38:04 +0000
Subject: (최겸) 구매 입찰 제출기간 수정
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../bidding/manage/bidding-schedule-editor.tsx     | 95 ++++++++++++++++------
 1 file changed, 72 insertions(+), 23 deletions(-)

(limited to 'components/bidding/manage/bidding-schedule-editor.tsx')

diff --git a/components/bidding/manage/bidding-schedule-editor.tsx b/components/bidding/manage/bidding-schedule-editor.tsx
index f2978f95..f3260f04 100644
--- a/components/bidding/manage/bidding-schedule-editor.tsx
+++ b/components/bidding/manage/bidding-schedule-editor.tsx
@@ -19,7 +19,7 @@ import { BiddingInvitationDialog } from '@/lib/bidding/detail/table/bidding-invi
 import { sendBiddingBasicContracts, getSelectedVendorsForBidding } from '@/lib/bidding/pre-quote/service'
 import { registerBidding } from '@/lib/bidding/detail/service'
 import { useToast } from '@/hooks/use-toast'
-
+import { format } from 'date-fns'
 interface BiddingSchedule {
   submissionStartDate?: string
   submissionEndDate?: string
@@ -112,7 +112,7 @@ export function BiddingScheduleEditor({ biddingId, readonly = false }: BiddingSc
   })
   const [isLoading, setIsLoading] = React.useState(false)
   const [isSubmitting, setIsSubmitting] = React.useState(false)
-  const [biddingInfo, setBiddingInfo] = React.useState<{ title: string; projectName?: string; status: string } | null>(null)
+  const [biddingInfo, setBiddingInfo] = React.useState<{ title: string; projectName?: string; status: string; biddingNumber?: string } | null>(null)
   const [isBiddingInvitationDialogOpen, setIsBiddingInvitationDialogOpen] = React.useState(false)
   const [isApprovalDialogOpen, setIsApprovalDialogOpen] = React.useState(false)
   const [selectedVendors, setSelectedVendors] = React.useState<VendorContractRequirement[]>([])
@@ -120,6 +120,19 @@ export function BiddingScheduleEditor({ biddingId, readonly = false }: BiddingSc
   const [approvalTitle, setApprovalTitle] = React.useState('')
   const [invitationData, setInvitationData] = React.useState<BiddingInvitationData | null>(null)
 
+  // 차수 추출 헬퍼 함수
+  const getRoundNumber = (biddingNumber: string): number => {
+    const match = biddingNumber.match(/-(\d+)$/)
+    return match ? parseInt(match[1]) : 1
+  }
+
+  // 차수 증가된 입찰인지 확인 (01이 아닌 경우)
+  const isRoundIncreased = (biddingNumber?: string): boolean => {
+    if (!biddingNumber) return false
+    const round = getRoundNumber(biddingNumber)
+    return round > 1
+  }
+
   // 데이터 로딩
   React.useEffect(() => {
     const loadSchedule = async () => {
@@ -132,25 +145,12 @@ export function BiddingScheduleEditor({ biddingId, readonly = false }: BiddingSc
             title: bidding.title || '',
             projectName: bidding.projectName || undefined,
             status: bidding.status || '',
+            biddingNumber: bidding.biddingNumber || undefined,
           })
 
-          // 날짜를 문자열로 변환하는 헬퍼
-          const formatDateTime = (date: unknown): string => {
-            if (!date) return ''
-            if (typeof date === 'string') {
-              // 이미 datetime-local 형식인 경우
-              if (date.includes('T')) {
-                return date.slice(0, 16)
-              }
-              return date
-            }
-            if (date instanceof Date) return date.toISOString().slice(0, 16)
-            return ''
-          }
-
           setSchedule({
-            submissionStartDate: formatDateTime(bidding.submissionStartDate),
-            submissionEndDate: formatDateTime(bidding.submissionEndDate),
+            submissionStartDate: bidding.submissionStartDate ? new Date(bidding.submissionStartDate).toISOString().slice(0, 16) : '',
+            submissionEndDate: bidding.submissionEndDate ? new Date(bidding.submissionEndDate).toISOString().slice(0, 16) : '',
             remarks: bidding.remarks || '',
             isUrgent: bidding.isUrgent || false,
             hasSpecificationMeeting: bidding.hasSpecificationMeeting || false,
@@ -286,6 +286,48 @@ export function BiddingScheduleEditor({ biddingId, readonly = false }: BiddingSc
     }
   }
 
+  // 차수 증가된 입찰의 직접 입찰공고 함수 (결재 생략)
+  const handleDirectBiddingInvitation = async (data: BiddingInvitationData, vendors: VendorContractRequirement[]) => {
+    try {
+      if (!session?.user?.id) {
+        toast({
+          title: '오류',
+          description: '사용자 정보가 없습니다.',
+          variant: 'destructive',
+        })
+        return
+      }
+
+      // 입찰 등록 (결재 생략)
+      const result = await registerBidding(biddingId, session.user.id.toString())
+
+      if (result.success) {
+        toast({
+          title: '입찰공고 완료',
+          description: '차수 증가된 입찰이 성공적으로 공고되었습니다.',
+        })
+
+        // 다이얼로그 닫기 및 페이지 새로고침
+        setIsBiddingInvitationDialogOpen(false)
+        setInvitationData(null)
+        router.refresh()
+      } else {
+        toast({
+          title: '오류',
+          description: result.error || '입찰공고 중 오류가 발생했습니다.',
+          variant: 'destructive',
+        })
+      }
+    } catch (error) {
+      console.error('직접 입찰공고 중 오류 발생:', error)
+      toast({
+        title: '오류',
+        description: '입찰공고 중 오류가 발생했습니다.',
+        variant: 'destructive',
+      })
+    }
+  }
+
   // 입찰 초대 발송 핸들러 - 결재 준비 및 결재 다이얼로그 열기
   const handleBiddingInvitationSend = async (data: BiddingInvitationData) => {
     try {
@@ -309,7 +351,14 @@ export function BiddingScheduleEditor({ biddingId, readonly = false }: BiddingSc
         return
       }
 
-      // 결재 데이터 준비 (템플릿 변수, 제목 등)
+      // 차수 증가된 입찰(02, 03 등)인지 확인
+      if (isRoundIncreased(biddingInfo?.biddingNumber)) {
+        // 차수 증가된 입찰은 결재 생략하고 바로 입찰 등록
+        await handleDirectBiddingInvitation(data, vendors)
+        return
+      }
+
+      // 일반 입찰의 경우 결재 데이터 준비 (템플릿 변수, 제목 등)
       const approvalData = await prepareBiddingApprovalData({
         biddingId,
         vendors,
@@ -435,7 +484,7 @@ export function BiddingScheduleEditor({ biddingId, readonly = false }: BiddingSc
                 <Input
                   id="submission-start"
                   type="datetime-local"
-                  value={schedule.submissionStartDate || ''}
+                  value={schedule.submissionStartDate}
                   onChange={(e) => handleScheduleChange('submissionStartDate', e.target.value)}
                 />
               </div>
@@ -444,7 +493,7 @@ export function BiddingScheduleEditor({ biddingId, readonly = false }: BiddingSc
                 <Input
                   id="submission-end"
                   type="datetime-local"
-                  value={schedule.submissionEndDate || ''}
+                  value={schedule.submissionEndDate}
                   onChange={(e) => handleScheduleChange('submissionEndDate', e.target.value)}
                 />
               </div>
@@ -613,7 +662,7 @@ export function BiddingScheduleEditor({ biddingId, readonly = false }: BiddingSc
               <span className="font-medium">입찰서 제출 기간:</span>
               <span>
                 {schedule.submissionStartDate && schedule.submissionEndDate
-                  ? `${new Date(schedule.submissionStartDate).toLocaleString('ko-KR')} ~ ${new Date(schedule.submissionEndDate).toLocaleString('ko-KR')}`
+                  ? `${format(new Date(schedule.submissionStartDate), "yyyy-MM-dd HH:mm")} ~ ${format(new Date(schedule.submissionEndDate), "yyyy-MM-dd HH:mm")}`
                   : '미설정'
                 }
               </span>
@@ -634,7 +683,7 @@ export function BiddingScheduleEditor({ biddingId, readonly = false }: BiddingSc
               <div className="flex justify-between">
                 <span className="font-medium">사양설명회 일시:</span>
                 <span>
-                  {new Date(specMeetingInfo.meetingDate).toLocaleString('ko-KR')}
+                  {format(new Date(specMeetingInfo.meetingDate), "yyyy-MM-dd HH:mm")}
                 </span>
               </div>
             )}
-- 
cgit v1.2.3

