heshaofeng
2026-03-09 557f7f6079c30cd6fe8d6005cea3d89468bbcd31
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs
@@ -58,6 +58,7 @@
using WIDESEA_IStockService;
using WIDESEA_ITaskInfoService;
using WIDESEA_Model.Models;
using WIDESEA_Model.Models.Basic;
using WIDESEA_Model.Models.Check;
using WIDESEA_Model.Models.Outbound;
using static HslCommunication.Profinet.Knx.KnxCode;
@@ -95,6 +96,8 @@
        private readonly HttpClientHelper _httpClientHelper;
        private readonly IBasicService _basicService;
        private readonly IRepository<Dt_TakeStockOrder> _takeStockOrder;
        public readonly IRepository<Dt_LocationType> _locationTypeRepository;
        public readonly IRepository<Dt_WarehouseArea> _warehouseAreaRepository;
        public IRepository<Dt_Task> Repository => BaseDal;
        private Dictionary<string, SqlSugar.OrderByType> _taskOrderBy = new()
@@ -114,7 +117,7 @@
        public List<int> TaskOutboundTypes => typeof(TaskTypeEnum).GetEnumIndexList();
        public TaskService(IRepository<Dt_Task> BaseDal, IMapper mapper, IUnitOfWorkManage unitOfWorkManage, IRepository<Dt_StockInfo> stockRepository, ILocationInfoService locationInfoService, IInboundOrderService inboundOrderService, ILocationStatusChangeRecordService locationStatusChangeRecordService, IESSApiService eSSApiService, ILogger<TaskService> logger, IStockService stockService, IRecordService recordService, IInboundOrderDetailService inboundOrderDetailService, IOutboundOrderService outboundOrderService, IOutboundOrderDetailService outboundOrderDetailService, IInvokeMESService invokeMESService, IOutStockLockInfoService outStockLockInfoService, IAllocateService allocateService, IRepository<Dt_OutboundBatch> outboundBatchRepository, IRepository<Dt_ReCheckOrder> reCheckOrderRepository, IRepository<Dt_AllocateOrderDetail> allocateOrderDetailRepository, IRepository<Dt_AllocateOrder> allocateOrderRepository, IMaterialUnitService materialUnitService, ITask_HtyService task_HtyService, IRepository<Dt_AllocateMaterialInfo> allocateMaterialInfo, IRepository<Dt_AllocateMaterialInfo_Hty> allocateMaterialInfo_Hty, HttpClientHelper httpClientHelper, IBasicService basicService,IRepository<Dt_TakeStockOrder> takeStockOrder) : base(BaseDal)
        public TaskService(IRepository<Dt_Task> BaseDal, IMapper mapper, IUnitOfWorkManage unitOfWorkManage, IRepository<Dt_StockInfo> stockRepository, ILocationInfoService locationInfoService, IInboundOrderService inboundOrderService, ILocationStatusChangeRecordService locationStatusChangeRecordService, IESSApiService eSSApiService, ILogger<TaskService> logger, IStockService stockService, IRecordService recordService, IInboundOrderDetailService inboundOrderDetailService, IOutboundOrderService outboundOrderService, IOutboundOrderDetailService outboundOrderDetailService, IInvokeMESService invokeMESService, IOutStockLockInfoService outStockLockInfoService, IAllocateService allocateService, IRepository<Dt_OutboundBatch> outboundBatchRepository, IRepository<Dt_ReCheckOrder> reCheckOrderRepository, IRepository<Dt_AllocateOrderDetail> allocateOrderDetailRepository, IRepository<Dt_AllocateOrder> allocateOrderRepository, IMaterialUnitService materialUnitService, ITask_HtyService task_HtyService, IRepository<Dt_AllocateMaterialInfo> allocateMaterialInfo, IRepository<Dt_AllocateMaterialInfo_Hty> allocateMaterialInfo_Hty, HttpClientHelper httpClientHelper, IBasicService basicService,IRepository<Dt_TakeStockOrder> takeStockOrder, IRepository<Dt_LocationType> locationTypeRepository, IRepository<Dt_WarehouseArea> warehouseAreaRepository) : base(BaseDal)
        {
            _mapper = mapper;
            _unitOfWorkManage = unitOfWorkManage;
@@ -143,6 +146,8 @@
            _httpClientHelper = httpClientHelper;
            _basicService = basicService;
            _takeStockOrder = takeStockOrder;
            _locationTypeRepository = locationTypeRepository;
            _warehouseAreaRepository = warehouseAreaRepository;
        }
        public async Task TaskStatusChange(string taskNum, TaskStatusEnum taskStatusEnum)
