diff --git a/backend-node/src/controllers/outboundController.ts b/backend-node/src/controllers/outboundController.ts index 896b25b1..3f7cc5a5 100644 --- a/backend-node/src/controllers/outboundController.ts +++ b/backend-node/src/controllers/outboundController.ts @@ -543,6 +543,9 @@ export async function getItems(req: AuthenticatedRequest, res: Response) { const result = await pool.query( `SELECT id, item_number, item_name, size AS spec, material, unit, + COALESCE(width::text, '') AS width, + COALESCE(height::text, '') AS height, + COALESCE(thickness::text, '') AS thickness, COALESCE(CAST(NULLIF(standard_price, '') AS numeric), 0) AS standard_price FROM item_info WHERE ${conditions.join(" AND ")} diff --git a/backend-node/src/controllers/receivingController.ts b/backend-node/src/controllers/receivingController.ts index f6a818f0..b2d920b5 100644 --- a/backend-node/src/controllers/receivingController.ts +++ b/backend-node/src/controllers/receivingController.ts @@ -991,6 +991,9 @@ export async function getItems(req: AuthenticatedRequest, res: Response) { const dataResult = await pool.query( `SELECT id, item_number, item_name, size AS spec, material, unit, + COALESCE(width::text, '') AS width, + COALESCE(height::text, '') AS height, + COALESCE(thickness::text, '') AS thickness, COALESCE(CAST(NULLIF(standard_price, '') AS numeric), 0) AS standard_price FROM item_info WHERE ${whereClause} diff --git a/backend-node/src/controllers/shippingOrderController.ts b/backend-node/src/controllers/shippingOrderController.ts index 6044c4b9..896f68f0 100644 --- a/backend-node/src/controllers/shippingOrderController.ts +++ b/backend-node/src/controllers/shippingOrderController.ts @@ -333,7 +333,7 @@ export async function getShipmentPlanSource(req: AuthenticatedRequest, res: Resp LEFT JOIN sales_order_detail d ON sp.detail_id = d.id AND sp.company_code = d.company_code LEFT JOIN sales_order_mng m ON sp.sales_order_id = m.id AND sp.company_code = m.company_code LEFT JOIN LATERAL ( - SELECT item_name FROM item_info + SELECT item_name, width, height, thickness FROM item_info WHERE item_number = COALESCE(d.part_code, m.part_code) AND company_code = sp.company_code LIMIT 1 ) i ON true @@ -353,6 +353,9 @@ export async function getShipmentPlanSource(req: AuthenticatedRequest, res: Resp COALESCE(d.part_code, m.part_code, '') AS item_code, COALESCE(i.item_name, d.part_name, m.part_name, COALESCE(d.part_code, m.part_code, '')) AS item_name, COALESCE(d.spec, m.spec, '') AS spec, + COALESCE(i.width::text, '') AS width, + COALESCE(i.height::text, '') AS height, + COALESCE(i.thickness::text, '') AS thickness, COALESCE(m.material, '') AS material, COALESCE(c.customer_name, '') AS customer_name, COALESCE(m.partner_id, d.delivery_partner_code, '') AS partner_code, @@ -400,7 +403,7 @@ export async function getSalesOrderSource(req: AuthenticatedRequest, res: Respon FROM sales_order_detail d LEFT JOIN sales_order_mng m ON d.order_no = m.order_no AND d.company_code = m.company_code LEFT JOIN LATERAL ( - SELECT item_name FROM item_info + SELECT item_name, width, height, thickness FROM item_info WHERE item_number = d.part_code AND company_code = d.company_code LIMIT 1 ) i ON true @@ -418,6 +421,9 @@ export async function getSalesOrderSource(req: AuthenticatedRequest, res: Respon d.id, d.order_no, d.part_code AS item_code, COALESCE(i.item_name, d.part_name, d.part_code) AS item_name, COALESCE(d.spec, '') AS spec, COALESCE(m.material, '') AS material, + COALESCE(i.width::text, '') AS width, + COALESCE(i.height::text, '') AS height, + COALESCE(i.thickness::text, '') AS thickness, COALESCE(NULLIF(d.qty,'')::numeric, 0) AS qty, COALESCE(NULLIF(d.balance_qty,'')::numeric, 0) AS balance_qty, COALESCE(c.customer_name, COALESCE(d.delivery_partner_code, m.partner_id, '')) AS customer_name, @@ -465,7 +471,10 @@ export async function getItemSource(req: AuthenticatedRequest, res: Response) { const query = ` SELECT item_number AS item_code, item_name, - COALESCE(size, '') AS spec, COALESCE(material, '') AS material + COALESCE(size, '') AS spec, COALESCE(material, '') AS material, + COALESCE(width::text, '') AS width, + COALESCE(height::text, '') AS height, + COALESCE(thickness::text, '') AS thickness FROM item_info WHERE ${whereClause} ORDER BY item_name diff --git a/frontend/app/(main)/COMPANY_30/logistics/inbound-outbound/page.tsx b/frontend/app/(main)/COMPANY_30/logistics/inbound-outbound/page.tsx index 587940ce..3c00baca 100644 --- a/frontend/app/(main)/COMPANY_30/logistics/inbound-outbound/page.tsx +++ b/frontend/app/(main)/COMPANY_30/logistics/inbound-outbound/page.tsx @@ -75,7 +75,7 @@ export default function InboundOutboundPage() { const [checkedIds, setCheckedIds] = useState>(new Set()); // 품목명/단위 캐시 - const [itemMap, setItemMap] = useState>({}); + const [itemMap, setItemMap] = useState>({}); const [warehouseMap, setWarehouseMap] = useState>({}); const [userMap, setUserMap] = useState>({}); @@ -125,10 +125,16 @@ export default function InboundOutboundPage() { autoFilter: true, }); const items = itemRes.data?.data?.data || itemRes.data?.data?.rows || []; - const map: Record = {}; + const map: Record = {}; for (const i of items) { const rawUnit = i.unit || ""; - if (!map[i.item_number]) map[i.item_number] = { item_name: i.item_name || "", unit: unitLabelMap[rawUnit] || rawUnit }; + if (!map[i.item_number]) map[i.item_number] = { + item_name: i.item_name || "", + unit: unitLabelMap[rawUnit] || rawUnit, + width: i.width || "", + height: i.height || "", + thickness: i.thickness || "", + }; } setItemMap(map); } catch { /* skip */ } @@ -341,6 +347,9 @@ export default function InboundOutboundPage() { 위치 품목코드 품목명 + 가로 + 세로 + 두께 수량 단위 로트번호 @@ -361,6 +370,7 @@ export default function InboundOutboundPage() { {row._count}건 + {fmtNum(row._totalQty)} @@ -404,6 +414,9 @@ export default function InboundOutboundPage() { {row.location_code || "-"} {row.item_code || "-"} {info?.item_name || "-"} + {info?.width || "-"} + {info?.height || "-"} + {info?.thickness || "-"} {isIn ? "+" : ""}{fmtNum(qty)} diff --git a/frontend/app/(main)/COMPANY_30/logistics/outbound/page.tsx b/frontend/app/(main)/COMPANY_30/logistics/outbound/page.tsx index d6e801a1..ea244869 100644 --- a/frontend/app/(main)/COMPANY_30/logistics/outbound/page.tsx +++ b/frontend/app/(main)/COMPANY_30/logistics/outbound/page.tsx @@ -106,6 +106,9 @@ const GRID_COLUMNS = [ { key: "customer_name", label: "거래처" }, { key: "item_number", label: "품목코드" }, { key: "item_name", label: "품목명" }, + { key: "width", label: "가로" }, + { key: "height", label: "세로" }, + { key: "thickness", label: "두께" }, { key: "spec", label: "규격" }, { key: "outbound_qty", label: "출고수량" }, { key: "unit_price", label: "단가" }, @@ -115,8 +118,8 @@ const GRID_COLUMNS = [ { key: "remark", label: "비고" }, ]; -// 총 컬럼 수: 체크박스(1) + GRID_COLUMNS(15) = 16 -const TOTAL_COLS = 16; +// 총 컬럼 수: 체크박스(1) + GRID_COLUMNS(18) = 19 +const TOTAL_COLS = 19; // 헤더 필터 Popover function HeaderFilterPopover({ @@ -626,6 +629,9 @@ export default function OutboundPage() { item_number: si.item_code, item_name: si.item_name, spec: si.spec || "", + width: (si as any).width || "", + height: (si as any).height || "", + thickness: (si as any).thickness || "", material: si.material || "", unit: "EA", outbound_qty: si.remain_qty, @@ -652,6 +658,9 @@ export default function OutboundPage() { item_number: po.item_code, item_name: po.item_name, spec: po.spec || "", + width: (po as any).width || "", + height: (po as any).height || "", + thickness: (po as any).thickness || "", material: po.material || "", unit: "EA", outbound_qty: po.received_qty, @@ -678,6 +687,9 @@ export default function OutboundPage() { item_number: item.item_number, item_name: item.item_name, spec: item.spec || "", + width: (item as any).width || "", + height: (item as any).height || "", + thickness: (item as any).thickness || "", material: item.material || "", unit: item.inventory_unit || "EA", outbound_qty: 0, @@ -896,6 +908,9 @@ export default function OutboundPage() { + + + @@ -1007,6 +1022,9 @@ export default function OutboundPage() { {row.customer_name || ""} {row.item_number || ""} {row.item_name || ""} + {(row as any).width || "-"} + {(row as any).height || "-"} + {(row as any).thickness || "-"} {row.spec || ""} {row.outbound_qty ? Number(row.outbound_qty).toLocaleString() : ""} {row.unit_price ? Number(row.unit_price).toLocaleString() : ""} @@ -1372,7 +1390,7 @@ export default function OutboundPage() { {resolveCat("outbound_type", item.outbound_type) || "-"} - +
{item.item_name} @@ -1381,6 +1399,13 @@ export default function OutboundPage() { {item.item_number} {item.spec ? ` | ${item.spec}` : ""} + {((item as any).width || (item as any).height || (item as any).thickness) && ( + + {(item as any).width && `W ${(item as any).width}`} + {(item as any).height && ` × H ${(item as any).height}`} + {(item as any).thickness && ` × T ${(item as any).thickness}`} + + )}
{item.reference_number} @@ -1535,13 +1560,20 @@ function SourceShipmentInstructionTable({ ? new Date(si.instruction_date).toLocaleDateString("ko-KR") : "-"}
- +
{si.item_name} {si.item_code} {si.spec ? ` | ${si.spec}` : ""} + {((si as any).width || (si as any).height || (si as any).thickness) && ( + + {(si as any).width && `W ${(si as any).width}`} + {(si as any).height && ` × H ${(si as any).height}`} + {(si as any).thickness && ` × T ${(si as any).thickness}`} + + )}
@@ -1612,13 +1644,20 @@ function SourcePurchaseOrderTable({ {po.purchase_no} {po.supplier_name} - +
{po.item_name} {po.item_code} {po.spec ? ` | ${po.spec}` : ""} + {((po as any).width || (po as any).height || (po as any).thickness) && ( + + {(po as any).width && `W ${(po as any).width}`} + {(po as any).height && ` × H ${(po as any).height}`} + {(po as any).thickness && ` × T ${(po as any).thickness}`} + + )}
@@ -1692,6 +1731,13 @@ function SourceItemTable({ {item.item_number} + {((item as any).width || (item as any).height || (item as any).thickness) && ( + + {(item as any).width && `W ${(item as any).width}`} + {(item as any).height && ` × H ${(item as any).height}`} + {(item as any).thickness && ` × T ${(item as any).thickness}`} + + )} {item.spec || "-"} diff --git a/frontend/app/(main)/COMPANY_30/logistics/receiving/page.tsx b/frontend/app/(main)/COMPANY_30/logistics/receiving/page.tsx index a9825af5..8cf7d653 100644 --- a/frontend/app/(main)/COMPANY_30/logistics/receiving/page.tsx +++ b/frontend/app/(main)/COMPANY_30/logistics/receiving/page.tsx @@ -86,6 +86,9 @@ const GRID_COLUMNS = [ { key: "supplier_name", label: "공급처" }, { key: "item_number", label: "품목코드" }, { key: "item_name", label: "품목명" }, + { key: "width", label: "가로" }, + { key: "height", label: "세로" }, + { key: "thickness", label: "두께" }, { key: "spec", label: "규격" }, { key: "inbound_qty", label: "입고수량" }, { key: "unit_price", label: "단가" }, @@ -95,8 +98,8 @@ const GRID_COLUMNS = [ { key: "remark", label: "비고" }, ]; -// 총 컬럼 수: 체크박스(1) + GRID_COLUMNS(15) = 16 -const TOTAL_COLS = 16; +// 총 컬럼 수: 체크박스(1) + GRID_COLUMNS(18) = 19 +const TOTAL_COLS = 19; // 헤더 필터 Popover function HeaderFilterPopover({ @@ -658,6 +661,9 @@ export default function ReceivingPage() { item_number: po.item_code, item_name: po.item_name, spec: po.spec || "", + width: (po as any).width || "", + height: (po as any).height || "", + thickness: (po as any).thickness || "", material: po.material || "", unit: "EA", inbound_qty: po.remain_qty, @@ -684,6 +690,9 @@ export default function ReceivingPage() { item_number: sh.item_code, item_name: sh.item_name, spec: sh.spec || "", + width: (sh as any).width || "", + height: (sh as any).height || "", + thickness: (sh as any).thickness || "", material: sh.material || "", unit: "EA", inbound_qty: sh.ship_qty, @@ -710,6 +719,9 @@ export default function ReceivingPage() { item_number: item.item_number, item_name: item.item_name, spec: item.spec || "", + width: (item as any).width || "", + height: (item as any).height || "", + thickness: (item as any).thickness || "", material: item.material || "", unit: item.inventory_unit || "EA", inbound_qty: 0, @@ -939,6 +951,9 @@ export default function ReceivingPage() { + + + @@ -1050,6 +1065,9 @@ export default function ReceivingPage() { {row.supplier_name || ""} {row.item_number || ""} {row.item_name || ""} + {(row as any).width || "-"} + {(row as any).height || "-"} + {(row as any).thickness || "-"} {row.spec || ""} {row.inbound_qty ? Number(row.inbound_qty).toLocaleString() : ""} {row.unit_price ? Number(row.unit_price).toLocaleString() : ""} @@ -1421,7 +1439,7 @@ export default function ReceivingPage() { {idx + 1} - +
{item.item_name} @@ -1430,6 +1448,13 @@ export default function ReceivingPage() { {item.item_number} {item.spec ? ` | ${item.spec}` : ""} + {((item as any).width || (item as any).height || (item as any).thickness) && ( + + {(item as any).width && `W ${(item as any).width}`} + {(item as any).height && ` × H ${(item as any).height}`} + {(item as any).thickness && ` × T ${(item as any).thickness}`} + + )}
@@ -1595,13 +1620,20 @@ function SourcePurchaseOrderTable({ {po.purchase_no} {po.supplier_name} - +
{po.item_name} {po.item_code} {po.spec ? ` | ${po.spec}` : ""} + {((po as any).width || (po as any).height || (po as any).thickness) && ( + + {(po as any).width && `W ${(po as any).width}`} + {(po as any).height && ` × H ${(po as any).height}`} + {(po as any).thickness && ` × T ${(po as any).thickness}`} + + )}
@@ -1679,13 +1711,20 @@ function SourceShipmentTable({ : "-"} {sh.partner_id} - +
{sh.item_name} {sh.item_code} {sh.spec ? ` | ${sh.spec}` : ""} + {((sh as any).width || (sh as any).height || (sh as any).thickness) && ( + + {(sh as any).width && `W ${(sh as any).width}`} + {(sh as any).height && ` × H ${(sh as any).height}`} + {(sh as any).thickness && ` × T ${(sh as any).thickness}`} + + )}
@@ -1758,6 +1797,13 @@ function SourceItemTable({ {item.item_number} + {((item as any).width || (item as any).height || (item as any).thickness) && ( + + {(item as any).width && `W ${(item as any).width}`} + {(item as any).height && ` × H ${(item as any).height}`} + {(item as any).thickness && ` × T ${(item as any).thickness}`} + + )} {item.spec || "-"} diff --git a/frontend/app/(main)/COMPANY_30/master-data/item-info/page.tsx b/frontend/app/(main)/COMPANY_30/master-data/item-info/page.tsx index ad55d2b2..55d4f24b 100644 --- a/frontend/app/(main)/COMPANY_30/master-data/item-info/page.tsx +++ b/frontend/app/(main)/COMPANY_30/master-data/item-info/page.tsx @@ -142,6 +142,9 @@ const GRID_COLUMNS = [ { key: "image", label: "이미지", type: "image" }, { key: "division", label: "관리품목" }, { key: "type", label: "품목구분" }, + { key: "width", label: "가로", align: "right" as const }, + { key: "height", label: "세로", align: "right" as const }, + { key: "thickness", label: "두께", align: "right" as const }, { key: "size", label: "규격" }, { key: "unit", label: "단위" }, { key: "material", label: "재질" }, @@ -160,6 +163,9 @@ const FORM_FIELDS = [ { key: "item_name", label: "품명", type: "text", required: true }, { key: "division", label: "관리품목", type: "multi-category" }, { key: "type", label: "품목구분", type: "category" }, + { key: "width", label: "가로", type: "text", placeholder: "숫자 입력 (예: 1000)" }, + { key: "height", label: "세로", type: "text", placeholder: "숫자 입력 (예: 2000)" }, + { key: "thickness", label: "두께", type: "text", placeholder: "숫자 입력 (예: 10)" }, { key: "size", label: "규격", type: "text" }, { key: "unit", label: "단위", type: "category" }, { key: "material", label: "재질", type: "category" }, @@ -383,8 +389,12 @@ export default function ItemInfoPage() { } return categoryOptions[col]?.find((o) => o.code === code)?.label || code; }; - setRawItems(raw); - const data = raw.map((r: any) => { + // item_number 내림차순 정렬 (최근 품목이 위로, 자연 정렬) + const sortedRaw = [...raw].sort((a: any, b: any) => + String(b.item_number || "").localeCompare(String(a.item_number || ""), undefined, { numeric: true, sensitivity: "base" }) + ); + setRawItems(sortedRaw); + const data = sortedRaw.map((r: any) => { const converted = { ...r }; for (const col of CATEGORY_COLUMNS) { if (converted[col]) converted[col] = resolve(col, converted[col]); diff --git a/frontend/app/(main)/COMPANY_30/outsourcing/subcontractor-item/page.tsx b/frontend/app/(main)/COMPANY_30/outsourcing/subcontractor-item/page.tsx index 92673fa0..8c1371bd 100644 --- a/frontend/app/(main)/COMPANY_30/outsourcing/subcontractor-item/page.tsx +++ b/frontend/app/(main)/COMPANY_30/outsourcing/subcontractor-item/page.tsx @@ -42,6 +42,9 @@ const formatNum = (v: any) => (v == null || v === "" ? "-" : Number(v).toLocaleS const GRID_COLUMNS_CONFIG = [ { key: "item_number", label: "품번" }, { key: "item_name", label: "품명" }, + { key: "width", label: "가로" }, + { key: "height", label: "세로" }, + { key: "thickness", label: "두께" }, { key: "size", label: "규격" }, { key: "unit", label: "단위" }, { key: "standard_price", label: "기준단가" }, @@ -124,6 +127,9 @@ export default function SubcontractorItemPage() { item_number: { width: "w-[110px]" }, item_name: { minWidth: "min-w-[130px]", render: (v) => v || "-" }, size: { width: "w-[90px]", render: (v) => v || "-" }, + width: { width: "w-[70px]", align: "right", render: (v) => v || "-" }, + height: { width: "w-[70px]", align: "right", render: (v) => v || "-" }, + thickness: { width: "w-[70px]", align: "right", render: (v) => v || "-" }, unit: { width: "w-[60px]", render: (v) => v || "-" }, standard_price: { width: "w-[90px]", align: "right", formatNumber: true }, selling_price: { width: "w-[90px]", align: "right", formatNumber: true }, diff --git a/frontend/app/(main)/COMPANY_30/purchase/order/page.tsx b/frontend/app/(main)/COMPANY_30/purchase/order/page.tsx index 5da53411..965b0a0e 100644 --- a/frontend/app/(main)/COMPANY_30/purchase/order/page.tsx +++ b/frontend/app/(main)/COMPANY_30/purchase/order/page.tsx @@ -76,6 +76,9 @@ const GRID_COLUMNS_CONFIG = [ { key: "supplier_name", label: "공급업체" }, { key: "item_code", label: "품번" }, { key: "item_name", label: "품명" }, + { key: "width", label: "가로" }, + { key: "height", label: "세로" }, + { key: "thickness", label: "두께" }, { key: "spec", label: "규격" }, { key: "order_qty", label: "발주수량" }, { key: "received_qty", label: "입고수량" }, @@ -91,6 +94,9 @@ const MODAL_DETAIL_COLUMNS = [ { key: "item_code", label: "품번", width: "min-w-[120px]" }, { key: "item_name", label: "품명", width: "min-w-[150px]" }, { key: "supplier", label: "공급업체", width: "min-w-[150px]" }, + { key: "width", label: "가로", width: "min-w-[70px]" }, + { key: "height", label: "세로", width: "min-w-[70px]" }, + { key: "thickness", label: "두께", width: "min-w-[70px]" }, { key: "spec", label: "규격", width: "min-w-[80px]" }, { key: "unit", label: "단위", width: "min-w-[90px]" }, { key: "order_qty", label: "발주수량", width: "min-w-[90px]" }, @@ -351,6 +357,9 @@ export default function PurchaseOrderPage() { ...row, item_name: row.item_name || item?.item_name || "", spec: row.spec || item?.size || "", + width: row.width || item?.width || "", + height: row.height || item?.height || "", + thickness: row.thickness || item?.thickness || "", unit: resolveLabel("item_inventory_unit", rawUnit) || rawUnit, status: master?.status || "", supplier_name: master?.supplier_name || "", @@ -641,6 +650,9 @@ export default function PurchaseOrderPage() { item_code: itemCode, item_name: item.item_name, spec: item.size || "", + width: item.width || "", + height: item.height || "", + thickness: item.thickness || "", material: getCategoryLabel("item_material", item.material) || item.material || "", unit: getCategoryLabel("item_inventory_unit", item.inventory_unit) || item.inventory_unit || "", order_qty: "", @@ -1087,6 +1099,12 @@ export default function PurchaseOrderPage() { ); case "spec": return {row.spec}; + case "width": + return {row.width || "-"}; + case "height": + return {row.height || "-"}; + case "thickness": + return {row.thickness || "-"}; case "unit": return {row.unit}; case "order_qty": @@ -1224,6 +1242,9 @@ export default function PurchaseOrderPage() { 품목코드 품명 + 가로 + 세로 + 두께 규격 재질 단위 @@ -1231,7 +1252,7 @@ export default function PurchaseOrderPage() { {itemSearchResults.length === 0 ? ( - 검색 결과가 없어요 + 검색 결과가 없어요 ) : itemSearchResults.map((item) => ( setItemSelectedMap((prev) => { @@ -1244,6 +1265,9 @@ export default function PurchaseOrderPage() {
{item.item_number} {item.item_name} + {item.width || "-"} + {item.height || "-"} + {item.thickness || "-"} {item.size} {categoryOptions["item_material"]?.find((o) => o.code === item.material)?.label || item.material} {categoryOptions["item_inventory_unit"]?.find((o) => o.code === item.inventory_unit)?.label || item.inventory_unit} diff --git a/frontend/app/(main)/COMPANY_30/purchase/purchase-item/page.tsx b/frontend/app/(main)/COMPANY_30/purchase/purchase-item/page.tsx index fd203d40..225f69d4 100644 --- a/frontend/app/(main)/COMPANY_30/purchase/purchase-item/page.tsx +++ b/frontend/app/(main)/COMPANY_30/purchase/purchase-item/page.tsx @@ -141,6 +141,9 @@ const FORM_FIELDS = [ { key: "item_name", label: "품명", type: "text", required: true }, { key: "division", label: "관리품목", type: "multi-category" }, { key: "type", label: "품목구분", type: "category" }, + { key: "width", label: "가로", type: "text", placeholder: "숫자 입력 (예: 1000)" }, + { key: "height", label: "세로", type: "text", placeholder: "숫자 입력 (예: 2000)" }, + { key: "thickness", label: "두께", type: "text", placeholder: "숫자 입력 (예: 10)" }, { key: "size", label: "규격", type: "text" }, { key: "inventory_unit", label: "단위", type: "category" }, { key: "material", label: "재질", type: "category" }, @@ -173,6 +176,9 @@ const formatNum = (val: any): string => { const ITEM_GRID_COLUMNS = [ { key: "item_number", label: "품번" }, { key: "item_name", label: "품명" }, + { key: "width", label: "가로", align: "right" as const }, + { key: "height", label: "세로", align: "right" as const }, + { key: "thickness", label: "두께", align: "right" as const }, { key: "size", label: "규격" }, { key: "inventory_unit", label: "단위" }, { key: "standard_price", label: "기준단가/구매단가" }, diff --git a/frontend/app/(main)/COMPANY_30/sales/order/page.tsx b/frontend/app/(main)/COMPANY_30/sales/order/page.tsx index 6f4502bd..708c9840 100644 --- a/frontend/app/(main)/COMPANY_30/sales/order/page.tsx +++ b/frontend/app/(main)/COMPANY_30/sales/order/page.tsx @@ -537,19 +537,27 @@ export default function JeilGlassOrderPage() { if (!code) return ""; return categoryOptions["item_division"]?.find((o) => o.code === code)?.label || code; }; - const newRows = selected.map((item) => ({ - _id: `new_${Date.now()}_${Math.random()}`, - _fromItemInfo: true, - part_code: item.item_number || "", - part_name: item.item_name || "", - spec: item.size || "", - division: item.division || "", - _divisionLabel: resolveDivision(item.division), - unit: resolveUnit(item.unit) || "", - width: "", height: "", thickness: "", area: "", - qty: "", unit_price: item.selling_price || item.standard_price || "", amount: "", - due_date: "", memo: "", - })); + const newRows = selected.map((item) => { + const w = parseFloat(item.width) || 0; + const h = parseFloat(item.height) || 0; + const autoArea = w > 0 && h > 0 ? String(Math.round((w * h / 1_000_000) * 10000) / 10000) : ""; + return { + _id: `new_${Date.now()}_${Math.random()}`, + _fromItemInfo: true, + part_code: item.item_number || "", + part_name: item.item_name || "", + spec: item.size || "", + division: item.division || "", + _divisionLabel: resolveDivision(item.division), + unit: resolveUnit(item.unit) || "", + width: item.width || "", + height: item.height || "", + thickness: item.thickness || "", + area: item.area || autoArea, + qty: "", unit_price: item.selling_price || item.standard_price || "", amount: "", + due_date: "", memo: "", + }; + }); setModalDetailRows((prev) => [...prev, ...newRows]); setItemSelectOpen(false); setItemCheckedIds(new Set()); @@ -1080,13 +1088,16 @@ export default function JeilGlassOrderPage() { 품목코드 품명 + 가로 + 세로 + 두께 규격 단위 {itemSearchResults.length === 0 ? ( - 검색 결과가 없습니다 + 검색 결과가 없습니다 ) : itemSearchResults.map((item) => ( setItemCheckedIds((prev) => { @@ -1097,6 +1108,9 @@ export default function JeilGlassOrderPage() { {item.item_number} {item.item_name} + {item.width || "-"} + {item.height || "-"} + {item.thickness || "-"} {item.size} {item.unit} diff --git a/frontend/app/(main)/COMPANY_30/sales/sales-item/page.tsx b/frontend/app/(main)/COMPANY_30/sales/sales-item/page.tsx index 6e558a82..70ebf5c2 100644 --- a/frontend/app/(main)/COMPANY_30/sales/sales-item/page.tsx +++ b/frontend/app/(main)/COMPANY_30/sales/sales-item/page.tsx @@ -148,6 +148,9 @@ const formatNum = (val: any): string => { const ITEM_GRID_COLUMNS = [ { key: "item_number", label: "품번" }, { key: "item_name", label: "품명" }, + { key: "width", label: "가로", align: "right" as const }, + { key: "height", label: "세로", align: "right" as const }, + { key: "thickness", label: "두께", align: "right" as const }, { key: "size", label: "규격" }, { key: "inventory_unit", label: "단위" }, { key: "standard_price", label: "기준단가" }, @@ -161,6 +164,9 @@ const FORM_FIELDS = [ { key: "item_name", label: "품명", type: "text", required: true }, { key: "division", label: "관리품목", type: "multi-category" }, { key: "type", label: "품목구분", type: "category" }, + { key: "width", label: "가로", type: "text", placeholder: "숫자 입력 (예: 1000)" }, + { key: "height", label: "세로", type: "text", placeholder: "숫자 입력 (예: 2000)" }, + { key: "thickness", label: "두께", type: "text", placeholder: "숫자 입력 (예: 10)" }, { key: "size", label: "규격", type: "text" }, { key: "inventory_unit", label: "단위", type: "category" }, { key: "material", label: "재질", type: "category" }, @@ -1169,6 +1175,9 @@ export default function SalesItemPage() { const itemColumns: EDataTableColumn[] = [ { key: "item_number", label: "품번", width: "w-[110px]" }, { key: "item_name", label: "품명", minWidth: "min-w-[130px]" }, + { key: "width", label: "가로", width: "w-[70px]", align: "right" }, + { key: "height", label: "세로", width: "w-[70px]", align: "right" }, + { key: "thickness", label: "두께", width: "w-[70px]", align: "right" }, { key: "size", label: "규격", width: "w-[80px]" }, { key: "inventory_unit", label: "단위", width: "w-[60px]" }, { key: "standard_price", label: "기준단가", width: "w-[90px]", align: "right", formatNumber: true }, diff --git a/frontend/app/(main)/COMPANY_30/sales/shipping-order/page.tsx b/frontend/app/(main)/COMPANY_30/sales/shipping-order/page.tsx index 2ed29b40..d9e11ed6 100644 --- a/frontend/app/(main)/COMPANY_30/sales/shipping-order/page.tsx +++ b/frontend/app/(main)/COMPANY_30/sales/shipping-order/page.tsx @@ -37,6 +37,9 @@ const GRID_COLUMNS = [ { key: "status", label: "상태" }, { key: "item_code", label: "품번" }, { key: "item_name", label: "품명" }, + { key: "width", label: "가로" }, + { key: "height", label: "세로" }, + { key: "thickness", label: "두께" }, { key: "qty", label: "수량" }, { key: "source_type", label: "소스" }, { key: "remark", label: "비고" }, @@ -76,6 +79,9 @@ interface SelectedItem { itemCode: string; itemName: string; spec: string; + width: string; + height: string; + thickness: string; material: string; customer: string; planQty: number; @@ -248,6 +254,9 @@ export default function ShippingOrderPage() { itemCode: it.item_code || "", itemName: it.item_name || "", spec: it.spec || "", + width: it.width || "", + height: it.height || "", + thickness: it.thickness || "", material: it.material || "", customer: order.customer_name || "", planQty: Number(it.plan_qty || 0), @@ -311,6 +320,9 @@ export default function ShippingOrderPage() { itemCode: item.item_code || "", itemName: item.item_name || "", spec: item.spec || "", + width: item.width || "", + height: item.height || "", + thickness: item.thickness || "", material: item.material || "", customer: item.customer_name || "", planQty: Number(item.plan_qty || item.qty || item.balance_qty || 0), @@ -628,6 +640,9 @@ export default function ShippingOrderPage() { 선택 품번 품명 + 가로 + 세로 + 두께 규격 거래처 수량 @@ -657,6 +672,9 @@ export default function ShippingOrderPage() {
{item.item_code || "-"} {item.item_name || "-"} + {item.width || "-"} + {item.height || "-"} + {item.thickness || "-"} {item.spec || "-"} {item.customer_name || "-"} @@ -837,6 +855,9 @@ export default function ShippingOrderPage() { 소스 품번 품명 + 가로 + 세로 + 두께 출하수량 계획수량 삭제 @@ -854,6 +875,9 @@ export default function ShippingOrderPage() { {item.itemCode} {item.itemName} + {item.width || "-"} + {item.height || "-"} + {item.thickness || "-"} {val || "-"} }, { key: "part_code", label: "품목코드", render: (val: any) => {val || "-"} }, { key: "part_name", label: "품목명", render: (val: any) => {val || "-"} }, + { key: "width", label: "가로", align: "right" as const, render: (val: any) => {val || "-"} }, + { key: "height", label: "세로", align: "right" as const, render: (val: any) => {val || "-"} }, + { key: "thickness", label: "두께", align: "right" as const, render: (val: any) => {val || "-"} }, { key: "order_qty", label: "수주수량", align: "right" as const, formatNumber: true }, { key: "plan_qty", label: "계획수량", align: "right" as const, render: (val: any) => {formatNumber(val)} }, { key: "plan_date", label: "계획일", align: "center" as const, render: (val: any) => {formatDate(val)} }, diff --git a/frontend/app/(main)/COMPANY_8/master-data/item-info/page.tsx b/frontend/app/(main)/COMPANY_8/master-data/item-info/page.tsx index ad55d2b2..ee671b6e 100644 --- a/frontend/app/(main)/COMPANY_8/master-data/item-info/page.tsx +++ b/frontend/app/(main)/COMPANY_8/master-data/item-info/page.tsx @@ -37,6 +37,7 @@ import { } from "lucide-react"; import { Badge } from "@/components/ui/badge"; import { ImageUpload } from "@/components/common/ImageUpload"; +import { PdfUpload } from "@/components/common/PdfUpload"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command"; import { EDataTable, EDataTableColumn } from "@/components/common/EDataTable"; @@ -145,6 +146,7 @@ const GRID_COLUMNS = [ { key: "size", label: "규격" }, { key: "unit", label: "단위" }, { key: "material", label: "재질" }, + { key: "mold_number", label: "금형번호" }, { key: "status", label: "상태" }, { key: "selling_price", label: "판매가격", align: "right" as const, formatNumber: true }, { key: "standard_price", label: "기준단가", align: "right" as const, formatNumber: true }, @@ -153,6 +155,9 @@ const GRID_COLUMNS = [ { key: "user_type01", label: "대분류" }, { key: "user_type02", label: "중분류" }, { key: "lead_time", label: "생산 리드타임(일)", align: "right" as const }, + { key: "use_insert", label: "인서트" }, + { key: "use_packaging", label: "포장" }, + { key: "drawing_path", label: "도면" }, ]; const FORM_FIELDS = [ @@ -163,6 +168,7 @@ const FORM_FIELDS = [ { key: "size", label: "규격", type: "text" }, { key: "unit", label: "단위", type: "category" }, { key: "material", label: "재질", type: "category" }, + { key: "mold_number", label: "금형번호", type: "text" }, { key: "status", label: "상태", type: "category" }, { key: "weight", label: "중량", type: "text", placeholder: "숫자 입력 (예: 3.5)" }, { key: "volum", label: "부피", type: "text", placeholder: "숫자 입력 (예: 100)" }, @@ -174,6 +180,9 @@ const FORM_FIELDS = [ { key: "user_type01", label: "대분류", type: "category" }, { key: "user_type02", label: "중분류", type: "category" }, { key: "lead_time", label: "생산 리드타임(일)", type: "text", placeholder: "숫자 입력 (예: 7)" }, + { key: "use_insert", label: "인서트 사용", type: "category" }, + { key: "use_packaging", label: "포장 사용", type: "category" }, + { key: "drawing_path", label: "도면 (PDF)", type: "pdf" }, { key: "image", label: "품목 이미지", type: "image" }, { key: "meno", label: "메모", type: "textarea" }, ]; @@ -181,6 +190,7 @@ const FORM_FIELDS = [ const CATEGORY_COLUMNS = [ "division", "type", "unit", "material", "status", "inventory_unit", "currency_code", "user_type01", "user_type02", + "use_insert", "use_packaging", ]; export default function ItemInfoPage() { @@ -737,7 +747,7 @@ export default function ItemInfoPage() { {FORM_FIELDS.map((field) => (