From e4bd037d158513e45373ad9e1ef13f71af12162a Mon Sep 17 00:00:00 2001 From: dujinkim Date: Mon, 22 Sep 2025 08:56:13 +0000 Subject: (최겸) 구매 입찰 중량별 구분 삭제, itb requestTitle 컬럼 maxSize 변경 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/bidding/actions.ts | 45 +++-------- .../detail/table/bidding-vendor-prices-dialog.tsx | 88 +++++----------------- lib/bidding/list/biddings-transmission-dialog.tsx | 58 +++++++++----- lib/itb/table/purchase-request-columns.tsx | 2 +- 4 files changed, 72 insertions(+), 121 deletions(-) (limited to 'lib') diff --git a/lib/bidding/actions.ts b/lib/bidding/actions.ts index ae1fb54f..3eadaace 100644 --- a/lib/bidding/actions.ts +++ b/lib/bidding/actions.ts @@ -85,8 +85,6 @@ export async function transmitToContract(biddingId: number, userId: number) { materialDescription: prItemsForBidding.materialDescription, quantity: prItemsForBidding.quantity, quantityUnit: prItemsForBidding.quantityUnit, - totalWeight: prItemsForBidding.totalWeight, - weightUnit: prItemsForBidding.weightUnit, }) .from(companyPrItemBids) .leftJoin(prItemsForBidding, eq(companyPrItemBids.prItemId, prItemsForBidding.id)) @@ -138,16 +136,12 @@ export async function transmitToContract(biddingId: number, userId: number) { if (companyBids.length > 0) { console.log(`Creating ${companyBids.length} contract items for winner company ${winnerCompany.companyId} with award ratio ${awardRatio}`) for (const bid of companyBids) { - // 발주비율에 따른 최종 수량/중량 계산 + // 발주비율에 따른 최종 수량 계산 (중량 제외) const originalQuantity = Number(bid.quantity) || 0 - const originalWeight = Number(bid.totalWeight) || 0 const bidUnitPrice = Number(bid.bidUnitPrice) || 0 const finalQuantity = originalQuantity * awardRatio - const finalWeight = originalWeight * awardRatio - const finalAmount = finalQuantity > 0 - ? finalQuantity * bidUnitPrice - : finalWeight * bidUnitPrice + const finalAmount = finalQuantity * bidUnitPrice await db.insert(generalContractItems).values({ contractId: contractId, @@ -156,13 +150,13 @@ export async function transmitToContract(biddingId: number, userId: number) { specification: bid.materialDescription || '', quantity: finalQuantity || null, quantityUnit: bid.quantityUnit || '', - totalWeight: finalWeight || null, - weightUnit: bid.weightUnit || '', + totalWeight: null, // 중량 정보 제외 + weightUnit: '', // 중량 단위 제외 contractDeliveryDate: bid.proposedDeliveryDate || null, contractUnitPrice: bid.bidUnitPrice || null, contractAmount: finalAmount || null, contractCurrency: bid.currency || biddingData.currency || 'KRW', - } as any) + }) } console.log(`Created ${companyBids.length} contract items for winner company ${winnerCompany.companyId}`) } else { @@ -239,10 +233,7 @@ export async function transmitToPO(biddingId: number) { materialDescription: string | null quantity: string | null quantityUnit: string | null - totalWeight: string | null - weightUnit: string | null finalQuantity: number - finalWeight: number finalAmount: number awardRatio: number vendorCode: string | null @@ -265,29 +256,22 @@ export async function transmitToPO(biddingId: number) { materialDescription: prItemsForBidding.materialDescription, quantity: prItemsForBidding.quantity, quantityUnit: prItemsForBidding.quantityUnit, - totalWeight: prItemsForBidding.totalWeight, - weightUnit: prItemsForBidding.weightUnit, }) .from(companyPrItemBids) .leftJoin(prItemsForBidding, eq(companyPrItemBids.prItemId, prItemsForBidding.id)) .where(eq(companyPrItemBids.biddingCompanyId, winner.id)) - // 발주비율 적용하여 PO 아이템 생성 + // 발주비율 적용하여 PO 아이템 생성 (중량 제외) for (const bid of companyBids) { const originalQuantity = Number(bid.quantity) || 0 - const originalWeight = Number(bid.totalWeight) || 0 const bidUnitPrice = Number(bid.bidUnitPrice) || 0 const finalQuantity = originalQuantity * awardRatio - const finalWeight = originalWeight * awardRatio - const finalAmount = finalQuantity > 0 - ? finalQuantity * bidUnitPrice - : finalWeight * bidUnitPrice + const finalAmount = finalQuantity * bidUnitPrice poItems.push({ ...bid, finalQuantity, - finalWeight, finalAmount, awardRatio, vendorCode: winner.vendorCode, @@ -394,28 +378,21 @@ export async function getWinnerDetails(biddingId: number) { materialDescription: prItemsForBidding.materialDescription, quantity: prItemsForBidding.quantity, quantityUnit: prItemsForBidding.quantityUnit, - totalWeight: prItemsForBidding.totalWeight, - weightUnit: prItemsForBidding.weightUnit, }) .from(companyPrItemBids) .leftJoin(prItemsForBidding, eq(companyPrItemBids.prItemId, prItemsForBidding.id)) .where(eq(companyPrItemBids.biddingCompanyId, winner.id)) - // 발주비율에 따른 계산 (백분율을 실제 비율로 변환) + // 발주비율에 따른 계산 (백분율을 실제 비율로 변환, 중량 제외) const awardRatio = (Number(winner.awardRatio) || 100) / 100 const calculatedItems = companyBids.map(bid => { const originalQuantity = Number(bid.quantity) || 0 - const originalWeight = Number(bid.totalWeight) || 0 const bidUnitPrice = Number(bid.bidUnitPrice) || 0 - // 발주비율에 따른 최종 수량/중량 계산 + // 발주비율에 따른 최종 수량 계산 const finalQuantity = originalQuantity * awardRatio - const finalWeight = originalWeight * awardRatio - - // 최종 견적가 계산 (수량 또는 중량에 따른) - const finalAmount = finalQuantity > 0 - ? finalQuantity * bidUnitPrice - : finalWeight * bidUnitPrice + const finalWeight = 0 // 중량 제외 + const finalAmount = finalQuantity * bidUnitPrice return { ...bid, diff --git a/lib/bidding/detail/table/bidding-vendor-prices-dialog.tsx b/lib/bidding/detail/table/bidding-vendor-prices-dialog.tsx index c12ac1df..dfcef812 100644 --- a/lib/bidding/detail/table/bidding-vendor-prices-dialog.tsx +++ b/lib/bidding/detail/table/bidding-vendor-prices-dialog.tsx @@ -8,7 +8,6 @@ import { DialogHeader, DialogTitle, } from '@/components/ui/dialog' -import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { @@ -21,8 +20,6 @@ import { } from '@/components/ui/table' import { DollarSign, - Package, - Scale, Building, TrendingDown, TrendingUp @@ -41,8 +38,6 @@ interface VendorPrice { itemName: string quantity: number quantityUnit: string - weight: number | null - weightUnit: string | null unitPrice: number amount: number proposedDeliveryDate?: string @@ -71,16 +66,8 @@ export function BiddingVendorPricesDialog({ const { toast } = useToast() const [vendorPrices, setVendorPrices] = React.useState([]) const [isLoading, setIsLoading] = React.useState(false) - const [viewMode, setViewMode] = React.useState<'quantity' | 'weight'>('quantity') - // 다이얼로그가 열릴 때 데이터 로드 - React.useEffect(() => { - if (open) { - loadVendorPrices() - } - }, [open, biddingId]) - - const loadVendorPrices = async () => { + const loadVendorPrices = React.useCallback(async () => { setIsLoading(true) try { const data = await getVendorPricesForBidding(biddingId) @@ -95,7 +82,15 @@ export function BiddingVendorPricesDialog({ } finally { setIsLoading(false) } - } + }, [biddingId, toast]) + + // 다이얼로그가 열릴 때 데이터 로드 + React.useEffect(() => { + if (open) { + loadVendorPrices() + } + }, [open, loadVendorPrices]) + // 금액 포맷팅 const formatCurrency = (amount: number) => { @@ -107,22 +102,14 @@ export function BiddingVendorPricesDialog({ }).format(amount) } - // 수량/중량 포맷팅 + // 수량 포맷팅 const formatQuantity = (quantity: number, unit: string) => { return `${quantity.toLocaleString()} ${unit}` } - const formatWeight = (weight: number | null, unit: string | null) => { - if (!weight || !unit) return '-' - return `${weight.toLocaleString()} ${unit}` - } - // 최저가 계산 - const getLowestPrice = (itemPrices: VendorPrice['itemPrices'], field: 'quantity' | 'weight') => { - const validPrices = itemPrices.filter(item => { - if (field === 'quantity') return item.quantity > 0 - return item.weight && item.weight > 0 - }) + const getLowestPrice = (itemPrices: VendorPrice['itemPrices']) => { + const validPrices = itemPrices.filter(item => item.quantity > 0) if (validPrices.length === 0) return null @@ -131,11 +118,8 @@ export function BiddingVendorPricesDialog({ } // 최고가 계산 - const getHighestPrice = (itemPrices: VendorPrice['itemPrices'], field: 'quantity' | 'weight') => { - const validPrices = itemPrices.filter(item => { - if (field === 'quantity') return item.quantity > 0 - return item.weight && item.weight > 0 - }) + const getHighestPrice = (itemPrices: VendorPrice['itemPrices']) => { + const validPrices = itemPrices.filter(item => item.quantity > 0) if (validPrices.length === 0) return null @@ -205,30 +189,6 @@ export function BiddingVendorPricesDialog({ - {/* 뷰 모드 토글 */} -
- 보기 방식: -
- - -
-
{isLoading ? (
@@ -262,9 +222,7 @@ export function BiddingVendorPricesDialog({ 품목명 - - {viewMode === 'quantity' ? '수량' : '중량'} - + 수량 단가 금액 가격대 @@ -273,13 +231,10 @@ export function BiddingVendorPricesDialog({ {vendor.itemPrices - .filter(item => { - if (viewMode === 'quantity') return item.quantity > 0 - return item.weight && item.weight > 0 - }) + .filter(item => item.quantity > 0) .map((item, index) => { - const lowestPrice = getLowestPrice(vendor.itemPrices, viewMode) - const highestPrice = getHighestPrice(vendor.itemPrices, viewMode) + const lowestPrice = getLowestPrice(vendor.itemPrices) + const highestPrice = getHighestPrice(vendor.itemPrices) const isLowest = item.unitPrice === lowestPrice const isHighest = item.unitPrice === highestPrice @@ -289,10 +244,7 @@ export function BiddingVendorPricesDialog({ {item.itemName} - {viewMode === 'quantity' - ? formatQuantity(item.quantity, item.quantityUnit) - : formatWeight(item.weight, item.weightUnit) // totalWeight를 weight로 매핑했으므로 사용 가능 - } + {formatQuantity(item.quantity, item.quantityUnit)} {formatCurrency(item.unitPrice)} diff --git a/lib/bidding/list/biddings-transmission-dialog.tsx b/lib/bidding/list/biddings-transmission-dialog.tsx index 61207327..de28bf54 100644 --- a/lib/bidding/list/biddings-transmission-dialog.tsx +++ b/lib/bidding/list/biddings-transmission-dialog.tsx @@ -18,6 +18,12 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Label } from "@/components/ui/label" import { Badge } from "@/components/ui/badge" import { Separator } from "@/components/ui/separator" +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip" import { BiddingListItem } from "@/db/schema" import { transmitToContract, transmitToPO, getWinnerDetails } from "@/lib/bidding/actions" @@ -36,15 +42,16 @@ interface WinnerDetail { awardRatio: number totalFinalAmount: number items: Array<{ + prItemId: number + proposedDeliveryDate: string | null + bidUnitPrice: string | null + bidAmount: string | null + currency: string | null itemNumber: string | null itemInfo: string | null materialDescription: string | null quantity: string | null quantityUnit: string | null - totalWeight: string | null - weightUnit: string | null - bidUnitPrice: string | null - currency: string | null finalQuantity: number finalWeight: number finalAmount: number @@ -215,12 +222,6 @@ export function TransmissionDialog({ open, onOpenChange, bidding, userId }: Tran
발주 수량: {item.finalQuantity.toLocaleString()} {item.quantityUnit}
-
- 원래 중량: {Number(item.totalWeight).toLocaleString()} {item.weightUnit} -
-
- 발주 중량: {item.finalWeight.toLocaleString()} {item.weightUnit} -
단가: {Number(item.bidUnitPrice).toLocaleString()} {item.currency}
@@ -252,14 +253,35 @@ export function TransmissionDialog({ open, onOpenChange, bidding, userId }: Tran TO Contract - + {bidding.ANFNR ? ( + + ) : ( + + + +
+ +
+
+ +

해당 입찰은 SAP TO PO가 불가능합니다.

+
+
+
+ )} diff --git a/lib/itb/table/purchase-request-columns.tsx b/lib/itb/table/purchase-request-columns.tsx index 55321a21..e6489c18 100644 --- a/lib/itb/table/purchase-request-columns.tsx +++ b/lib/itb/table/purchase-request-columns.tsx @@ -157,7 +157,7 @@ export function getPurchaseRequestColumns({ )}
), - size: 300, + maxSize: 300, }, { accessorKey: "projectName", -- cgit v1.2.3