| @@ -1211,7 +1211,7 @@ export const fetchMaterialPickStatus = cache(async (): Promise<MaterialPickStatu | |||
| }) | |||
| export interface ProcessStatusInfo { | |||
| processName?: string | null; | |||
| equipmentDescription?: string | null; | |||
| equipmentName?: string | null; | |||
| equipmentDetailName?: string | null; | |||
| startTime?: string | null; | |||
| endTime?: string | null; | |||
| @@ -33,7 +33,7 @@ export interface PoResult { | |||
| status: string; | |||
| pol?: PurchaseOrderLine[]; | |||
| } | |||
| export type { StockInLine } from "../stockIn"; | |||
| export interface PurchaseOrderLine { | |||
| id: number; | |||
| purchaseOrderId: number; | |||
| @@ -127,6 +127,7 @@ export interface StockInLine { | |||
| joCode?: string; | |||
| warehouseCode?: string; | |||
| defaultWarehouseId: number; // id for now | |||
| locationCode?: string; | |||
| dnNo?: string; | |||
| dnDate?: number[]; | |||
| stockQty?: number; | |||
| @@ -285,7 +285,7 @@ const JobProcessStatus: React.FC = () => { | |||
| } | |||
| const label = [ | |||
| process.processName, | |||
| process.equipmentDescription, | |||
| process.equipmentName, | |||
| process.equipmentDetailName ? `-${process.equipmentDetailName}` : "", | |||
| ].filter(Boolean).join(" "); | |||
| // 如果工序是必需的,显示三行(Start、Finish、Wait Time) | |||
| @@ -20,6 +20,8 @@ import { useSession } from "next-auth/react"; | |||
| import { SessionWithTokens } from "@/config/authConfig"; | |||
| import dayjs from "dayjs"; | |||
| import { OUTPUT_DATE_FORMAT } from "@/app/utils/formatUtil"; | |||
| import { | |||
| fetchAllJoborderProductProcessInfo, | |||
| AllJoborderProductProcessInfoResponse, | |||
| @@ -50,6 +52,7 @@ const ProductProcessList: React.FC<ProductProcessListProps> = ({ onSelectProcess | |||
| const [openModal, setOpenModal] = useState<boolean>(false); | |||
| const [modalInfo, setModalInfo] = useState<StockInLineInput>(); | |||
| const currentUserId = session?.id ? parseInt(session.id) : undefined; | |||
| const [suggestedLocationCode, setSuggestedLocationCode] = useState<string | null>(null); | |||
| const handleAssignPickOrder = useCallback(async (pickOrderId: number, jobOrderId?: number, productProcessId?: number) => { | |||
| if (!currentUserId) { | |||
| @@ -87,17 +90,17 @@ const ProductProcessList: React.FC<ProductProcessListProps> = ({ onSelectProcess | |||
| alert(t(`Unknown error: ${error?.message || "Unknown error"}。Please try again later.`)); | |||
| } | |||
| }, [currentUserId, t, onSelectMatchingStock]); | |||
| const handleViewStockIn = useCallback((process: AllJoborderProductProcessInfoResponse) => { | |||
| if (!process.stockInLineId) { | |||
| alert(t("Invalid Stock In Line Id")); | |||
| return; | |||
| } | |||
| setModalInfo({ | |||
| id: process.stockInLineId, | |||
| //itemId: process.itemId, // 如果 process 中有 itemId,添加这一行 | |||
| //expiryDate: dayjs().add(1, "month").format(OUTPUT_DATE_FORMAT), | |||
| // 视需要补 itemId、jobOrderId 等 | |||
| }); | |||
| setOpenModal(true); | |||
| }, [t]); | |||
| @@ -316,13 +319,14 @@ const ProductProcessList: React.FC<ProductProcessListProps> = ({ onSelectProcess | |||
| })} | |||
| </Grid> | |||
| <QcStockInModal | |||
| session={sessionToken} | |||
| open={openModal} | |||
| onClose={closeNewModal} | |||
| inputDetail={modalInfo} | |||
| printerCombo={printerCombo} | |||
| printSource="productionProcess" | |||
| /> | |||
| session={sessionToken} | |||
| open={openModal} | |||
| onClose={closeNewModal} | |||
| inputDetail={modalInfo} | |||
| printerCombo={printerCombo} | |||
| warehouse={[]} | |||
| printSource="productionProcess" | |||
| /> | |||
| {processes.length > 0 && ( | |||
| <TablePagination | |||
| component="div" | |||
| @@ -174,42 +174,31 @@ const PutAwayModal: React.FC<Props> = ({ open, onClose, warehouse, stockInLineId | |||
| // 根据 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); | |||
| // 直接使用 fetchStockInLineInfo 返回的 locationCode | |||
| // 只在第一次上架时(firstWarehouseId === null)设置默认值 | |||
| if (itemDetail?.locationCode && warehouse.length > 0 && firstWarehouseId === null) { | |||
| const locationCode = itemDetail.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 (from API, display only):", "color:green", { | |||
| locationCode, | |||
| warehouseId: matchedWarehouse.id, | |||
| warehouseCode: matchedWarehouse.code | |||
| }); | |||
| } else { | |||
| console.log("%c No warehouse found for locationCode:", "color:yellow", locationCode); | |||
| } | |||
| } | |||
| }; | |||
| if (itemDetail && itemDetail.status === "received") { | |||
| fetchItemAndSetDefaultWarehouse(); | |||
| } | |||
| }, [itemDetail, warehouse, firstWarehouseId]); | |||
| }, [itemDetail?.locationCode, warehouse, firstWarehouseId]); | |||
| useEffect(() => { | |||
| // 只使用实际扫描的 warehouseId,不使用默认值进行验证 | |||
| @@ -119,12 +119,20 @@ const QcStockInModal: React.FC<Props> = ({ | |||
| const res = await fetchStockInLineInfo(stockInLineId); | |||
| if (res) { | |||
| console.log("%c Fetched Stock In Line: ", "color:orange", res); | |||
| console.log("%c [QC] itemId in response:", "color:yellow", res.itemId); | |||
| console.log("%c [QC] locationCode in response:", "color:yellow", res.locationCode); | |||
| // 如果 res 中没有 itemId,检查是否有其他方式获取 | |||
| if (!res.itemId) { | |||
| console.warn("%c [QC] Warning: itemId is missing in response!", "color:red"); | |||
| } | |||
| setStockInLineInfo({...inputDetail, ...res, expiryDate: res.expiryDate}); | |||
| // fetchQcResultData(stockInLineId); | |||
| } else throw("Result is undefined"); | |||
| } catch (e) { | |||
| console.log("%c Error when fetching Stock In Line: ", "color:red", e); | |||
| console.log("%c Error details: ", "color:red", { | |||
| message: e instanceof Error ? e.message : String(e), | |||
| stack: e instanceof Error ? e.stack : undefined | |||
| }); | |||
| alert("Something went wrong, please retry"); | |||
| closeHandler({}, "backdropClick"); | |||
| } | |||
| @@ -144,16 +152,24 @@ const QcStockInModal: React.FC<Props> = ({ | |||
| } | |||
| }, [open]); | |||
| useEffect(() => { | |||
| // 如果后端已经在 StockInLine 中返回了 locationCode,直接使用 | |||
| if (stockInLineInfo?.locationCode) { | |||
| setItemLocationCode(stockInLineInfo.locationCode); | |||
| console.log("%c [QC] item LocationCode from API:", "color:cyan", stockInLineInfo.locationCode); | |||
| return; | |||
| } | |||
| // 如果没有 locationCode,尝试从 itemId 获取(向后兼容) | |||
| const loadItemLocationCode = async () => { | |||
| if (!stockInLineInfo?.itemId) return; | |||
| try { | |||
| const itemResult = await fetchItemForPutAway(stockInLineInfo.itemId); | |||
| const item = itemResult.item; | |||
| const locationCode = item.LocationCode || item.locationCode || null; | |||
| setItemLocationCode(locationCode); | |||
| console.log("%c [QC] item LocationCode:", "color:cyan", locationCode); | |||
| console.log("%c [QC] item LocationCode from fetchItemForPutAway:", "color:cyan", locationCode); | |||
| } catch (error) { | |||
| console.error("Error fetching item to get LocationCode in QC:", error); | |||
| setItemLocationCode(null); | |||