From 93b6b8868d409c7f6c9d9222b93750848caaedde Mon Sep 17 00:00:00 2001 From: dujinkim Date: Fri, 5 Dec 2025 03:28:04 +0000 Subject: (최겸) 구매 입찰 수정 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bidding/create/bidding-create-dialog.tsx | 51 ++++++++---- .../bidding/manage/bidding-basic-info-editor.tsx | 2 - .../bidding/manage/bidding-companies-editor.tsx | 17 +++- .../manage/bidding-detail-vendor-create-dialog.tsx | 15 +++- .../bidding/manage/create-pre-quote-rfq-dialog.tsx | 90 ++++++++-------------- 5 files changed, 97 insertions(+), 78 deletions(-) (limited to 'components') diff --git a/components/bidding/create/bidding-create-dialog.tsx b/components/bidding/create/bidding-create-dialog.tsx index b3972e11..af33f1f6 100644 --- a/components/bidding/create/bidding-create-dialog.tsx +++ b/components/bidding/create/bidding-create-dialog.tsx @@ -63,7 +63,7 @@ import { PurchaseGroupCodeSelector } from '@/components/common/selectors/purchas import { ProcurementManagerSelector } from '@/components/common/selectors/procurement-manager' import type { PurchaseGroupCodeWithUser } from '@/components/common/selectors/purchase-group-code/purchase-group-code-service' import type { ProcurementManagerWithUser } from '@/components/common/selectors/procurement-manager/procurement-manager-service' -import { createBidding } from '@/lib/bidding/service' +import { createBidding, getUserDetails } from '@/lib/bidding/service' import { useSession } from 'next-auth/react' import { useRouter } from 'next/navigation' @@ -97,13 +97,6 @@ export function BiddingCreateDialog({ form, onSuccess }: BiddingCreateDialogProp sparePartOptions: '', }) - // 구매요청자 정보 (현재 사용자) - // React.useEffect(() => { - // // 실제로는 현재 로그인한 사용자의 정보를 가져와야 함 - // // 임시로 기본값 설정 - // form.setValue('requesterName', '김두진') // 실제로는 API에서 가져와야 함 - // }, [form]) - const [shiAttachmentFiles, setShiAttachmentFiles] = React.useState([]) const [vendorAttachmentFiles, setVendorAttachmentFiles] = React.useState([]) @@ -164,13 +157,41 @@ export function BiddingCreateDialog({ form, onSuccess }: BiddingCreateDialogProp React.useEffect(() => { if (isOpen) { - if (userId && session?.user?.name) { - // 현재 사용자의 정보를 임시로 입찰담당자로 설정 - form.setValue('bidPicName', session.user.name) - form.setValue('bidPicId', userId) - // userCode는 현재 세션에 없으므로 이름으로 설정 (실제로는 API에서 가져와야 함) - // form.setValue('bidPicCode', session.user.name) + const initUser = async () => { + if (userId) { + try { + const user = await getUserDetails(userId) + if (user) { + // 현재 사용자의 정보를 입찰담당자로 설정 + form.setValue('bidPicName', user.name) + form.setValue('bidPicId', user.id) + form.setValue('bidPicCode', user.userCode || '') + + // 담당자 selector 상태 업데이트 + setSelectedBidPic({ + PURCHASE_GROUP_CODE: user.userCode || '', + DISPLAY_NAME: user.name, + EMPLOYEE_NUMBER: user.employeeNumber || '', + user: { + id: user.id, + name: user.name, + email: '', + employeeNumber: user.employeeNumber + } + } as any) + } + } catch (error) { + console.error('Failed to fetch user details:', error) + // 실패 시 세션 정보로 폴백 + if (session?.user?.name) { + form.setValue('bidPicName', session.user.name) + form.setValue('bidPicId', userId) + } + } + } } + initUser() + loadPaymentTerms() loadIncoterms() loadShippingPlaces() @@ -181,7 +202,7 @@ export function BiddingCreateDialog({ form, onSuccess }: BiddingCreateDialogProp form.setValue('biddingConditions.taxConditions', 'V1') } } - }, [isOpen, loadPaymentTerms, loadIncoterms, loadShippingPlaces, loadDestinationPlaces, form]) + }, [isOpen, userId, session, form, loadPaymentTerms, loadIncoterms, loadShippingPlaces, loadDestinationPlaces]) // SHI용 파일 첨부 핸들러 const handleShiFileUpload = (event: React.ChangeEvent) => { diff --git a/components/bidding/manage/bidding-basic-info-editor.tsx b/components/bidding/manage/bidding-basic-info-editor.tsx index 27a2c097..13c58311 100644 --- a/components/bidding/manage/bidding-basic-info-editor.tsx +++ b/components/bidding/manage/bidding-basic-info-editor.tsx @@ -88,7 +88,6 @@ interface BiddingBasicInfo { contractEndDate?: string submissionStartDate?: string submissionEndDate?: string - evaluationDate?: string hasSpecificationMeeting?: boolean hasPrDocument?: boolean currency?: string @@ -252,7 +251,6 @@ export function BiddingBasicInfoEditor({ biddingId, readonly = false }: BiddingB contractEndDate: formatDate(bidding.contractEndDate), submissionStartDate: formatDateTime(bidding.submissionStartDate), submissionEndDate: formatDateTime(bidding.submissionEndDate), - evaluationDate: formatDateTime(bidding.evaluationDate), hasSpecificationMeeting: bidding.hasSpecificationMeeting || false, hasPrDocument: bidding.hasPrDocument || false, currency: bidding.currency || 'KRW', diff --git a/components/bidding/manage/bidding-companies-editor.tsx b/components/bidding/manage/bidding-companies-editor.tsx index 4c3e6bbc..9bfea90e 100644 --- a/components/bidding/manage/bidding-companies-editor.tsx +++ b/components/bidding/manage/bidding-companies-editor.tsx @@ -566,7 +566,22 @@ export function BiddingCompaniesEditor({ biddingId, readonly = false }: BiddingC {vendor.vendorName} {vendor.vendorCode} - {vendor.businessSize || '-'} + + {(() => { + switch (vendor.businessSize) { + case 'A': + return '대기업'; + case 'B': + return '중견기업'; + case 'C': + return '중소기업'; + case 'D': + return '소기업'; + default: + return '-'; + } + })()} + {vendor.companyId && vendorFirstContacts.has(vendor.companyId) ? vendorFirstContacts.get(vendor.companyId)!.contactName diff --git a/components/bidding/manage/bidding-detail-vendor-create-dialog.tsx b/components/bidding/manage/bidding-detail-vendor-create-dialog.tsx index 0dd9f0eb..489f104d 100644 --- a/components/bidding/manage/bidding-detail-vendor-create-dialog.tsx +++ b/components/bidding/manage/bidding-detail-vendor-create-dialog.tsx @@ -408,7 +408,20 @@ export function BiddingDetailVendorCreateDialog({ 연동제 적용요건 문의 - 기업규모: {businessSizeMap[item.vendor.id] || '미정'} + 기업규모: {(() => { + switch (businessSizeMap[item.vendor.id]) { + case 'A': + return '대기업'; + case 'B': + return '중견기업'; + case 'C': + return '중소기업'; + case 'D': + return '소기업'; + default: + return '-'; + } + })()} diff --git a/components/bidding/manage/create-pre-quote-rfq-dialog.tsx b/components/bidding/manage/create-pre-quote-rfq-dialog.tsx index 1ab7a40f..b0cecc25 100644 --- a/components/bidding/manage/create-pre-quote-rfq-dialog.tsx +++ b/components/bidding/manage/create-pre-quote-rfq-dialog.tsx @@ -26,13 +26,6 @@ import { FormMessage, FormDescription, } from "@/components/ui/form" -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select" import { Input } from "@/components/ui/input" import { Textarea } from "@/components/ui/textarea" import { @@ -41,20 +34,15 @@ import { PopoverTrigger, } from "@/components/ui/popover" import { Calendar } from "@/components/ui/calendar" -import { Badge } from "@/components/ui/badge" import { cn } from "@/lib/utils" import { toast } from "sonner" import { ScrollArea } from "@/components/ui/scroll-area" import { Separator } from "@/components/ui/separator" import { createPreQuoteRfqAction } from "@/lib/bidding/pre-quote/service" -import { previewGeneralRfqCode } from "@/lib/rfq-last/service" -import { MaterialGroupSelectorDialogSingle } from "@/components/common/material/material-group-selector-dialog-single" -import { MaterialSearchItem } from "@/lib/material/material-group-service" -import { MaterialSelectorDialogSingle } from "@/components/common/selectors/material/material-selector-dialog-single" -import { MaterialSearchItem as SAPMaterialSearchItem } from "@/components/common/selectors/material/material-service" import { PurchaseGroupCodeSelector } from "@/components/common/selectors/purchase-group-code/purchase-group-code-selector" import type { PurchaseGroupCodeWithUser } from "@/components/common/selectors/purchase-group-code" import { getBiddingById } from "@/lib/bidding/service" +import { getProjectIdByCodeAndName } from "@/lib/bidding/manage/project-utils" // 아이템 스키마 const itemSchema = z.object({ @@ -64,6 +52,8 @@ const itemSchema = z.object({ materialName: z.string().optional(), quantity: z.number().min(1, "수량은 1 이상이어야 합니다"), uom: z.string().min(1, "단위를 입력해주세요"), + totalWeight: z.union([z.number(), z.string(), z.null()]).optional(), // 중량 추가 + weightUnit: z.string().optional().nullable(), // 중량단위 추가 remark: z.string().optional(), }) @@ -125,8 +115,6 @@ export function CreatePreQuoteRfqDialog({ onSuccess }: CreatePreQuoteRfqDialogProps) { const [isLoading, setIsLoading] = React.useState(false) - const [previewCode, setPreviewCode] = React.useState("") - const [isLoadingPreview, setIsLoadingPreview] = React.useState(false) const [selectedBidPic, setSelectedBidPic] = React.useState(undefined) const { data: session } = useSession() @@ -143,6 +131,8 @@ export function CreatePreQuoteRfqDialog({ materialName: item.materialInfo || "", quantity: item.quantity ? parseFloat(item.quantity) : 1, uom: item.quantityUnit || item.weightUnit || "EA", + totalWeight: item.totalWeight ? parseFloat(item.totalWeight) : null, + weightUnit: item.weightUnit || null, remark: "", })) }, [biddingItems]) @@ -164,6 +154,8 @@ export function CreatePreQuoteRfqDialog({ materialName: "", quantity: 1, uom: "", + totalWeight: null, + weightUnit: null, remark: "", }, ], @@ -231,6 +223,14 @@ export function CreatePreQuoteRfqDialog({ const pName = bidding.projectName || ""; setProjectInfo(pCode && pName ? `${pCode} - ${pName}` : pCode || pName || ""); + // 프로젝트 ID 조회 + if (pCode && pName) { + const fetchedProjectId = await getProjectIdByCodeAndName(pCode, pName) + if (fetchedProjectId) { + form.setValue("projectId", fetchedProjectId) + } + } + // 폼 값 설정 form.setValue("rfqTitle", rfqTitle); form.setValue("rfqType", "pre_bidding"); // 기본값 설정 @@ -264,36 +264,15 @@ export function CreatePreQuoteRfqDialog({ materialName: "", quantity: 1, uom: "", + totalWeight: null, + weightUnit: null, remark: "", }, ], }) - setPreviewCode("") } }, [open, initialItems, form, selectedBidPic, biddingId]) - // 견적담당자 선택 시 RFQ 코드 미리보기 생성 - React.useEffect(() => { - if (!selectedBidPic?.user?.id) { - setPreviewCode("") - return - } - - // 즉시 실행 함수 패턴 사용 - (async () => { - setIsLoadingPreview(true) - try { - const code = await previewGeneralRfqCode(selectedBidPic.user!.id) - setPreviewCode(code) - } catch (error) { - console.error("코드 미리보기 오류:", error) - setPreviewCode("") - } finally { - setIsLoadingPreview(false) - } - })() - }, [selectedBidPic]) - // 견적 종류 변경 const handleRfqTypeChange = (value: string) => { form.setValue("rfqType", value) @@ -315,12 +294,13 @@ export function CreatePreQuoteRfqDialog({ materialName: "", quantity: 1, uom: "", + totalWeight: null, + weightUnit: null, remark: "", }, ], }) setSelectedBidPic(undefined) - setPreviewCode("") onOpenChange(false) } @@ -350,15 +330,17 @@ export function CreatePreQuoteRfqDialog({ biddingNumber: data.biddingNumber, // 추가 contractStartDate: data.contractStartDate, // 추가 contractEndDate: data.contractEndDate, // 추가 - items: data.items as Array<{ - itemCode: string; - itemName: string; - materialCode?: string; - materialName?: string; - quantity: number; - uom: string; - remark?: string; - }>, + items: data.items.map(item => ({ + itemCode: item.itemCode || "", + itemName: item.itemName || "", + materialCode: item.materialCode, + materialName: item.materialName, + quantity: item.quantity, + uom: item.uom, + totalWeight: item.totalWeight, + weightUnit: item.weightUnit, + remark: item.remark, + })), biddingConditions: biddingConditions || undefined, createdBy: userId, updatedBy: userId, @@ -590,17 +572,7 @@ export function CreatePreQuoteRfqDialog({ )} /> - {/* RFQ 코드 미리보기 */} - {previewCode && ( -
- - 예상 RFQ 코드: {previewCode} - - {isLoadingPreview && ( - - )} -
- )} + {/* 계약기간 */}
-- cgit v1.2.3