@@ -482,6 +487,293 @@
            return WebResponseContent.Instance.OK();
        }
        public async Task<WebResponseContent> RelocationTaskCompleted(Dt_Task task)
        {
            WebResponseContent content = new WebResponseContent();
            try
            {
                if (task == null || string.IsNullOrEmpty(task.PalletCode) || string.IsNullOrEmpty(task.TargetAddress))
                {
                    return WebResponseContent.Instance.Error("移库任务信息不完整(托盘号/目标货位为空)");
                }
                // 2. æŸ¥è¯¢æ‰˜ç›˜åº“存信息
                Dt_StockInfo stockInfo = await _stockRepository.Db.Queryable<Dt_StockInfo>()
                    .Includes(x => x.Details)
                    .Where(x => x.PalletCode == task.PalletCode)
                    .FirstAsync();
                if (stockInfo == null)
                {
                    return WebResponseContent.Instance.Error($"未找到托盘[{task.PalletCode}]对应的组盘信息");
                }
                // éžç©ºæ‰˜ç›˜å¿…须有明细
                if (stockInfo.Details.Count == 0 && stockInfo.PalletType != PalletTypeEnum.Empty.ObjToInt())
                {
                    _logger.LogInformation($"TaskService RelocationTaskCompleted: æœªæ‰¾åˆ°è¯¥æ‰˜ç›˜åº“存明细信息.{task.TaskNum}");
                    return WebResponseContent.Instance.Error($"未找到该托盘[{task.PalletCode}]库存明细信息");
                }
                // 3. æŸ¥è¯¢ç›®æ ‡è´§ä½+原货位信息
                Dt_LocationInfo targetLocationInfo = _locationInfoService.Repository.QueryFirst(x => x.LocationCode == task.TargetAddress);
                if (targetLocationInfo == null)
                {
                    return content.Error($"未找到对应的终点货位[{task.TargetAddress}]信息");
                }
                // åŽŸè´§ä½ä¿¡æ¯
                Dt_LocationInfo oldLocationInfo = null;
                if (!string.IsNullOrEmpty(stockInfo.LocationCode))
                {
                    oldLocationInfo = _locationInfoService.Repository.QueryFirst(x => x.LocationCode == stockInfo.LocationCode);
                    if (oldLocationInfo == null)
                    {
                        return content.Error($"未找到原货位[{stockInfo.LocationCode}]信息");
                    }
                }
                // 4. è´§ä½çŠ¶æ€æ ¡éªŒ
                if (targetLocationInfo.LocationStatus == LocationStatusEnum.InStock.ObjToInt())
                {
                    return WebResponseContent.Instance.Error($"目标货位[{task.TargetAddress}]状态不正确(当前为已占用)");
                }
                // 5. å¼€å¯äº‹åŠ¡å¤„ç†æ ¸å¿ƒé€»è¾‘
                _unitOfWorkManage.BeginTran();
                // 5.1 è®°å½•目标货位原状态,更新为占用
                var beforeTargetLocationStatus = targetLocationInfo.LocationStatus;
                targetLocationInfo.LocationStatus = LocationStatusEnum.InStock.ObjToInt();
                _locationInfoService.Repository.UpdateData(targetLocationInfo);
                // 5.2 é‡Šæ”¾åŽŸè´§ä½
                int beforeOldLocationStatus = 0;
                if (oldLocationInfo != null)
                {
                    beforeOldLocationStatus = oldLocationInfo.LocationStatus;
                    // åŽŸè´§ä½æ¢å¤ä¸ºç©ºé—²
                    oldLocationInfo.LocationStatus = stockInfo.PalletType == PalletTypeEnum.Empty.ObjToInt()
                        ? LocationStatusEnum.Pallet.ObjToInt()
                        : LocationStatusEnum.Free.ObjToInt();
                    _locationInfoService.Repository.UpdateData(oldLocationInfo);
                }
                var stockLockInfo = _outStockLockInfoService.Db.Queryable<Dt_OutboundLockInfo_Hty>().Where(x => x.PalletCode == stockInfo.PalletCode && x.TaskNum == task.TaskNum).First();
                var allocateOrderToWarehouse = _allocateOrderRepository.Db.Queryable<Dt_AllocateOrder>().Where(x => x.OrderNo == stockLockInfo.OrderNo).First();
                // 5.3 æ›´æ–°åº“存明细状态(移库完成)
                stockInfo.Details.ForEach(x =>
                {
                    x.Status = StockStatusEmun.入库完成.ObjToInt();
                    x.WarehouseCode = allocateOrderToWarehouse.ToWarehouse;
                });
                _stockService.StockInfoDetailService.Repository.UpdateData(stockInfo.Details);
                // 5.4 æ›´æ–°åº“存主信息(绑定新货位)
                string oldLocationCode = stockInfo.LocationCode; // è®°å½•原货位
                stockInfo.LocationCode = targetLocationInfo.LocationCode; // ç»‘定目标货位
                stockInfo.PalletCode = task.PalletCode;
                stockInfo.StockStatus = StockStatusEmun.入库完成.ObjToInt();
                var name =_warehouseAreaRepository.Db.Queryable<Dt_WarehouseArea>().Where(x => x.Code == allocateOrderToWarehouse.ToWarehouse).First();
                var locationType =_locationTypeRepository.QueryFirst(x => x.LocationTypeDesc.Equals(name.Name));
                if(locationType != null)
                {
                    stockInfo.LocationType = locationType.LocationType;
                }
                _stockRepository.UpdateData(stockInfo);
                // 5.5 æ›´æ–°ä»»åŠ¡çŠ¶æ€ä¸ºå®Œæˆ
                task.TaskStatus = TaskStatusEnum.Finish.ObjToInt();
                var result = _task_HtyService.DeleteAndMoveIntoHty(task, OperateTypeEnum.自动完成);
                // æäº¤äº‹åŠ¡
                _unitOfWorkManage.CommitTran();
                // ä»»åŠ¡å½’æ¡£å¤±è´¥åˆ™ç›´æŽ¥åˆ é™¤
                if (!result)
                {
                    await Db.Deleteable(task).ExecuteCommandAsync();
                }
                // 6. å¤„理出库单+调拨物料信息
                Dt_OutboundOrder outboundOrder = null;
                //var firstDetail = stockInfo.Details.FirstOrDefault();
                if (stockLockInfo != null && !string.IsNullOrEmpty(stockLockInfo.OrderNo))
                {
                    outboundOrder = _outboundOrderService.Db.Queryable<Dt_OutboundOrder>()
                        .Where(x => x.OrderNo == stockLockInfo.OrderNo)
                        .Includes(x => x.Details)
                        .First();
                    if (outboundOrder != null)
                    {
                        var allocatInfo =_allocateMaterialInfo.Db.Queryable<Dt_AllocateMaterialInfo>().Where(x => x.OrderNo == outboundOrder.OrderNo).ToList();
                        // åˆ é™¤è°ƒæ‹¨ç‰©æ–™ä¿¡æ¯
                        foreach (var item in allocatInfo)
                        {
                            var inbounddetail = _allocateMaterialInfo.QueryFirst(x => x.OrderNo == item.OrderNo && x.Barcode == item.Barcode);
                            if (inbounddetail != null)
                            {
                                var alldelete = _allocateMaterialInfo.DeleteAndMoveIntoHty(inbounddetail, OperateTypeEnum.自动删除);
                                if (!alldelete)
                                {
                                    await Db.Deleteable(task).ExecuteCommandAsync();
                                }
                            }
                        }
                        // 7. å›žè°ƒMES
                        string Operator = outboundOrder.Modifier;
                        HttpResponseResult<MesResponseDTO> httpResponseResult = new HttpResponseResult<MesResponseDTO>();
                        string reqCode = Guid.NewGuid().ToString();
                        string reqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                        string requestData = string.Empty;
                        List<string> lineNos = new List<string>();
                        Dt_AllocateMaterialInfo allocateMaterialInfo = _allocateMaterialInfo.QueryFirst(x => x.OrderNo == outboundOrder.OrderNo);
                        // ç§»åº“场景:出库完成且未回传MES、无调拨物料信息时回调
                        if (outboundOrder.OrderStatus == OutOrderStatusEnum.出库完成.ObjToInt() && outboundOrder.ReturnToMESStatus == 0 && allocateMaterialInfo == null)
                        {
                            Dt_AllocateOrder allocateOrder = _allocateOrderRepository.QueryFirst(x => x.OrderNo == outboundOrder.OrderNo);
                            if (allocateOrder == null)
                            {
                                return WebResponseContent.Instance.Error($"未找到对应的调拨单[{outboundOrder.OrderNo}]");
                            }
                            // æž„建移库回调数据
                            AllocationReturnDTO? returnDTO = BuildAllocationFeedbackData(
                                outboundOrder,
                                allocateOrder.FromWarehouse,
                                allocateOrder.ToWarehouse,
                                Operator);
                            if (returnDTO == null)
                            {
                                return WebResponseContent.Instance.Error($"构建移库回调对象失败");
                            }
                            string apiUrl = AppSettings.GetValue("AllocationFeedbackUrl");
                            returnDTO.ReqCode = reqCode;
                            returnDTO.ReqTime = reqTime;
                            JsonSerializerSettings settings = new JsonSerializerSettings
                            {
                                ContractResolver = new CamelCasePropertyNamesContractResolver()
                            };
                            requestData = JsonConvert.SerializeObject(returnDTO, settings);
                            lineNos = returnDTO.Details.Select(x => x.LineNo).ToList();
                            httpResponseResult = _httpClientHelper.Post<MesResponseDTO>(apiUrl, requestData);
                            httpResponseResult.ApiUrl = apiUrl;
                        }
                        // 8. å¤„理MES回调结果
                        bool isSuccess = httpResponseResult.IsSuccess && 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}";
                            }
                        }
                        // 9. è®°å½•MES回传记录
                        Dt_MesReturnRecord mesReturnRecord = new Dt_MesReturnRecord()
                        {
                            ApiUrl = httpResponseResult.ApiUrl,
                            InterfaceType = outboundOrder.OrderType == 0 ? 1 : 3, // ç§»åº“接口类型:复用调拨类型3
                            OrderId = outboundOrder.Id,
                            OrderNo = outboundOrder.OrderNo,
                            RequestCode = reqCode,
                            RequestData = requestData,
                            FailureReason = message,
                            LastReturnTime = DateTime.Now,
                            HttpStatusCode = httpResponseResult.StatusCode.ObjToInt(),
                            ResponseData = httpResponseResult.Content,
                            ReturnType = 0,
                            ReturnCount = 1,
                            ReturnStatus = isSuccess ? 1 : 2,
                            SuccessTime = isSuccess ? DateTime.Now : null
                        };
                        // å¼€å¯äº‹åŠ¡ä¿å­˜MES记录+更新出库单状态
                        _unitOfWorkManage.BeginTran();
                        _unitOfWorkManage.Db.Insertable(mesReturnRecord).ExecuteCommand();
                        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 = "";
                        });
                        mesReturnRecord.ReturnType = outboundOrder.Details.Count == outboundOrderDetails.Count ? 1 : 2;
                        if (outboundOrder.Details.Count == outboundOrderDetails.Count && outboundOrderDetails.All(x => x.ReturnToMESStatus == 1 || x.ReturnToMESStatus == 2))
                        {
                            outboundOrder.ReturnToMESStatus = isSuccess ? 1 : 2;
                        }
                        else
                        {
                            outboundOrder.ReturnToMESStatus = isSuccess ? 3 : 4;
                        }
                        _outboundOrderService.Db.Updateable(outboundOrderDetails).ExecuteCommand();
                        _outboundOrderService.UpdateData(outboundOrder);
                        _unitOfWorkManage.CommitTran();
                    }
                }
                // 10. è®°å½•货位状态变更(目标货位+原货位)
                try
                {
                    // è®°å½•目标货位状态变更
                    _locationStatusChangeRecordService.AddLocationStatusChangeRecord(
                        targetLocationInfo,
                        beforeTargetLocationStatus,
                        StockChangeType.Inbound.ObjToInt(),
                        $"移库入库(原货位:{oldLocationCode})",
                        task.TaskNum);
                    // è®°å½•原货位状态变更(若有)
                    if (oldLocationInfo != null)
                    {
                        _locationStatusChangeRecordService.AddLocationStatusChangeRecord(
                            oldLocationInfo,
                            beforeOldLocationStatus,
                            StockChangeType.Outbound.ObjToInt(),
                            $"移库出库(目标货位:{targetLocationInfo.LocationCode})",
                            task.TaskNum);
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogInformation($"RelocationTaskCompleted AddLocationStatusChangeRecord : {ex.Message} ");
                }
                return content;
            }
            catch (Exception ex)
            {
                // äº‹åŠ¡å›žæ»š
                _unitOfWorkManage.RollbackTran();
                _logger.LogError($"RelocationTaskCompleted å¤„理失败:{ex.Message}", ex);
                return await Task.FromResult(WebResponseContent.Instance.Error($"移库任务处理失败:{ex.Message}"));
            }
        }
        public HttpResponseResult<MesResponseDTO> responseModel(Dt_InboundOrder order, int InterfaceType, FeedbackInboundRequestModel model = null, AllocateDto allocateDto = null)
        {
            HttpResponseResult<MesResponseDTO> httpResponseResult = new HttpResponseResult<MesResponseDTO>();
@@ -529,7 +821,7 @@
                ResponseData = httpResponseResult.Content,
                ReturnType = 0,
                ReturnCount = 1,
                ReturnStatus = httpResponseResult.IsSuccess ? 1 : 2,
                ReturnStatus = isSuccess ? 1 : 2,
                SuccessTime = httpResponseResult.IsSuccess ? DateTime.Now : null
            };
            _unitOfWorkManage.Db.Insertable(mesReturnRecord).ExecuteCommand();