fix: Correct SQL parameter indexing and improve date handling in various components
- Updated SQL query in `productionPlanService.ts` to fix parameter indexing for company code. - Refactored date handling in `department/page.tsx`, `customer/page.tsx`, and `sales-item/page.tsx` to ensure consistent date formatting. - Enhanced equipment list state management in `production/plan-management/page.tsx` to use more descriptive property names. These changes aim to improve the reliability of SQL operations and ensure consistent date handling across the application.
This commit is contained in:
@@ -371,7 +371,7 @@ export async function updatePlan(
|
||||
const query = `
|
||||
UPDATE production_plan_mng
|
||||
SET ${setClauses.join(", ")}
|
||||
WHERE id = $${paramIdx - 1} AND company_code = $${paramIdx}
|
||||
WHERE id = $${paramIdx} AND company_code = $${paramIdx + 1}
|
||||
RETURNING *
|
||||
`;
|
||||
|
||||
|
||||
@@ -309,7 +309,8 @@ export default function DepartmentPage() {
|
||||
};
|
||||
|
||||
// 퇴사일 기반 재직/퇴사 분리
|
||||
const today = new Date().toISOString().split("T")[0];
|
||||
const _now = new Date();
|
||||
const today = `${_now.getFullYear()}-${String(_now.getMonth() + 1).padStart(2, "0")}-${String(_now.getDate()).padStart(2, "0")}`;
|
||||
const activeMembers = members.filter((m) => !m.end_date || m.end_date.substring(0, 10) >= today);
|
||||
const resignedMembers = members.filter((m) => m.end_date && m.end_date.substring(0, 10) < today);
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ export default function ProductionPlanManagementPage() {
|
||||
const [stockItems, setStockItems] = useState<StockShortageItem[]>([]);
|
||||
const [finishedPlans, setFinishedPlans] = useState<ProductionPlan[]>([]);
|
||||
const [semiPlans, setSemiPlans] = useState<ProductionPlan[]>([]);
|
||||
const [equipmentList, setEquipmentList] = useState<{ equipment_id: string; equipment_name: string }[]>([]);
|
||||
const [equipmentList, setEquipmentList] = useState<{ id: string; equipment_code: string; equipment_name: string }[]>([]);
|
||||
|
||||
// 선택/토글 상태
|
||||
const [expandedItems, setExpandedItems] = useState<Set<string>>(new Set());
|
||||
@@ -659,7 +659,7 @@ export default function ProductionPlanManagementPage() {
|
||||
setModalManager((plan as any).manager_name || "");
|
||||
setModalWorkOrderNo((plan as any).work_order_no || "");
|
||||
setModalRemarks(plan.remarks || "");
|
||||
setModalEquipmentId(plan.equipment_id ? String(plan.equipment_id) : "");
|
||||
setModalEquipmentId((plan as any).equipment_code || (plan.equipment_id ? String(plan.equipment_id) : ""));
|
||||
setScheduleModalOpen(true);
|
||||
}, []);
|
||||
|
||||
@@ -1426,8 +1426,8 @@ export default function ProductionPlanManagementPage() {
|
||||
<SelectContent>
|
||||
<SelectItem value="none">미지정</SelectItem>
|
||||
{equipmentList.map((eq) => (
|
||||
<SelectItem key={eq.equipment_id} value={String(eq.equipment_id)}>
|
||||
{eq.equipment_name} ({eq.equipment_id})
|
||||
<SelectItem key={eq.id} value={eq.equipment_code || eq.id}>
|
||||
{eq.equipment_name} ({eq.equipment_code})
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
|
||||
@@ -345,7 +345,8 @@ export default function CustomerManagementPage() {
|
||||
if (!code) return "";
|
||||
return priceCategoryOptions[col]?.find((o) => o.code === code)?.label || code;
|
||||
};
|
||||
const today = new Date().toISOString().split("T")[0];
|
||||
const now = new Date();
|
||||
const today = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`;
|
||||
|
||||
// 품목 기준 그룹핑 — master: 첫 매핑 + 현재 단가, details: 전체 단가 리스트
|
||||
const grouped: Record<string, { master: any; details: any[] }> = {};
|
||||
@@ -810,11 +811,13 @@ export default function CustomerManagementPage() {
|
||||
const searchItems = async () => {
|
||||
setItemSearchLoading(true);
|
||||
try {
|
||||
const filters: any[] = [];
|
||||
const filters: any[] = [
|
||||
{ columnName: "division", operator: "contains", value: "CAT_ML8ZFVEL_1TOR" },
|
||||
];
|
||||
if (itemSearchKeyword) filters.push({ columnName: "item_name", operator: "contains", value: itemSearchKeyword });
|
||||
const res = await apiClient.post(`/table-management/tables/item_info/data`, {
|
||||
page: 1, size: 500,
|
||||
dataFilter: filters.length > 0 ? { enabled: true, filters } : undefined,
|
||||
dataFilter: { enabled: true, filters },
|
||||
autoFilter: true,
|
||||
});
|
||||
const allItems = res.data?.data?.data || res.data?.data?.rows || [];
|
||||
|
||||
@@ -402,32 +402,41 @@ export default function SalesItemPage() {
|
||||
if (found) custInfo = 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);
|
||||
|
||||
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);
|
||||
|
||||
if (priceRows.length === 0) {
|
||||
priceRows.push({
|
||||
_id: `p_${Date.now()}`, start_date: "", end_date: "", currency_code: "CAT_MLAMDKVN_PZJI",
|
||||
base_price_type: "CAT_MLAMFGFT_4RZW", base_price: "", discount_type: "", discount_value: "",
|
||||
rounding_type: "", rounding_unit_value: "", calculated_price: "",
|
||||
let mappingRows: any[] = [];
|
||||
try {
|
||||
const mapRes = await apiClient.post(`/table-management/tables/customer_item_mapping/data`, {
|
||||
page: 1, size: 100,
|
||||
dataFilter: { enabled: true, filters: [
|
||||
{ columnName: "customer_id", operator: "equals", value: custKey },
|
||||
{ columnName: "item_id", operator: "equals", value: selectedItem!.item_number },
|
||||
]}, 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 */ }
|
||||
let priceRows: any[] = [];
|
||||
try {
|
||||
const priceRes = await apiClient.post(`/table-management/tables/customer_item_prices/data`, {
|
||||
page: 1, size: 100,
|
||||
dataFilter: { enabled: true, filters: [
|
||||
{ columnName: "customer_id", operator: "equals", value: custKey },
|
||||
{ columnName: "item_id", operator: "equals", value: selectedItem!.item_number },
|
||||
]}, 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) {
|
||||
priceRows.push({ _id: `p_${Date.now()}`, start_date: "", end_date: "", currency_code: "CAT_MLAMDKVN_PZJI",
|
||||
base_price_type: "CAT_MLAMFGFT_4RZW", base_price: "", discount_type: "", discount_value: "",
|
||||
rounding_type: "", rounding_unit_value: "", calculated_price: "" });
|
||||
}
|
||||
|
||||
setSelectedCustsForDetail([custInfo]);
|
||||
@@ -782,23 +791,17 @@ export default function SalesItemPage() {
|
||||
"cursor-pointer h-[41px]",
|
||||
customerCheckedIds.includes(row.id) ? "bg-primary/[0.08]" : "hover:bg-accent"
|
||||
)}
|
||||
onClick={() => {
|
||||
setCustomerCheckedIds((prev) =>
|
||||
prev.includes(row.id) ? prev.filter((id) => id !== row.id) : [...prev, row.id]
|
||||
);
|
||||
}}
|
||||
onDoubleClick={() => openEditCust(row)}
|
||||
>
|
||||
<TableCell
|
||||
className="text-center px-2"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setCustomerCheckedIds((prev) =>
|
||||
prev.includes(row.id) ? prev.filter((id) => id !== row.id) : [...prev, row.id]
|
||||
);
|
||||
}}
|
||||
>
|
||||
<TableCell className="text-center px-2">
|
||||
<Checkbox
|
||||
checked={customerCheckedIds.includes(row.id)}
|
||||
onCheckedChange={(checked) => {
|
||||
if (checked === true) setCustomerCheckedIds((prev) => [...prev, row.id]);
|
||||
else setCustomerCheckedIds((prev) => prev.filter((id) => id !== row.id));
|
||||
}}
|
||||
onCheckedChange={() => {}}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className="text-[13px] font-mono text-muted-foreground">{row.customer_code}</TableCell>
|
||||
|
||||
@@ -309,7 +309,8 @@ export default function DepartmentPage() {
|
||||
};
|
||||
|
||||
// 퇴사일 기반 재직/퇴사 분리
|
||||
const today = new Date().toISOString().split("T")[0];
|
||||
const _now = new Date();
|
||||
const today = `${_now.getFullYear()}-${String(_now.getMonth() + 1).padStart(2, "0")}-${String(_now.getDate()).padStart(2, "0")}`;
|
||||
const activeMembers = members.filter((m) => !m.end_date || m.end_date.substring(0, 10) >= today);
|
||||
const resignedMembers = members.filter((m) => m.end_date && m.end_date.substring(0, 10) < today);
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ export default function ProductionPlanManagementPage() {
|
||||
const [stockItems, setStockItems] = useState<StockShortageItem[]>([]);
|
||||
const [finishedPlans, setFinishedPlans] = useState<ProductionPlan[]>([]);
|
||||
const [semiPlans, setSemiPlans] = useState<ProductionPlan[]>([]);
|
||||
const [equipmentList, setEquipmentList] = useState<{ equipment_id: string; equipment_name: string }[]>([]);
|
||||
const [equipmentList, setEquipmentList] = useState<{ id: string; equipment_code: string; equipment_name: string }[]>([]);
|
||||
|
||||
// 선택/토글 상태
|
||||
const [expandedItems, setExpandedItems] = useState<Set<string>>(new Set());
|
||||
@@ -659,7 +659,7 @@ export default function ProductionPlanManagementPage() {
|
||||
setModalManager((plan as any).manager_name || "");
|
||||
setModalWorkOrderNo((plan as any).work_order_no || "");
|
||||
setModalRemarks(plan.remarks || "");
|
||||
setModalEquipmentId(plan.equipment_id ? String(plan.equipment_id) : "");
|
||||
setModalEquipmentId((plan as any).equipment_code || (plan.equipment_id ? String(plan.equipment_id) : ""));
|
||||
setScheduleModalOpen(true);
|
||||
}, []);
|
||||
|
||||
@@ -674,7 +674,10 @@ export default function ProductionPlanManagementPage() {
|
||||
manager_name: modalManager,
|
||||
work_order_no: modalWorkOrderNo,
|
||||
remarks: modalRemarks,
|
||||
equipment_id: modalEquipmentId ? Number(modalEquipmentId) : null,
|
||||
equipment_code: modalEquipmentId && modalEquipmentId !== "none" ? modalEquipmentId : null,
|
||||
equipment_name: modalEquipmentId && modalEquipmentId !== "none"
|
||||
? equipmentList.find((eq) => (eq.equipment_code || eq.id) === modalEquipmentId)?.equipment_name || null
|
||||
: null,
|
||||
} as any);
|
||||
if (res.success) {
|
||||
toast.success("생산계획이 수정되었습니다");
|
||||
@@ -1426,8 +1429,8 @@ export default function ProductionPlanManagementPage() {
|
||||
<SelectContent>
|
||||
<SelectItem value="none">미지정</SelectItem>
|
||||
{equipmentList.map((eq) => (
|
||||
<SelectItem key={eq.equipment_id} value={String(eq.equipment_id)}>
|
||||
{eq.equipment_name} ({eq.equipment_id})
|
||||
<SelectItem key={eq.id} value={eq.equipment_code || eq.id}>
|
||||
{eq.equipment_name} ({eq.equipment_code})
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
|
||||
@@ -345,7 +345,8 @@ export default function CustomerManagementPage() {
|
||||
if (!code) return "";
|
||||
return priceCategoryOptions[col]?.find((o) => o.code === code)?.label || code;
|
||||
};
|
||||
const today = new Date().toISOString().split("T")[0];
|
||||
const now = new Date();
|
||||
const today = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`;
|
||||
|
||||
// 품목 기준 그룹핑 — master: 첫 매핑 + 현재 단가, details: 전체 단가 리스트
|
||||
const grouped: Record<string, { master: any; details: any[] }> = {};
|
||||
@@ -810,11 +811,13 @@ export default function CustomerManagementPage() {
|
||||
const searchItems = async () => {
|
||||
setItemSearchLoading(true);
|
||||
try {
|
||||
const filters: any[] = [];
|
||||
const filters: any[] = [
|
||||
{ columnName: "division", operator: "contains", value: "CAT_ML8ZFVEL_1TOR" },
|
||||
];
|
||||
if (itemSearchKeyword) filters.push({ columnName: "item_name", operator: "contains", value: itemSearchKeyword });
|
||||
const res = await apiClient.post(`/table-management/tables/item_info/data`, {
|
||||
page: 1, size: 500,
|
||||
dataFilter: filters.length > 0 ? { enabled: true, filters } : undefined,
|
||||
dataFilter: { enabled: true, filters },
|
||||
autoFilter: true,
|
||||
});
|
||||
const allItems = res.data?.data?.data || res.data?.data?.rows || [];
|
||||
|
||||
@@ -402,25 +402,51 @@ export default function SalesItemPage() {
|
||||
if (found) custInfo = 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);
|
||||
// 매핑 조회
|
||||
let mappingRows: any[] = [];
|
||||
try {
|
||||
const mapRes = await apiClient.post(`/table-management/tables/customer_item_mapping/data`, {
|
||||
page: 1, size: 100,
|
||||
dataFilter: { enabled: true, filters: [
|
||||
{ columnName: "customer_id", operator: "equals", value: custKey },
|
||||
{ columnName: "item_id", operator: "equals", value: selectedItem!.item_number },
|
||||
]}, 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);
|
||||
// 단가 전체 조회
|
||||
let priceRows: any[] = [];
|
||||
try {
|
||||
const priceRes = await apiClient.post(`/table-management/tables/customer_item_prices/data`, {
|
||||
page: 1, size: 100,
|
||||
dataFilter: { enabled: true, filters: [
|
||||
{ columnName: "customer_id", operator: "equals", value: custKey },
|
||||
{ columnName: "item_id", operator: "equals", value: selectedItem!.item_number },
|
||||
]}, 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) {
|
||||
priceRows.push({
|
||||
@@ -782,23 +808,17 @@ export default function SalesItemPage() {
|
||||
"cursor-pointer h-[41px]",
|
||||
customerCheckedIds.includes(row.id) ? "bg-primary/[0.08]" : "hover:bg-accent"
|
||||
)}
|
||||
onClick={() => {
|
||||
setCustomerCheckedIds((prev) =>
|
||||
prev.includes(row.id) ? prev.filter((id) => id !== row.id) : [...prev, row.id]
|
||||
);
|
||||
}}
|
||||
onDoubleClick={() => openEditCust(row)}
|
||||
>
|
||||
<TableCell
|
||||
className="text-center px-2"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setCustomerCheckedIds((prev) =>
|
||||
prev.includes(row.id) ? prev.filter((id) => id !== row.id) : [...prev, row.id]
|
||||
);
|
||||
}}
|
||||
>
|
||||
<TableCell className="text-center px-2">
|
||||
<Checkbox
|
||||
checked={customerCheckedIds.includes(row.id)}
|
||||
onCheckedChange={(checked) => {
|
||||
if (checked === true) setCustomerCheckedIds((prev) => [...prev, row.id]);
|
||||
else setCustomerCheckedIds((prev) => prev.filter((id) => id !== row.id));
|
||||
}}
|
||||
onCheckedChange={() => {}}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className="text-[13px] font-mono text-muted-foreground">{row.customer_code}</TableCell>
|
||||
|
||||
@@ -309,7 +309,8 @@ export default function DepartmentPage() {
|
||||
};
|
||||
|
||||
// 퇴사일 기반 재직/퇴사 분리
|
||||
const today = new Date().toISOString().split("T")[0];
|
||||
const _now = new Date();
|
||||
const today = `${_now.getFullYear()}-${String(_now.getMonth() + 1).padStart(2, "0")}-${String(_now.getDate()).padStart(2, "0")}`;
|
||||
const activeMembers = members.filter((m) => !m.end_date || m.end_date.substring(0, 10) >= today);
|
||||
const resignedMembers = members.filter((m) => m.end_date && m.end_date.substring(0, 10) < today);
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ export default function ProductionPlanManagementPage() {
|
||||
const [stockItems, setStockItems] = useState<StockShortageItem[]>([]);
|
||||
const [finishedPlans, setFinishedPlans] = useState<ProductionPlan[]>([]);
|
||||
const [semiPlans, setSemiPlans] = useState<ProductionPlan[]>([]);
|
||||
const [equipmentList, setEquipmentList] = useState<{ equipment_id: string; equipment_name: string }[]>([]);
|
||||
const [equipmentList, setEquipmentList] = useState<{ id: string; equipment_code: string; equipment_name: string }[]>([]);
|
||||
|
||||
// 선택/토글 상태
|
||||
const [expandedItems, setExpandedItems] = useState<Set<string>>(new Set());
|
||||
@@ -659,7 +659,7 @@ export default function ProductionPlanManagementPage() {
|
||||
setModalManager((plan as any).manager_name || "");
|
||||
setModalWorkOrderNo((plan as any).work_order_no || "");
|
||||
setModalRemarks(plan.remarks || "");
|
||||
setModalEquipmentId(plan.equipment_id ? String(plan.equipment_id) : "");
|
||||
setModalEquipmentId((plan as any).equipment_code || (plan.equipment_id ? String(plan.equipment_id) : ""));
|
||||
setScheduleModalOpen(true);
|
||||
}, []);
|
||||
|
||||
@@ -1426,8 +1426,8 @@ export default function ProductionPlanManagementPage() {
|
||||
<SelectContent>
|
||||
<SelectItem value="none">미지정</SelectItem>
|
||||
{equipmentList.map((eq) => (
|
||||
<SelectItem key={eq.equipment_id} value={String(eq.equipment_id)}>
|
||||
{eq.equipment_name} ({eq.equipment_id})
|
||||
<SelectItem key={eq.id} value={eq.equipment_code || eq.id}>
|
||||
{eq.equipment_name} ({eq.equipment_code})
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
|
||||
@@ -345,7 +345,8 @@ export default function CustomerManagementPage() {
|
||||
if (!code) return "";
|
||||
return priceCategoryOptions[col]?.find((o) => o.code === code)?.label || code;
|
||||
};
|
||||
const today = new Date().toISOString().split("T")[0];
|
||||
const now = new Date();
|
||||
const today = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`;
|
||||
|
||||
// 품목 기준 그룹핑 — master: 첫 매핑 + 현재 단가, details: 전체 단가 리스트
|
||||
const grouped: Record<string, { master: any; details: any[] }> = {};
|
||||
@@ -810,11 +811,13 @@ export default function CustomerManagementPage() {
|
||||
const searchItems = async () => {
|
||||
setItemSearchLoading(true);
|
||||
try {
|
||||
const filters: any[] = [];
|
||||
const filters: any[] = [
|
||||
{ columnName: "division", operator: "contains", value: "CAT_ML8ZFVEL_1TOR" },
|
||||
];
|
||||
if (itemSearchKeyword) filters.push({ columnName: "item_name", operator: "contains", value: itemSearchKeyword });
|
||||
const res = await apiClient.post(`/table-management/tables/item_info/data`, {
|
||||
page: 1, size: 500,
|
||||
dataFilter: filters.length > 0 ? { enabled: true, filters } : undefined,
|
||||
dataFilter: { enabled: true, filters },
|
||||
autoFilter: true,
|
||||
});
|
||||
const allItems = res.data?.data?.data || res.data?.data?.rows || [];
|
||||
|
||||
@@ -402,32 +402,41 @@ export default function SalesItemPage() {
|
||||
if (found) custInfo = 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);
|
||||
|
||||
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);
|
||||
|
||||
if (priceRows.length === 0) {
|
||||
priceRows.push({
|
||||
_id: `p_${Date.now()}`, start_date: "", end_date: "", currency_code: "CAT_MLAMDKVN_PZJI",
|
||||
base_price_type: "CAT_MLAMFGFT_4RZW", base_price: "", discount_type: "", discount_value: "",
|
||||
rounding_type: "", rounding_unit_value: "", calculated_price: "",
|
||||
let mappingRows: any[] = [];
|
||||
try {
|
||||
const mapRes = await apiClient.post(`/table-management/tables/customer_item_mapping/data`, {
|
||||
page: 1, size: 100,
|
||||
dataFilter: { enabled: true, filters: [
|
||||
{ columnName: "customer_id", operator: "equals", value: custKey },
|
||||
{ columnName: "item_id", operator: "equals", value: selectedItem!.item_number },
|
||||
]}, 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 */ }
|
||||
let priceRows: any[] = [];
|
||||
try {
|
||||
const priceRes = await apiClient.post(`/table-management/tables/customer_item_prices/data`, {
|
||||
page: 1, size: 100,
|
||||
dataFilter: { enabled: true, filters: [
|
||||
{ columnName: "customer_id", operator: "equals", value: custKey },
|
||||
{ columnName: "item_id", operator: "equals", value: selectedItem!.item_number },
|
||||
]}, 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) {
|
||||
priceRows.push({ _id: `p_${Date.now()}`, start_date: "", end_date: "", currency_code: "CAT_MLAMDKVN_PZJI",
|
||||
base_price_type: "CAT_MLAMFGFT_4RZW", base_price: "", discount_type: "", discount_value: "",
|
||||
rounding_type: "", rounding_unit_value: "", calculated_price: "" });
|
||||
}
|
||||
|
||||
setSelectedCustsForDetail([custInfo]);
|
||||
@@ -782,23 +791,17 @@ export default function SalesItemPage() {
|
||||
"cursor-pointer h-[41px]",
|
||||
customerCheckedIds.includes(row.id) ? "bg-primary/[0.08]" : "hover:bg-accent"
|
||||
)}
|
||||
onClick={() => {
|
||||
setCustomerCheckedIds((prev) =>
|
||||
prev.includes(row.id) ? prev.filter((id) => id !== row.id) : [...prev, row.id]
|
||||
);
|
||||
}}
|
||||
onDoubleClick={() => openEditCust(row)}
|
||||
>
|
||||
<TableCell
|
||||
className="text-center px-2"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setCustomerCheckedIds((prev) =>
|
||||
prev.includes(row.id) ? prev.filter((id) => id !== row.id) : [...prev, row.id]
|
||||
);
|
||||
}}
|
||||
>
|
||||
<TableCell className="text-center px-2">
|
||||
<Checkbox
|
||||
checked={customerCheckedIds.includes(row.id)}
|
||||
onCheckedChange={(checked) => {
|
||||
if (checked === true) setCustomerCheckedIds((prev) => [...prev, row.id]);
|
||||
else setCustomerCheckedIds((prev) => prev.filter((id) => id !== row.id));
|
||||
}}
|
||||
onCheckedChange={() => {}}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className="text-[13px] font-mono text-muted-foreground">{row.customer_code}</TableCell>
|
||||
|
||||
@@ -309,7 +309,8 @@ export default function DepartmentPage() {
|
||||
};
|
||||
|
||||
// 퇴사일 기반 재직/퇴사 분리
|
||||
const today = new Date().toISOString().split("T")[0];
|
||||
const _now = new Date();
|
||||
const today = `${_now.getFullYear()}-${String(_now.getMonth() + 1).padStart(2, "0")}-${String(_now.getDate()).padStart(2, "0")}`;
|
||||
const activeMembers = members.filter((m) => !m.end_date || m.end_date.substring(0, 10) >= today);
|
||||
const resignedMembers = members.filter((m) => m.end_date && m.end_date.substring(0, 10) < today);
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ export default function ProductionPlanManagementPage() {
|
||||
const [stockItems, setStockItems] = useState<StockShortageItem[]>([]);
|
||||
const [finishedPlans, setFinishedPlans] = useState<ProductionPlan[]>([]);
|
||||
const [semiPlans, setSemiPlans] = useState<ProductionPlan[]>([]);
|
||||
const [equipmentList, setEquipmentList] = useState<{ equipment_id: string; equipment_name: string }[]>([]);
|
||||
const [equipmentList, setEquipmentList] = useState<{ id: string; equipment_code: string; equipment_name: string }[]>([]);
|
||||
|
||||
// 선택/토글 상태
|
||||
const [expandedItems, setExpandedItems] = useState<Set<string>>(new Set());
|
||||
@@ -659,7 +659,7 @@ export default function ProductionPlanManagementPage() {
|
||||
setModalManager((plan as any).manager_name || "");
|
||||
setModalWorkOrderNo((plan as any).work_order_no || "");
|
||||
setModalRemarks(plan.remarks || "");
|
||||
setModalEquipmentId(plan.equipment_id ? String(plan.equipment_id) : "");
|
||||
setModalEquipmentId((plan as any).equipment_code || (plan.equipment_id ? String(plan.equipment_id) : ""));
|
||||
setScheduleModalOpen(true);
|
||||
}, []);
|
||||
|
||||
@@ -1426,8 +1426,8 @@ export default function ProductionPlanManagementPage() {
|
||||
<SelectContent>
|
||||
<SelectItem value="none">미지정</SelectItem>
|
||||
{equipmentList.map((eq) => (
|
||||
<SelectItem key={eq.equipment_id} value={String(eq.equipment_id)}>
|
||||
{eq.equipment_name} ({eq.equipment_id})
|
||||
<SelectItem key={eq.id} value={eq.equipment_code || eq.id}>
|
||||
{eq.equipment_name} ({eq.equipment_code})
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
|
||||
@@ -345,7 +345,8 @@ export default function CustomerManagementPage() {
|
||||
if (!code) return "";
|
||||
return priceCategoryOptions[col]?.find((o) => o.code === code)?.label || code;
|
||||
};
|
||||
const today = new Date().toISOString().split("T")[0];
|
||||
const now = new Date();
|
||||
const today = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`;
|
||||
|
||||
// 품목 기준 그룹핑 — master: 첫 매핑 + 현재 단가, details: 전체 단가 리스트
|
||||
const grouped: Record<string, { master: any; details: any[] }> = {};
|
||||
@@ -810,11 +811,13 @@ export default function CustomerManagementPage() {
|
||||
const searchItems = async () => {
|
||||
setItemSearchLoading(true);
|
||||
try {
|
||||
const filters: any[] = [];
|
||||
const filters: any[] = [
|
||||
{ columnName: "division", operator: "contains", value: "CAT_ML8ZFVEL_1TOR" },
|
||||
];
|
||||
if (itemSearchKeyword) filters.push({ columnName: "item_name", operator: "contains", value: itemSearchKeyword });
|
||||
const res = await apiClient.post(`/table-management/tables/item_info/data`, {
|
||||
page: 1, size: 500,
|
||||
dataFilter: filters.length > 0 ? { enabled: true, filters } : undefined,
|
||||
dataFilter: { enabled: true, filters },
|
||||
autoFilter: true,
|
||||
});
|
||||
const allItems = res.data?.data?.data || res.data?.data?.rows || [];
|
||||
|
||||
@@ -402,32 +402,41 @@ export default function SalesItemPage() {
|
||||
if (found) custInfo = 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);
|
||||
|
||||
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);
|
||||
|
||||
if (priceRows.length === 0) {
|
||||
priceRows.push({
|
||||
_id: `p_${Date.now()}`, start_date: "", end_date: "", currency_code: "CAT_MLAMDKVN_PZJI",
|
||||
base_price_type: "CAT_MLAMFGFT_4RZW", base_price: "", discount_type: "", discount_value: "",
|
||||
rounding_type: "", rounding_unit_value: "", calculated_price: "",
|
||||
let mappingRows: any[] = [];
|
||||
try {
|
||||
const mapRes = await apiClient.post(`/table-management/tables/customer_item_mapping/data`, {
|
||||
page: 1, size: 100,
|
||||
dataFilter: { enabled: true, filters: [
|
||||
{ columnName: "customer_id", operator: "equals", value: custKey },
|
||||
{ columnName: "item_id", operator: "equals", value: selectedItem!.item_number },
|
||||
]}, 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 */ }
|
||||
let priceRows: any[] = [];
|
||||
try {
|
||||
const priceRes = await apiClient.post(`/table-management/tables/customer_item_prices/data`, {
|
||||
page: 1, size: 100,
|
||||
dataFilter: { enabled: true, filters: [
|
||||
{ columnName: "customer_id", operator: "equals", value: custKey },
|
||||
{ columnName: "item_id", operator: "equals", value: selectedItem!.item_number },
|
||||
]}, 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) {
|
||||
priceRows.push({ _id: `p_${Date.now()}`, start_date: "", end_date: "", currency_code: "CAT_MLAMDKVN_PZJI",
|
||||
base_price_type: "CAT_MLAMFGFT_4RZW", base_price: "", discount_type: "", discount_value: "",
|
||||
rounding_type: "", rounding_unit_value: "", calculated_price: "" });
|
||||
}
|
||||
|
||||
setSelectedCustsForDetail([custInfo]);
|
||||
@@ -782,23 +791,17 @@ export default function SalesItemPage() {
|
||||
"cursor-pointer h-[41px]",
|
||||
customerCheckedIds.includes(row.id) ? "bg-primary/[0.08]" : "hover:bg-accent"
|
||||
)}
|
||||
onClick={() => {
|
||||
setCustomerCheckedIds((prev) =>
|
||||
prev.includes(row.id) ? prev.filter((id) => id !== row.id) : [...prev, row.id]
|
||||
);
|
||||
}}
|
||||
onDoubleClick={() => openEditCust(row)}
|
||||
>
|
||||
<TableCell
|
||||
className="text-center px-2"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setCustomerCheckedIds((prev) =>
|
||||
prev.includes(row.id) ? prev.filter((id) => id !== row.id) : [...prev, row.id]
|
||||
);
|
||||
}}
|
||||
>
|
||||
<TableCell className="text-center px-2">
|
||||
<Checkbox
|
||||
checked={customerCheckedIds.includes(row.id)}
|
||||
onCheckedChange={(checked) => {
|
||||
if (checked === true) setCustomerCheckedIds((prev) => [...prev, row.id]);
|
||||
else setCustomerCheckedIds((prev) => prev.filter((id) => id !== row.id));
|
||||
}}
|
||||
onCheckedChange={() => {}}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className="text-[13px] font-mono text-muted-foreground">{row.customer_code}</TableCell>
|
||||
|
||||
@@ -309,7 +309,8 @@ export default function DepartmentPage() {
|
||||
};
|
||||
|
||||
// 퇴사일 기반 재직/퇴사 분리
|
||||
const today = new Date().toISOString().split("T")[0];
|
||||
const _now = new Date();
|
||||
const today = `${_now.getFullYear()}-${String(_now.getMonth() + 1).padStart(2, "0")}-${String(_now.getDate()).padStart(2, "0")}`;
|
||||
const activeMembers = members.filter((m) => !m.end_date || m.end_date.substring(0, 10) >= today);
|
||||
const resignedMembers = members.filter((m) => m.end_date && m.end_date.substring(0, 10) < today);
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ export default function ProductionPlanManagementPage() {
|
||||
const [stockItems, setStockItems] = useState<StockShortageItem[]>([]);
|
||||
const [finishedPlans, setFinishedPlans] = useState<ProductionPlan[]>([]);
|
||||
const [semiPlans, setSemiPlans] = useState<ProductionPlan[]>([]);
|
||||
const [equipmentList, setEquipmentList] = useState<{ equipment_id: string; equipment_name: string }[]>([]);
|
||||
const [equipmentList, setEquipmentList] = useState<{ id: string; equipment_code: string; equipment_name: string }[]>([]);
|
||||
|
||||
// 선택/토글 상태
|
||||
const [expandedItems, setExpandedItems] = useState<Set<string>>(new Set());
|
||||
@@ -659,7 +659,7 @@ export default function ProductionPlanManagementPage() {
|
||||
setModalManager((plan as any).manager_name || "");
|
||||
setModalWorkOrderNo((plan as any).work_order_no || "");
|
||||
setModalRemarks(plan.remarks || "");
|
||||
setModalEquipmentId(plan.equipment_id ? String(plan.equipment_id) : "");
|
||||
setModalEquipmentId((plan as any).equipment_code || (plan.equipment_id ? String(plan.equipment_id) : ""));
|
||||
setScheduleModalOpen(true);
|
||||
}, []);
|
||||
|
||||
@@ -1426,8 +1426,8 @@ export default function ProductionPlanManagementPage() {
|
||||
<SelectContent>
|
||||
<SelectItem value="none">미지정</SelectItem>
|
||||
{equipmentList.map((eq) => (
|
||||
<SelectItem key={eq.equipment_id} value={String(eq.equipment_id)}>
|
||||
{eq.equipment_name} ({eq.equipment_id})
|
||||
<SelectItem key={eq.id} value={eq.equipment_code || eq.id}>
|
||||
{eq.equipment_name} ({eq.equipment_code})
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
|
||||
@@ -345,7 +345,8 @@ export default function CustomerManagementPage() {
|
||||
if (!code) return "";
|
||||
return priceCategoryOptions[col]?.find((o) => o.code === code)?.label || code;
|
||||
};
|
||||
const today = new Date().toISOString().split("T")[0];
|
||||
const now = new Date();
|
||||
const today = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`;
|
||||
|
||||
// 품목 기준 그룹핑 — master: 첫 매핑 + 현재 단가, details: 전체 단가 리스트
|
||||
const grouped: Record<string, { master: any; details: any[] }> = {};
|
||||
@@ -810,11 +811,13 @@ export default function CustomerManagementPage() {
|
||||
const searchItems = async () => {
|
||||
setItemSearchLoading(true);
|
||||
try {
|
||||
const filters: any[] = [];
|
||||
const filters: any[] = [
|
||||
{ columnName: "division", operator: "contains", value: "CAT_ML8ZFVEL_1TOR" },
|
||||
];
|
||||
if (itemSearchKeyword) filters.push({ columnName: "item_name", operator: "contains", value: itemSearchKeyword });
|
||||
const res = await apiClient.post(`/table-management/tables/item_info/data`, {
|
||||
page: 1, size: 500,
|
||||
dataFilter: filters.length > 0 ? { enabled: true, filters } : undefined,
|
||||
dataFilter: { enabled: true, filters },
|
||||
autoFilter: true,
|
||||
});
|
||||
const allItems = res.data?.data?.data || res.data?.data?.rows || [];
|
||||
|
||||
@@ -402,25 +402,51 @@ export default function SalesItemPage() {
|
||||
if (found) custInfo = 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);
|
||||
// 매핑 조회
|
||||
let mappingRows: any[] = [];
|
||||
try {
|
||||
const mapRes = await apiClient.post(`/table-management/tables/customer_item_mapping/data`, {
|
||||
page: 1, size: 100,
|
||||
dataFilter: { enabled: true, filters: [
|
||||
{ columnName: "customer_id", operator: "equals", value: custKey },
|
||||
{ columnName: "item_id", operator: "equals", value: selectedItem!.item_number },
|
||||
]}, 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);
|
||||
// 단가 전체 조회
|
||||
let priceRows: any[] = [];
|
||||
try {
|
||||
const priceRes = await apiClient.post(`/table-management/tables/customer_item_prices/data`, {
|
||||
page: 1, size: 100,
|
||||
dataFilter: { enabled: true, filters: [
|
||||
{ columnName: "customer_id", operator: "equals", value: custKey },
|
||||
{ columnName: "item_id", operator: "equals", value: selectedItem!.item_number },
|
||||
]}, 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) {
|
||||
priceRows.push({
|
||||
@@ -782,23 +808,17 @@ export default function SalesItemPage() {
|
||||
"cursor-pointer h-[41px]",
|
||||
customerCheckedIds.includes(row.id) ? "bg-primary/[0.08]" : "hover:bg-accent"
|
||||
)}
|
||||
onClick={() => {
|
||||
setCustomerCheckedIds((prev) =>
|
||||
prev.includes(row.id) ? prev.filter((id) => id !== row.id) : [...prev, row.id]
|
||||
);
|
||||
}}
|
||||
onDoubleClick={() => openEditCust(row)}
|
||||
>
|
||||
<TableCell
|
||||
className="text-center px-2"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setCustomerCheckedIds((prev) =>
|
||||
prev.includes(row.id) ? prev.filter((id) => id !== row.id) : [...prev, row.id]
|
||||
);
|
||||
}}
|
||||
>
|
||||
<TableCell className="text-center px-2">
|
||||
<Checkbox
|
||||
checked={customerCheckedIds.includes(row.id)}
|
||||
onCheckedChange={(checked) => {
|
||||
if (checked === true) setCustomerCheckedIds((prev) => [...prev, row.id]);
|
||||
else setCustomerCheckedIds((prev) => prev.filter((id) => id !== row.id));
|
||||
}}
|
||||
onCheckedChange={() => {}}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className="text-[13px] font-mono text-muted-foreground">{row.customer_code}</TableCell>
|
||||
|
||||
@@ -309,7 +309,8 @@ export default function DepartmentPage() {
|
||||
};
|
||||
|
||||
// 퇴사일 기반 재직/퇴사 분리
|
||||
const today = new Date().toISOString().split("T")[0];
|
||||
const _now = new Date();
|
||||
const today = `${_now.getFullYear()}-${String(_now.getMonth() + 1).padStart(2, "0")}-${String(_now.getDate()).padStart(2, "0")}`;
|
||||
const activeMembers = members.filter((m) => !m.end_date || m.end_date.substring(0, 10) >= today);
|
||||
const resignedMembers = members.filter((m) => m.end_date && m.end_date.substring(0, 10) < today);
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ export default function ProductionPlanManagementPage() {
|
||||
const [stockItems, setStockItems] = useState<StockShortageItem[]>([]);
|
||||
const [finishedPlans, setFinishedPlans] = useState<ProductionPlan[]>([]);
|
||||
const [semiPlans, setSemiPlans] = useState<ProductionPlan[]>([]);
|
||||
const [equipmentList, setEquipmentList] = useState<{ equipment_id: string; equipment_name: string }[]>([]);
|
||||
const [equipmentList, setEquipmentList] = useState<{ id: string; equipment_code: string; equipment_name: string }[]>([]);
|
||||
|
||||
// 선택/토글 상태
|
||||
const [expandedItems, setExpandedItems] = useState<Set<string>>(new Set());
|
||||
@@ -659,7 +659,7 @@ export default function ProductionPlanManagementPage() {
|
||||
setModalManager((plan as any).manager_name || "");
|
||||
setModalWorkOrderNo((plan as any).work_order_no || "");
|
||||
setModalRemarks(plan.remarks || "");
|
||||
setModalEquipmentId(plan.equipment_id ? String(plan.equipment_id) : "");
|
||||
setModalEquipmentId((plan as any).equipment_code || (plan.equipment_id ? String(plan.equipment_id) : ""));
|
||||
setScheduleModalOpen(true);
|
||||
}, []);
|
||||
|
||||
@@ -1426,8 +1426,8 @@ export default function ProductionPlanManagementPage() {
|
||||
<SelectContent>
|
||||
<SelectItem value="none">미지정</SelectItem>
|
||||
{equipmentList.map((eq) => (
|
||||
<SelectItem key={eq.equipment_id} value={String(eq.equipment_id)}>
|
||||
{eq.equipment_name} ({eq.equipment_id})
|
||||
<SelectItem key={eq.id} value={eq.equipment_code || eq.id}>
|
||||
{eq.equipment_name} ({eq.equipment_code})
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
|
||||
@@ -345,7 +345,8 @@ export default function CustomerManagementPage() {
|
||||
if (!code) return "";
|
||||
return priceCategoryOptions[col]?.find((o) => o.code === code)?.label || code;
|
||||
};
|
||||
const today = new Date().toISOString().split("T")[0];
|
||||
const now = new Date();
|
||||
const today = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`;
|
||||
|
||||
// 품목 기준 그룹핑 — master: 첫 매핑 + 현재 단가, details: 전체 단가 리스트
|
||||
const grouped: Record<string, { master: any; details: any[] }> = {};
|
||||
@@ -810,11 +811,13 @@ export default function CustomerManagementPage() {
|
||||
const searchItems = async () => {
|
||||
setItemSearchLoading(true);
|
||||
try {
|
||||
const filters: any[] = [];
|
||||
const filters: any[] = [
|
||||
{ columnName: "division", operator: "contains", value: "CAT_ML8ZFVEL_1TOR" },
|
||||
];
|
||||
if (itemSearchKeyword) filters.push({ columnName: "item_name", operator: "contains", value: itemSearchKeyword });
|
||||
const res = await apiClient.post(`/table-management/tables/item_info/data`, {
|
||||
page: 1, size: 500,
|
||||
dataFilter: filters.length > 0 ? { enabled: true, filters } : undefined,
|
||||
dataFilter: { enabled: true, filters },
|
||||
autoFilter: true,
|
||||
});
|
||||
const allItems = res.data?.data?.data || res.data?.data?.rows || [];
|
||||
|
||||
@@ -402,32 +402,41 @@ export default function SalesItemPage() {
|
||||
if (found) custInfo = 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);
|
||||
|
||||
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);
|
||||
|
||||
if (priceRows.length === 0) {
|
||||
priceRows.push({
|
||||
_id: `p_${Date.now()}`, start_date: "", end_date: "", currency_code: "CAT_MLAMDKVN_PZJI",
|
||||
base_price_type: "CAT_MLAMFGFT_4RZW", base_price: "", discount_type: "", discount_value: "",
|
||||
rounding_type: "", rounding_unit_value: "", calculated_price: "",
|
||||
let mappingRows: any[] = [];
|
||||
try {
|
||||
const mapRes = await apiClient.post(`/table-management/tables/customer_item_mapping/data`, {
|
||||
page: 1, size: 100,
|
||||
dataFilter: { enabled: true, filters: [
|
||||
{ columnName: "customer_id", operator: "equals", value: custKey },
|
||||
{ columnName: "item_id", operator: "equals", value: selectedItem!.item_number },
|
||||
]}, 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 */ }
|
||||
let priceRows: any[] = [];
|
||||
try {
|
||||
const priceRes = await apiClient.post(`/table-management/tables/customer_item_prices/data`, {
|
||||
page: 1, size: 100,
|
||||
dataFilter: { enabled: true, filters: [
|
||||
{ columnName: "customer_id", operator: "equals", value: custKey },
|
||||
{ columnName: "item_id", operator: "equals", value: selectedItem!.item_number },
|
||||
]}, 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) {
|
||||
priceRows.push({ _id: `p_${Date.now()}`, start_date: "", end_date: "", currency_code: "CAT_MLAMDKVN_PZJI",
|
||||
base_price_type: "CAT_MLAMFGFT_4RZW", base_price: "", discount_type: "", discount_value: "",
|
||||
rounding_type: "", rounding_unit_value: "", calculated_price: "" });
|
||||
}
|
||||
|
||||
setSelectedCustsForDetail([custInfo]);
|
||||
@@ -782,23 +791,17 @@ export default function SalesItemPage() {
|
||||
"cursor-pointer h-[41px]",
|
||||
customerCheckedIds.includes(row.id) ? "bg-primary/[0.08]" : "hover:bg-accent"
|
||||
)}
|
||||
onClick={() => {
|
||||
setCustomerCheckedIds((prev) =>
|
||||
prev.includes(row.id) ? prev.filter((id) => id !== row.id) : [...prev, row.id]
|
||||
);
|
||||
}}
|
||||
onDoubleClick={() => openEditCust(row)}
|
||||
>
|
||||
<TableCell
|
||||
className="text-center px-2"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setCustomerCheckedIds((prev) =>
|
||||
prev.includes(row.id) ? prev.filter((id) => id !== row.id) : [...prev, row.id]
|
||||
);
|
||||
}}
|
||||
>
|
||||
<TableCell className="text-center px-2">
|
||||
<Checkbox
|
||||
checked={customerCheckedIds.includes(row.id)}
|
||||
onCheckedChange={(checked) => {
|
||||
if (checked === true) setCustomerCheckedIds((prev) => [...prev, row.id]);
|
||||
else setCustomerCheckedIds((prev) => prev.filter((id) => id !== row.id));
|
||||
}}
|
||||
onCheckedChange={() => {}}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className="text-[13px] font-mono text-muted-foreground">{row.customer_code}</TableCell>
|
||||
|
||||
@@ -309,7 +309,8 @@ export default function DepartmentPage() {
|
||||
};
|
||||
|
||||
// 퇴사일 기반 재직/퇴사 분리
|
||||
const today = new Date().toISOString().split("T")[0];
|
||||
const _now = new Date();
|
||||
const today = `${_now.getFullYear()}-${String(_now.getMonth() + 1).padStart(2, "0")}-${String(_now.getDate()).padStart(2, "0")}`;
|
||||
const activeMembers = members.filter((m) => !m.end_date || m.end_date.substring(0, 10) >= today);
|
||||
const resignedMembers = members.filter((m) => m.end_date && m.end_date.substring(0, 10) < today);
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ export default function ProductionPlanManagementPage() {
|
||||
const [stockItems, setStockItems] = useState<StockShortageItem[]>([]);
|
||||
const [finishedPlans, setFinishedPlans] = useState<ProductionPlan[]>([]);
|
||||
const [semiPlans, setSemiPlans] = useState<ProductionPlan[]>([]);
|
||||
const [equipmentList, setEquipmentList] = useState<{ equipment_id: string; equipment_name: string }[]>([]);
|
||||
const [equipmentList, setEquipmentList] = useState<{ id: string; equipment_code: string; equipment_name: string }[]>([]);
|
||||
|
||||
// 선택/토글 상태
|
||||
const [expandedItems, setExpandedItems] = useState<Set<string>>(new Set());
|
||||
@@ -659,7 +659,7 @@ export default function ProductionPlanManagementPage() {
|
||||
setModalManager((plan as any).manager_name || "");
|
||||
setModalWorkOrderNo((plan as any).work_order_no || "");
|
||||
setModalRemarks(plan.remarks || "");
|
||||
setModalEquipmentId(plan.equipment_id ? String(plan.equipment_id) : "");
|
||||
setModalEquipmentId((plan as any).equipment_code || (plan.equipment_id ? String(plan.equipment_id) : ""));
|
||||
setScheduleModalOpen(true);
|
||||
}, []);
|
||||
|
||||
@@ -1426,8 +1426,8 @@ export default function ProductionPlanManagementPage() {
|
||||
<SelectContent>
|
||||
<SelectItem value="none">미지정</SelectItem>
|
||||
{equipmentList.map((eq) => (
|
||||
<SelectItem key={eq.equipment_id} value={String(eq.equipment_id)}>
|
||||
{eq.equipment_name} ({eq.equipment_id})
|
||||
<SelectItem key={eq.id} value={eq.equipment_code || eq.id}>
|
||||
{eq.equipment_name} ({eq.equipment_code})
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
|
||||
@@ -345,7 +345,8 @@ export default function CustomerManagementPage() {
|
||||
if (!code) return "";
|
||||
return priceCategoryOptions[col]?.find((o) => o.code === code)?.label || code;
|
||||
};
|
||||
const today = new Date().toISOString().split("T")[0];
|
||||
const now = new Date();
|
||||
const today = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`;
|
||||
|
||||
// 품목 기준 그룹핑 — master: 첫 매핑 + 현재 단가, details: 전체 단가 리스트
|
||||
const grouped: Record<string, { master: any; details: any[] }> = {};
|
||||
@@ -810,11 +811,13 @@ export default function CustomerManagementPage() {
|
||||
const searchItems = async () => {
|
||||
setItemSearchLoading(true);
|
||||
try {
|
||||
const filters: any[] = [];
|
||||
const filters: any[] = [
|
||||
{ columnName: "division", operator: "contains", value: "CAT_ML8ZFVEL_1TOR" },
|
||||
];
|
||||
if (itemSearchKeyword) filters.push({ columnName: "item_name", operator: "contains", value: itemSearchKeyword });
|
||||
const res = await apiClient.post(`/table-management/tables/item_info/data`, {
|
||||
page: 1, size: 500,
|
||||
dataFilter: filters.length > 0 ? { enabled: true, filters } : undefined,
|
||||
dataFilter: { enabled: true, filters },
|
||||
autoFilter: true,
|
||||
});
|
||||
const allItems = res.data?.data?.data || res.data?.data?.rows || [];
|
||||
|
||||
@@ -402,32 +402,41 @@ export default function SalesItemPage() {
|
||||
if (found) custInfo = 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);
|
||||
|
||||
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);
|
||||
|
||||
if (priceRows.length === 0) {
|
||||
priceRows.push({
|
||||
_id: `p_${Date.now()}`, start_date: "", end_date: "", currency_code: "CAT_MLAMDKVN_PZJI",
|
||||
base_price_type: "CAT_MLAMFGFT_4RZW", base_price: "", discount_type: "", discount_value: "",
|
||||
rounding_type: "", rounding_unit_value: "", calculated_price: "",
|
||||
let mappingRows: any[] = [];
|
||||
try {
|
||||
const mapRes = await apiClient.post(`/table-management/tables/customer_item_mapping/data`, {
|
||||
page: 1, size: 100,
|
||||
dataFilter: { enabled: true, filters: [
|
||||
{ columnName: "customer_id", operator: "equals", value: custKey },
|
||||
{ columnName: "item_id", operator: "equals", value: selectedItem!.item_number },
|
||||
]}, 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 */ }
|
||||
let priceRows: any[] = [];
|
||||
try {
|
||||
const priceRes = await apiClient.post(`/table-management/tables/customer_item_prices/data`, {
|
||||
page: 1, size: 100,
|
||||
dataFilter: { enabled: true, filters: [
|
||||
{ columnName: "customer_id", operator: "equals", value: custKey },
|
||||
{ columnName: "item_id", operator: "equals", value: selectedItem!.item_number },
|
||||
]}, 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) {
|
||||
priceRows.push({ _id: `p_${Date.now()}`, start_date: "", end_date: "", currency_code: "CAT_MLAMDKVN_PZJI",
|
||||
base_price_type: "CAT_MLAMFGFT_4RZW", base_price: "", discount_type: "", discount_value: "",
|
||||
rounding_type: "", rounding_unit_value: "", calculated_price: "" });
|
||||
}
|
||||
|
||||
setSelectedCustsForDetail([custInfo]);
|
||||
@@ -782,23 +791,17 @@ export default function SalesItemPage() {
|
||||
"cursor-pointer h-[41px]",
|
||||
customerCheckedIds.includes(row.id) ? "bg-primary/[0.08]" : "hover:bg-accent"
|
||||
)}
|
||||
onClick={() => {
|
||||
setCustomerCheckedIds((prev) =>
|
||||
prev.includes(row.id) ? prev.filter((id) => id !== row.id) : [...prev, row.id]
|
||||
);
|
||||
}}
|
||||
onDoubleClick={() => openEditCust(row)}
|
||||
>
|
||||
<TableCell
|
||||
className="text-center px-2"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setCustomerCheckedIds((prev) =>
|
||||
prev.includes(row.id) ? prev.filter((id) => id !== row.id) : [...prev, row.id]
|
||||
);
|
||||
}}
|
||||
>
|
||||
<TableCell className="text-center px-2">
|
||||
<Checkbox
|
||||
checked={customerCheckedIds.includes(row.id)}
|
||||
onCheckedChange={(checked) => {
|
||||
if (checked === true) setCustomerCheckedIds((prev) => [...prev, row.id]);
|
||||
else setCustomerCheckedIds((prev) => prev.filter((id) => id !== row.id));
|
||||
}}
|
||||
onCheckedChange={() => {}}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className="text-[13px] font-mono text-muted-foreground">{row.customer_code}</TableCell>
|
||||
|
||||
Reference in New Issue
Block a user