From 59c1a4c7273bf8468f4b41563115b9aa95959586 Mon Sep 17 00:00:00 2001 From: "CANCERYS\\kw093" Date: Tue, 2 Sep 2025 21:36:33 +0800 Subject: [PATCH] update --- .../PickQcStockInModalVer3.tsx | 236 ++++++++++-------- 1 file changed, 130 insertions(+), 106 deletions(-) diff --git a/src/components/PickOrderSearch/PickQcStockInModalVer3.tsx b/src/components/PickOrderSearch/PickQcStockInModalVer3.tsx index 745b0da..43ebc2c 100644 --- a/src/components/PickOrderSearch/PickQcStockInModalVer3.tsx +++ b/src/components/PickOrderSearch/PickQcStockInModalVer3.tsx @@ -34,6 +34,23 @@ import { fetchPickOrderQcResult, savePickOrderQcResult } from "@/app/api/qc/acti import { updateInventoryLotLineStatus } from "@/app/api/inventory/actions"; // ✅ 导入新的 API +import { dayjsToInputDateString } from "@/app/utils/formatUtil"; +import dayjs from "dayjs"; +interface Props extends CommonProps { + itemDetail: GetPickOrderLineInfo & { + pickOrderCode: string; + qcResult?: PurchaseQcResult[] + }; + qcItems: ExtendedQcItem[]; + setQcItems: Dispatch>; + selectedLotId?: number; + onStockOutLineUpdate?: () => void; + lotData: LotPickData[]; + pickQtyData?: PickQtyData; + selectedRowId?: number; + // ✅ Add callback to update pickQtyData in parent + onPickQtyUpdate?: (updatedPickQtyData: PickQtyData) => void; +} // Define QcData interface locally interface ExtendedQcItem extends QcItemWithChecks { @@ -44,6 +61,7 @@ interface ExtendedQcItem extends QcItemWithChecks { stableId?: string; // ✅ Also add stableId for better row identification } + const style = { position: "absolute", top: "50%", @@ -58,7 +76,11 @@ const style = { maxHeight: "90vh", overflowY: "auto", }; - +interface PickQtyData { + [lineId: number]: { + [lotId: number]: number; + }; +} interface CommonProps extends Omit { itemDetail: GetPickOrderLineInfo & { pickOrderCode: string; @@ -117,6 +139,8 @@ const PickQcStockInModalVer3: React.FC = ({ selectedLotId, onStockOutLineUpdate, lotData, + pickQtyData, + selectedRowId, }) => { const { t, @@ -222,10 +246,16 @@ const PickQcStockInModalVer3: React.FC = ({ try { const qcAccept = qcDecision === "1"; const acceptQty = Number(accQty) || null; - + const validationErrors : string[] = []; const selectedLot = lotData.find(lot => lot.stockOutLineId === selectedLotId); - + + // ✅ Add safety check for selectedLot + if (!selectedLot) { + console.error("Selected lot not found"); + return; + } + const itemsWithoutResult = qcItems.filter(item => item.qcPassed === undefined); if (itemsWithoutResult.length > 0) { validationErrors.push(`${t("QC items without result")}: ${itemsWithoutResult.map(item => item.code).join(", ")}`); @@ -244,7 +274,7 @@ const PickQcStockInModalVer3: React.FC = ({ qcItem: item.code, qcDescription: item.description || "", isPassed: item.qcPassed, - failQty: item.qcPassed ? 0 : (selectedLot?.requiredQty || 0), + failQty: item.qcPassed ? 0 : (selectedLot.requiredQty || 0), remarks: item.remarks || "", })), }; @@ -257,35 +287,64 @@ const PickQcStockInModalVer3: React.FC = ({ return; } - // ✅ Fix: Update stock out line status based on QC decision - if (selectedLotId) { // ✅ Remove qcData.qcAccept condition + // ✅ Handle different QC decisions + if (selectedLotId) { try { const allPassed = qcData.qcItems.every(item => item.isPassed); - // ✅ Fix: Use correct backend enum values - const newStockOutLineStatus = allPassed ? 'completed' : 'rejected'; - - console.log("Updating stock out line status after QC:", { - stockOutLineId: selectedLotId, - newStatus: newStockOutLineStatus - }); - - // ✅ Fix: 1. Update stock out line status with required qty field - if (selectedLot) { + if (qcDecision === "1") { + // ✅ QC Decision 1: Accept - Update lot's required pick qty to actual pick qty + // ✅ Use selectedLotId to get the actual pick qty from pickQtyData + const actualPickQty = pickQtyData?.[selectedRowId || 0]?.[selectedLot?.lotId || 0] || 0; + + console.log("QC Decision 1 - Accept: Updating lot required pick qty to actual pick qty:", { + lotId: selectedLot.lotId, + currentRequiredQty: selectedLot.requiredQty, + newRequiredQty: actualPickQty + }); + + // Update stock out line status to completed + const newStockOutLineStatus = 'completed'; + + await updateStockOutLineStatus({ + id: selectedLotId, + status: newStockOutLineStatus, + qty: actualPickQty // Use actual pick qty + }); + + } else if (qcDecision === "2") { + // ✅ QC Decision 2: Report and Re-pick - Return to no accept and pick another lot + console.log("QC Decision 2 - Report and Re-pick: Returning to no accept and allowing another lot pick"); + + // Update stock out line status to rejected (for re-pick) + const newStockOutLineStatus = 'rejected'; + await updateStockOutLineStatus({ id: selectedLotId, status: newStockOutLineStatus, qty: selectedLot.requiredQty || 0 }); - } else { - console.warn("Selected lot not found for stock out line status update"); - } - - // ✅ Fix: 2. If QC failed, also update inventory lot line status - if (!allPassed) { + + // ✅ Update inventory lot line status to unavailable so user can pick another lot try { - if (selectedLot) { - console.log("Updating inventory lot line status for failed QC:", { + console.log("Updating inventory lot line status to unavailable for re-pick:", { + inventoryLotLineId: selectedLot.lotId, + status: 'unavailable' + }); + + await updateInventoryLotLineStatus({ + inventoryLotLineId: selectedLot.lotId, + status: 'unavailable' + }); + console.log("Inventory lot line status updated to unavailable - user can now pick another lot"); + } catch (error) { + console.error("Failed to update inventory lot line status:", error); + } + + // ✅ Also update inventory lot line status for failed QC items + if (!allPassed) { + try { + console.log("Updating inventory lot line status for failed QC items:", { inventoryLotLineId: selectedLot.lotId, status: 'unavailable' }); @@ -294,18 +353,16 @@ const PickQcStockInModalVer3: React.FC = ({ inventoryLotLineId: selectedLot.lotId, status: 'unavailable' }); - console.log("Inventory lot line status updated to unavailable"); - } else { - console.warn("Selected lot not found for inventory lot line status update"); + console.log("Failed QC items inventory lot line status updated to unavailable"); + } catch (error) { + console.error("Failed to update failed QC items inventory lot line status:", error); + } } - } catch (error) { - console.error("Failed to update inventory lot line status:", error); - } } console.log("Stock out line status updated successfully after QC"); - // ✅ Call callback to refresh data + // Call callback to refresh data if (onStockOutLineUpdate) { onStockOutLineUpdate(); } @@ -316,8 +373,8 @@ const PickQcStockInModalVer3: React.FC = ({ console.log("QC results saved successfully!"); - // ✅ Show warning dialog for failed QC items - if (!qcData.qcItems.every((q) => q.isPassed) && qcData.qcAccept) { + // ✅ Show warning dialog for failed QC items when accepting + if (qcDecision === "1" && !qcData.qcItems.every((q) => q.isPassed)) { submitDialogWithWarning(() => { closeHandler?.({}, 'escapeKeyDown'); }, t, {title:"有不合格檢查項目,確認接受出庫?", confirmButtonText: "Confirm", html: ""}); @@ -327,7 +384,6 @@ const PickQcStockInModalVer3: React.FC = ({ closeHandler?.({}, 'escapeKeyDown'); } catch (error) { console.error("Error in QC submission:", error); - // ✅ Enhanced error logging if (error instanceof Error) { console.error("Error details:", error.message); console.error("Error stack:", error.stack); @@ -336,9 +392,8 @@ const PickQcStockInModalVer3: React.FC = ({ setIsSubmitting(false); } }, - [qcItems, closeHandler, t, itemDetail, qcDecision, accQty, selectedLotId, onStockOutLineUpdate, lotData], + [qcItems, closeHandler, t, itemDetail, qcDecision, accQty, selectedLotId, onStockOutLineUpdate, lotData, pickQtyData, selectedRowId], ); - // DataGrid columns (QcComponent style) const qcColumns: GridColDef[] = useMemo( () => [ @@ -529,77 +584,46 @@ const PickQcStockInModalVer3: React.FC = ({ )} - - ( - { - const value = e.target.value.toString(); - if (value != "1" && Boolean(errors.acceptQty)) { - setValue("acceptQty", itemDetail.requiredQty ?? 0); - } - field.onChange(value); - }} - > - } - label="接受出庫" - /> - - - - + + ( + { + const value = e.target.value.toString(); + if (value != "1" && Boolean(errors.acceptQty)) { + setValue("acceptQty", itemDetail.requiredQty ?? 0); + } + field.onChange(value); + }} + > + } + label="接受出庫" + /> + - } - sx={{"& .Mui-checked": {color: "red"}}} - label="不接受並重新揀貨" - /> - - } - sx={{"& .Mui-checked": {color: "blue"}}} - label="上報品檢結果" - /> - - )} - /> - - - - {qcDecision == 3 && ( - - - - )} - - + {/* ✅ Combine options 2 & 3 into one */} + } + sx={{"& .Mui-checked": {color: "blue"}}} + label="上報品檢結果並重新揀貨" + /> + + )} + /> + + +/* +