|
|
|
@@ -60,6 +60,7 @@ import { |
|
|
|
useContext, |
|
|
|
useEffect, |
|
|
|
useMemo, |
|
|
|
useRef, |
|
|
|
useState, |
|
|
|
} from "react"; |
|
|
|
import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown"; |
|
|
|
@@ -252,7 +253,7 @@ interface PolInputResult { |
|
|
|
dnQty: string, |
|
|
|
} |
|
|
|
|
|
|
|
/** FP-MTMS Version Checklist | Functions Ref. No. 56 | v1.0.0 | 2026-08-06 */ |
|
|
|
/** FP-MTMS Version Checklist | Functions Ref. No. 56 | v1.0.1 | 2026-08-12 */ |
|
|
|
const PoDetail: React.FC<Props> = ({ po, warehouse, printerCombo }) => { |
|
|
|
const cameras = useContext(CameraContext); |
|
|
|
const { data: session } = useSession(); |
|
|
|
@@ -302,16 +303,43 @@ const PoDetail: React.FC<Props> = ({ po, warehouse, printerCombo }) => { |
|
|
|
const [selectedRow, setSelectedRow] = useState<PurchaseOrderLine | null>(null); |
|
|
|
const [stockInLine, setStockInLine] = useState<StockInLine[]>([]); |
|
|
|
const [processedQty, setProcessedQty] = useState(0); |
|
|
|
/** Tracks user/nav selection so query patches via history.replaceState stay authoritative. */ |
|
|
|
const selectedPolIdRef = useRef<number | null>(null); |
|
|
|
|
|
|
|
/** Patch PO edit query without Next soft-navigation (avoids scroll-to-top). */ |
|
|
|
const patchPoEditQuery = useCallback( |
|
|
|
(mutate: (params: URLSearchParams) => void) => { |
|
|
|
if (typeof window === "undefined") return; |
|
|
|
const params = new URLSearchParams(window.location.search); |
|
|
|
mutate(params); |
|
|
|
const qs = params.toString(); |
|
|
|
window.history.replaceState( |
|
|
|
window.history.state, |
|
|
|
"", |
|
|
|
qs ? `${pathname}?${qs}` : pathname, |
|
|
|
); |
|
|
|
}, |
|
|
|
[pathname], |
|
|
|
); |
|
|
|
|
|
|
|
/** Keep selection + bottom stock-in grid in sync with selected / URL `polId`. */ |
|
|
|
useEffect(() => { |
|
|
|
const polIdParam = searchParams.get("polId"); |
|
|
|
if (!polIdParam || rows.length === 0) return; |
|
|
|
const match = rows.find((r) => r.id.toString() === polIdParam); |
|
|
|
if (match) { |
|
|
|
setSelectedRow(match); |
|
|
|
setStockInLine(match.stockInLine); |
|
|
|
setProcessedQty(match.processed); |
|
|
|
} |
|
|
|
if (rows.length === 0) return; |
|
|
|
const urlPolId = searchParams.get("polId"); |
|
|
|
const preferredId = |
|
|
|
selectedPolIdRef.current ?? |
|
|
|
(urlPolId != null ? Number(urlPolId) : null); |
|
|
|
if (preferredId == null || Number.isNaN(preferredId)) return; |
|
|
|
const match = |
|
|
|
rows.find((r) => r.id === preferredId) ?? |
|
|
|
(urlPolId != null |
|
|
|
? rows.find((r) => r.id.toString() === urlPolId) |
|
|
|
: undefined); |
|
|
|
if (!match) return; |
|
|
|
selectedPolIdRef.current = match.id; |
|
|
|
setSelectedRow(match); |
|
|
|
setStockInLine(match.stockInLine ?? []); |
|
|
|
setProcessedQty(match.processed); |
|
|
|
}, [rows, searchParams]); |
|
|
|
|
|
|
|
const router = useRouter(); |
|
|
|
@@ -465,9 +493,10 @@ const PoDetail: React.FC<Props> = ({ po, warehouse, printerCombo }) => { |
|
|
|
}); |
|
|
|
setRows(result.pol || []); |
|
|
|
if (result.pol && result.pol.length > 0) { |
|
|
|
const targetPolId = preferredPolId ?? selectedRow?.id; |
|
|
|
const targetPolId = preferredPolId ?? selectedPolIdRef.current ?? selectedRow?.id; |
|
|
|
const targetPol = |
|
|
|
result.pol.find((p) => p.id === targetPolId) ?? result.pol[0]; |
|
|
|
selectedPolIdRef.current = targetPol.id; |
|
|
|
setSelectedRow(targetPol); |
|
|
|
setStockInLine(targetPol.stockInLine); |
|
|
|
setProcessedQty(targetPol.processed); |
|
|
|
@@ -482,6 +511,7 @@ const PoDetail: React.FC<Props> = ({ po, warehouse, printerCombo }) => { |
|
|
|
const handlePoSelect = useCallback( |
|
|
|
async (selectedPo: PoResult) => { |
|
|
|
if (selectedPo.id === selectedPoId) return; |
|
|
|
selectedPolIdRef.current = null; |
|
|
|
setSelectedPoId(selectedPo.id); |
|
|
|
await fetchPoDetail(selectedPo.id.toString()); |
|
|
|
const newSelectedIds = selectedIdsParam || selectedPo.id.toString(); |
|
|
|
@@ -570,13 +600,6 @@ const PoDetail: React.FC<Props> = ({ po, warehouse, printerCombo }) => { |
|
|
|
() => returnWeightUnit(row.uom), |
|
|
|
[row.uom], |
|
|
|
); |
|
|
|
useEffect(() => { |
|
|
|
const polId = searchParams.get("polId") != null ? parseInt(searchParams.get("polId")!) : null |
|
|
|
if (polId) { |
|
|
|
setStockInLine(rows.find((r) => r.id == polId)!.stockInLine) |
|
|
|
} |
|
|
|
}, []); |
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
// `processedQty` comes from putAwayLines (stock unit). |
|
|
|
// After the fix, `row.qty` is qtyM18 (M18 unit), so compare using stockUom demand. |
|
|
|
@@ -595,23 +618,22 @@ const PoDetail: React.FC<Props> = ({ po, warehouse, printerCombo }) => { |
|
|
|
setDnQtyInput(polInputList[row.id]?.dnQty ?? ""); |
|
|
|
}, [polInputList, row.id]); |
|
|
|
|
|
|
|
const handleRowSelect = () => { |
|
|
|
// setSelectedRowId(row.id); |
|
|
|
setSelectedRow(row); |
|
|
|
setStockInLine(row.stockInLine); |
|
|
|
setProcessedQty(row.processed); |
|
|
|
}; |
|
|
|
const changeStockInLines = useCallback( |
|
|
|
(id: number) => { |
|
|
|
//rows = purchaseOrderLine |
|
|
|
const target = rows.find((r) => r.id === id) |
|
|
|
const stockInLine = target!.stockInLine |
|
|
|
setStockInLine(stockInLine) |
|
|
|
setSelectedRow(target!) |
|
|
|
// console.log(pathname) |
|
|
|
// router.replace(`/po/edit?id=${item.poId}&polId=${item.polId}&stockInLineId=${item.stockInLineId}`); |
|
|
|
const target = rows.find((r) => r.id === id); |
|
|
|
if (!target) return; |
|
|
|
selectedPolIdRef.current = id; |
|
|
|
setSelectedRow(target); |
|
|
|
setStockInLine(target.stockInLine ?? []); |
|
|
|
setProcessedQty(target.processed); |
|
|
|
|
|
|
|
// history.replaceState: keep URL in sync without scrolling to top |
|
|
|
patchPoEditQuery((params) => { |
|
|
|
params.set("polId", String(id)); |
|
|
|
params.delete("stockInLineId"); |
|
|
|
}); |
|
|
|
}, |
|
|
|
[rows] |
|
|
|
[rows, patchPoEditQuery], |
|
|
|
); |
|
|
|
|
|
|
|
const handleStart = useCallback( |
|
|
|
@@ -644,7 +666,12 @@ const PoDetail: React.FC<Props> = ({ po, warehouse, printerCombo }) => { |
|
|
|
...prev, |
|
|
|
[row.id]: { lotNo: "", dnQty: "" }, |
|
|
|
})); |
|
|
|
selectedPolIdRef.current = row.id; |
|
|
|
setSelectedRow(row); |
|
|
|
patchPoEditQuery((params) => { |
|
|
|
params.set("polId", String(row.id)); |
|
|
|
params.delete("stockInLineId"); |
|
|
|
}); |
|
|
|
fetchPoDetail(selectedPoId.toString(), true, row.id); |
|
|
|
} |
|
|
|
console.log(res); |
|
|
|
@@ -662,7 +689,7 @@ const PoDetail: React.FC<Props> = ({ po, warehouse, printerCombo }) => { |
|
|
|
doSubmit(); |
|
|
|
} |
|
|
|
}, |
|
|
|
[dnQtyInput, row, dnFormProps, selectedPoId, fetchPoDetail, t, lotNoInput], |
|
|
|
[dnQtyInput, row, dnFormProps, selectedPoId, fetchPoDetail, t, lotNoInput, patchPoEditQuery], |
|
|
|
); |
|
|
|
|
|
|
|
const syncRowInputToParent = useCallback((lotNo: string, dnQty: string) => { |
|
|
|
@@ -746,8 +773,6 @@ const PoDetail: React.FC<Props> = ({ po, warehouse, printerCombo }) => { |
|
|
|
)} |
|
|
|
<Radio |
|
|
|
checked={selectedRow?.id === row.id} |
|
|
|
// onChange={handleRowSelect} |
|
|
|
// onClick={(e) => e.stopPropagation()} |
|
|
|
/> |
|
|
|
</TableCell> |
|
|
|
<TableCell align="left" sx={{ width: 88, maxWidth: 88, px: 1, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }} title={row.itemNo}> |
|
|
|
|