fix(WEB): 견적V2 자동 산출 로직 안정화
- pendingAutoCalculate를 useRef로 변경 (무한 렌더링 방지) - BOM 계산 결과 매핑 로직 수정 - bomMaterials 변환 로직 단순화 (API 응답 직접 사용) - DevFill 기본 상품코드 수정
This commit is contained in:
@@ -167,7 +167,7 @@ export function QuoteRegistrationV2({
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const [isCalculating, setIsCalculating] = useState(false);
|
||||
const [previewModalOpen, setPreviewModalOpen] = useState(false);
|
||||
const [pendingAutoCalculate, setPendingAutoCalculate] = useState(false);
|
||||
const pendingAutoCalculateRef = useRef(false);
|
||||
|
||||
// API 데이터
|
||||
const [clients, setClients] = useState<Vendor[]>([]);
|
||||
@@ -203,8 +203,8 @@ export function QuoteRegistrationV2({
|
||||
code: `${randomPrefix}-${String(index + 1).padStart(2, "0")}`,
|
||||
openWidth: randomWidth,
|
||||
openHeight: randomHeight,
|
||||
productCode: randomProduct?.item_code || "FG-001",
|
||||
productName: randomProduct?.item_name || "방화셔터",
|
||||
productCode: randomProduct?.item_code || "FG-SCR-001",
|
||||
productName: randomProduct?.item_name || "방화 스크린 셔터 (소형)",
|
||||
quantity: Math.floor(Math.random() * 3) + 1, // 1~3
|
||||
guideRailType: guideRailTypes[Math.floor(Math.random() * guideRailTypes.length)],
|
||||
motorPower: motorPowers[Math.floor(Math.random() * motorPowers.length)],
|
||||
@@ -252,7 +252,7 @@ export function QuoteRegistrationV2({
|
||||
toast.success(`[DevFill] 테스트 데이터가 채워졌습니다. (${locationCount}개 개소)`);
|
||||
|
||||
// 자동 견적 산출 트리거
|
||||
setPendingAutoCalculate(true);
|
||||
pendingAutoCalculateRef.current = true;
|
||||
}, [clients, finishedGoods]));
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -455,20 +455,24 @@ export function QuoteRegistrationV2({
|
||||
const result = await calculateBomBulk(bomItems);
|
||||
|
||||
if (result.success && result.data) {
|
||||
// API 응답: { summary: { grand_total }, items: [{ index, result: BomCalculationResult }] }
|
||||
const apiData = result.data as {
|
||||
summary?: { grand_total: number };
|
||||
items?: Array<{ index: number; result: BomCalculationResult }>;
|
||||
};
|
||||
|
||||
const bomItems = apiData.items || [];
|
||||
|
||||
// 결과 반영
|
||||
const updatedLocations = formData.locations.map((loc, index) => {
|
||||
const bomResult = apiData.items?.find((item) => item.index === index);
|
||||
if (bomResult?.result) {
|
||||
const bomItem = bomItems.find((item) => item.index === index);
|
||||
const bomResult = bomItem?.result;
|
||||
if (bomResult) {
|
||||
return {
|
||||
...loc,
|
||||
unitPrice: bomResult.result.grand_total,
|
||||
totalPrice: bomResult.result.grand_total * loc.quantity,
|
||||
bomResult: bomResult.result,
|
||||
unitPrice: bomResult.grand_total,
|
||||
totalPrice: bomResult.grand_total * loc.quantity,
|
||||
bomResult: bomResult,
|
||||
};
|
||||
}
|
||||
return loc;
|
||||
@@ -494,15 +498,14 @@ export function QuoteRegistrationV2({
|
||||
|
||||
// DevFill 후 자동 견적 산출
|
||||
useEffect(() => {
|
||||
if (pendingAutoCalculate && formData.locations.length > 0 && calculateRef.current) {
|
||||
setPendingAutoCalculate(false);
|
||||
// 약간의 딜레이 후 산출 실행 (상태 업데이트 완료 대기)
|
||||
const timer = setTimeout(() => {
|
||||
calculateRef.current?.();
|
||||
}, 100);
|
||||
return () => clearTimeout(timer);
|
||||
if (pendingAutoCalculateRef.current && formData.locations.length > 0) {
|
||||
pendingAutoCalculateRef.current = false;
|
||||
// 상태 업데이트 완료 후 산출 실행
|
||||
setTimeout(() => {
|
||||
handleCalculate();
|
||||
}, 50);
|
||||
}
|
||||
}, [pendingAutoCalculate, formData.locations.length]);
|
||||
}, [formData.locations, handleCalculate]);
|
||||
|
||||
// 저장 (임시/최종)
|
||||
const handleSave = useCallback(async (saveType: "temporary" | "final") => {
|
||||
|
||||
@@ -541,24 +541,9 @@ export function transformQuoteToFormData(quote: Quote): QuoteFormData {
|
||||
};
|
||||
}),
|
||||
// BOM 자재 목록:
|
||||
// - calcInputs가 있으면: quote.items에 BOM 자재가 저장되어 있음 (quote_items 테이블)
|
||||
// - calcInputs가 없으면: quote.bomMaterials 사용 (별도 bom_materials 필드가 있는 경우)
|
||||
bomMaterials: calcInputs.length > 0
|
||||
? quote.items.map((item, index) => ({
|
||||
itemIndex: index,
|
||||
finishedGoodsCode: '',
|
||||
itemCode: item.itemCode || '', // 품목코드 사용
|
||||
itemName: item.productName,
|
||||
itemType: '',
|
||||
itemCategory: '',
|
||||
specification: item.specification || '',
|
||||
unit: item.unit || '',
|
||||
quantity: item.quantity,
|
||||
unitPrice: item.unitPrice,
|
||||
totalPrice: item.totalAmount,
|
||||
processType: '',
|
||||
}))
|
||||
: quote.bomMaterials,
|
||||
// - API에서 bom_materials를 계산하여 반환 (item_type 포함)
|
||||
// - quote.bomMaterials가 있으면 그대로 사용
|
||||
bomMaterials: quote.bomMaterials,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user