|
|
|
@@ -32,7 +32,7 @@ import { DatePicker } from "@mui/x-date-pickers/DatePicker"; |
|
|
|
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; |
|
|
|
import dayjs from "dayjs"; |
|
|
|
import CheckIcon from "@mui/icons-material/Check"; |
|
|
|
import { submitStockAdjustment, StockAdjustmentLineRequest } from "@/app/api/stockAdjustment/actions"; |
|
|
|
import { submitStockAdjustment, StockAdjustmentLineRequest, fetchLatestAdjustmentRemarks } from "@/app/api/stockAdjustment/actions"; |
|
|
|
import { useSession } from "next-auth/react"; |
|
|
|
import { AUTH, hasAbility } from "@/authorities"; |
|
|
|
|
|
|
|
@@ -59,7 +59,7 @@ interface Props { |
|
|
|
onStockAdjustmentSuccess?: () => void | Promise<void>; |
|
|
|
} |
|
|
|
|
|
|
|
/** FP-MTMS Version Checklist | Functions Ref. No. 3 | v1.0.6 | 2026-09-07 */ |
|
|
|
/** FP-MTMS Version Checklist | Functions Ref. No. 3 | v1.0.7 | 2026-09-08 */ |
|
|
|
const InventoryLotLineTable: React.FC<Props> = ({ |
|
|
|
inventoryLotLines, pagingController, setPagingController, totalCount, inventory, |
|
|
|
filterLotNo, |
|
|
|
@@ -99,7 +99,11 @@ const InventoryLotLineTable: React.FC<Props> = ({ |
|
|
|
remarks: '', |
|
|
|
}); |
|
|
|
const originalAdjustmentLinesRef = useRef<AdjustmentEntry[]>([]); |
|
|
|
const adjustSaveInFlightRef = useRef(false); |
|
|
|
const loadedRemarksByLotRef = useRef<Map<string, string>>(new Map()); |
|
|
|
const remarksFetchGenRef = useRef(0); |
|
|
|
const [adjustmentEntries, setAdjustmentEntries] = useState<AdjustmentEntry[]>([]); |
|
|
|
const [isAdjustSaving, setIsAdjustSaving] = useState(false); |
|
|
|
useEffect(() => { |
|
|
|
if (stockTransferModalOpen) { |
|
|
|
fetchWarehouseListClient() |
|
|
|
@@ -153,9 +157,34 @@ const prevAdjustmentModalOpenRef = useRef(false); |
|
|
|
})); |
|
|
|
setAdjustmentEntries(initial); |
|
|
|
originalAdjustmentLinesRef.current = initial; |
|
|
|
loadedRemarksByLotRef.current = new Map(); |
|
|
|
const fetchGen = ++remarksFetchGenRef.current; |
|
|
|
const itemId = inventory.itemId; |
|
|
|
fetchLatestAdjustmentRemarks(itemId) |
|
|
|
.then((rows) => { |
|
|
|
if (fetchGen !== remarksFetchGenRef.current) return; |
|
|
|
const byLot = new Map<string, string>(); |
|
|
|
for (const row of rows ?? []) { |
|
|
|
const lot = row.lotNo?.trim(); |
|
|
|
const remarks = row.remarks?.trim(); |
|
|
|
if (!lot || !remarks || byLot.has(lot)) continue; |
|
|
|
byLot.set(lot, remarks); |
|
|
|
} |
|
|
|
loadedRemarksByLotRef.current = byLot; |
|
|
|
const apply = (line: AdjustmentEntry): AdjustmentEntry => { |
|
|
|
const lot = line.lotNo?.trim(); |
|
|
|
const remarks = (lot && byLot.get(lot)) || line.remarks || ''; |
|
|
|
return { ...line, remarks }; |
|
|
|
}; |
|
|
|
setAdjustmentEntries((prev) => prev.map(apply)); |
|
|
|
originalAdjustmentLinesRef.current = originalAdjustmentLinesRef.current.map(apply); |
|
|
|
}) |
|
|
|
.catch(console.error); |
|
|
|
} |
|
|
|
setPendingRemovalLineId(null); |
|
|
|
setRemovalReasons({}); |
|
|
|
} else if (!stockAdjustmentModalOpen) { |
|
|
|
remarksFetchGenRef.current += 1; |
|
|
|
} |
|
|
|
}, [stockAdjustmentModalOpen, inventory, availableLotLines]); |
|
|
|
|
|
|
|
@@ -164,12 +193,15 @@ const prevAdjustmentModalOpenRef = useRef(false); |
|
|
|
setPendingRemovalLineId(null); |
|
|
|
setRemovalReasons({}); |
|
|
|
setAdjustmentEntries( |
|
|
|
(availableLotLines ?? []).map((line) => ({ |
|
|
|
...line, |
|
|
|
adjustedQty: line.availableQty ?? 0, |
|
|
|
originalQty: line.availableQty ?? 0, |
|
|
|
remarks: '', |
|
|
|
})) |
|
|
|
(availableLotLines ?? []).map((line) => { |
|
|
|
const lot = line.lotNo?.trim(); |
|
|
|
return { |
|
|
|
...line, |
|
|
|
adjustedQty: line.availableQty ?? 0, |
|
|
|
originalQty: line.availableQty ?? 0, |
|
|
|
remarks: (lot && loadedRemarksByLotRef.current.get(lot)) || '', |
|
|
|
}; |
|
|
|
}) |
|
|
|
); |
|
|
|
}, [availableLotLines]); |
|
|
|
|
|
|
|
@@ -241,15 +273,26 @@ const prevAdjustmentModalOpenRef = useRef(false); |
|
|
|
expiryDate, |
|
|
|
warehouseId: line.warehouse?.id ?? 0, |
|
|
|
uom: line.uom ?? null, |
|
|
|
remarks: line.remarks?.trim() || null, |
|
|
|
}; |
|
|
|
}, []); |
|
|
|
|
|
|
|
const handleAdjustmentSave = useCallback(async () => { |
|
|
|
if (!inventory) return; |
|
|
|
const itemCode = inventory.itemCode; |
|
|
|
const originalLines = originalAdjustmentLinesRef.current.map((line) => toApiLine(line, itemCode)); |
|
|
|
const currentLines = adjustmentEntries.map((line) => toApiLine(line, itemCode)); |
|
|
|
if (adjustSaveInFlightRef.current) return; |
|
|
|
adjustSaveInFlightRef.current = true; |
|
|
|
setIsAdjustSaving(true); |
|
|
|
try { |
|
|
|
const itemCode = inventory.itemCode; |
|
|
|
const currentIds = new Set(adjustmentEntries.map((line) => line.id)); |
|
|
|
const originalLines = originalAdjustmentLinesRef.current.map((line) => { |
|
|
|
const api = toApiLine(line, itemCode); |
|
|
|
if (!currentIds.has(line.id)) { |
|
|
|
api.remarks = removalReasons[line.id]?.trim() || null; |
|
|
|
} |
|
|
|
return api; |
|
|
|
}); |
|
|
|
const currentLines = adjustmentEntries.map((line) => toApiLine(line, itemCode)); |
|
|
|
setIsUploading(true); |
|
|
|
await submitStockAdjustment({ |
|
|
|
itemId: inventory.itemId, |
|
|
|
@@ -264,8 +307,10 @@ const prevAdjustmentModalOpenRef = useRef(false); |
|
|
|
msgError(message || t("Save failed")); |
|
|
|
} finally { |
|
|
|
setIsUploading(false); |
|
|
|
setIsAdjustSaving(false); |
|
|
|
adjustSaveInFlightRef.current = false; |
|
|
|
} |
|
|
|
}, [adjustmentEntries, inventory, t, toApiLine, onStockAdjustmentSuccess]); |
|
|
|
}, [adjustmentEntries, inventory, t, toApiLine, onStockAdjustmentSuccess, removalReasons]); |
|
|
|
|
|
|
|
const handleOpenAddEntry = useCallback(() => { |
|
|
|
setAddEntryForm({ |
|
|
|
@@ -857,7 +902,7 @@ const prevAdjustmentModalOpenRef = useRef(false); |
|
|
|
color="primary" |
|
|
|
startIcon={<SaveIcon />} |
|
|
|
onClick={handleAdjustmentSave} |
|
|
|
disabled={!hasAdjustmentChange} |
|
|
|
disabled={!hasAdjustmentChange || isAdjustSaving} |
|
|
|
> |
|
|
|
{t("Save")} |
|
|
|
</Button> |
|
|
|
@@ -1004,7 +1049,9 @@ const prevAdjustmentModalOpenRef = useRef(false); |
|
|
|
}, |
|
|
|
}} |
|
|
|
/> |
|
|
|
) : null} |
|
|
|
) : ( |
|
|
|
line.remarks || null |
|
|
|
)} |
|
|
|
</TableCell> |
|
|
|
<TableCell align="center"> |
|
|
|
{pendingRemovalLineId === line.id ? ( |
|
|
|
|