Refactor customer management page to improve price item handling

- Update the logic for retrieving and processing customer item prices.
- Replace the previous price mapping with a grouping mechanism based on item_id and today's date.
- Enhance the handling of customer item codes and names to ensure proper aggregation.
- Improve overall readability and maintainability of the code.

This commit enhances the functionality of the customer management page by ensuring accurate price data is displayed based on the current date, improving user experience in managing customer items.
This commit is contained in:
kjs 2026-03-30 17:02:48 +09:00
parent 42bb3a18fb
commit f2f18db449
2 changed files with 148 additions and 86 deletions

View File

@ -284,8 +284,8 @@ export default function CustomerManagementPage() {
} catch { /* skip */ }
}
// 3. customer_item_prices 조회 (단가 — 있으면 보강)
let priceMap: Record<string, any> = {};
// 3. customer_item_prices 조회
let allPrices: any[] = [];
if (mappings.length > 0) {
try {
const priceRes = await apiClient.post(`/table-management/tables/${PRICE_TABLE}/data`, {
@ -295,36 +295,43 @@ export default function CustomerManagementPage() {
]},
autoFilter: true,
});
const prices = priceRes.data?.data?.data || priceRes.data?.data?.rows || [];
// item_id별 최신 단가 매핑
for (const p of prices) {
const key = p.item_id;
if (!priceMap[key] || (p.start_date && (!priceMap[key].start_date || p.start_date > priceMap[key].start_date))) {
priceMap[key] = p;
}
}
allPrices = priceRes.data?.data?.data || priceRes.data?.data?.rows || [];
} catch { /* skip */ }
}
// 4. 매핑 + 품목정보 + 단가 병합 + 카테고리 코드→라벨
// 4. 매핑별 행 생성 + 오늘 날짜 기준 단가 + 같은 품목 첫 행만 품목코드/품명 표시
const priceResolve = (col: string, code: string) => {
if (!code) return "";
return priceCategoryOptions[col]?.find((o) => o.code === code)?.label || code;
};
setPriceItems(mappings.map((m: any) => {
const itemInfo = itemMap[m.item_id] || {};
const price = priceMap[m.item_id] || {};
const today = new Date().toISOString().split("T")[0];
const seenItemIds = new Set<string>();
// item_id로 정렬하여 같은 품목끼리 묶기
const sortedMappings = [...mappings].sort((a: any, b: any) => (a.item_id || "").localeCompare(b.item_id || ""));
setPriceItems(sortedMappings.map((m: any) => {
const itemKey = m.item_id || "";
const itemInfo = itemMap[itemKey] || {};
const isFirstOfGroup = !seenItemIds.has(itemKey);
if (itemKey) seenItemIds.add(itemKey);
// 오늘 날짜에 해당하는 단가
const itemPriceList = allPrices.filter((p: any) => p.item_id === itemKey);
const todayPrice = itemPriceList.find((p: any) =>
(!p.start_date || p.start_date <= today) && (!p.end_date || p.end_date >= today)
) || itemPriceList[0] || {};
return {
...m,
item_number: m.item_id,
item_name: itemInfo.item_name || "",
base_price_type: priceResolve("base_price_type", price.base_price_type || m.base_price_type || ""),
base_price: price.base_price || m.base_price || "",
discount_type: priceResolve("discount_type", price.discount_type || m.discount_type || ""),
discount_value: price.discount_value || m.discount_value || "",
rounding_type: priceResolve("rounding_unit_value", price.rounding_type || m.rounding_type || ""),
calculated_price: price.calculated_price || m.calculated_price || "",
currency_code: priceResolve("currency_code", price.currency_code || m.currency_code || ""),
item_number: isFirstOfGroup ? itemKey : "",
item_name: isFirstOfGroup ? (itemInfo.item_name || "") : "",
base_price_type: priceResolve("base_price_type", todayPrice.base_price_type || ""),
base_price: todayPrice.base_price || "",
discount_type: priceResolve("discount_type", todayPrice.discount_type || ""),
discount_value: todayPrice.discount_value || "",
calculated_price: todayPrice.calculated_price || todayPrice.unit_price || "",
currency_code: priceResolve("currency_code", todayPrice.currency_code || ""),
};
}));
} catch (err) {
@ -572,27 +579,51 @@ export default function CustomerManagementPage() {
if (found) itemInfo = found;
} catch { /* skip */ }
// 기존 매핑 데이터 → 거래처 품번/품명
const mappingRows = [{
_id: `m_existing_${row.id}`,
customer_item_code: row.customer_item_code || "",
customer_item_name: row.customer_item_name || "",
}].filter((m) => m.customer_item_code || m.customer_item_name);
// DB에서 해당 품목의 모든 매핑 조회
let mappingRows: any[] = [];
try {
const mapRes = await apiClient.post(`/table-management/tables/${MAPPING_TABLE}/data`, {
page: 1, size: 100,
dataFilter: { enabled: true, filters: [
{ columnName: "customer_id", operator: "equals", value: selectedCustomer!.customer_code },
{ columnName: "item_id", operator: "equals", value: itemKey },
]}, autoFilter: true,
});
const allMappings = mapRes.data?.data?.data || mapRes.data?.data?.rows || [];
mappingRows = allMappings
.filter((m: any) => m.customer_item_code || m.customer_item_name)
.map((m: any) => ({
_id: `m_existing_${m.id}`,
customer_item_code: m.customer_item_code || "",
customer_item_name: m.customer_item_name || "",
}));
} catch { /* skip */ }
// 기존 단가 데이터
const priceRows = [{
_id: `p_existing_${row.id}`,
start_date: row.start_date || "",
end_date: row.end_date || "",
currency_code: row.currency_code || "CAT_MLAMDKVN_PZJI",
base_price_type: row.base_price_type || "CAT_MLAMFGFT_4RZW",
base_price: row.base_price ? String(row.base_price) : "",
discount_type: row.discount_type || "",
discount_value: row.discount_value ? String(row.discount_value) : "",
rounding_type: row.rounding_type || "",
rounding_unit_value: row.rounding_unit_value || "",
calculated_price: row.calculated_price ? String(row.calculated_price) : "",
}].filter((p) => p.base_price || p.start_date);
// DB에서 해당 품목의 모든 기간별 단가 조회
let priceRows: any[] = [];
try {
const priceRes = await apiClient.post(`/table-management/tables/${PRICE_TABLE}/data`, {
page: 1, size: 100,
dataFilter: { enabled: true, filters: [
{ columnName: "customer_id", operator: "equals", value: selectedCustomer!.customer_code },
{ columnName: "item_id", operator: "equals", value: itemKey },
]}, autoFilter: true,
});
const allPriceData = priceRes.data?.data?.data || priceRes.data?.data?.rows || [];
priceRows = allPriceData.map((p: any) => ({
_id: `p_existing_${p.id}`,
start_date: p.start_date ? String(p.start_date).split("T")[0] : "",
end_date: p.end_date ? String(p.end_date).split("T")[0] : "",
currency_code: p.currency_code || "CAT_MLAMDKVN_PZJI",
base_price_type: p.base_price_type || "CAT_MLAMFGFT_4RZW",
base_price: p.base_price ? String(p.base_price) : "",
discount_type: p.discount_type || "",
discount_value: p.discount_value ? String(p.discount_value) : "",
rounding_type: p.rounding_type || "",
rounding_unit_value: p.rounding_unit_value || "",
calculated_price: p.calculated_price ? String(p.calculated_price) : "",
}));
} catch { /* skip */ }
// 빈 단가 행이 없으면 하나 추가
if (priceRows.length === 0) {

View File

@ -284,8 +284,8 @@ export default function CustomerManagementPage() {
} catch { /* skip */ }
}
// 3. customer_item_prices 조회 (단가 — 있으면 보강)
let priceMap: Record<string, any> = {};
// 3. customer_item_prices 조회
let allPrices: any[] = [];
if (mappings.length > 0) {
try {
const priceRes = await apiClient.post(`/table-management/tables/${PRICE_TABLE}/data`, {
@ -295,36 +295,43 @@ export default function CustomerManagementPage() {
]},
autoFilter: true,
});
const prices = priceRes.data?.data?.data || priceRes.data?.data?.rows || [];
// item_id별 최신 단가 매핑
for (const p of prices) {
const key = p.item_id;
if (!priceMap[key] || (p.start_date && (!priceMap[key].start_date || p.start_date > priceMap[key].start_date))) {
priceMap[key] = p;
}
}
allPrices = priceRes.data?.data?.data || priceRes.data?.data?.rows || [];
} catch { /* skip */ }
}
// 4. 매핑 + 품목정보 + 단가 병합 + 카테고리 코드→라벨
// 4. 매핑별 행 생성 + 오늘 날짜 기준 단가 + 같은 품목 첫 행만 품목코드/품명 표시
const priceResolve = (col: string, code: string) => {
if (!code) return "";
return priceCategoryOptions[col]?.find((o) => o.code === code)?.label || code;
};
setPriceItems(mappings.map((m: any) => {
const itemInfo = itemMap[m.item_id] || {};
const price = priceMap[m.item_id] || {};
const today = new Date().toISOString().split("T")[0];
const seenItemIds = new Set<string>();
// item_id로 정렬하여 같은 품목끼리 묶기
const sortedMappings = [...mappings].sort((a: any, b: any) => (a.item_id || "").localeCompare(b.item_id || ""));
setPriceItems(sortedMappings.map((m: any) => {
const itemKey = m.item_id || "";
const itemInfo = itemMap[itemKey] || {};
const isFirstOfGroup = !seenItemIds.has(itemKey);
if (itemKey) seenItemIds.add(itemKey);
// 오늘 날짜에 해당하는 단가
const itemPriceList = allPrices.filter((p: any) => p.item_id === itemKey);
const todayPrice = itemPriceList.find((p: any) =>
(!p.start_date || p.start_date <= today) && (!p.end_date || p.end_date >= today)
) || itemPriceList[0] || {};
return {
...m,
item_number: m.item_id,
item_name: itemInfo.item_name || "",
base_price_type: priceResolve("base_price_type", price.base_price_type || m.base_price_type || ""),
base_price: price.base_price || m.base_price || "",
discount_type: priceResolve("discount_type", price.discount_type || m.discount_type || ""),
discount_value: price.discount_value || m.discount_value || "",
rounding_type: priceResolve("rounding_unit_value", price.rounding_type || m.rounding_type || ""),
calculated_price: price.calculated_price || m.calculated_price || "",
currency_code: priceResolve("currency_code", price.currency_code || m.currency_code || ""),
item_number: isFirstOfGroup ? itemKey : "",
item_name: isFirstOfGroup ? (itemInfo.item_name || "") : "",
base_price_type: priceResolve("base_price_type", todayPrice.base_price_type || ""),
base_price: todayPrice.base_price || "",
discount_type: priceResolve("discount_type", todayPrice.discount_type || ""),
discount_value: todayPrice.discount_value || "",
calculated_price: todayPrice.calculated_price || todayPrice.unit_price || "",
currency_code: priceResolve("currency_code", todayPrice.currency_code || ""),
};
}));
} catch (err) {
@ -572,27 +579,51 @@ export default function CustomerManagementPage() {
if (found) itemInfo = found;
} catch { /* skip */ }
// 기존 매핑 데이터 → 거래처 품번/품명
const mappingRows = [{
_id: `m_existing_${row.id}`,
customer_item_code: row.customer_item_code || "",
customer_item_name: row.customer_item_name || "",
}].filter((m) => m.customer_item_code || m.customer_item_name);
// DB에서 해당 품목의 모든 매핑 조회
let mappingRows: any[] = [];
try {
const mapRes = await apiClient.post(`/table-management/tables/${MAPPING_TABLE}/data`, {
page: 1, size: 100,
dataFilter: { enabled: true, filters: [
{ columnName: "customer_id", operator: "equals", value: selectedCustomer!.customer_code },
{ columnName: "item_id", operator: "equals", value: itemKey },
]}, autoFilter: true,
});
const allMappings = mapRes.data?.data?.data || mapRes.data?.data?.rows || [];
mappingRows = allMappings
.filter((m: any) => m.customer_item_code || m.customer_item_name)
.map((m: any) => ({
_id: `m_existing_${m.id}`,
customer_item_code: m.customer_item_code || "",
customer_item_name: m.customer_item_name || "",
}));
} catch { /* skip */ }
// 기존 단가 데이터
const priceRows = [{
_id: `p_existing_${row.id}`,
start_date: row.start_date || "",
end_date: row.end_date || "",
currency_code: row.currency_code || "CAT_MLAMDKVN_PZJI",
base_price_type: row.base_price_type || "CAT_MLAMFGFT_4RZW",
base_price: row.base_price ? String(row.base_price) : "",
discount_type: row.discount_type || "",
discount_value: row.discount_value ? String(row.discount_value) : "",
rounding_type: row.rounding_type || "",
rounding_unit_value: row.rounding_unit_value || "",
calculated_price: row.calculated_price ? String(row.calculated_price) : "",
}].filter((p) => p.base_price || p.start_date);
// DB에서 해당 품목의 모든 기간별 단가 조회
let priceRows: any[] = [];
try {
const priceRes = await apiClient.post(`/table-management/tables/${PRICE_TABLE}/data`, {
page: 1, size: 100,
dataFilter: { enabled: true, filters: [
{ columnName: "customer_id", operator: "equals", value: selectedCustomer!.customer_code },
{ columnName: "item_id", operator: "equals", value: itemKey },
]}, autoFilter: true,
});
const allPriceData = priceRes.data?.data?.data || priceRes.data?.data?.rows || [];
priceRows = allPriceData.map((p: any) => ({
_id: `p_existing_${p.id}`,
start_date: p.start_date ? String(p.start_date).split("T")[0] : "",
end_date: p.end_date ? String(p.end_date).split("T")[0] : "",
currency_code: p.currency_code || "CAT_MLAMDKVN_PZJI",
base_price_type: p.base_price_type || "CAT_MLAMFGFT_4RZW",
base_price: p.base_price ? String(p.base_price) : "",
discount_type: p.discount_type || "",
discount_value: p.discount_value ? String(p.discount_value) : "",
rounding_type: p.rounding_type || "",
rounding_unit_value: p.rounding_unit_value || "",
calculated_price: p.calculated_price ? String(p.calculated_price) : "",
}));
} catch { /* skip */ }
// 빈 단가 행이 없으면 하나 추가
if (priceRows.length === 0) {