fix(WEB): 견적 품목 삭제/수량변경 기능 수정 - 참조비교를 값비교로 변경
- 삭제: grouped_items에서 index로 대상 특정 후 값 비교로 items에서 제거 - 수량변경: 동일하게 참조비교 → 값비교로 수정 - 삭제/수량변경 시 grouped_items, subtotals, grand_total 동기 업데이트
This commit is contained in:
@@ -559,32 +559,64 @@ export function LocationDetailPanel({
|
||||
const existingBomResult = location.bomResult;
|
||||
if (!existingBomResult) return;
|
||||
|
||||
// 해당 아이템 찾아서 수량 및 금액 업데이트
|
||||
const updatedItems = (existingBomResult.items || []).map((bomItem: any, i: number) => {
|
||||
if (bomItemsByTab[tab.value]?.[index] === bomItem) {
|
||||
const newTotalPrice = (bomItem.unit_price || 0) * newQty;
|
||||
return {
|
||||
...bomItem,
|
||||
quantity: newQty,
|
||||
total_price: newTotalPrice,
|
||||
};
|
||||
const targetItem = item;
|
||||
const targetCode = targetItem.item_code;
|
||||
const targetName = targetItem.item_name;
|
||||
|
||||
// grouped_items 내 해당 탭에서 index로 매칭하여 items에서 찾기
|
||||
const groupItems = existingBomResult.grouped_items?.[tab.value]?.items || [];
|
||||
const matchedItem = groupItems[index];
|
||||
if (!matchedItem) return;
|
||||
|
||||
// items 배열에서 같은 item_code + item_name 매칭 (동일 코드 복수 가능하므로 순서 기반)
|
||||
let matchCount = 0;
|
||||
const updatedItems = (existingBomResult.items || []).map((bomItem: any) => {
|
||||
if (bomItem.item_code === targetCode && bomItem.item_name === targetName) {
|
||||
matchCount++;
|
||||
// grouped_items 내 순서와 items 내 순서가 같은 아이템 찾기
|
||||
if (bomItem.quantity === targetItem.quantity && bomItem.unit_price === targetItem.unit_price) {
|
||||
const newTotalPrice = (bomItem.unit_price || 0) * newQty;
|
||||
return { ...bomItem, quantity: newQty, total_price: newTotalPrice };
|
||||
}
|
||||
}
|
||||
return bomItem;
|
||||
});
|
||||
|
||||
// grouped_items도 업데이트
|
||||
const updatedGroupedItems: Record<string, any> = { ...existingBomResult.grouped_items };
|
||||
if (updatedGroupedItems[tab.value]) {
|
||||
const updatedTabItems = [...(updatedGroupedItems[tab.value].items || [])];
|
||||
if (updatedTabItems[index]) {
|
||||
const newTotalPrice = (updatedTabItems[index].unit_price || 0) * newQty;
|
||||
updatedTabItems[index] = { ...updatedTabItems[index], quantity: newQty, total_price: newTotalPrice };
|
||||
}
|
||||
updatedGroupedItems[tab.value] = { ...updatedGroupedItems[tab.value], items: updatedTabItems };
|
||||
}
|
||||
|
||||
// grand_total 재계산
|
||||
const newGrandTotal = updatedItems.reduce(
|
||||
(sum: number, item: any) => sum + (item.total_price || 0),
|
||||
0
|
||||
(sum: number, bi: any) => sum + (bi.total_price || 0), 0
|
||||
);
|
||||
|
||||
// location 업데이트 (unitPrice, totalPrice 포함)
|
||||
// subtotals 재계산
|
||||
const updatedSubtotals = { ...existingBomResult.subtotals };
|
||||
Object.entries(updatedGroupedItems).forEach(([key, group]) => {
|
||||
const groupItemsList = (group as any)?.items || [];
|
||||
const subtotal = groupItemsList.reduce((s: number, gi: any) => s + (gi.total_price || 0), 0);
|
||||
const existing = updatedSubtotals[key];
|
||||
if (typeof existing === 'object' && existing !== null) {
|
||||
updatedSubtotals[key] = { ...existing, count: groupItemsList.length, subtotal };
|
||||
}
|
||||
});
|
||||
|
||||
onUpdateLocation(location.id, {
|
||||
unitPrice: newGrandTotal,
|
||||
totalPrice: newGrandTotal * location.quantity,
|
||||
bomResult: {
|
||||
...existingBomResult,
|
||||
items: updatedItems,
|
||||
grouped_items: updatedGroupedItems,
|
||||
subtotals: updatedSubtotals,
|
||||
grand_total: newGrandTotal,
|
||||
},
|
||||
});
|
||||
@@ -602,18 +634,62 @@ export function LocationDetailPanel({
|
||||
disabled={disabled}
|
||||
onClick={() => {
|
||||
if (!location) return;
|
||||
// 품목 삭제 로직
|
||||
const existingBomResult = location.bomResult;
|
||||
if (!existingBomResult) return;
|
||||
|
||||
const updatedItems = (existingBomResult.items || []).filter(
|
||||
(_: any, i: number) => !(bomItemsByTab[tab.value]?.[index] === _)
|
||||
// 삭제 대상: 현재 탭의 grouped_items에서 index번째 아이템
|
||||
const groupItems: any[] = existingBomResult.grouped_items?.[tab.value]?.items || [];
|
||||
const targetItem = groupItems[index];
|
||||
if (!targetItem) return;
|
||||
|
||||
// grouped_items에서 해당 아이템 제거
|
||||
const updatedGroupedItems: Record<string, any> = { ...existingBomResult.grouped_items };
|
||||
if (updatedGroupedItems[tab.value]) {
|
||||
const updatedTabItems = [...(updatedGroupedItems[tab.value].items || [])];
|
||||
updatedTabItems.splice(index, 1);
|
||||
updatedGroupedItems[tab.value] = { ...updatedGroupedItems[tab.value], items: updatedTabItems };
|
||||
}
|
||||
|
||||
// items 배열에서도 제거 (item_code + item_name + quantity + unit_price 매칭)
|
||||
let removed = false;
|
||||
const updatedItems = (existingBomResult.items || []).filter((bi: any) => {
|
||||
if (!removed &&
|
||||
bi.item_code === targetItem.item_code &&
|
||||
bi.item_name === targetItem.item_name &&
|
||||
bi.quantity === targetItem.quantity &&
|
||||
bi.unit_price === targetItem.unit_price
|
||||
) {
|
||||
removed = true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
// grand_total 재계산
|
||||
const newGrandTotal = updatedItems.reduce(
|
||||
(sum: number, bi: any) => sum + (bi.total_price || 0), 0
|
||||
);
|
||||
|
||||
// subtotals 재계산
|
||||
const updatedSubtotals = { ...existingBomResult.subtotals };
|
||||
Object.entries(updatedGroupedItems).forEach(([key, group]) => {
|
||||
const groupItemsList = (group as any)?.items || [];
|
||||
const subtotal = groupItemsList.reduce((s: number, gi: any) => s + (gi.total_price || 0), 0);
|
||||
const existing = updatedSubtotals[key];
|
||||
if (typeof existing === 'object' && existing !== null) {
|
||||
updatedSubtotals[key] = { ...existing, count: groupItemsList.length, subtotal };
|
||||
}
|
||||
});
|
||||
|
||||
onUpdateLocation(location.id, {
|
||||
unitPrice: newGrandTotal,
|
||||
totalPrice: newGrandTotal * location.quantity,
|
||||
bomResult: {
|
||||
...existingBomResult,
|
||||
items: updatedItems,
|
||||
grouped_items: updatedGroupedItems,
|
||||
subtotals: updatedSubtotals,
|
||||
grand_total: newGrandTotal,
|
||||
},
|
||||
});
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user