z8018
2025-12-16 4dbdd03f0476e219b1593dda302f478c15860fa6
回传
已添加10个文件
已修改18个文件
5835 ■■■■ 文件已修改
项目代码/WIDESEA_WMSClient/.claude/settings.local.json 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WIDESEA_WMSClient/package-lock.json 4190 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WIDESEA_WMSClient/package.json 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WIDESEA_WMSClient/src/extension/outbound/extend/outOrderDetail.vue 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.1204.46620/CodeChunks.db 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.1204.46620/SemanticSymbols.db 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_BasicService/BasicService.cs 254 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_BasicService/MESOperation/FeedbackMesService.cs 167 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_Core/BaseRepository/UnitOfWorks/IUnitOfWorkManage.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_Core/BaseRepository/UnitOfWorks/UnitOfWorkManage.cs 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_Core/CodeConfigEnum/RuleCodeEnum.cs 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_Core/Extensions/DbSetup.cs 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_Core/Util/HttpClientHelper.cs 272 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_Core/Util/HttpRequestConfig.cs 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_Core/Util/HttpResponseResult.cs 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_DTO/Base/UnitConvertResultDTO.cs 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_DTO/CalcOut/OutboundCalculationDTO.cs 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_DTO/CalcOut/PickingOutboundRequestDTO.cs 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_DTO/ReturnMES/BaseReturnDTO.cs 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_DTO/ReturnMES/MaterialOutboundReturnDTO.cs 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_DTO/ReturnMES/MesResponseDTO.cs 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_IBasicService/IBasicService.cs 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_IBasicService/MESOperation/IFeedbackMesService.cs 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_Model/Models/Outbound/Dt_OutboundOrderDetail.cs 30 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_Model/Models/Record/Dt_MesReturnRecord.cs 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundOrderDetailService.cs 110 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundQueryService.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundService.cs 204 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ÏîÄ¿´úÂë/WIDESEA_WMSClient/.claude/settings.local.json
@@ -6,7 +6,9 @@
      "Bash(SET NODE_OPTIONS=--openssl-legacy-provider)",
      "Bash(export NODE_OPTIONS=--openssl-legacy-provider:*)",
      "Bash(node:*)",
      "Bash(npm --version:*)"
      "Bash(npm --version:*)",
      "Bash(npm run build)",
      "Bash(npx:*)"
    ]
  }
}
ÏîÄ¿´úÂë/WIDESEA_WMSClient/package-lock.json
ÎļþÌ«´ó
ÏîÄ¿´úÂë/WIDESEA_WMSClient/package.json
@@ -29,7 +29,7 @@
  },
  "devDependencies": {
    "@babel/plugin-syntax-dynamic-import": "^7.8.3",
    "@vue/cli-plugin-babel": "~4.5.0",
    "@vue/cli-plugin-babel": "^4.5.19",
    "@vue/cli-plugin-eslint": "~4.5.0",
    "@vue/cli-plugin-router": "~4.5.0",
    "@vue/cli-plugin-unit-mocha": "~4.5.0",
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/outbound/extend/outOrderDetail.vue
@@ -320,7 +320,7 @@
    },
    handleOpenBatchPicking() {
      this.$router.push({
        path: "/outbound/batchpicking",
        path: "/outbound/outPicking",
        query: { orderId: this.row.id, orderNo: this.row.orderNo },
      });
    },
