|
- "use client";
-
- import {
- Autocomplete,
- Box,
- Button,
- CircularProgress,
- FormControl,
- Grid,
- Paper,
- Stack,
- Table,
- TableBody,
- TableCell,
- TableContainer,
- TableHead,
- TableRow,
- TextField,
- Typography,
- Checkbox,
- FormControlLabel,
- Select,
- MenuItem,
- InputLabel,
- TablePagination,
- } from "@mui/material";
- import { useCallback, useEffect, useMemo, useState } from "react";
- import { useTranslation } from "react-i18next";
- import {
- ByItemsSummary,
- ConsoPickOrderResult,
- PickOrderLine,
- PickOrderResult,
- } from "@/app/api/pickOrder";
- import { useRouter } from "next/navigation";
- import { GridInputRowSelectionModel } from "@mui/x-data-grid";
- import {
- fetchConsoDetail,
- fetchConsoPickOrderClient,
- releasePickOrder,
- ReleasePickOrderInputs,
- fetchPickOrderDetails,
- fetchAllPickOrderDetails,
- GetPickOrderInfoResponse,
- GetPickOrderLineInfo,
- createStockOutLine,
- updateStockOutLineStatus,
- resuggestPickOrder,
- checkAndCompletePickOrderByConsoCode,
- } from "@/app/api/pickOrder/actions";
- import { EditNote } from "@mui/icons-material";
- import { fetchNameList, NameList } from "@/app/api/user/actions";
- import {
- FormProvider,
- SubmitErrorHandler,
- SubmitHandler,
- useForm,
- } from "react-hook-form";
- import { OUTPUT_DATE_FORMAT, pickOrderStatusMap } from "@/app/utils/formatUtil";
- import { QcItemWithChecks } from "@/app/api/qc";
- import { fetchQcItemCheck, fetchPickOrderQcResult } from "@/app/api/qc/actions";
-
- import { PurchaseQcResult } from "@/app/api/po/actions";
- //import PickQcStockInModalVer2 from "./PickQcStockInModalVer3";
- import { fetchPickOrderLineLotDetails, PickOrderLotDetailResponse } from "@/app/api/pickOrder/actions";
- import SearchResults, { Column } from "../SearchResults/SearchResults";
- import { defaultPagingController } from "../SearchResults/SearchResults";
- import SearchBox, { Criterion } from "../SearchBox";
- import dayjs from "dayjs";
- import { CreateStockOutLine , NoLotLineDto} from "@/app/api/pickOrder/actions";
- import LotTable from './LotTable';
- import PickOrderDetailsTable from './PickOrderDetailsTable'; // Import the new component
- import { updateInventoryLotLineStatus, updateInventoryStatus, updateInventoryLotLineQuantities } from "@/app/api/inventory/actions";
- import { useSession } from "next-auth/react";
- import { SessionWithTokens } from "@/config/authConfig";
-
- interface Props {
- filterArgs: Record<string, any>;
- }
-
- interface LotPickData {
- id: number;
- lotId: number | null;
- lotNo: string | null;
- expiryDate: string;
- location: string | null;
- stockUnit: string;
- inQty: number;
- outQty: number;
- holdQty: number;
- totalPickedByAllPickOrders: number;
- availableQty: number;
- requiredQty: number;
- actualPickQty: number;
- lotStatus: string;
- noLot?: boolean;
- lotAvailability: 'available' | 'insufficient_stock' | 'expired' | 'status_unavailable'|'rejected';
- stockOutLineId?: number;
- stockOutLineStatus?: string;
- stockOutLineQty?: number;
-
- }
-
- interface PickQtyData {
- [lineId: number]: {
- [lotId: number]: number;
- };
- }
-
- const PickExecution: React.FC<Props> = ({ filterArgs }) => {
- const { t } = useTranslation("pickOrder");
- const router = useRouter();
- const { data: session } = useSession() as { data: SessionWithTokens | null };
-
- const currentUserId = session?.id ? parseInt(session.id) : undefined;
-
- const [filteredPickOrders, setFilteredPickOrders] = useState(
- [] as ConsoPickOrderResult[],
- );
- const [isLoading, setIsLoading] = useState(false);
- const [selectedConsoCode, setSelectedConsoCode] = useState<string | undefined>();
- const [revertIds, setRevertIds] = useState<GridInputRowSelectionModel>([]);
- const [totalCount, setTotalCount] = useState<number>();
- const [usernameList, setUsernameList] = useState<NameList[]>([]);
-
- const [byPickOrderRows, setByPickOrderRows] = useState<
- Omit<PickOrderResult, "items">[] | undefined
- >(undefined);
- const [byItemsRows, setByItemsRows] = useState<ByItemsSummary[] | undefined>(
- undefined,
- );
- const [disableRelease, setDisableRelease] = useState<boolean>(true);
- const [selectedRowId, setSelectedRowId] = useState<number | null>(null);
-
- const [pickOrderDetails, setPickOrderDetails] = useState<GetPickOrderInfoResponse | null>(null);
- const [detailLoading, setDetailLoading] = useState(false);
-
- const [pickQtyData, setPickQtyData] = useState<PickQtyData>({});
- const [lotData, setLotData] = useState<LotPickData[]>([]);
-
- const [qcItems, setQcItems] = useState<QcItemWithChecks[]>([]);
- const [qcModalOpen, setQcModalOpen] = useState(false);
- const [selectedItemForQc, setSelectedItemForQc] = useState<GetPickOrderLineInfo & {
- pickOrderCode: string;
- qcResult?: PurchaseQcResult[];
- } | null>(null);
- const [selectedLotForQc, setSelectedLotForQc] = useState<LotPickData | null>(null);
-
- const [selectedLotRowId, setSelectedLotRowId] = useState<string | null>(null);
- const [selectedLotId, setSelectedLotId] = useState<number | null>(null);
-
- // Keep only the main table paging controller
- const [mainTablePagingController, setMainTablePagingController] = useState({
- pageNum: 0,
- pageSize: 10,
- });
- const [lotTablePagingController, setLotTablePagingController] = useState({
- pageNum: 0,
- pageSize: 10,
- });
-
- const [searchQuery, setSearchQuery] = useState<Record<string, any>>({});
- const [originalPickOrderData, setOriginalPickOrderData] = useState<GetPickOrderInfoResponse | null>(null);
-
- const formProps = useForm<ReleasePickOrderInputs>();
- const errors = formProps.formState.errors;
-
- const onDetailClick = useCallback(
- (pickOrder: any) => {
- console.log(pickOrder);
- const status = pickOrder.status;
- if (pickOrderStatusMap[status] >= 3) {
- router.push(`/pickOrder/detail?consoCode=${pickOrder.consoCode}`);
- } else {
- setSelectedConsoCode(pickOrder.consoCode);
- }
- },
- [router],
- );
-
- const fetchNewPageConsoPickOrder = useCallback(
- async (
- pagingController: Record<string, number>,
- filterArgs: Record<string, number>,
- ) => {
- setIsLoading(true);
- const params = {
- ...pagingController,
- ...filterArgs,
- };
- const res = await fetchConsoPickOrderClient(params);
- if (res) {
- console.log(res);
- setFilteredPickOrders(res.records);
- setTotalCount(res.total);
- }
- setIsLoading(false);
- },
- [],
- );
-
- useEffect(() => {
- fetchNewPageConsoPickOrder({ limit: 10, offset: 0 }, filterArgs);
- }, [fetchNewPageConsoPickOrder, filterArgs]);
-
-
- const isReleasable = useCallback((itemList: ByItemsSummary[]): boolean => {
- let isReleasable = true;
- for (const item of itemList) {
- isReleasable = item.requiredQty >= item.availableQty;
- if (!isReleasable) return isReleasable;
- }
- return isReleasable;
- }, []);
-
- const fetchConso = useCallback(
- async (consoCode: string) => {
- const res = await fetchConsoDetail(consoCode);
- const nameListRes = await fetchNameList();
- if (res) {
- console.log(res);
- setByPickOrderRows(res.pickOrders);
- setByItemsRows(res.items);
- setDisableRelease(isReleasable(res.items));
- } else {
- console.log("error");
- console.log(res);
- }
- if (nameListRes) {
- console.log(nameListRes);
- setUsernameList(nameListRes);
- }
- },
- [isReleasable],
- );
-
- const handleFetchAllPickOrderDetails = useCallback(async () => {
- setDetailLoading(true);
- try {
- const data = await fetchAllPickOrderDetails(currentUserId);
- console.log("All Pick Order Details for user:", currentUserId, data);
-
- if (data && data.pickOrders) {
- setPickOrderDetails(data);
- setOriginalPickOrderData(data);
-
- const initialPickQtyData: PickQtyData = {};
- data.pickOrders.forEach((pickOrder: any) => {
- pickOrder.pickOrderLines.forEach((line: any) => {
- initialPickQtyData[line.id] = {};
- });
- });
- setPickQtyData(initialPickQtyData);
- } else {
- console.log("No pick order data returned");
- setPickOrderDetails({
- consoCode: null,
- pickOrders: [],
- items: []
- });
- setOriginalPickOrderData({
- consoCode: null,
- pickOrders: [],
- items: []
- });
- setPickQtyData({});
- }
-
- } catch (error) {
- console.error("Error fetching all pick order details:", error);
- setPickOrderDetails({
- consoCode: null,
- pickOrders: [],
- items: []
- });
- setOriginalPickOrderData({
- consoCode: null,
- pickOrders: [],
- items: []
- });
- setPickQtyData({});
- } finally {
- setDetailLoading(false);
- }
- }, [currentUserId]);
-
- useEffect(() => {
- handleFetchAllPickOrderDetails();
- }, [handleFetchAllPickOrderDetails]);
-
- const onChange = useCallback(
- (event: React.SyntheticEvent, newValue: NameList) => {
- console.log(newValue);
- formProps.setValue("assignTo", newValue.id);
- },
- [formProps],
- );
-
- const onSubmit = useCallback<SubmitHandler<ReleasePickOrderInputs>>(
- async (data, event) => {
- console.log(data);
- try {
- const res = await releasePickOrder(data);
- console.log(res);
- if (res.consoCode.length > 0) {
- console.log(res);
- router.push(`/pickOrder/detail?consoCode=${res.consoCode}`);
- } else {
- console.log(res);
- }
- } catch (error) {
- console.log(error);
- }
- },
- [router],
- );
-
- const onSubmitError = useCallback<SubmitErrorHandler<ReleasePickOrderInputs>>(
- (errors) => {},
- [],
- );
-
- const handleConsolidate_revert = useCallback(() => {
- console.log(revertIds);
- }, [revertIds]);
-
- useEffect(() => {
- if (selectedConsoCode) {
- fetchConso(selectedConsoCode);
- formProps.setValue("consoCode", selectedConsoCode);
- }
- }, [selectedConsoCode, fetchConso, formProps]);
-
- const handlePickQtyChange = useCallback((lineId: number, lotId: number, value: number | string) => {
- console.log("Changing pick qty:", { lineId, lotId, value });
-
- const numericValue = typeof value === 'string' ? (value === '' ? 0 : parseInt(value, 10)) : value;
-
- setPickQtyData(prev => {
- const newData = {
- ...prev,
- [lineId]: {
- ...prev[lineId],
- [lotId]: numericValue
- }
- };
- console.log("New pick qty data:", newData);
- return newData;
- });
- }, []);
-
- const handleSubmitPickQty = useCallback(async (lineId: number, lotId: number) => {
- const qty = pickQtyData[lineId]?.[lotId] || 0;
- console.log(`提交拣货数量: Line ${lineId}, Lot ${lotId}, Qty ${qty}`);
-
- const selectedLot = lotData.find(lot => lot.lotId === lotId);
- if (!selectedLot?.stockOutLineId) {
- return;
- }
-
- try {
- // FIXED: 计算累计拣货数量
- const totalPickedForThisLot = (selectedLot.actualPickQty || 0) + qty;
- console.log(" DEBUG - Previous picked:", selectedLot.actualPickQty || 0);
- console.log("🔍 DEBUG - Current submit:", qty);
- console.log("🔍 DEBUG - Total picked:", totalPickedForThisLot);
- console.log("�� DEBUG - Required qty:", selectedLot.requiredQty);
-
- // FIXED: 状态应该基于累计拣货数量
- let newStatus = 'partially_completed';
- if (totalPickedForThisLot >= selectedLot.requiredQty) {
- newStatus = 'completed';
- }
-
- console.log("�� DEBUG - Calculated status:", newStatus);
-
- try {
- const stockOutLineUpdate = await updateStockOutLineStatus({
- id: selectedLot.stockOutLineId,
- status: newStatus,
- qty: qty
- });
-
- console.log(" Stock out line updated:", stockOutLineUpdate);
-
- } catch (error) {
- console.error("❌ Error updating stock out line:", error);
- return;
- }
-
- if (qty > 0) {
- const inventoryLotLineUpdate = await updateInventoryLotLineQuantities({
- inventoryLotLineId: lotId,
- qty: qty,
- status: 'available',
- operation: 'pick'
- });
-
- console.log("Inventory lot line updated:", inventoryLotLineUpdate);
- }
-
- // RE-ENABLE: Check if pick order should be completed
- if (newStatus === 'completed') {
- console.log(" Stock out line completed, checking if entire pick order is complete...");
-
- // 添加调试日志来查看所有 pick orders 的 consoCode
- console.log("📋 DEBUG - All pick orders and their consoCodes:");
- if (pickOrderDetails) {
- pickOrderDetails.pickOrders.forEach((pickOrder, index) => {
- console.log(` Pick Order ${index + 1}: ID=${pickOrder.id}, Code=${pickOrder.code}, ConsoCode=${pickOrder.consoCode}`);
- });
- }
-
- // FIXED: 直接查找 consoCode,不依赖 selectedRow
- if (pickOrderDetails) {
- let currentConsoCode: string | null = null;
-
- // 找到当前选中行所属的 pick order
- for (const pickOrder of pickOrderDetails.pickOrders) {
- const foundLine = pickOrder.pickOrderLines.find(line => line.id === selectedRowId);
- if (foundLine) {
- // 直接使用 pickOrder.code 作为 consoCode
- currentConsoCode = pickOrder.consoCode;
- console.log(`�� DEBUG - Found consoCode for line ${selectedRowId}: ${currentConsoCode} (from pick order ${pickOrder.id})`);
- break;
- }
- }
-
- if (currentConsoCode) {
- try {
- console.log(`🔍 Checking completion for consoCode: ${currentConsoCode}`);
- const completionResponse = await checkAndCompletePickOrderByConsoCode(currentConsoCode);
-
- console.log("�� Completion response:", completionResponse);
-
- if (completionResponse.message === "completed") {
- console.log("🎉 Pick order completed successfully!");
-
- await handleFetchAllPickOrderDetails();
- // 刷新当前选中的行数据
- if (selectedRowId) {
- await handleRowSelect(selectedRowId, true);
- }
-
- } else if (completionResponse.message === "not completed") {
- console.log("⏳ Pick order not completed yet, more lines remaining");
- } else {
- console.error("❌ Error checking completion:", completionResponse.message);
- }
- } catch (error) {
- console.error("❌ Error checking pick order completion:", error);
- }
- } else {
- console.warn("⚠️ No consoCode found for current pick order, cannot check completion");
- }
- }
- }
-
- console.log("All updates completed successfully");
-
- if (selectedRowId) {
- await handleRowSelect(selectedRowId, true);
- console.log("Data refresh needed but handleRowSelect not available yet");
- }
- await handleFetchAllPickOrderDetails();
- } catch (error) {
- console.error("Error updating pick quantity:", error);
- }
- }, [pickQtyData, lotData, selectedRowId, pickOrderDetails, handleFetchAllPickOrderDetails]);
-
- const getTotalPickedQty = useCallback((lineId: number) => {
- const lineData = pickQtyData[lineId];
- if (!lineData) return 0;
- return Object.values(lineData).reduce((sum, qty) => sum + qty, 0);
- }, [pickQtyData]);
-
- const handleQcCheck = useCallback(async (line: GetPickOrderLineInfo, pickOrderCode: string) => {
- if (!selectedLotId) {
- return;
- }
-
- const selectedLot = lotData.find(lot => lot.lotId === selectedLotId);
- if (!selectedLot) {
- return;
- }
-
- if (!selectedLot.stockOutLineId) {
- return;
- }
-
- setSelectedLotForQc(selectedLot);
-
-
-
- let qcResult: any[] = [];
- try {
- const rawQcResult = await fetchPickOrderQcResult(line.id);
- qcResult = rawQcResult.map((result: any) => ({
- ...result,
- isPassed: result.isPassed || false
- }));
- } catch (error) {
- // No existing QC result found - this is normal
- }
-
- setSelectedItemForQc({
- ...line,
- pickOrderCode,
- qcResult
- });
- setQcModalOpen(true);
- }, [lotData, selectedLotId, setQcItems]);
-
- const handleCloseQcModal = useCallback(() => {
- console.log("Closing QC modal");
- setQcModalOpen(false);
- setSelectedItemForQc(null);
- }, []);
-
- const handleSetItemDetail = useCallback((item: any) => {
- setSelectedItemForQc(item);
- }, []);
-
- // Main table pagination handlers
- const handleMainTablePageChange = useCallback((event: unknown, newPage: number) => {
- setMainTablePagingController(prev => ({
- ...prev,
- pageNum: newPage,
- }));
- }, []);
-
- const handleMainTablePageSizeChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
- const newPageSize = parseInt(event.target.value, 10);
- setMainTablePagingController({
- pageNum: 0,
- pageSize: newPageSize,
- });
- }, []);
-
- const handleLotTablePageChange = useCallback((event: unknown, newPage: number) => {
- setLotTablePagingController(prev => ({
- ...prev,
- pageNum: newPage,
- }));
- }, []);
-
- const handleLotTablePageSizeChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
- const newPageSize = parseInt(event.target.value, 10);
- setLotTablePagingController({
- pageNum: 0,
- pageSize: newPageSize,
- });
- }, []);
-
- const handleLotSelection = useCallback((uniqueLotId: string, lotId: number | null) => {
- console.log("=== DEBUG: Lot Selection ===");
- console.log("uniqueLotId:", uniqueLotId);
- console.log("lotId (inventory lot line ID):", lotId);
-
- const selectedLot = lotData.find(lot => lot.lotId === lotId);
- console.log("Selected lot data:", selectedLot);
-
- if (selectedLotRowId === uniqueLotId) {
- setSelectedLotRowId(null);
- setSelectedLotId(null);
- } else {
- setSelectedLotRowId(uniqueLotId);
- setSelectedLotId(lotId ?? null);
- }
- }, [selectedLotRowId, lotData]);
-
- const handleRowSelect = useCallback(async (lineId: number, preserveLotSelection: boolean = false) => {
- setSelectedRowId(lineId);
-
- if (!preserveLotSelection) {
- setSelectedLotRowId(null);
- setSelectedLotId(null);
- }
-
- try {
- const lotDetails = await fetchPickOrderLineLotDetails(lineId);
- console.log("lineId:", lineId);
- console.log("Lot details from API:", lotDetails);
-
- // ✅ 直接使用 API 返回的数据,包括 noLot 字段
- const allLotData: LotPickData[] = lotDetails.map((lot: PickOrderLotDetailResponse) => ({
- id: lot.lotId ?? -(lineId * 1000 + Math.random()), // 如果 lotId 为 null,生成一个临时 ID
- lotId: lot.lotId,
- lotNo: lot.lotNo,
- expiryDate: lot.expiryDate ? dayjs(lot.expiryDate).format(OUTPUT_DATE_FORMAT) : t("N/A"),
- location: lot.location?? t("N/A"),
- stockUnit: lot.stockUnit || "",
- inQty: lot.inQty ?? 0,
- outQty: lot.outQty ?? 0,
- holdQty: lot.holdQty ?? 0,
- totalPickedByAllPickOrders: lot.totalPickedByAllPickOrders ?? 0,
- availableQty: lot.availableQty ?? 0,
- requiredQty: lot.requiredQty ?? 0,
- actualPickQty: lot.actualPickQty || 0,
- lotStatus: lot.lotStatus || "unavailable",
- lotAvailability: lot.lotAvailability,
- stockOutLineId: lot.stockOutLineId ?? undefined,
- stockOutLineStatus: lot.stockOutLineStatus ?? undefined,
- stockOutLineQty: lot.stockOutLineQty ?? undefined,
- noLot: lot.noLot, // ✅ 关键:使用 API 返回的 noLot 字段
- }));
-
- console.log("✅ Combined lot data:", allLotData);
- console.log(" - Total rows:", allLotData.length);
- console.log(" - No-lot rows:", allLotData.filter(l => l.noLot).length);
-
- setLotData(allLotData);
- } catch (error) {
- console.error("Error fetching lot details:", error);
- setLotData([]);
- }
- }, []);
-
- const prepareLotTableData = useMemo(() => {
- return lotData.map((lot) => ({
- ...lot,
- id: lot.lotId,
- }));
- }, [lotData]);
-
- const paginatedLotTableData = useMemo(() => {
- const startIndex = lotTablePagingController.pageNum * lotTablePagingController.pageSize;
- const endIndex = startIndex + lotTablePagingController.pageSize;
- return prepareLotTableData.slice(startIndex, endIndex);
- }, [prepareLotTableData, lotTablePagingController]);
-
- const selectedRow = useMemo(() => {
- if (!selectedRowId || !pickOrderDetails) return null;
-
- for (const pickOrder of pickOrderDetails.pickOrders) {
- const foundLine = pickOrder.pickOrderLines.find(line => line.id === selectedRowId);
- if (foundLine) {
- return { ...foundLine, pickOrderCode: pickOrder.code,
- pickOrderId: pickOrder.id };
- }
- }
- return null;
- }, [selectedRowId, pickOrderDetails]);
-
- const handleInventoryUpdate = useCallback(async (itemId: number, lotId: number, qty: number) => {
- try {
- const inventoryUpdate = await updateInventoryStatus({
- itemId: itemId,
- lotId: lotId,
- status: 'reserved',
- qty: qty
- });
-
- console.log("Inventory status updated:", inventoryUpdate);
- } catch (error) {
- console.error("Error updating inventory status:", error);
- }
- }, []);
-
- const handleLotDataRefresh = useCallback(async () => {
- if (selectedRowId) {
- try {
- await handleRowSelect(selectedRowId, true);
- } catch (error) {
- console.error("Error refreshing lot data:", error);
- }
- }
- }, [selectedRowId, handleRowSelect]);
-
- const handleDataRefresh = useCallback(async () => {
- if (selectedRowId) {
- try {
- await handleRowSelect(selectedRowId, true);
- } catch (error) {
- console.error("Error refreshing data:", error);
- }
- }
- }, [selectedRowId, handleRowSelect]);
-
- const handleInsufficientStock = useCallback(async () => {
- console.log("Insufficient stock - testing resuggest API");
-
- if (!selectedRowId || !pickOrderDetails) {
- return;
- }
-
- let pickOrderId: number | null = null;
- for (const pickOrder of pickOrderDetails.pickOrders) {
- const foundLine = pickOrder.pickOrderLines.find(line => line.id === selectedRowId);
- if (foundLine) {
- pickOrderId = pickOrder.id;
- break;
- }
- }
-
- if (!pickOrderId) {
- return;
- }
-
- try {
- console.log(`Calling resuggest API for pick order ID: ${pickOrderId}`);
-
- const result = await resuggestPickOrder(pickOrderId);
-
- console.log("Resuggest API result:", result);
-
- if (result.code === "SUCCESS") {
- if (selectedRowId) {
- await handleRowSelect(selectedRowId);
- }
-
- await handleFetchAllPickOrderDetails();
- }
-
- } catch (error) {
- console.error("Error calling resuggest API:", error);
- }
- }, [selectedRowId, pickOrderDetails, handleRowSelect, handleFetchAllPickOrderDetails]);
-
- const hasSelectedLots = useCallback((lineId: number) => {
- return selectedLotRowId !== null;
- }, [selectedLotRowId]);
-
- const [showInputBody, setShowInputBody] = useState(false);
- const [selectedLotForInput, setSelectedLotForInput] = useState<LotPickData | null>(null);
-
- const handleLotSelectForInput = useCallback((lot: LotPickData) => {
- setSelectedLotForInput(lot);
- setShowInputBody(true);
- }, []);
-
- const generateInputBody = useCallback(() => {
- if (!selectedLotForInput || !selectedRowId || !pickOrderDetails?.consoCode) {
- return null;
- }
-
- // ✅ 處理 lotId 可能為 null 的情況
- if (selectedLotForInput.lotId === null) {
- return null; // no-lot 行不能創建 stock out line
- }
-
- return {
- consoCode: pickOrderDetails.consoCode,
- pickOrderLineId: selectedRowId,
- inventoryLotLineId: selectedLotForInput.lotId, // ✅ 現在確定不是 null
- qty: 0.0
- };
- }, [selectedLotForInput, selectedRowId, selectedRow, pickOrderDetails?.consoCode]);
- // 在 handleSubmitPickQty 函数附近添加新函数
- const handleIssueNoLotStockOutLine = useCallback(async (stockOutLineId: number) => {
- if (!stockOutLineId) {
- console.error("Cannot issue: stockOutLineId is missing");
- return;
- }
-
- try {
- console.log(`提交 no-lot stock out line: ${stockOutLineId}`);
-
- // ✅ 直接完成 no-lot 的 stock out line(设置状态为 completed,qty 为 0)
- const result = await updateStockOutLineStatus({
- id: stockOutLineId,
- status: 'completed',
- qty: 0 // no-lot 行没有实际数量
- });
-
- console.log("✅ No-lot stock out line completed:", result);
-
- // 刷新数据
- if (selectedRowId) {
- handleRowSelect(selectedRowId);
- }
- } catch (error) {
- console.error("❌ Error completing no-lot stock out line:", error);
- }
- }, [selectedRowId, handleRowSelect]);
- const handleCreateStockOutLine = useCallback(async (inventoryLotLineId: number) => {
- if (!selectedRowId || !pickOrderDetails?.consoCode) {
- console.error("Missing required data for creating stock out line.");
- return;
- }
-
- try {
- const currentSelectedLotRowId = selectedLotRowId;
- const currentSelectedLotId = selectedLotId;
- let correctConsoCode: string | null = null;
- if (pickOrderDetails && selectedRowId) {
- for (const pickOrder of pickOrderDetails.pickOrders) {
- const foundLine = pickOrder.pickOrderLines.find(line => line.id === selectedRowId);
- if (foundLine) {
- correctConsoCode = pickOrder.consoCode;
- console.log(`🔍 Found consoCode for line ${selectedRowId}: ${correctConsoCode} (from pick order ${pickOrder.id})`);
- break;
- }
- }
- }
- const stockOutLineData: CreateStockOutLine = {
- consoCode: correctConsoCode || pickOrderDetails?.consoCode || "", // 使用正确的 consoCode
- pickOrderLineId: selectedRowId,
- inventoryLotLineId: inventoryLotLineId,
- qty: 0.0
- };
-
- console.log("=== STOCK OUT LINE CREATION DEBUG ===");
- console.log("Input Body:", JSON.stringify(stockOutLineData, null, 2));
-
- const result = await createStockOutLine(stockOutLineData);
-
- console.log("Stock Out Line created:", result);
-
- if (result) {
- console.log("Stock out line created successfully:", result);
-
- console.log("🔄 Refreshing data after stock out line creation...");
-
- try {
- if (selectedRowId) {
- await handleRowSelect(selectedRowId, true);
- }
-
- await handleFetchAllPickOrderDetails();
-
- console.log(" Data refresh completed - lot selection maintained!");
- } catch (refreshError) {
- console.error("❌ Error refreshing data:", refreshError);
- }
-
- setShowInputBody(false);
- } else {
- console.error("Failed to create stock out line: No response");
- }
- } catch (error) {
- console.error("Error creating stock out line:", error);
- }
- }, [selectedRowId, pickOrderDetails?.consoCode, handleRowSelect, handleFetchAllPickOrderDetails, selectedLotRowId, selectedLotId]);
-
- const handleRefreshDataPreserveSelection = useCallback(async () => {
- if (!selectedRowId) return;
-
- const currentSelectedLotRowId = selectedLotRowId;
- const currentSelectedLotId = selectedLotId;
-
- try {
- await handleRowSelect(selectedRowId, true);
-
- await handleFetchAllPickOrderDetails();
-
- setSelectedLotRowId(currentSelectedLotRowId);
- setSelectedLotId(currentSelectedLotId);
-
- console.log(" Data refreshed with selection preserved");
- } catch (error) {
- console.error("❌ Error refreshing data:", error);
- }
- }, [selectedRowId, selectedLotRowId, selectedLotId, handleRowSelect, handleFetchAllPickOrderDetails]);
-
- // Search criteria
- const searchCriteria: Criterion<any>[] = useMemo(
- () => [
- {
- label: t("Item Code"),
- paramName: "itemCode",
- type: "text",
- },
- {
- label: t("Pick Order Code"),
- paramName: "pickOrderCode",
- type: "text",
- },
- {
- label: t("Item Name"),
- paramName: "itemName",
- type: "text",
- },
- {
- label: t("Target Date From"),
- label2: t("Target Date To"),
- paramName: "targetDate",
- type: "dateRange",
- },
- ],
- [t],
- );
-
- // Search handler
- const handleSearch = useCallback((query: Record<string, any>) => {
- setSearchQuery({ ...query });
- console.log("Search query:", query);
-
- if (!originalPickOrderData) return;
-
- const filtered = originalPickOrderData.pickOrders.filter((pickOrder) => {
- return pickOrder.pickOrderLines.some((line) => {
- const itemCodeMatch = !query.itemCode ||
- line.itemCode?.toLowerCase().includes((query.itemCode || "").toLowerCase());
-
- const itemNameMatch = !query.itemName ||
- line.itemName?.toLowerCase().includes((query.itemName || "").toLowerCase());
-
- const pickOrderCodeMatch = !query.pickOrderCode ||
- pickOrder.code?.toLowerCase().includes((query.pickOrderCode || "").toLowerCase());
-
- return itemCodeMatch && itemNameMatch && pickOrderCodeMatch;
- });
- });
-
- const filteredData: GetPickOrderInfoResponse = {
- ...originalPickOrderData,
- pickOrders: filtered
- };
-
- setPickOrderDetails(filteredData);
- console.log("Filtered pick orders count:", filtered.length);
- }, [originalPickOrderData, t]);
-
- // Reset handler
- const handleReset = useCallback(() => {
- setSearchQuery({});
- if (originalPickOrderData) {
- setPickOrderDetails(originalPickOrderData);
- }
- }, [originalPickOrderData]);
-
- // Debug the lot data
- useEffect(() => {
- console.log("Lot data:", lotData);
- console.log("Pick Qty Data:", pickQtyData);
- }, [lotData, pickQtyData]);
-
- return (
- <FormProvider {...formProps}>
- <Stack spacing={2}>
- {/* Search Box */}
- <Box>
- <SearchBox
- criteria={searchCriteria}
- onSearch={handleSearch}
- onReset={handleReset}
- />
- </Box>
-
- {/* Main table using the new component */}
- <Box>
- <Typography variant="h6" gutterBottom>
- {t("Pick Order Details")}
- </Typography>
- <PickOrderDetailsTable
- pickOrderDetails={pickOrderDetails}
- detailLoading={detailLoading}
- selectedRowId={selectedRowId}
- onRowSelect={handleRowSelect}
- onPageChange={handleMainTablePageChange}
- onPageSizeChange={handleMainTablePageSizeChange}
- pageNum={mainTablePagingController.pageNum}
- pageSize={mainTablePagingController.pageSize}
- />
- </Box>
-
- {/* Lot table - below main table */}
- {selectedRow && (
- <Box>
- <Typography variant="h6" gutterBottom>
- {t("Item lot to be Pick:")} {selectedRow.pickOrderCode} - {selectedRow.itemName}
- </Typography>
-
- {lotData.length > 0 ? (
- <LotTable
- lotData={lotData}
- selectedRowId={selectedRowId}
- selectedRow={selectedRow}
- pickQtyData={pickQtyData}
- selectedLotRowId={selectedLotRowId}
- selectedLotId={selectedLotId}
- onLotSelection={handleLotSelection}
- onPickQtyChange={handlePickQtyChange}
- onSubmitPickQty={handleSubmitPickQty}
- onCreateStockOutLine={handleCreateStockOutLine}
- onQcCheck={handleQcCheck}
- onDataRefresh={handleFetchAllPickOrderDetails}
- onLotDataRefresh={handleLotDataRefresh}
- onLotSelectForInput={handleLotSelectForInput}
- showInputBody={showInputBody}
- onIssueNoLotStockOutLine={handleIssueNoLotStockOutLine}
- setShowInputBody={setShowInputBody}
- //selectedLotForInput={selectedLotForInput}
- generateInputBody={generateInputBody}
- // Add missing props
- totalPickedByAllPickOrders={0} // You can calculate this from lotData if needed
- outQty={0} // You can calculate this from lotData if needed
- holdQty={0} // You can calculate this from lotData if needed
- />
- ) : (
- <Box
- sx={{
- p: 3,
- textAlign: 'center',
- border: '1px solid',
- borderColor: 'divider',
- borderRadius: 1,
- backgroundColor: 'background.paper'
- }}
- >
- <Typography variant="body1" color="text.secondary" gutterBottom>
- {selectedRow.availableQty === null || selectedRow.availableQty === 0
- ? t("No available stock for this item")
- : t("No lot details available for this item")
- }
- </Typography>
- <Typography variant="body2" color="text.secondary">
- {selectedRow.availableQty === null || selectedRow.availableQty === 0
- ? t("Current stock is insufficient or unavailable")
- : t("Please check inventory status")
- }
- </Typography>
- </Box>
- )}
-
- {/* Action buttons below the lot table */}
- {/*
- <Box sx={{ mt: 2 }}>
- <Stack direction="row" spacing={1}>
- <Button
- variant="contained"
- onClick={() => handleInsufficientStock()}
- sx={{ whiteSpace: 'nowrap' }}
- >
- {t("Pick Another Lot")}
- </Button>
- </Stack>
- </Box>
- */}
- </Box>
- )}
-
- {/* Action Buttons */}
- {selectedRow && (
- <Grid container>
- <Grid item xs={12} display="flex" justifyContent="end" alignItems="end">
- <Button
- disabled={(revertIds as number[]).length < 1}
- variant="outlined"
- onClick={handleConsolidate_revert}
- sx={{ mr: 1 }}
- >
- {t("remove")}
- </Button>
- <Button
- disabled={disableRelease}
- variant="contained"
- onClick={formProps.handleSubmit(onSubmit, onSubmitError)}
- >
- {t("release")}
- </Button>
- </Grid>
- </Grid>
- )}
-
-
- {/* QC Modal */}
- { /*
- {selectedItemForQc && qcModalOpen && (
- <PickQcStockInModalVer2
- open={qcModalOpen}
- onClose={handleCloseQcModal}
- itemDetail={selectedItemForQc}
- setItemDetail={handleSetItemDetail}
- qc={qcItems}
- warehouse={[]}
- qcItems={qcItems}
- setQcItems={setQcItems}
- selectedLotId={selectedLotForQc?.stockOutLineId}
- onStockOutLineUpdate={() => {
- if (selectedRowId) {
- handleRowSelect(selectedRowId);
- }
- }}
- lotData={lotData}
- />
- )}
- */}
- </Stack>
- </FormProvider>
- );
- };
-
- export default PickExecution;
|