647556386
2026-01-09 7354151f37391cc27462bc9d787c79f624f6e50e
盘点,单位转换优化
已修改7个文件
453 ■■■■ 文件已修改
项目代码/WIDESEA_WMSClient/src/extension/inbound/extend/TakeStockSelect.vue 122 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WIDESEA_WMSClient/src/extension/inbound/takeStockOrderDetail.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_IOutboundService/IOutboundService.cs 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_InboundService/TakeStockOrderService.cs 287 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundPickingService.cs 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundService.cs 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Inbound/TakeStockOrderController.cs 补丁 | 查看 | 原始文档 | blame | 历史
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/inbound/extend/TakeStockSelect.vue
@@ -12,44 +12,46 @@
      <div class="order-info">
        <div class="info-row">
          <span class="label">单据ID:</span>
          <span class="value">{{ currentRow.id || '-' }}</span>
          <span class="value">{{ currentRow.id || "-" }}</span>
        </div>
        <div class="info-row" v-if="selectedItem">
          <span class="label">已选订单:</span>
          <span class="value selected-order">{{ selectedItem.orderId }}</span>
          <span class="value selected-order">{{ selectedItem.id }}</span>
        </div>
      </div>
      <!-- æ•°æ®åˆ—表展示 -->
      <el-scrollbar height="400px" class="custom-scrollbar">
        <transition-group name="data-item-transition">
          <div class="data-item" v-for="(item, index) in displayData" :key="`${item.orderId}-${index}`">
          <div
            class="data-item"
            v-for="(item, index) in displayData"
            :key="`${item.orderId}-${index}`"
          >
            <div class="radio-container">
              <el-radio 
                v-model="selectedItem" 
                :label="item"
                :value="item"
                @change="handleRadioChange(item)"
              >
                <!-- å•选按钮的内容留空,只显示单选按钮 -->
              </el-radio>
              ></el-radio>
            </div>
            <div class="data-detail">
              <div class="detail-row">
                <span class="label">订单ID:</span>
                <span class="value">{{ item.orderId || '-' }}</span>
                <span class="value">{{ item.id || "-" }}</span>
              </div>
              <div class="detail-row">
                <span class="label">物料编码:</span>
                <span class="value">{{ item.materielCode || '-' }}</span>
                <span class="value">{{ item.materielCode || "-" }}</span>
              </div>
              <div class="detail-row">
                <span class="label">物料名称:</span>
                <span class="value">{{ item.materielName || '-' }}</span>
                <span class="value">{{ item.materielName || "-" }}</span>
              </div>
              <div class="detail-row">
                <span class="label">批次号:</span>
                <span class="value">{{ item.batchNo || '-' }}</span>
                <span class="value">{{ item.batchNo || "-" }}</span>
              </div>
              <div class="detail-row">
                <span class="label">订单数量:</span>
@@ -57,15 +59,15 @@
              </div>
              <div class="detail-row">
                <span class="label">单位:</span>
                <span class="value">{{ item.unit || '-' }}</span>
                <span class="value">{{ item.unit || "-" }}</span>
              </div>
              <div class="detail-row">
                <span class="label">供应商编码:</span>
                <span class="value">{{ item.supplyCode || '-' }}</span>
                <span class="value">{{ item.supplyCode || "-" }}</span>
              </div>
              <div class="detail-row">
                <span class="label">仓库编码:</span>
                <span class="value">{{ item.warehouseCode || '-' }}</span>
                <span class="value">{{ item.warehouseCode || "-" }}</span>
              </div>
            </div>
          </div>
@@ -84,17 +86,20 @@
        :disabled="!selectedItem"
        :loading="loading"
      >
        {{ loading ? '平账中...' : '确认平账' }}
        {{ loading ? "平账中..." : "确认平账" }}
      </el-button>
    </template>
  </el-dialog>
  <!-- æ‰“印组件(必须在模板中声明,才能通过ref获取) -->
  <printView ref="printViewRef" @parentcall="parentcall"></printView>
