summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-09-22 08:56:13 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-09-22 08:56:13 +0000
commite4bd037d158513e45373ad9e1ef13f71af12162a (patch)
treebf4a174ea33a2fb1173dc46c41f27e50df3310dd /lib
parent06d4753d61a803e2f8447bc3167dced3434107d4 (diff)
(최겸) 구매 입찰 중량별 구분 삭제, itb requestTitle 컬럼 maxSize 변경
Diffstat (limited to 'lib')
-rw-r--r--lib/bidding/actions.ts45
-rw-r--r--lib/bidding/detail/table/bidding-vendor-prices-dialog.tsx88
-rw-r--r--lib/bidding/list/biddings-transmission-dialog.tsx58
-rw-r--r--lib/itb/table/purchase-request-columns.tsx2
4 files changed, 72 insertions, 121 deletions
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<VendorPrice[]>([])
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({
</Card>
</div>
- {/* 뷰 모드 토글 */}
- <div className="flex items-center gap-2">
- <span className="text-sm font-medium">보기 방식:</span>
- <div className="flex bg-muted rounded-lg p-1">
- <Button
- variant={viewMode === 'quantity' ? 'default' : 'ghost'}
- size="sm"
- onClick={() => setViewMode('quantity')}
- className="flex items-center gap-2"
- >
- <Package className="w-4 h-4" />
- 수량별
- </Button>
- <Button
- variant={viewMode === 'weight' ? 'default' : 'ghost'}
- size="sm"
- onClick={() => setViewMode('weight')}
- className="flex items-center gap-2"
- >
- <Scale className="w-4 h-4" />
- 중량별
- </Button>
- </div>
- </div>
{isLoading ? (
<div className="flex items-center justify-center py-12">
@@ -262,9 +222,7 @@ export function BiddingVendorPricesDialog({
<TableHeader>
<TableRow>
<TableHead>품목명</TableHead>
- <TableHead className="text-right">
- {viewMode === 'quantity' ? '수량' : '중량'}
- </TableHead>
+ <TableHead className="text-right">수량</TableHead>
<TableHead className="text-right">단가</TableHead>
<TableHead className="text-right">금액</TableHead>
<TableHead className="text-center">가격대</TableHead>
@@ -273,13 +231,10 @@ export function BiddingVendorPricesDialog({
</TableHeader>
<TableBody>
{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}
</TableCell>
<TableCell className="text-right font-mono">
- {viewMode === 'quantity'
- ? formatQuantity(item.quantity, item.quantityUnit)
- : formatWeight(item.weight, item.weightUnit) // totalWeight를 weight로 매핑했으므로 사용 가능
- }
+ {formatQuantity(item.quantity, item.quantityUnit)}
</TableCell>
<TableCell className="text-right font-mono">
{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
@@ -216,12 +223,6 @@ export function TransmissionDialog({ open, onOpenChange, bidding, userId }: Tran
<span className="font-medium">발주 수량:</span> {item.finalQuantity.toLocaleString()} {item.quantityUnit}
</div>
<div>
- <span className="font-medium">원래 중량:</span> {Number(item.totalWeight).toLocaleString()} {item.weightUnit}
- </div>
- <div>
- <span className="font-medium">발주 중량:</span> {item.finalWeight.toLocaleString()} {item.weightUnit}
- </div>
- <div>
<span className="font-medium">단가:</span> {Number(item.bidUnitPrice).toLocaleString()} {item.currency}
</div>
<div>
@@ -252,14 +253,35 @@ export function TransmissionDialog({ open, onOpenChange, bidding, userId }: Tran
<FileText className="w-4 h-4" />
TO Contract
</Button>
- <Button
- onClick={handleToPO}
- disabled={isLoading}
- className="gap-2"
- >
- <Truck className="w-4 h-4" />
- TO PO
- </Button>
+ {bidding.ANFNR ? (
+ <Button
+ onClick={handleToPO}
+ disabled={isLoading}
+ className="gap-2"
+ >
+ <Truck className="w-4 h-4" />
+ TO PO
+ </Button>
+ ) : (
+ <TooltipProvider>
+ <Tooltip>
+ <TooltipTrigger asChild>
+ <div>
+ <Button
+ disabled
+ className="gap-2 opacity-50"
+ >
+ <Truck className="w-4 h-4" />
+ TO PO
+ </Button>
+ </div>
+ </TooltipTrigger>
+ <TooltipContent>
+ <p>해당 입찰은 SAP TO PO가 불가능합니다.</p>
+ </TooltipContent>
+ </Tooltip>
+ </TooltipProvider>
+ )}
</DialogFooter>
</DialogContent>
</Dialog>
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({
)}
</div>
),
- size: 300,
+ maxSize: 300,
},
{
accessorKey: "projectName",