@@ -452,9 +452,9 @@
                          render(null, mountNode);
                          document.body.removeChild(mountNode);
                        })
                        // .catch(() => {
                        //   ElMessage.error("请求失败,请稍后重试");
                        // });
                      // .catch(() => {
                      //   ElMessage.error("请求失败,请稍后重试");
                      // });
                    },
                    style: {
                      borderRadius: "4px",
@@ -617,14 +617,16 @@
                      const keys = this.selection.map((item) => item.id);
                      const requestParams = {
                        orderDetailId: keys[0],
                        outboundPlatform: formData.selectedPlatform,
                        batchQuantity: formData.outboundDecimal,
                        detailIds: keys,
                        outboundTargetLocation: formData.selectedPlatform,
                        outboundQuantity: formData.outboundDecimal,
                        operator: "",
                        orderNo: this.row.orderNo,
                      };
                      this.http
                        .post(
                          "api/Task/GenerateOutboundBatchTasks",
                          "api/Outbound/ProcessPickingOutbound",
                          requestParams,
                          "数据处理中"
                        )
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.1204.46620/CodeChunks.db
Binary files differ
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.1204.46620/SemanticSymbols.db
Binary files differ
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_BasicService/BasicService.cs
@@ -1,9 +1,21 @@
using WIDESEA_IBasicService;
using SqlSugar;
using WIDESEA_Core.Attributes;
using WIDESEA_Core.BaseRepository;
using WIDESEA_Core.CodeConfigEnum;
using WIDESEA_Core.DB;
using WIDESEA_Core.Helper;
using WIDESEA_Core.Seed;
using WIDESEA_DTO.Base;
using WIDESEA_IBasicService;
using WIDESEA_Model.Models;
using WIDESEA_Model.Models.Basic;
namespace WIDESEA_BasicService
{
    public class BasicService : IBasicService
    {
        private readonly IUnitOfWorkManage _unitOfWorkManage;
        public IPalletCodeInfoService PalletCodeInfoService { get; }
        public ILocationInfoService LocationInfoService { get; }
@@ -14,13 +26,251 @@
        public IMaterielCodeInfoService MaterielCodeInfoService { get; }
        public BasicService(ILocationInfoService locationInfoService, IMaterielInfoService materielInfoService, IWarehouseService warehouseService, IPalletCodeInfoService palletCodeInfoService, IMaterielCodeInfoService materielCodeInfoService)
        public IMaterialUnitService MaterialUnitService { get; }
        public BasicService(IUnitOfWorkManage unitOfWorkManage, ILocationInfoService locationInfoService, IMaterielInfoService materielInfoService, IWarehouseService warehouseService, IPalletCodeInfoService palletCodeInfoService, IMaterielCodeInfoService materielCodeInfoService, IMaterialUnitService materialUnitService)
        {
            _unitOfWorkManage = unitOfWorkManage;
            LocationInfoService = locationInfoService;
            MaterielInfoService = materielInfoService;
            WarehouseService = warehouseService;
            PalletCodeInfoService = palletCodeInfoService;
            MaterielCodeInfoService = materielCodeInfoService;
            MaterialUnitService = materialUnitService;
        }
        #region
        public string CreateCodeByRule(string ruleCode)
        {
            string code = string.Empty;
            DateTime dataTime = DateTime.Now;
            DateTime now = DateTime.Now;
            try
            {
                Dt_CodeRuleConfig ruleConfig = _unitOfWorkManage.Db.Queryable<Dt_CodeRuleConfig>().Where(x => x.RuleCode == ruleCode).First();
                if (ruleConfig.ModifyDate != null)
                {
                    dataTime = ruleConfig.ModifyDate.Value;
                }
                else
                {
                    dataTime = ruleConfig.CreateDate;
                }
                if (now.Year == dataTime.Year && now.Month == dataTime.Month && now.Day == dataTime.Day)
                {
                    now = dataTime;
                    ruleConfig.CurrentVal = Convert.ToInt32(ruleConfig.CurrentVal) + 1;
                }
                else
                {
                    ruleConfig.CurrentVal = 1;
                }
                ruleConfig.ModifyDate = DateTime.Now;
                code = ruleConfig.Format;
                code = code.Replace($"[{CodeFormatTypeEnum.YYYY}]", now.Year.ToString().PadLeft(4, '0'));
                code = code.Replace($"[{CodeFormatTypeEnum.MM}]", now.Month.ToString().PadLeft(2, '0'));
                code = code.Replace($"[{CodeFormatTypeEnum.DD}]", now.Day.ToString().PadLeft(2, '0'));
                code = code.Replace($"[{CodeFormatTypeEnum.ST}]", ruleConfig.StartStr.ToString());
                code = code.Replace($"[{CodeFormatTypeEnum.NUM}]", ruleConfig.CurrentVal.ToString().PadLeft(ruleConfig.Length, '0'));
                _unitOfWorkManage.Db.Updateable(ruleConfig).ExecuteCommand();
            }
            catch (Exception ex)
            {
            }
            return code;
        }
        #endregion
        #region å•位转换
        /// <summary>
        /// å•位转换
        /// </summary>
        /// <param name="materialCode"></param>
        /// <param name="fromUnit"></param>
        /// <param name="toUnit"></param>
        /// <param name="quantity"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public UnitConvertResultDTO UnitQuantityConvert(string materialCode, string fromUnit, string toUnit, decimal quantity)
        {
            if (string.IsNullOrEmpty(fromUnit))
            {
                throw new Exception($"转换前单位不能为空");
            }
            if (string.IsNullOrEmpty(toUnit))
            {
                throw new Exception($"转换后单位不能为空");
            }
            decimal ratio = 0;
            if (fromUnit.Trim().ToLower() == toUnit.Trim().ToLower())
            {
                return new UnitConvertResultDTO(materialCode, fromUnit, toUnit, quantity, ratio);
            }
            Dt_MaterialUnit materialUnit = MaterialUnitService.Repository.QueryFirst(x => x.ItemNo == materialCode && x.FromUom == fromUnit && x.ToUom == toUnit);
            if (materialUnit != null)
            {
                ratio = materialUnit.Ratio;
                return new UnitConvertResultDTO(materialCode, fromUnit, toUnit, quantity, ratio);
            }
            else
            {
                materialUnit = MaterialUnitService.Repository.QueryFirst(x => x.ItemNo == materialCode && x.FromUom == toUnit && x.ToUom == fromUnit);
                if (materialUnit == null)
                {
                    throw new Exception($"未找到单位转换关系,物料编号:{materialCode},转换前单位:{fromUnit},转换后单位:{toUnit}");
                }
                ratio = materialUnit.Ratio;
                return new UnitConvertResultDTO(materialCode, fromUnit, toUnit, quantity, ratio);
            }
        }
        /// <summary>
        /// å•位转换,领料转采购
        /// </summary>
        /// <param name="materialCode"></param>
        /// <param name="quantity"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public UnitConvertResultDTO UnitUsageToPurchase(string materialCode, decimal quantity)
        {
            if (string.IsNullOrEmpty(materialCode))
            {
                throw new Exception($"物料编号不能为空");
            }
            Dt_MaterielInfo materielInfo = MaterielInfoService.Repository.QueryFirst(x => x.MaterielCode == materialCode);
            if (materielInfo == null)
            {
                throw new Exception($"未找到物料信息{materialCode}");
            }
            return UnitQuantityConvert(materialCode, materielInfo.usageUOM, materielInfo.purchaseUOM, quantity);
        }
        /// <summary>
        /// å•位转换,领料转库存
        /// </summary>
        /// <param name="materialCode"></param>
        /// <param name="quantity"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public UnitConvertResultDTO UnitUsageToInventory(string materialCode, decimal quantity)
        {
            if (string.IsNullOrEmpty(materialCode))
            {
                throw new Exception($"物料编号不能为空");
            }
            Dt_MaterielInfo materielInfo = MaterielInfoService.Repository.QueryFirst(x => x.MaterielCode == materialCode);
            if (materielInfo == null)
            {
                throw new Exception($"未找到物料信息{materialCode}");
            }
            return UnitQuantityConvert(materialCode, materielInfo.usageUOM, materielInfo.inventoryUOM, quantity);
        }
        /// <summary>
        /// å•位转换,采购转库存
        /// </summary>
        /// <param name="materialCode"></param>
        /// <param name="quantity"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public UnitConvertResultDTO UnitPurchaseToInventory(string materialCode, decimal quantity)
        {
            if (string.IsNullOrEmpty(materialCode))
            {
                throw new Exception($"物料编号不能为空");
            }
            Dt_MaterielInfo materielInfo = MaterielInfoService.Repository.QueryFirst(x => x.MaterielCode == materialCode);
            if (materielInfo == null)
            {
                throw new Exception($"未找到物料信息{materialCode}");
            }
            return UnitQuantityConvert(materialCode, materielInfo.purchaseUOM, materielInfo.inventoryUOM, quantity);
        }
        /// <summary>
        /// å•位转换,采购转领料
        /// </summary>
        /// <param name="materialCode"></param>
        /// <param name="quantity"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public UnitConvertResultDTO UnitPurchaseToUsage(string materialCode, decimal quantity)
        {
            if (string.IsNullOrEmpty(materialCode))
            {
                throw new Exception($"物料编号不能为空");
            }
            Dt_MaterielInfo materielInfo = MaterielInfoService.Repository.QueryFirst(x => x.MaterielCode == materialCode);
            if (materielInfo == null)
            {
                throw new Exception($"未找到物料信息{materialCode}");
            }
            return UnitQuantityConvert(materialCode, materielInfo.purchaseUOM, materielInfo.usageUOM, quantity);
        }
        /// <summary>
        /// å•位转换,库存转领料
        /// </summary>
        /// <param name="materialCode"></param>
        /// <param name="quantity"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public UnitConvertResultDTO UnitInventoryToUsage(string materialCode, decimal quantity)
        {
            if (string.IsNullOrEmpty(materialCode))
            {
                throw new Exception($"物料编号不能为空");
            }
            Dt_MaterielInfo materielInfo = MaterielInfoService.Repository.QueryFirst(x => x.MaterielCode == materialCode);
            if (materielInfo == null)
            {
                throw new Exception($"未找到物料信息{materialCode}");
            }
            return UnitQuantityConvert(materialCode, materielInfo.inventoryUOM, materielInfo.usageUOM, quantity);
        }
        /// <summary>
        /// å•位转换,库存转采购
        /// </summary>
        /// <param name="materialCode"></param>
        /// <param name="quantity"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public UnitConvertResultDTO UnitInventoryToPurchase(string materialCode, decimal quantity)
        {
            if (string.IsNullOrEmpty(materialCode))
            {
                throw new Exception($"物料编号不能为空");
            }
            Dt_MaterielInfo materielInfo = MaterielInfoService.Repository.QueryFirst(x => x.MaterielCode == materialCode);
            if (materielInfo == null)
            {
                throw new Exception($"未找到物料信息{materialCode}");
            }
            return UnitQuantityConvert(materialCode, materielInfo.inventoryUOM, materielInfo.purchaseUOM, quantity);
        }
        #endregion
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_BasicService/MESOperation/FeedbackMesService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,167 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using WIDESEA_Core;
using WIDESEA_Core.BaseRepository;
using WIDESEA_Core.Helper;
using WIDESEA_Core.HttpContextUser;
using WIDESEA_Core.Util;
using WIDESEA_DTO.Base;
using WIDESEA_DTO.ReturnMES;
using WIDESEA_IBasicService;
using WIDESEA_Model.Models;
namespace WIDESEA_BasicService.MESOperation
{
    public class FeedbackMesService : IFeedbackMesService
    {
        private readonly IUnitOfWorkManage _unitOfWorkManage;
        private readonly HttpClientHelper _httpClientHelper;
        private readonly IRepository<Dt_OutboundOrder> _outboundOrderRepository;
        private readonly IBasicService _basicService;
        public FeedbackMesService(IUnitOfWorkManage unitOfWorkManage, HttpClientHelper httpClientHelper, IRepository<Dt_OutboundOrder> outboundOrderRepository, IBasicService basicService)
        {
            _unitOfWorkManage = unitOfWorkManage;
            _httpClientHelper = httpClientHelper;
            _outboundOrderRepository = outboundOrderRepository;
            _basicService = basicService;
        }
        public void MaterialOutboundFeedback(string orderNo)
        {
            try
            {
                Dt_OutboundOrder outboundOrder = _outboundOrderRepository.Db.Queryable<Dt_OutboundOrder>().Where(x => x.OrderNo == orderNo).Includes(x => x.Details).First();
                if (outboundOrder == null)
                {
                    // todo è®°å½•日志:未找到对应的出库单
                    return;
                }
                MaterialOutboundReturnDTO? returnDTO = BuildOutboundFeedbackData(outboundOrder);
                if (returnDTO != null)
                {
                    string apiUrl = "";
                    HttpResponseResult<MesResponseDTO> httpResponseResult = _httpClientHelper.Post<MesResponseDTO>(apiUrl, returnDTO.Serialize());
                    bool isSuccess = httpResponseResult.IsSuccess && httpResponseResult.Data != null && httpResponseResult.Data.Code == "200";
                    string message = "";
                    if (!isSuccess)
                    {
                        if (httpResponseResult.IsSuccess)
                        {
                            message = $"MES接口返回错误,HTTP代码:{httpResponseResult.StatusCode},信息:{httpResponseResult.ErrorMessage}";
                        }
                        else if (httpResponseResult.Data.Code != "200")
                        {
                            message = $"调用MES接口失败,代码:{httpResponseResult.Data.Code},信息:{httpResponseResult.Data.Message}";
                        }
                    }
                    Dt_MesReturnRecord mesReturnRecord = new Dt_MesReturnRecord()
                    {
                        ApiUrl = apiUrl,
                        InterfaceType = 1,
                        OrderId = outboundOrder.Id,
                        OrderNo = outboundOrder.OrderNo,
                        OrderType = outboundOrder.OrderType,
                        RequestCode = returnDTO.ReqCode,
                        RequestData = returnDTO.Serialize(),
                        FailureReason = message,
                        LastReturnTime = DateTime.Now,
                        HttpStatusCode = httpResponseResult.StatusCode.ObjToInt(),
                        ResponseData = httpResponseResult.Content,
                        ReturnType = 0,
                        ReturnCount = 1,
                        ReturnStatus = httpResponseResult.IsSuccess ? 1 : 2,
                        SuccessTime = httpResponseResult.IsSuccess ? DateTime.Now : null
                    };
                    _unitOfWorkManage.BeginTran();
                    _unitOfWorkManage.Db.Insertable(mesReturnRecord).ExecuteCommand();
                    List<string> lineNos = returnDTO.Details.Select(x => x.LineNo).ToList();
                    List<Dt_OutboundOrderDetail> outboundOrderDetails = outboundOrder.Details.Where(x => lineNos.Contains(x.lineNo)).ToList();
                    outboundOrderDetails.ForEach(x =>
                    {
                        if (x.OverOutQuantity == x.OrderQuantity - x.MoveQty)
                        {
                            x.ReturnToMESStatus = isSuccess ? 1 : 2;
                        }
                        else
                        {
                            x.ReturnToMESStatus = isSuccess ? 3 : 4;
                        }
                        x.CurrentDeliveryQty = 0;
                        x.ReturnJsonData = "";
                    });
                    _outboundOrderRepository.Db.Updateable(outboundOrderDetails).ExecuteCommand();
                    _unitOfWorkManage.CommitTran();
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }
        public MaterialOutboundReturnDTO? BuildOutboundFeedbackData(Dt_OutboundOrder outboundOrder)
        {
            try
            {
                List<Dt_OutboundOrderDetail> details = outboundOrder.Details;
                List<MaterialOutboundDetail> returnDetails = new List<MaterialOutboundDetail>();
                foreach (var detail in details)
                {
                    List<Barcodes>? barcodes = JsonConvert.DeserializeObject<List<Barcodes>>(detail.ReturnJsonData);
                    if (barcodes != null && barcodes.Any())
                    {
                        UnitConvertResultDTO currentResult = _basicService.UnitQuantityConvert(detail.MaterielCode, detail.Unit, detail.BarcodeUnit, detail.CurrentDeliveryQty);
                        UnitConvertResultDTO totalResult = _basicService.UnitQuantityConvert(detail.MaterielCode, detail.Unit, detail.BarcodeUnit, detail.OrderQuantity);
                        returnDetails.Add(new MaterialOutboundDetail
                        {
                            Barcodes = barcodes,
                            CurrentDeliveryQty = currentResult.ToQuantity,
                            LineNo = detail.lineNo,
                            MaterialCode = detail.MaterielCode,
                            Qty = totalResult.ToQuantity,
                            WarehouseCode = detail.WarehouseCode,
                            Unit = detail.BarcodeUnit
                        });
                    }
                }
                MaterialOutboundReturnDTO outboundReturnDTO = new MaterialOutboundReturnDTO()
                {
                    Business_type = outboundOrder.BusinessType,
                    Details = returnDetails,
                    DocumentsNO = "",
                    FactoryArea = outboundOrder.FactoryArea,
                    OperationType = 1,
                    Operator = App.User.UserName,
                    OrderNo = outboundOrder.OrderNo,
                    Status = 1
                };
                return outboundReturnDTO;
            }
            catch (Exception ex)
            {
                return null;
            }
        }
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Core/BaseRepository/UnitOfWorks/IUnitOfWorkManage.cs
@@ -10,6 +10,7 @@
{
    public interface IUnitOfWorkManage
    {
        SqlSugarClient Db { get; }
        SqlSugarClient GetDbClient();
        int TranCount { get; }
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Core/BaseRepository/UnitOfWorks/UnitOfWorkManage.cs
@@ -27,6 +27,8 @@
            _tranCount = 0;
        }
        public SqlSugarClient Db => GetDbClient();
        /// <summary>
        /// èŽ·å–DB,保证唯一性
        /// </summary>
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Core/CodeConfigEnum/RuleCodeEnum.cs
@@ -49,6 +49,8 @@
        /// è°ƒæ‹¨å•号编码规则
        /// </summary>
        [Description("调拨单号编码规则")]
        AllocateOrderCodeRule
        AllocateOrderCodeRule,
        NewBarcodeRule
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Core/Extensions/DbSetup.cs
@@ -1,10 +1,12 @@
using Microsoft.Extensions.DependencyInjection;
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using WIDESEA_Core.Helper;
using WIDESEA_Core.Seed;
using WIDESEA_Core.Util;
namespace WIDESEA_Core
{
@@ -16,9 +18,15 @@
        public static void AddDbSetup(this IServiceCollection services)
        {
            if (services == null) throw new ArgumentNullException(nameof(services));
            services.AddScoped<DBSeed>();
            services.AddScoped<DBContext>();
            // æ³¨å†ŒIHttpClientFactory
            services.AddHttpClient();
            // æ³¨å†ŒHttpHelper
            services.AddScoped<HttpClientHelper>();
        }
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Core/Util/HttpClientHelper.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,272 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reflection.Metadata;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using WIDESEA_Core.Helper;
namespace WIDESEA_Core.Util
{
    public class HttpClientHelper
    {
        private readonly IHttpClientFactory _httpClientFactory;
        public HttpClientHelper(IHttpClientFactory httpClientFactory, IConfiguration configuration = null)
        {
            _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory));
        }
        /// <summary>
        /// POST请求
        /// </summary>
        /// <param name="url">请求URL</param>
        /// <param name="content">请求内容</param>
        /// <param name="mediaType">媒体类型</param>
        /// <param name="config">请求配置</param>
        /// <returns></returns>
        public HttpResponseResult Post(string url, string content, string contentType = "application/json", HttpRequestConfig? config = null)
        {
            HttpResponseResult httpResponseResult = ExecuteAsync(async (client) =>
            {
                var request = new HttpRequestMessage(HttpMethod.Post, url);
                request.Content = new StringContent(content ?? string.Empty, Encoding.UTF8, contentType);
                SetRequestHeaders(request, config?.Headers);
                return await client.SendAsync(request);
            }, config, $"POST {url}").Result;
            return httpResponseResult;
        }
        public HttpResponseResult Get(string url, HttpRequestConfig? config = null)
        {
            HttpResponseResult httpResponseResult = ExecuteAsync(async (client) =>
            {
                var request = new HttpRequestMessage(HttpMethod.Get, url);
                SetRequestHeaders(request, config?.Headers);
                return await client.SendAsync(request);
            }, config, $"GET {url}").Result;
            return httpResponseResult;
        }
        /// <summary>
        /// POST请求
        /// </summary>
        /// <param name="url">请求URL</param>
        /// <param name="content">请求内容</param>
        /// <param name="mediaType">媒体类型</param>
        /// <param name="config">请求配置</param>
        /// <returns></returns>
        public HttpResponseResult<TResponse> Post<TResponse>(string url, string content, string contentType = "application/json", HttpRequestConfig? config = null)
        {
            HttpResponseResult httpResponseResult = Post(url, content, contentType, config);
            HttpResponseResult<TResponse> result = new HttpResponseResult<TResponse>
            {
                IsSuccess = httpResponseResult.IsSuccess,
                StatusCode = httpResponseResult.StatusCode,
                Content = httpResponseResult.Content,
                Headers = httpResponseResult.Headers,
                Duration = httpResponseResult.Duration,
                ErrorMessage = httpResponseResult.ErrorMessage,
                Exception = httpResponseResult.Exception
            };
            if (result.IsSuccess && !string.IsNullOrEmpty(result.Content))
            {
                try
                {
                    TResponse? response = JsonSerializer.Deserialize<TResponse>(result.Content, new JsonSerializerOptions
                    {
                        PropertyNameCaseInsensitive = true
                    });
                    if (response != null)
                    {
                        result.Data = response;
                    }
                    else
                    {
                        result.IsSuccess = false;
                        result.ErrorMessage = "反序列化结果为null";
                    }
                }
                catch (Exception ex)
                {
                    result.IsSuccess = false;
                    result.ErrorMessage = $"反序列化失败: {ex.Message}";
                    result.Exception = ex;
                }
            }
            return result;
        }
        public HttpResponseResult<TResponse> Get<TResponse>(string url, HttpRequestConfig? config = null)
        {
            HttpResponseResult httpResponseResult = Get(url, config);
            HttpResponseResult<TResponse> result = new HttpResponseResult<TResponse>
            {
                IsSuccess = httpResponseResult.IsSuccess,
                StatusCode = httpResponseResult.StatusCode,
                Content = httpResponseResult.Content,
                Headers = httpResponseResult.Headers,
                Duration = httpResponseResult.Duration,
                ErrorMessage = httpResponseResult.ErrorMessage,
                Exception = httpResponseResult.Exception
            };
            if (result.IsSuccess && !string.IsNullOrEmpty(result.Content))
            {
                try
                {
                    TResponse? response = JsonSerializer.Deserialize<TResponse>(result.Content, new JsonSerializerOptions
                    {
                        PropertyNameCaseInsensitive = true
                    });
                    if (response != null)
                    {
                        result.Data = response;
                    }
                    else
                    {
                        result.IsSuccess = false;
                        result.ErrorMessage = "反序列化结果为null";
                    }
                }
                catch (Exception ex)
                {
                    result.IsSuccess = false;
                    result.ErrorMessage = $"反序列化失败: {ex.Message}";
                    result.Exception = ex;
                }
            }
            return result;
        }
        /// <summary>
        /// æ‰§è¡ŒHTTP请求
        /// </summary>
        private async Task<HttpResponseResult> ExecuteAsync(Func<HttpClient, Task<HttpResponseMessage>> requestFunc, HttpRequestConfig? config, string requestInfo)
        {
            var result = new HttpResponseResult();
            var stopwatch = System.Diagnostics.Stopwatch.StartNew();
            config ??= new HttpRequestConfig();
            try
            {
                using var client = CreateHttpClient(config);
                HttpResponseMessage? response = null;
                Exception? lastException = null;
                // é‡è¯•机制
                for (int retry = 0; retry <= config.MaxRetryCount; retry++)
                {
                    try
                    {
                        response = await requestFunc(client);
                        break;
                    }
                    catch (Exception ex) when (retry < config.MaxRetryCount)
                    {
                        lastException = ex;
                        if (config.EnableLogging)
                        {
                            // TODO:日志记录
                        }
                        await Task.Delay(config.RetryIntervalMs, default);
                    }
                }
                if (response == null)
                {
                    throw lastException ?? new HttpRequestException("请求失败");
                }
                result.StatusCode = response.StatusCode;
                result.IsSuccess = response.IsSuccessStatusCode;
                // è¯»å–响应内容
                result.Content = await response.Content.ReadAsStringAsync();
                // èŽ·å–å“åº”å¤´
                result.Headers = new Dictionary<string, IEnumerable<string>>();
                foreach (var header in response.Headers)
                {
                    result.Headers[header.Key] = header.Value;
                }
                foreach (var header in response.Content.Headers)
                {
                    result.Headers[header.Key] = header.Value;
                }
                if (config.EnableLogging)
                {
                    // TODO:日志记录
                }
            }
            catch (Exception ex)
            {
                result.IsSuccess = false;
                result.ErrorMessage = ex.Message;
                result.Exception = ex;
                if (config.EnableLogging)
                {
                    // TODO:日志记录
                }
            }
            finally
            {
                stopwatch.Stop();
                result.Duration = stopwatch.ElapsedMilliseconds;
            }
            return result;
        }
        /// <summary>
        /// åˆ›å»ºHttpClient
        /// </summary>
        private HttpClient CreateHttpClient(HttpRequestConfig config)
        {
            var client = _httpClientFactory.CreateClient();
            client.Timeout = TimeSpan.FromMilliseconds(config.TimeoutMs);
            // è®¾ç½®é»˜è®¤è¯·æ±‚头
            client.DefaultRequestHeaders.Clear();
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            return client;
        }
        /// <summary>
        /// è®¾ç½®è¯·æ±‚头
        /// </summary>
        private void SetRequestHeaders(HttpRequestMessage request, Dictionary<string, string>? headers)
        {
            if (headers != null)
            {
                foreach (var header in headers)
                {
                    if (!request.Headers.Contains(header.Key))
                    {
                        request.Headers.Add(header.Key, header.Value);
                    }
                }
            }
        }
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Core/Util/HttpRequestConfig.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEA_Core.Util
{
    /// <summary>
    /// HTTP请求配置
    /// </summary>
    public class HttpRequestConfig
    {
        /// <summary>
        /// è¶…时时间(毫秒)
        /// </summary>
        public int TimeoutMs { get; set; } = 30000;
        /// <summary>
        /// æœ€å¤§é‡è¯•次数
        /// </summary>
        public int MaxRetryCount { get; set; } = 3;
        /// <summary>
        /// é‡è¯•间隔(毫秒)
        /// </summary>
        public int RetryIntervalMs { get; set; } = 1000;
        /// <summary>
        /// è¯·æ±‚头
        /// </summary>
        public Dictionary<string, string> Headers { get; set; } = new Dictionary<string, string>();
        /// <summary>
        /// æ˜¯å¦å¯ç”¨æ—¥å¿—
        /// </summary>
        public bool EnableLogging { get; set; } = true;
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Core/Util/HttpResponseResult.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEA_Core.Util
{
    /// <summary>
    /// HTTP响应结果
    /// </summary>
    public class HttpResponseResult
    {
        /// <summary>
        /// æ˜¯å¦æˆåŠŸ
        /// </summary>
        public bool IsSuccess { get; set; }
        /// <summary>
        /// HTTP状态码
        /// </summary>
        public HttpStatusCode StatusCode { get; set; }
        /// <summary>
        /// å“åº”内容
        /// </summary>
        public string Content { get; set; }
        /// <summary>
        /// å“åº”头
        /// </summary>
        public Dictionary<string, IEnumerable<string>> Headers { get; set; }
        /// <summary>
        /// è¯·æ±‚耗时(毫秒)
        /// </summary>
        public long Duration { get; set; }
        /// <summary>
        /// é”™è¯¯ä¿¡æ¯
        /// </summary>
        public string ErrorMessage { get; set; }
        /// <summary>
        /// å¼‚常信息
        /// </summary>
        public Exception Exception { get; set; }
    }
    /// <summary>
    /// HTTP响应结果(泛型)
    /// </summary>
    public class HttpResponseResult<T> : HttpResponseResult
    {
        /// <summary>
        /// ååºåˆ—化后的数据
        /// </summary>
        public T Data { get; set; }
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_DTO/Base/UnitConvertResultDTO.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEA_DTO.Base
{
    /// <summary>
    ///
    /// </summary>
    public class UnitConvertResultDTO
    {
        /// <summary>
        ///
        /// </summary>
        public string MaterialCode { get; set; }
        /// <summary>
        ///
        /// </summary>
        public string FromUnit { get; set; }
        /// <summary>
        ///
        /// </summary>
        public string ToUnit { get; set; }
        /// <summary>
        ///
        /// </summary>
        public decimal FromQuantity { get; set; }
        /// <summary>
        ///
        /// </summary>
        public decimal ToQuantity { get; }
        /// <summary>
        ///
        /// </summary>
        public decimal UnitRatio { get; set; }
        /// <summary>
        ///
        /// </summary>
        /// <param name="materialCode"></param>
        /// <param name="fromUnit"></param>
        /// <param name="toUnit"></param>
        /// <param name="fromQuantity"></param>
        /// <param name="unitRatio"></param>
        public UnitConvertResultDTO(string materialCode, string fromUnit, string toUnit, decimal fromQuantity, decimal unitRatio)
        {
            MaterialCode = materialCode;
            FromUnit = fromUnit;
            ToUnit = toUnit;
            FromQuantity = fromQuantity;
            ToQuantity = fromQuantity * unitRatio;
            UnitRatio = unitRatio;
        }
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_DTO/CalcOut/OutboundCalculationDTO.cs
@@ -40,11 +40,5 @@
        /// åŽ‚åŒº
        /// </summary>
        public string FactoryArea { get; set; }
        /// <summary>
        /// æ˜¯å¦å¤šæ˜Žç»†å‡ºåº“
        /// </summary>
        public bool IsMultiDetail { get; set; }
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_DTO/CalcOut/PickingOutboundRequestDTO.cs
@@ -39,11 +39,5 @@
        /// å‡ºåº“目标位置
        /// </summary>
        public string OutboundTargetLocation { get; set; }
        /// <summary>
        /// æ˜¯å¦å¤šæ˜Žç»†å‡ºåº“(通过DetailIds数量判断,也可手动指定)
        /// </summary>
        public bool IsMultiDetail => DetailIds?.Count > 1;
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_DTO/ReturnMES/BaseReturnDTO.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEA_DTO.ReturnMES
{
    /// <summary>
    ///
    /// </summary>
    public class BaseReturnDTO
    {
        /// <summary>
        ///
        /// </summary>
        public string ReqCode { get; set; } = Guid.NewGuid().ToString();
        /// <summary>
        ///
        /// </summary>
        public string ReqTime { get; set; } = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_DTO/ReturnMES/MaterialOutboundReturnDTO.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,126 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEA_DTO.ReturnMES
{
    /// <summary>
    ///
    /// </summary>
    public class MaterialOutboundReturnDTO : BaseReturnDTO
    {
        /// <summary>
        /// å•号
        /// </summary>
        public string OrderNo {  get; set; }
        /// <summary>
        /// çŠ¶æ€
        /// </summary>
        public int Status {  get; set; }
        /// <summary>
        /// åŽ‚åŒº
        /// </summary>
        public string FactoryArea {  get; set; }
        /// <summary>
        /// ä¸šåŠ¡ç±»åž‹
        /// </summary>
        public string Business_type {  get; set; }
        /// <summary>
        /// 1新增2修改3删除
        /// </summary>
        public int OperationType { get; set; }
        /// <summary>
        /// æ“ä½œäºº
        /// </summary>
        public string Operator {  get; set; }
        /// <summary>
        /// å‘料单
        /// </summary>
        public string DocumentsNO {  get; set; }
        /// <summary>
        /// æ˜Žç»†
        /// </summary>
        public List<MaterialOutboundDetail> Details { get; set; }
    }
    /// <summary>
    /// æ˜Žç»†
    /// </summary>
    public class MaterialOutboundDetail
    {
        /// <summary>
        /// ç‰©æ–™ç¼–码
        /// </summary>
        public string MaterialCode {  get; set; }
        /// <summary>
        /// è¡Œå·
        /// </summary>
        public string LineNo {  get; set; }
        /// <summary>
        /// æ•°é‡
        /// </summary>
        public decimal Qty {  get; set; }
        /// <summary>
        /// æœ¬æ¬¡å·²å‘æ•°
        /// </summary>
        public decimal CurrentDeliveryQty {  get; set; }
        /// <summary>
        /// ä»“库
        /// </summary>
        public string WarehouseCode {  get; set; }
        /// <summary>
        /// å•位
        /// </summary>
        public string Unit {  get; set; }
        /// <summary>
        /// æ¡ç ä¿¡æ¯
        /// </summary>
        public List<Barcodes> Barcodes { get; set; }
    }
    /// <summary>
    /// æ¡ç ä¿¡æ¯
    /// </summary>
    public class Barcodes
    {
        /// <summary>
        /// æ¡ç 
        /// </summary>
        public string Barcode { get; set; }
        /// <summary>
        /// æ•°é‡
        /// </summary>
        public decimal Qty { get; set; }
        /// <summary>
        /// ä¾›åº”商
        /// </summary>
        public string SupplyCode { get; set; }
        /// <summary>
        /// æ‰¹æ¬¡
        /// </summary>
        public string BatchNo { get; set; }
        /// <summary>
        /// å•位
        /// </summary>
        public string Unit { get; set; }
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_DTO/ReturnMES/MesResponseDTO.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEA_DTO.ReturnMES
{
    /// <summary>
    ///
    /// </summary>
    public class MesResponseDTO
    {
        /// <summary>
        ///
        /// </summary>
        public string Code { get; set; }
        /// <summary>
        ///
        /// </summary>
        public string Message { get; set; }
        /// <summary>
        ///
        /// </summary>
        public object Data { get; set; }
        /// <summary>
        ///
        /// </summary>
        public string ResponseTime { get; set; }
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_IBasicService/IBasicService.cs
@@ -4,10 +4,11 @@
using System.Text;
using System.Threading.Tasks;
using WIDESEA_Core;
using WIDESEA_DTO.Base;
namespace WIDESEA_IBasicService
{
    public interface IBasicService: IDependency
    public interface IBasicService : IDependency
    {
        /// <summary>
        /// è´§ä½ä¸šåС层
@@ -27,5 +28,78 @@
        IPalletCodeInfoService PalletCodeInfoService { get; }
        IMaterielCodeInfoService MaterielCodeInfoService { get; }
        IMaterialUnitService MaterialUnitService { get; }
        #region
        string CreateCodeByRule(string ruleCode);
        #endregion
        #region å•位转换
        /// <summary>
        /// å•位转换
        /// </summary>
        /// <param name="materialCode"></param>
        /// <param name="fromUnit"></param>
        /// <param name="toUnit"></param>
        /// <param name="quantity"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public UnitConvertResultDTO UnitQuantityConvert(string materialCode, string fromUnit, string toUnit, decimal quantity);
        /// <summary>
        /// å•位转换,领料转采购
        /// </summary>
        /// <param name="materialCode"></param>
        /// <param name="quantity"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public UnitConvertResultDTO UnitUsageToPurchase(string materialCode, decimal quantity);
        /// <summary>
        /// å•位转换,领料转库存
        /// </summary>
        /// <param name="materialCode"></param>
        /// <param name="quantity"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public UnitConvertResultDTO UnitUsageToInventory(string materialCode, decimal quantity);
        /// <summary>
        /// å•位转换,采购转库存
        /// </summary>
        /// <param name="materialCode"></param>
        /// <param name="quantity"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public UnitConvertResultDTO UnitPurchaseToInventory(string materialCode, decimal quantity);
        /// <summary>
        /// å•位转换,采购转领料
        /// </summary>
        /// <param name="materialCode"></param>
        /// <param name="quantity"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public UnitConvertResultDTO UnitPurchaseToUsage(string materialCode, decimal quantity);
        /// <summary>
        /// å•位转换,库存转领料
        /// </summary>
        /// <param name="materialCode"></param>
        /// <param name="quantity"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public UnitConvertResultDTO UnitInventoryToUsage(string materialCode, decimal quantity);
        /// <summary>
        /// å•位转换,库存转采购
        /// </summary>
        /// <param name="materialCode"></param>
        /// <param name="quantity"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public UnitConvertResultDTO UnitInventoryToPurchase(string materialCode, decimal quantity);
        #endregion
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_IBasicService/MESOperation/IFeedbackMesService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEA_Core;
namespace WIDESEA_IBasicService
{
    public interface IFeedbackMesService : IDependency
    {
        void MaterialOutboundFeedback(string orderNo);
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Model/Models/Outbound/Dt_OutboundOrderDetail.cs
@@ -48,24 +48,24 @@
        /// è¡Œå·
        /// </summary>
        [SugarColumn(IsNullable = false, ColumnDescription = "行号", DefaultValue = "0")]
        public int RowNo {  get; set; }
        public int RowNo { get; set; }
        /// <summary>
        /// å•据数量
        /// </summary>
        [SugarColumn(IsNullable = false,  ColumnDescription = "单据数量")]
        [SugarColumn(IsNullable = false, ColumnDescription = "单据数量")]
        public decimal OrderQuantity { get; set; }
        /// <summary>
        /// é”å®šæ•°é‡
        /// </summary>
        [SugarColumn(IsNullable = false,  ColumnDescription = "锁定数量", DefaultValue = "0")]
        [SugarColumn(IsNullable = false, ColumnDescription = "锁定数量", DefaultValue = "0")]
        public decimal LockQuantity { get; set; }
        /// <summary>
        /// å·²å‡ºæ•°é‡
        /// </summary>
        [SugarColumn(IsNullable = false,  ColumnDescription = "已出数量", DefaultValue = "0")]
        [SugarColumn(IsNullable = false, ColumnDescription = "已出数量", DefaultValue = "0")]
        public decimal OverOutQuantity { get; set; }
        /// <summary>
@@ -83,14 +83,14 @@
        /// è¡Œå·
        /// é»˜è®¤å€¼:
        ///</summary>
        [SugarColumn(ColumnName = "lineNo", ColumnDescription = "行号", DefaultValue= "0")]
        [SugarColumn(ColumnName = "lineNo", ColumnDescription = "行号", DefaultValue = "0")]
        public string? lineNo { get; set; }
        /// <summary>
        /// æŒªæ–™æ•°é‡
        /// é»˜è®¤å€¼:
        ///</summary>
        [SugarColumn(ColumnName = "MoveQty", ColumnDescription = "挪料数量",IsNullable = true)]
        [SugarColumn(ColumnName = "MoveQty", ColumnDescription = "挪料数量", IsNullable = true)]
        public decimal MoveQty { get; set; }
        /// <summary>
@@ -111,7 +111,7 @@
        /// å•位
        /// é»˜è®¤å€¼:
        ///</summary>
        [SugarColumn(ColumnName = "barcodeUnit", ColumnDescription = "单位", IsNullable = true    )]
        [SugarColumn(ColumnName = "barcodeUnit", ColumnDescription = "单位", IsNullable = true)]
        public string BarcodeUnit { get; set; } = null!;
@@ -119,8 +119,8 @@
        ///  
        /// é»˜è®¤å€¼:
        ///</summary>
        [SugarColumn(ColumnName = "barcodemoveQty", ColumnDescription = "数量" , DefaultValue = "0", IsNullable = true)]
        public decimal BarcodeMoveQty { get; set; }
        [SugarColumn(ColumnName = "barcodemoveQty", ColumnDescription = "数量", DefaultValue = "0", IsNullable = true)]
        public decimal BarcodeMoveQty { get; set; }
        /// <summary>
        /// ä»“库
        /// é»˜è®¤å€¼:
@@ -160,5 +160,17 @@
        [SugarColumn(IsNullable = true, ColumnDescription = "虚拟出入库数量")]
        public decimal NoStockOutQty { get; set; }
        // æ–°å¢žå­—段
        /// <summary>
        ///
        /// </summary>
        [SugarColumn(IsNullable = true, ColumnDescription = "回传MES数据")]
        public string ReturnJsonData { get; set; }
        [SugarColumn(IsNullable = true)]
        public decimal CurrentDeliveryQty { get; set; }
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Model/Models/Record/Dt_MesReturnRecord.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,109 @@
using SqlSugar;
using System;
using WIDESEA_Core.DB.Models;
namespace WIDESEA_Model.Models
{
    /// <summary>
    /// MES回传记录表
    /// </summary>
    [SugarTable("Dt_MesReturnRecord")]
    public class Dt_MesReturnRecord : BaseEntity
    {
        /// <summary>
        /// ä¸»é”®
        /// </summary>
        [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
        public int Id { get; set; }
        /// <summary>
        /// å•据类型
        /// </summary>
        [SugarColumn(IsNullable = false)]
        public int OrderType { get; set; }
        /// <summary>
        /// å•据主表ID
        /// </summary>
        [SugarColumn(IsNullable = false)]
        public int OrderId { get; set; }
        /// <summary>
        /// å•据编号
        /// </summary>
        [SugarColumn(IsNullable = false, Length = 50)]
        public string OrderNo { get; set; }
        /// <summary>
        /// å›žä¼ ç±»åž‹ï¼š1=整单,2=分批
        /// </summary>
        [SugarColumn(IsNullable = false)]
        public int ReturnType { get; set; }
        /// <summary>
        /// å›žä¼ æŽ¥å£ç±»åž‹ï¼š1=出库,2=入库,3=调拨
        /// </summary>
        [SugarColumn(IsNullable = false)]
        public int InterfaceType { get; set; }
        /// <summary>
        /// å›žä¼ æ•°æ®ï¼ˆJSON格式,包含完整的回传数据)
        /// </summary>
        [SugarColumn(IsNullable = false, Length = int.MaxValue)]
        public string RequestData { get; set; }
        /// <summary>
        /// API地址
        /// </summary>
        [SugarColumn(IsNullable = false, Length = 200)]
        public string ApiUrl { get; set; }
        /// <summary>
        /// è¿”回报文(JSON格式)
        /// </summary>
        [SugarColumn(Length = int.MaxValue, IsNullable = true)]
        public string ResponseData { get; set; }
        /// <summary>
        /// HTTP状态码
        /// </summary>
        [SugarColumn(IsNullable = true)]
        public int? HttpStatusCode { get; set; }
        /// <summary>
        /// å›žä¼ æ¬¡æ•°
        /// </summary>
        [SugarColumn(IsNullable = false)]
        public int ReturnCount { get; set; }
        /// <summary>
        /// è¯·æ±‚代码(重试时保持不变)
        /// </summary>
        [SugarColumn(IsNullable = false, Length = 50)]
        public string RequestCode { get; set; }
        /// <summary>
        /// å›žä¼ çŠ¶æ€ï¼š1=回传成功,2=回传失败
        /// </summary>
        [SugarColumn(IsNullable = false)]
        public int ReturnStatus { get; set; }
        /// <summary>
        /// æœ€åŽå›žä¼ æ—¶é—´
        /// </summary>
        [SugarColumn(IsNullable = true)]
        public DateTime? LastReturnTime { get; set; }
        /// <summary>
        /// å›žä¼ æˆåŠŸæ—¶é—´
        /// </summary>
        [SugarColumn(IsNullable = true)]
        public DateTime? SuccessTime { get; set; }
        /// <summary>
        /// å¤±è´¥åŽŸå› 
        /// </summary>
        [SugarColumn(Length = 500, IsNullable = true)]
        public string FailureReason { get; set; }
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundOrderDetailService.cs
@@ -27,17 +27,15 @@
        private readonly IOutStockLockInfoService _outStockLockInfoService;
        private readonly ILocationInfoService _locationInfoService;
        private readonly IBasicService _basicService;
        private readonly IRecordService _recordService;
        private readonly IOutboundOrderService _outboundOrderService;
        private readonly ILocationStatusChangeRecordService _locationStatusChangeRecordService;
        private readonly ILogger<OutboundOrderDetailService> _logger;
        public OutboundOrderDetailService(IRepository<Dt_OutboundOrderDetail> BaseDal, IUnitOfWorkManage unitOfWorkManage, IStockService stockService, IOutStockLockInfoService outStockLockInfoService, IBasicService basicService, IRecordService recordService, ILocationInfoService locationInfoService, ILocationStatusChangeRecordService locationStatusChangeRecordService, IOutboundOrderService outboundOrderService, ILogger<OutboundOrderDetailService> logger) : base(BaseDal)
        public OutboundOrderDetailService(IRepository<Dt_OutboundOrderDetail> BaseDal, IUnitOfWorkManage unitOfWorkManage, IStockService stockService, IOutStockLockInfoService outStockLockInfoService, IRecordService recordService, ILocationInfoService locationInfoService, ILocationStatusChangeRecordService locationStatusChangeRecordService, IOutboundOrderService outboundOrderService, ILogger<OutboundOrderDetailService> logger) : base(BaseDal)
        {
            _unitOfWorkManage = unitOfWorkManage;
            _stockService = stockService;
            _outStockLockInfoService = outStockLockInfoService;
            _basicService = basicService;
            _recordService = recordService;
            _locationInfoService = locationInfoService;
            _locationStatusChangeRecordService = locationStatusChangeRecordService;
@@ -46,8 +44,6 @@
        }
        /// <summary>
        /// åˆ†é…å‡ºåº“库存  æŒ‰å…ˆè¿›å…ˆå‡ºåŽŸåˆ™åˆ†é…
        /// </summary>
        public (List<Dt_StockInfo>, List<Dt_OutboundOrderDetail>, List<Dt_OutStockLockInfo>, List<Dt_LocationInfo>)
@@ -78,14 +74,14 @@
            // æŒ‰ç‰©æ–™å’Œæ‰¹æ¬¡åˆ†ç»„处理
            var groupDetails = outboundOrderDetails
                .GroupBy(x => new { x.MaterielCode, x.BatchNo, x.SupplyCode,x.WarehouseCode })
                .GroupBy(x => new { x.MaterielCode, x.BatchNo, x.SupplyCode, x.WarehouseCode })
                .Select(x => new
                {
                    MaterielCode = x.Key.MaterielCode,
                    BatchNo = x.Key.BatchNo,
                    SupplyCode = x.Key.SupplyCode,
                    Details = x.ToList(),
                    WarehouseCode=x.Key.WarehouseCode,
                    WarehouseCode = x.Key.WarehouseCode,
                    TotalNeedQuantity = CalculateReassignNeedQuantity(x.ToList())
                })
                .Where(x => x.TotalNeedQuantity > 0)
@@ -94,9 +90,9 @@
            foreach (var item in groupDetails)
            {
                var needQuantity = item.TotalNeedQuantity;
                // èŽ·å–å¯ç”¨åº“å­˜ï¼ˆæŒ‰å…ˆè¿›å…ˆå‡ºæŽ’åºï¼‰
                List<Dt_StockInfo> stockInfos = _stockService.StockInfoService.GetUseableStocks(item.MaterielCode, item.BatchNo, item.SupplyCode,item.WarehouseCode, outboundOrder.FactoryArea);
                List<Dt_StockInfo> stockInfos = _stockService.StockInfoService.GetUseableStocks(item.MaterielCode, item.BatchNo, item.SupplyCode, item.WarehouseCode, outboundOrder.FactoryArea);
                if (!stockInfos.Any())
                {
@@ -128,7 +124,7 @@
                // æ›´æ–°åº“存和托盘状态
               UpdateNormalStocksAndPalletsStatus(autoAssignStocks, stockAllocations);
                UpdateNormalStocksAndPalletsStatus(autoAssignStocks, stockAllocations);
            }
            if (outStocks.Any())
@@ -150,13 +146,13 @@
                if (stockAllocations.TryGetValue(stockDetail.Id, out decimal allocatedQty) && allocatedQty > 0)
                {
                      _stockService.StockInfoService.Db.Updateable<Dt_StockInfo>()
                        .SetColumns(x => new Dt_StockInfo
                        {
                            StockStatus = (int)StockStatusEmun.出库锁定,
                        })
                        .Where(x => x.Id == stock.Id)
                        .ExecuteCommand();
                    _stockService.StockInfoService.Db.Updateable<Dt_StockInfo>()
                      .SetColumns(x => new Dt_StockInfo
                      {
                          StockStatus = (int)StockStatusEmun.出库锁定,
                      })
                      .Where(x => x.Id == stock.Id)
                      .ExecuteCommand();
                }
            }
        }
@@ -312,13 +308,13 @@
            // æŒ‰ç‰©æ–™å’Œæ‰¹æ¬¡åˆ†ç»„处理(这里只有一个明细)
            var groupDetails = new List<Dt_OutboundOrderDetail> { orderDetail }
                .GroupBy(x => new { x.MaterielCode, x.BatchNo, x.SupplyCode ,x.WarehouseCode})
                .GroupBy(x => new { x.MaterielCode, x.BatchNo, x.SupplyCode, x.WarehouseCode })
                .Select(x => new
                {
                    MaterielCode = x.Key.MaterielCode,
                    BatchNo = x.Key.BatchNo,
                    SupplyCode = x.Key.SupplyCode,
                    WarehouseCode=x.Key.WarehouseCode,
                    WarehouseCode = x.Key.WarehouseCode,
                    Details = x.ToList(),
                    TotalNeedQuantity = batchQuantity  // ä½¿ç”¨åˆ†æ‰¹æ•°é‡
                })
@@ -330,7 +326,7 @@
                var needQuantity = item.TotalNeedQuantity;
                // èŽ·å–å¯ç”¨åº“å­˜ï¼ˆæŒ‰å…ˆè¿›å…ˆå‡ºæŽ’åºï¼‰
                List<Dt_StockInfo> stockInfos = _stockService.StockInfoService.GetUseableStocks(item.MaterielCode, item.BatchNo, item.SupplyCode,item.WarehouseCode,outboundOrder.FactoryArea);
                List<Dt_StockInfo> stockInfos = _stockService.StockInfoService.GetUseableStocks(item.MaterielCode, item.BatchNo, item.SupplyCode, item.WarehouseCode, outboundOrder.FactoryArea);
                if (!stockInfos.Any())
                {
                    throw new Exception($"物料[{item.MaterielCode}]批次[{item.BatchNo}]未找到可分配库存");
@@ -383,11 +379,11 @@
                var stockDetail = stock.Details.First();
                if (stockAllocations.TryGetValue(stockDetail.Id, out decimal allocatedQty) && allocatedQty > 0)
                {
                    await _stockService.StockInfoService.Db.Updateable<Dt_StockInfo>()
                        .SetColumns(x => new Dt_StockInfo
                        {
                            StockStatus = (int)StockStatusEmun.出库锁定,
                            StockStatus = (int)StockStatusEmun.出库锁定,
                        })
                        .Where(x => x.Id == stock.Id)
                        .ExecuteCommandAsync();
@@ -595,9 +591,55 @@
                        SearchParameters? searchParameters = searchParametersList.FirstOrDefault(x => x.Name == nameof(Dt_InboundOrderDetail.OrderId).FirstLetterToLower());
                        if (searchParameters != null)
                        {
                            sugarQueryable1 = sugarQueryable1.Where(x => x.OrderId == searchParameters.Value.ObjToInt());
                            var dataList = sugarQueryable1.ToPageList(options.Page, options.Rows, ref totalCount);
                            return new PageGridData<Dt_OutboundOrderDetail>(totalCount, dataList);
                            Dt_OutboundOrder outboundOrder = _outboundOrderService.Repository.QueryFirst(x => x.Id == searchParameters.Value.ObjToInt());
                            if (outboundOrder != null)
                            {
                                if (outboundOrder.IsBatch == 0)
                                {
                                    sugarQueryable1 = sugarQueryable1.Where(x => x.OrderId == searchParameters.Value.ObjToInt());
                                    var dataList = sugarQueryable1.ToPageList(options.Page, options.Rows, ref totalCount);
                                    return new PageGridData<Dt_OutboundOrderDetail>(totalCount, dataList);
                                }
                                else
                                {
                                    sugarQueryable1 = sugarQueryable1.Where(x => x.OrderId == searchParameters.Value.ObjToInt());
                                    sugarQueryable1.GroupBy(x => new { x.MaterielCode, x.MaterielName, x.BatchNo, x.SupplyCode, x.WarehouseCode }).Select(s => new Dt_OutboundOrderDetail
                                    {
                                        WarehouseCode = s.WarehouseCode,
                                        SupplyCode = s.SupplyCode,
                                        BatchNo = s.BatchNo,
                                        MaterielName = s.MaterielName,
                                        MaterielCode = s.MaterielCode,
                                        AllocatedQuantity = SqlFunc.AggregateSum(s.AllocatedQuantity),
                                        OrderQuantity = SqlFunc.AggregateSum(s.OrderQuantity),
                                        PickedQty = SqlFunc.AggregateSum(s.PickedQty),
                                        OverOutQuantity = SqlFunc.AggregateSum(s.OverOutQuantity),
                                        MoveQty = SqlFunc.AggregateSum(s.MoveQty),
                                        NoStockOutQty = SqlFunc.AggregateSum(s.NoStockOutQty),
                                        LockQuantity = SqlFunc.AggregateSum(s.LockQuantity),
                                        BarcodeMoveQty = SqlFunc.AggregateSum(s.BarcodeMoveQty),
                                        BarcodeQty =SqlFunc.AggregateMin( s.BarcodeQty),
                                        BarcodeUnit = SqlFunc.AggregateMin(s.BarcodeUnit),
                                        BatchAllocateStatus = SqlFunc.AggregateMin(s.BatchAllocateStatus),
                                        CreateDate = SqlFunc.AggregateMin(s.CreateDate),
                                        Creater = SqlFunc.AggregateMin(s.Creater),
                                        documentsNO = SqlFunc.AggregateMin(s.documentsNO),
                                        Id = SqlFunc.AggregateMin(s.Id),
                                        lineNo = SqlFunc.AggregateMin(s.lineNo),
                                        Modifier = SqlFunc.AggregateMin(s.Modifier),
                                        ModifyDate = SqlFunc.AggregateMin(s.ModifyDate),
                                        OrderDetailStatus = SqlFunc.AggregateMin(s.OrderDetailStatus),
                                        OrderId = SqlFunc.AggregateMin(s.OrderId),
                                        Remark = SqlFunc.AggregateMin(s.Remark),
                                        ReturnJsonData = SqlFunc.AggregateMin(s.ReturnJsonData),
                                        ReturnToMESStatus = SqlFunc.AggregateMin(s.ReturnToMESStatus),
                                        RowNo = SqlFunc.AggregateMin(s.RowNo),
                                        Unit = SqlFunc.AggregateMin(s.Unit)
                                    });
                                    var dataList = sugarQueryable1.ToPageList(options.Page, options.Rows, ref totalCount);
                                    return new PageGridData<Dt_OutboundOrderDetail>(totalCount, dataList);
                                }
                            }
                        }
                    }
@@ -608,7 +650,7 @@
        }
        public (List<Dt_StockInfo>, Dt_OutboundOrderDetail, List<Dt_OutStockLockInfo>, List<Dt_LocationInfo>)AssignStockOutbound(Dt_OutboundOrderDetail outboundOrderDetail, List<StockSelectViewDTO> stockSelectViews)
        public (List<Dt_StockInfo>, Dt_OutboundOrderDetail, List<Dt_OutStockLockInfo>, List<Dt_LocationInfo>) AssignStockOutbound(Dt_OutboundOrderDetail outboundOrderDetail, List<StockSelectViewDTO> stockSelectViews)
        {
            // éªŒè¯ç”¨æˆ·é€‰æ‹©
            (bool, string) checkResult = CheckSelectStockDeital(outboundOrderDetail, stockSelectViews);
@@ -668,10 +710,10 @@
            }
            // å¦‚果用户选择的库存不够,自动分配剩余部分
            if (remainingNeedQuantity > 0)
            {
            }
            // æ›´æ–°é”å®šæ•°é‡
@@ -724,7 +766,7 @@
                .Where(d => d.MaterielCode == detail.MaterielCode &&
                           (d.StockQuantity - d.OutboundQuantity) > 0 &&
                           d.Barcode == barcode); // åªåˆ†é…æŒ‡å®šæ¡ç 
            query = query.Where(x => x.WarehouseCode == detail.WarehouseCode);
            if (!string.IsNullOrEmpty(detail.BatchNo))
@@ -761,7 +803,7 @@
            var query = stock.Details.AsQueryable()
                .Where(d => d.MaterielCode == detail.MaterielCode &&
                           (d.StockQuantity - d.OutboundQuantity) > 0);
               // .OrderBy(d => d.CreateDate);
            // .OrderBy(d => d.CreateDate);
            if (!string.IsNullOrEmpty(detail.BatchNo))
            {
@@ -772,7 +814,7 @@
            {
                query = query.Where(d => d.SupplyCode == detail.SupplyCode);
            }
            var sortedDetails= query.ToList().OrderBy(d => d.CreateDate);
            var sortedDetails = query.ToList().OrderBy(d => d.CreateDate);
            foreach (var stockDetail in sortedDetails)
@@ -795,9 +837,9 @@
        }
        private Dt_OutStockLockInfo CreateOutStockLockInfo(Dt_OutboundOrder outboundOrder, Dt_OutboundOrderDetail detail,
            Dt_StockInfo stock, decimal quantity,string barcode="")
            Dt_StockInfo stock, decimal quantity, string barcode = "")
        {
            return _outStockLockInfoService.GetOutStockLockInfo(outboundOrder, detail, stock, quantity, barcode);
        }
@@ -862,7 +904,7 @@
                }
                var available = CalculateAvailableQuantityByBarcode(stock, outboundOrderDetail.MaterielCode,
                    outboundOrderDetail.BatchNo, outboundOrderDetail.SupplyCode,selection.Barcode);
                    outboundOrderDetail.BatchNo, outboundOrderDetail.SupplyCode, selection.Barcode);
                if (available <= 0)
                {
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundQueryService.cs
@@ -18,7 +18,7 @@
        {
            try
            {
                List<Dt_OutStockLockInfo> outStockLockInfos = _outboundLockInfoService.Repository.QueryData(x => x.PalletCode == palletCode && x.OrderNo == orderNo);
                List<Dt_OutStockLockInfo> outStockLockInfos = _outboundLockInfoRepository.QueryData(x => x.PalletCode == palletCode && x.OrderNo == orderNo);
                return WebResponseContent.Instance.OK(data: outStockLockInfos);
            }
            catch (Exception ex)
@@ -39,7 +39,7 @@
            try
            {
                // æž„建查询条件
                var query = _stockChangeService.Repository.Db
                var query = _stockChangeRepository.Db
                    .Queryable<Dt_StockQuantityChangeRecord>()
                    .LeftJoin<Dt_OutboundOrder>((r, o) => r.OrderNo == o.OrderNo)
                    .Where((r, o) => r.ChangeType == (int)StockChangeTypeEnum.Outbound)
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_OutboundService/OutboundService.cs
@@ -1,12 +1,16 @@
using SqlSugar;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using SqlSugar;
using WIDESEA_Common.LocationEnum;
using WIDESEA_Common.OrderEnum;
using WIDESEA_Common.StockEnum;
using WIDESEA_Common.TaskEnum;
using WIDESEA_Core;
using WIDESEA_Core.BaseRepository;
using WIDESEA_Core.CodeConfigEnum;
using WIDESEA_Core.Helper;
using WIDESEA_DTO.CalcOut;
using WIDESEA_DTO.ReturnMES;
using WIDESEA_IBasicService;
using WIDESEA_IOutboundService;
using WIDESEA_IRecordService;
@@ -27,30 +31,34 @@
        public IOutStockLockInfoService OutboundStockLockInfoService { get; }
        private readonly ISqlSugarClient Db;
        private readonly IOutboundOrderDetailService _detailService;
        private readonly IOutboundOrderService _outboundOrderService;
        private readonly IOutStockLockInfoService _outboundLockInfoService;
        private readonly IStockInfoService _stockInfoService;
        private readonly IStockInfoDetailService _stockDetailService;
        private readonly ILocationInfoService _locationInfoService;
        private readonly IStockQuantityChangeRecordService _stockChangeService;
        private readonly IStockInfoDetail_HtyService _stockDetailHistoryService;
        private readonly IBasicService _basicService;
        public OutboundService(IUnitOfWorkManage unitOfWorkManage, IOutboundOrderDetailService outboundOrderDetailService, IOutboundOrderService outboundOrderService, IOutStockLockInfoService outboundStockLockInfoService, IStockInfoService stockInfoService, IStockInfoDetailService stockDetailService, ILocationInfoService locationInfoService, IStockQuantityChangeRecordService stockQuantityChangeRecordService, IStockInfoDetail_HtyService stockDetailHistoryService)
        private readonly IRepository<Dt_OutboundOrderDetail> _detailRepository;
        private readonly IRepository<Dt_OutboundOrder> _outboundRepository;
        private readonly IRepository<Dt_OutStockLockInfo> _outboundLockInfoRepository;
        private readonly IRepository<Dt_StockInfo> _stockInfoRepository;
        private readonly IRepository<Dt_StockInfoDetail> _stockDetailRepository;
        private readonly IRepository<Dt_LocationInfo> _locationInfoRepository;
        private readonly IRepository<Dt_StockQuantityChangeRecord> _stockChangeRepository;
        private readonly IRepository<Dt_StockInfoDetail_Hty> _stockDetailHistoryRepository;
        public OutboundService(IUnitOfWorkManage unitOfWorkManage, IRepository<Dt_OutboundOrderDetail> detailRepository, IRepository<Dt_OutboundOrder> outboundRepository, IRepository<Dt_OutStockLockInfo> outboundLockInfoRepository, IRepository<Dt_StockInfo> stockInfoRepository, IRepository<Dt_StockInfoDetail> stockDetailRepository, IRepository<Dt_StockQuantityChangeRecord> stockChangeRepository, IRepository<Dt_StockInfoDetail_Hty> stockDetailHistoryRepository, IBasicService basicService, IOutboundOrderDetailService outboundOrderDetailService, IOutboundOrderService outboundOrderService, IOutStockLockInfoService outboundStockLockInfoService)
        {
            _unitOfWorkManage = unitOfWorkManage;
            Db = _unitOfWorkManage.GetDbClient();
            OutboundOrderDetailService = outboundOrderDetailService;
            OutboundOrderService = outboundOrderService;
            OutboundStockLockInfoService = outboundStockLockInfoService;
            _detailService = outboundOrderDetailService;
            _outboundOrderService = outboundOrderService;
            _outboundLockInfoService = outboundStockLockInfoService;
            _stockInfoService = stockInfoService;
            _stockDetailService = stockDetailService;
            _locationInfoService = locationInfoService;
            _stockChangeService = stockQuantityChangeRecordService;
            _stockDetailHistoryService = stockDetailHistoryService;
            _detailRepository = detailRepository;
            _outboundRepository = outboundRepository;
            _outboundLockInfoRepository = outboundLockInfoRepository;
            _stockInfoRepository = stockInfoRepository;
            _stockDetailRepository = stockDetailRepository;
            _locationInfoRepository = basicService.LocationInfoService.Repository;
            _stockChangeRepository = stockChangeRepository;
            _stockDetailHistoryRepository = stockDetailHistoryRepository;
            _basicService = basicService;
        }
        /// <summary>
@@ -129,9 +137,17 @@
                    foreach (var detail in materielCalc.Details)
                    {
                        decimal lockQuantity = (detail.OrderQuantity - detail.OverOutQuantity);
                        detail.LockQuantity += lockQuantity; // å¢žåŠ é”å®šæ•°é‡ ä¸æ›´æ–° OverOutQuantity å’Œ OrderDetailStatus,因为还没有实际出库
                        outboundOrderDetails.Add(detail);
                        if (lockQuantity < materielCalc.UnallocatedQuantity)
                        {
                            detail.LockQuantity += lockQuantity; // å¢žåŠ é”å®šæ•°é‡ ä¸æ›´æ–° OverOutQuantity å’Œ OrderDetailStatus,因为还没有实际出库
                            outboundOrderDetails.Add(detail);
                        }
                        else
                        {
                            detail.LockQuantity += materielCalc.UnallocatedQuantity;
                            outboundOrderDetails.Add(detail);
                            break;
                        }
                    }
                }
@@ -139,7 +155,7 @@
                UpdateOutboundOrderStatus(request.OrderNo, (int)OutOrderStatusEnum.出库中);
                // 4. æ›´æ–°å‡ºåº“单明细锁定数量
                _detailService.Repository.UpdateData(outboundOrderDetails);
                _detailRepository.UpdateData(outboundOrderDetails);
                // 5. æ›´æ–°åº“存状态
                UpdateStockStatus(pickedDetails.Select(x => x.PalletCode).ToList(), StockStatusEmun.出库锁定.ObjToInt());
@@ -179,7 +195,7 @@
            try
            {
                Dt_OutboundOrder outboundOrder = _outboundOrderService.Repository.QueryFirst(x => x.OrderNo == request.OrderNo);
                Dt_OutboundOrder outboundOrder = _outboundRepository.QueryFirst(x => x.OrderNo == request.OrderNo);
                if (outboundOrder == null)
                {
                    result.CanOutbound = false;
@@ -188,10 +204,15 @@
                }
                result.FactoryArea = outboundOrder.FactoryArea;
                result.IsMultiDetail = request.IsMultiDetail;
                // èŽ·å–é€‰æ‹©çš„å‡ºåº“æ˜Žç»†
                List<Dt_OutboundOrderDetail> selectedDetails = _detailService.Repository.QueryData(x => x.OrderId == outboundOrder.Id && request.DetailIds.Contains(x.Id));
                List<Dt_OutboundOrderDetail> selectedDetails = _detailRepository.QueryData(x => x.OrderId == outboundOrder.Id && request.DetailIds.Contains(x.Id));
                if (outboundOrder.IsBatch == 1)
                {
                    selectedDetails = _detailRepository.QueryData(x => x.WarehouseCode == selectedDetails.First().WarehouseCode && x.MaterielCode == selectedDetails.First().MaterielCode && x.BatchNo == selectedDetails.First().BatchNo && x.SupplyCode == selectedDetails.First().SupplyCode);
                }
                if (!selectedDetails.Any())
                {
@@ -199,7 +220,6 @@
                    result.ErrorMessage = $"未找到选择的出库明细信息";
                    return result;
                }
                if (selectedDetails.Any(x => x.LockQuantity > x.OrderQuantity - x.MoveQty || x.OverOutQuantity > x.OrderQuantity - x.MoveQty))
                {
                    List<int> selectDetailIds = selectedDetails.Where(x => x.LockQuantity > x.OrderQuantity - x.MoveQty || x.OverOutQuantity > x.OrderQuantity - x.MoveQty).Select(x => x.Id).ToList();
@@ -212,7 +232,7 @@
                result.OutboundOrder = outboundOrder;
                result.SelectedDetails = selectedDetails;
                if (request.IsMultiDetail)
                if (outboundOrder.IsBatch == 0)
                {
                    // å¤šæ˜Žç»†å‡ºåº“:按物料分组处理
                    result.MaterielCalculations = CalcMaterielOutboundQuantities(outboundOrder, selectedDetails.ToList());
@@ -227,15 +247,21 @@
                        return result;
                    }
                    decimal lockQuantity = selectedDetails.Sum(x => x.LockQuantity);
                    decimal orderQuantity = selectedDetails.Sum(x => x.OrderQuantity);
                    decimal moveQuantity = selectedDetails.Sum(x => x.MoveQty);
                    decimal overQuantity = selectedDetails.Sum(x => x.OverOutQuantity);
                    Dt_OutboundOrderDetail? singleDetail = selectedDetails.First();
                    //判断可出库数量
                    if (singleDetail.OrderQuantity - singleDetail.LockQuantity - singleDetail.MoveQty <= 0)
                    if (orderQuantity - lockQuantity - moveQuantity < request.OutboundQuantity.Value || orderQuantity - overQuantity - moveQuantity < request.OutboundQuantity.Value)
                    {
                        result.CanOutbound = false;
                        result.ErrorMessage = $"本次出库数量 {request.OutboundQuantity.Value} è¶…过可出库数量 {singleDetail.OrderQuantity - singleDetail.LockQuantity - singleDetail.MoveQty}";
                        result.ErrorMessage = $"本次出库数量 {request.OutboundQuantity.Value} è¶…过可出库数量 {orderQuantity - lockQuantity - moveQuantity}";
                        return result;
                    }
                    result.MaterielCalculations = new List<MaterielOutboundCalculationDTO>()
                    {
                        new MaterielOutboundCalculationDTO
@@ -245,12 +271,12 @@
                            BatchNo = singleDetail.BatchNo,
                            SupplyCode = singleDetail.SupplyCode,
                            WarehouseCode = singleDetail.WarehouseCode,
                            TotalOrderQuantity = singleDetail.OrderQuantity - singleDetail.MoveQty,
                            TotalOverOutQuantity = singleDetail.OverOutQuantity,
                            AssignedQuantity = singleDetail.LockQuantity,
                            UnallocatedQuantity = singleDetail.OrderQuantity - singleDetail.LockQuantity - singleDetail.MoveQty,
                            MovedQuantity = singleDetail.MoveQty,
                            Details = new List<Dt_OutboundOrderDetail>() { singleDetail }
                            TotalOrderQuantity = orderQuantity - moveQuantity,
                            TotalOverOutQuantity = overQuantity,
                            AssignedQuantity = lockQuantity,
                            UnallocatedQuantity = request.OutboundQuantity.Value,
                            MovedQuantity = moveQuantity,
                            Details = selectedDetails
                        }
                    };
                }
@@ -297,7 +323,7 @@
                    UnallocatedQuantity = g.Sum(x => x.OrderQuantity - x.LockQuantity - x.MoveQty),
                    MovedQuantity = g.Sum(x => x.MoveQty),
                    Details = g.ToList(),
                    OutStockLockInfos = _outboundLockInfoService.Repository.QueryData(x => x.MaterielCode == g.Key.MaterielCode && x.BatchNo == g.Key.BatchNo && x.OrderType == (int)outboundOrder.OrderType && x.OrderNo == outboundOrder.OrderNo)
                    OutStockLockInfos = _outboundLockInfoRepository.QueryData(x => x.MaterielCode == g.Key.MaterielCode && x.BatchNo == g.Key.BatchNo && x.OrderType == (int)outboundOrder.OrderType && x.OrderNo == outboundOrder.OrderNo)
                })
                .ToList();
@@ -454,7 +480,7 @@
        private List<Dt_StockInfo> BuildStockQueryWithInfo(MaterielOutboundCalculationDTO materielCalc, string factoryArea)
        {
            // åŸºç¡€æŸ¥è¯¢æ¡ä»¶ï¼šç‰©æ–™ç¼–号、批次号(如果提供)、库存数量>0
            ISugarQueryable<Dt_StockInfoDetail> stockDetails = _stockDetailService.Repository.Db.Queryable<Dt_StockInfoDetail>().Where(x => x.MaterielCode == materielCalc.MaterielCode && x.StockQuantity > 0);
            ISugarQueryable<Dt_StockInfoDetail> stockDetails = _stockDetailRepository.Db.Queryable<Dt_StockInfoDetail>().Where(x => x.MaterielCode == materielCalc.MaterielCode && x.StockQuantity > 0);
            // æ ¹æ®æ¡ä»¶æ·»åŠ ä¾›åº”å•†ç¼–å·åŒ¹é…ï¼ˆä¸ä¸ºç©ºæ—¶æ‰éœ€è¦åŒ¹é…ï¼‰
            if (!string.IsNullOrEmpty(materielCalc.SupplyCode))
@@ -483,11 +509,11 @@
            List<Dt_StockInfoDetail> stockDetailList = stockDetails.ToList();
            // èŽ·å–å¯ç”¨è´§ä½ç¼–å·
            List<string> locationCodes = _locationInfoService.Repository.QueryData(x => (x.LocationStatus == LocationStatusEnum.InStock.ObjToInt() /*|| x.LocationStatus == LocationStatusEnum.Lock.ObjToInt()*/) && x.EnableStatus == EnableStatusEnum.Normal.ObjToInt()).Select(x => x.LocationCode).ToList();
            List<string> locationCodes = _locationInfoRepository.QueryData(x => (x.LocationStatus == LocationStatusEnum.InStock.ObjToInt() /*|| x.LocationStatus == LocationStatusEnum.Lock.ObjToInt()*/) && x.EnableStatus == EnableStatusEnum.Normal.ObjToInt()).Select(x => x.LocationCode).ToList();
            // èŽ·å–æ‰€æœ‰ç›¸å…³çš„åº“å­˜ä¿¡æ¯
            List<int> stockIds = stockDetailList.GroupBy(x => x.StockId).Select(x => x.Key).ToList();
            List<Dt_StockInfo> stockInfos = _stockInfoService.Repository.QueryData(x => stockIds.Contains(x.Id) && (x.StockStatus == StockStatusEmun.入库完成.ObjToInt() /*|| x.StockStatus == StockStatusEmun.出库锁定.ObjToInt()*/) && !string.IsNullOrEmpty(x.LocationCode) && locationCodes.Contains(x.LocationCode));
            List<Dt_StockInfo> stockInfos = _stockInfoRepository.QueryData(x => stockIds.Contains(x.Id) && (x.StockStatus == StockStatusEmun.入库完成.ObjToInt() /*|| x.StockStatus == StockStatusEmun.出库锁定.ObjToInt()*/) && !string.IsNullOrEmpty(x.LocationCode) && locationCodes.Contains(x.LocationCode));
            // åœ¨å†…存中关联数据
            foreach (var stockInfo in stockInfos)
@@ -652,7 +678,7 @@
        private decimal CalcTotalAllocatedQuantity(List<Dt_OutStockLockInfo> lockInfos, int stockId, string materielCode)
        {
            // æŸ¥è¯¢è¯¥æ‰˜ç›˜è¯¥ç‰©æ–™åœ¨æ‰€æœ‰é”å®šè®°å½•中的最大已分配数量
            List<Dt_OutStockLockInfo> lockRecords = _outboundLockInfoService.Repository.QueryData(x =>
            List<Dt_OutStockLockInfo> lockRecords = _outboundLockInfoRepository.QueryData(x =>
                x.StockId == stockId &&
                x.MaterielCode == materielCode);
@@ -672,11 +698,11 @@
        {
            try
            {
                Dt_OutboundOrder outboundOrder = _outboundOrderService.Repository.QueryFirst(x => x.OrderNo == orderNo);
                Dt_OutboundOrder outboundOrder = _outboundRepository.QueryFirst(x => x.OrderNo == orderNo);
                if (outboundOrder == null) return false;
                outboundOrder.OrderStatus = status;
                _outboundOrderService.Repository.UpdateData(outboundOrder);
                _outboundRepository.UpdateData(outboundOrder);
                return true;
            }
            catch
@@ -695,13 +721,13 @@
        {
            try
            {
                List<Dt_StockInfo> stockInfos = _stockInfoService.Repository.QueryData(x => palletCodes.Contains(x.PalletCode));
                List<Dt_StockInfo> stockInfos = _stockInfoRepository.QueryData(x => palletCodes.Contains(x.PalletCode));
                stockInfos.ForEach(stockInfo =>
                {
                    stockInfo.StockStatus = status;
                });
                _stockInfoService.Repository.UpdateData(stockInfos);
                _stockInfoRepository.UpdateData(stockInfos);
                return true;
            }
            catch
@@ -720,13 +746,13 @@
        {
            try
            {
                List<Dt_LocationInfo> locationInfos = _locationInfoService.Repository.QueryData(x => locationCodes.Contains(x.LocationCode));
                List<Dt_LocationInfo> locationInfos = _locationInfoRepository.QueryData(x => locationCodes.Contains(x.LocationCode));
                locationInfos.ForEach(x =>
                {
                    x.LocationStatus = status;
                });
                _locationInfoService.Repository.UpdateData(locationInfos);
                _locationInfoRepository.UpdateData(locationInfos);
                return true;
            }
            catch
@@ -745,10 +771,10 @@
            try
            {
                List<Dt_OutStockLockInfo> updateData = outStockLockInfos.Where(x => x.Id > 0).ToList();
                _outboundLockInfoService.Repository.UpdateData(updateData);
                _outboundLockInfoRepository.UpdateData(updateData);
                List<Dt_OutStockLockInfo> addData = outStockLockInfos.Where(x => x.Id <= 0).ToList();
                _outboundLockInfoService.Repository.AddData(addData);
                _outboundLockInfoRepository.AddData(addData);
                return true;
            }
@@ -772,7 +798,7 @@
            try
            {
                // 1. æ ¹æ®æ‰˜ç›˜å·æŸ¥æ‰¾åº“存信息
                Dt_StockInfo stockInfo = _stockInfoService.Repository.QueryFirst(x => x.PalletCode == request.PalletCode);
                Dt_StockInfo stockInfo = _stockInfoRepository.QueryFirst(x => x.PalletCode == request.PalletCode);
                if (stockInfo == null)
                {
                    response.Success = false;
@@ -781,7 +807,7 @@
                }
                // 2. æ ¹æ®æ¡ç æŸ¥æ‰¾åº“存明细
                Dt_StockInfoDetail stockDetail = _stockDetailService.Repository.QueryFirst(x => x.Barcode == request.Barcode);
                Dt_StockInfoDetail stockDetail = _stockDetailRepository.QueryFirst(x => x.Barcode == request.Barcode);
                if (stockDetail == null)
                {
                    response.Success = false;
@@ -798,7 +824,7 @@
                }
                // 4. æŸ¥æ‰¾å‡ºåº“单信息
                Dt_OutboundOrder outboundOrder = _outboundOrderService.Repository.QueryFirst(o => o.OrderNo == request.OrderNo);
                Dt_OutboundOrder outboundOrder = _outboundRepository.QueryFirst(o => o.OrderNo == request.OrderNo);
                if (outboundOrder == null)
                {
                    response.Success = false;
@@ -807,7 +833,7 @@
                }
                // 5. æŸ¥æ‰¾é”å®šè®°å½•
                Dt_OutStockLockInfo lockInfo = _outboundLockInfoService.Repository.QueryFirst(x =>
                Dt_OutStockLockInfo lockInfo = _outboundLockInfoRepository.QueryFirst(x =>
                    x.OrderNo == request.OrderNo &&
                    x.StockId == stockInfo.Id &&
                    x.MaterielCode == stockDetail.MaterielCode &&
@@ -886,33 +912,68 @@
                    {
                        if (allocatedQuantity <= 0) break;
                        if (item.OrderQuantity - item.MoveQty - item.OverOutQuantity >= allocatedQuantity)
                        //if (item.OrderQuantity - item.MoveQty - item.OverOutQuantity >= allocatedQuantity)
                        //{
                        //    item.OverOutQuantity += allocatedQuantity;
                        //    allocatedQuantity = 0;
                        //}
                        //else
                        //{
                        //    allocatedQuantity -= (item.OrderQuantity - item.MoveQty - item.OverOutQuantity);
                        //    item.OverOutQuantity = item.OrderQuantity - item.MoveQty;
                        //}
                        if (item.LockQuantity - item.OverOutQuantity >= allocatedQuantity)
                        {
                            item.OverOutQuantity += allocatedQuantity;
                            item.CurrentDeliveryQty += allocatedQuantity;
                            allocatedQuantity = 0;
                        }
                        else
                        {
                            allocatedQuantity -= (item.OrderQuantity - item.MoveQty - item.OverOutQuantity);
                            item.OverOutQuantity = item.OrderQuantity - item.MoveQty;
                            allocatedQuantity -= (item.LockQuantity - item.OverOutQuantity);
                            item.OverOutQuantity = item.LockQuantity;
                            item.CurrentDeliveryQty = item.LockQuantity;
                        }
                        updateDetails.Add(item);
                        List<Barcodes> barcodesList = new List<Barcodes>();
                        Barcodes barcodes = new Barcodes
                        {
                            Barcode = request.Barcode,
                            Qty = actualOutboundQuantity,
                            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);
                    }
                    lockInfo.SortedQuantity = lockInfo.SortedQuantity + actualOutboundQuantity;
                    if (lockInfo.SortedQuantity == lockInfo.AssignQuantity)
                    {
                        _outboundLockInfoService.Repository.DeleteAndMoveIntoHty(lockInfo, WIDESEA_Core.Enums.OperateTypeEnum.自动完成);
                        _outboundLockInfoRepository.DeleteAndMoveIntoHty(lockInfo, WIDESEA_Core.Enums.OperateTypeEnum.自动完成);
                    }
                    else
                    {
                        // æ›´æ–°é”å®šè®°å½•
                        _outboundLockInfoService.Repository.UpdateData(lockInfo);
                        _outboundLockInfoRepository.UpdateData(lockInfo);
                    }
                    // æ›´æ–°å‡ºåº“单明细的已出库数量
                    _detailService.Repository.UpdateData(updateDetails);
                    _detailRepository.UpdateData(updateDetails);
                    // æ›´æ–°é”å®šè®°å½•的累计已出库数量(需要更新该托盘该物料的所有相关记录)
                    //UpdateLockInfoAllocatedQuantity(stockInfo.Id, stockDetail.MaterielCode, stockDetail.BatchNo, actualOutboundQuantity);
@@ -974,7 +1035,7 @@
        /// <returns></returns>
        private List<Dt_OutboundOrderDetail> FindMatchingOutboundDetails(int orderId, Dt_StockInfoDetail stockDetail, List<int> detailIds)
        {
            List<Dt_OutboundOrderDetail> details = _detailService.Repository.QueryData(x =>
            List<Dt_OutboundOrderDetail> details = _detailRepository.QueryData(x =>
                x.OrderId == orderId &&
                x.MaterielCode == stockDetail.MaterielCode && x.OrderQuantity - x.MoveQty > x.OverOutQuantity && detailIds.Contains(x.Id));
@@ -1002,7 +1063,6 @@
                Math.Min(availableOutboundQuantity, detailRemainingQuantity),
                stockDetail.StockQuantity);
        }
        /// <summary>
        /// æ‰§è¡Œæ‹†åŒ…操作
@@ -1043,7 +1103,7 @@
                WarehouseCode = stockDetail.WarehouseCode,
                Remark = $"拆包前原始记录,原条码:{request.Barcode},原数量:{stockDetail.StockQuantity},出库数量:{actualOutboundQuantity},操作者:{request.Operator}"
            };
            _stockDetailHistoryService.Repository.AddData(originalHistoryRecord);
            _stockDetailHistoryRepository.AddData(originalHistoryRecord);
            // ä¿å­˜å‰©ä½™éƒ¨åˆ†åˆ°åŽ†å²è®°å½•
            decimal remainingQuantity = stockDetail.StockQuantity - actualOutboundQuantity;
@@ -1053,7 +1113,7 @@
                stockDetail.StockQuantity = remainingQuantity;
                //stockDetail.Barcode = newBarcode;
                stockDetail.Remark = $"拆包后更新,原条码:{request.Barcode},新数量:{remainingQuantity},操作者:{request.Operator}";
                _stockDetailService.Repository.UpdateData(stockDetail);
                _stockDetailRepository.UpdateData(stockDetail);
            }
            // è®°å½•拆包变动
@@ -1076,7 +1136,7 @@
                WarehouseCode = stockDetail.WarehouseCode,
                Remark = $"拆包出库,原条码:{request.Barcode},新条码:{newBarcode},出库数量:{actualOutboundQuantity},剩余:{remainingQuantity},操作者:{request.Operator}"
            };
            _stockChangeService.Repository.AddData(unpackChangeRecord);
            _stockChangeRepository.AddData(unpackChangeRecord);
            return newBarcode;
        }
@@ -1111,10 +1171,10 @@
                WarehouseCode = stockDetail.WarehouseCode,
                Remark = $"出库完成删除,条码:{request.Barcode},原数量:{stockDetail.StockQuantity},出库数量:{actualOutboundQuantity},操作者:{request.Operator}"
            };
            _stockDetailHistoryService.Repository.AddData(historyRecord);
            _stockDetailHistoryRepository.AddData(historyRecord);
            // åˆ é™¤åº“存明细记录
            _stockDetailService.Repository.DeleteData(stockDetail);
            _stockDetailRepository.DeleteData(stockDetail);
            // è®°å½•库存变动
            Dt_StockQuantityChangeRecord changeRecord = new Dt_StockQuantityChangeRecord
@@ -1136,7 +1196,7 @@
                WarehouseCode = stockDetail.WarehouseCode,
                Remark = $"出库完成删除库存明细,条码:{request.Barcode},出库数量:{actualOutboundQuantity},操作者:{request.Operator}"
            };
            _stockChangeService.Repository.AddData(changeRecord);
            _stockChangeRepository.AddData(changeRecord);
        }
        /// <summary>
@@ -1148,7 +1208,7 @@
            // ä½¿ç”¨æ—¶é—´æˆ³å’Œéšæœºæ•°ç”Ÿæˆå”¯ä¸€æ¡ç 
            string newBarcode = string.Empty;
            //todo é‡æ–°ç”Ÿæˆæ¡ç é€»è¾‘
            newBarcode = _basicService.CreateCodeByRule(RuleCodeEnum.NewBarcodeRule.ToString());
            return newBarcode;
        }
@@ -1164,7 +1224,7 @@
        private void UpdateLockInfoAllocatedQuantity(int stockId, string materielCode, string batchNo, decimal actualOutboundQuantity)
        {
            // æŸ¥è¯¢è¯¥æ‰˜ç›˜è¯¥ç‰©æ–™çš„æ‰€æœ‰é”å®šè®°å½•
            List<Dt_OutStockLockInfo> lockRecords = _outboundLockInfoService.Repository.QueryData(x =>
            List<Dt_OutStockLockInfo> lockRecords = _outboundLockInfoRepository.QueryData(x =>
                x.StockId == stockId &&
                x.MaterielCode == materielCode &&
                x.BatchNo == batchNo);
@@ -1178,7 +1238,7 @@
                }
                // æ‰¹é‡æ›´æ–°
                _outboundLockInfoService.Repository.UpdateData(lockRecords);
                _outboundLockInfoRepository.UpdateData(lockRecords);
            }
        }
@@ -1187,13 +1247,13 @@
        /// </summary>
        public bool CheckOutboundOrderCompleted(string orderNo)
        {
            Dt_OutboundOrder outboundOrder = _outboundOrderService.Repository.QueryFirst(x => x.OrderNo == orderNo);
            Dt_OutboundOrder outboundOrder = _outboundRepository.QueryFirst(x => x.OrderNo == orderNo);
            if (outboundOrder == null) return false;
            List<Dt_OutboundOrderDetail> details = _detailService.Repository.QueryData(x => x.OrderId == outboundOrder.Id);
            List<Dt_OutboundOrderDetail> details = _detailRepository.QueryData(x => x.OrderId == outboundOrder.Id);
            // æ£€æŸ¥æ‰€æœ‰æ˜Žç»†çš„已出数量是否都等于单据数量
            return details.All(x => x.OverOutQuantity >= x.OrderQuantity);
            return details.All(x => x.OverOutQuantity >= x.OrderQuantity - x.MoveQty);
        }
    }
}