ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/inbound/extend/SelectedStock.vue
@@ -5,7 +5,7 @@ :lazy="true" width="75%" :padding="15" title="åºåºè¯¦æ " title="è°æ¨åºåºè¯¦æ " > <div class="box-head"> <el-alert :closable="false" style="width: 100%"> ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/inbound/extend/StockSelect.vue
@@ -132,11 +132,11 @@ data() { return { row: null, showDetialBox: false, showDetialBox: false, tableData: [], tableColumns: [ { prop: "materielCode", title: "ç©æç¼å·", type: "string", width: 150 }, { prop: "materielName", title: "ç©æåç§°", type: "string", width: 150 }, { prop: "barcode", title: "ç©ææ¡ç ", type: "string", width: 150 }, { prop: "palletCode", title: "æçç¼å·", type: "string", width: 150 }, { prop: "locationCode", title: "è´§ä½ç¼å·", type: "string", width: 180 }, { prop: "useableQuantity", title: "å¯ç¨æ°é", type: "string" }, @@ -201,30 +201,23 @@ if (!valid) return; // æé 请æ±åæ° const keys = this.selection.map((item) => item.id); const requestParams = { taskIds: keys, outboundPlatform: this.outboundForm.selectedPlatform, }; console.log(this.selection) // è°ç¨åºåºæ¥å£ this.http .post("api/Task/GenerateOutboundTasks", requestParams, "æ°æ®å¤çä¸") .then((x) => { if (!x.status) return ElMessage.error(x.message); ElMessage.success("æä½æå"); this.showOutboundDialog = false; this.showDetialBox = false; this.$emit("parentCall", ($vue) => { $vue.getData(); }); }) .catch((error) => { console.error("åºåºè¯·æ±å¤±è´¥:", error); ElMessage.error("请æ±å¤±è´¥ï¼è¯·ç¨åéè¯"); if (this.selection.length <= 0) { return this.$message.error("请å¾é"); } let url = this.pkcx ? "api/Task/GenerateOutboundTask?orderDetailId=" : "api/Task/GenerateOutboundTask?orderDetailId="; this.http .post(url + this.row.id, this.selection, "æ°æ®å¤çä¸") .then((x) => { if (!x.status) return this.$message.error(x.message); this.$message.success("æä½æå"); this.showDetialBox = false; this.$emit("parentCall", ($vue) => { $vue.getData(); }); }); }); }, ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/inbound/extend/allocateOrderDetail.vue
@@ -1,9 +1,10 @@ <template> <div> <div> <vol-box v-model="showDetialBox" :lazy="true" width="75%" height="80%" title="åæ®æç»ä¿¡æ¯" > <div class="box-head"> @@ -27,13 +28,13 @@ @click="handleOpenPicking" >æ£é</el-link> <el-link <!-- <el-link type="primary" size="small" style="float: right; height: 20px; margin-right: 10px" @click="outbound" >ç´æ¥åºåº</el-link > > --> <el-link type="primary" size="small" @@ -362,7 +363,7 @@ } }, { default: () => h(ElForm, { model: formData, model: formData00, rules: { selectedPlatform: [ { required: true, message: 'è¯·éæ©åºåºç«å°', trigger: 'change' } ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/outbound/extend/NoStockOut.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,380 @@ <template> <div> <vol-box v-model="showDetailBox" :lazy="true" width="65%" :padding="20" title="æ åºååºåº" class="custom-vol-box" > <div> <!-- 䏿¹è¾å ¥æ¡ --> <el-form :inline="true" :model="formData" ref="formData" style="margin-bottom: 20px; align-items: flex-end;"> <el-form-item label="æ«ææ¡ç :" style="width: 80%" prop="barcode" > <el-input ref="barcodeInput" v-model="formData.barcode" placeholder="è¯·ä½¿ç¨æ«ç æªæ«ææ¡ç ï¼ææå¨è¾å ¥" @keyup.enter="handleScan" autofocus class="custom-input" ></el-input> </el-form-item> <el-form-item> <el-button type="primary" size="small" @click="handleScan" class="custom-button"> <i class="el-icon-search"></i> ç¡®è®¤æ«æ </el-button> </el-form-item> </el-form> <!-- 䏿¹æ¾ç¤ºæ¡ --> <div class="scan-list"> <el-card shadow="hover" style="margin-bottom: 10px; border: none;" class="custom-card"> <div class="card-header"> <span class="header-title">å·²æ«ææ¡ç å表ï¼å ±{{ scannedBarcodes.length }}æ¡ï¼</span> <el-button class="clear-all-btn" @click="clearAll" :disabled="scannedBarcodes.length === 0" >æ¸ ç©ºææ</el-button> </div> <div class="card-body"> <el-scrollbar height="400px" class="custom-scrollbar"> <!-- ä½¿ç¨ transition-group å 裹以å®ç°å¨ç» --> <transition-group name="barcode-item-transition"> <div class="barcode-item" v-for="(barcode, index) in scannedBarcodes" :key="barcode" :data-index="index"> <span class="barcode-text">{{ index + 1 }}. {{ barcode }}</span> <el-button class="delete-btn" @click="removeItem(index)" >å é¤</el-button> </div> </transition-group> <div class="empty-tip" v-if="scannedBarcodes.length === 0"> <i class="el-icon-information"></i> <span>ææ æ«æè®°å½ï¼è¯·æ«ææ¡ç </span> </div> </el-scrollbar> </div> </el-card> </div> </div> <template #footer> <div class="footer-actions"> <el-button type="primary" size="small" @click="submit" :disabled="scannedBarcodes.length === 0" class="submit-btn"> <i class="el-icon-check"></i> æäº¤åºåº </el-button> <el-button type="text" size="small" @click="showDetailBox = false" class="cancel-btn"> åæ¶ </el-button> </div> </template> </vol-box> </div> </template> <script> import VolBox from "@/components/basic/VolBox.vue"; export default { components: { VolBox }, data() { return { showDetailBox: false, formData: { barcode: "", }, scannedBarcodes: [], }; }, methods: { open() { this.showDetailBox = true; this.scannedBarcodes = []; this.formData.barcode = ""; this.$nextTick(() => { this.$refs.barcodeInput.focus(); }); }, handleScan() { const barcode = this.formData.barcode.trim(); if (!barcode) { this.$refs.barcodeInput.focus(); return; } if (this.scannedBarcodes.includes(barcode)) { this.$message.warning(`æ¡ç ${barcode} å·²æ«æè¿ï¼è¯·å¿é夿«æ`); this.formData.barcode = ""; this.$refs.barcodeInput.focus(); return; } this.scannedBarcodes.push(barcode); this.formData.barcode = ""; this.$nextTick(() => { this.$refs.barcodeInput.focus(); }); }, removeItem(index) { this.scannedBarcodes.splice(index, 1); }, clearAll() { this.$confirm("ç¡®å®è¦æ¸ ç©ºæææ«æè®°å½åï¼", "æç¤º", { confirmButtonText: "ç¡®å®", cancelButtonText: "åæ¶", type: "warning", }).then(() => { this.scannedBarcodes = []; }).catch(() => { this.$refs.barcodeInput.focus(); }); }, submit() { if (this.scannedBarcodes.length === 0) { this.$message.warning("è¯·å æ«æè³å°ä¸æ¡æ¡ç "); this.$refs.barcodeInput.focus(); return; } const params = { barcodes: this.scannedBarcodes, }; this.http .post("/api/OutboundOrder/NoStockOut", params, "æ°æ®å¤çä¸...") .then((res) => { if (!res.status) { this.$message.error(res.message); this.$refs.barcodeInput.focus(); return; } this.$message.success("åºåºæå"); this.showDetailBox = false; this.$emit("parentCall", ($vue) => { $vue.refresh(); }); }) .catch((err) => { this.$message.error(`请æ±å¤±è´¥ï¼${err.message || "æªç¥é误"}`); this.$refs.barcodeInput.focus(); }); }, }, }; </script> <style scoped> /* å ³é®ï¼å®ä¹å表项çè¿æ¸¡å¨ç» */ .barcode-item-transition-enter-active, .barcode-item-transition-leave-active { transition: all 0.3s ease; } .barcode-item-transition-enter-from { opacity: 0; transform: translateY(10px); } .barcode-item-transition-leave-to { opacity: 0; transform: translateX(30px); } /* ç¡®ä¿å 餿¶å ¶ä»å ç´ å¹³æ»ä¸ç§» */ .barcode-item-transition-move { transition: transform 1s ease; } .scan-list { width: 100%; } .custom-card { border-radius: 12px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08) !important; transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); } .custom-card:hover { box-shadow: 0 10px 30px rgba(0, 0, 0, 0.12) !important; } .card-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; padding-bottom: 10px; border-bottom: 1px solid #f0f0f0; } .header-title { font-weight: 600; font-size: 15px; color: #333; } .clear-all-btn { color: #f56c6c; font-size: 13px; transition: color 0.2s; } .clear-all-btn:hover { color: #e53e3e; background: rgba(245, 108, 108, 0.1); } .card-body { padding: 0; } /* èªå®ä¹æ»å¨æ¡ */ .custom-scrollbar ::v-deep .el-scrollbar__thumb { background: rgba(0, 0, 0, 0.2); border-radius: 4px; width: 4px; } .custom-scrollbar ::v-deep .el-scrollbar__bar:hover .el-scrollbar__thumb { background: rgba(0, 0, 0, 0.3); width: 6px; } .custom-scrollbar ::v-deep .el-scrollbar__wrap { overflow-x: hidden; } .barcode-item { display: flex; justify-content: space-between; align-items: center; padding: 10px 15px; border-bottom: 1px solid #f7f7f7; transition: background-color 0.2s ease; } .barcode-item:hover { background-color: #fafafa; } /* ä¸ºå¥æ°è¡æ·»å 轻微çèæ¯è²ï¼å¢å¼ºå¯è¯»æ§ */ .barcode-item:nth-child(odd) { background-color: #e1e1e1; } .barcode-text { flex: 1; font-size: 14px; color: #666; transition: color 0.2s; } .barcode-item:hover .barcode-text { color: #409eff; } .delete-btn { color: #ea1919; font-size: 20px; transition: all 0.2s; transform: scale(0.8); } .barcode-item:hover .delete-btn { opacity: 1; transform: scale(1); } .delete-btn:hover { color: #f56c6c !important; /* ä½¿ç¨ !important è¦ç Element UI é»è®¤æ ·å¼ */ background: rgba(245, 108, 108, 0.1); } .empty-tip { text-align: center; padding: 80px 0; color: #999; font-size: 14px; display: flex; flex-direction: column; align-items: center; justify-content: center; } .empty-tip i { font-size: 40px; margin-bottom: 15px; color: #dcdfe6; } /* èªå®ä¹è¾å ¥æ¡ */ .custom-input ::v-deep .el-input__inner { border-radius: 6px; border-color: #e4e7ed; transition: all 0.3s; height: 36px; line-height: 36px; } .custom-input ::v-deep .el-input__inner:focus { border-color: #409eff; box-shadow: 0 0 0 3px rgba(64, 158, 255, 0.1); } /* èªå®ä¹æé® */ .custom-button { border-radius: 6px; height: 36px; line-height: 36px; font-size: 13px; font-weight: 500; transition: all 0.2s; } .custom-button:hover { transform: translateY(-1px); box-shadow: 0 4px 12px rgba(64, 158, 255, 0.2); } .footer-actions { text-align: right; } .submit-btn { border-radius: 6px; font-weight: 500; padding: 10px 20px; transition: all 0.2s; } .submit-btn:hover { transform: translateY(-1px); box-shadow: 0 4px 12px rgba(46, 164, 79, 0.2); } .cancel-btn { color: #666; margin-right: 10px; transition: color 0.2s; } .cancel-btn:hover { color: #333; background: #f5f5f5; } </style> <style> /* ... (å ¨å±æ ·å¼é¨åä¿æä¸å) ... */ .text-button:hover { background-color: #f0f9eb !important; } .el-table .warning-row { background: oldlace; } .box-table .el-table tbody tr:hover > td { background-color: #d8e0d4 !important; } .box-table .el-table tbody tr.current-row > td { background-color: #f0f9eb !important; } .el-table .success-row { background: #f0f9eb; } .box-table .el-table { border: 1px solid #ebeef5; } .box-head .el-alert__content { width: 100%; } </style> ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/outbound/extend/outOrderDetail.vue
@@ -103,6 +103,7 @@ ref="selectedStock" @parentCall="parentCall" ></selected-stock> <NoStockOut ref="NoStockOut" @parentCall="parentCall"></NoStockOut> </div> </template> <script> @@ -110,10 +111,12 @@ import VolForm from "@/components/basic/VolForm.vue"; import StockSelect from "./StockSelect.vue"; import SelectedStock from "./SelectedStock.vue"; import NoStockOut from "./NoStockOut.vue"; import { h,createVNode, render,reactive } from 'vue'; import { ElDialog , ElForm, ElFormItem, ElSelect,ElOption, ElButton, ElMessage } from 'element-plus'; import { th } from 'element-plus/es/locale'; export default { components: { VolBox, VolForm, StockSelect, SelectedStock }, components: { VolBox, VolForm, StockSelect, SelectedStock,NoStockOut}, data() { return { row: null, @@ -189,7 +192,7 @@ prop: "orderDetailStatus", title: "订åæç»ç¶æ", type: "tag", width: 180, width: 90, bindKey: "orderDetailStatusEnum", }, { @@ -198,6 +201,13 @@ type: "icon", width: 90, icon: "el-icon-s-grid", }, { prop: "NoStockOut", title: "æ åºååºåº", type: "icon", width: 100, icon: "el-icon-setting", }, { prop: "viewDetail", @@ -304,8 +314,10 @@ tableButtonClick(row, column) { if (column.prop == "assignStock") { this.$refs.child.open(row); } else { //ç¹å»æå¼åºåºè¯¦æ } else if (column.prop == "NoStockOut") { this.$refs.NoStockOut.open(row); }else{ //ç¹å»æå¼åºåºè¯¦æ this.$refs.selectedStock.open(row); } }, ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/stock/stockView.js
@@ -1,8 +1,4 @@ //æ¤jsæä»¶æ¯ç¨æ¥èªå®ä¹æ©å±ä¸å¡ä»£ç ï¼å¯ä»¥æ©å±ä¸äºèªå®ä¹é¡µé¢æè éæ°é ç½®çæç代ç import { el } from "element-plus/es/locales.mjs"; let extension = { components: { //æ¥è¯¢ç颿©å±ç»ä»¶ @@ -35,65 +31,65 @@ // }); // } // } this.columns.forEach(column => { if (column.field == 'materielCode') { column.formatter = (row) => { var str = ''; var list = row.materielCode.split(','); for (let index = 0; index < list.length; index++) { str += list[index] + '<br>'; } return str = list[0] == "" ? "空箱" : str; } } if (column.field == 'batchNo') { column.formatter = (row) => { var str = ''; var list = row.batchNo.split(','); for (let index = 0; index < list.length; index++) { str += list[index] + '<br>'; } return str = list[0] == "" ? "æ " : str; } } if (column.field == 'materielInfo') { const today = new Date() column.formatter = (row) => { if (row.details.length > 0) { const today = new Date(); const closestDate = row.details .map(x => { const date = new Date(x.effectiveDate); const diffInDays = Math.ceil(Math.abs((today - date) / (1000 * 60 * 60 * 24))); return { date, diffInDays }; }) .reduce((closest, current) => (current.diffInDays < closest.diffInDays ? current : closest)) .date; // this.columns.forEach(column => { // if (column.field == 'materielCode') { // column.formatter = (row) => { // var str = ''; // var list = row.materielCode.split(','); // for (let index = 0; index < list.length; index++) { // str += list[index] + '<br>'; // } // return str = list[0] == "" ? "空箱" : str; // } // } // if (column.field == 'batchNo') { // column.formatter = (row) => { // var str = ''; // var list = row.batchNo.split(','); // for (let index = 0; index < list.length; index++) { // str += list[index] + '<br>'; // } // return str = list[0] == "" ? "æ " : str; // } // } // if (column.field == 'materielInfo') { // const today = new Date() // column.formatter = (row) => { // if (row.details.length > 0) { // const today = new Date(); // const closestDate = row.details // .map(x => { // const date = new Date(x.effectiveDate); // const diffInDays = Math.ceil(Math.abs((today - date) / (1000 * 60 * 60 * 24))); // return { date, diffInDays }; // }) // .reduce((closest, current) => (current.diffInDays < closest.diffInDays ? current : closest)) // .date; const daysSinceClosest = Math.ceil(Math.abs((today - closestDate) / (1000 * 60 * 60 * 24))); return '<span style="color: #F56C6C">' + daysSinceClosest + "天" + '</span>'; } else { return '<span style="color: #F56C6C">' + "æ ä¿è´¨æ" + '</span>'; } // const daysSinceClosest = Math.ceil(Math.abs((today - closestDate) / (1000 * 60 * 60 * 24))); // return '<span style="color: #F56C6C">' + daysSinceClosest + "天" + '</span>'; // } else { // return '<span style="color: #F56C6C">' + "æ ä¿è´¨æ" + '</span>'; // } } } if (column.field == 'sumStock') { column.formatter = (row) => { if (row.details.length > 0) { var sum = 0; const closestDate = row.details .map(x => { sum += (x.stockQuantity) }) return '<span style="color: #F56C6C">' + sum + row.details[0].unit + '</span>'; } else { return '<span style="color: #F56C6C">' + "1个" + '</span>'; } // } // } // if (column.field == 'sumStock') { // column.formatter = (row) => { // if (row.details.length > 0) { // var sum = 0; // const closestDate = row.details // .map(x => { // sum += (x.stockQuantity) // }) // return '<span style="color: #F56C6C">' + sum + row.details[0].unit + '</span>'; // } else { // return '<span style="color: #F56C6C">' + "1个" + '</span>'; // } } } }) // } // } // }) }, onInited() { //æ¡æ¶åå§åé ç½®å ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/views/outbound/PickingConfirm.vue
@@ -28,7 +28,7 @@ <el-button type="success" @click="confirmPicking">确认æ£é</el-button> <!-- <el-button type="warning" @click="openSplitDialog">æå </el-button> <el-button type="info" @click="openRevertSplitDialog">æ¤éæå </el-button> --> <el-button type="info" @click="handleEmptyPallet">å空箱</el-button> <el-button type="primary" @click="openBatchReturnDialog">ååº</el-button> <!-- <el-button type="danger" @click="handleDirectOutbound">ç´æ¥åºåº</el-button> --> @@ -250,6 +250,49 @@ </div> </div> </div> <!-- å走空箱--> <div v-if="showEmptyPalletDialog" class="custom-dialog-overlay"> <div class="custom-dialog-wrapper"> <div class="custom-dialog"> <div class="custom-dialog-header"> <h3>å走空箱</h3> <el-button type="text" @click="closeEmptyPalletDialog" class="close-button"> à </el-button> </div> <div class="custom-dialog-body"> <el-form :model="emptypalletOutForm" :rules="emptypalletOutFormRules" ref="emptypalletOutFormRef" label-width="100px"> <el-form-item label="订åç¼å·"> <el-input v-model="emptypalletOutForm.orderNo" disabled></el-input> </el-form-item> <el-form-item label="æçç¼å·" prop="palletCode"> <el-input v-model="emptypalletOutForm.palletCode" placeholder="æ«ææçç " @keyup.enter.native="onEmptyPalletScan" @change="onEmptyPalletScan" clearable> </el-input> </el-form-item> </el-form> </div> <div class="custom-dialog-footer"> <el-button @click="closeEmptyPalletDialog">åæ¶</el-button> <el-button type="primary" @click="handleEmptyPalletConfirm" :loading="emptypalletOutLoading">确认å走空箱</el-button> </div> </div> </div> </div> </div> <!-- ç´æ¥åºåºå¼¹çª --> <div v-if="showDirectOutDialog" class="custom-dialog-overlay"> <div class="custom-dialog-wrapper"> @@ -290,7 +333,7 @@ </div> </div> </div> </div> <print-view ref="childs" @parentcall="parentcall"></print-view> </template> @@ -431,6 +474,20 @@ { required: true, validator: validateDirectOutPalletCode, trigger: 'blur' } ] }, showEmptyPalletDialog: false, // åèµ°ç©ºç®±å¼¹çªæ¾ç¤ºç¶æ emptypalletOutLoading: false, // å走空箱å è½½ç¶æ emptypalletOutForm: { orderNo: '', palletCode: '' }, emptypalletOutFormRules: { palletCode: [ { required: true, validator: validateDirectOutPalletCode, trigger: 'blur' } ] }, returnForm: { orderNo: '', palletCode: '', @@ -708,6 +765,109 @@ handleDirectOutbound() { this.openDirectOutDialog(); }, // æå¼åèµ°ç©ºç®±å¼¹çª openEmptyPalletDialog() { console.log('æå¼å走空箱弹çª'); this.showEmptyPalletDialog = true; // é置表å this.resetEmptyPalletForm(); // 设置订åä¿¡æ¯ this.emptypalletOutForm.orderNo = this.scanData.orderNo; // æ¸ é¤è¡¨åéªè¯ this.$nextTick(() => { if (this.$refs.emptyPalletFormRef) { this.$refs.emptyPalletFormRef.clearValidate(); } }); }, // å ³éåèµ°ç©ºç®±å¼¹çª closeEmptyPalletDialog() { this.showEmptyPalletDialog = false; this.resetEmptyPalletForm(); // æ¸ é¤è¡¨åéªè¯ if (this.$refs.emptyPalletFormRef) { this.$refs.emptyPalletFormRef.clearValidate(); } }, // å走空箱æçç æ«ç onEmptyPalletScan() { if (!this.emptypalletOutForm.palletCode) return; this.emptypalletOutForm.palletCode = this.emptypalletOutForm.palletCode.replace(/\n/g, '').trim(); // æ¸ é¤éªè¯ç¶æ if (this.$refs.emptyPalletFormRef) { this.$refs.emptyPalletFormRef.clearValidate(['palletCode']); } }, // å走空箱确认 async handleEmptyPalletConfirm() { // 表åéªè¯ if (this.$refs.emptyPalletFormRef) { this.$refs.emptyPalletFormRef.validate((valid) => { if (valid) { this.submitEmptyPallet(); } else { this.$message.warning('è¯·æ«ææçç '); return false; } }); } else { // å¦ææ²¡æè¡¨åå¼ç¨ï¼ä½¿ç¨åæçéªè¯ if (!this.emptypalletOutForm.palletCode) { this.$message.warning('è¯·æ«ææçç '); return; } this.submitEmptyPallet(); } }, // æäº¤åèµ°ç©ºç®±è¯·æ± async submitEmptyPallet() { this.emptypalletOutLoading = true; try { const res = await this.http.post('/api/OutboundPicking/remove-empty-pallet', { orderNo: this.emptypalletOutForm.orderNo, palletCode: this.emptypalletOutForm.palletCode }); debugger; if (res.status) { this.$message.success('å走空箱æå'); this.showEmptyPalletDialog = false; this.loadData(); } else { this.$message.error(res.message || 'å走空箱失败'); } } catch (error) { this.$message.error('å走空箱失败'); } finally { this.emptypalletOutLoading = false; } }, // éç½®å走空箱表å resetEmptyPalletForm() { this.emptypalletOutForm.palletCode = ''; }, // ä¿®æ¹åæçå走空箱æé®ç¹å»äºä»¶ handleEmptyPallet() { this.openEmptyPalletDialog(); }, async loadData() { if (!this.scanData.orderNo || !this.scanData.palletCode) { return; ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/views/stock/stockView.vue
@@ -27,18 +27,12 @@ sortName: "stockId", }); const editFormFields = ref({ palletCode: "", locationCode: "", locationName: "", }); const editFormOptions = ref([ ]); const searchFormFields = ref({ palletCode: "", // locationCode: "", materielCode:"", batchNo:"" }); const searchFormOptions = ref([ [ @@ -69,7 +63,7 @@ title: "æçç¼å·", type: "string", width: 150, link: true, // link: true, align: "left", }, { @@ -92,7 +86,6 @@ type: "string", width: 80, align: "left", bind: { key: "warehouses", data: [] }, }, { field: "roadwayNo", @@ -110,90 +103,13 @@ align: "left", }, { field: "batchNo", title: "æå«ç©ææ¹æ¬¡", type: "string", width: 200, align: "left" }, { field: "materielInfo", title: "æå«ç©æææ©ä¸´æ", type: "string", width: 140, align: "left", }, { field: "sumStock", title: "æ»åºå", type: "string", width: 140, align: "left", }, { field: "row", title: "è´§ä½è¡", type: "string", width: 90, align: "left", hidden: true, }, { field: "column", title: "è´§ä½å", type: "int", width: 120, align: "left", hidden: true, }, { field: "layer", title: "è´§ä½å±", type: "string", width: 200, align: "left", hidden: true, }, { field: "depth", title: "è´§ä½æ·±åº¦", type: "string", width: 180, align: "left", hidden: true, }, { field: "stockStatus", title: "åºåç¶æ", type: "string", width: 200, align: "left", bind: { key: "stockStatusEmun", data: [] }, }, { field: "locationType", title: "è´§ä½ç±»å", type: "string", width: 100, align: "left", bind:{key: "locationTypeEnum", data: []} }, { field: "locationStatus", title: "è´§ä½ç¶æ", type: "string", width: 120, align: "left", bind: { key: "locationStatusEnum", data: [] }, }, { field: "enalbeStatus", title: "ç¦ç¨ç¶æ", type: "string", width: 80, align: "left", bind: { key: "enableStatusEnum", data: [] }, }, { field: "creater", title: "å建人", @@ -235,143 +151,7 @@ cnName: "åºåæç»ä¿¡æ¯", table: "StockInfoDetail", columns: [ { field: "id", title: "Id", type: "int", width: 90, hidden: true, readonly: true, require: true, align: "left", }, { field: "stockId", title: "åºåä¿¡æ¯ä¸»é®", type: "string", width: 90, align: "left", hidden: true }, { field: "materielCode", title: "ç©æç¼å·", type: "string", width: 110, align: "left", }, { field: "materielName", title: "ç©æåç§°", type: "string", width: 130, align: "left", }, { field: "orderNo", title: "åæ®ç¼å·", type: "decimal", width: 130, align: "left", }, { field: "batchNo", title: "æ¹æ¬¡å·", type: "string", width: 180, align: "left", }, { field: "serialNumber", title: "åºåå·", type: "int", width: 120, align: "left", hidden: true, }, { field: "stockQuantity", title: "åºåæ°é", type: "string", width: 80, align: "left", }, { field: "outboundQuantity", title: "åºåºæ°é", type: "string", width: 80, align: "left", }, { field: "unit", title: "åä½", type: "string", width: 50, align: "left", }, { field: "productionDate", title: "çäº§æ¥æ", type: "string", width: 80, align: "left", }, { field: "effectiveDate", title: "æææ¥æ", type: "string", width: 80, align: "left", }, { field: "status", title: "åºåæç»ç¶æ", type: "string", width: 120, align: "left", bind: { key: "stockStatusEmun", data: [] } }, { field: "creater", title: "å建人", type: "string", width: 90, align: "left", hidden: true }, { field: "createDate", title: "å建æ¶é´", type: "datetime", width: 160, align: "left", hidden: true }, { field: "modifier", title: "ä¿®æ¹äºº", type: "string", width: 100, align: "left", hidden: true }, { field: "modifyDate", title: "ä¿®æ¹æ¶é´", type: "datetime", width: 160, align: "left", hidden: true }, { field: "remark", title: "夿³¨", type: "string", width: 100, align: "left", hidden: true }, ], sortName: "id", key: "id", ÏîÄ¿´úÂë/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/LocationInfoService.cs
@@ -189,6 +189,10 @@ if (first != null) { locationCaches.Add(new LocationCache { LocationCode = first.LocationCode, DateTime = DateTime.Now }); Db.Updateable<Dt_LocationInfo>().SetColumns(x => new Dt_LocationInfo { LocationStatus = (int)LocationStatusEnum.InStockLock, }).Where(x => x.Id == first.Id).ExecuteCommand(); } return first; ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_DTO/Outbound/OutboundOrderAddDTO.cs
@@ -92,6 +92,8 @@ /// </summary> public string orderNo { get; set; } public string documentsNO { get; set; } public string business_type { get; set; } public int status { get; set; } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_DTO/Stock/StockSelectViewDTO.cs
@@ -19,6 +19,7 @@ public string LocationCode { get; set; } public string Barcode { get; set; } } } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_DTO/Stock/StockViewDTO.cs
@@ -22,11 +22,13 @@ /// <summary> /// è´§ä½ç¼å· /// </summary> [SugarColumn(Length = 255, ColumnDescription = "è´§ä½ç¼å·")] public string LocationCode { get; set; } /// <summary> /// è´§ä½åç§° /// </summary> [SugarColumn(Length = 255, ColumnDescription = "è´§ä½åç§°")] public string LocationName { get; set; } /// <summary> @@ -62,6 +64,7 @@ /// <summary> /// å··éç¼å· /// </summary> [SugarColumn(Length = 255, ColumnDescription = "å··éç¼å·")] public string RoadwayNo { get; set; } /// <summary> @@ -77,6 +80,7 @@ /// <summary> /// æçå· /// </summary> [SugarColumn(Length = 255, ColumnDescription = "æçå·")] public string PalletCode { get; set; } /// <summary> @@ -87,11 +91,13 @@ /// <summary> /// ç©æç¼ç /// </summary> [SugarColumn(Length = 255, ColumnDescription = "ç©æç¼ç ")] public string MaterielCode { get; set; } /// <summary> /// ç©ææ¹å· /// </summary> [SugarColumn(Length = 255, ColumnDescription = "ç©ææ¹å·")] public string BatchNo { get; set; } /// <summary> ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_IOutboundService/IOutboundPickingService.cs
@@ -24,5 +24,7 @@ Task<WebResponseContent> CancelPicking(string orderNo, string palletCode, string barcode); Task<WebResponseContent> ConfirmPicking(string orderNo, string palletCode, string barcode); Task<WebResponseContent> ReturnRemaining(string orderNo, string palletCode, string reason); Task<WebResponseContent> RemoveEmptyPallet(string orderNo, string palletCode); } } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundOrderDetailService.cs
@@ -299,7 +299,7 @@ if (!checkResult.Item1) throw new Exception(checkResult.Item2); Dt_OutboundOrder outboundOrder = _outboundOrderService.Repository.QueryFirst(x => x.Id == outboundOrderDetail.OrderId); var originalNeedQuantity = outboundOrderDetail.OrderQuantity - outboundOrderDetail.LockQuantity; var originalNeedQuantity = outboundOrderDetail.OrderQuantity - outboundOrderDetail.LockQuantity-outboundOrderDetail.MoveQty; var needQuantity = originalNeedQuantity; @@ -352,10 +352,10 @@ { return (false, "该æç»ä¸å¯æä½"); } if (stockSelectViews.Sum(x => x.UseableQuantity) > outboundOrderDetail.OrderQuantity - outboundOrderDetail.LockQuantity) { return (false, "éæ©æ°éè¶ åºåæ®æ°é"); } //if (stockSelectViews.Sum(x => x.UseableQuantity) > outboundOrderDetail.OrderQuantity - outboundOrderDetail.LockQuantity - outboundOrderDetail.MoveQty) //{ // return (false, "éæ©æ°éè¶ åºåæ®æ°é"); //} return (true, "æå"); } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundPickingService.cs
@@ -10,6 +10,7 @@ using System.Text; using System.Text.Json; using System.Threading.Tasks; using WIDESEA_Common.CommonEnum; using WIDESEA_Common.LocationEnum; using WIDESEA_Common.OrderEnum; using WIDESEA_Common.StockEnum; @@ -17,6 +18,7 @@ using WIDESEA_Core; using WIDESEA_Core.BaseRepository; using WIDESEA_Core.BaseServices; using WIDESEA_Core.Enums; using WIDESEA_Core.Helper; using WIDESEA_DTO.Basic; using WIDESEA_DTO.Inbound; @@ -86,6 +88,8 @@ _dailySequenceService = dailySequenceService; } #region æ¥è¯¢æ¹æ³ // è·åæªæ£éå表 public async Task<List<Dt_OutStockLockInfo>> GetUnpickedList(string orderNo, string palletCode) { @@ -148,6 +152,8 @@ return summary; } #endregion #region æ ¸å¿ä¸å¡æµç¨ /// <summary> /// æ£é @@ -161,7 +167,7 @@ try { _unitOfWorkManage.BeginTran(); var validationResult = await ValidatePickingRequest(orderNo, palletCode, barcode); if (!validationResult.IsValid) return WebResponseContent.Instance.Error(validationResult.ErrorMessage); @@ -252,11 +258,11 @@ { _unitOfWorkManage.BeginTran(); // 1. åºç¡éªè¯ if (string.IsNullOrEmpty(orderNo) || string.IsNullOrEmpty(palletCode)) return WebResponseContent.Instance.Error("订åå·åæçç ä¸è½ä¸ºç©º"); // 2. è·ååºååä»»å¡ä¿¡æ¯ // è·ååºååä»»å¡ä¿¡æ¯ var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>().FirstAsync(x => x.PalletCode == palletCode); if (stockInfo == null) @@ -266,23 +272,34 @@ if (task == null) return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºçä»»å¡ä¿¡æ¯"); // 3. åæéè¦ååºçè´§ç© var returnAnalysis = await AnalyzeReturnItems(orderNo, palletCode, stockInfo.Id); if (!returnAnalysis.HasItemsToReturn) return await HandleNoReturnItems(orderNo, palletCode,task); //åæéè¦ååºçè´§ç© //var returnAnalysis = await AnalyzeReturnItems(orderNo, palletCode, stockInfo.Id); //if (!returnAnalysis.HasItemsToReturn) // return await HandleNoReturnItems(orderNo, palletCode, task); // 4. æ§è¡ååºæä½ await ExecuteReturnOperations(orderNo, palletCode, stockInfo, task, returnAnalysis); var statusAnalysis = await AnalyzePalletStatus(orderNo, palletCode, stockInfo.Id); if (!statusAnalysis.HasItemsToReturn) return await HandleNoReturnItems(orderNo, palletCode, task, stockInfo.Id); // 5. å建ååºä»»å¡ await CreateReturnTaskAndHandleESS(orderNo, palletCode, task, returnAnalysis); // 4. æ£æ¥æ¯å¦æè¿è¡ä¸çä»»å¡ if (statusAnalysis.HasActiveTasks) { return WebResponseContent.Instance.Error($"æç {palletCode} æè¿è¡ä¸çä»»å¡ï¼ä¸è½æ§è¡ååºæä½"); } //æ§è¡ååºæä½ await ExecuteReturnOperations(orderNo, palletCode, stockInfo, task, statusAnalysis); _unitOfWorkManage.CommitTran(); // 6. æ´æ°è®¢åç¶æï¼ä¸è§¦åMESåä¼ ï¼ // å建ååºä»»å¡ await CreateReturnTaskAndHandleESS(orderNo, palletCode, task, TaskTypeEnum.InPick); // æ´æ°è®¢åç¶æï¼ä¸è§¦åMESåä¼ ï¼ await UpdateOrderStatusForReturn(orderNo); return WebResponseContent.Instance.OK($"ååºæä½æåï¼å ±ååºæ°éï¼{returnAnalysis.TotalReturnQty}"); return WebResponseContent.Instance.OK($"ååºæä½æåï¼å ±ååºæ°éï¼{statusAnalysis.TotalReturnQty}"); } catch (Exception ex) { @@ -292,6 +309,71 @@ } } /// <summary> /// 空æçåèµ°æ¥å£ï¼å¸¦è®¢åå·ï¼ /// éªè¯æçæ¯å¦ççä¸ºç©ºï¼æ¸ çæ°æ®ï¼æ´æ°è®¢åç¶æï¼å建åæçä»»å¡ /// </summary> public async Task<WebResponseContent> RemoveEmptyPallet(string orderNo, string palletCode) { try { _unitOfWorkManage.BeginTran(); if (string.IsNullOrEmpty(orderNo) || string.IsNullOrEmpty(palletCode)) return WebResponseContent.Instance.Error("订åå·åæçç ä¸è½ä¸ºç©º"); // æ£æ¥è®¢åæ¯å¦åå¨ var order = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>() .Where(x => x.OrderNo == orderNo) .FirstAsync(); if (order == null) return WebResponseContent.Instance.Error($"æªæ¾å°è®¢å {orderNo}"); //æ£æ¥æçæ¯å¦åå¨ä¸å±äºè¯¥è®¢å var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>() .Where(x => x.PalletCode == palletCode) .FirstAsync(); if (stockInfo == null) return WebResponseContent.Instance.Error($"æªæ¾å°æç {palletCode} 对åºçåºåä¿¡æ¯"); var statusAnalysis = await AnalyzePalletStatus(orderNo, palletCode, stockInfo.Id); if (!statusAnalysis.CanRemove) { if (!statusAnalysis.IsEmptyPallet) { return WebResponseContent.Instance.Error($"æç {palletCode} ä¸è¿æè´§ç©ï¼ä¸è½åèµ°"); } if (statusAnalysis.HasActiveTasks) { return WebResponseContent.Instance.Error($"æç {palletCode} è¿æè¿è¡ä¸çä»»å¡ï¼ä¸è½åèµ°"); } } // æ¸ çé¶åºåæ°æ® await CleanupZeroStockData(stockInfo.Id); // å 餿忶ç¸å ³ä»»å¡ await HandleTaskCleanup(orderNo, palletCode); // æ´æ°è®¢åç¸å ³æ°æ® await UpdateOrderData(orderNo, palletCode); _unitOfWorkManage.CommitTran(); _logger.LogInformation($"空æçåèµ°æä½æå - 订å: {orderNo}, æç: {palletCode}, æä½äºº: {App.User.UserName}"); return WebResponseContent.Instance.OK("空æçåèµ°æä½æå"); } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); _logger.LogError($"RemoveEmptyPallet失败 - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}"); return WebResponseContent.Instance.Error($"空æçå走失败: {ex.Message}"); } } #endregion #region åæ£ç¡®è®¤ç§ææ¹æ³ @@ -367,7 +449,7 @@ { // æ¥æ¾åä¸è®¢åä¸çè®°å½ lockInfo = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() .Where(it => it.OrderNo == orderNo && it.CurrentBarcode == barcode && it.Status == (int)OutLockStockStatusEnum.åºåºä¸ && it.AssignQuantity > it.PickedQty).FirstAsync(); .Where(it => it.OrderNo == orderNo && it.CurrentBarcode == barcode && it.Status == (int)OutLockStockStatusEnum.åºåºä¸ && it.AssignQuantity > it.PickedQty).FirstAsync(); if (lockInfo == null) { @@ -436,7 +518,7 @@ adjustedReason = adjustedReason != null ? $"{adjustedReason}ï¼é²è¶ æ£éå¶ï¼æç»è°æ´ä¸º{actualQty}" : $"é²è¶ æ£éå¶ï¼ä»{plannedQty}è°æ´ä¸º{actualQty}"; } } if (adjustedReason != null) { @@ -501,30 +583,34 @@ { decimal remainingStockQty = stockQuantity - actualQty; // 1. æ´æ°åæ¡ç åºå // æ´æ°åæ¡ç åºå stockDetail.StockQuantity = remainingStockQty; stockDetail.OutboundQuantity = remainingStockQty; await _stockInfoDetailService.Db.Updateable(stockDetail).ExecuteCommandAsync(); // 2. çææ°æ¡ç //çææ°æ¡ç string newBarcode = await GenerateNewBarcode(); // 3. å建æ°éå®ä¿¡æ¯ //å建æ°éå®ä¿¡æ¯ var newLockInfo = await CreateSplitLockInfo(lockInfo, actualQty, newBarcode); // 4. è®°å½æå åå² // è®°å½æå åå² await RecordSplitHistory(lockInfo, stockDetail, actualQty, remainingStockQty, newBarcode); // 5. æ´æ°åéå®ä¿¡æ¯ // æ´æ°åéå®ä¿¡æ¯ lockInfo.AssignQuantity = remainingStockQty; lockInfo.PickedQty = 0; lockInfo.Operator = App.User.UserName; await _outStockLockInfoService.Db.Updateable(lockInfo).ExecuteCommandAsync(); // 6. è®¾ç½®ç»æ // è®¾ç½®ç»æ result.FinalLockInfo = newLockInfo; result.FinalBarcode = newBarcode; result.SplitResults.AddRange(CreateSplitResults(lockInfo, actualQty, remainingStockQty, newBarcode, stockDetail.Barcode)); await UpdateOrderRelatedData(lockInfo.OrderDetailId, actualQty, lockInfo.OrderNo); _logger.LogInformation($"æå åæ£æ´æ°è®¢åæç» - OrderDetailId: {lockInfo.OrderDetailId}, 忣æ°é: {actualQty}"); } private async Task HandleFullPicking(Dt_OutStockLockInfo lockInfo, Dt_StockInfoDetail stockDetail, @@ -578,10 +664,10 @@ if (newOverOutQuantity > currentOrderDetail.NeedOutQuantity) { _logger.LogError($"é²è¶ æ£æ£æ¥å¤±è´¥ - OrderDetailId: {orderDetailId}, å·²åºåº: {newOverOutQuantity}, éæ±: {currentOrderDetail.NeedOutQuantity}, æ¬æ¬¡åæ£: {pickedQty}"); decimal adjustedQty = currentOrderDetail.NeedOutQuantity - currentOrderDetail.OverOutQuantity; if (adjustedQty > 0) @@ -673,7 +759,7 @@ if (lockInfo == null) return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error("æªæ¾å°å¯¹åºçåºåºéå®ä¿¡æ¯"); if (lockInfo.PickedQty < pickingRecord.PickQuantity) { return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error( @@ -715,8 +801,8 @@ { return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Error($"æ¡ç {barcode}å·²ç»ååºï¼ä¸è½åæ¶åæ£"); } } } return ValidationResult<(Dt_PickingRecord, Dt_OutStockLockInfo, Dt_OutboundOrderDetail)>.Success((pickingRecord, lockInfo, orderDetail)); } /// <summary> @@ -846,6 +932,8 @@ await _outStockLockInfoService.Db.Deleteable<Dt_OutStockLockInfo>() .Where(x => x.Id == lockInfo.Id) .ExecuteCommandAsync(); await UpdateOrderDetailOnCancel(pickingRecord.OrderDetailId, cancelQty); } private async Task HandleNormalBarcodeCancel(Dt_OutStockLockInfo lockInfo, Dt_PickingRecord pickingRecord, decimal cancelQty) @@ -942,59 +1030,7 @@ return task; } private async Task<ReturnAnalysisResult> AnalyzeReturnItems(string orderNo, string palletCode, int stockId) { var result = new ReturnAnalysisResult(); // æ åµ1ï¼è·åæªåæ£çåºåºéå®è®°å½ var remainingLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() .Where(it => it.OrderNo == orderNo && it.PalletCode == palletCode && it.Status == (int)OutLockStockStatusEnum.åºåºä¸) .ToListAsync(); if (remainingLocks.Any()) { result.HasRemainingLocks = true; result.RemainingLocks = remainingLocks; result.RemainingLocksReturnQty = remainingLocks.Sum(x => x.AssignQuantity - x.PickedQty); } // æ åµ2ï¼æ£æ¥æç䏿¯å¦æå ¶ä»åºåè´§ç© var palletStockGoods = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() .Where(it => it.StockId == stockId && (it.Status == StockStatusEmun.å ¥åºç¡®è®¤.ObjToInt() || it.Status == StockStatusEmun.å ¥åºå®æ.ObjToInt() || it.Status == StockStatusEmun.åºåºéå®.ObjToInt())) .Where(it => it.StockQuantity > 0) .ToListAsync(); if (palletStockGoods.Any()) { result.HasPalletStockGoods = true; result.PalletStockGoods = palletStockGoods; result.PalletStockReturnQty = palletStockGoods.Sum(x => x.StockQuantity); } // æ åµ3ï¼æ£æ¥æå è®°å½ var splitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>() .Where(it => it.OrderNo == orderNo && it.PalletCode == palletCode && !it.IsReverted && it.Status != (int)SplitPackageStatusEnum.å·²ååº) .ToListAsync(); if (splitRecords.Any()) { result.HasSplitRecords = true; result.SplitRecords = splitRecords; result.SplitReturnQty = await CalculateSplitReturnQuantity(splitRecords, stockId); } result.TotalReturnQty = result.RemainingLocksReturnQty + result.PalletStockReturnQty + result.SplitReturnQty; result.HasItemsToReturn = result.TotalReturnQty > 0; return result; } private async Task<decimal> CalculateSplitReturnQuantity(List<Dt_SplitPackageRecord> splitRecords, int stockId) { decimal totalQty = 0; @@ -1034,40 +1070,74 @@ return totalQty; } private async Task<WebResponseContent> HandleNoReturnItems(string orderNo, string palletCode,Dt_Task originalTask) private async Task<WebResponseContent> HandleNoReturnItems(string orderNo, string palletCode, Dt_Task originalTask, int stockInfoId) { // æ£æ¥æ¯å¦ææè´§ç©é½å·²æ£é宿 var allPicked = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() .Where(it => it.OrderNo == orderNo && it.PalletCode == palletCode) .AnyAsync(it => it.Status == (int)OutLockStockStatusEnum.æ£é宿); //var allPicked = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() // .Where(it => it.OrderNo == orderNo && it.PalletCode == palletCode) // .AnyAsync(it => it.Status == (int)OutLockStockStatusEnum.æ£é宿); if (allPicked) //if (allPicked) //{ // // å é¤åå§åºåºä»»å¡ ç»ç©ºç 空çååº // //await _taskRepository.Db.Deleteable(originalTask).ExecuteCommandAsync(); // return WebResponseContent.Instance.OK("ææè´§ç©å·²æ£éå®æï¼æç为空"); //} //else //{ // // å é¤åå§åºåºä»»å¡ // //await _taskRepository.Db.Deleteable(originalTask).ExecuteCommandAsync(); // return WebResponseContent.Instance.Error("没æéè¦ååºçå©ä½è´§ç©"); //} try { // å é¤åå§åºåºä»»å¡ await _taskRepository.Db.Deleteable(originalTask).ExecuteCommandAsync(); return WebResponseContent.Instance.OK("ææè´§ç©å·²æ£éå®æï¼æç为空"); var locationtype = 0; var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>() .Where(x => x.PalletCode == palletCode) .FirstAsync(); if (stockInfo == null) { var firstLocation = await _locationInfoService.Db.Queryable<Dt_LocationInfo>().FirstAsync(x => x.LocationCode == originalTask.SourceAddress); locationtype = firstLocation?.LocationType ?? 1; } else { locationtype = stockInfo.LocationType; } var targetAddress = originalTask.TargetAddress; await CleanupZeroStockData(stockInfoId); var emptystockInfo = new Dt_StockInfo() { PalletType = PalletTypeEnum.Empty.ObjToInt(), StockStatus = StockStatusEmun.ç»çæå.ObjToInt(), PalletCode = palletCode, LocationType = locationtype }; emptystockInfo.Details = new List<Dt_StockInfoDetail>(); _stockInfoService.AddMaterielGroup(emptystockInfo); //空æçå¦ä½å¤ç è¿æä¸ä¸ªåºåºä»»å¡è¦å¤çã originalTask.PalletType = PalletTypeEnum.Empty.ObjToInt(); await CreateReturnTaskAndHandleESS(orderNo, palletCode, originalTask, TaskTypeEnum.InEmpty); } else catch (Exception ex) { // å é¤åå§åºåºä»»å¡ await _taskRepository.Db.Deleteable(originalTask).ExecuteCommandAsync(); return WebResponseContent.Instance.Error("没æéè¦ååºçå©ä½è´§ç©"); _logger.LogError($" HandleNoReturnItems 失败: {ex.Message}"); return WebResponseContent.Instance.Error($" ååºç©ºæç失败ï¼"); } //空æçå¦ä½å¤ç è¿æä¸ä¸ªåºåºä»»å¡è¦å¤çã return WebResponseContent.Instance.OK("空æçååºä»»å¡å建æå"); } private async Task ExecuteReturnOperations(string orderNo, string palletCode, Dt_StockInfo stockInfo, Dt_Task task, ReturnAnalysisResult analysis) Dt_Task task, PalletStatusAnalysis analysis) { // æ åµ1ï¼å¤çæªåæ£çåºåºéå®è®°å½ if (analysis.HasRemainingLocks) { await HandleRemainingLocksReturn(analysis.RemainingLocks, stockInfo.Id); // å ³é®ï¼æ´æ°è®¢åæç»çå·²æ£éæ°é await UpdateOrderDetailsOnReturn(analysis.RemainingLocks); } // await UpdateOrderDetailsOnReturn(analysis.RemainingLocks); } // å¤çæçä¸å ¶ä»åºåè´§ç© if (analysis.HasPalletStockGoods) @@ -1177,9 +1247,9 @@ foreach (var stockGood in palletStockGoods) { _logger.LogInformation($"å¾ ååºè´§ç© - æ¡ç : {stockGood.Barcode}, æ°é: {stockGood.StockQuantity}, å½åç¶æ: {stockGood.Status}"); // æ¢å¤åºåç¶æ stockGood.OutboundQuantity = 0; // æ¢å¤åºåç¶æ stockGood.OutboundQuantity = 0; stockGood.Status = StockStatusEmun.å ¥åºç¡®è®¤.ObjToInt(); await _stockInfoDetailService.Db.Updateable(stockGood).ExecuteCommandAsync(); @@ -1213,7 +1283,7 @@ /// <param name="originalTask"></param> /// <param name="analysis"></param> /// <returns></returns> private async Task CreateReturnTaskAndHandleESS(string orderNo, string palletCode, Dt_Task originalTask, ReturnAnalysisResult analysis) private async Task CreateReturnTaskAndHandleESS(string orderNo, string palletCode, Dt_Task originalTask, TaskTypeEnum taskTypeEnum) { var firstLocation = await _locationInfoService.Db.Queryable<Dt_LocationInfo>() .FirstAsync(x => x.LocationCode == originalTask.SourceAddress); @@ -1232,17 +1302,20 @@ SourceAddress = stations[originalTask.TargetAddress], TargetAddress = newLocation.LocationCode, TaskStatus = TaskStatusEnum.New.ObjToInt(), TaskType = TaskTypeEnum.InPick.ObjToInt(), TaskType = taskTypeEnum.ObjToInt(), PalletType = originalTask.PalletType, WarehouseId = originalTask.WarehouseId }; // ä¿åååºä»»å¡ await _taskRepository.Db.Insertable(returnTask).ExecuteCommandAsync(); var targetAddress = originalTask.TargetAddress; var targetAddress = originalTask.TargetAddress; // å é¤åå§åºåºä»»å¡ await _taskRepository.Db.Deleteable(originalTask).ExecuteCommandAsync(); _taskRepository.DeleteAndMoveIntoHty(originalTask, OperateTypeEnum.èªå¨å®æ); // await _taskRepository.Db.Deleteable(originalTask).ExecuteCommandAsync(); // ç» ESS åéæµå¨ä¿¡å·ååå»ºä»»å¡ await SendESSCommands(palletCode, targetAddress, returnTask); @@ -1274,10 +1347,7 @@ taskType = "putaway", taskGroupCode = "", groupPriority = 0, tasks = new List<TasksType> { new() { tasks = new List<TasksType>{ new() { taskCode = returnTask.TaskNum.ToString(), taskPriority = 0, taskDescribe = new TaskDescribeType @@ -1290,8 +1360,7 @@ deadline = 0, storageTag = "" } } } } } }; var resultTask = await _eSSApiService.CreateTaskAsync(essTask); @@ -1356,6 +1425,8 @@ } } private async Task UpdateOrderStatusForReturn(string orderNo) { try @@ -1419,6 +1490,7 @@ operationType = 1, Operator = App.User.UserName, orderNo = outboundOrder.UpperOrderNo, documentsNO = outboundOrder.OrderNo, status = outboundOrder.OrderStatus, details = new List<FeedbackOutboundDetailsModel>() }; @@ -1473,7 +1545,324 @@ #endregion #region 空æç /// <summary> /// æ¸ çé¶åºåæ°æ® /// </summary> private async Task CleanupZeroStockData(int stockId) { try { // 1. å é¤åºåæ°é为0çæç»è®°å½ var deleteDetailCount = await _stockInfoDetailService.Db.Deleteable<Dt_StockInfoDetail>() .Where(x => x.StockId == stockId && x.StockQuantity == 0 && (x.Status == StockStatusEmun.åºåºå®æ.ObjToInt() || x.Status == StockStatusEmun.å ¥åºå®æ.ObjToInt())) .ExecuteCommandAsync(); await _stockInfoService.Db.Deleteable<Dt_StockInfo>() .Where(x => x.Id == stockId).ExecuteCommandAsync(); _logger.LogInformation($"æ¸ çé¶åºåæç»è®°å½ - StockId: {stockId}, å é¤è®°å½æ°: {deleteDetailCount}"); } catch (Exception ex) { _logger.LogWarning($"æ¸ çé¶åºåæ°æ®å¤±è´¥ - StockId: {stockId}, Error: {ex.Message}"); // 注æï¼æ¸ ç失败ä¸åºè¯¥å½±å主æµç¨ } } /// <summary> /// å¤ç任塿¸ çï¼æè®¢ååæçï¼ /// </summary> private async Task HandleTaskCleanup(string orderNo, string palletCode) { try { // 1. æ¥æ¾ææä¸è¯¥è®¢ååæçç¸å ³çä»»å¡ var tasks = await _taskRepository.Db.Queryable<Dt_Task>().Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode).ToListAsync(); if (tasks.Any()) { foreach (var task in tasks) { task.TaskStatus = (int)TaskStatusEnum.Finish; } // await _taskRepository.Db.Updateable(tasks).ExecuteCommandAsync(); _taskRepository.DeleteAndMoveIntoHty(tasks, OperateTypeEnum.èªå¨å®æ); _logger.LogInformation($"宿{tasks.Count}个æçä»»å¡ - 订å: {orderNo}, æç: {palletCode}"); } } catch (Exception ex) { _logger.LogWarning($"å¤ç任塿¸ ç失败 - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}"); throw new Exception($"任塿¸ ç失败: {ex.Message}"); } } /// <summary> /// æ´æ°è®¢åç¸å ³æ°æ® /// </summary> private async Task UpdateOrderData(string orderNo, string palletCode) { try { // æ£æ¥è®¢åæ¯å¦è¿æå ¶ä»æçå¨å¤çä¸ var otherActivePallets = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() .Where(x => x.OrderNo == orderNo && x.PalletCode != palletCode && (x.Status == (int)OutLockStockStatusEnum.åºåºä¸ || x.Status == (int)OutLockStockStatusEnum.ååºä¸)) .AnyAsync(); var otherActiveTasks = await _taskRepository.Db.Queryable<Dt_Task>() .Where(x => x.OrderNo == orderNo && x.PalletCode != palletCode // && x.TaskStatus.In((int)TaskStatusEnum.å¾ æ§è¡, (int)TaskStatusEnum.æ§è¡ä¸) ) .AnyAsync(); // å¦ææ²¡æå ¶ä»æçå¨å¤çï¼æ£æ¥è®¢åæ¯å¦åºè¯¥å®æ if (!otherActivePallets && !otherActiveTasks) { await CheckAndUpdateOrderCompletion(orderNo); } else { _logger.LogInformation($"订å {orderNo} è¿æå ¶ä»æçå¨å¤çï¼ä¸æ´æ°è®¢åç¶æ"); } // 3. æ´æ°æ£éè®°å½ç¶æï¼å¯éï¼ await UpdatePickingRecordsStatus(orderNo, palletCode); } catch (Exception ex) { _logger.LogWarning($"æ´æ°è®¢åæ°æ®å¤±è´¥ - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}"); throw new Exception($"æ´æ°è®¢åæ°æ®å¤±è´¥: {ex.Message}"); } } /// <summary> /// æ£æ¥å¹¶æ´æ°è®¢åå®æç¶æ /// </summary> private async Task CheckAndUpdateOrderCompletion(string orderNo) { var orderDetails = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>() .LeftJoin<Dt_OutboundOrder>((o, item) => o.OrderId == item.Id) .Where((o, item) => item.OrderNo == orderNo) .Select((o, item) => o) .ToListAsync(); bool allCompleted = true; foreach (var detail in orderDetails) { if (detail.OverOutQuantity < detail.NeedOutQuantity) { allCompleted = false; break; } } var outboundOrder = await _outboundOrderService.Db.Queryable<Dt_OutboundOrder>() .FirstAsync(x => x.OrderNo == orderNo); if (outboundOrder != null && allCompleted && outboundOrder.OrderStatus != (int)OutOrderStatusEnum.åºåºå®æ) { outboundOrder.OrderStatus = (int)OutOrderStatusEnum.åºåºå®æ; await _outboundOrderService.Db.Updateable(outboundOrder).ExecuteCommandAsync(); _logger.LogInformation($"订å {orderNo} å·²æ 记为åºåºå®æ"); // åMESåé¦è®¢å宿ï¼å¦æéè¦ï¼ await HandleOrderCompletion(outboundOrder, orderNo); } } /// <summary> /// æ´æ°æ£éè®°å½ç¶æ /// </summary> private async Task UpdatePickingRecordsStatus(string orderNo, string palletCode) { try { // å¯ä»¥å°ç¸å ³çæ£éè®°å½æ è®°ä¸ºå·²å®æ var pickingRecords = await Db.Queryable<Dt_PickingRecord>() .Where(x => x.OrderNo == orderNo && x.PalletCode == palletCode) .ToListAsync(); // è¿éå¯ä»¥æ ¹æ®éè¦æ´æ°æ£éè®°å½çç¶æåæ®µ // ä¾å¦ï¼pickingRecord.Status = (int)PickingStatusEnum.已宿; _logger.LogInformation($"æ¾å°{pickingRecords.Count}æ¡æ£éè®°å½ - 订å: {orderNo}, æç: {palletCode}"); } catch (Exception ex) { _logger.LogWarning($"æ´æ°æ£éè®°å½ç¶æå¤±è´¥: {ex.Message}"); } } #endregion #region è¾ å©æ¹æ³ /// <summary> /// ç»ä¸åææçç¶æ - è¿åæçç宿´ç¶æä¿¡æ¯ /// </summary> private async Task<PalletStatusAnalysis> AnalyzePalletStatus(string orderNo, string palletCode, int stockId) { var result = new PalletStatusAnalysis { OrderNo = orderNo, PalletCode = palletCode, StockId = stockId }; // 1. åææªåæ£çåºåºéå®è®°å½ var remainingLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>() .Where(it => it.OrderNo == orderNo && it.PalletCode == palletCode && it.Status == (int)OutLockStockStatusEnum.åºåºä¸) .ToListAsync(); if (remainingLocks.Any()) { result.HasRemainingLocks = true; result.RemainingLocks = remainingLocks; result.RemainingLocksReturnQty = remainingLocks.Sum(x => x.AssignQuantity - x.PickedQty); } // 2. åææçä¸çåºåè´§ç© var palletStockGoods = await _stockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>() .Where(it => it.StockId == stockId && (it.Status == StockStatusEmun.å ¥åºç¡®è®¤.ObjToInt() || it.Status == StockStatusEmun.å ¥åºå®æ.ObjToInt() || it.Status == StockStatusEmun.åºåºéå®.ObjToInt())) .Where(it => it.StockQuantity > 0) .ToListAsync(); if (palletStockGoods.Any()) { result.HasPalletStockGoods = true; result.PalletStockGoods = palletStockGoods; result.PalletStockReturnQty = palletStockGoods.Sum(x => x.StockQuantity); } // 3. åææå è®°å½ var splitRecords = await _splitPackageService.Db.Queryable<Dt_SplitPackageRecord>() .Where(it => it.OrderNo == orderNo && it.PalletCode == palletCode && !it.IsReverted && it.Status != (int)SplitPackageStatusEnum.å·²ååº) .ToListAsync(); if (splitRecords.Any()) { result.HasSplitRecords = true; result.SplitRecords = splitRecords; result.SplitReturnQty = await CalculateSplitReturnQuantity(splitRecords, stockId); } // 4. è®¡ç®æ»ååºæ°éå空æçç¶æ result.TotalReturnQty = result.RemainingLocksReturnQty + result.PalletStockReturnQty + result.SplitReturnQty; result.HasItemsToReturn = result.TotalReturnQty > 0; result.IsEmptyPallet = !result.HasItemsToReturn; // 5. æ£æ¥æ¯å¦æè¿è¡ä¸çä»»å¡ result.HasActiveTasks = await _taskRepository.Db.Queryable<Dt_Task>() .Where(x => x.OrderNo == orderNo && x.TaskType == TaskTypeEnum.InPick.ObjToInt() && x.PalletCode == palletCode && x.TaskStatus == (int)TaskStatusEnum.New) .AnyAsync(); return result; } /// <summary> /// æ£æ¥æçæ¯å¦ä¸ºç©º /// </summary> private async Task<bool> IsPalletEmpty(string orderNo, string palletCode) { try { // è·ååºåä¿¡æ¯ var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>() .Where(x => x.PalletCode == palletCode) .FirstAsync(); if (stockInfo == null) return false; // 使ç¨ç»ä¸çç¶æåæ var statusAnalysis = await AnalyzePalletStatus(orderNo, palletCode, stockInfo.Id); return statusAnalysis.IsEmptyPallet; } catch (Exception ex) { _logger.LogWarning($"æ£æ¥æçæ¯å¦ä¸ºç©ºå¤±è´¥ - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}"); return false; } } /// <summary> /// æ£æ¥å¹¶å¤ç空æç /// </summary> private async Task<bool> CheckAndHandleEmptyPallet(string orderNo, string palletCode) { try { // 1. è·ååºåä¿¡æ¯ var stockInfo = await _stockInfoService.Db.Queryable<Dt_StockInfo>() .Where(x => x.PalletCode == palletCode) .FirstAsync(); if (stockInfo == null) { _logger.LogWarning($"æªæ¾å°æç {palletCode} çåºåä¿¡æ¯"); return false; } // 2. 使ç¨ç»ä¸çç¶æåæ var statusAnalysis = await AnalyzePalletStatus(orderNo, palletCode, stockInfo.Id); // 3. æ£æ¥æ¯å¦ä¸ºç©ºæç䏿²¡æè¿è¡ä¸çä»»å¡ if (!statusAnalysis.IsEmptyPallet || statusAnalysis.HasActiveTasks) { return false; } _logger.LogInformation($"æ£æµå°ç©ºæçï¼å¼å§èªå¨å¤ç - 订å: {orderNo}, æç: {palletCode}"); //// æ¸ çé¶åºåæ°æ® //await CleanupZeroStockData(stockInfo.Id); //// æ´æ°åºåä¸»è¡¨ç¶æä¸ºç©ºæç //await UpdateStockInfoAsEmpty(stockInfo); //// å¤çåºåºéå®è®°å½ //await HandleOutStockLockRecords(orderNo, palletCode); //// å¤çä»»å¡ç¶æ //await HandleTaskStatusForEmptyPallet(orderNo, palletCode); //// æ´æ°è®¢åæ°æ® //await UpdateOrderDataForEmptyPallet(orderNo, palletCode); ////è®°å½æä½åå² //await RecordAutoEmptyPalletOperation(orderNo, palletCode); _logger.LogInformation($"空æçèªå¨å¤ç宿 - 订å: {orderNo}, æç: {palletCode}"); return true; } catch (Exception ex) { _logger.LogError($"èªå¨å¤ç空æç失败 - OrderNo: {orderNo}, PalletCode: {palletCode}, Error: {ex.Message}"); return false; } } private async Task<string> GenerateNewBarcode() { @@ -1506,10 +1895,10 @@ OriginalLockQuantity = quantity, IsSplitted = 1, ParentLockId = originalLock.Id, Operator= App.User.UserName, FactoryArea=originalLock.FactoryArea, lineNo=originalLock.lineNo, WarehouseCode=originalLock.WarehouseCode, Operator = App.User.UserName, FactoryArea = originalLock.FactoryArea, lineNo = originalLock.lineNo, WarehouseCode = originalLock.WarehouseCode, }; @@ -1614,7 +2003,7 @@ } return WebResponseContent.Instance.OK("æ£é确认æå", new { SplitResults = new List<SplitResult>() }); } #endregion } @@ -1668,6 +2057,32 @@ public List<Dt_StockInfoDetail> PalletStockGoods { get; set; } = new List<Dt_StockInfoDetail>(); public List<Dt_SplitPackageRecord> SplitRecords { get; set; } = new List<Dt_SplitPackageRecord>(); } public class PalletStatusAnalysis { public string OrderNo { get; set; } public string PalletCode { get; set; } public int StockId { get; set; } // ååºç¸å ³å±æ§ public bool HasItemsToReturn { get; set; } public bool HasRemainingLocks { get; set; } public bool HasPalletStockGoods { get; set; } public bool HasSplitRecords { get; set; } public decimal RemainingLocksReturnQty { get; set; } public decimal PalletStockReturnQty { get; set; } public decimal SplitReturnQty { get; set; } public decimal TotalReturnQty { get; set; } public List<Dt_OutStockLockInfo> RemainingLocks { get; set; } = new List<Dt_OutStockLockInfo>(); public List<Dt_StockInfoDetail> PalletStockGoods { get; set; } = new List<Dt_StockInfoDetail>(); public List<Dt_SplitPackageRecord> SplitRecords { get; set; } = new List<Dt_SplitPackageRecord>(); // 空æçç¸å ³å±æ§ public bool IsEmptyPallet { get; set; } public bool HasActiveTasks { get; set; } // ä¾¿å©æ¹æ³ public bool CanReturn => HasItemsToReturn && !HasActiveTasks; public bool CanRemove => IsEmptyPallet && !HasActiveTasks; } #endregion } ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_StockService/StockInfoService.cs
@@ -254,6 +254,7 @@ LocationCode = a.LocationCode, MaterielCode = b.MaterielCode, MaterielName = b.MaterielName, Barcode=b.Barcode, PalletCode = a.PalletCode, UseableQuantity = b.StockQuantity - b.OutboundQuantity }, a => locationCodes.Contains(a.LocationCode), b => b.StockQuantity > b.OutboundQuantity && b.MaterielCode == materielCode, x => true).GroupBy(x => x.PalletCode).Select(x => new StockSelectViewDTO @@ -261,6 +262,7 @@ LocationCode = x.FirstOrDefault()?.LocationCode ?? "", MaterielCode = x.FirstOrDefault()?.MaterielCode ?? "", MaterielName = x.FirstOrDefault()?.MaterielName ?? "", Barcode=x.FirstOrDefault()?.Barcode??"", PalletCode = x.Key, UseableQuantity = x.Sum(x => x.UseableQuantity) }).ToList(); ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_Outbound.cs
@@ -219,6 +219,7 @@ _outboundOrderService.Repository.UpdateData(outboundOrder); } outboundOrder.Operator = App.User.UserName; outboundOrder.OrderStatus = OutOrderStatusEnum.åºåºä¸.ObjToInt(); _outboundOrderService.Repository.UpdateData(outboundOrder); WebResponseContent content = _outboundOrderDetailService.LockOutboundStockDataUpdate(stockInfos, outboundOrderDetails, outStockLockInfos, locationInfos, tasks: tasks); @@ -239,6 +240,9 @@ { _outboundOrderService.Repository.UpdateData(outboundOrder); } outboundOrder.Operator = App.User.UserName; outboundOrder.OrderStatus = OutOrderStatusEnum.åºåºä¸.ObjToInt(); _outboundOrderService.Repository.UpdateData(outboundOrder); _outboundOrderDetailService.Repository.UpdateData(outboundOrderDetails); } _unitOfWorkManage.CommitTran(); @@ -471,10 +475,10 @@ throw new Exception("æªæ¾å°åºåºåæç»ä¿¡æ¯"); } if (stockSelectViews.Sum(x => x.UseableQuantity) > outboundOrderDetail.OrderQuantity - outboundOrderDetail.LockQuantity) { throw new Exception("éæ©æ°éè¶ åºåæ®æ°é"); } //if (stockSelectViews.Sum(x => x.UseableQuantity) > outboundOrderDetail.OrderQuantity - outboundOrderDetail.LockQuantity) //{ // throw new Exception("éæ©æ°éè¶ åºåæ®æ°é"); //} List<Dt_StockInfo>? stockInfos = null; Dt_OutboundOrderDetail? orderDetail = null; List<Dt_OutStockLockInfo>? outStockLockInfos = null; ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Outbound/OutboundPickingController.cs
@@ -91,13 +91,20 @@ return await Service.ReturnRemaining(dto.OrderNo, dto.PalletCode, ""); } [HttpPost("remove-empty-pallet")] public async Task<WebResponseContent> RemoveEmptyPallet ([FromBody] ConfirmPickingDto dto) { return await Service.RemoveEmptyPallet(dto.OrderNo, dto.PalletCode); } //[HttpPost("direct-outbound")] //public async Task<WebResponseContent> DirectOutbound([FromBody] DirectOutboundRequest dto) //{ // return await Service.DirectOutbound(dto); //} /// <summary> /// æ¤éæ£é /// </summary>