summaryrefslogtreecommitdiff
path: root/components/bidding/manage
diff options
context:
space:
mode:
Diffstat (limited to 'components/bidding/manage')
-rw-r--r--components/bidding/manage/bidding-basic-info-editor.tsx39
-rw-r--r--components/bidding/manage/bidding-items-editor.tsx204
-rw-r--r--components/bidding/manage/create-pre-quote-rfq-dialog.tsx2
3 files changed, 165 insertions, 80 deletions
diff --git a/components/bidding/manage/bidding-basic-info-editor.tsx b/components/bidding/manage/bidding-basic-info-editor.tsx
index d60c5d88..a956d73c 100644
--- a/components/bidding/manage/bidding-basic-info-editor.tsx
+++ b/components/bidding/manage/bidding-basic-info-editor.tsx
@@ -26,8 +26,9 @@ import { Textarea } from '@/components/ui/textarea'
import { Switch } from '@/components/ui/switch'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
// CreateBiddingInput 타입 정의가 없으므로 CreateBiddingSchema를 확장하여 사용합니다.
-import { getBiddingById, updateBiddingBasicInfo, getBiddingConditions, getBiddingNotice, updateBiddingConditions } from '@/lib/bidding/service'
-import { getBiddingNoticeTemplate } from '@/lib/bidding/service'
+import { getBiddingById, updateBiddingBasicInfo, getBiddingConditions, getBiddingNotice, updateBiddingConditions, getBiddingNoticeTemplate } from '@/lib/bidding/service'
+import { getPurchaseGroupCodes } from '@/components/common/selectors/purchase-group-code'
+import { getProcurementManagers } from '@/components/common/selectors/procurement-manager'
import {
getIncotermsForSelection,
getPaymentTermsForSelection,
@@ -39,8 +40,8 @@ import { contractTypeLabels, biddingTypeLabels, awardCountLabels, biddingNoticeT
import TiptapEditor from '@/components/qna/tiptap-editor'
import { PurchaseGroupCodeSelector } from '@/components/common/selectors/purchase-group-code'
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 type { PurchaseGroupCodeWithUser } from '@/components/common/selectors/purchase-group-code'
+import type { ProcurementManagerWithUser } from '@/components/common/selectors/procurement-manager'
import { getBiddingDocuments, uploadBiddingDocument, deleteBiddingDocument } from '@/lib/bidding/detail/service'
import { downloadFile } from '@/lib/file-download'
@@ -259,7 +260,7 @@ export function BiddingBasicInfoEditor({ biddingId }: BiddingBasicInfoEditorProp
}
// Procurement 데이터 로드
- const [paymentTermsData, incotermsData, shippingData, destinationData] = await Promise.all([
+ const [paymentTermsData, incotermsData, shippingData, destinationData, purchaseGroupCodes, procurementManagers] = await Promise.all([
getPaymentTermsForSelection().catch(() => []),
getIncotermsForSelection().catch(() => []),
getPlaceOfShippingForSelection().catch(() => []),
@@ -269,6 +270,34 @@ export function BiddingBasicInfoEditor({ biddingId }: BiddingBasicInfoEditorProp
setIncotermsOptions(incotermsData)
setShippingPlaces(shippingData)
setDestinationPlaces(destinationData)
+ setSelectedBidPic({
+ DISPLAY_NAME: bidding.bidPicName || '',
+ PURCHASE_GROUP_CODE: bidding.bidPicCode || '',
+ user: {
+ id: bidding.bidPicUserId || undefined,
+ }
+ })
+ setSelectedSupplyPic({
+ DISPLAY_NAME: bidding.supplyPicName || '',
+ PROCUREMENT_MANAGER_CODE: bidding.supplyPicCode || '',
+ user: {
+ id: bidding.supplyPicUserId || undefined,
+ }
+ })
+ // // 입찰담당자 및 조달담당자 초기 선택값 설정
+ // if (bidding.bidPicCode && purchaseGroupCodes.length > 0) {
+ // const selectedBidPicData = purchaseGroupCodes.find(code => code.PURCHASE_GROUP_CODE === bidding.bidPicCode)
+ // if (selectedBidPicData) {
+
+ // }
+ // }
+
+ // if (bidding.supplyPicCode && procurementManagers.length > 0) {
+ // const selectedSupplyPicData = procurementManagers.find(manager => manager.PROCUREMENT_MANAGER_CODE === bidding.supplyPicCode)
+ // if (selectedSupplyPicData) {
+
+ // }
+ // }
// 공고 템플릿 로드
await loadNoticeTemplate(biddingExtended.noticeType || undefined)
diff --git a/components/bidding/manage/bidding-items-editor.tsx b/components/bidding/manage/bidding-items-editor.tsx
index 96a8d2ae..dc0aaeec 100644
--- a/components/bidding/manage/bidding-items-editor.tsx
+++ b/components/bidding/manage/bidding-items-editor.tsx
@@ -80,6 +80,7 @@ interface BiddingItemsEditorProps {
import { removeBiddingItem, addPRItemForBidding, getBiddingById, getBiddingConditions } from '@/lib/bidding/service'
import { CreatePreQuoteRfqDialog } from './create-pre-quote-rfq-dialog'
+import { ProcurementItemSelectorDialogSingle } from '@/components/common/selectors/procurement-item/procurement-item-selector-dialog-single'
import { Textarea } from '@/components/ui/textarea'
import { Label } from '@/components/ui/label'
@@ -100,6 +101,7 @@ export function BiddingItemsEditor({ biddingId }: BiddingItemsEditorProps) {
const [preQuoteDialogOpen, setPreQuoteDialogOpen] = React.useState(false)
const [targetPriceCalculationCriteria, setTargetPriceCalculationCriteria] = React.useState('')
const [biddingPicUserId, setBiddingPicUserId] = React.useState<number | null>(null)
+ const [biddingType, setBiddingType] = React.useState<string | null>(null)
const [biddingConditions, setBiddingConditions] = React.useState<{
paymentTerms?: string | null
taxConditions?: string | null
@@ -159,13 +161,15 @@ export function BiddingItemsEditor({ biddingId }: BiddingItemsEditorProps) {
actualAmount: item.actualAmount ? item.actualAmount.toString() : null,
actualCurrency: item.actualCurrency || 'KRW',
}))
-
+
// 첫 번째 아이템을 대표로 설정
- formattedItems[0].isRepresentative = true
-
+ if (formattedItems.length > 0) {
+ formattedItems[0].isRepresentative = true
+ }
+
setItems(formattedItems)
setDeletedItemIds(new Set()) // 삭제 목록 초기화
-
+
// 기존 품목 로드 성공 알림 (조용히 표시, 선택적)
console.log(`기존 품목 ${formattedItems.length}개를 불러왔습니다.`)
} else {
@@ -199,7 +203,9 @@ export function BiddingItemsEditor({ biddingId }: BiddingItemsEditorProps) {
])
if (bidding) {
+ console.log('📋 bidding:', bidding.biddingType)
setBiddingPicUserId(bidding.bidPicId || null)
+ setBiddingType(bidding.biddingType || null)
setTargetPriceCalculationCriteria(bidding.targetPriceCalculationCriteria || '')
}
@@ -332,52 +338,73 @@ export function BiddingItemsEditor({ biddingId }: BiddingItemsEditorProps) {
toast.success('품목 정보가 성공적으로 저장되었습니다.')
// 삭제 목록 초기화
setDeletedItemIds(new Set())
+
// 데이터 다시 로딩하여 최신 상태 반영
+ console.log('🔄 저장 후 데이터 재로드 시작 - biddingId:', biddingId)
const prItems = await getPRItemsForBidding(biddingId)
- const formattedItems: PRItemInfo[] = prItems.map((item) => ({
- id: item.id,
- prNumber: item.prNumber || null,
- projectId: item.projectId || null,
- projectInfo: item.projectInfo || null,
- shi: item.shi || null,
- quantity: item.quantity ? item.quantity.toString() : null,
- quantityUnit: item.quantityUnit || null,
- totalWeight: item.totalWeight ? item.totalWeight.toString() : null,
- weightUnit: item.weightUnit || null,
- materialDescription: item.itemInfo || null,
- hasSpecDocument: item.hasSpecDocument || false,
- requestedDeliveryDate: item.requestedDeliveryDate ? new Date(item.requestedDeliveryDate).toISOString().split('T')[0] : null,
- isRepresentative: false,
- annualUnitPrice: item.annualUnitPrice ? item.annualUnitPrice.toString() : null,
- currency: item.currency || 'KRW',
- materialGroupNumber: item.materialGroupNumber || null,
- materialGroupInfo: item.materialGroupInfo || null,
- materialNumber: item.materialNumber || null,
- materialInfo: item.materialInfo || null,
- priceUnit: item.priceUnit || null,
- purchaseUnit: item.purchaseUnit || null,
- materialWeight: item.materialWeight ? item.materialWeight.toString() : null,
- wbsCode: item.wbsCode || null,
- wbsName: item.wbsName || null,
- costCenterCode: item.costCenterCode || null,
- costCenterName: item.costCenterName || null,
- glAccountCode: item.glAccountCode || null,
- glAccountName: item.glAccountName || null,
- targetUnitPrice: item.targetUnitPrice ? item.targetUnitPrice.toString() : null,
- targetAmount: item.targetAmount ? item.targetAmount.toString() : null,
- targetCurrency: item.targetCurrency || 'KRW',
- budgetAmount: item.budgetAmount ? item.budgetAmount.toString() : null,
- budgetCurrency: item.budgetCurrency || 'KRW',
- actualAmount: item.actualAmount ? item.actualAmount.toString() : null,
- actualCurrency: item.actualCurrency || 'KRW',
- }))
-
- // 첫 번째 아이템을 대표로 설정
- if (formattedItems.length > 0) {
- formattedItems[0].isRepresentative = true
+ console.log('📦 getPRItemsForBidding 결과:', prItems)
+
+ if (prItems && prItems.length > 0) {
+ console.log('✅ 저장된 아이템 수:', prItems.length)
+ const formattedItems: PRItemInfo[] = prItems.map((item, index) => {
+ console.log(`🔍 아이템 ${index + 1}:`, {
+ id: item.id,
+ materialGroupNumber: item.materialGroupNumber,
+ materialNumber: item.materialNumber,
+ quantity: item.quantity
+ })
+ return {
+ id: item.id,
+ prNumber: item.prNumber || null,
+ projectId: item.projectId || null,
+ projectInfo: item.projectInfo || null,
+ shi: item.shi || null,
+ quantity: item.quantity ? item.quantity.toString() : null,
+ quantityUnit: item.quantityUnit || null,
+ totalWeight: item.totalWeight ? item.totalWeight.toString() : null,
+ weightUnit: item.weightUnit || null,
+ materialDescription: item.itemInfo || null,
+ hasSpecDocument: item.hasSpecDocument || false,
+ requestedDeliveryDate: item.requestedDeliveryDate ? new Date(item.requestedDeliveryDate).toISOString().split('T')[0] : null,
+ isRepresentative: false,
+ annualUnitPrice: item.annualUnitPrice ? item.annualUnitPrice.toString() : null,
+ currency: item.currency || 'KRW',
+ materialGroupNumber: item.materialGroupNumber || null,
+ materialGroupInfo: item.materialGroupInfo || null,
+ materialNumber: item.materialNumber || null,
+ materialInfo: item.materialInfo || null,
+ priceUnit: item.priceUnit || null,
+ purchaseUnit: item.purchaseUnit || null,
+ materialWeight: item.materialWeight ? item.materialWeight.toString() : null,
+ wbsCode: item.wbsCode || null,
+ wbsName: item.wbsName || null,
+ costCenterCode: item.costCenterCode || null,
+ costCenterName: item.costCenterName || null,
+ glAccountCode: item.glAccountCode || null,
+ glAccountName: item.glAccountName || null,
+ targetUnitPrice: item.targetUnitPrice ? item.targetUnitPrice.toString() : null,
+ targetAmount: item.targetAmount ? item.targetAmount.toString() : null,
+ targetCurrency: item.targetCurrency || 'KRW',
+ budgetAmount: item.budgetAmount ? item.budgetAmount.toString() : null,
+ budgetCurrency: item.budgetCurrency || 'KRW',
+ actualAmount: item.actualAmount ? item.actualAmount.toString() : null,
+ actualCurrency: item.actualCurrency || 'KRW',
+ }
+ })
+
+ // 첫 번째 아이템을 대표로 설정
+ if (formattedItems.length > 0) {
+ formattedItems[0].isRepresentative = true
+ }
+
+ console.log('📋 최종 formattedItems:', formattedItems)
+ setItems(formattedItems)
+ console.log('✅ 상태 업데이트 완료')
+ } else {
+ console.log('❌ 저장 후 데이터가 없음 - 빈 배열 설정')
+ // 저장 후 데이터가 없으면 빈 배열로 설정
+ setItems([])
}
-
- setItems(formattedItems)
}
} catch (error) {
console.error('Failed to save items:', error)
@@ -593,30 +620,57 @@ export function BiddingItemsEditor({ biddingId }: BiddingItemsEditorProps) {
/>
</td>
<td className="border-r px-3 py-2">
- <MaterialGroupSelectorDialogSingle
- triggerLabel={item.materialGroupNumber || "자재그룹 선택"}
- triggerVariant="outline"
- selectedMaterial={item.materialGroupNumber ? {
- materialGroupCode: item.materialGroupNumber,
- materialGroupDescription: item.materialGroupInfo || '',
- displayText: `${item.materialGroupNumber} - ${item.materialGroupInfo || ''}`
- } : null}
- onMaterialSelect={(material) => {
- if (material) {
- updatePRItem(item.id, {
- materialGroupNumber: material.materialGroupCode,
- materialGroupInfo: material.materialGroupDescription
- })
- } else {
- updatePRItem(item.id, {
- materialGroupNumber: '',
- materialGroupInfo: ''
- })
- }
- }}
- title="자재그룹 선택"
- description="자재그룹을 검색하고 선택해주세요."
- />
+ {biddingType === 'equipment' ? (
+ <ProcurementItemSelectorDialogSingle
+ triggerLabel={item.materialGroupNumber || "품목 선택"}
+ triggerVariant="outline"
+ selectedProcurementItem={item.materialGroupNumber ? {
+ itemCode: item.materialGroupNumber,
+ itemName: item.materialGroupInfo || '',
+ displayText: `${item.materialGroupNumber}`
+ } : null}
+ onProcurementItemSelect={(procurementItem) => {
+ if (procurementItem) {
+ updatePRItem(item.id, {
+ materialGroupNumber: procurementItem.itemCode,
+ materialGroupInfo: procurementItem.itemName
+ })
+ } else {
+ updatePRItem(item.id, {
+ materialGroupNumber: '',
+ materialGroupInfo: ''
+ })
+ }
+ }}
+ title="품목 선택"
+ description="품목을 검색하고 선택해주세요."
+ />
+ ) : (
+ <MaterialGroupSelectorDialogSingle
+ triggerLabel={item.materialGroupNumber || "자재그룹 선택"}
+ triggerVariant="outline"
+ selectedMaterial={item.materialGroupNumber ? {
+ materialGroupCode: item.materialGroupNumber,
+ materialGroupDescription: item.materialGroupInfo || '',
+ displayText: `${item.materialGroupNumber}`
+ } : null}
+ onMaterialSelect={(material) => {
+ if (material) {
+ updatePRItem(item.id, {
+ materialGroupNumber: material.materialGroupCode,
+ materialGroupInfo: material.materialGroupDescription
+ })
+ } else {
+ updatePRItem(item.id, {
+ materialGroupNumber: '',
+ materialGroupInfo: ''
+ })
+ }
+ }}
+ title="자재그룹 선택"
+ description="자재그룹을 검색하고 선택해주세요."
+ />
+ )}
</td>
<td className="border-r px-3 py-2">
<Input
@@ -633,7 +687,7 @@ export function BiddingItemsEditor({ biddingId }: BiddingItemsEditorProps) {
selectedMaterial={item.materialNumber ? {
materialCode: item.materialNumber,
materialName: item.materialInfo || '',
- displayText: `${item.materialNumber} - ${item.materialInfo || ''}`
+ displayText: `${item.materialNumber}`
} : null}
onMaterialSelect={(material) => {
if (material) {
@@ -830,7 +884,7 @@ export function BiddingItemsEditor({ biddingId }: BiddingItemsEditorProps) {
>
{item.wbsCode ? (
<span className="truncate">
- {`${item.wbsCode}${item.wbsName ? ` - ${item.wbsName}` : ''}`}
+ {`${item.wbsCode}`}
</span>
) : (
<span className="text-muted-foreground">WBS 코드 선택</span>
@@ -880,7 +934,7 @@ export function BiddingItemsEditor({ biddingId }: BiddingItemsEditorProps) {
>
{item.costCenterCode ? (
<span className="truncate">
- {`${item.costCenterCode}${item.costCenterName ? ` - ${item.costCenterName}` : ''}`}
+ {`${item.costCenterCode}`}
</span>
) : (
<span className="text-muted-foreground">코스트센터 선택</span>
@@ -931,7 +985,7 @@ export function BiddingItemsEditor({ biddingId }: BiddingItemsEditorProps) {
>
{item.glAccountCode ? (
<span className="truncate">
- {`${item.glAccountCode}${item.glAccountName ? ` - ${item.glAccountName}` : ''}`}
+ {`${item.glAccountCode}`}
</span>
) : (
<span className="text-muted-foreground">GL계정 선택</span>
diff --git a/components/bidding/manage/create-pre-quote-rfq-dialog.tsx b/components/bidding/manage/create-pre-quote-rfq-dialog.tsx
index 88732deb..c49f6232 100644
--- a/components/bidding/manage/create-pre-quote-rfq-dialog.tsx
+++ b/components/bidding/manage/create-pre-quote-rfq-dialog.tsx
@@ -95,6 +95,7 @@ interface CreatePreQuoteRfqDialogProps {
totalWeight?: string | null
weightUnit?: string | null
}>
+ picUserId?: number | null
biddingConditions?: {
paymentTerms?: string | null
taxConditions?: string | null
@@ -114,6 +115,7 @@ export function CreatePreQuoteRfqDialog({
onOpenChange,
biddingId,
biddingItems,
+ picUserId,
biddingConditions,
onSuccess
}: CreatePreQuoteRfqDialogProps) {