diff --git a/frontend/app/(main)/COMPANY_29/sales/customer/page.tsx b/frontend/app/(main)/COMPANY_29/sales/customer/page.tsx index c2d521f3..045679e5 100644 --- a/frontend/app/(main)/COMPANY_29/sales/customer/page.tsx +++ b/frontend/app/(main)/COMPANY_29/sales/customer/page.tsx @@ -284,8 +284,8 @@ export default function CustomerManagementPage() { } catch { /* skip */ } } - // 3. customer_item_prices 조회 (단가 — 있으면 보강) - let priceMap: Record = {}; + // 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(); + + // 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) { diff --git a/frontend/app/(main)/COMPANY_7/sales/customer/page.tsx b/frontend/app/(main)/COMPANY_7/sales/customer/page.tsx index c2d521f3..045679e5 100644 --- a/frontend/app/(main)/COMPANY_7/sales/customer/page.tsx +++ b/frontend/app/(main)/COMPANY_7/sales/customer/page.tsx @@ -284,8 +284,8 @@ export default function CustomerManagementPage() { } catch { /* skip */ } } - // 3. customer_item_prices 조회 (단가 — 있으면 보강) - let priceMap: Record = {}; + // 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(); + + // 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) {