diff --git a/src/app/api/pickOrder/actions.ts b/src/app/api/pickOrder/actions.ts index c3d302a..962ae03 100644 --- a/src/app/api/pickOrder/actions.ts +++ b/src/app/api/pickOrder/actions.ts @@ -247,6 +247,34 @@ export interface PickOrderCompletionResponse { export interface UpdateSuggestedLotLineIdRequest { newLotLineId: number; } +export interface FGPickOrderResponse { + pickOrderId: number; + pickOrderCode: string; + pickOrderConsoCode: string; + pickOrderTargetDate: string; + pickOrderStatus: string; + deliveryOrderId: number; + deliveryNo: string; + deliveryDate: string; + shopId: number; + shopCode: string; + shopName: string; + shopAddress: string; + shopPoNo: string; + numberOfCartons: number; + DepartureTime: string; + truckNo: string; + qrCodeData: number; +} +export const fetchFGPickOrders = async (pickOrderId: number) => { + const response = await serverFetchJson( + `${BASE_API_URL}/pickOrder/fg-pick-orders/${pickOrderId}`, + { + method: "GET", + }, + ); + return response; +}; export const updateSuggestedLotLineId = async (suggestedPickLotId: number, newLotLineId: number) => { const response = await serverFetchJson>( `${BASE_API_URL}/suggestedPickLot/update-suggested-lot/${suggestedPickLotId}`, diff --git a/src/components/FinishedGoodSearch/FGPickOrderCard.tsx b/src/components/FinishedGoodSearch/FGPickOrderCard.tsx new file mode 100644 index 0000000..e406fca --- /dev/null +++ b/src/components/FinishedGoodSearch/FGPickOrderCard.tsx @@ -0,0 +1,113 @@ +"use client"; + +import { FGPickOrderResponse } from "@/app/api/pickOrder/actions"; +import { Box, Card, CardContent, Grid, Stack, TextField, Button } from "@mui/material"; +import { useTranslation } from "react-i18next"; +import QrCodeIcon from '@mui/icons-material/QrCode'; + +type Props = { + fgOrder: FGPickOrderResponse; + onQrCodeClick: (pickOrderId: number) => void; +}; + +const FGPickOrderCard: React.FC = ({ fgOrder, onQrCodeClick }) => { + const { t } = useTranslation("pickOrder"); + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default FGPickOrderCard; \ No newline at end of file diff --git a/src/components/FinishedGoodSearch/GoodPickExecution.tsx b/src/components/FinishedGoodSearch/GoodPickExecution.tsx index cc7c541..be24cd1 100644 --- a/src/components/FinishedGoodSearch/GoodPickExecution.tsx +++ b/src/components/FinishedGoodSearch/GoodPickExecution.tsx @@ -26,6 +26,13 @@ import { updateStockOutLineStatus, createStockOutLine, recordPickExecutionIssue, + fetchFGPickOrders, // ✅ Add this import + FGPickOrderResponse, + autoAssignAndReleasePickOrder, + AutoAssignReleaseResponse, + checkPickOrderCompletion, + PickOrderCompletionResponse, + checkAndCompletePickOrderByConsoCode } from "@/app/api/pickOrder/actions"; import { fetchNameList, NameList } from "@/app/api/user/actions"; import { @@ -39,16 +46,9 @@ import QrCodeIcon from '@mui/icons-material/QrCode'; import { useQrCodeScannerContext } from '../QrCodeScannerProvider/QrCodeScannerProvider'; import { useSession } from "next-auth/react"; import { SessionWithTokens } from "@/config/authConfig"; -import { - autoAssignAndReleasePickOrder, - AutoAssignReleaseResponse, - checkPickOrderCompletion, - PickOrderCompletionResponse, - checkAndCompletePickOrderByConsoCode -} from "@/app/api/pickOrder/actions"; import { fetchStockInLineInfo } from "@/app/api/po/actions"; import GoodPickExecutionForm from "./GoodPickExecutionForm"; - +import FGPickOrderCard from "./FGPickOrderCard"; interface Props { filterArgs: Record; } @@ -73,7 +73,7 @@ const QrCodeModal: React.FC<{ const [processedQrCodes, setProcessedQrCodes] = useState>(new Set()); const [scannedQrResult, setScannedQrResult] = useState(''); - + const [fgPickOrder, setFgPickOrder] = useState(null); // Process scanned QR codes useEffect(() => { if (qrValues.length > 0 && lot && !isProcessingQr && !qrScanSuccess) { @@ -347,6 +347,51 @@ const PickExecution: React.FC = ({ filterArgs }) => { // ✅ Add GoodPickExecutionForm states const [pickExecutionFormOpen, setPickExecutionFormOpen] = useState(false); const [selectedLotForExecutionForm, setSelectedLotForExecutionForm] = useState(null); + const [fgPickOrders, setFgPickOrders] = useState([]); + const [fgPickOrdersLoading, setFgPickOrdersLoading] = useState(false); + const fetchFgPickOrdersData = useCallback(async () => { + if (!currentUserId) return; + + setFgPickOrdersLoading(true); + try { + // Get all pick order IDs from combinedLotData + const pickOrderIds = Array.from(new Set(combinedLotData.map(lot => lot.pickOrderId))); + + if (pickOrderIds.length === 0) { + setFgPickOrders([]); + return; + } + + // Fetch FG pick orders for each pick order ID + const fgPickOrdersPromises = pickOrderIds.map(pickOrderId => + fetchFGPickOrders(pickOrderId) + ); + + const fgPickOrdersResults = await Promise.all(fgPickOrdersPromises); + + // Flatten the results (each fetchFGPickOrders returns an array) + const allFgPickOrders = fgPickOrdersResults.flat(); + + setFgPickOrders(allFgPickOrders); + console.log("✅ Fetched FG pick orders:", allFgPickOrders); + } catch (error) { + console.error("❌ Error fetching FG pick orders:", error); + setFgPickOrders([]); + } finally { + setFgPickOrdersLoading(false); + } + }, [currentUserId, combinedLotData]); + useEffect(() => { + if (combinedLotData.length > 0) { + fetchFgPickOrdersData(); + } + }, [combinedLotData, fetchFgPickOrdersData]); + + // ✅ Handle QR code button click + const handleQrCodeClick = (pickOrderId: number) => { + console.log(`QR Code clicked for pick order ID: ${pickOrderId}`); + // TODO: Implement QR code functionality + }; useEffect(() => { startScan(); @@ -850,11 +895,30 @@ const PickExecution: React.FC = ({ filterArgs }) => { }); }, []); - // Pagination data + // Pagination data with sorting by routerIndex const paginatedData = useMemo(() => { + // ✅ Sort by routerIndex first, then by other criteria + const sortedData = [...combinedLotData].sort((a, b) => { + const aIndex = a.routerIndex || 0; + const bIndex = b.routerIndex || 0; + + // Primary sort: by routerIndex + if (aIndex !== bIndex) { + return aIndex - bIndex; + } + + // Secondary sort: by pickOrderCode if routerIndex is the same + if (a.pickOrderCode !== b.pickOrderCode) { + return a.pickOrderCode.localeCompare(b.pickOrderCode); + } + + // Tertiary sort: by lotNo if everything else is the same + return (a.lotNo || '').localeCompare(b.lotNo || ''); + }); + const startIndex = paginationController.pageNum * paginationController.pageSize; const endIndex = startIndex + paginationController.pageSize; - return combinedLotData.slice(startIndex, endIndex); + return sortedData.slice(startIndex, endIndex); }, [combinedLotData, paginationController]); return ( @@ -862,11 +926,35 @@ const PickExecution: React.FC = ({ filterArgs }) => { {/* Search Box */} - + + + {t("FG Pick Orders")} + + + + {fgPickOrdersLoading ? ( + + + + ) : ( + + {fgPickOrders.length === 0 ? ( + + + {t("No FG pick orders found")} + + + ) : ( + fgPickOrders.map((fgOrder) => ( + + )) + )} + + )} @@ -887,8 +975,8 @@ const PickExecution: React.FC = ({ filterArgs }) => { - {t("Pick Order Code")} - {t("Item Code")} + {t("Index")} + {t("Route")} {t("Item Name")} {t("Lot#")} {t("Target Date")} @@ -921,8 +1009,16 @@ const PickExecution: React.FC = ({ filterArgs }) => { } }} > - {lot.pickOrderCode} - {lot.itemCode} + + + {lot.routerIndex || index + 1} + + + + + {lot.routerRoute || '-'} + + {lot.itemName} @@ -933,18 +1029,7 @@ const PickExecution: React.FC = ({ filterArgs }) => { }} > {lot.lotNo} - - {/* - {lot.lotAvailability !== 'available' && ( - - ({lot.lotAvailability === 'expired' ? 'Expired' : - lot.lotAvailability === 'insufficient_stock' ? 'Insufficient' : - lot.lotAvailability === 'rejected' ? 'Rejected' : - 'Unavailable'}) - - - )*/} {lot.pickOrderTargetDate} diff --git a/src/i18n/zh/common.json b/src/i18n/zh/common.json index e5292d1..ebc5e15 100644 --- a/src/i18n/zh/common.json +++ b/src/i18n/zh/common.json @@ -86,6 +86,8 @@ "Production": "生產流程", "Put Away": "上架", "Put Away Scan": "上架掃碼", - "Finished Good Order": "成品訂單", - "finishedGood": "成品" + "Finished Good Order": "成品出倉", + "finishedGood": "成品", + "Router": "執貨路線" + }