</template>
<script setup>
import { ref } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
// æ ¹æ®æ‚¨çš„实际项目引入请求方法,这里使用axios作为示例
import axios from 'axios';
import { ref } from "vue";
import printView from "@/extension/outbound/extend/printView.vue";
import { ElMessage, ElMessageBox } from "element-plus";
import axios from "axios";
// å¼¹çª—显示状态
const dialogVisible = ref(false);
@@ -106,6 +111,8 @@
const selectedItem = ref(null);
// åŠ è½½çŠ¶æ€
const loading = ref(false);
// å£°æ˜Žæ‰“印组件的ref引用(关键:替代this.$refs.printView)
const printViewRef = ref(null);
// æ‰“开弹窗方法(供父组件调用)
const open = (row, data) => {
@@ -126,22 +133,27 @@
  loading.value = false;
};
// çˆ¶ç»„件调用的回调(如果printView需要)
const parentcall = (params) => {
  console.log("printView回调参数:", params);
};
// ç¡®è®¤å¹³è´¦æ“ä½œ
const handleConfirm = async () => {
  if (!selectedItem.value) {
    ElMessage.warning('请选择一条数据进行平账处理');
    ElMessage.warning("请选择一条数据进行平账处理");
    return;
  }
  try {
    // ç¡®è®¤æç¤º
    await ElMessageBox.confirm(
      `确定要对订单 ${selectedItem.value.orderId} è¿›è¡Œå¹³è´¦å¤„理吗?`,
      '平账确认',
      `确定要对订单 ${selectedItem.value.id} è¿›è¡Œå¹³è´¦å¤„理吗?`,
      "平账确认",
      {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      }
    );
@@ -150,31 +162,54 @@
    // è°ƒç”¨å¹³è´¦æŽ¥å£
    const params = {
      id: currentRow.value.id, // è¡ŒID
      orderId: selectedItem.value.orderId // é€‰æ‹©çš„单据orderId
      orderId: selectedItem.value.id, // é€‰æ‹©çš„单据orderId
    };
    // æ ¹æ®æ‚¨çš„æŽ¥å£å®žé™…情况调整请求方式
    const response = await axios.get('/api/TakeStockOrder/DocumentReconciliation', {
      params: params // GET请求传参
      // å¦‚果是POST请求,可以这样写:
      // data: params
    });
    const response = await axios.get(
      "/api/TakeStockOrder/DocumentReconciliation",
      {
        params: params,
      }
    );
    if (response.status) {
      ElMessage.success('平账操作成功');
      dialogVisible.value = false;
    console.log("接口完整返回值:", response); // è°ƒè¯•用:打印完整返回
      
      // å¯ä»¥é€šè¿‡emit通知父组件刷新表格
      // emit('refresh-table');
    // ç¬¬ä¸€æ­¥ï¼šæ ¡éªŒæœ€å¤–层状态
    if (response.data?.status) {
      ElMessage.success("平账操作成功");
      // ç¬¬äºŒæ­¥ï¼šè§£æžæ­£ç¡®çš„scannedDetail层级(三层data)
      const thirdLayerData = response.data.data?.data; // å…³é”®ä¿®å¤ï¼šå–第三层data
      const scannedDetail = thirdLayerData?.scannedDetail;
      console.log("解析后的scannedDetail:", scannedDetail); // è°ƒè¯•用:打印目标数据
      // ç¬¬ä¸‰æ­¥ï¼šåˆ¤æ–­æ‰“印条件
      if (scannedDetail?.isUnpacked && scannedDetail?.materialCodes?.length > 0) {
        // ç¡®ä¿æ‰“印组件实例存在
        if (printViewRef.value) {
          console.log("触发打印方法,参数:", scannedDetail.materialCodes);
          printViewRef.value.open(scannedDetail.materialCodes);
    } else {
          ElMessage.warning("打印组件未加载完成,请检查组件引用");
        }
      } else {
        ElMessage.info("无需打印:未满足拆包条件或无物料编码数据");
      }
      dialogVisible.value = false;
    } else {
      ElMessage.error(response.data?.message || "平账操作失败");
    }
  } catch (error) {
    // å¦‚果是用户取消操作,不显示错误信息
    if (error === 'cancel' || error === 'close') {
    // å®Œå–„错误处理:区分用户取消和真实错误
    if (error === "cancel" || error === "close") {
      ElMessage.info("已取消平账操作");
      return;
    }
    ElMessage.error('平账操作失败,请稍后重试');
    // æ‰“印错误日志,方便排查
    console.error("平账接口调用失败:", error);
    ElMessage.error(`平账操作失败:${error.message || "网络异常"}`);
  } finally {
    loading.value = false;
  }
@@ -182,11 +217,12 @@
// æš´éœ²æ–¹æ³•给父组件
defineExpose({
  open
  open,
});
</script>
<style scoped>
/* æ ·å¼éƒ¨åˆ†ä¸å˜ï¼Œçœç•¥é‡å¤ä»£ç  */
.reconciliation-container {
  padding: 10px 0;
}
@@ -219,7 +255,7 @@
}
.selected-order {
  color: #409EFF;
  color: #409eff;
  font-weight: 600;
}
@@ -244,7 +280,7 @@
}
.data-item.selected {
  border-color: #409EFF;
  border-color: #409eff;
  background-color: #f0f7ff;
}
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/inbound/takeStockOrderDetail.js
@@ -146,7 +146,7 @@
            // æå–需要展示的字段
            const displayData = response.data.map(item => ({
              orderId: item.orderId || '',
              id: item.id || '',
              materielCode: item.materielCode || '',
              materielName: item.materielName || '',
              batchNo: item.batchNo || '',
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_IOutboundService/IOutboundService.cs
@@ -5,6 +5,7 @@
using System.Threading.Tasks;
using WIDESEA_Core;
using WIDESEA_DTO.CalcOut;
using WIDESEA_Model.Models;
namespace WIDESEA_IOutboundService
{
@@ -53,5 +54,12 @@
        /// <param name="OrderNo"></param>
        /// <returns></returns>
        Task<WebResponseContent> ReturnToWarehouse(string palletCode, string OrderNo,string station);
        public (string NewBarcode, List<MaterialCodeReturnDTO> MaterialCodeReturnDTOs) PerformUnpackOperation(Dt_StockInfoDetail stockDetail, Dt_StockInfo stockInfo,
            decimal actualOutboundQuantity, OutboundCompleteRequestDTO request, decimal beforeQuantity, int taskNum, int orderId, string orderNo);
        public void PerformFullOutboundOperation(Dt_StockInfoDetail stockDetail, Dt_StockInfo stockInfo,
            decimal actualOutboundQuantity, OutboundCompleteRequestDTO request, decimal beforeQuantity, int taskNum);
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_InboundService/TakeStockOrderService.cs
@@ -27,6 +27,9 @@
using WIDESEA_Common.AllocateEnum;
using WIDESEA_Model.Models.Basic;
using WIDESEA_IOutboundService;
using WIDESEA_DTO.CalcOut;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json;
namespace WIDESEA_InboundService
{
@@ -44,7 +47,10 @@
        private readonly IRepository<Dt_InboundOrderDetail> _inboundOrderDetailRepository;
        private readonly IRepository<Dt_OutboundOrderDetail> _outboundOrderDetailRepository;
        private readonly IOutboundPickingService _outboundPickingService;
        public TakeStockOrderService(IRepository<Dt_TakeStockOrder> BaseDal, IUnitOfWorkManage unitOfWorkManage,IRepository<Dt_TakeStockOrder> takeStockOrder,IRepository<Dt_StockInfo> stockInfoRepository,IRepository<Dt_TakeStockOrderDetail> takeStockOrderDetail,IRepository<Dt_Task> taskRepository,ILocationInfoService locationInfoService, IRepository<Dt_InboundOrder> inboundOrderRepository,IRepository<Dt_OutboundOrder> outboundOrderRepository,IRepository<Dt_InboundOrderDetail> inboundOrderDetailRepository, IRepository<Dt_OutboundOrderDetail> outboundOrderDetailRepository, IOutboundPickingService outboundPickingService) : base(BaseDal)
        private readonly IRepository<Dt_StockInfoDetail> _stockInfoDetailRepository;
        private readonly IOutboundService _outboundService;
        private readonly IFeedbackMesService _feedbackMesService;
        public TakeStockOrderService(IRepository<Dt_TakeStockOrder> BaseDal, IUnitOfWorkManage unitOfWorkManage,IRepository<Dt_TakeStockOrder> takeStockOrder,IRepository<Dt_StockInfo> stockInfoRepository,IRepository<Dt_TakeStockOrderDetail> takeStockOrderDetail,IRepository<Dt_Task> taskRepository,ILocationInfoService locationInfoService, IRepository<Dt_InboundOrder> inboundOrderRepository,IRepository<Dt_OutboundOrder> outboundOrderRepository,IRepository<Dt_InboundOrderDetail> inboundOrderDetailRepository, IRepository<Dt_OutboundOrderDetail> outboundOrderDetailRepository, IOutboundPickingService outboundPickingService, IRepository<Dt_StockInfoDetail> stockInfoDetailRepository, IOutboundService outboundService,IFeedbackMesService feedbackMesService) : base(BaseDal)
        {
            _unitOfWorkManage = unitOfWorkManage;
            _takeStockOrder = takeStockOrder;
@@ -57,6 +63,9 @@
            _inboundOrderDetailRepository = inboundOrderDetailRepository;
            _outboundOrderDetailRepository = outboundOrderDetailRepository;
            _outboundPickingService = outboundPickingService;
            _stockInfoDetailRepository = stockInfoDetailRepository;
            _outboundService = outboundService;
            _feedbackMesService = feedbackMesService;
        }
        public WebResponseContent ValidateBoxNo(string orderNo, string boxNo)
@@ -170,13 +179,13 @@
                    Unit = stockInfoDetail.Unit,
                    SysQty = completeStockTakeDTO.stockQuantity,
                    Qty = completeStockTakeDTO.actualQuantity,
                    Remark = completeStockTakeDTO.stockQuantity - completeStockTakeDTO.actualQuantity >= 0 ? "盘亏" : "盘盈",
                    Remark = completeStockTakeDTO.actualQuantity - completeStockTakeDTO.stockQuantity >= 0 ? "盘盈" : "盘亏",
                    barcode = completeStockTakeDTO.barcode,
                    WarehouseCode = stockInfoDetail.WarehouseCode ?? "",
                    FactoryArea = stockInfoDetail.FactoryArea,
                    SupplyCode = stockInfoDetail.SupplyCode ?? "",
                    TakeStockNo = takeStockOrder.OrderNo,
                    DifferenceQty = completeStockTakeDTO.stockQuantity - completeStockTakeDTO.actualQuantity
                    DifferenceQty = completeStockTakeDTO.actualQuantity - completeStockTakeDTO.stockQuantity
                };
                foreach (var item in stockInfo.Details)
@@ -374,7 +383,7 @@
                        {
                            var matchedDetails = outboundOrder.Details
                                .Where(detail => !string.IsNullOrWhiteSpace(detail.MaterielCode)
                                              && detail.MaterielCode == takeStockOrderDetail.MaterielCode)
                                              && detail.MaterielCode == takeStockOrderDetail.MaterielCode && detail.OrderQuantity-detail.MoveQty-detail.OverOutQuantity>0)
                                .WhereIF(!string.IsNullOrWhiteSpace(takeStockOrderDetail.FactoryArea),
                                         detail => !string.IsNullOrWhiteSpace(outboundOrder.FactoryArea)
                                              && outboundOrder.FactoryArea == takeStockOrderDetail.FactoryArea)
@@ -405,6 +414,7 @@
        public WebResponseContent DocumentReconciliation(int orderId, int id)
        {
            WebResponseContent webResponseContent = new WebResponseContent();
            try
            {
                Dt_TakeStockOrderDetail takeStockOrderDetail = _takeStockOrderDetail.QueryFirst(x => x.Id == id);
@@ -414,12 +424,12 @@
                }
                if(takeStockOrderDetail.Remark == "盘盈")
                {
                    Dt_InboundOrderDetail inboundOrderDetail = _inboundOrderDetailRepository.QueryFirst(x => x.OrderId == orderId);
                    Dt_InboundOrderDetail inboundOrderDetail = _inboundOrderDetailRepository.QueryFirst(x => x.Id == orderId);
                    if(inboundOrderDetail == null)
                    {
                        return WebResponseContent.Instance.Error("未找到选择的杂收平账单据");
                    }
                    Dt_InboundOrder inboundOrder = _inboundOrderRepository.Db.Queryable<Dt_InboundOrder>().Where(x=>x.Id == orderId).Includes(x=>x.Details).First();
                    Dt_InboundOrder inboundOrder = _inboundOrderRepository.Db.Queryable<Dt_InboundOrder>().Where(x=>x.Id == inboundOrderDetail.OrderId).Includes(x=>x.Details).First();
                    Dt_StockInfo  stockInfo = _stockInfoRepository.Db.Queryable<Dt_StockInfo>().Where(x=>x.PalletCode == takeStockOrderDetail.TakePalletCode && x.StockStatus == StockStatusEmun.盘点库存完成.ObjToInt()).Includes(x=>x.Details).First();
                    if(stockInfo== null)
                    {
@@ -461,10 +471,10 @@
                    {
                        inboundOrder.OrderStatus = InOrderStatusEnum.入库中.ObjToInt();
                    }
                    takeStockOrderDetail.DifferenceQty += inboundOrderDetail.OrderQuantity;
                    takeStockOrderDetail.DifferenceQty -= inboundOrderDetail.OrderQuantity;
                    if(takeStockOrderDetail.DifferenceQty > 0)
                    {
                        return WebResponseContent.Instance.Error("该杂收单据明细条码数量大于待平账数量,请另选其他单据平账");
                        takeStockOrderDetail.TakeDetalStatus = TakeStockDetailStatusEnum.杂收杂发平账处理中.ObjToInt();
                    }
                    else if (takeStockOrderDetail.DifferenceQty == 0)
                    {
@@ -472,7 +482,7 @@
                    }
                    else
                    {
                        takeStockOrderDetail.TakeDetalStatus = TakeStockDetailStatusEnum.杂收杂发平账处理中.ObjToInt();
                        return WebResponseContent.Instance.Error("该杂收单据明细条码数量大于待平账数量,请另选其他单据平账");
                    }
                    
                    _unitOfWorkManage.BeginTran();
@@ -483,15 +493,48 @@
                    _unitOfWorkManage.CommitTran();
                    List<string> barcodes = new List<string>();
                    barcodes.Add(inboundOrderDetail.Barcode);
                    _outboundPickingService.NoStockOutBatchInOrderFeedbackToMes(orderId, barcodes);
                    _outboundPickingService.NoStockOutBatchInOrderFeedbackToMes(inboundOrder.Id, barcodes);
                }
                else
                {
                    Dt_OutboundOrderDetail outboundOrderDetail = _outboundOrderDetailRepository.QueryFirst(x => x.Id == orderId);
                    if (outboundOrderDetail == null)
                    {
                        return WebResponseContent.Instance.Error("未找到选择的杂发平账单据");
                }
                return WebResponseContent.Instance.OK();
                    Dt_OutboundOrder outboundOrder = _outboundOrderRepository.Db.Queryable<Dt_OutboundOrder>().Where(x => x.Id == outboundOrderDetail.OrderId).Includes(x => x.Details).First();
                    Dt_StockInfo stockInfo = _stockInfoRepository.Db.Queryable<Dt_StockInfo>().Where(x => x.PalletCode == takeStockOrderDetail.TakePalletCode && x.StockStatus == StockStatusEmun.盘点库存完成.ObjToInt()).Includes(x => x.Details).First();
                    if (stockInfo == null)
                    {
                        return WebResponseContent.Instance.Error($"盘点托盘{takeStockOrderDetail.TakePalletCode}的库存信息未找到,或托盘状态不正确");
                    }
                    if(outboundOrderDetail.OrderQuantity + takeStockOrderDetail.DifferenceQty > 0)
                    {
                        return WebResponseContent.Instance.Error("该杂发单据明细发料数量大于待平账数量,请另选其他单据平账");
                    }
                    else if(outboundOrderDetail.OrderQuantity + takeStockOrderDetail.DifferenceQty < 0)
                    {
                        takeStockOrderDetail.TakeDetalStatus = TakeStockDetailStatusEnum.杂收杂发平账处理中.ObjToInt();
                    }
                    else
                    {
                        takeStockOrderDetail.TakeDetalStatus = TakeStockDetailStatusEnum.杂收杂发平账处理.ObjToInt();
                    }
                    OutboundCompleteRequestDTO request = new OutboundCompleteRequestDTO()
                    {
                        OrderNo = outboundOrder.OrderNo,
                        PalletCode = stockInfo.PalletCode,
                        Barcode = takeStockOrderDetail.barcode,
                        Operator = App.User.UserName
                    };
                    decimal stoQty = takeStockOrderDetail.SysQty;
                  webResponseContent = CompleteOutboundWithBarcode(request, stoQty, orderId);
                    takeStockOrderDetail.DifferenceQty = 0;
                    _takeStockOrderDetail.UpdateData(takeStockOrderDetail);
                }
                return WebResponseContent.Instance.OK(data: webResponseContent);
            }
            catch(Exception ex)
            {
@@ -500,6 +543,226 @@
            }
        }
        public WebResponseContent CompleteOutboundWithBarcode(OutboundCompleteRequestDTO request ,decimal stoQty, int orderDetailId)
        {
            WebResponseContent content = WebResponseContent.Instance;
            OutboundCompleteResponseDTO response = new();
            try
            {
                // 1. æ ¹æ®æ‰˜ç›˜å·æŸ¥æ‰¾åº“存信息
                Dt_StockInfo stockInfo = _stockInfoRepository.QueryFirst(x => x.PalletCode == request.PalletCode);
                if (stockInfo == null)
                {
                    response.Success = false;
                    response.Message = $"托盘号 {request.PalletCode} å¯¹åº”的库存不存在";
                    return WebResponseContent.Instance.Error($"托盘号 {request.PalletCode} å¯¹åº”的库存不存在");
                }
                // 2. æ ¹æ®æ¡ç æŸ¥æ‰¾åº“存明细
                Dt_StockInfoDetail stockDetail = _stockInfoDetailRepository.QueryFirst(x => x.Barcode == request.Barcode);
                if (stockDetail == null)
                {
                    response.Success = false;
                    response.Message = $"条码 {request.Barcode} å¯¹åº”的库存明细不存在";
                    return WebResponseContent.Instance.Error($"条码 {request.Barcode} å¯¹åº”的库存明细不存在");
                }
                // 3. éªŒè¯åº“存明细与托盘是否匹配
                if (stockDetail.StockId != stockInfo.Id)
                {
                    response.Success = false;
                    response.Message = $"条码 {request.Barcode} ä¸å±žäºŽæ‰˜ç›˜å· {request.PalletCode} çš„库存明细";
                    return WebResponseContent.Instance.Error($"条码 {request.Barcode} ä¸å±žäºŽæ‰˜ç›˜å· {request.PalletCode} çš„库存明细");
                }
                // 4. æŸ¥æ‰¾å‡ºåº“单信息
                Dt_OutboundOrder outboundOrder = _outboundOrderRepository.QueryFirst(o => o.OrderNo == request.OrderNo);
                if (outboundOrder == null)
                {
                    response.Success = false;
                    response.Message = $"出库单 {request.OrderNo} ä¸å­˜åœ¨";
                    return WebResponseContent.Instance.Error($"出库单 {request.OrderNo} ä¸å­˜åœ¨");
                }
                Dt_OutboundOrderDetail outboundOrderDetail = _outboundOrderDetailRepository.QueryFirst(x => x.Id == orderDetailId);
                if (outboundOrderDetail == null)
                {
                    return WebResponseContent.Instance.Error("未找到出库单明细");
                }
                // å®žé™…出库量
                decimal actualOutboundQuantity = outboundOrderDetail.OrderQuantity;
                // 8. åˆ¤æ–­æ˜¯å¦éœ€è¦æ‹†åŒ…(当出库数量小于库存数量时需要拆包)
                bool isUnpacked = outboundOrderDetail.OrderQuantity < stockDetail.StockQuantity;
                List<MaterialCodeReturnDTO> returnDTOs = new List<MaterialCodeReturnDTO>();
                string newBarcode = string.Empty;
                // 9. å¼€å¯äº‹åŠ¡
                _unitOfWorkManage.BeginTran();
                try
                {
                    decimal beforeQuantity = stockDetail.StockQuantity; // åŽŸå§‹åº“å­˜é‡
                    Dt_AllocateMaterialInfo allocateMaterialInfo = new Dt_AllocateMaterialInfo();
                    // æ ¹æ®æ˜¯å¦æ‹†åŒ…执行不同的操作
                    if (isUnpacked)
                    {
                        (string NewBarcode, List<MaterialCodeReturnDTO> MaterialCodeReturnDTOs) result = _outboundService.PerformUnpackOperation(stockDetail, stockInfo, actualOutboundQuantity, request, beforeQuantity, 0, outboundOrder.Id, outboundOrder.OrderNo);
                        returnDTOs = result.MaterialCodeReturnDTOs;
                        newBarcode = result.NewBarcode;
                        MaterialCodeReturnDTO returnDTO = returnDTOs.First(x => x.Barcode == newBarcode);
                        if (outboundOrder.OrderType != 0)
                        {
                            allocateMaterialInfo = new Dt_AllocateMaterialInfo()
                            {
                                Barcode = returnDTO.Barcode,
                                BatchNo = returnDTO.BatchNo,
                                FactoryArea = returnDTO.FactoryArea,
                                MaterialCode = returnDTO.MaterialCode,
                                MaterialName = returnDTO.MaterialName,
                                OrderId = outboundOrder.Id,
                                OrderNo = outboundOrder.OrderNo,
                                Quantity = returnDTO.Quantity,
                                SupplyCode = returnDTO.SuplierCode,
                                Unit = stockDetail.Unit
                            };
                        }
                    }
                    else
                    {
                       _outboundService.PerformFullOutboundOperation(stockDetail, stockInfo, actualOutboundQuantity, request, beforeQuantity, 0);
                        if (outboundOrder.OrderType != 0)
                        {
                            allocateMaterialInfo = new Dt_AllocateMaterialInfo()
                            {
                                Barcode = stockDetail.Barcode,
                                BatchNo = stockDetail.BatchNo,
                                FactoryArea = stockDetail.FactoryArea,
                                MaterialCode = stockDetail.MaterielCode,
                                MaterialName = stockDetail.MaterielName,
                                OrderId = outboundOrder.Id,
                                OrderNo = outboundOrder.OrderNo,
                                Quantity = stockDetail.StockQuantity,
                                SupplyCode = stockDetail.SupplyCode,
                                Unit = stockDetail.Unit
                            };
                        }
                    }
                    List<Dt_OutboundOrderDetail> outboundOrderDetails = new List<Dt_OutboundOrderDetail>();
                    outboundOrderDetails.Add(outboundOrderDetail);
                    decimal allocatedQuantity = actualOutboundQuantity;
                    List<Dt_OutboundOrderDetail> updateDetails = new();
                    foreach (var item in outboundOrderDetails)
                    {
                        if (allocatedQuantity <= 0) break;
                        decimal barcodeQuantity = allocatedQuantity;
                        if (item.LockQuantity - item.OverOutQuantity >= allocatedQuantity)
                        {
                            item.OverOutQuantity += allocatedQuantity;
                            item.CurrentDeliveryQty += allocatedQuantity;
                            allocatedQuantity = 0;
                        }
                        else
                        {
                            barcodeQuantity = allocatedQuantity;
                            allocatedQuantity -= (item.LockQuantity - item.OverOutQuantity);
                            item.OverOutQuantity = allocatedQuantity;
                            item.LockQuantity = allocatedQuantity;
                            item.CurrentDeliveryQty = allocatedQuantity;
                        }
                        updateDetails.Add(item);
                        List<Barcodes> barcodesList = new List<Barcodes>();
                        Barcodes barcodes = new Barcodes
                        {
                            Barcode = isUnpacked ? newBarcode : stockDetail?.Barcode,
                            Qty = barcodeQuantity,
                            SupplyCode = stockDetail?.SupplyCode ?? "",
                            BatchNo = stockDetail?.BatchNo ?? "",
                            Unit = stockDetail?.Unit ?? ""
                        };
                        if (!string.IsNullOrEmpty(item.ReturnJsonData))
                        {
                            barcodesList = JsonConvert.DeserializeObject<List<Barcodes>>(item.ReturnJsonData) ?? new List<Barcodes>();
                        }
                        barcodesList.Add(barcodes);
                        JsonSerializerSettings settings = new JsonSerializerSettings
                        {
                            ContractResolver = new CamelCasePropertyNamesContractResolver()
                        };
                        item.ReturnJsonData = JsonConvert.SerializeObject(barcodesList, settings);
                    }
                    // æ›´æ–°å‡ºåº“单明细的已出库数量
                    _outboundOrderDetailRepository.UpdateData(updateDetails);
                    // æ›´æ–°é”å®šè®°å½•的累计已出库数量(需要更新该托盘该物料的所有相关记录)
                    //UpdateLockInfoAllocatedQuantity(stockInfo.Id, stockDetail.MaterielCode, stockDetail.BatchNo, actualOutboundQuantity);
                    // æäº¤äº‹åŠ¡
                    _unitOfWorkManage.CommitTran();
                    // æž„建返回信息
                    ScannedStockDetailDTO scannedDetail = new ScannedStockDetailDTO
                    {
                        StockDetailId = stockDetail.Id,
                        PalletCode = stockInfo.PalletCode,
                        MaterielCode = stockDetail.MaterielCode,
                        MaterielName = stockDetail.MaterielName,
                        BatchNo = stockDetail.BatchNo,
                        OriginalBarcode = request.Barcode,
                        BeforeQuantity = beforeQuantity,
                        AfterQuantity = isUnpacked ? actualOutboundQuantity : 0,
                        ChangeQuantity = -actualOutboundQuantity,
                        IsUnpacked = isUnpacked,
                        MaterialCodes = returnDTOs
                    };
                    response.Success = true;
                    response.Message = "出库完成";
                    response.ScannedDetail = scannedDetail;
                    response.UpdatedDetails = updateDetails;
                    if (!string.IsNullOrEmpty(newBarcode))
                    {
                        // ç‰©æ–™æ–°æ¡ç å›žä¼ 
                        _feedbackMesService.BarcodeFeedback(newBarcode);
                    }
                    _feedbackMesService.OutboundFeedback(outboundOrder.OrderNo);
                }
                catch (Exception ex)
                {
                    _unitOfWorkManage.RollbackTran();
                    response.Success = false;
                    response.Message = $"出库处理失败:{ex.Message}";
                    return WebResponseContent.Instance.Error(ex.Message);
                }
                content = WebResponseContent.Instance.OK(data: response);
            }
            catch (Exception ex)
            {
                content = WebResponseContent.Instance.Error("处理出库完成失败:" + ex.Message);
            }
            return content;
        }
    }
    
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundPickingService.cs
@@ -2766,8 +2766,13 @@
                if (CheckOutboundOrderCompleted(outboundOrder.OrderNo))
                {
                    outboundOrder.OrderStatus = OutOrderStatusEnum.出库完成.ObjToInt();
                    _outboundOrderService.UpdateData(outboundOrder);
                }
                else
                {
                    outboundOrder.OrderStatus = OutOrderStatusEnum.出库中.ObjToInt();
                }
                _outboundOrderService.UpdateData(outboundOrder);
                _unitOfWorkManage.CommitTran();
                //出库回传MES
                _feedbackMesService.OutboundFeedback(outboundOrder.OrderNo);
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundService.cs
@@ -19,6 +19,7 @@
using WIDESEA_Core.BaseRepository;
using WIDESEA_Core.CodeConfigEnum;
using WIDESEA_Core.Helper;
using WIDESEA_DTO.Base;
using WIDESEA_DTO.Basic;
using WIDESEA_DTO.CalcOut;
using WIDESEA_DTO.ReturnMES;
@@ -1063,18 +1064,23 @@
                        List<Dt_StockInfoDetail> stockInfoDetails = stockInfo.Details.Where((x => x.StockQuantity > x.OutboundQuantity)).ToList();
                        decimal itemQuantity = item.LockQuantity - item.OverOutQuantity;
                        decimal unitbarcodeQuantity;
                        foreach (var stockDetail in stockInfoDetails)
                        {
                            if (itemQuantity >= stockDetail.StockQuantity - stockDetail.OutboundQuantity)
                            {
                                unitbarcodeQuantity = stockDetail.StockQuantity - stockDetail.OutboundQuantity;
                                UnitConvertResultDTO currentResult = _basicService.UnitQuantityConvert(item.MaterielCode, item.Unit, item.BarcodeUnit, unitbarcodeQuantity);
                                Barcodes barcodes = new Barcodes
                                {
                                    Barcode = stockDetail.Barcode,
                                    Qty = stockDetail.StockQuantity - stockDetail.OutboundQuantity,
                                    Qty = currentResult.ToQuantity,
                                    SupplyCode = stockDetail?.SupplyCode ?? "",
                                    BatchNo = stockDetail?.BatchNo ?? "",
                                    Unit = stockDetail?.Unit ?? ""
                                    Unit = currentResult.ToUnit ?? ""
                                };
                                itemQuantity -= (stockDetail.StockQuantity - stockDetail.OutboundQuantity);
@@ -1085,13 +1091,14 @@
                            }
                            else
                            {
                                UnitConvertResultDTO currentResult = _basicService.UnitQuantityConvert(item.MaterielCode, item.Unit, item.BarcodeUnit, itemQuantity);
                                Barcodes barcodes = new Barcodes
                                {
                                    Barcode = stockDetail.Barcode,
                                    Qty = itemQuantity,
                                    Qty = currentResult.ToQuantity,
                                    SupplyCode = stockDetail?.SupplyCode ?? "",
                                    BatchNo = stockDetail?.BatchNo ?? "",
                                    Unit = stockDetail?.Unit ?? ""
                                    Unit = currentResult.ToUnit ?? ""
                                };
                                stockDetail.OutboundQuantity += itemQuantity;
                                barcodesList.Add(barcodes);
@@ -1478,13 +1485,15 @@
                        updateDetails.Add(item);
                        List<Barcodes> barcodesList = new List<Barcodes>();
                        UnitConvertResultDTO currentResult = _basicService.UnitQuantityConvert(item.MaterielCode, item.Unit, item.BarcodeUnit, barcodeQuantity);
                        Barcodes barcodes = new Barcodes
                        {
                            Barcode = isUnpacked ? newBarcode : stockDetail?.Barcode,
                            Qty = barcodeQuantity,
                            Qty = currentResult.ToQuantity,
                            SupplyCode = stockDetail?.SupplyCode ?? "",
                            BatchNo = stockDetail?.BatchNo ?? "",
                            Unit = stockDetail?.Unit ?? ""
                            Unit = currentResult.ToUnit ?? ""
                        };
                        if (!string.IsNullOrEmpty(item.ReturnJsonData))
                        {
@@ -1640,7 +1649,7 @@
        /// <param name="beforeQuantity"></param>
        /// <param name="taskNum"></param>
        /// <returns></returns>
        private (string NewBarcode, List<MaterialCodeReturnDTO> MaterialCodeReturnDTOs) PerformUnpackOperation(Dt_StockInfoDetail stockDetail, Dt_StockInfo stockInfo,
        public (string NewBarcode, List<MaterialCodeReturnDTO> MaterialCodeReturnDTOs) PerformUnpackOperation(Dt_StockInfoDetail stockDetail, Dt_StockInfo stockInfo,
            decimal actualOutboundQuantity, OutboundCompleteRequestDTO request, decimal beforeQuantity, int taskNum, int orderId, string orderNo)
        {
            string newBarcode = GenerateNewBarcode();
@@ -1718,7 +1727,7 @@
        /// <summary>
        /// æ‰§è¡Œå®Œæ•´å‡ºåº“操作(不拆包)
        /// </summary>
        private void PerformFullOutboundOperation(Dt_StockInfoDetail stockDetail, Dt_StockInfo stockInfo,
        public void PerformFullOutboundOperation(Dt_StockInfoDetail stockDetail, Dt_StockInfo stockInfo,
            decimal actualOutboundQuantity, OutboundCompleteRequestDTO request, decimal beforeQuantity, int taskNum)
        {
            // ä¿å­˜åº“存明细到历史记录
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Inbound/TakeStockOrderController.cs