| 2025-11-30 | pan | ![]() |
| 2025-11-30 | pan | ![]() |
| 2025-11-30 | heshaofeng | ![]() |
| 2025-11-30 | 647556386 | ![]() |
| 2025-11-30 | pan | ![]() |
| 2025-11-30 | heshaofeng | ![]() |
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/inbound/allocateinboundOrder.js
@@ -194,8 +194,8 @@ // æ¶éææéä¸åæ®çç¼å·ï¼è¿æ»¤æ åæ®å·çå¼å¸¸è¡ï¼ const inboundOrderNos = selectedRows .filter(row => row.inboundOrderNo) .map(row => row.inboundOrderNo); .filter(row => row.orderNo) .map(row => row.orderNo); // æ ¡éª2ï¼æ¯å¦æææåæ®å· if (inboundOrderNos.length === 0) { ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/outbound/extend/NoStockOut.vue
@@ -9,51 +9,29 @@ class="custom-vol-box" > <div> <!-- 忮鿩åºåï¼å¯è¾å ¥æç´¢ï¼ --> <!-- åæ®è¾å ¥åºåï¼æ¯ææ«ç ï¼ --> <el-form :inline="true" :model="orderForm" style="margin-bottom: 20px; align-items: flex-end;"> <el-form-item label="åºåºåæ®:" name="outboundOrderId"> <el-select v-model="orderForm.outboundOrderId" placeholder="è¯·éæ©ææ«æåºåºåæ®å·" <el-form-item label="åºåºåæ®:" name="outboundOrderNo"> <el-input v-model="orderForm.outboundOrderNo" placeholder="请è¾å ¥ææ«æåºåºåæ®å·" clearable style="width: 220px; margin-right: 10px;" @change="handleOrderChange" @visible-change="handleOutboundVisibleChange" :loading="loading" filterable :filter-method="filterOutboundOrders" @input="handleOutboundScanInput" ref="outboundSelectRef" > <el-option v-for="order in filteredOutboundOrders" :key="order.id" :label="order.orderNo" :value="order.id" ></el-option> </el-select> @input="handleOutboundInput" @keyup.enter="focusPurchaseInput" ref="outboundInputRef" ></el-input> </el-form-item> <el-form-item label="éè´åæ®:" name="purchaseOrderId"> <el-select v-model="orderForm.purchaseOrderId" placeholder="è¯·éæ©ææ«æéè´åæ®å·" <el-form-item label="éè´åæ®:" name="purchaseOrderNo"> <el-input v-model="orderForm.purchaseOrderNo" placeholder="请è¾å ¥ææ«æéè´åæ®å·" clearable style="width: 220px; margin-right: 10px;" @change="handleOrderChange" @visible-change="handlePurchaseVisibleChange" :loading="loading" filterable :filter-method="filterPurchaseOrders" @input="handlePurchaseScanInput" ref="purchaseSelectRef" > <el-option v-for="order in filteredPurchaseOrders" :key="order.id" :label="order.orderNo" :value="order.id" ></el-option> </el-select> @input="handlePurchaseInput" @keyup.enter="focusBarcodeInput" ref="purchaseInputRef" ></el-input> </el-form-item> </el-form> @@ -72,7 +50,7 @@ @keyup.enter="handleScan" autofocus class="custom-input" :disabled="!orderForm.outboundOrderId || !orderForm.purchaseOrderId" :disabled="!orderForm.outboundOrderNo || !orderForm.purchaseOrderNo" ></el-input> </el-form-item> <el-form-item> @@ -81,7 +59,7 @@ size="small" @click="handleScan" class="custom-button" :disabled="!orderForm.outboundOrderId || !orderForm.purchaseOrderId || loading" :disabled="!orderForm.outboundOrderNo || !orderForm.purchaseOrderNo || loading" > <Search /> ç¡®è®¤æ«æ </el-button> @@ -109,7 +87,7 @@ </div> </transition-group> <div class="empty-tip" v-if="scannedBarcodes.length === 0"> <span>ææ æ«æè®°å½ï¼è¯·å éæ©åæ®åæ«ææ¡ç </span> <span>ææ æ«æè®°å½ï¼è¯·å è¾å ¥åæ®åæ«ææ¡ç </span> </div> </el-scrollbar> </div> @@ -123,7 +101,7 @@ type="primary" size="small" @click="submit" :disabled="scannedBarcodes.length === 0 || !orderForm.outboundOrderId || !orderForm.purchaseOrderId || loading" :disabled="scannedBarcodes.length === 0 || !orderForm.outboundOrderNo || !orderForm.purchaseOrderNo || loading" class="submit-btn" > <Check /> æäº¤åºåº @@ -140,6 +118,7 @@ <script setup> import { ref, reactive, onMounted, nextTick } from 'vue'; import { ElMessage } from 'element-plus'; import { Search } from '@element-plus/icons-vue'; import VolBox from "@/components/basic/VolBox.vue"; import http from '@/api/http'; @@ -147,32 +126,26 @@ // ååºå¼æ°æ® const showDetailBox = ref(false); const orderForm = reactive({ outboundOrderId: "", purchaseOrderId: "" outboundOrderNo: "", purchaseOrderNo: "" }); const formData = reactive({ barcode: "", }); const scannedBarcodes = ref([]); const outboundOrders = ref([]); const purchaseOrders = ref([]); const filteredOutboundOrders = ref([]); const filteredPurchaseOrders = ref([]); const loading = ref(false); // 模æ¿å¼ç¨ const formRef = ref(null); const barcodeInputRef = ref(null); const outboundSelectRef = ref(null); // æ°å¢ï¼åºåºåselectçref const purchaseSelectRef = ref(null); // æ°å¢ï¼éè´åselectçref const outboundInputRef = ref(null); const purchaseInputRef = ref(null); // ç¨äºé²æ¢è¾å ¥äºä»¶åchangeäºä»¶å²çªçé const isProcessingScan = ref(false); // ç»ä»¶æè½½æ¶åå§åè¿æ»¤åçå表 // ç»ä»¶æè½½æ¶èç¦å°åºåºåè¾å ¥æ¡ onMounted(() => { filteredOutboundOrders.value = [...outboundOrders.value]; filteredPurchaseOrders.value = [...purchaseOrders.value]; nextTick(() => { outboundInputRef.value?.focus(); }); }); // æå¼å¼¹çª @@ -180,169 +153,44 @@ showDetailBox.value = true; scannedBarcodes.value = []; formData.barcode = ""; orderForm.outboundOrderId = ""; orderForm.purchaseOrderId = ""; orderForm.outboundOrderNo = ""; orderForm.purchaseOrderNo = ""; nextTick(() => { barcodeInputRef.value?.focus(); outboundInputRef.value?.focus(); }); }; // å è½½åºåºåæ®å表 const loadOutboundOrders = async () => { if (outboundOrders.value.length > 0) return; try { loading.value = true; const res = await http.get("/api/OutboundPicking/GetAvailablePickingOrders"); if (res.code === 0) { outboundOrders.value = res.data.map(orderNo => ({ id: orderNo, orderNo: orderNo })); filteredOutboundOrders.value = [...outboundOrders.value]; } else { ElMessage.error("å è½½åºåºåæ®å¤±è´¥ï¼" + (res.message || 'æªç¥é误')); } } catch (error) { ElMessage.error("å è½½åºåºåæ®å¼å¸¸ï¼" + error.message); } finally { loading.value = false; // åºåºåè¾å ¥å¤çï¼æ«ç ææå¨è¾å ¥ï¼ const handleOutboundInput = (value) => { // æ«ç æªè¾å ¥é常ä¼èªå¨è§¦åenteräºä»¶ï¼è¿é主è¦å¤çæå¨è¾å ¥çæ åµ if (value && value.trim()) { // å¯ä»¥å¨è¿éæ·»å åºåºåå·çæ ¼å¼éªè¯é»è¾ } }; // å è½½éè´åæ®å表 const loadPurchaseOrders = async () => { if (purchaseOrders.value.length > 0) return; try { loading.value = true; const res = await http.get("/api/OutboundPicking/GetAvailablePurchaseOrders"); if (res.status === true) { purchaseOrders.value = res.data.map(orderNo => ({ id: orderNo, orderNo: orderNo })); filteredPurchaseOrders.value = [...purchaseOrders.value]; } else { ElMessage.error("å è½½éè´åæ®å¤±è´¥ï¼" + (res.message || 'æªç¥é误')); } } catch (error) { ElMessage.error("å è½½éè´åæ®å¼å¸¸ï¼" + error.message); } finally { loading.value = false; // éè´åè¾å ¥å¤çï¼æ«ç ææå¨è¾å ¥ï¼ const handlePurchaseInput = (value) => { if (value && value.trim()) { // å¯ä»¥å¨è¿éæ·»å éè´åå·çæ ¼å¼éªè¯é»è¾ } }; // åºåºåæ®è¿æ»¤æ¹æ³ const filterOutboundOrders = (value) => { if (!value) { filteredOutboundOrders.value = [...outboundOrders.value]; // ç¦ç¹è·³è½¬å½æ° const focusPurchaseInput = () => { if (orderForm.outboundOrderNo.trim()) { purchaseInputRef.value?.focus(); } else { const lowerValue = value.toLowerCase(); filteredOutboundOrders.value = outboundOrders.value.filter(order => order.orderNo.toLowerCase().includes(lowerValue) ); ElMessage.warning("请å è¾å ¥ææçåºåºåæ®å·"); } }; // éè´åæ®è¿æ»¤æ¹æ³ const filterPurchaseOrders = (value) => { if (!value) { filteredPurchaseOrders.value = [...purchaseOrders.value]; } else { const lowerValue = value.toLowerCase(); filteredPurchaseOrders.value = purchaseOrders.value.filter(order => order.orderNo.toLowerCase().includes(lowerValue) ); } }; // åºåºåæ®ä¸ææ¡æ¾ç¤º/éèæ¶è§¦å const handleOutboundVisibleChange = (visible) => { if (visible) { loadOutboundOrders(); } else { // å½ä¸ææ¡å ³éæ¶ï¼å¦ææ¯æ«ææä½å¯¼è´çï¼æ¸ 空è¾å ¥æ¡ if (isProcessingScan.value) { nextTick(() => { outboundSelectRef.value?.clearInput(); isProcessingScan.value = false; }); } } }; // éè´åæ®ä¸ææ¡æ¾ç¤º/éèæ¶è§¦å const handlePurchaseVisibleChange = (visible) => { if (visible) { loadPurchaseOrders(); } else { // å½ä¸ææ¡å ³éæ¶ï¼å¦ææ¯æ«ææä½å¯¼è´çï¼æ¸ 空è¾å ¥æ¡ if (isProcessingScan.value) { nextTick(() => { purchaseSelectRef.value?.clearInput(); isProcessingScan.value = false; }); } } }; // 忮鿩ååæ¶è§¦å const handleOrderChange = () => { // å¦ææ¯æå¨éæ©ï¼å䏿¸ 空è¾å ¥æ¡ isProcessingScan.value = false; scannedBarcodes.value = []; nextTick(() => { const focusBarcodeInput = () => { if (orderForm.purchaseOrderNo.trim()) { barcodeInputRef.value?.focus(); }); }; /** * å¤çåºåºåæ«æè¾å ¥ * @param {string} scanText - æ«ææªè¾å ¥çææ¬ */ const handleOutboundScanInput = async (scanText) => { // é¿å å¤ç空å符串æç±changeäºä»¶è§¦åçå é¨æä½ if (!scanText || isProcessingScan.value) return; // æ¥æ¾å®å ¨å¹é ç订å const matchedOrder = outboundOrders.value.find(order => order.orderNo === scanText); if (matchedOrder) { isProcessingScan.value = true; // æ 记为æ£å¨å¤çæ«æ // æå¨èµå¼ orderForm.outboundOrderId = matchedOrder.id; ElMessage.success(`æåéæ©åºåºåï¼${matchedOrder.orderNo}`); // å»¶è¿èç¦å°ä¸ä¸ä¸ªè¾å ¥æ¡ï¼ç¡®ä¿èµå¼å®æ setTimeout(() => { purchaseSelectRef.value?.focus(); }, 100); } // å¦ææ²¡æå¹é 项ï¼ä¸åä»»ä½äºï¼è®©el-selectä¿æè¿æ»¤ç¶æï¼ç¨æ·å¯ä»¥æå¨éæ© }; /** * å¤çéè´åæ«æè¾å ¥ * @param {string} scanText - æ«ææªè¾å ¥çææ¬ */ const handlePurchaseScanInput = async (scanText) => { if (!scanText || isProcessingScan.value) return; const matchedOrder = purchaseOrders.value.find(order => order.orderNo === scanText); if (matchedOrder) { isProcessingScan.value = true; // æ 记为æ£å¨å¤çæ«æ orderForm.purchaseOrderId = matchedOrder.id; ElMessage.success(`æåéæ©éè´åï¼${matchedOrder.orderNo}`); setTimeout(() => { barcodeInputRef.value?.focus(); }, 100); } else { ElMessage.warning("请å è¾å ¥ææçéè´åæ®å·"); } }; // æ«ææ¡ç å¤ç const handleScan = async () => { @@ -360,9 +208,10 @@ try { loading.value = true; // è¿éä¿çäºåæçæ¡ç éªè¯æ¥å£ï¼ä½ å¯ä»¥æ ¹æ®å®é éæ±ä¿®æ¹æä¿ç const res = await http.post("/api/OutboundPicking/BarcodeValidate", { outOder: orderForm.outboundOrderId, inOder: orderForm.purchaseOrderId, outOder: orderForm.outboundOrderNo, // 注æï¼è¿éç°å¨ä¼ éçæ¯åæ®å·å符串ï¼è䏿¯ID inOder: orderForm.purchaseOrderNo, // 注æï¼è¿éç°å¨ä¼ éçæ¯åæ®å·å符串ï¼è䏿¯ID barCode: barcode }); @@ -385,9 +234,10 @@ const removeItem = async (index, barcode) => { try { loading.value = true; // è¿éä¿çäºåæçå 餿¡ç æ¥å£ï¼ä½ å¯ä»¥æ ¹æ®å®é éæ±ä¿®æ¹æä¿ç const res = await http.post("/api/OutboundPicking/DeleteBarcode", { outOder: orderForm.outboundOrderId, inOder: orderForm.purchaseOrderId, outOder: orderForm.outboundOrderNo, inOder: orderForm.purchaseOrderNo, barCode: barcode }); @@ -415,9 +265,10 @@ try { loading.value = true; // è¿éä¿çäºåæçæäº¤æ¥å£ï¼æ³¨æåæ°ç°å¨ä¼ éçæ¯åæ®å·å符串 const res = await http.post("/api/OutboundPicking/NoStockOutSubmit", { OutOderSubmit: orderForm.outboundOrderId, InOderSubmit: orderForm.purchaseOrderId, OutOderSubmit: orderForm.outboundOrderNo, InOderSubmit: orderForm.purchaseOrderNo, BarCodeSubmit: barcodes }); ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/outbound/extend/printView.vue
@@ -1,239 +1,246 @@ <template> <div> <vol-box v-model="showDetialBox" :lazy="true" width="500px" :padding="15" title=""> <!-- æå°ä¸ç¨å®¹å¨ --> <div id="printContainer" style="position: absolute; left: -9999px;"> <div class="print-page" v-for="(item, index) in printData" :key="index"> <div class="material-card"> <!-- <div class="header">ååè½ç©ææ è¯å¡(å°å )</div> --> <div class="dual-column preview-card-header-qrcode"> <div class="preview-card-header">ç©æå¡ {{ idx + 1 }}</div> <VueQrcode :value="generateQr(item)" :size="20" id="qrcode" /> <div> <vol-box v-model="showDetialBox" :lazy="true" width="500px" :padding="15" title=""> <!-- æå°ä¸ç¨å®¹å¨ --> <div id="printContainer" style="position: absolute; left: -9999px"> <div class="print-page" v-for="(item, index) in printData" :key="index"> <div class="material-card"> <div class="dual-column header-section"> <div class="header">ååè½ç©ææ è¯å¡(å°å )</div> <VueQrcode :value="generateQr(item)" :size="60" class="qrcode" /> </div> <div class="content"> <div class="row dual-column"> <div class="column"> <span class="label">æå·</span> <span class="value code-value full-width">{{ item.materialCode }}</span> </div> <div class="column"> <span class="label">ä¾åºåç¼ç </span> <span class="value full-width">{{ item.supplierCode }}</span> </div> </div> <div class="row dual-column"> <div class="column"> <span class="label">åå</span> <span class="value full-width">{{ item.materialName }}</span> </div> <div class="column"> <span class="label">éè´åå·</span> <span class="value full-width">{{ item.purchaseOrderNo }}</span> </div> </div> <div class="row dual-column"> <div class="column"> <span class="label">è§æ ¼</span> <span class="value full-width">{{ item.specification }}</span> </div> <div class="column"> <span class="label">æ°é/æ»æ°</span> <span class="value full-width">{{ item.quantityTotal }}</span> </div> </div> <div class="row dual-column"> <div class="column"> <span class="label">æ¹å·</span> <span class="value full-width">{{ item.batchNumber }}</span> </div> <div class="column"> <span class="label">æ¹æ¬¡</span> <span class="value full-width">{{ item.batch }}</span> </div> </div> <div class="row dual-column"> <div class="column"> <span class="label">ååº</span> <span class="value full-width">{{ item.factory }}</span> </div> <div class="column"> <span class="label">æ¥æ</span> <span class="value full-width">{{ item.date }}</span> </div> </div> </div> </div> </div> </div> <div class="content"> <!-- äºç»´ç æ¾å¨å³ä¸è§ --> <!-- <div class="qr-section"> --> <!-- <VueQrcode :value="generateQr(item)" id="qrcode" /> --> <!-- </div> --> <div class="row dual-column"> <div class="column"> <span class="label">æå·</span> <span class="value code-value">{{ item.materialCode }}</span> </div> <div class="column"> <span class="label">ä¾åºåç¼ç </span> <span class="value">{{ item.supplierCode }}</span> </div> </div> <div class="row dual-column"> <div class="column"> <span class="label">åå</span> <span class="value">{{ item.materialName }}</span> </div> <div class="column"> <span class="label">éè´åå·</span> <span class="value">{{ item.purchaseOrderNo }}</span> </div> </div> <!-- é¢è§åºåä¿æä¸å --> <div id="previewContent" class="preview-container"> <div class="preview-header">ååè½ç©ææ è¯å¡(å°å ) - é¢è§ (å ±{{ printData.length }}个)</div> <div class="preview-scroll"> <div v-for="(item, idx) in printData" :key="idx" class="preview-card"> <div class="dual-column preview-card-header-qrcode"> <div class="preview-card-header">ååè½ç©ææ è¯å¡(å°å )</div> <VueQrcode :value="generateQr(item)" :size="40" class="qrcode-preview" /> </div> <div class="preview-wrapper"> <div class="content-preview"> <div class="row-preview dual-column"> <div class="column-preview"> <span class="label-preview">æå·</span> <span class="value-preview code-value full-width">{{ item.materialCode }}</span> </div> <div class="column-preview"> <span class="label-preview">ä¾åºåç¼ç </span> <span class="value-preview full-width">{{ item.supplierCode }}</span> </div> </div> <div class="row dual-column"> <div class="column"> <span class="label">è§æ ¼</span> <span class="value full-width">{{ item.specification }}</span> </div> <div class="column"> <span class="label">æ°é/æ»æ°</span> <span class="value">{{ item.quantityTotal }}</span> </div> </div> <div class="row-preview dual-column"> <div class="column-preview"> <span class="label-preview">åå</span> <span class="value-preview full-width">{{ item.materialName }}</span> </div> <div class="column-preview"> <span class="label-preview">éè´åå·</span> <span class="value-preview full-width">{{ item.purchaseOrderNo }}</span> </div> </div> <div class="row dual-column"> <div class="column"> <span class="label">æ¹å·</span> <span class="value">{{ item.batchNumber }}</span> </div> <div class="column"> <span class="label">æ¹æ¬¡</span> <span class="value">{{ item.batch }}</span> </div> </div> <div class="row-preview dual-column"> <div class="column-preview"> <span class="label-preview">è§æ ¼</span> <span class="value-preview full-width">{{ item.specification }}</span> </div> <div class="column-preview"> <span class="label-preview">æ°é/æ»æ°</span> <span class="value-preview full-width">{{ item.quantityTotal }}</span> </div> </div> <div class="row dual-column"> <div class="column"> <span class="label">ååº</span> <span class="value">{{ item.factory }}</span> <div class="row-preview dual-column"> <div class="column-preview"> <span class="label-preview">æ¹å·</span> <span class="value-preview full-width">{{ item.batchNumber }}</span> </div> <div class="column-preview"> <span class="label-preview">æ¹æ¬¡</span> <span class="value-preview full-width">{{ item.batch }}</span> </div> </div> <div class="row-preview dual-column"> <div class="column-preview"> <span class="label-preview">ååº</span> <span class="value-preview full-width">{{ item.factory }}</span> </div> <div class="column-preview"> <span class="label-preview">æ¥æ</span> <span class="value-preview full-width">{{ item.date }}</span> </div> </div> </div> </div> </div> </div> <div class="column"> <span class="label">æ¥æ</span> <span class="value">{{ item.date }}</span> </div> </div> </div> </div> </div> </div> <!-- é¢è§åºå --> <div id="previewContent" class="preview-container"> <div class="preview-header">ååè½ç©ææ è¯å¡(å°å ) - é¢è§ (å ±{{ printData.length }}个)</div> <div class="preview-scroll"> <div v-for="(item, idx) in printData" :key="idx" class="preview-card"> <div class="dual-column preview-card-header-qrcode"> <div class="preview-card-header">ç©æå¡ {{ idx + 1 }}</div> <VueQrcode :value="generateQr(item)" :size="20" id="qrcode" /> </div> <div class="preview-wrapper"> <div class="content-preview"> <div class="row-preview dual-column"> <div class="column-preview"> <span class="label-preview">æå·</span> <span class="value-preview code-value">{{ item.materialCode }}</span> </div> <div class="column-preview"> <span class="label-preview">ä¾åºåç¼ç </span> <span class="value-preview">{{ item.supplierCode }}</span> </div> <template #footer> <div class="footer-actions"> <span class="print-count">å ± {{ printData.length }} ä¸ªç©æå¡å¾ æå°</span> <div> <el-button type="primary" size="small" @click="print">æå°å ¨é¨</el-button> <el-button type="danger" size="small" @click="showDetialBox = false">å ³é</el-button> </div> </div> <div class="row-preview dual-column"> <div class="column-preview"> <span class="label-preview">åå</span> <span class="value-preview">{{ item.materialName }}</span> </div> <div class="column-preview"> <span class="label-preview">éè´åå·</span> <span class="value-preview">{{ item.purchaseOrderNo }}</span> </div> </div> <div class="row-preview dual-column"> <div class="column-preview"> <span class="label-preview">è§æ ¼</span> <span class="value-preview full-width">{{ item.specification }}</span> </div> <div class="column-preview"> <span class="label-preview">æ°é/æ»æ°</span> <span class="value-preview">{{ item.quantityTotal }}</span> </div> </div> <div class="row-preview dual-column"> <div class="column-preview"> <span class="label-preview">æ¹å·</span> <span class="value-preview">{{ item.batchNumber }}</span> </div> <div class="column-preview"> <span class="label-preview">æ¹æ¬¡</span> <span class="value-preview">{{ item.batch }}</span> </div> </div> <div class="row-preview dual-column"> <div class="column-preview"> <span class="label-preview">ååº</span> <span class="value-preview">{{ item.factory }}</span> </div> <div class="column-preview"> <span class="label-preview">æ¥æ</span> <span class="value-preview">{{ item.date }}</span> </div> </div> </div> </div> </div> </div> </div> <template #footer> <div class="footer-actions"> <span class="print-count">å ± {{ printData.length }} ä¸ªç©æå¡å¾ æå°</span> <div> <el-button type="primary" size="small" @click="print">æå°å ¨é¨</el-button> <el-button type="danger" size="small" @click="showDetialBox = false">å ³é</el-button> </div> </div> </template> </vol-box> </div> </template> </vol-box> </div> </template> <script> import VolBox from "@/components/basic/VolBox.vue"; import VueQrcode from "vue-qrcode"; import VolBox from '@/components/basic/VolBox.vue' import VueQrcode from 'vue-qrcode' export default { components: { VolBox, VueQrcode }, data() { return { showDetialBox: false, printData: [], // å卿尿°æ®éå }; }, methods: { generateQr(item) { return `${item.batchNumber}`; components: { VolBox, VueQrcode }, data() { return { showDetialBox: false, printData: [] } }, methods: { generateQr(item) { return `${item.batchNumber}` }, open(rows) { this.showDetialBox = true; this.printData = Array.isArray(rows) ? rows : [rows]; console.log('æå°æ°æ®:', this.printData); }, open(rows) { this.showDetialBox = true this.printData = Array.isArray(rows) ? rows : [rows] console.log('æå°æ°æ®:', this.printData); }, async print() { if (this.printData.length === 0) { this.$message.warning('没æå¯æå°çæ°æ®'); return; } async print() { if (this.printData.length === 0) { this.$message.warning('没æå¯æå°çæ°æ®') return } this.$nextTick(() => { try { const printContent = document.getElementById("printContainer").innerHTML; const printWindow = window.open("", "_blank", "width=800,height=600,scrollbars=yes"); this.$nextTick(() => { try { const printContent = document.getElementById('printContainer').innerHTML const printWindow = window.open('', '_blank', 'width=800,height=600,scrollbars=yes') if (!printWindow) { this.$message.error('æ æ³æå¼æå°çªå£ï¼è¯·æ£æ¥æµè§å¨å¼¹çªè®¾ç½®'); return; } if (!printWindow) { this.$message.error('æ æ³æå¼æå°çªå£ï¼è¯·æ£æ¥æµè§å¨å¼¹çªè®¾ç½®') return } printWindow.document.write(` printWindow.document.write(` <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>ç©ææ è¯å¡æå° - å ±${this.printData.length}个</title> <style> /* éç½®æææ ·å¼ */ * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: SimSun, "å®ä½", sans-serif; -webkit-print-color-adjust: exact !important; print-color-adjust: exact !important; color-adjust: exact !important; } #qrcode { width: 60px; height: 60px; display: block; margin: 0, 15px body { font-family: "Microsoft YaHei", "SimHei", Arial, sans-serif; background: white !important; margin: 0 !important; padding: 0 !important; width: 80mm !important; } .qrcode { width: 15mm !important; height: 15mm !important; display: block; } .qrcode canvas { width: 15mm !important; height: 15mm !important; image-rendering: -webkit-optimize-contrast; image-rendering: crisp-edges; } @media print { @page { size: 80mm 60mm; margin: 0; padding: 0; size: 80mm 60mm !important; margin: 0 !important; padding: 0 !important; } body { width: 80mm !important; height: 60mm !important; margin: 0 !important; padding: 0 !important; width: 80mm !important; background: white !important; } @@ -241,44 +248,52 @@ width: 80mm !important; height: 60mm !important; page-break-after: always !important; break-after: page !important; margin: 0 !important; padding: 2mm !important; display: block !important; } .print-page:last-child { page-break-after: auto !important; } .material-card { width: 80mm !important; height: 56mm !important; border: 0.3mm solid #000 !important; padding: 1mm !important; box-sizing: border-box !important; position: relative !important; display: block !important; background: white !important; } .print-page:last-child { page-break-after: avoid !important; } .material-card { width: 78mm !important; height: 58mm !important; border: 0.5mm solid #000 !important; padding: 1.5mm !important; box-sizing: border-box !important; position: relative !important; background: white !important; font-family: "Microsoft YaHei", "SimHei", Arial, sans-serif !important; } .header-section { display: flex !important; justify-content: space-between !important; align-items: center !important; margin-bottom: 1.5mm !important; padding-bottom: 1mm !important; border-bottom: 0.3mm solid #000 !important; } .header { font-size: 3.5mm !important; font-size: 4mm !important; font-weight: bold !important; text-align: center !important; margin-bottom: 1mm !important; padding-bottom: 0.5mm !important; border-bottom: 0.2mm solid #000 !important; white-space: nowrap !important; } .content { height: calc(100% - 6mm) !important; height: calc(100% - 10mm) !important; position: relative !important; } .row { display: flex !important; margin-bottom: 0.8mm !important; min-height: 6mm !important; margin-bottom: 1.2mm !important; min-height: 6.5mm !important; align-items: stretch !important; } .dual-column { @@ -290,101 +305,44 @@ flex: 1 !important; display: flex !important; align-items: center !important; min-height: 5mm !important; } .column:first-child { margin-right: 2mm !important; margin-right: 2.5mm !important; } .label { font-weight: bold !important; flex: 0 0 15mm !important; flex: 0 0 8mm !important; white-space: nowrap !important; font-size: 2.2mm !important; font-size: 2.5mm !important; line-height: 1.3 !important; } .value { flex: 1 !important; overflow: hidden !important; text-overflow: ellipsis !important; white-space: nowrap !important; border-bottom: 0.1mm dashed #666 !important; padding-bottom: 0.2mm !important; min-height: 2.5mm !important; font-size: 2.2mm !important; white-space: normal !important; word-break: break-all !important; word-wrap: break-word !important; min-height: 4mm !important; font-size: 2.5mm !important; line-height: 1.3 !important; border-bottom: none !important; padding: 0.5mm !important; } .full-width { display: block !important; white-space: normal !important; word-break: break-all !important; word-wrap: break-word !important; line-height: 1.3 !important; } .code-value { font-weight: bold !important; } .full-width { white-space: normal !important; word-break: break-all !important; line-height: 1.2 !important; } /* äºç»´ç æ ·å¼ */ .qr-section { width: 10mm !important; height: 12mm !important; font-siz:10px; } .qr-section canvas { width: 10mm !important; height: 10mm !important; max-width: 100% !important; max-height: 100% !important; } } /* å±å¹é¢è§æ ·å¼ */ @media screen { body { background: #f5f5f5; padding: 10px; display: flex; flex-direction: column; align-items: center; } .print-page { width: 80mm; height: 60mm; margin: 10px 0; padding: 2mm; background: white; box-shadow: 0 2px 10px rgba(0,0,0,0.1); border: 1px dashed #ccc; } .material-card { width: 80mm; height: 60mm; border: 0.3mm solid #000; padding: 1.5mm; background: white; position: relative; } .qr-section { position: absolute; top: 4mm; right: 2mm; width: 12mm; height: 12mm; border: 0.2mm solid #ccc; padding: 0.5mm; background: white; display: flex; align-items: center; justify-content: center; } .qr-section canvas { width: 10mm !important; height: 10mm !important; } } </style> @@ -393,196 +351,181 @@ ${printContent} <script> window.onload = function() { console.log('æå°é¡µé¢å è½½å®æï¼å ±${this.printData.length}ä¸ªç©æå¡'); // çå¾ äºç»´ç 渲æå®æ setTimeout(() => { // 强å¶è®¾ç½®äºç»´ç canvas尺寸 const canvases = document.querySelectorAll('canvas'); canvases.forEach(canvas => { canvas.style.width = '10mm !important'; canvas.style.height = '10mm !important'; canvas.setAttribute('width', '60'); canvas.setAttribute('height', '60'); canvas.style.width = '15mm'; canvas.style.height = '15mm'; }); window.print(); setTimeout(() => { window.close(); }, 500); }, 800); }; window.onafterprint = function() { setTimeout(() => { window.close(); }, 500); }; <\/script> </body> </html> `); `) printWindow.document.close(); } catch (error) { console.error('æå°é误:', error); this.$message.error('æå°å¤±è´¥: ' + error.message); printWindow.document.close() } catch (error) { console.error('æå°é误:', error) this.$message.error('æå°å¤±è´¥: ' + error.message) } }) } }); } } }; } </script> <style scoped> #qrcode { width: 60px; height: 60px; display: block; margin: 0, 15px .qrcode { width: 60px; height: 60px; display: block; } .qrcode-preview { width: 40px; height: 40px; display: block; } .preview-container { max-height: 500px; overflow: hidden; display: flex; flex-direction: column; max-height: 500px; overflow: hidden; display: flex; flex-direction: column; } .preview-header { text-align: center; font-size: 16px; font-weight: bold; margin-bottom: 10px; padding: 8px; background: #f0f0f0; border-radius: 4px; text-align: center; font-size: 16px; font-weight: bold; margin-bottom: 10px; padding: 8px; background: #f0f0f0; border-radius: 4px; } .preview-scroll { max-height: 400px; overflow-y: auto; padding: 10px; border: 1px solid #e0e0e0; border-radius: 4px; background: #f9f9f9; max-height: 400px; overflow-y: auto; padding: 10px; border: 1px solid #e0e0e0; border-radius: 4px; background: #f9f9f9; } .preview-card { width: 320px; height: 240px; margin: 0 auto 15px auto; padding: 8px; border: 1px solid #ccc; font-family: SimSun; box-sizing: border-box; border: 2px solid #000; background: white; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); position: relative; width: 320px; height: 240px; margin: 0 auto 15px auto; padding: 8px; border: 2px solid #000; font-family: 'Microsoft YaHei', sans-serif; box-sizing: border-box; background: white; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); position: relative; } .preview-card:last-child { margin-bottom: 0; margin-bottom: 0; } .preview-card-header { text-align: center; font-size: 14px; /* font-weight: bold; margin-bottom: 8px; padding-bottom: 4px; border-bottom: 1px solid #000; background: #f5f5f5; padding: 4px; */ height: 60px; width: 60px; font-size: 14px; font-weight: bold; white-space: nowrap; } .preview-wrapper { position: relative; height: calc(100% - 40px); position: relative; height: calc(100% - 30px); } .content-preview { width: 100%; height: 100%; width: 100%; height: 100%; } .row-preview { /* margin-bottom: px; */ min-height: 32px; margin-bottom: 6px; min-height: 24px; display: flex; align-items: center; } .dual-column { display: flex; justify-content: space-between; display: flex; justify-content: space-between; } .column-preview { flex: 1; display: flex; align-items: center; flex: 1; display: flex; align-items: center; min-height: 22px; } .column-preview:first-child { margin-right: 10px; margin-right: 8px; } .label-preview { font-weight: bold; flex: 0 0 60px; white-space: nowrap; font-size: 12px; font-weight: bold; flex: 0 0 30px; white-space: nowrap; font-size: 12px; line-height: 1.2; } .value-preview { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; border-bottom: 1px dashed #666; padding-bottom: 2px; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 10px; padding-bottom: 2px; line-height: 1.2; font-weight: normal; } .code-value { font-weight: bold; font-weight: bold; } .full-width { display: block; margin-top: 2px; white-space: normal; word-break: break-all; line-height: 1.2; font-size: 12px; display: block; white-space: normal; word-break: break-all !important; line-height: 1.2; font-size: 11px; min-height: auto; word-wrap: break-word !important; } /* é¢è§åºåäºç»´ç æ ·å¼ */ .qr-section-preview { position: absolute; top: 10px; right: 10px; width: 150px; height: 175px; display: flex; align-items: center; justify-content: center; border: 1px solid #ddd; background: white; padding: 2px; } .qr-section-preview canvas { width: 56px !important; height: 56px !important; .preview-card-header-qrcode { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 8px; border-bottom: 2px solid #000; padding-bottom: 4px; } .footer-actions { display: flex; justify-content: space-between; align-items: center; width: 100%; display: flex; justify-content: space-between; align-items: center; width: 100%; } .print-count { font-size: 14px; color: #409EFF; font-weight: bold; font-size: 14px; color: #409eff; font-weight: bold; } </style> </style> ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/outbound/extend/printView1.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,588 @@ <template> <div> <vol-box v-model="showDetialBox" :lazy="true" width="500px" :padding="15" title=""> <!-- æå°ä¸ç¨å®¹å¨ --> <div id="printContainer" style="position: absolute; left: -9999px;"> <div class="print-page" v-for="(item, index) in printData" :key="index"> <div class="material-card"> <!-- <div class="header">ååè½ç©ææ è¯å¡(å°å )</div> --> <div class="dual-column preview-card-header-qrcode"> <div class="preview-card-header">ç©æå¡ {{ idx + 1 }}</div> <VueQrcode :value="generateQr(item)" :size="20" id="qrcode" /> </div> <div class="content"> <!-- äºç»´ç æ¾å¨å³ä¸è§ --> <!-- <div class="qr-section"> --> <!-- <VueQrcode :value="generateQr(item)" id="qrcode" /> --> <!-- </div> --> <div class="row dual-column"> <div class="column"> <span class="label">æå·</span> <span class="value code-value">{{ item.materialCode }}</span> </div> <div class="column"> <span class="label">ä¾åºåç¼ç </span> <span class="value">{{ item.supplierCode }}</span> </div> </div> <div class="row dual-column"> <div class="column"> <span class="label">åå</span> <span class="value">{{ item.materialName }}</span> </div> <div class="column"> <span class="label">éè´åå·</span> <span class="value">{{ item.purchaseOrderNo }}</span> </div> </div> <div class="row dual-column"> <div class="column"> <span class="label">è§æ ¼</span> <span class="value full-width">{{ item.specification }}</span> </div> <div class="column"> <span class="label">æ°é/æ»æ°</span> <span class="value">{{ item.quantityTotal }}</span> </div> </div> <div class="row dual-column"> <div class="column"> <span class="label">æ¹å·</span> <span class="value">{{ item.batchNumber }}</span> </div> <div class="column"> <span class="label">æ¹æ¬¡</span> <span class="value">{{ item.batch }}</span> </div> </div> <div class="row dual-column"> <div class="column"> <span class="label">ååº</span> <span class="value">{{ item.factory }}</span> </div> <div class="column"> <span class="label">æ¥æ</span> <span class="value">{{ item.date }}</span> </div> </div> </div> </div> </div> </div> <!-- é¢è§åºå --> <div id="previewContent" class="preview-container"> <div class="preview-header">ååè½ç©ææ è¯å¡(å°å ) - é¢è§ (å ±{{ printData.length }}个)</div> <div class="preview-scroll"> <div v-for="(item, idx) in printData" :key="idx" class="preview-card"> <div class="dual-column preview-card-header-qrcode"> <div class="preview-card-header">ç©æå¡ {{ idx + 1 }}</div> <VueQrcode :value="generateQr(item)" :size="20" id="qrcode" /> </div> <div class="preview-wrapper"> <div class="content-preview"> <div class="row-preview dual-column"> <div class="column-preview"> <span class="label-preview">æå·</span> <span class="value-preview code-value">{{ item.materialCode }}</span> </div> <div class="column-preview"> <span class="label-preview">ä¾åºåç¼ç </span> <span class="value-preview">{{ item.supplierCode }}</span> </div> </div> <div class="row-preview dual-column"> <div class="column-preview"> <span class="label-preview">åå</span> <span class="value-preview">{{ item.materialName }}</span> </div> <div class="column-preview"> <span class="label-preview">éè´åå·</span> <span class="value-preview">{{ item.purchaseOrderNo }}</span> </div> </div> <div class="row-preview dual-column"> <div class="column-preview"> <span class="label-preview">è§æ ¼</span> <span class="value-preview full-width">{{ item.specification }}</span> </div> <div class="column-preview"> <span class="label-preview">æ°é/æ»æ°</span> <span class="value-preview">{{ item.quantityTotal }}</span> </div> </div> <div class="row-preview dual-column"> <div class="column-preview"> <span class="label-preview">æ¹å·</span> <span class="value-preview">{{ item.batchNumber }}</span> </div> <div class="column-preview"> <span class="label-preview">æ¹æ¬¡</span> <span class="value-preview">{{ item.batch }}</span> </div> </div> <div class="row-preview dual-column"> <div class="column-preview"> <span class="label-preview">ååº</span> <span class="value-preview">{{ item.factory }}</span> </div> <div class="column-preview"> <span class="label-preview">æ¥æ</span> <span class="value-preview">{{ item.date }}</span> </div> </div> </div> </div> </div> </div> </div> <template #footer> <div class="footer-actions"> <span class="print-count">å ± {{ printData.length }} ä¸ªç©æå¡å¾ æå°</span> <div> <el-button type="primary" size="small" @click="print">æå°å ¨é¨</el-button> <el-button type="danger" size="small" @click="showDetialBox = false">å ³é</el-button> </div> </div> </template> </vol-box> </div> </template> <script> import VolBox from "@/components/basic/VolBox.vue"; import VueQrcode from "vue-qrcode"; export default { components: { VolBox, VueQrcode }, data() { return { showDetialBox: false, printData: [], // å卿尿°æ®éå }; }, methods: { generateQr(item) { return `${item.batchNumber}`; }, open(rows) { this.showDetialBox = true; this.printData = Array.isArray(rows) ? rows : [rows]; console.log('æå°æ°æ®:', this.printData); }, async print() { if (this.printData.length === 0) { this.$message.warning('没æå¯æå°çæ°æ®'); return; } this.$nextTick(() => { try { const printContent = document.getElementById("printContainer").innerHTML; const printWindow = window.open("", "_blank", "width=800,height=600,scrollbars=yes"); if (!printWindow) { this.$message.error('æ æ³æå¼æå°çªå£ï¼è¯·æ£æ¥æµè§å¨å¼¹çªè®¾ç½®'); return; } printWindow.document.write(` <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>ç©ææ è¯å¡æå° - å ±${this.printData.length}个</title> <style> /* éç½®æææ ·å¼ */ * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: SimSun, "å®ä½", sans-serif; -webkit-print-color-adjust: exact !important; print-color-adjust: exact !important; color-adjust: exact !important; } #qrcode { width: 60px; height: 60px; display: block; margin: 0, 15px } @media print { @page { size: 80mm 60mm; margin: 0; padding: 0; } body { margin: 0 !important; padding: 0 !important; width: 80mm !important; background: white !important; } .print-page { width: 80mm !important; height: 60mm !important; page-break-after: always !important; break-after: page !important; margin: 0 !important; padding: 2mm !important; display: block !important; } .print-page:last-child { page-break-after: auto !important; } .material-card { width: 80mm !important; height: 56mm !important; border: 0.3mm solid #000 !important; padding: 1mm !important; box-sizing: border-box !important; position: relative !important; background: white !important; } .header { font-size: 3.5mm !important; font-weight: bold !important; text-align: center !important; margin-bottom: 1mm !important; padding-bottom: 0.5mm !important; border-bottom: 0.2mm solid #000 !important; } .content { height: calc(100% - 6mm) !important; position: relative !important; } .row { display: flex !important; margin-bottom: 0.8mm !important; min-height: 6mm !important; } .dual-column { display: flex !important; justify-content: space-between !important; } .column { flex: 1 !important; display: flex !important; align-items: center !important; } .column:first-child { margin-right: 2mm !important; } .label { font-weight: bold !important; flex: 0 0 15mm !important; white-space: nowrap !important; font-size: 2.2mm !important; } .value { flex: 1 !important; overflow: hidden !important; text-overflow: ellipsis !important; white-space: nowrap !important; border-bottom: 0.1mm dashed #666 !important; padding-bottom: 0.2mm !important; min-height: 2.5mm !important; font-size: 2.2mm !important; } .code-value { font-weight: bold !important; } .full-width { white-space: normal !important; word-break: break-all !important; line-height: 1.2 !important; } /* äºç»´ç æ ·å¼ */ .qr-section { width: 10mm !important; height: 12mm !important; font-siz:10px; } .qr-section canvas { width: 10mm !important; height: 10mm !important; max-width: 100% !important; max-height: 100% !important; } } /* å±å¹é¢è§æ ·å¼ */ @media screen { body { background: #f5f5f5; padding: 10px; display: flex; flex-direction: column; align-items: center; } .print-page { width: 80mm; height: 60mm; margin: 10px 0; padding: 2mm; background: white; box-shadow: 0 2px 10px rgba(0,0,0,0.1); border: 1px dashed #ccc; } .material-card { width: 80mm; height: 60mm; border: 0.3mm solid #000; padding: 1.5mm; background: white; position: relative; } .qr-section { position: absolute; top: 4mm; right: 2mm; width: 12mm; height: 12mm; border: 0.2mm solid #ccc; padding: 0.5mm; background: white; display: flex; align-items: center; justify-content: center; } .qr-section canvas { width: 10mm !important; height: 10mm !important; } } </style> </head> <body> ${printContent} <script> window.onload = function() { console.log('æå°é¡µé¢å è½½å®æï¼å ±${this.printData.length}ä¸ªç©æå¡'); // çå¾ äºç»´ç 渲æå®æ setTimeout(() => { // 强å¶è®¾ç½®äºç»´ç canvas尺寸 const canvases = document.querySelectorAll('canvas'); canvases.forEach(canvas => { canvas.style.width = '10mm !important'; canvas.style.height = '10mm !important'; }); window.print(); }, 800); }; window.onafterprint = function() { setTimeout(() => { window.close(); }, 500); }; <\/script> </body> </html> `); printWindow.document.close(); } catch (error) { console.error('æå°é误:', error); this.$message.error('æå°å¤±è´¥: ' + error.message); } }); } } }; </script> <style scoped> #qrcode { width: 60px; height: 60px; display: block; margin: 0, 15px } .preview-container { max-height: 500px; overflow: hidden; display: flex; flex-direction: column; } .preview-header { text-align: center; font-size: 16px; font-weight: bold; margin-bottom: 10px; padding: 8px; background: #f0f0f0; border-radius: 4px; } .preview-scroll { max-height: 400px; overflow-y: auto; padding: 10px; border: 1px solid #e0e0e0; border-radius: 4px; background: #f9f9f9; } .preview-card { width: 320px; height: 240px; margin: 0 auto 15px auto; padding: 8px; border: 1px solid #ccc; font-family: SimSun; box-sizing: border-box; border: 2px solid #000; background: white; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); position: relative; } .preview-card:last-child { margin-bottom: 0; } .preview-card-header { text-align: center; font-size: 14px; /* font-weight: bold; margin-bottom: 8px; padding-bottom: 4px; border-bottom: 1px solid #000; background: #f5f5f5; padding: 4px; */ height: 60px; width: 60px; } .preview-wrapper { position: relative; height: calc(100% - 40px); } .content-preview { width: 100%; height: 100%; } .row-preview { /* margin-bottom: px; */ min-height: 32px; } .dual-column { display: flex; justify-content: space-between; } .column-preview { flex: 1; display: flex; align-items: center; } .column-preview:first-child { margin-right: 10px; } .label-preview { font-weight: bold; flex: 0 0 60px; white-space: nowrap; font-size: 12px; } .value-preview { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; border-bottom: 1px dashed #666; padding-bottom: 2px; } .code-value { font-weight: bold; } .full-width { display: block; margin-top: 2px; white-space: normal; word-break: break-all; line-height: 1.2; font-size: 12px; } /* é¢è§åºåäºç»´ç æ ·å¼ */ .qr-section-preview { position: absolute; top: 10px; right: 10px; width: 150px; height: 175px; display: flex; align-items: center; justify-content: center; border: 1px solid #ddd; background: white; padding: 2px; } .qr-section-preview canvas { width: 56px !important; height: 56px !important; } .footer-actions { display: flex; justify-content: space-between; align-items: center; width: 100%; } .print-count { font-size: 14px; color: #409EFF; font-weight: bold; } </style> ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.878.3237/CodeChunks.db-shmBinary files differ
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.878.3237/SemanticSymbols.db-shmBinary files differ
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_BasicService/InvokeMESService.cs
@@ -14,6 +14,7 @@ using WIDESEA_Common.StockEnum; using WIDESEA_Core; using WIDESEA_Core.BaseRepository; using WIDESEA_Core.Helper; using WIDESEA_DTO.Allocate; using WIDESEA_DTO.Basic; using WIDESEA_DTO.Inbound; @@ -115,9 +116,11 @@ public async Task<ResponseModel> FeedbackAllocate(AllocateDto model) { _logger.LogInformation($"InvokeMESService FeedbackAllocate åºååå: {JsonConvert.SerializeObject(model)}"); string json = JsonConvert.SerializeObject(model, new JsonSerializerSettings { ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver() ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver(), NullValueHandling = NullValueHandling.Include }); var content = new StringContent(json, Encoding.UTF8, "application/json"); var _client = _httpClientFactory.CreateClient("MESUrl"); @@ -246,42 +249,89 @@ var inboundOrder = _inboundOrderRepository.Db.Queryable<Dt_InboundOrder>().First(x => x.InboundOrderNo == lists.FirstOrDefault().OrderNo); if (inboundOrder != null) { var feedmodel = new FeedbackInboundRequestModel if (inboundOrder.OrderType == (int)InOrderTypeEnum.AllocatInbound)//è°æ¨å ¥åº { reqCode = Guid.NewGuid().ToString(), reqTime = DateTime.Now.ToString(), business_type = inboundOrder.BusinessType, factoryArea = inboundOrder.FactoryArea, operationType = 1, Operator = inboundOrder.Operator, orderNo = inboundOrder.UpperOrderNo, status = inboundOrder.OrderStatus, details = new List<FeedbackInboundDetailsModel>() var allocate = SqlSugarHelper.DbWMS.Queryable<Dt_AllocateOrder>().Where(x => x.OrderNo == inboundOrder.InboundOrderNo).First(); var allocatefeedmodel = new AllocateDto { ReqCode = Guid.NewGuid().ToString(), ReqTime = DateTime.Now.ToString(), BusinessType = "2", FactoryArea = inboundOrder.FactoryArea, OperationType = 1, Operator = inboundOrder.Operator, OrderNo = inboundOrder.UpperOrderNo, fromWarehouse = allocate?.FromWarehouse ?? "", toWarehouse = allocate?.ToWarehouse ?? "", Details = new List<AllocateDtoDetail>() }; }; var groupedData = lists.GroupBy(item => new { item.MaterielCode, item.SupplyCode, item.BatchNo, item.InboundOrderRowNo, item.BarcodeUnit, item.WarehouseCode }) .Select(group => new FeedbackInboundDetailsModel { materialCode = group.Key.MaterielCode, supplyCode = group.Key.SupplyCode, batchNo = group.Key.BatchNo, lineNo = group.Key.InboundOrderRowNo, qty = group.Sum(x => x.BarcodeQty), // warehouseCode = group.Key.WarehouseCode=="0"?"1072": group.Key.WarehouseCode, warehouseCode = group.Key.WarehouseCode, unit = group.Key.BarcodeUnit, barcodes = group.Select(row => new FeedbackBarcodesModel var groupedData = lists.GroupBy(item => new { item.MaterielCode, item.SupplyCode, item.BatchNo, item.InboundOrderRowNo, item.BarcodeUnit, item.WarehouseCode }) .Select(group => new AllocateDtoDetail { barcode = row.Barcode, qty = row.BarcodeQty }).ToList() }).ToList(); feedmodel.details = groupedData; var result = await FeedbackInbound(feedmodel); if (result != null && result.code == 200) MaterialCode = group.Key.MaterielCode, LineNo = group.Key.InboundOrderRowNo, WarehouseCode = group.Key.WarehouseCode, Qty = group.Sum(x => x.BarcodeQty), // warehouseCode= "1072", Unit = group.Key.BarcodeUnit, Barcodes = group.Select(row => new BarcodeInfo { Barcode = row.Barcode, Qty = row.BarcodeQty, BatchNo = row.BatchNo, SupplyCode = row.SupplyCode, Unit = row.Unit }).ToList() }).ToList(); allocatefeedmodel.Details = groupedData; var result = await FeedbackAllocate(allocatefeedmodel); if (result != null && result.code == 200) { _feedbacktomesRepository.Db.Insertable(new Dt_FeedbackToMes { OrderNo = orderNo, PalletCode = item.PalletCode, ReportStatus = 1 }).ExecuteCommand(); } } else { _feedbacktomesRepository.Db.Insertable(new Dt_FeedbackToMes { OrderNo = orderNo, PalletCode = item.PalletCode, ReportStatus = 1 }).ExecuteCommand(); var feedmodel = new FeedbackInboundRequestModel { reqCode = Guid.NewGuid().ToString(), reqTime = DateTime.Now.ToString(), business_type = inboundOrder.BusinessType, factoryArea = inboundOrder.FactoryArea, operationType = 1, Operator = inboundOrder.Operator, orderNo = inboundOrder.UpperOrderNo, status = inboundOrder.OrderStatus, details = new List<FeedbackInboundDetailsModel>() }; var groupedData = lists.GroupBy(item => new { item.MaterielCode, item.SupplyCode, item.BatchNo, item.InboundOrderRowNo, item.BarcodeUnit, item.WarehouseCode }) .Select(group => new FeedbackInboundDetailsModel { materialCode = group.Key.MaterielCode, supplyCode = group.Key.SupplyCode, batchNo = group.Key.BatchNo, lineNo = group.Key.InboundOrderRowNo, qty = group.Sum(x => x.BarcodeQty), // warehouseCode = group.Key.WarehouseCode=="0"?"1072": group.Key.WarehouseCode, warehouseCode = group.Key.WarehouseCode, unit = group.Key.BarcodeUnit, barcodes = group.Select(row => new FeedbackBarcodesModel { barcode = row.Barcode, qty = row.BarcodeQty }).ToList() }).ToList(); feedmodel.details = groupedData; var result = await FeedbackInbound(feedmodel); if (result != null && result.code == 200) { _feedbacktomesRepository.Db.Insertable(new Dt_FeedbackToMes { OrderNo = orderNo, PalletCode = item.PalletCode, ReportStatus = 1 }).ExecuteCommand(); } } } } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_DTO/Allocate/AllocateDto.cs
@@ -39,8 +39,10 @@ [JsonProperty("business_type")] public string BusinessType { get; set; } [JsonProperty("fromWarehouse")] public string fromWarehouse { get; set; } [JsonProperty("toWarehouse")] public string toWarehouse { get; set; } /// <summary> ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_DTO/Outbound/BatchOutBoundDto.cs
@@ -186,6 +186,8 @@ public decimal SplitQuantity { get; set; } public string Operator { get; set; } public bool IsReverted { get; set; } public bool IsAutoSplit { get; set; } } #endregion ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Model/Models/Outbound/Dt_OutboundOrderDetail.cs
@@ -148,7 +148,7 @@ public decimal AllocatedQuantity { get; set; } public string BatchAllocateStatus { get; set; } public int BatchAllocateStatus { get; set; } /// <summary> /// èæåºå ¥åºæ°é ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Model/Models/Outbound/Dt_PickingRecord.cs
@@ -133,6 +133,8 @@ public string PalletCode { get; set; } public int StockId { get; set; } public bool IsReverted { get; set; } = false; public bool IsAutoSplit { get; set; } = false; public int OutStockLockInfoId { get; set; } // å ³èçåºåºéå®ä¿¡æ¯ public string OriginalBarcode { get; set; } // åæ¡ç public string NewBarcode { get; set; } // æ°æ¡ç ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundBatchPickingService.cs
@@ -1,5 +1,6 @@ using Microsoft.Extensions.Logging; using SqlSugar; using SqlSugar.Extensions; using System; using System.Collections.Generic; using System.Linq; @@ -267,7 +268,7 @@ await UpdateOrderStatusAfterPalletRemoval(orderNo); // è®°å½æä½åå² await RecordEmptyPalletRemoval(orderNo, palletCode, completedLocks); // await RecordEmptyPalletRemoval(orderNo, palletCode, completedLocks); _unitOfWorkManage.CommitTran(); @@ -411,32 +412,68 @@ { _unitOfWorkManage.BeginTran(); // 1. éªè¯åæ£è¯·æ± // éªè¯åæ£è¯·æ± var validationResult = await ValidatePickingRequest(orderNo, palletCode, barcode); if (!validationResult.IsValid) return WebResponseContent.Instance.Error(validationResult.ErrorMessage); var (lockInfo, orderDetail, stockDetail, batch) = validationResult.Data; // 使ç¨éå®ä¿¡æ¯çåé æ°éä½ä¸ºå®é 忣æ°é var actualPickedQty = lockInfo.AssignQuantity; // æ£æ¥æ¯å¦éè¦èªå¨æå var autoSplitResult = await CheckAndAutoSplitIfNeeded(lockInfo, stockDetail, palletCode); if (autoSplitResult != null) { // 妿æ§è¡äºèªå¨æå ï¼éæ°è·åææ°çéå®ä¿¡æ¯ååºåä¿¡æ¯ var refreshedValidation = await ValidatePickingRequest(orderNo, palletCode, barcode); if (!refreshedValidation.IsValid) { _unitOfWorkManage.RollbackTran(); return WebResponseContent.Instance.Error(refreshedValidation.ErrorMessage); } // 2. æ§è¡åæ£é»è¾ var pickingResult = await ExecutePickingLogic(lockInfo, orderDetail, stockDetail, actualPickedQty); (lockInfo, orderDetail, stockDetail, batch) = refreshedValidation.Data; // 3. æ´æ°æ¹æ¬¡åè®¢åæ°æ® await UpdateBatchAndOrderData(batch, orderDetail, actualPickedQty, orderNo); // éè¦ä¿®å¤ï¼èªå¨æå åï¼ç«å³æ§è¡åæ¡ç ç忣 var actualPickedQty = lockInfo.AssignQuantity; var pickingResult = await ExecutePickingLogic(lockInfo, orderDetail, stockDetail, actualPickedQty); // 4. è®°å½æ£éåå² await RecordPickingHistory(pickingResult, orderNo, palletCode); // æ´æ°æ¹æ¬¡åè®¢åæ°æ® await UpdateBatchAndOrderData(batch, orderDetail, actualPickedQty, orderNo); // è®°å½æ£éåå² await RecordPickingHistory(pickingResult, orderNo, palletCode); _unitOfWorkManage.CommitTran(); return WebResponseContent.Instance.OK("èªå¨æå 并忣æå", new { AutoSplitted = true, NewBarcode = autoSplitResult.NewBarcode, OriginalBarcode = barcode, SplitQuantity = autoSplitResult.SplitQuantity, PickedQuantity = actualPickedQty, MaterialCode = lockInfo.MaterielCode }); } // æ£å¸¸åæ£æµç¨ï¼ä¸éè¦èªå¨æå ï¼ var normalPickedQty = lockInfo.AssignQuantity; var normalPickingResult = await ExecutePickingLogic(lockInfo, orderDetail, stockDetail, normalPickedQty); // æ´æ°æ¹æ¬¡åè®¢åæ°æ® await UpdateBatchAndOrderData(batch, orderDetail, normalPickedQty, orderNo); // è®°å½æ£éåå² await RecordPickingHistory(normalPickingResult, orderNo, palletCode); _unitOfWorkManage.CommitTran(); return WebResponseContent.Instance.OK("忣æå", new { PickedQuantity = actualPickedQty, PickedQuantity = normalPickedQty, Barcode = barcode, MaterialCode = lockInfo.MaterielCode MaterialCode = lockInfo.MaterielCode, AutoSplitted = false }); } catch (Exception ex) @@ -494,6 +531,8 @@ #region æå¨æå #region æå¨æå ç¸å ³æ¹æ³ /// <summary> /// æå¨æå /// </summary> @@ -503,15 +542,15 @@ { _unitOfWorkManage.BeginTran(); // éªè¯æå è¯·æ± // éªè¯æå è¯·æ± var validationResult = await ValidateSplitRequest(orderNo, palletCode, originalBarcode, splitQuantity); if (!validationResult.IsValid) return WebResponseContent.Instance.Error(validationResult.ErrorMessage); var (lockInfo, stockDetail) = validationResult.Data; // . æ§è¡æå é»è¾ var splitResult = await ExecuteSplitLogic(lockInfo, stockDetail, splitQuantity, palletCode); // æ§è¡æå é»è¾ var splitResult = await ExecuteManualSplitLogic(lockInfo, stockDetail, splitQuantity, palletCode); _unitOfWorkManage.CommitTran(); @@ -530,9 +569,224 @@ } } /// <summary> /// éªè¯æå è¯·æ± - å¢å¼ºåé æ°éæ§å¶ /// </summary> private async Task<ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>> ValidateSplitRequest( string orderNo, string palletCode, string originalBarcode, decimal splitQuantity) { _logger.LogInformation($"å¼å§éªè¯æå è¯·æ± - 订å: {orderNo}, æç: {palletCode}, åæ¡ç : {originalBarcode}, æå æ°é: {splitQuantity}"); // æ¥æ¾éå®ä¿¡æ¯ var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode && x.CurrentBarcode == originalBarcode && x.Status == (int)OutLockStockStatusEnum.åºåºä¸) .FirstAsync(); if (lockInfo == null) { _logger.LogWarning($"æªæ¾å°ææçéå®ä¿¡æ¯ - 订å: {orderNo}, æç: {palletCode}, æ¡ç : {originalBarcode}"); return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("æªæ¾å°ææçéå®ä¿¡æ¯"); } _logger.LogInformation($"æ¾å°éå®ä¿¡æ¯ - åé æ°é: {lockInfo.AssignQuantity}, å·²æ£é: {lockInfo.PickedQty}, è®¢åæ°é: {lockInfo.OrderQuantity}"); // è·å订åæç» var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() .FirstAsync(x => x.Id == lockInfo.OrderDetailId); if (orderDetail == null) { _logger.LogWarning($"æªæ¾å°è®¢åæç» - OrderDetailId: {lockInfo.OrderDetailId}"); return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("æªæ¾å°è®¢åæç»"); } _logger.LogInformation($"æ¾å°è®¢åæç» - å·²åé æ°é: {orderDetail.AllocatedQuantity}, é宿°é: {orderDetail.LockQuantity}"); // è·ååºåä¿¡æ¯ var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() .FirstAsync(x => x.Barcode == originalBarcode && x.StockId == lockInfo.StockId); if (stockDetail == null) { _logger.LogWarning($"æªæ¾å°åºåä¿¡æ¯ - æ¡ç : {originalBarcode}, StockId: {lockInfo.StockId}"); return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("æªæ¾å°å¯¹åºçåºåä¿¡æ¯"); } _logger.LogInformation($"æ¾å°åºåä¿¡æ¯ - åºåæ°é: {stockDetail.StockQuantity}, åºåºæ°é: {stockDetail.OutboundQuantity}"); // éè¦ä¿®å¤ï¼éªè¯æå æ°éä¸è½å¤§äºåºåæ°é if (stockDetail.StockQuantity < splitQuantity) { _logger.LogWarning($"æå æ°é大äºåºåæ°é - æå æ°é: {splitQuantity}, åºåæ°é: {stockDetail.StockQuantity}"); return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error($"æå æ°éä¸è½å¤§äºåºåæ°éï¼å½ååºåï¼{stockDetail.StockQuantity}"); } // éè¦ä¿®å¤ï¼éªè¯æå æ°éä¸è½å¤§äºéå®ä¿¡æ¯çåé æ°é if (lockInfo.AssignQuantity < splitQuantity) { _logger.LogWarning($"æå æ°é大äºåé æ°é - æå æ°é: {splitQuantity}, åé æ°é: {lockInfo.AssignQuantity}"); return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error($"æå æ°éä¸è½å¤§äºåé æ°éï¼å½ååé æ°éï¼{lockInfo.AssignQuantity}"); } // éè¦ä¿®å¤ï¼éªè¯æå æ°éä¸è½å¤§äºéå®ä¿¡æ¯çæªæ£éæ°é decimal remainingToPick = lockInfo.AssignQuantity - lockInfo.PickedQty; if (remainingToPick < splitQuantity) { _logger.LogWarning($"æå æ°éå¤§äºæªæ£éæ°é - æå æ°é: {splitQuantity}, æªæ£éæ°é: {remainingToPick}"); return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error($"æå æ°éä¸è½å¤§äºæªæ£éæ°éï¼å½åæªæ£éï¼{remainingToPick}"); } // éè¦ä¿®å¤ï¼éªè¯æå ååéå®ä¿¡æ¯çåé æ°éä¸ä¼ä¸ºè´æ° if (lockInfo.AssignQuantity - splitQuantity < 0) { _logger.LogWarning($"æå ååé æ°éä¸ºè´æ° - å½ååé æ°é: {lockInfo.AssignQuantity}, æå æ°é: {splitQuantity}"); return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error($"æå ååé æ°éä¸è½ä¸ºè´æ°"); } // éè¦ä¿®å¤ï¼éªè¯è®¢åæç»çåé æ°éæ¯å¦è¶³å¤ // 注æï¼æå¨æå ä¸ä¼æ¹å订åæç»çåé æ°éï¼å 为æ»åé æ°éä¸å // åªæ¯ä»ä¸ä¸ªéå®ä¿¡æ¯è½¬ç§»å°å¦ä¸ä¸ªéå®ä¿¡æ¯ decimal totalLockAssignQuantity = await GetTotalLockAssignQuantity(orderDetail.Id); if (orderDetail.AllocatedQuantity != totalLockAssignQuantity) { _logger.LogWarning($"订åæç»åé æ°éä¸éå®ä¿¡æ¯ä¸ä¸è´ - 订åæç»åé æ°é: {orderDetail.AllocatedQuantity}, éå®ä¿¡æ¯æ»åé æ°é: {totalLockAssignQuantity}"); // è¿éä¸ç´æ¥è¿åé误ï¼å 为æå æä½æ¬èº«ä¸ä¼å¯¼è´ä¸ä¸è´ï¼åªæ¯è®°å½è¦å } _logger.LogInformation($"æå éªè¯éè¿ - åæ¡ç : {originalBarcode}, æå æ°é: {splitQuantity}"); return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Success((lockInfo, stockDetail)); } /// <summary> /// è·å订åæç»çææéå®ä¿¡æ¯çæ»åé æ°é /// </summary> private async Task<decimal> GetTotalLockAssignQuantity(long orderDetailId) { var lockInfos = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() .Where(x => x.OrderDetailId == orderDetailId) .ToListAsync(); return lockInfos.Sum(x => x.AssignQuantity); } /// <summary> /// æ§è¡æå¨æå é»è¾ - å¢å¼ºåé æ°éæ§å¶ /// </summary> private async Task<SplitResultDto> ExecuteManualSplitLogic(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, decimal splitQuantity, string palletCode) { _logger.LogInformation($"å¼å§æ§è¡æå¨æå é»è¾ - åæ¡ç : {stockDetail.Barcode}, æå æ°é: {splitQuantity}"); // éè¦ä¿®å¤ï¼è·å订åæç»å¹¶éªè¯åé æ°é var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() .FirstAsync(x => x.Id == lockInfo.OrderDetailId); if (orderDetail == null) throw new InvalidOperationException("æªæ¾å°è®¢åæç»"); // éªè¯æå æ°éä¸ä¼å¯¼è´åé æ°éä¸ºè´æ° if (lockInfo.AssignQuantity < splitQuantity) { throw new InvalidOperationException($"æå æ°éè¶ è¿éå®ä¿¡æ¯åé æ°éï¼æå æ°é: {splitQuantity}, åé æ°é: {lockInfo.AssignQuantity}"); } // çææ°æ¡ç string newBarcode = await GenerateNewBarcode(); // è®°å½æå åçåé æ°é decimal originalAssignQtyBefore = lockInfo.AssignQuantity; decimal originalOrderQtyBefore = lockInfo.OrderQuantity; // 1. å建æ°åºåæç» var newStockDetail = new Dt_StockInfoDetail { StockId = stockDetail.StockId, MaterielCode = stockDetail.MaterielCode, OrderNo = stockDetail.OrderNo, BatchNo = stockDetail.BatchNo, StockQuantity = splitQuantity, OutboundQuantity = 0, Barcode = newBarcode, Status = (int)StockStatusEmun.åºåºéå®, SupplyCode = stockDetail.SupplyCode, Unit = stockDetail.Unit, BarcodeQty = stockDetail.BarcodeQty, BarcodeUnit = stockDetail.BarcodeUnit, BusinessType = stockDetail.BusinessType, InboundOrderRowNo = stockDetail.InboundOrderRowNo, }; await _stockInfoDetailService.Db.Insertable(newStockDetail).ExecuteCommandAsync(); _logger.LogInformation($"å建æ°åºåæç» - æ¡ç : {newBarcode}, åºåæ°é: {splitQuantity}"); // 2. æ´æ°ååºåæç» decimal originalStockQtyBefore = stockDetail.StockQuantity; stockDetail.StockQuantity -= splitQuantity; await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); _logger.LogInformation($"æ´æ°ååºåæç» - åºåæ°éä» {originalStockQtyBefore} åå°å° {stockDetail.StockQuantity}"); // 3. å建æ°éå®ä¿¡æ¯ var newLockInfo = new Dt_OutStockLockInfo { OrderNo = lockInfo.OrderNo, OrderDetailId = lockInfo.OrderDetailId, OutboundBatchNo = lockInfo.OutboundBatchNo, MaterielCode = lockInfo.MaterielCode, MaterielName = lockInfo.MaterielName, StockId = lockInfo.StockId, OrderQuantity = splitQuantity, AssignQuantity = splitQuantity, PickedQty = 0, LocationCode = lockInfo.LocationCode, PalletCode = lockInfo.PalletCode, TaskNum = lockInfo.TaskNum, Status = (int)OutLockStockStatusEnum.åºåºä¸, Unit = lockInfo.Unit, SupplyCode = lockInfo.SupplyCode, OrderType = lockInfo.OrderType, CurrentBarcode = newBarcode, IsSplitted = 1, ParentLockId = lockInfo.Id, Operator = App.User.UserName, FactoryArea = lockInfo.FactoryArea, lineNo = lockInfo.lineNo, WarehouseCode = lockInfo.WarehouseCode, BarcodeQty = lockInfo.BarcodeQty, BarcodeUnit = lockInfo.BarcodeUnit, }; await _outStockLockInfoService.Db.Insertable(newLockInfo).ExecuteCommandAsync(); _logger.LogInformation($"å建æ°éå®ä¿¡æ¯ - æ¡ç : {newBarcode}, åé æ°é: {splitQuantity}"); // 4. æ´æ°åéå®ä¿¡æ¯ lockInfo.AssignQuantity -= splitQuantity; lockInfo.OrderQuantity -= splitQuantity; _logger.LogInformation($"æ´æ°åéå®ä¿¡æ¯ - åé æ°éä» {originalAssignQtyBefore} åå°å° {lockInfo.AssignQuantity}"); _logger.LogInformation($"æ´æ°åéå®ä¿¡æ¯ - è®¢åæ°éä» {originalOrderQtyBefore} åå°å° {lockInfo.OrderQuantity}"); await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); // éè¦ä¿®å¤ï¼æå¨æå ä¸ä¼æ¹å订åæç»çåé æ°éï¼å 为æ»åé æ°éä¸å // åªæ¯ä»ä¸ä¸ªéå®ä¿¡æ¯è½¬ç§»å°å¦ä¸ä¸ªéå®ä¿¡æ¯ _logger.LogInformation($"订åæç»åé æ°éä¿æä¸å - å·²åé æ°é: {orderDetail.AllocatedQuantity}"); // 5. è®°å½æå åå² await RecordSplitHistory(lockInfo, stockDetail, splitQuantity, newBarcode, false); _logger.LogInformation($"æå¨æå é»è¾æ§è¡å®æ"); return new SplitResultDto { NewBarcode = newBarcode }; } #endregion #endregion #region åæ¶æå @@ -588,15 +842,24 @@ Dt_OutStockLockInfo originalLockInfo, Dt_OutStockLockInfo newLockInfo, Dt_StockInfoDetail newStockDetail) { // 1. æ¢å¤åéå®ä¿¡æ¯ // 注æï¼è¿ééè¦ç´¯å ï¼è䏿¯ç®åçèµå¼ï¼å 为å¯è½æå¤æ¬¡æå _logger.LogInformation($"å¼å§æ§è¡åæ¶æå é»è¾ - åæ¡ç : {splitRecord.OriginalBarcode}, æ°æ¡ç : {splitRecord.NewBarcode}, æå æ°é: {splitRecord.SplitQty}"); // æ¢å¤åéå®ä¿¡æ¯ decimal originalAssignQtyBefore = originalLockInfo.AssignQuantity; decimal originalOrderQtyBefore = originalLockInfo.OrderQuantity; // éè¦ä¿®å¤ï¼æ¢å¤åé æ°éåè®¢åæ°é originalLockInfo.AssignQuantity += splitRecord.SplitQty; originalLockInfo.OrderQuantity += splitRecord.SplitQty; _logger.LogInformation($"æ¢å¤åéå®ä¿¡æ¯ - åé æ°éä» {originalAssignQtyBefore} å¢å å° {originalLockInfo.AssignQuantity}"); _logger.LogInformation($"æ¢å¤åéå®ä¿¡æ¯ - è®¢åæ°éä» {originalOrderQtyBefore} å¢å å° {originalLockInfo.OrderQuantity}"); // 妿åéå®ä¿¡æ¯çç¶ææ¯æ£é宿ï¼éè¦éæ°è®¾ç½®ä¸ºåºåºä¸ if (originalLockInfo.Status == (int)OutLockStockStatusEnum.æ£é宿) { originalLockInfo.Status = (int)OutLockStockStatusEnum.åºåºä¸; _logger.LogInformation($"åéå®ä¿¡æ¯ç¶æä»æ£é宿æ¢å¤ä¸ºåºåºä¸"); } await _outStockLockInfoService.Db.Updateable(originalLockInfo).ExecuteCommandAsync(); @@ -605,35 +868,47 @@ var originalStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() .FirstAsync(x => x.Barcode == splitRecord.OriginalBarcode && x.StockId == splitRecord.StockId); originalStock.StockQuantity += splitRecord.SplitQty; // 妿ååºåç¶ææ¯åºåºå®æï¼éè¦éæ°è®¾ç½®ä¸ºåºåºéå® if (originalStock.Status == (int)StockStatusEmun.åºåºå®æ) if (originalStock != null) { originalStock.Status = (int)StockStatusEmun.åºåºéå®; decimal originalStockQtyBefore = originalStock.StockQuantity; originalStock.StockQuantity += splitRecord.SplitQty; _logger.LogInformation($"æ¢å¤ååºåæç» - åºåæ°éä» {originalStockQtyBefore} å¢å å° {originalStock.StockQuantity}"); // 妿ååºåç¶ææ¯åºåºå®æï¼éè¦éæ°è®¾ç½®ä¸ºåºåºéå® if (originalStock.Status == (int)StockStatusEmun.åºåºå®æ) { originalStock.Status = (int)StockStatusEmun.åºåºéå®; _logger.LogInformation($"ååºåç¶æä»åºåºå®ææ¢å¤ä¸ºåºåºéå®"); } await _stockInfoDetailService.Db.Updateable(originalStock).ExecuteCommandAsync(); } await _stockInfoDetailService.Db.Updateable(originalStock).ExecuteCommandAsync(); // å 餿°éå®ä¿¡æ¯ _logger.LogInformation($"å 餿°éå®ä¿¡æ¯ - æ¡ç : {newLockInfo.CurrentBarcode}, åé æ°é: {newLockInfo.AssignQuantity}"); await _outStockLockInfoService.Db.Deleteable<Dt_OutStockLockInfo>() .Where(x => x.Id == newLockInfo.Id) .ExecuteCommandAsync(); // å 餿°åºåæç» // å 餿°åºåæç» _logger.LogInformation($"å 餿°åºåæç» - æ¡ç : {newStockDetail.Barcode}, åºåæ°é: {newStockDetail.StockQuantity}"); await _stockInfoDetailService.Db.Deleteable<Dt_StockInfoDetail>() .Where(x => x.Barcode == newLockInfo.CurrentBarcode) .ExecuteCommandAsync(); //æ è®°æå è®°å½ä¸ºå·²æ¤é // æ è®°æå è®°å½ä¸ºå·²æ¤é splitRecord.IsReverted = true; splitRecord.RevertTime = DateTime.Now; splitRecord.RevertOperator = App.User.UserName; await _splitPackageService.Db.Updateable(splitRecord).ExecuteCommandAsync(); _logger.LogInformation($"æ è®°æå è®°å½ä¸ºå·²æ¤é"); // æ£æ¥å¹¶æ´æ°æ¹æ¬¡å订åç¶æ await CheckAndUpdateBatchStatus(originalLockInfo.BatchNo); await CheckAndUpdateOrderStatus(originalLockInfo.OrderNo); _logger.LogInformation($"åæ¶æå é»è¾æ§è¡å®æ"); } /// <summary> @@ -642,6 +917,8 @@ private async Task<ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>> ValidateCancelSplitRequest( string orderNo, string palletCode, string newBarcode) { _logger.LogInformation($"å¼å§éªè¯åæ¶æå è¯·æ± - 订å: {orderNo}, æç: {palletCode}, æ¡ç : {newBarcode}"); // æ¥æ¾æå è®°å½ var splitRecord = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>() .Where(x => x.NewBarcode == newBarcode && @@ -651,6 +928,8 @@ if (splitRecord == null) return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("æªæ¾å°æå è®°å½"); _logger.LogInformation($"æ¾å°æå è®°å½ - åæ¡ç : {splitRecord.OriginalBarcode}, æ°æ¡ç : {splitRecord.NewBarcode}, æå æ°é: {splitRecord.SplitQty}"); // æ¥æ¾æ°éå®ä¿¡æ¯ var newLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() @@ -662,13 +941,35 @@ if (newLockInfo == null) return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("æªæ¾å°æ°éå®ä¿¡æ¯"); // æ£æ¥æ°æ¡ç æ¯å¦å·²è¢«åæ£ var pickingRecord = await Db.Queryable<Dt_PickingRecord>() .Where(x => x.Barcode == newBarcode && !x.IsCancelled) .FirstAsync(); _logger.LogInformation($"æ¾å°æ°éå®ä¿¡æ¯ - ç¶æ: {newLockInfo.Status}, å·²æ£é: {newLockInfo.PickedQty}, åé æ°é: {newLockInfo.AssignQuantity}"); if (pickingRecord != null) return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("该æ¡ç å·²è¢«åæ£ï¼æ æ³åæ¶æå "); // éè¦ä¿®å¤ï¼æ£æ¥æ°æ¡ç æ¯å¦å·²è¢«åæ£ var newBarcodePickingRecords = await Db.Queryable<Dt_PickingRecord>() .Where(x => x.Barcode == newBarcode && x.OrderNo == orderNo && !x.IsCancelled) .ToListAsync(); if (newBarcodePickingRecords.Any()) { var totalPickedQty = newBarcodePickingRecords.Sum(x => x.PickQuantity); _logger.LogWarning($"æ°æ¡ç {newBarcode} å·²è¢«åæ£ï¼æ»æ£éæ°é: {totalPickedQty}"); return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error( $"æ°æ¡ç å·²è¢«åæ£ï¼å·²æ£éæ°éï¼{totalPickedQty}ï¼ï¼è¯·å 忶忣ï¼ç¶åååæ¶æå "); } // éè¦ä¿®å¤ï¼æ£æ¥åæ¡ç æ¯å¦å·²è¢«åæ£ var originalBarcodePickingRecords = await Db.Queryable<Dt_PickingRecord>() .Where(x => x.Barcode == splitRecord.OriginalBarcode && x.OrderNo == orderNo && !x.IsCancelled) .ToListAsync(); if (originalBarcodePickingRecords.Any()) { var totalPickedQty = originalBarcodePickingRecords.Sum(x => x.PickQuantity); _logger.LogWarning($"åæ¡ç {splitRecord.OriginalBarcode} å·²è¢«åæ£ï¼æ»æ£éæ°é: {totalPickedQty}"); return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error( $"åæ¡ç å·²è¢«åæ£ï¼å·²æ£éæ°éï¼{totalPickedQty}ï¼ï¼è¯·å 忶忣ï¼ç¶åååæ¶æå "); } _logger.LogInformation($"æ°æ§æ¡ç åæªè¢«åæ£ï¼å¯ä»¥åæ¶æå "); // æ£æ¥æ°æ¡ç æ¯å¦è¢«å次æå var childSplitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>() @@ -678,12 +979,18 @@ if (childSplitRecords.Any()) { var childBarcodes = string.Join(", ", childSplitRecords.Select(x => x.NewBarcode)); _logger.LogWarning($"æ¡ç {newBarcode} å·²è¢«åæ¬¡æå ï¼çæçæ°æ¡ç : {childBarcodes}"); return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error( $"该æ¡ç å·²è¢«åæ¬¡æå ï¼çæçæ°æ¡ç ï¼{childBarcodes}ï¼è¯·å åæ¶åç»æå "); } var newStockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() .FirstAsync(x => x.Barcode == newBarcode); if (newStockDetail == null) return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("æªæ¾å°æ°åºåæç»"); _logger.LogInformation($"åæ¶æå éªè¯éè¿ - æ¡ç : {newBarcode}"); return ValidationResult<(Dt_SplitPackageRecord, Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Success((splitRecord, newLockInfo, newStockDetail)); } @@ -707,11 +1014,28 @@ if (!splitChain.Any()) return WebResponseContent.Instance.Error("æªæ¾å°æå è®°å½"); // 2. ææå 顺åºååºåæ¶ï¼ä»ææ°çå¼å§åæ¶ï¼ _logger.LogInformation($"æ¾å°æå é¾ï¼å ± {splitChain.Count} æ¡è®°å½"); // 2. æ¶éæå é¾ä¸æ¶åçæææ¡ç ï¼å æ¬åæ¡ç åæ°æ¡ç ï¼ var allBarcodesInChain = new List<string> { startBarcode }; allBarcodesInChain.AddRange(splitChain.Select(x => x.NewBarcode)); // 3. æ£æ¥æå é¾ä¸æ¯å¦æå·²è¢«åæ£çæ¡ç var pickedBarcodesInfo = await GetPickedBarcodesInfo(orderNo, allBarcodesInChain); if (pickedBarcodesInfo.Any()) { var pickedBarcodes = string.Join(", ", pickedBarcodesInfo.Select(x => $"{x.Barcode}(å·²æ£é{x.PickedQty})")); return WebResponseContent.Instance.Error( $"以䏿¡ç å·²è¢«åæ£ï¼è¯·å 忶忣ï¼{pickedBarcodes}"); } // 4. ææå 顺åºååºåæ¶ï¼ä»ææ°çå¼å§åæ¶ï¼ var reversedChain = splitChain.OrderByDescending(x => x.SplitTime).ToList(); foreach (var splitRecord in reversedChain) { _logger.LogInformation($"åæ¶æå è®°å½ - åæ¡ç : {splitRecord.OriginalBarcode}, æ°æ¡ç : {splitRecord.NewBarcode}"); await CancelSingleSplitPackage(splitRecord, palletCode); } @@ -727,6 +1051,133 @@ } } /// <summary> /// è·åæ¡ç çæå 忣éç¶æ /// </summary> public async Task<WebResponseContent> GetBarcodeSplitAndPickStatus(string orderNo, string barcode) { try { // 1. è·åæå ä¿¡æ¯ var splitChain = await GetSplitPackageChain(orderNo, barcode); var isOriginalBarcode = !splitChain.Any(x => x.NewBarcode == barcode); // 2. è·åæ£éä¿¡æ¯ var pickingRecords = await Db.Queryable<Dt_PickingRecord>() .Where(x => x.Barcode == barcode && x.OrderNo == orderNo && !x.IsCancelled) .ToListAsync(); var totalPickedQty = pickingRecords.Sum(x => x.PickQuantity); // 3. è·åéå®ä¿¡æ¯ var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() .Where(x => x.CurrentBarcode == barcode && x.OrderNo == orderNo) .FirstAsync(); // 4. è·ååºåä¿¡æ¯ var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() .Where(x => x.Barcode == barcode) .FirstAsync(); var statusInfo = new BarcodeStatusInfoDto { Barcode = barcode, OrderNo = orderNo, IsOriginalBarcode = isOriginalBarcode, SplitChainCount = splitChain.Count, HasBeenPicked = pickingRecords.Any(), TotalPickedQuantity = totalPickedQty, PickRecordCount = pickingRecords.Count, LockInfoStatus = lockInfo?.Status ?? 0, LockInfoPickedQty = lockInfo?.PickedQty ?? 0, LockInfoAssignQty = lockInfo?.AssignQuantity ?? 0, StockQuantity = stockDetail?.StockQuantity ?? 0, StockStatus = stockDetail?.Status ?? 0, CanCancelSplit = !pickingRecords.Any(), // æªè¢«åæ£æè½åæ¶æå NeedCancelPickFirst = pickingRecords.Any() // éè¦å 忶忣 }; // 5. è·åæä½å»ºè®® statusInfo.OperationSuggestions = GetOperationSuggestions(statusInfo); return WebResponseContent.Instance.OK("è·åç¶ææå", statusInfo); } catch (Exception ex) { _logger.LogError($"è·åæ¡ç ç¶æå¤±è´¥ - OrderNo: {orderNo}, Barcode: {barcode}, Error: {ex.Message}"); return WebResponseContent.Instance.Error("è·åæ¡ç ç¶æå¤±è´¥"); } } /// <summary> /// è·åæä½å»ºè®® /// </summary> private List<string> GetOperationSuggestions(BarcodeStatusInfoDto statusInfo) { var suggestions = new List<string>(); if (statusInfo.HasBeenPicked) { suggestions.Add($"该æ¡ç å·²è¢«åæ£ï¼æ°éï¼{statusInfo.TotalPickedQuantity}ï¼ï¼å¦éåæ¶æå ï¼è¯·å 忶忣"); if (statusInfo.IsOriginalBarcode) { suggestions.Add("è¿æ¯åæ¡ç ï¼åæ¶åæ£åå°æ¢å¤ä¸ºå¯åæ£ç¶æ"); } else { suggestions.Add("è¿æ¯æå çæçæ°æ¡ç ï¼åæ¶åæ£åæè½åæ¶æå "); } } else { if (statusInfo.IsOriginalBarcode && statusInfo.SplitChainCount > 0) { suggestions.Add("è¿æ¯åæ¡ç ï¼å¯ä»¥åæ¶æå é¾"); } else if (!statusInfo.IsOriginalBarcode) { suggestions.Add("è¿æ¯æå çæçæ°æ¡ç ï¼å¯ä»¥åç¬åæ¶æå "); } } if (statusInfo.LockInfoStatus == (int)OutLockStockStatusEnum.æ£é宿) { suggestions.Add("éå®ç¶æï¼æ£é宿"); } else if (statusInfo.LockInfoStatus == (int)OutLockStockStatusEnum.åºåºä¸) { suggestions.Add("éå®ç¶æï¼åºåºä¸"); } return suggestions; } /// <summary> /// è·åå·²è¢«åæ£çæ¡ç ä¿¡æ¯ /// </summary> private async Task<List<PickedBarcodeInfo>> GetPickedBarcodesInfo(string orderNo, List<string> barcodes) { var pickedBarcodes = new List<PickedBarcodeInfo>(); foreach (var barcode in barcodes) { var pickingRecords = await Db.Queryable<Dt_PickingRecord>() .Where(x => x.Barcode == barcode && x.OrderNo == orderNo && !x.IsCancelled) .ToListAsync(); if (pickingRecords.Any()) { var totalPickedQty = pickingRecords.Sum(x => x.PickQuantity); pickedBarcodes.Add(new PickedBarcodeInfo { Barcode = barcode, PickedQty = totalPickedQty, PickRecordCount = pickingRecords.Count }); } } return pickedBarcodes; } /// <summary> /// è·åæå é¾ - æ¥æ¾æä¸ªæ¡ç çæææå è®°å½ï¼å æ¬åç»æå ï¼ /// </summary> @@ -771,6 +1222,27 @@ /// </summary> private async Task CancelSingleSplitPackage(Dt_SplitPackageRecord splitRecord, string palletCode) { _logger.LogInformation($"å¼å§åæ¶å个æå è®°å½ - åæ¡ç : {splitRecord.OriginalBarcode}, æ°æ¡ç : {splitRecord.NewBarcode}"); // 忬¡éªè¯åæ£ç¶æï¼é²æ¢å¹¶åæä½ï¼ var newBarcodePickingRecords = await Db.Queryable<Dt_PickingRecord>() .Where(x => x.Barcode == splitRecord.NewBarcode && !x.IsCancelled) .ToListAsync(); if (newBarcodePickingRecords.Any()) { throw new InvalidOperationException($"æ°æ¡ç {splitRecord.NewBarcode} å¨éªè¯åè¢«åæ£ï¼æ æ³åæ¶æå "); } var originalBarcodePickingRecords = await Db.Queryable<Dt_PickingRecord>() .Where(x => x.Barcode == splitRecord.OriginalBarcode && !x.IsCancelled) .ToListAsync(); if (originalBarcodePickingRecords.Any()) { throw new InvalidOperationException($"åæ¡ç {splitRecord.OriginalBarcode} å¨éªè¯åè¢«åæ£ï¼æ æ³åæ¶æå "); } // æ¥æ¾ç¸å ³æ°æ® var newLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() .Where(x => x.CurrentBarcode == splitRecord.NewBarcode && @@ -785,6 +1257,8 @@ // æ§è¡åæ¶é»è¾ await ExecuteCancelSplitLogic(splitRecord, originalLockInfo, newLockInfo, newStockDetail); _logger.LogInformation($"åæ¶å个æå è®°å½å®æ - åæ¡ç : {splitRecord.OriginalBarcode}, æ°æ¡ç : {splitRecord.NewBarcode}"); } #endregion @@ -810,7 +1284,8 @@ NewBarcode = x.NewBarcode, SplitQuantity = x.SplitQty, Operator = x.Operator, IsReverted = x.IsReverted IsReverted = x.IsReverted , IsAutoSplit = x.IsAutoSplit }).ToList() }; @@ -899,9 +1374,7 @@ #endregion #region åæ¹ååº /// <summary> @@ -961,6 +1434,8 @@ private async Task<ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>> ValidatePickingRequest( string orderNo, string palletCode, string barcode) { _logger.LogInformation($"å¼å§éªè¯åæ£è¯·æ± - 订å: {orderNo}, æç: {palletCode}, æ¡ç : {barcode}"); // æ¥æ¾éå®ä¿¡æ¯ var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() .Where(x => x.OrderNo == orderNo && @@ -972,6 +1447,8 @@ if (lockInfo == null) return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Error("æªæ¾å°ææçéå®ä¿¡æ¯"); _logger.LogInformation($"æ¾å°éå®ä¿¡æ¯ - åé æ°é: {lockInfo.AssignQuantity}, å·²æ£é: {lockInfo.PickedQty}"); // æ£æ¥æ¯å¦å·²ç»åæ£å®æ if (lockInfo.PickedQty >= lockInfo.AssignQuantity) return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Error("该æ¡ç 已忣宿"); @@ -980,132 +1457,106 @@ var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() .FirstAsync(x => x.Id == lockInfo.OrderDetailId); if (orderDetail == null) return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Error("æªæ¾å°è®¢åæç»"); _logger.LogInformation($"æ¾å°è®¢åæç» - å·²åé æ°é: {orderDetail.AllocatedQuantity}, é宿°é: {orderDetail.LockQuantity}"); // éè¦ä¿®å¤ï¼æ£æ¥è®¢åæç»çå·²åé æ°éæ¯å¦è¶³å¤ decimal remainingToPick = lockInfo.AssignQuantity - lockInfo.PickedQty; if (orderDetail.AllocatedQuantity < remainingToPick) { _logger.LogWarning($"订åæç»å·²åé æ°éä¸è¶³ - éè¦æ£é: {remainingToPick}, å¯ç¨åé æ°é: {orderDetail.AllocatedQuantity}"); return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Error( $"订åæç»åé æ°éä¸è¶³ï¼éè¦æ£éï¼{remainingToPick}ï¼å¯ç¨åé æ°éï¼{orderDetail.AllocatedQuantity}"); } // éè¦ä¿®å¤ï¼æ£æ¥é宿°éæ¯å¦è¶³å¤ if (orderDetail.LockQuantity < remainingToPick) { _logger.LogWarning($"订åæç»é宿°éä¸è¶³ - éè¦æ£é: {remainingToPick}, å¯ç¨é宿°é: {orderDetail.LockQuantity}"); return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Error( $"订åæç»é宿°éä¸è¶³ï¼éè¦æ£éï¼{remainingToPick}ï¼å¯ç¨é宿°éï¼{orderDetail.LockQuantity}"); } var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() .FirstAsync(x => x.Barcode == barcode && x.StockId == lockInfo.StockId); if (stockDetail == null) return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Error("æªæ¾å°å¯¹åºçåºåä¿¡æ¯"); // éªè¯åºåæ°é if (stockDetail.StockQuantity < lockInfo.AssignQuantity) if (stockDetail.StockQuantity < remainingToPick) return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Error( $"åºåæ°éä¸è¶³ï¼éè¦ï¼{lockInfo.AssignQuantity}ï¼å®é ï¼{stockDetail.StockQuantity}"); $"åºåæ°éä¸è¶³ï¼éè¦æ£éï¼{remainingToPick}ï¼å®é åºåï¼{stockDetail.StockQuantity}"); // éªè¯åºåç¶æ if (stockDetail.Status != (int)StockStatusEmun.åºåºéå®) { return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Error( $"åºåç¶æå¼å¸¸ï¼å½åç¶æï¼{stockDetail.Status}ï¼ææç¶æï¼åºåºéå®"); } // ä½¿ç¨ OutboundBatchNo æ¥æ¾æ¹æ¬¡ var batch = await _outboundBatchRepository.Db.Queryable<Dt_OutboundBatch>() .FirstAsync(x => x.BatchNo == lockInfo.OutboundBatchNo); // ä¿®æ£ä¸º OutboundBatchNo .FirstAsync(x => x.BatchNo == lockInfo.OutboundBatchNo); _logger.LogInformation($"忣éªè¯éè¿ - æ¡ç : {barcode}, å©ä½éæ£é: {remainingToPick}, å¯ç¨åºå: {stockDetail.StockQuantity}"); return ValidationResult<(Dt_OutStockLockInfo, Dt_OutboundOrderDetail, Dt_StockInfoDetail, Dt_OutboundBatch)>.Success((lockInfo, orderDetail, stockDetail, batch)); } private async Task<ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>> ValidateSplitRequest( string orderNo, string palletCode, string originalBarcode, decimal splitQuantity) /// <summary> /// æ£æ¥å¹¶æ§è¡èªå¨æå ï¼å¦æéè¦ï¼ /// </summary> private async Task<AutoSplitResult> CheckAndAutoSplitIfNeeded(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, string palletCode) { var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode && x.CurrentBarcode == originalBarcode && x.Status == (int)OutLockStockStatusEnum.åºåºä¸) .FirstAsync(); // æ£æ¥æ¯å¦éè¦èªå¨æå çæ¡ä»¶ï¼ // 1. åºåæ°é大äºåé æ°é // 2. éå®ä¿¡æ¯ç¶æä¸ºåºåºä¸ // 3. æªæ£éæ°éçäºåé æ°éï¼è¡¨ç¤ºè¿æªå¼å§æ£éï¼ bool needAutoSplit = stockDetail.StockQuantity > lockInfo.AssignQuantity && lockInfo.Status == (int)OutLockStockStatusEnum.åºåºä¸ && lockInfo.PickedQty == 0; if (lockInfo == null) return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("æªæ¾å°ææçéå®ä¿¡æ¯"); if (!needAutoSplit) return null; var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() .FirstAsync(x => x.Barcode == originalBarcode && x.StockId == lockInfo.StockId); // è®¡ç®æå æ°é = åºåæ°é - åé æ°é decimal splitQuantity = stockDetail.StockQuantity - lockInfo.AssignQuantity; if (stockDetail.StockQuantity < splitQuantity) return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("æå æ°éä¸è½å¤§äºåºåæ°é"); // æ§è¡èªå¨æå var splitResult = await ExecuteAutoSplitLogic(lockInfo, stockDetail, splitQuantity, palletCode); if (lockInfo.AssignQuantity - lockInfo.PickedQty < splitQuantity) return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Error("æå æ°éä¸è½å¤§äºæªæ£éæ°é"); return ValidationResult<(Dt_OutStockLockInfo, Dt_StockInfoDetail)>.Success((lockInfo, stockDetail)); } #endregion #region æ ¸å¿é»è¾æ¹æ³ private async Task<PickingResult> ExecutePickingLogic( Dt_OutStockLockInfo lockInfo, Dt_OutboundOrderDetail orderDetail, Dt_StockInfoDetail stockDetail, decimal actualPickedQty) { // æ´æ°éå®ä¿¡æ¯ lockInfo.PickedQty += actualPickedQty; if (lockInfo.PickedQty >= lockInfo.AssignQuantity) return new AutoSplitResult { lockInfo.Status = (int)OutLockStockStatusEnum.æ£é宿; } await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); // æ´æ°åºå stockDetail.StockQuantity -= actualPickedQty; stockDetail.OutboundQuantity += actualPickedQty; if (stockDetail.StockQuantity <= 0) { stockDetail.Status = (int)StockStatusEmun.åºåºå®æ; } await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); return new PickingResult { FinalLockInfo = lockInfo, ActualPickedQty = actualPickedQty NewBarcode = splitResult.NewBarcode, SplitQuantity = splitQuantity }; } private async Task<RevertPickingResult> RevertPickingData(Dt_PickingRecord pickingRecord) /// <summary> /// æ§è¡èªå¨æå é»è¾ /// </summary> private async Task<SplitResultDto> ExecuteAutoSplitLogic(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, decimal splitQuantity, string palletCode) { // æ¢å¤éå®ä¿¡æ¯ var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() .FirstAsync(x => x.Id == pickingRecord.OutStockLockId); _logger.LogInformation($"å¼å§æ§è¡èªå¨æå é»è¾ - åæ¡ç : {stockDetail.Barcode}, æå æ°é: {splitQuantity}"); lockInfo.PickedQty -= pickingRecord.PickQuantity; // æ ¹æ®æ£éæ°éå¤æç¶æ if (lockInfo.PickedQty <= 0) { lockInfo.Status = (int)OutLockStockStatusEnum.åºåºä¸; } else if (lockInfo.PickedQty < lockInfo.AssignQuantity) { lockInfo.Status = (int)OutLockStockStatusEnum.åºåºä¸; } await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); // æ¢å¤åºå var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() .FirstAsync(x => x.Barcode == pickingRecord.Barcode); stockDetail.StockQuantity += pickingRecord.PickQuantity; stockDetail.OutboundQuantity -= pickingRecord.PickQuantity; // æ¢å¤åºåç¶æ if (stockDetail.StockQuantity > 0) { stockDetail.Status = (int)StockStatusEmun.åºåºéå®; } await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); return new RevertPickingResult { LockInfo = lockInfo, StockDetail = stockDetail }; } private async Task<SplitResultDto> ExecuteSplitLogic(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, decimal splitQuantity, string palletCode) { // çææ°æ¡ç string newBarcode = await GenerateNewBarcode(); // å建æ°åºåæç» // éè¦ä¿®å¤ï¼è®°å½æå åçåé æ°é decimal originalAssignQtyBefore = lockInfo.AssignQuantity; decimal originalOrderQtyBefore = lockInfo.OrderQuantity; // 1. å建æ°åºåæç»ï¼å©ä½é¨åï¼ var newStockDetail = new Dt_StockInfoDetail { StockId = stockDetail.StockId, MaterielCode = stockDetail.MaterielCode, OrderNo = stockDetail.OrderNo, BatchNo = stockDetail.BatchNo, // ç©ææ¹æ¬¡ BatchNo = stockDetail.BatchNo, StockQuantity = splitQuantity, OutboundQuantity = 0, Barcode = newBarcode, @@ -1115,20 +1566,25 @@ BarcodeQty = stockDetail.BarcodeQty, BarcodeUnit = stockDetail.BarcodeUnit, BusinessType = stockDetail.BusinessType, InboundOrderRowNo = stockDetail.InboundOrderRowNo, InboundOrderRowNo = stockDetail.InboundOrderRowNo, }; await _stockInfoDetailService.Db.Insertable(newStockDetail).ExecuteCommandAsync(); _logger.LogInformation($"å建æ°åºåæç» - æ¡ç : {newBarcode}, åºåæ°é: {splitQuantity}"); // æ´æ°ååºåæç» stockDetail.StockQuantity -= splitQuantity; await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); // 2. æ´æ°ååºåæç» // éè¦ä¿®å¤ï¼ååºåæ°é设置为åé æ°éï¼ä¿æä¸åï¼ decimal originalStockQtyBefore = stockDetail.StockQuantity; // 注æï¼èªå¨æå æ¶ï¼ååºåæ°éä¿æä¸åï¼å 为æä»¬è¦åæ£çå°±æ¯åé æ°é // stockDetail.StockQuantity ä¿æä¸å // å建æ°éå®ä¿¡æ¯ - ä½¿ç¨æ£ç¡®ç OutboundBatchNo _logger.LogInformation($"ååºåæç»ä¿æä¸å - åºåæ°é: {stockDetail.StockQuantity}"); // 3. å建æ°éå®ä¿¡æ¯ï¼å©ä½é¨åï¼ var newLockInfo = new Dt_OutStockLockInfo { OrderNo = lockInfo.OrderNo, OrderDetailId = lockInfo.OrderDetailId, OutboundBatchNo = lockInfo.OutboundBatchNo, // ä½¿ç¨ OutboundBatchNo OutboundBatchNo = lockInfo.OutboundBatchNo, MaterielCode = lockInfo.MaterielCode, MaterielName = lockInfo.MaterielName, StockId = lockInfo.StockId, @@ -1150,111 +1606,310 @@ lineNo = lockInfo.lineNo, WarehouseCode = lockInfo.WarehouseCode, BarcodeQty = lockInfo.BarcodeQty, BarcodeUnit = lockInfo.BarcodeUnit, BarcodeUnit = lockInfo.BarcodeUnit, }; await _outStockLockInfoService.Db.Insertable(newLockInfo).ExecuteCommandAsync(); _logger.LogInformation($"å建æ°éå®ä¿¡æ¯ - æ¡ç : {newBarcode}, åé æ°é: {splitQuantity}"); // æ´æ°åéå®ä¿¡æ¯ lockInfo.AssignQuantity -= splitQuantity; lockInfo.OrderQuantity -= splitQuantity; await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); // 4. éè¦ä¿®å¤ï¼èªå¨æå æ¶ï¼åéå®ä¿¡æ¯çåé æ°éä¿æä¸å // å 为èªå¨æå åï¼åæ¡ç ä»ç¶éè¦è¢«åæ£ï¼åé æ°éä¸åºè¯¥æ¹å _logger.LogInformation($"åéå®ä¿¡æ¯ä¿æä¸å - åé æ°é: {lockInfo.AssignQuantity}, è®¢åæ°é: {lockInfo.OrderQuantity}"); // è®°å½æå åå² await RecordSplitHistory(lockInfo, stockDetail, splitQuantity, newBarcode); // 5. è®°å½æå åå² await RecordSplitHistory(lockInfo, stockDetail, splitQuantity, newBarcode, true, originalStockQtyBefore); _logger.LogInformation($"èªå¨æå é»è¾æ§è¡å®æ"); return new SplitResultDto { NewBarcode = newBarcode }; } private async Task ExecuteCancelSplitLogic(Dt_SplitPackageRecord splitRecord, Dt_OutStockLockInfo newLockInfo, Dt_StockInfoDetail newStockDetail) #endregion #region æ ¸å¿é»è¾æ¹æ³ private async Task<PickingResult> ExecutePickingLogic( Dt_OutStockLockInfo lockInfo, Dt_OutboundOrderDetail orderDetail, Dt_StockInfoDetail stockDetail, decimal actualPickedQty) { // æ¢å¤ååºå var originalStock = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() .FirstAsync(x => x.Barcode == splitRecord.OriginalBarcode && x.StockId == splitRecord.StockId); _logger.LogInformation($"å¼å§æ§è¡åæ£é»è¾ - æ¡ç : {stockDetail.Barcode}, åé æ°é: {lockInfo.AssignQuantity}, å®é æ£é: {actualPickedQty}"); originalStock.StockQuantity += splitRecord.SplitQty; await _stockInfoDetailService.Db.Updateable(originalStock).ExecuteCommandAsync(); // éè¦ä¿®å¤ï¼å次éªè¯è®¢åæç»çåé æ°éï¼é²æ¢å¹¶åæä½ï¼ if (orderDetail.AllocatedQuantity < actualPickedQty) { throw new InvalidOperationException($"订åæç»åé æ°éä¸è¶³ï¼éè¦æ£é {actualPickedQty}ï¼å¯ç¨åé æ°é {orderDetail.AllocatedQuantity}"); } // æ¢å¤åéå®ä¿¡æ¯ var originalLockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() .FirstAsync(x => x.Id == splitRecord.OutStockLockInfoId); if (orderDetail.LockQuantity < actualPickedQty) { throw new InvalidOperationException($"订åæç»é宿°éä¸è¶³ï¼éè¦æ£é {actualPickedQty}ï¼å¯ç¨é宿°é {orderDetail.LockQuantity}"); } originalLockInfo.AssignQuantity += splitRecord.SplitQty; originalLockInfo.OrderQuantity += splitRecord.SplitQty; await _outStockLockInfoService.Db.Updateable(originalLockInfo).ExecuteCommandAsync(); // 1. æ´æ°éå®ä¿¡æ¯ lockInfo.PickedQty += actualPickedQty; _logger.LogInformation($"æ´æ°éå®ä¿¡æ¯ - å·²æ£éæ°éä» {lockInfo.PickedQty - actualPickedQty} å¢å å° {lockInfo.PickedQty}"); // å 餿°åºåæç» await _stockInfoDetailService.Db.Deleteable<Dt_StockInfoDetail>() .Where(x => x.Barcode == newLockInfo.CurrentBarcode) .ExecuteCommandAsync(); // åç¡®å¤ææ£éå®æç¶æ if (Math.Abs(lockInfo.PickedQty - lockInfo.AssignQuantity) < 0.001m) { lockInfo.Status = (int)OutLockStockStatusEnum.æ£é宿; _logger.LogInformation($"éå®ä¿¡æ¯ç¶ææ´æ°ä¸ºæ£é宿"); } else if (lockInfo.PickedQty > 0) { lockInfo.Status = (int)OutLockStockStatusEnum.åºåºä¸; _logger.LogInformation($"éå®ä¿¡æ¯ç¶æä¿æä¸ºåºåºä¸ï¼é¨åæ£éï¼"); } // å 餿°éå®ä¿¡æ¯ await _outStockLockInfoService.Db.Deleteable<Dt_OutStockLockInfo>() .Where(x => x.Id == newLockInfo.Id) .ExecuteCommandAsync(); lockInfo.Operator = App.User.UserName; await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); // æ è®°æå è®°å½ä¸ºå·²æ¤é splitRecord.IsReverted = true; splitRecord.RevertTime = DateTime.Now; splitRecord.RevertOperator = App.User.UserName; await _splitPackageService.Db.Updateable(splitRecord).ExecuteCommandAsync(); // 2. æ´æ°åºåä¿¡æ¯ decimal originalStockQty = stockDetail.StockQuantity; decimal originalOutboundQty = stockDetail.OutboundQuantity; stockDetail.StockQuantity -= actualPickedQty; stockDetail.OutboundQuantity += actualPickedQty; _logger.LogInformation($"æ´æ°åºåä¿¡æ¯ - åºåæ°éä» {originalStockQty} åå°å° {stockDetail.StockQuantity}"); _logger.LogInformation($"æ´æ°åºåä¿¡æ¯ - åºåºæ°éä» {originalOutboundQty} å¢å å° {stockDetail.OutboundQuantity}"); // åç¡®å¤æåºåç¶æ if (stockDetail.StockQuantity <= 0) { stockDetail.Status = (int)StockStatusEmun.åºåºå®æ; _logger.LogInformation($"åºåç¶ææ´æ°ä¸ºåºåºå®æ"); } else { stockDetail.Status = (int)StockStatusEmun.åºåºéå®; _logger.LogInformation($"åºåç¶æä¿æä¸ºåºåºéå®"); } await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); _logger.LogInformation($"忣é»è¾æ§è¡å®æ - æ¡ç : {stockDetail.Barcode}"); return new PickingResult { FinalLockInfo = lockInfo, ActualPickedQty = actualPickedQty }; } private async Task<RevertPickingResult> RevertPickingData(Dt_PickingRecord pickingRecord) { _logger.LogInformation($"å¼å§æ¢å¤æ£éæ°æ® - æ£éè®°å½ID: {pickingRecord.Id}, æ¡ç : {pickingRecord.Barcode}, æ£éæ°é: {pickingRecord.PickQuantity}"); // 1. æ¢å¤éå®ä¿¡æ¯ var lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() .FirstAsync(x => x.Id == pickingRecord.OutStockLockId); if (lockInfo == null) { throw new InvalidOperationException($"æªæ¾å°å¯¹åºçéå®ä¿¡æ¯ï¼ID: {pickingRecord.OutStockLockId}"); } decimal originalPickedQty = lockInfo.PickedQty; decimal originalAssignQty = lockInfo.AssignQuantity; // è®°å½åå§åé æ°é // éè¦ä¿®å¤ï¼åªæ¢å¤å·²æ£éæ°éï¼ä¸ä¿®æ¹åé æ°é lockInfo.PickedQty -= pickingRecord.PickQuantity; // ç¡®ä¿å·²æ£éæ°éä¸ä¼ä¸ºè´æ° if (lockInfo.PickedQty < 0) { _logger.LogWarning($"å·²æ£éæ°éåºç°è´æ°ï¼é置为0ãåå¼: {lockInfo.PickedQty + pickingRecord.PickQuantity}, æ¢å¤æ°é: {pickingRecord.PickQuantity}"); lockInfo.PickedQty = 0; } _logger.LogInformation($"æ¢å¤éå®ä¿¡æ¯ - å·²æ£éæ°éä» {originalPickedQty} åå°å° {lockInfo.PickedQty}"); _logger.LogInformation($"éå®ä¿¡æ¯åé æ°éä¿æä¸å: {originalAssignQty}"); // æ¢å¤éå®ç¶æ if (lockInfo.PickedQty <= 0) { lockInfo.Status = (int)OutLockStockStatusEnum.åºåºä¸; _logger.LogInformation($"éå®ä¿¡æ¯ç¶ææ¢å¤ä¸ºåºåºä¸"); } else if (lockInfo.PickedQty < lockInfo.AssignQuantity) { lockInfo.Status = (int)OutLockStockStatusEnum.åºåºä¸; // é¨åæ£éç¶æ _logger.LogInformation($"éå®ä¿¡æ¯ç¶ææ¢å¤ä¸ºåºåºä¸ï¼é¨åæ£éï¼"); } await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); // 2. æ¢å¤åºåä¿¡æ¯ var stockDetail = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() .FirstAsync(x => x.Barcode == pickingRecord.Barcode); if (stockDetail == null) { throw new InvalidOperationException($"æªæ¾å°å¯¹åºçåºåä¿¡æ¯ï¼æ¡ç : {pickingRecord.Barcode}"); } decimal originalStockQty = stockDetail.StockQuantity; decimal originalOutboundQty = stockDetail.OutboundQuantity; stockDetail.StockQuantity += pickingRecord.PickQuantity; stockDetail.OutboundQuantity -= pickingRecord.PickQuantity; // ç¡®ä¿åºåºæ°éä¸ä¼ä¸ºè´æ° if (stockDetail.OutboundQuantity < 0) { _logger.LogWarning($"åºåºæ°éåºç°è´æ°ï¼é置为0ãåå¼: {stockDetail.OutboundQuantity + pickingRecord.PickQuantity}, æ¢å¤æ°é: {pickingRecord.PickQuantity}"); stockDetail.OutboundQuantity = 0; } _logger.LogInformation($"æ¢å¤åºåä¿¡æ¯ - åºåæ°éä» {originalStockQty} å¢å å° {stockDetail.StockQuantity}"); _logger.LogInformation($"æ¢å¤åºåä¿¡æ¯ - åºåºæ°éä» {originalOutboundQty} åå°å° {stockDetail.OutboundQuantity}"); // æ¢å¤åºåç¶æ if (stockDetail.StockQuantity > 0) { stockDetail.Status = (int)StockStatusEmun.åºåºéå®; _logger.LogInformation($"åºåç¶ææ¢å¤ä¸ºåºåºéå®"); } await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); _logger.LogInformation($"æ¢å¤æ£éæ°æ®å®æ - æ¡ç : {pickingRecord.Barcode}"); return new RevertPickingResult { LockInfo = lockInfo, StockDetail = stockDetail }; } #endregion #region æ°æ®æ´æ°æ¹æ³ private async Task UpdateBatchAndOrderData(Dt_OutboundBatch batch, Dt_OutboundOrderDetail orderDetail, decimal pickedQty, string orderNo) { // æ´æ°æ¹æ¬¡å®ææ°é _logger.LogInformation($"å¼å§æ´æ°æ¹æ¬¡åè®¢åæ°æ® - æ£éæ°é: {pickedQty}"); // éè¦ä¿®å¤ï¼éªè¯åé æ°éä¸ä¼åæè´æ° if (orderDetail.AllocatedQuantity < pickedQty) { throw new InvalidOperationException($"æ´æ°è®¢åæ°æ®æ¶åé æ°éä¸è¶³ï¼éè¦åå° {pickedQty}ï¼å½ååé æ°é {orderDetail.AllocatedQuantity}"); } if (orderDetail.LockQuantity < pickedQty) { throw new InvalidOperationException($"æ´æ°è®¢åæ°æ®æ¶é宿°éä¸è¶³ï¼éè¦åå° {pickedQty}ï¼å½åé宿°é {orderDetail.LockQuantity}"); } // 1. æ´æ°æ¹æ¬¡å®ææ°é decimal originalBatchCompletedQty = batch.CompletedQuantity; batch.CompletedQuantity += pickedQty; _logger.LogInformation($"æ´æ°æ¹æ¬¡å®ææ°é - ä» {originalBatchCompletedQty} å¢å å° {batch.CompletedQuantity}"); if (batch.CompletedQuantity >= batch.BatchQuantity) { batch.BatchStatus = (int)BatchStatusEnum.已宿; _logger.LogInformation($"æ¹æ¬¡ç¶ææ´æ°ä¸ºå·²å®æ"); } await _outboundBatchRepository.Db.Updateable(batch).ExecuteCommandAsync(); // æ´æ°è®¢åæç» // 2. æ´æ°è®¢åæç» decimal originalOverOutQty = orderDetail.OverOutQuantity; decimal originalAllocatedQty = orderDetail.AllocatedQuantity; decimal originalLockQty = orderDetail.LockQuantity; orderDetail.OverOutQuantity += pickedQty; orderDetail.AllocatedQuantity -= pickedQty; // LockQuantity 忥åå° orderDetail.LockQuantity = orderDetail.AllocatedQuantity; _logger.LogInformation($"æ´æ°è®¢åæç» - å·²åºåºæ°éä» {originalOverOutQty} å¢å å° {orderDetail.OverOutQuantity}"); _logger.LogInformation($"æ´æ°è®¢åæç» - å·²åé æ°éä» {originalAllocatedQty} åå°å° {orderDetail.AllocatedQuantity}"); _logger.LogInformation($"æ´æ°è®¢åæç» - é宿°éä» {originalLockQty} åå°å° {orderDetail.LockQuantity}"); await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync(); // æ£æ¥è®¢åç¶æ // 3. æ£æ¥è®¢åç¶æ await CheckAndUpdateOrderStatus(orderNo); _logger.LogInformation($"æ¹æ¬¡åè®¢åæ°æ®æ´æ°å®æ"); } private async Task RevertBatchAndOrderData(Dt_PickingRecord pickingRecord, RevertPickingResult revertResult) { // æ¢å¤æ¹æ¬¡å®ææ°é _logger.LogInformation($"å¼å§æ¢å¤æ¹æ¬¡åè®¢åæ°æ®"); // 1. æ¢å¤æ¹æ¬¡å®ææ°é var batch = await _outboundBatchRepository.Db.Queryable<Dt_OutboundBatch>() .FirstAsync(x => x.BatchNo == revertResult.LockInfo.OutboundBatchNo); // ä½¿ç¨ OutboundBatchNo .FirstAsync(x => x.BatchNo == revertResult.LockInfo.OutboundBatchNo); if (batch != null) { decimal originalCompletedQty = batch.CompletedQuantity; batch.CompletedQuantity -= pickingRecord.PickQuantity; _logger.LogInformation($"æ¢å¤æ¹æ¬¡å®ææ°é - ä» {originalCompletedQty} åå°å° {batch.CompletedQuantity}"); // éæ°è®¡ç®æ¹æ¬¡ç¶æ if (batch.CompletedQuantity <= 0) { batch.BatchStatus = (int)BatchStatusEnum.åé ä¸; _logger.LogInformation($"æ¹æ¬¡ç¶ææ¢å¤ä¸ºåé ä¸"); } else if (batch.CompletedQuantity < batch.BatchQuantity) { batch.BatchStatus = (int)BatchStatusEnum.æ§è¡ä¸; _logger.LogInformation($"æ¹æ¬¡ç¶ææ¢å¤ä¸ºæ§è¡ä¸"); } await _outboundBatchRepository.Db.Updateable(batch).ExecuteCommandAsync(); } // æ¢å¤è®¢åæç» // 2. æ¢å¤è®¢åæç» var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() .FirstAsync(x => x.Id == pickingRecord.OrderDetailId); orderDetail.OverOutQuantity -= pickingRecord.PickQuantity; orderDetail.AllocatedQuantity += pickingRecord.PickQuantity; await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync(); if (orderDetail != null) { decimal originalOverOutQty = orderDetail.OverOutQuantity; decimal originalAllocatedQty = orderDetail.AllocatedQuantity; decimal originalLockQty = orderDetail.LockQuantity; // éæ°æ£æ¥è®¢åç¶æ // éè¦ä¿®å¤ï¼åªæ¢å¤ç¸å ³æ°éï¼åé æ°éä¿æä¸å orderDetail.OverOutQuantity -= pickingRecord.PickQuantity; // 注æï¼AllocatedQuantity å LockQuantity å¨åæ¶åæ£æ¶ä¸åºè¯¥æ¹å _logger.LogInformation($"æ¢å¤è®¢åæç» - å·²åºåºæ°éä» {originalOverOutQty} åå°å° {orderDetail.OverOutQuantity}"); _logger.LogInformation($"订åæç»åé æ°éä¿æä¸å: {originalAllocatedQty}"); _logger.LogInformation($"订åæç»é宿°éä¿æä¸å: {originalLockQty}"); await UpdateBatchAllocateStatus(orderDetail); await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync(); } // 3. éæ°æ£æ¥è®¢åç¶æ await CheckAndUpdateOrderStatus(pickingRecord.OrderNo); _logger.LogInformation($"æ¢å¤æ¹æ¬¡åè®¢åæ°æ®å®æ"); } private async Task UpdateBatchAllocateStatus(Dt_OutboundOrderDetail orderDetail) { if (orderDetail.AllocatedQuantity >= orderDetail.NeedOutQuantity) { orderDetail.BatchAllocateStatus = OrderDetailStatusEnum.AssignOver.ObjToInt(); } else if (orderDetail.AllocatedQuantity > 0) { orderDetail.BatchAllocateStatus = OrderDetailStatusEnum.AssignOverPartial.ObjToInt(); } else { orderDetail.BatchAllocateStatus = OrderDetailStatusEnum.New.ObjToInt(); } } private async Task ReleaseLockAndStock(Dt_OutStockLockInfo lockInfo) { @@ -1326,6 +1981,11 @@ if (orderDetail != null) { orderDetail.AllocatedQuantity -= returnedQty; // LockQuantity 忥åå°ï¼ä¿æä¸å·²åé æ°éä¸è´ orderDetail.LockQuantity = orderDetail.AllocatedQuantity; await UpdateBatchAllocateStatus(orderDetail); await _outboundOrderDetailService.Db.Updateable(orderDetail).ExecuteCommandAsync(); } } @@ -1340,7 +2000,7 @@ return "WSLOT" + DateTime.Now.ToString("yyyyMMdd") + seq.ToString().PadLeft(5, '0'); } private async Task RecordSplitHistory(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, decimal splitQty, string newBarcode) private async Task RecordSplitHistory(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, decimal splitQty, string newBarcode, bool isAutoSplit, decimal? originalStockQuantity = null) { var splitHistory = new Dt_SplitPackageRecord { @@ -1352,7 +2012,11 @@ NewBarcode = newBarcode, SplitQty = splitQty, SplitTime = DateTime.Now, Status = (int)SplitPackageStatusEnum.å·²æå Status = (int)SplitPackageStatusEnum.å·²æå , IsAutoSplit = isAutoSplit , // SplitType = isAutoSplit ? "èªå¨æå " : "æå¨æå " OriginalStockQuantity = originalStockQuantity ?? stockDetail.StockQuantity, //RemainingStockQuantity = stockDetail.StockQuantity - splitQty }; await _splitPackageService.Db.Insertable(splitHistory).ExecuteCommandAsync(); @@ -1414,9 +2078,44 @@ }; } #endregion #region DTOç±» /// <summary> /// æ¡ç ç¶æä¿¡æ¯DTO /// </summary> public class BarcodeStatusInfoDto { public string Barcode { get; set; } public string OrderNo { get; set; } public bool IsOriginalBarcode { get; set; } public int SplitChainCount { get; set; } public bool HasBeenPicked { get; set; } public decimal TotalPickedQuantity { get; set; } public int PickRecordCount { get; set; } public int LockInfoStatus { get; set; } public decimal LockInfoPickedQty { get; set; } public decimal LockInfoAssignQty { get; set; } public decimal StockQuantity { get; set; } public int StockStatus { get; set; } public bool CanCancelSplit { get; set; } public bool NeedCancelPickFirst { get; set; } public List<string> OperationSuggestions { get; set; } = new List<string>(); } public class PickedBarcodeInfo { public string Barcode { get; set; } public decimal PickedQty { get; set; } public int PickRecordCount { get; set; } } /// <summary> /// èªå¨æå ç»æ /// </summary> public class AutoSplitResult { public string NewBarcode { get; set; } public decimal SplitQuantity { get; set; } } public class PickingResult { ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundOrderDetailService.cs
@@ -417,6 +417,7 @@ // æ´æ°æç»çå·²åé æ°é detail.AllocatedQuantity += assignQuantity; detail.LockQuantity = detail.AllocatedQuantity; remainingAllocate -= assignQuantity; allocatedQuantity += assignQuantity; } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundOrderService.cs
@@ -35,6 +35,7 @@ _materialUnitService = materialUnitService; } private int[] OrderTypes = new int[] { InOrderTypeEnum.AllocatOutbound.ObjToInt(), InOrderTypeEnum.InternalAllocat.ObjToInt(), InOrderTypeEnum.ReCheck.ObjToInt() }; public async Task<WebResponseContent> ReceiveOutboundOrder(Dt_OutboundOrder model, int operateType) { try @@ -71,11 +72,11 @@ var moveissueoStockResult = await _materialUnitService.ConvertFromToStockAsync(item.MaterielCode, item.BarcodeUnit, item.BarcodeMoveQty); item.MoveQty = moveissueoStockResult.Quantity; } if (model.OrderType != InOrderTypeEnum.AllocatOutbound.ObjToInt() || model.OrderType != InOrderTypeEnum.InternalAllocat.ObjToInt()) if (!OrderTypes.Contains(model.OrderType)) { model.OrderNo = CreateCodeByRule(nameof(RuleCodeEnum.OutboundOrderRule)); } Db.InsertNav(model).Include(x => x.Details).ExecuteCommand(); return WebResponseContent.Instance.OK(); ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundPickingService.cs
@@ -684,9 +684,7 @@ if (newOverOutQuantity > currentOrderDetail.NeedOutQuantity) { _logger.LogError($"é²è¶ æ£æ£æ¥å¤±è´¥ - OrderDetailId: {orderDetailId}, å·²åºåº: {newOverOutQuantity}, éæ±: {currentOrderDetail.NeedOutQuantity}, æ¬æ¬¡åæ£: {pickedQty}"); decimal adjustedQty = currentOrderDetail.NeedOutQuantity - currentOrderDetail.OverOutQuantity; @@ -695,6 +693,7 @@ _logger.LogWarning($"èªå¨è°æ´åæ£æ°é鲿¢è¶ æ£ï¼ä»{pickedQty}è°æ´ä¸º{adjustedQty}"); newOverOutQuantity = currentOrderDetail.NeedOutQuantity; newPickedQty = currentOrderDetail.PickedQty + adjustedQty; pickedQty = adjustedQty; // æ´æ°å®é æ£éæ°é } else { @@ -702,15 +701,21 @@ } } // æ´æ°è®¢åæç» // æ´æ°è®¢åæç»æ°éåç¶æ await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>() .SetColumns(it => new Dt_OutboundOrderDetail { PickedQty = newPickedQty, OverOutQuantity = newOverOutQuantity, OrderDetailStatus = newOverOutQuantity >= currentOrderDetail.NeedOutQuantity ? OrderDetailStatusEnum.Over.ObjToInt() : OrderDetailStatusEnum.Outbound.ObjToInt() }) .Where(it => it.Id == orderDetailId) .ExecuteCommandAsync(); // æ´æ°é宿°é await UpdateOrderDetailLockQuantity(orderDetailId); // æ£æ¥å¹¶æ´æ°è®¢åç¶æ await CheckAndUpdateOrderStatus(orderNo); @@ -1112,12 +1117,28 @@ if (newPickedQty < 0) throw new Exception($"忶忣å°å¯¼è´å·²æ£éæ°é({newPickedQty})ä¸ºè´æ°"); // ç¡®å®æ°çç¶æ int newStatus; if (newOverOutQuantity >= currentOrderDetail.NeedOutQuantity) { newStatus = OrderDetailStatusEnum.Over.ObjToInt(); } else if (newOverOutQuantity > 0) { newStatus = OrderDetailStatusEnum.Outbound.ObjToInt(); } else { newStatus = OrderDetailStatusEnum.New.ObjToInt(); } // æ´æ°è®¢åæç» var updateResult = await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>() .SetColumns(it => new Dt_OutboundOrderDetail { PickedQty = newPickedQty, OverOutQuantity = newOverOutQuantity OverOutQuantity = newOverOutQuantity, OrderDetailStatus = newStatus }) .Where(it => it.Id == orderDetailId) .ExecuteCommandAsync(); @@ -1125,9 +1146,13 @@ if (updateResult <= 0) throw new Exception("æ´æ°è®¢åæç»å¤±è´¥"); // æ´æ°é宿°é await UpdateOrderDetailLockQuantity(orderDetailId); _logger.LogInformation($"æ´æ°è®¢åæç» - OrderDetailId: {orderDetailId}, " + $"æ£åå·²åºåº: {cancelQty}, æ°å·²åºåº: {newOverOutQuantity}, " + $"æ£åå·²æ£é: {cancelQty}, æ°å·²æ£é: {newPickedQty}"); $"æ£åå·²æ£é: {cancelQty}, æ°å·²æ£é: {newPickedQty}, " + $"æ°ç¶æ: {newStatus}"); } #endregion @@ -1464,6 +1489,7 @@ if (stockDetail != null) { stockDetail.StockQuantity += returnQty; // æ¢å¤åºåç¶æ stockDetail.OutboundQuantity = Math.Max(0, stockDetail.OutboundQuantity - returnQty); stockDetail.Status = StockStatusEmun.å ¥åºç¡®è®¤.ObjToInt(); @@ -1471,6 +1497,7 @@ } else { _logger.LogWarning($"æªæ¾å°å¯¹åºçåºåæç» - æ¡ç : {lockInfo.CurrentBarcode}, åºåID: {lockInfo.StockId}"); // å建æ°çåºåè®°å½ //var newStockDetail = new Dt_StockInfoDetail //{ @@ -1490,7 +1517,34 @@ //}; //await _stockInfoDetailService.Db.Insertable(newStockDetail).ExecuteCommandAsync(); } try { var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() .FirstAsync(x => x.Id == lockInfo.OrderDetailId); if (orderDetail != null) { decimal newLockQuantity = Math.Max(0, orderDetail.LockQuantity - returnQty); await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>() .SetColumns(it => new Dt_OutboundOrderDetail { LockQuantity = newLockQuantity }) .Where(it => it.Id == lockInfo.OrderDetailId) .ExecuteCommandAsync(); _logger.LogInformation($"æ´æ°è®¢åæç»é宿°é - OrderDetailId: {lockInfo.OrderDetailId}, " + $"æ£åéå®: {returnQty}, æ°é宿°é: {newLockQuantity}"); } } catch (Exception ex) { _logger.LogError($"æ´æ°è®¢åæç»é宿°é失败 - OrderDetailId: {lockInfo.OrderDetailId}, Error: {ex.Message}"); } } } private async Task UpdateOrderDetailsOnReturn(List<Dt_OutStockLockInfo> remainingLocks) @@ -1692,13 +1746,25 @@ .ToListAsync(); bool allCompleted = true; bool hasPartial = false; bool hasLocked = false; foreach (var detail in orderDetails) { if (detail.OverOutQuantity < detail.NeedOutQuantity) { allCompleted = false; break; } if (detail.OrderDetailStatus == OrderDetailStatusEnum.Outbound.ObjToInt()) { hasPartial = true; } //if (detail.OrderDetailStatus == OrderDetailStatusEnum.Locked.ObjToInt()) //{ // hasLocked = true; //} } var outboundOrder = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>() @@ -1706,7 +1772,19 @@ if (outboundOrder == null) return; int newStatus = allCompleted ? (int)OutOrderStatusEnum.åºåºå®æ : (int)OutOrderStatusEnum.åºåºä¸; int newStatus; if (allCompleted) { newStatus = (int)OutOrderStatusEnum.åºåºå®æ; } else if (hasPartial ) { newStatus = (int)OutOrderStatusEnum.åºåºä¸; } else { newStatus = (int)OutOrderStatusEnum.æªå¼å§; } if (outboundOrder.OrderStatus != newStatus) { @@ -1719,11 +1797,13 @@ .Where(x => x.OrderNo == orderNo) .ExecuteCommandAsync(); _logger.LogInformation($"订åç¶ææ´æ° - OrderNo: {orderNo}, æ§ç¶æ: {outboundOrder.OrderStatus}, æ°ç¶æ: {newStatus}"); // åªææ£å¸¸åæ£å®ææ¶æåMESåé¦ //if (allCompleted && newStatus == (int)OutOrderStatusEnum.åºåºå®æ) //{ // await HandleOrderCompletion(outboundOrder, orderNo); //} if (allCompleted && newStatus == (int)OutOrderStatusEnum.åºåºå®æ) { await HandleOrderCompletion(outboundOrder, orderNo); } } } catch (Exception ex) @@ -1732,8 +1812,70 @@ } } /// <summary> /// æ´æ°è®¢åæç»ç¶æï¼åºäºå·²åºåºæ°éï¼ /// </summary> private async Task UpdateOrderDetailStatus(int orderDetailId) { var orderDetail = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() .FirstAsync(x => x.Id == orderDetailId); if (orderDetail == null) return; int newStatus = orderDetail.OrderDetailStatus; if (orderDetail.OverOutQuantity >= orderDetail.NeedOutQuantity) { // å·²åºåºæ°é >= éæ±æ°éï¼æ è®°ä¸ºå®æ newStatus = OrderDetailStatusEnum.Over.ObjToInt(); } else if (orderDetail.OverOutQuantity > 0) { // æé¨ååºåºï¼ä½æªå®æ newStatus = OrderDetailStatusEnum.Outbound.ObjToInt(); } else if (orderDetail.LockQuantity > 0) { // æé宿°éï¼ä½æªåºåº //newStatus = OrderDetailStatusEnum.Locked.ObjToInt(); } else { // æ°å»ºç¶æ newStatus = OrderDetailStatusEnum.New.ObjToInt(); } // åªæç¶æåçååæ¶ææ´æ° if (orderDetail.OrderDetailStatus != newStatus) { await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>() .SetColumns(it => new Dt_OutboundOrderDetail { OrderDetailStatus = newStatus, }) .Where(it => it.Id == orderDetailId) .ExecuteCommandAsync(); } } /// <summary> /// æ´æ°è®¢åæç»é宿°é /// </summary> private async Task UpdateOrderDetailLockQuantity(int orderDetailId) { var totalLockedQty = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() .Where(x => x.OrderDetailId == orderDetailId && x.Status == (int)OutLockStockStatusEnum.åºåºä¸) .SumAsync(x => x.AssignQuantity - x.PickedQty); await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>() .SetColumns(it => new Dt_OutboundOrderDetail { LockQuantity = totalLockedQty }) .Where(it => it.Id == orderDetailId) .ExecuteCommandAsync(); } private async Task UpdateOrderStatusForReturn(string orderNo) { try @@ -2581,17 +2723,27 @@ } //å¤æå ¥åºåæ®æç»æ¯å¦å ¨é¨æ¯å®æç¶æ bool inoderOver = inboundOrder.Details.Count() == inboundOrder.Details.Select(x => x.OrderDetailStatus == OrderDetailStatusEnum.Over.ObjToInt()).Count(); int e = inboundOrder.Details.Count(); int w = inboundOrder.Details.Where(x => x.OrderDetailStatus == OrderDetailStatusEnum.Over.ObjToInt()).Count(); bool inoderOver = inboundOrder.Details.Count() == inboundOrder.Details.Where(x => x.OrderDetailStatus == OrderDetailStatusEnum.Over.ObjToInt()).Count(); if (inoderOver) { inboundOrder.OrderStatus = InOrderStatusEnum.å ¥åºå®æ.ObjToInt(); } else { inboundOrder.OrderStatus = InOrderStatusEnum.å ¥åºä¸.ObjToInt(); } //夿åºåºåæ®æç»æ¯å¦å ¨é¨æ¯å®æç¶æ bool outOderOver = outboundOrder.Details.Count() == outboundOrder.Details.Select(x => x.OrderDetailStatus == OrderDetailStatusEnum.Over.ObjToInt()).Count(); bool outOderOver = outboundOrder.Details.Count() == outboundOrder.Details.Where(x => x.OrderDetailStatus == OrderDetailStatusEnum.Over.ObjToInt()).Count(); if (outOderOver) { outboundOrder.OrderStatus = OutOrderStatusEnum.åºåºå®æ.ObjToInt(); } else { outboundOrder.OrderStatus = OutOrderStatusEnum.åºåºä¸.ObjToInt(); } //æ°æ®å¤ç _unitOfWorkManage.BeginTran(); _inboundOrderDetailService.UpdateData(inboundOrderDetails); ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_StockService/StockInfoService.cs
@@ -186,7 +186,7 @@ public List<Dt_StockInfo> GetStockInfos(string materielCode, string lotNo, string supplyCode, List<string> locationCodes) { var query = Db.Queryable<Dt_StockInfo>() .Where(x => locationCodes.Contains(x.LocationCode) .Where(x => locationCodes.Contains(x.LocationCode) && x.StockStatus==StockStatusEmun.å ¥åºå®æ.ObjToInt() // && x.StockStatus == (int)StockStatusEmun.æ£å¸¸) ).Includes(x => x.Details); ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs
@@ -593,6 +593,7 @@ bool allCompleted = true; foreach (var detail in orderDetails) { _logger.LogInformation($"TaskService HandleOutboundOrderToMESCompletion: {outboundOrder.OrderNo} , {detail.NeedOutQuantity}"); if (detail.OverOutQuantity < detail.NeedOutQuantity) { allCompleted = false; @@ -662,7 +663,6 @@ allocatefeedmodel.Details.Add(detailModel); } var result = await _invokeMESService.FeedbackAllocate(allocatefeedmodel); if (result != null && result.code == 200) { @@ -728,7 +728,6 @@ feedmodel.details.Add(detailModel); } var result = await _invokeMESService.FeedbackOutbound(feedmodel); if (result != null && result.code == 200) { ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_Inbound.cs
@@ -32,7 +32,12 @@ Dt_Task dbtask = Repository.Db.Queryable<Dt_Task>().Where(x => x.PalletCode == palletCode).OrderByDescending(x=>x.CreateDate).First(); if (dbtask != null) { if (dbtask.TaskType == TaskTypeEnum.Outbound.ObjToInt() || dbtask.TaskType == TaskTypeEnum.OutAllocate.ObjToInt()) _logger.LogInformation(dbtask.TaskType.ToString()); if (dbtask.TaskType == TaskTypeEnum.Outbound.ObjToInt()) { return WebResponseContent.Instance.Error($"åºåºå¾ 忣任å¡"); } else if (dbtask.TaskType == TaskTypeEnum.OutAllocate.ObjToInt()) { return WebResponseContent.Instance.Error($"åºåºå¾ 忣任å¡"); }