CANCERYS\kw093 3 miesięcy temu
rodzic
commit
b7b3f637f9
3 zmienionych plików z 98 dodań i 69 usunięć
  1. +15
    -1
      src/app/api/pickOrder/actions.ts
  2. +81
    -67
      src/components/FinishedGoodSearch/GoodPickExecution.tsx
  3. +2
    -1
      src/components/PickOrderSearch/LotTable.tsx

+ 15
- 1
src/app/api/pickOrder/actions.ts Wyświetl plik

@@ -244,7 +244,21 @@ export interface PickOrderCompletionResponse {
}>;
};
}

export interface UpdateSuggestedLotLineIdRequest {
newLotLineId: number;
}
export const updateSuggestedLotLineId = async (suggestedPickLotId: number, newLotLineId: number) => {
const response = await serverFetchJson<PostPickOrderResponse<UpdateSuggestedLotLineIdRequest>>(
`${BASE_API_URL}/suggestedPickLot/update-suggested-lot/${suggestedPickLotId}`,
{
method: "POST",
body: JSON.stringify({ newLotLineId }),
headers: { "Content-Type": "application/json" },
},
);
revalidateTag("pickorder");
return response;
};
export const autoAssignAndReleasePickOrder = async (userId: number): Promise<AutoAssignReleaseResponse> => {
const response = await serverFetchJson<AutoAssignReleaseResponse>(
`${BASE_API_URL}/pickOrder/auto-assign-release/${userId}`,


+ 81
- 67
src/components/FinishedGoodSearch/GoodPickExecution.tsx Wyświetl plik

@@ -59,7 +59,8 @@ const QrCodeModal: React.FC<{
onClose: () => void;
lot: any | null;
onQrCodeSubmit: (lotNo: string) => void;
}> = ({ open, onClose, lot, onQrCodeSubmit }) => {
combinedLotData: any[]; // ✅ Add this prop
}> = ({ open, onClose, lot, onQrCodeSubmit, combinedLotData }) => {
const { t } = useTranslation("pickOrder");
const { values: qrValues, isScanning, startScan, stopScan, resetScan } = useQrCodeScannerContext();
const [manualInput, setManualInput] = useState<string>('');
@@ -398,11 +399,15 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => {
// const handleAutoAssignAndRelease = useCallback(async () => { ... }); // 删除这个函数

// ✅ Handle QR code submission for matched lot (external scanning)
const handleQrCodeSubmit = useCallback(async (lotNo: string) => {
// ✅ Handle QR code submission for matched lot (external scanning)
const handleQrCodeSubmit = useCallback(async (lotNo: string) => {
console.log(`✅ Processing QR Code for lot: ${lotNo}`);
console.log(`🔍 Available lots:`, combinedLotData.map(lot => lot.lotNo));
const matchingLots = combinedLotData.filter(lot =>
// ✅ Use current data without refreshing to avoid infinite loop
const currentLotData = combinedLotData;
console.log(`🔍 Available lots:`, currentLotData.map(lot => lot.lotNo));
const matchingLots = currentLotData.filter(lot =>
lot.lotNo === lotNo ||
lot.lotNo?.toLowerCase() === lotNo.toLowerCase()
);
@@ -430,7 +435,7 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => {
existsCount++;
} else {
const stockOutLineData: CreateStockOutLine = {
consoCode: matchingLot.pickOrderConsoCode, // ✅ Use pickOrderConsoCode instead of pickOrderCode
consoCode: matchingLot.pickOrderConsoCode,
pickOrderLineId: matchingLot.pickOrderLineId,
inventoryLotLineId: matchingLot.lotId,
qty: 0.0
@@ -447,40 +452,56 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => {
console.log(`✅ Stock out line created successfully for line ${matchingLot.pickOrderLineId}`);
successCount++;
} else {
console.error(`❌ Unexpected response for line ${matchingLot.pickOrderLineId}:`, result);
console.error(`❌ Failed to create stock out line for line ${matchingLot.pickOrderLineId}:`, result);
errorCount++;
}
}
const lotKey = `${matchingLot.pickOrderLineId}-${matchingLot.lotId}`;
setPickQtyData(prev => ({
...prev,
[lotKey]: matchingLot.requiredQty
}));
}
// ✅ Always refresh data after processing (success or failure)
console.log("🔄 Refreshing data after QR code processing...");
await fetchAllCombinedLotData();
if (successCount > 0 || existsCount > 0) {
console.log(`✅ QR Code processing completed: ${successCount} created, ${existsCount} already existed`);
setQrScanSuccess(true);
setQrScanError(false);
console.log(`✅ QR Code processing completed: ${successCount} created, ${existsCount} already existed, ${errorCount} errors`);
setQrScanInput(''); // Clear input after successful processing
// ✅ Clear success state after a delay
setTimeout(() => {
setQrScanSuccess(false);
}, 2000);
} else {
console.error(`❌ QR Code processing failed: ${errorCount} errors`);
setQrScanError(true);
setQrScanSuccess(false);
console.error(`❌ All operations failed for lot ${lotNo}`);
return;
// ✅ Clear error state after a delay
setTimeout(() => {
setQrScanError(false);
}, 3000);
}
await fetchAllCombinedLotData();
setQrScanInput('');
console.log("Stock out line process completed successfully!");
} catch (error) {
console.error("Error creating stock out line:", error);
console.error("❌ Error processing QR code:", error);
setQrScanError(true);
setQrScanSuccess(false);
// ✅ Still refresh data even on error
await fetchAllCombinedLotData();
// ✅ Clear error state after a delay
setTimeout(() => {
setQrScanError(false);
}, 3000);
}
}, [combinedLotData, fetchAllCombinedLotData]);

const handleManualInputSubmit = useCallback(() => {
if (qrScanInput.trim() !== '') {
handleQrCodeSubmit(qrScanInput.trim());
}
}, [qrScanInput, handleQrCodeSubmit]);

// ✅ Handle QR code submission from modal (internal scanning)
const handleQrCodeSubmitFromModal = useCallback(async (lotNo: string) => {
if (selectedLotForQr && selectedLotForQr.lotNo === lotNo) {
@@ -523,22 +544,44 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => {
}
}, [selectedLotForQr, fetchAllCombinedLotData]);

// ✅ External QR scanning - process QR codes from outside the page
// ✅ Outside QR scanning - process QR codes from outside the page automatically
useEffect(() => {
if (qrValues.length > 0 && combinedLotData.length > 0) {
const latestQr = qrValues[qrValues.length - 1];
const qrContent = latestQr.replace(/[{}]/g, '');
setQrScanInput(qrContent);
handleQrCodeSubmit(qrContent);
// Extract lot number from QR code
let lotNo = '';
try {
const qrData = JSON.parse(latestQr);
if (qrData.stockInLineId && qrData.itemId) {
// For JSON QR codes, we need to fetch the lot number
fetchStockInLineInfo(qrData.stockInLineId)
.then((stockInLineInfo) => {
console.log("Outside QR scan - Stock in line info:", stockInLineInfo);
const extractedLotNo = stockInLineInfo.lotNo;
if (extractedLotNo) {
console.log(`Outside QR scan detected (JSON): ${extractedLotNo}`);
handleQrCodeSubmit(extractedLotNo);
}
})
.catch((error) => {
console.error("Outside QR scan - Error fetching stock in line info:", error);
});
return; // Exit early for JSON QR codes
}
} catch (error) {
// Not JSON format, treat as direct lot number
lotNo = latestQr.replace(/[{}]/g, '');
}
// For direct lot number QR codes
if (lotNo) {
console.log(`Outside QR scan detected (direct): ${lotNo}`);
handleQrCodeSubmit(lotNo);
}
}
}, [qrValues, combinedLotData, handleQrCodeSubmit]);

const handleManualInputSubmit = useCallback(() => {
if (qrScanInput.trim() !== '') {
handleQrCodeSubmit(qrScanInput.trim());
}
}, [qrScanInput, handleQrCodeSubmit]);

const handlePickQtyChange = useCallback((lotKey: string, value: number | string) => {
if (value === '' || value === null || value === undefined) {
@@ -836,41 +879,8 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => {
<Typography variant="h6" gutterBottom sx={{ mb: 0 }}>
{t("All Pick Order Lots")}
</Typography>
{/* ✅ External QR scan input - for scanning from outside the page */}
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<TextField
size="small"
value={qrScanInput}
onChange={(e) => setQrScanInput(e.target.value)}
onKeyPress={(e) => {
if (e.key === 'Enter') {
handleManualInputSubmit();
}
}}
error={qrScanError}
color={qrScanSuccess ? 'success' : undefined}
helperText={
qrScanError
? t("Lot number not found")
: qrScanSuccess
? t("Lot processed successfully")
: t("Enter lot number or scan QR code")
}
placeholder={t("Enter lot number...")}
sx={{ minWidth: '250px' }}
InputProps={{
startAdornment: <QrCodeIcon sx={{ mr: 1, color: isScanning ? 'primary.main' : 'text.secondary' }} />,
}}
/>
<Button
variant="outlined"
onClick={handleManualInputSubmit}
disabled={!qrScanInput.trim()}
size="small"
>
{t("Submit")}
</Button>
</Box>
</Box>
<TableContainer component={Paper}>
@@ -923,7 +933,9 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => {
}}
>
{lot.lotNo}
</Typography>
{/*
{lot.lotAvailability !== 'available' && (
<Typography variant="caption" color="error" display="block">
({lot.lotAvailability === 'expired' ? 'Expired' :
@@ -931,7 +943,8 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => {
lot.lotAvailability === 'rejected' ? 'Rejected' :
'Unavailable'})
</Typography>
)}
)*/}
</Box>
</TableCell>
<TableCell>{lot.pickOrderTargetDate}</TableCell>
@@ -1091,6 +1104,7 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => {
resetScan();
}}
lot={selectedLotForQr}
combinedLotData={combinedLotData} // ✅ Add this prop
onQrCodeSubmit={handleQrCodeSubmitFromModal}
/>



+ 2
- 1
src/components/PickOrderSearch/LotTable.tsx Wyświetl plik

@@ -620,6 +620,7 @@ const LotTable: React.FC<LotTableProps> = ({
>
{lot.lotNo}
</Typography>
{/*
{lot.lotAvailability !== 'available' && (
<Typography variant="caption" color="error" display="block">
({lot.lotAvailability === 'expired' ? 'Expired' :
@@ -627,7 +628,7 @@ const LotTable: React.FC<LotTableProps> = ({
lot.lotAvailability === 'rejected' ? 'Rejected' : // ✅ 添加 rejected 显示
'Unavailable'})
</Typography>
)}
)} */}
</Box>
</TableCell>
<TableCell>{lot.expiryDate}</TableCell>


Ładowanie…
Anuluj
Zapisz