diff --git a/src/components/quotes/LocationDetailPanel.tsx b/src/components/quotes/LocationDetailPanel.tsx index a8287819..0b913639 100644 --- a/src/components/quotes/LocationDetailPanel.tsx +++ b/src/components/quotes/LocationDetailPanel.tsx @@ -12,6 +12,7 @@ import { useState, useMemo, useEffect } from "react"; import { Package, Settings, Plus, Trash2, Loader2, Calculator, Save } from "lucide-react"; import { getItemCategoryTree, type ItemCategoryNode } from "./actions"; +import { fetchItemPrices } from "@/lib/api/items"; import { Badge } from "../ui/badge"; import { Button } from "../ui/button"; @@ -724,21 +725,32 @@ export function LocationDetailPanel({ { + onSelectItem={async (item) => { if (!location) return; const currentTab = detailTabs.find((t) => t.value === activeTab); const categoryCode = activeTab; const categoryLabel = currentTab?.label || activeTab; + // 단가 조회 (클라이언트 API 호출) + let unitPrice = 0; + try { + const priceResult = await fetchItemPrices([item.code]); + unitPrice = priceResult[item.code]?.unit_price || 0; + } catch (error) { + console.error('[품목 추가] 단가 조회 실패:', error); + } + + const totalPrice = unitPrice * 1; // quantity = 1 + const newItem: BomCalculationResultItem & { category_code?: string; is_manual?: boolean } = { item_code: item.code, item_name: item.name, specification: item.specification || "", unit: "EA", quantity: 1, - unit_price: 0, - total_price: 0, + unit_price: unitPrice, + total_price: totalPrice, process_group: categoryLabel, category_code: categoryCode, is_manual: true, @@ -789,8 +801,13 @@ export function LocationDetailPanel({ grand_total: updatedGrandTotal, }; - onUpdateLocation(location.id, { bomResult: updatedBomResult }); - console.log(`[품목 추가] ${item.code} - ${item.name} → ${categoryLabel} (${categoryCode})`); + // unitPrice, totalPrice도 함께 업데이트 + onUpdateLocation(location.id, { + bomResult: updatedBomResult, + unitPrice: updatedGrandTotal, + totalPrice: updatedGrandTotal * location.quantity, + }); + console.log(`[품목 추가] ${item.code} - ${item.name} → ${categoryLabel} (${categoryCode}), 단가: ${unitPrice}`); }} tabLabel={detailTabs.find((t) => t.value === activeTab)?.label} /> diff --git a/src/lib/api/items.ts b/src/lib/api/items.ts index 090748ea..8c89ce5b 100644 --- a/src/lib/api/items.ts +++ b/src/lib/api/items.ts @@ -759,4 +759,59 @@ export async function revalidateItems(): Promise { const { revalidatePath } = await import('next/cache'); revalidatePath('/items'); } +} + +// ===== 품목 단가 조회 ===== + +/** 품목 단가 조회 결과 */ +export interface ItemPriceResult { + item_code: string; + unit_price: number; +} + +/** + * 품목 단가 조회 (견적 품목 추가 시 사용) + * + * @param itemCodes - 조회할 품목 코드 배열 + * @returns 품목 코드별 단가 정보 + * + * @example + * const prices = await fetchItemPrices(['N71807', 'N71808']); + * console.log(prices['N71807']?.unit_price); // 1320000 + */ +export async function fetchItemPrices( + itemCodes: string[] +): Promise> { + if (!itemCodes.length) { + return {}; + } + + try { + // 프록시 경유: /api/proxy/quotes/items/prices → /api/v1/quotes/items/prices + const response = await fetch('/api/proxy/quotes/items/prices', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ item_codes: itemCodes }), + credentials: 'include', + }); + + if (!response.ok) { + console.error('[fetchItemPrices] API 에러:', response.status); + return {}; + } + + const result = await response.json(); + console.log('[fetchItemPrices] API 응답:', result); + + if (result.success && result.data) { + return result.data as Record; + } + + return {}; + } catch (error) { + console.error('[fetchItemPrices] 에러:', error); + return {}; + } } \ No newline at end of file