| @@ -71,7 +71,7 @@ const InventoryLotLineTable: React.FC<Props> = ({ | |||||
| const [startLocation, setStartLocation] = useState<string>(""); | const [startLocation, setStartLocation] = useState<string>(""); | ||||
| const [targetLocation, setTargetLocation] = useState<number | null>(null); // Store warehouse ID instead of code | const [targetLocation, setTargetLocation] = useState<number | null>(null); // Store warehouse ID instead of code | ||||
| const [targetLocationInput, setTargetLocationInput] = useState<string>(""); | const [targetLocationInput, setTargetLocationInput] = useState<string>(""); | ||||
| const [qtyToBeTransferred, setQtyToBeTransferred] = useState<number>(0); | |||||
| const [qtyToBeTransferred, setQtyToBeTransferred] = useState<string>(""); | |||||
| const [warehouses, setWarehouses] = useState<WarehouseResult[]>([]); | const [warehouses, setWarehouses] = useState<WarehouseResult[]>([]); | ||||
| const [printModalOpen, setPrintModalOpen] = useState(false); | const [printModalOpen, setPrintModalOpen] = useState(false); | ||||
| const [lotLineForPrint, setLotLineForPrint] = useState<InventoryLotLineResult | null>(null); | const [lotLineForPrint, setLotLineForPrint] = useState<InventoryLotLineResult | null>(null); | ||||
| @@ -117,7 +117,18 @@ const InventoryLotLineTable: React.FC<Props> = ({ | |||||
| return base.filter((line) => line.lotNo === f); | return base.filter((line) => line.lotNo === f); | ||||
| }, [inventoryLotLines, filterLotNo]); | }, [inventoryLotLines, filterLotNo]); | ||||
| const originalQty = selectedLotLine?.availableQty || 0; | const originalQty = selectedLotLine?.availableQty || 0; | ||||
| const remainingQty = originalQty - qtyToBeTransferred; | |||||
| const validatedTransferQty = useMemo(() => { | |||||
| const raw = (qtyToBeTransferred ?? '').replace(/\D/g, ''); | |||||
| if (raw === '') return 0; | |||||
| const parsed = parseInt(raw, 10); | |||||
| if (Number.isNaN(parsed)) return 0; | |||||
| if (originalQty < 1) return 0; | |||||
| const minClamped = Math.max(1, parsed); | |||||
| return Math.min(minClamped, originalQty); | |||||
| }, [qtyToBeTransferred, originalQty]); | |||||
| const remainingQty = originalQty - validatedTransferQty; | |||||
| const prevAdjustmentModalOpenRef = useRef(false); | const prevAdjustmentModalOpenRef = useRef(false); | ||||
| @@ -315,7 +326,7 @@ const prevAdjustmentModalOpenRef = useRef(false); | |||||
| setStartLocation(lotLine.warehouse.code || ""); | setStartLocation(lotLine.warehouse.code || ""); | ||||
| setTargetLocation(null); | setTargetLocation(null); | ||||
| setTargetLocationInput(""); | setTargetLocationInput(""); | ||||
| setQtyToBeTransferred(lotLine.availableQty >= 1 ? 1 : 0); | |||||
| setQtyToBeTransferred(""); | |||||
| }, | }, | ||||
| [], | [], | ||||
| ); | ); | ||||
| @@ -471,11 +482,11 @@ const prevAdjustmentModalOpenRef = useRef(false); | |||||
| setStartLocation(""); | setStartLocation(""); | ||||
| setTargetLocation(null); | setTargetLocation(null); | ||||
| setTargetLocationInput(""); | setTargetLocationInput(""); | ||||
| setQtyToBeTransferred(0); | |||||
| setQtyToBeTransferred(""); | |||||
| }, []); | }, []); | ||||
| const handleSubmitStockTransfer = useCallback(async () => { | const handleSubmitStockTransfer = useCallback(async () => { | ||||
| if (!selectedLotLine || !targetLocation || qtyToBeTransferred < 1) { | |||||
| if (!selectedLotLine || !targetLocation || validatedTransferQty < 1 || validatedTransferQty > originalQty) { | |||||
| return; | return; | ||||
| } | } | ||||
| @@ -484,7 +495,7 @@ const prevAdjustmentModalOpenRef = useRef(false); | |||||
| const request = { | const request = { | ||||
| inventoryLotLineId: selectedLotLine.id, | inventoryLotLineId: selectedLotLine.id, | ||||
| transferredQty: qtyToBeTransferred, | |||||
| transferredQty: validatedTransferQty, | |||||
| warehouseId: targetLocation, // targetLocation now contains warehouse ID | warehouseId: targetLocation, // targetLocation now contains warehouse ID | ||||
| }; | }; | ||||
| @@ -503,7 +514,7 @@ const prevAdjustmentModalOpenRef = useRef(false); | |||||
| } finally { | } finally { | ||||
| setIsUploading(false); | setIsUploading(false); | ||||
| } | } | ||||
| }, [selectedLotLine, targetLocation, qtyToBeTransferred, handleCloseStockTransferModal, setIsUploading, t, onStockTransferSuccess]); | |||||
| }, [selectedLotLine, targetLocation, validatedTransferQty, originalQty, handleCloseStockTransferModal, setIsUploading, t, onStockTransferSuccess]); | |||||
| return <> | return <> | ||||
| <Box sx={{ display: 'flex', alignItems: 'center', gap: 1, flexWrap: 'wrap', mb: 2 }}> | <Box sx={{ display: 'flex', alignItems: 'center', gap: 1, flexWrap: 'wrap', mb: 2 }}> | ||||
| @@ -662,15 +673,29 @@ const prevAdjustmentModalOpenRef = useRef(false); | |||||
| label={t("Qty To Be Transferred")} | label={t("Qty To Be Transferred")} | ||||
| fullWidth | fullWidth | ||||
| variant="outlined" | variant="outlined" | ||||
| type="number" | |||||
| type="text" | |||||
| inputMode="numeric" | |||||
| value={qtyToBeTransferred} | value={qtyToBeTransferred} | ||||
| onChange={(e) => { | onChange={(e) => { | ||||
| const value = parseInt(e.target.value) || 0; | |||||
| const minValue = 1; | |||||
| const maxValue = Math.max(0, originalQty); | |||||
| setQtyToBeTransferred(Math.min(Math.max(minValue, value), maxValue)); | |||||
| const raw = e.target.value.replace(/\D/g, ''); | |||||
| if (raw === '') { | |||||
| setQtyToBeTransferred(''); | |||||
| return; | |||||
| } | |||||
| const parsed = parseInt(raw, 10); | |||||
| if (Number.isNaN(parsed)) { | |||||
| setQtyToBeTransferred(''); | |||||
| return; | |||||
| } | |||||
| if (originalQty < 1) { | |||||
| setQtyToBeTransferred(''); | |||||
| return; | |||||
| } | |||||
| const clamped = Math.min(Math.max(1, parsed), originalQty); | |||||
| setQtyToBeTransferred(String(clamped)); | |||||
| }} | }} | ||||
| inputProps={{ min: 1, max: originalQty, step: 1 }} | |||||
| onFocus={(e) => (e.target as HTMLInputElement).select()} | |||||
| inputProps={{ pattern: "[0-9]*" }} | |||||
| InputLabelProps={{ | InputLabelProps={{ | ||||
| shrink: true, | shrink: true, | ||||
| sx: { fontSize: "0.9375rem" }, | sx: { fontSize: "0.9375rem" }, | ||||
| @@ -715,7 +740,7 @@ const prevAdjustmentModalOpenRef = useRef(false); | |||||
| fontSize: '0.9375rem', | fontSize: '0.9375rem', | ||||
| }} | }} | ||||
| onClick={handleSubmitStockTransfer} | onClick={handleSubmitStockTransfer} | ||||
| disabled={!selectedLotLine || !targetLocation || qtyToBeTransferred < 1 || qtyToBeTransferred > originalQty} | |||||
| disabled={!selectedLotLine || !targetLocation || validatedTransferQty < 1 || validatedTransferQty > originalQty} | |||||
| > | > | ||||
| {t("Submit")} | {t("Submit")} | ||||
| </Button> | </Button> | ||||