CANCERYS\kw093 преди 4 дни
родител
ревизия
a249363da4
променени са 5 файла, в които са добавени 84 реда и са изтрити 47 реда
  1. +1
    -0
      src/components/FinishedGoodSearch/GoodPickExecutionForm.tsx
  2. +24
    -6
      src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx
  3. +1
    -0
      src/components/Jodetail/JobPickExecutionForm.tsx
  4. +57
    -41
      src/components/Jodetail/newJobPickExecution.tsx
  5. +1
    -0
      src/i18n/zh/pickOrder.json

+ 1
- 0
src/components/FinishedGoodSearch/GoodPickExecutionForm.tsx Целия файл

@@ -140,6 +140,7 @@ const PickExecutionForm: React.FC<PickExecutionFormProps> = ({
itemDescription: selectedPickOrderLine.itemName,
lotId: selectedLot.lotId,
lotNo: selectedLot.lotNo,
stockOutLineId: selectedLot.stockOutLineId,
storeLocation: selectedLot.location,
requiredQty: selectedLot.requiredQty,
actualPickQty: selectedLot.actualPickQty || 0,


+ 24
- 6
src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx Целия файл

@@ -511,6 +511,8 @@ const [pickOrderSwitching, setPickOrderSwitching] = useState(false);
const [combinedLotData, setCombinedLotData] = useState<any[]>([]);
const [combinedDataLoading, setCombinedDataLoading] = useState(false);
const [originalCombinedData, setOriginalCombinedData] = useState<any[]>([]);
// issue form 里填的 actualPickQty(用于 batch submit 只提交实际拣到数量,而不是补拣到 required)
const [issuePickedQtyBySolId, setIssuePickedQtyBySolId] = useState<Record<number, number>>({});
const { values: qrValues, isScanning, startScan, stopScan, resetScan } = useQrCodeScannerContext();
@@ -2246,6 +2248,19 @@ useEffect(() => {
if (result && result.code === "SUCCESS") {
console.log(" Pick execution issue recorded successfully");
// 关键:issue form 只记录问题,不会更新 SOL.qty
// 但 batch submit 需要知道“实际拣到多少”,否则会按 requiredQty 补拣到满
const solId = Number(issueData.stockOutLineId || issueData.stockOutLineId === 0 ? issueData.stockOutLineId : data?.stockOutLineId);
if (solId > 0) {
const picked = Number(issueData.actualPickQty || 0);
setIssuePickedQtyBySolId(prev => ({ ...prev, [solId]: picked }));
setCombinedLotData(prev => prev.map(lot => {
if (Number(lot.stockOutLineId) === solId) {
return { ...lot, actualPickQty: picked, stockOutLineQty: picked };
}
return lot;
}));
}
} else {
console.error(" Failed to record pick execution issue:", result);
}
@@ -2265,7 +2280,7 @@ useEffect(() => {
} catch (error) {
console.error("Error submitting pick execution form:", error);
}
}, [fetchAllCombinedLotData]);
}, [fetchAllCombinedLotData, session]);

// Calculate remaining required quantity
const calculateRemainingRequiredQty = useCallback((lot: any) => {
@@ -2744,13 +2759,16 @@ const handleSubmitAllScanned = useCallback(async () => {
const requiredQty =
Number(lot.requiredQty || lot.pickOrderLineRequiredQty || 0);
// 2. 当前已经拣到的数量(数据库里的 qty)
const currentActualPickQty = Number(lot.actualPickQty || 0);
// 2. 当前已经拣到的数量
// issue form 不会写回 SOL.qty,所以如果这条 SOL 有 issue,就用 issue form 的 actualPickQty 作为“已拣到数量”
const solId = Number(lot.stockOutLineId) || 0;
const issuePicked = solId > 0 ? issuePickedQtyBySolId[solId] : undefined;
const currentActualPickQty = Number(issuePicked ?? lot.actualPickQty ?? 0);
// 🔹 判断是否走“只改状态模式”
// 这里先给一个简单条件示例:如果你不想再补拣,只想把当前数量标记完成,
// 就让这个条件为 true(后面你可以根据业务加 UI 开关或别的 flag)。
const onlyComplete = lot.stockOutLineStatus === "partially_completed";
const onlyComplete = lot.stockOutLineStatus === "partially_completed" || issuePicked !== undefined;
// lot.stockOutLineStatus === "partially_completed" && false === true;
let targetActual: number;
@@ -2836,7 +2854,7 @@ const handleSubmitAllScanned = useCallback(async () => {
} finally {
setIsSubmittingAll(false);
}
}, [combinedLotData, fetchAllCombinedLotData, checkAndAutoAssignNext, currentUserId, onSwitchToRecordTab, onRefreshReleasedOrderCount]);
}, [combinedLotData, fetchAllCombinedLotData, checkAndAutoAssignNext, currentUserId, onSwitchToRecordTab, onRefreshReleasedOrderCount, issuePickedQtyBySolId]);

// Calculate scanned items count
// Calculate scanned items count (should match handleSubmitAllScanned filter logic)
@@ -3171,7 +3189,7 @@ paginatedData.map((lot, index) => {
}}
>
{lot.lotNo ||
t('This lot is not available, please scan another lot.')}
t('Please check around have QR code or not, may be have just now stock in or transfer in or transfer out.')}
</Typography>
</Box>
</TableCell>


+ 1
- 0
src/components/Jodetail/JobPickExecutionForm.tsx Целия файл

@@ -161,6 +161,7 @@ useEffect(() => {
itemDescription: selectedPickOrderLine.itemName,
lotId: selectedLot.lotId,
lotNo: selectedLot.lotNo,
stockOutLineId: selectedLot.stockOutLineId,
storeLocation: selectedLot.location,
requiredQty: selectedLot.requiredQty,
actualPickQty: initialVerifiedQty,


+ 57
- 41
src/components/Jodetail/newJobPickExecution.tsx Целия файл

@@ -457,6 +457,8 @@ const JobPickExecution: React.FC<Props> = ({ filterArgs, onBackToList }) => {
const [jobOrderData, setJobOrderData] = useState<JobOrderLotsHierarchicalResponse | null>(null);
const [pickQtyData, setPickQtyData] = useState<Record<string, number>>({});
const [searchQuery, setSearchQuery] = useState<Record<string, any>>({});
// issue form 里填的 actualPickQty(用于 submit/batch submit 不补拣到 required)
const [issuePickedQtyBySolId, setIssuePickedQtyBySolId] = useState<Record<number, number>>({});

const [paginationController, setPaginationController] = useState({
pageNum: 0,
@@ -631,8 +633,24 @@ const JobPickExecution: React.FC<Props> = ({ filterArgs, onBackToList }) => {
return isNaN(n) ? 0 : n;
};
const combinedLotData = useMemo(() => {
return getAllLotsFromHierarchical(jobOrderData);
}, [jobOrderData, getAllLotsFromHierarchical]);
const lots = getAllLotsFromHierarchical(jobOrderData);
// 前端覆盖:issue form/submit0 不会立刻改写后端 qty 时,用本地缓存让 UI 与 batch submit 计算一致
return lots.map((lot: any) => {
const solId = Number(lot.stockOutLineId) || 0;
if (solId > 0 && Object.prototype.hasOwnProperty.call(issuePickedQtyBySolId, solId)) {
const picked = Number(issuePickedQtyBySolId[solId] ?? 0);
const status = String(lot.stockOutLineStatus || '').toLowerCase();
const isEnded = status === 'completed' || status === 'rejected';
return {
...lot,
actualPickQty: picked,
stockOutLineQty: picked,
stockOutLineStatus: isEnded ? lot.stockOutLineStatus : 'checked',
};
}
return lot;
});
}, [jobOrderData, getAllLotsFromHierarchical, issuePickedQtyBySolId]);

const originalCombinedData = useMemo(() => {
return getAllLotsFromHierarchical(jobOrderData);
@@ -1786,16 +1804,18 @@ const JobPickExecution: React.FC<Props> = ({ filterArgs, onBackToList }) => {
// Continue even if handler update fails
}
}
// Special case: If submitQty is 0 and all values are 0, mark as completed with qty: 0
// ✅ 两步完成(与 DO 对齐):
// 1) Skip/Submit0 只把 SOL 标记为 checked(不直接 completed)
// 2) 之后由 batch submit 把 SOL 推到 completed(允许 0)
if (submitQty === 0) {
console.log(`=== SUBMITTING ALL ZEROS CASE ===`);
console.log(`Lot: ${lot.lotNo}`);
console.log(`Stock Out Line ID: ${lot.stockOutLineId}`);
console.log(`Setting status to 'completed' with qty: 0`);
console.log(`Setting status to 'checked' with qty: 0 (will complete in batch submit)`);
const updateResult = await updateStockOutLineStatus({
id: lot.stockOutLineId,
status: 'completed',
status: 'checked',
qty: 0
});
@@ -1813,34 +1833,15 @@ const JobPickExecution: React.FC<Props> = ({ filterArgs, onBackToList }) => {
}
// Check if pick order is completed
if (lot.pickOrderConsoCode) {
console.log(` Lot ${lot.lotNo} completed (all zeros), checking if pick order ${lot.pickOrderConsoCode} is complete...`);
try {
const completionResponse = await checkAndCompletePickOrderByConsoCode(lot.pickOrderConsoCode);
console.log(` Pick order completion check result:`, completionResponse);
if (completionResponse.code === "SUCCESS") {
console.log(` Pick order ${lot.pickOrderConsoCode} completed successfully!`);
setTimeout(() => {
if (onBackToList) {
onBackToList();
}
}, 1500);
} 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);
}
// 记录该 SOL 的“目标实际拣货量=0”,让 batch submit 走 onlyComplete(不补拣到 required)
const solId = Number(lot.stockOutLineId) || 0;
if (solId > 0) {
setIssuePickedQtyBySolId(prev => ({ ...prev, [solId]: 0 }));
}
const pickOrderId = filterArgs?.pickOrderId ? Number(filterArgs.pickOrderId) : undefined;
await fetchJobOrderData(pickOrderId);
console.log("All zeros submission completed successfully!");
console.log("All zeros submission marked as checked successfully (waiting for batch submit).");
setTimeout(() => {
checkAndAutoAssignNext();
@@ -1965,24 +1966,32 @@ const JobPickExecution: React.FC<Props> = ({ filterArgs, onBackToList }) => {

// ✅ 转换为 batchSubmitList 所需的格式
const lines: batchSubmitListLineRequest[] = scannedLots.map((lot) => {
const submitQty = lot.requiredQty || lot.pickOrderLineRequiredQty || 0;
const currentActualPickQty = lot.actualPickQty || 0;
const cumulativeQty = currentActualPickQty + submitQty;
let newStatus = 'partially_completed';
if (cumulativeQty >= (lot.requiredQty || 0)) {
const requiredQty = Number(lot.requiredQty || lot.pickOrderLineRequiredQty || 0);
const solId = Number(lot.stockOutLineId) || 0;
const issuePicked = solId > 0 ? issuePickedQtyBySolId[solId] : undefined;
const currentActualPickQty = Number(issuePicked ?? lot.actualPickQty ?? 0);
const onlyComplete = lot.stockOutLineStatus === 'partially_completed' || issuePicked !== undefined;

let targetActual: number;
let newStatus: string;
if (onlyComplete) {
targetActual = currentActualPickQty;
newStatus = 'completed';
} else {
const remainingQty = Math.max(0, requiredQty - currentActualPickQty);
targetActual = currentActualPickQty + remainingQty;
newStatus = (requiredQty > 0 && targetActual >= requiredQty) ? 'completed' : 'partially_completed';
}
return {
stockOutLineId: Number(lot.stockOutLineId) || 0,
pickOrderLineId: Number(lot.pickOrderLineId),
inventoryLotLineId: lot.lotId ? Number(lot.lotId) : null,
requiredQty: Number(lot.requiredQty || lot.pickOrderLineRequiredQty || 0),
actualPickQty: Number(cumulativeQty),
requiredQty,
actualPickQty: Number(targetActual),
stockOutLineStatus: newStatus,
pickOrderConsoCode: String(lot.pickOrderConsoCode || ''),
noLot: Boolean(false) // Job Order 通常都有 lot
noLot: Boolean(lot.noLot === true)
};
});
@@ -2019,9 +2028,11 @@ const JobPickExecution: React.FC<Props> = ({ filterArgs, onBackToList }) => {
} finally {
setIsSubmittingAll(false);
}
}, [combinedLotData, fetchJobOrderData, checkAndAutoAssignNext, currentUserId, filterArgs?.pickOrderId, onBackToList, updateHandledBy])
}, [combinedLotData, fetchJobOrderData, checkAndAutoAssignNext, currentUserId, filterArgs?.pickOrderId, onBackToList, updateHandledBy, issuePickedQtyBySolId])
const scannedItemsCount = useMemo(() => {
return combinedLotData.filter(lot => lot.stockOutLineStatus === 'checked').length;
return combinedLotData.filter(lot =>
lot.stockOutLineStatus === 'checked' || lot.stockOutLineStatus === 'partially_completed'
).length;
}, [combinedLotData]);
// 先定义 filteredByFloor 和 availableFloors
@@ -2114,6 +2125,11 @@ const JobPickExecution: React.FC<Props> = ({ filterArgs, onBackToList }) => {
if (result && result.code === "SUCCESS") {
console.log(" Pick execution issue recorded successfully");
const solId = Number(issueData.stockOutLineId || data?.stockOutLineId);
if (solId > 0) {
const picked = Number(issueData.actualPickQty || 0);
setIssuePickedQtyBySolId(prev => ({ ...prev, [solId]: picked }));
}
} else {
console.error("❌ Failed to record pick execution issue:", result);
}
@@ -2126,7 +2142,7 @@ const JobPickExecution: React.FC<Props> = ({ filterArgs, onBackToList }) => {
} catch (error) {
console.error("Error submitting pick execution form:", error);
}
}, [fetchJobOrderData]);
}, [fetchJobOrderData, currentUserId, selectedLotForExecutionForm, updateHandledBy, filterArgs?.pickOrderId]);

// Calculate remaining required quantity
const calculateRemainingRequiredQty = useCallback((lot: any) => {


+ 1
- 0
src/i18n/zh/pickOrder.json Целия файл

@@ -438,6 +438,7 @@
"Tomorrow": "翌日",
"No Stock Available": "沒有庫存可用",
"This lot is not available, please scan another lot.": "此批號不可用,請掃描其他批號。",
"Please check around have QR code or not, may be have just now stock in or transfer in or transfer out.": "請檢查周圍是否有 QR 碼,可能有剛剛入庫或轉移入庫 QR 碼。",
"Day After Tomorrow": "後日",
"Select Date": "請選擇日期",
"Search by Shop": "搜尋商店",


Зареждане…
Отказ
Запис