|
|
|
@@ -12,6 +12,9 @@ import { |
|
|
|
Paper, |
|
|
|
Divider, |
|
|
|
} from "@mui/material"; |
|
|
|
import { fetchItemForPutAway } from "@/app/api/stockIn/actions"; |
|
|
|
import { Result } from "@/app/api/settings/item"; // 只导入类型 |
|
|
|
|
|
|
|
import { useCallback, useEffect, useLayoutEffect, useMemo, useState } from "react"; |
|
|
|
import ReactQrCodeScanner, { |
|
|
|
ScannerConfig, |
|
|
|
@@ -36,6 +39,7 @@ import { QrCodeScanner } from "../QrCodeScannerProvider/QrCodeScannerProvider"; |
|
|
|
import { msg } from "../Swal/CustomAlerts"; |
|
|
|
import { PutAwayRecord } from "."; |
|
|
|
import FgStockInForm from "../StockIn/FgStockInForm"; |
|
|
|
|
|
|
|
import Swal from "sweetalert2"; |
|
|
|
|
|
|
|
|
|
|
|
@@ -45,6 +49,7 @@ interface Props extends Omit<ModalProps, "children"> { |
|
|
|
warehouseId: number; |
|
|
|
scanner: QrCodeScanner; |
|
|
|
addPutAwayHistory: (putAwayData: PutAwayRecord) => void; |
|
|
|
onSetDefaultWarehouseId?: (warehouseId: number) => void; // 新增回调 |
|
|
|
} |
|
|
|
const style = { |
|
|
|
position: "absolute", |
|
|
|
@@ -76,7 +81,7 @@ const scannerStyle = { |
|
|
|
maxWidth: "600px", |
|
|
|
}; |
|
|
|
|
|
|
|
const PutAwayModal: React.FC<Props> = ({ open, onClose, warehouse, stockInLineId, warehouseId, scanner, addPutAwayHistory }) => { |
|
|
|
const PutAwayModal: React.FC<Props> = ({ open, onClose, warehouse, stockInLineId, warehouseId, scanner, addPutAwayHistory, onSetDefaultWarehouseId }) => { |
|
|
|
const { t } = useTranslation("putAway"); |
|
|
|
const [serverError, setServerError] = useState(""); |
|
|
|
const params = useSearchParams(); |
|
|
|
@@ -86,13 +91,14 @@ const PutAwayModal: React.FC<Props> = ({ open, onClose, warehouse, stockInLineId |
|
|
|
const [warehouseMismatchError, setWarehouseMismatchError] = useState<string>(""); |
|
|
|
|
|
|
|
const [firstWarehouseInfo, setFirstWarehouseInfo] = useState<{name: string, code: string} | null>(null); |
|
|
|
|
|
|
|
const [itemDefaultWarehouseId, setItemDefaultWarehouseId] = useState<number | null>(null); |
|
|
|
|
|
|
|
const [itemDetail, setItemDetail] = useState<StockInLine>(); |
|
|
|
const [totalPutAwayQty, setTotalPutAwayQty] = useState<number>(0); |
|
|
|
const [unavailableText, setUnavailableText] = useState<string | undefined>( |
|
|
|
undefined, |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
const [putQty, setPutQty] = useState<number>(itemDetail?.acceptedQty ?? 0); |
|
|
|
const [verified, setVerified] = useState<boolean>(false); |
|
|
|
const [qtyError, setQtyError] = useState<string>(""); |
|
|
|
@@ -136,6 +142,9 @@ const PutAwayModal: React.FC<Props> = ({ open, onClose, warehouse, stockInLineId |
|
|
|
setVerified(false); |
|
|
|
setItemDetail(undefined); |
|
|
|
setTotalPutAwayQty(0); |
|
|
|
setItemDefaultWarehouseId(null); |
|
|
|
setFirstWarehouseId(null); |
|
|
|
setFirstWarehouseInfo(null); |
|
|
|
onClose?.(...args); |
|
|
|
// reset(); |
|
|
|
}, |
|
|
|
@@ -162,11 +171,53 @@ const PutAwayModal: React.FC<Props> = ({ open, onClose, warehouse, stockInLineId |
|
|
|
scanner.startScan(); |
|
|
|
console.log("%c Scanning started ", "color:cyan"); |
|
|
|
}; |
|
|
|
|
|
|
|
// 根据 item 的 locationCode 设置默认 warehouseId |
|
|
|
useEffect(() => { |
|
|
|
const fetchItemAndSetDefaultWarehouse = async () => { |
|
|
|
if (itemDetail?.itemId && warehouse.length > 0 && firstWarehouseId === null) { |
|
|
|
// 只在第一次上架时设置默认值 |
|
|
|
try { |
|
|
|
const itemResult = await fetchItemForPutAway(itemDetail.itemId); |
|
|
|
const item = itemResult.item; |
|
|
|
|
|
|
|
// 获取 item 的 locationCode(处理大小写问题) |
|
|
|
const locationCode = item.LocationCode || item.locationCode; |
|
|
|
|
|
|
|
if (locationCode) { |
|
|
|
// 根据 locationCode 查找对应的 warehouse(通过 code 匹配) |
|
|
|
const matchedWarehouse = warehouse.find( |
|
|
|
(w) => w.code === locationCode || w.code?.toLowerCase() === locationCode?.toLowerCase() |
|
|
|
); |
|
|
|
|
|
|
|
if (matchedWarehouse) { |
|
|
|
// 只设置用于显示的默认值,不通知父组件 |
|
|
|
setItemDefaultWarehouseId(matchedWarehouse.id); |
|
|
|
console.log("%c Set default warehouse from item locationCode (display only):", "color:green", { |
|
|
|
locationCode, |
|
|
|
warehouseId: matchedWarehouse.id, |
|
|
|
warehouseCode: matchedWarehouse.code |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
console.error("Error fetching item to get default warehouse:", error); |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
if (itemDetail && itemDetail.status === "received") { |
|
|
|
fetchItemAndSetDefaultWarehouse(); |
|
|
|
} |
|
|
|
}, [itemDetail, warehouse, firstWarehouseId]); |
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
// 只使用实际扫描的 warehouseId,不使用默认值进行验证 |
|
|
|
if (warehouseId > 0 && firstWarehouseId !== null) { |
|
|
|
// 第二次及后续上架:必须使用第一次的仓库 |
|
|
|
if (warehouseId !== firstWarehouseId) { |
|
|
|
const firstWh = warehouse.find((w) => w.id == firstWarehouseId); |
|
|
|
const scannedWh = warehouse.find((w) => w.id == warehouseId); |
|
|
|
const firstWh = warehouse.find((w) => w.id == firstWarehouseId); |
|
|
|
const scannedWh = warehouse.find((w) => w.id == warehouseId); |
|
|
|
setWarehouseMismatchError("倉庫不匹配!必須使用首次上架的倉庫"); |
|
|
|
setVerified(false); |
|
|
|
} else { |
|
|
|
@@ -179,7 +230,7 @@ const PutAwayModal: React.FC<Props> = ({ open, onClose, warehouse, stockInLineId |
|
|
|
} |
|
|
|
} |
|
|
|
} else if (warehouseId > 0 && firstWarehouseId === null) { |
|
|
|
// First put away - no validation needed |
|
|
|
// 第一次上架 - 只接受扫描的 warehouseId |
|
|
|
if (scanner.isScanning) { |
|
|
|
setIsOpenScanner(false); |
|
|
|
setVerified(true); |
|
|
|
@@ -187,13 +238,17 @@ const PutAwayModal: React.FC<Props> = ({ open, onClose, warehouse, stockInLineId |
|
|
|
scanner.resetScan(); |
|
|
|
} |
|
|
|
} |
|
|
|
}, [warehouseId, firstWarehouseId]) |
|
|
|
}, [warehouseId, firstWarehouseId, scanner.isScanning]); |
|
|
|
|
|
|
|
const warehouseDisplay = useMemo(() => { |
|
|
|
const targetWarehouseId = firstWarehouseId || warehouseId || 1; |
|
|
|
const wh = warehouse.find((w) => w.id == warehouseId) ?? warehouse.find((w) => w.id == 1); |
|
|
|
// 优先使用扫描的 warehouseId,如果没有扫描则显示默认值作为建议 |
|
|
|
const displayWarehouseId = warehouseId > 0 |
|
|
|
? warehouseId |
|
|
|
: (itemDefaultWarehouseId || firstWarehouseId || 0); |
|
|
|
|
|
|
|
const wh = warehouse.find((w) => w.id == displayWarehouseId) ?? warehouse.find((w) => w.id == 1); |
|
|
|
return <>{wh?.name} <br/> [{wh?.code}]</>; |
|
|
|
}, [warehouse, warehouseId, firstWarehouseId,verified]); |
|
|
|
}, [warehouse, warehouseId, itemDefaultWarehouseId, firstWarehouseId, verified]); |
|
|
|
|
|
|
|
// useEffect(() => { // Restart scanner for changing warehouse |
|
|
|
// if (warehouseId > 0) { |
|
|
|
@@ -285,7 +340,7 @@ const PutAwayModal: React.FC<Props> = ({ open, onClose, warehouse, stockInLineId |
|
|
|
else |
|
|
|
// if (qty > itemDetail?.acceptedQty!!) { |
|
|
|
// setQtyError(`${t("putQty must not greater than")} ${ |
|
|
|
// itemDetail?.acceptedQty}` ); |
|
|
|
// itemDetail?.acceptedQty!!}` ); |
|
|
|
// } else |
|
|
|
if (qty < 1) { |
|
|
|
setQtyError(t("minimal value is 1")); |
|
|
|
@@ -303,7 +358,12 @@ const PutAwayModal: React.FC<Props> = ({ open, onClose, warehouse, stockInLineId |
|
|
|
// qty: acceptQty; |
|
|
|
// } |
|
|
|
try { |
|
|
|
if (firstWarehouseId !== null && warehouseId !== firstWarehouseId) { |
|
|
|
// 确定最终使用的 warehouseId |
|
|
|
const effectiveWarehouseId = warehouseId > 0 |
|
|
|
? warehouseId |
|
|
|
: (itemDefaultWarehouseId || 0); |
|
|
|
|
|
|
|
if (firstWarehouseId !== null && effectiveWarehouseId !== firstWarehouseId) { |
|
|
|
setWarehouseMismatchError("倉庫不匹配!必須使用首次上架的倉庫"); |
|
|
|
return; |
|
|
|
} |
|
|
|
@@ -327,7 +387,7 @@ const PutAwayModal: React.FC<Props> = ({ open, onClose, warehouse, stockInLineId |
|
|
|
// for putaway data |
|
|
|
|
|
|
|
inventoryLotLines: [{ |
|
|
|
warehouseId: warehouseId, |
|
|
|
warehouseId: effectiveWarehouseId, |
|
|
|
qty: putQty, |
|
|
|
}], |
|
|
|
// data.putAwayLines?.filter((line) => line._isNew !== false) |
|
|
|
@@ -356,8 +416,8 @@ const PutAwayModal: React.FC<Props> = ({ open, onClose, warehouse, stockInLineId |
|
|
|
poCode: itemDetail?.poCode, |
|
|
|
joCode: itemDetail?.joCode, |
|
|
|
lotNo: itemDetail?.lotNo, |
|
|
|
warehouseCode: warehouse.find((w) => w.id == warehouseId)?.code, |
|
|
|
warehouse: warehouse.find((w) => w.id == warehouseId)?.name, |
|
|
|
warehouseCode: warehouse.find((w) => w.id == effectiveWarehouseId)?.code, |
|
|
|
warehouse: warehouse.find((w) => w.id == effectiveWarehouseId)?.name, |
|
|
|
putQty: putQty, |
|
|
|
uom: itemDetail?.uom?.udfudesc, |
|
|
|
} as PutAwayRecord; |
|
|
|
@@ -376,7 +436,7 @@ const PutAwayModal: React.FC<Props> = ({ open, onClose, warehouse, stockInLineId |
|
|
|
console.log(e); |
|
|
|
} |
|
|
|
}, |
|
|
|
[t, itemDetail, putQty, warehouseId, firstWarehouseId], |
|
|
|
[t, itemDetail, putQty, warehouseId, itemDefaultWarehouseId, firstWarehouseId, warehouse], |
|
|
|
); |
|
|
|
|
|
|
|
return ( |
|
|
|
|