heshaofeng
7 天以前 461524a7a1def4532b9af4ab40733f899f360db7
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs
@@ -27,6 +27,7 @@
using SqlSugar;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using WIDESEA_BasicService;
@@ -98,6 +99,7 @@
        private readonly IRepository<Dt_TakeStockOrder> _takeStockOrder;
        public readonly IRepository<Dt_LocationType> _locationTypeRepository;
        public readonly IRepository<Dt_WarehouseArea> _warehouseAreaRepository;
        private readonly IRepository<Dt_OutStockLockInfo> _outboundLockInfoRepository;
        public IRepository<Dt_Task> Repository => BaseDal;
        private Dictionary<string, SqlSugar.OrderByType> _taskOrderBy = new()
@@ -117,7 +119,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, IRepository<Dt_LocationType> locationTypeRepository, IRepository<Dt_WarehouseArea> warehouseAreaRepository) : 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, IRepository<Dt_OutStockLockInfo> outboundLockInfoRepository) : base(BaseDal)
        {
            _mapper = mapper;
            _unitOfWorkManage = unitOfWorkManage;
@@ -148,6 +150,7 @@
            _takeStockOrder = takeStockOrder;
            _locationTypeRepository = locationTypeRepository;
            _warehouseAreaRepository = warehouseAreaRepository;
            _outboundLockInfoRepository = outboundLockInfoRepository;
        }
        public async Task TaskStatusChange(string taskNum, TaskStatusEnum taskStatusEnum)
@@ -308,7 +311,7 @@
            stockInfo.StockStatus = StockStatusEmun.入库完成.ObjToInt();
            stockInfo.Details.ForEach(x =>
            {
                x.Status = StockStatusEmun.入库确认.ObjToInt();
                x.Status = inboundOrders.FirstOrDefault().CreateType == (int)OrderCreateTypeEnum.CreateInSystem ? StockStatusEmun.入库完成.ObjToInt():StockStatusEmun.入库确认.ObjToInt();
            });
            _stockService.StockInfoService.Repository.UpdateData(stockInfo);
            _stockService.StockInfoDetailService.Repository.UpdateData(stockInfo.Details);
@@ -388,7 +391,7 @@
                            allocatefeedmodel.Details = groupedData;
                            var response = responseModel(inboundOrder, 3, null, allocatefeedmodel);
                            if (response != null && response.IsSuccess)
                            if (response != null && response.IsSuccess && response.Data.Code =="200")
                            {
                                var detailStatusList = _inboundOrderDetailService.Db.Queryable<Dt_InboundOrderDetail>()
                                .Where(it => it.OrderId == inboundOrder.Id)
@@ -453,7 +456,7 @@
                    }
                    else
                    {
                        if (inboundOrder != null && inboundOrder.OrderStatus == InOrderStatusEnum.入库完成.ObjToInt())
                        if (inboundOrder != null && inboundOrder.OrderStatus == InOrderStatusEnum.入库完成.ObjToInt() && inboundOrder.CreateType == (int)OrderCreateTypeEnum.UpperSystemPush)
                        {
                            var feedmodel = new FeedbackInboundRequestModel
                            {
@@ -493,7 +496,7 @@
                            var response= responseModel(inboundOrder,2, feedmodel);
                            if (response != null && response.IsSuccess)
                            if (response != null && response.IsSuccess && response.Data.Code == "200")
                            {
                                var detailStatusList = _inboundOrderDetailService.Db.Queryable<Dt_InboundOrderDetail>()
                                .Where(it => it.OrderId == inboundOrder.Id)
@@ -2231,7 +2234,7 @@
        /// <summary>
        /// ç›˜ç‚¹å‡ºåº“完成
        /// </summary>
        public WebResponseContent OutInventoryTaskCompleted(Dt_Task task)
        public async Task<WebResponseContent> OutInventoryTaskCompleted(Dt_Task task)
        {
            WebResponseContent content = new WebResponseContent();
            try
@@ -2282,7 +2285,7 @@
            catch (Exception ex)
            {
                _unitOfWorkManage.RollbackTran();
                content.Error(ex.Message);
                return await Task.FromResult(WebResponseContent.Instance.Error(ex.Message));
            }
            return content;
        }
@@ -2451,6 +2454,395 @@
                return await Task.FromResult(WebResponseContent.Instance.Error(ex.Message));
            }
        }
        /// <summary>
        /// ä»»åŠ¡å–æ¶ˆ
        /// </summary>
        /// <param name="taskCodes"></param>
        /// <returns></returns>
        /// <summary>
        public async Task<WebResponseContent> TaskCancel(List<int> taskCodes)
        {
            try
            {
                if (taskCodes == null || !taskCodes.Any())
                {
                    return WebResponseContent.Instance.Error("取消的任务号不能为空");
                }
                //var taskCancelUrl = AppSettings.GetValue("TaskCancelUrl");
                //TaskCancelRequest taskc = new TaskCancelRequest();
                //taskc.TaskCodes = taskCodes.Select(x => x.ToString()).ToList();
                //string json = JsonConvert.SerializeObject(taskc);
                //using var clientHttp = new HttpClient();
                //var content = new StringContent(json, Encoding.UTF8, "application/json");
                //HttpResponseMessage response = await clientHttp.PostAsync(taskCancelUrl,content);
                //string responseJson = await response.Content.ReadAsStringAsync();
                //TaskCancelApiResponse apiResponse = JsonConvert.DeserializeObject<TaskCancelApiResponse>(responseJson);
                //if (apiResponse.Code != 0)
                //{
                //    return WebResponseContent.Instance.Error($"请求失败:{apiResponse.Msg}");
                //}
                _unitOfWorkManage.BeginTran();
                var tasks = await Db.Queryable<Dt_Task>()
                                    .Where(x => taskCodes.Contains(x.TaskNum))
                                    .ToListAsync();
                if (!tasks.Any())
                {
                    _unitOfWorkManage.RollbackTran();
                    return WebResponseContent.Instance.Error("未找到对应的任务信息");
                }
                int inPickType = TaskTypeEnum.InPick.ObjToInt();
                var inboundTypes = new List<int>
        {
            TaskTypeEnum.InAllocate.ObjToInt(),
            TaskTypeEnum.InEmpty.ObjToInt(),
            TaskTypeEnum.Inbound.ObjToInt(),
            TaskTypeEnum.InInventory.ObjToInt(),
            TaskTypeEnum.InQuality.ObjToInt()
        };
                var outboundTypes = new List<int>
        {
            TaskTypeEnum.Outbound.ObjToInt(),
            TaskTypeEnum.OutAllocate.ObjToInt()
        };
                foreach (var task in tasks)
                {
                    if (task.TaskStatus == TaskStatusEnum.Cancel.ObjToInt())
                        continue;
                    var stock = await _stockRepository.QueryFirstAsync(x => x.PalletCode == task.PalletCode);
                    if (stock == null)
                        throw new Exception($"托盘 {task.PalletCode} æœªæ‰¾åˆ°åº“存信息");
                    if (task.TaskType == inPickType)
                    {
                        stock.StockStatus = StockStatusEmun.出库完成.ObjToInt();
                    }
                    else if (inboundTypes.Contains(task.TaskType))
                    {
                        stock.StockStatus = StockStatusEmun.组盘暂存.ObjToInt();
                    }
                    else if (outboundTypes.Contains(task.TaskType))
                    {
                        stock.StockStatus = StockStatusEmun.入库完成.ObjToInt();
                        var outStockLock = await _outStockLockInfoService.Db
                            .Queryable<Dt_OutStockLockInfo>()
                            .Where(x => x.PalletCode == task.PalletCode)
                            .FirstAsync();
                        if (outStockLock == null)
                            throw new Exception($"托盘 {task.PalletCode} æœªæ‰¾åˆ°å‡ºåº“锁定信息");
                        int detailId = outStockLock.OrderDetailIds.ObjToInt();
                        var outboundDetail = await _outboundOrderDetailService.Db
                            .Queryable<Dt_OutboundOrderDetail>()
                            .Where(x => x.Id == detailId)
                            .FirstAsync();
                        if (outboundDetail == null)
                            throw new Exception($"出库明细ID {detailId} ä¸å­˜åœ¨");
                        if (outboundDetail.LockQuantity < outStockLock.AssignQuantity)
                            throw new Exception($"出库明细 {detailId} é”å®šæ•°é‡ä¸è¶³");
                        outboundDetail.LockQuantity -= outStockLock.AssignQuantity;
                         _outboundOrderDetailService.UpdateData(outboundDetail);
                         _outboundLockInfoRepository.DeleteAndMoveIntoHty(outStockLock, OperateTypeEnum.人工删除);
                    }
                    await _stockRepository.UpdateDataAsync(stock);
                    task.TaskStatus = TaskStatusEnum.Cancel.ObjToInt();
                    bool archiveSuccess = _task_HtyService.DeleteAndMoveIntoHty(task, OperateTypeEnum.人工删除);
                    if (!archiveSuccess)
                    {
                        await Db.Deleteable(task).ExecuteCommandAsync();
                    }
                }
                _unitOfWorkManage.CommitTran();
                return WebResponseContent.Instance.OK("任务取消成功");
            }
            catch (Exception ex)
            {
                _unitOfWorkManage.RollbackTran();
                _logger.LogError(ex, "任务取消异常");
                return WebResponseContent.Instance.Error($"任务取消失败:{ex.Message}");
            }
        }
        public async Task<WebResponseContent> AreaRelocationTaskCompleted(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 = stockInfo.PalletType == PalletTypeEnum.Empty.ObjToInt()
                        ? LocationStatusEnum.Pallet.ObjToInt()
                        : LocationStatusEnum.InStock.ObjToInt();
                _locationInfoService.Repository.UpdateData(targetLocationInfo);
                // 5.2 é‡Šæ”¾åŽŸè´§ä½
                int beforeOldLocationStatus = 0;
                if (oldLocationInfo != null)
                {
                    beforeOldLocationStatus = oldLocationInfo.LocationStatus;
                    // åŽŸè´§ä½æ¢å¤ä¸ºç©ºé—²
                    oldLocationInfo.LocationStatus = LocationStatusEnum.Free.ObjToInt();
                    _locationInfoService.Repository.UpdateData(oldLocationInfo);
                }
                // 5.4 æ›´æ–°åº“存主信息(绑定新货位)
                string oldLocationCode = stockInfo.LocationCode; // è®°å½•原货位
                stockInfo.LocationCode = targetLocationInfo.LocationCode; // ç»‘定目标货位
                stockInfo.PalletCode = task.PalletCode;
                stockInfo.StockStatus = StockStatusEmun.入库完成.ObjToInt();
                _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();
                }
                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.OK();
            }
            catch (Exception ex)
            {
                // äº‹åŠ¡å›žæ»š
                _unitOfWorkManage.RollbackTran();
                _logger.LogError($"RelocationTaskCompleted å¤„理失败:{ex.Message}", ex);
                return await Task.FromResult(WebResponseContent.Instance.Error($"移库任务处理失败:{ex.Message}"));
            }
        }
        /// <summary>
        /// è·¨åŒºåŸŸç§»åº“任务完成
        /// </summary>
        /// <param name="task"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> CrossAreaRelocationTaskCompleted(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($"CrossAreaRelocationTaskCompleted: æœªæ‰¾åˆ°è¯¥æ‰˜ç›˜åº“存明细信息.{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 = stockInfo.PalletType == PalletTypeEnum.Empty.ObjToInt()
                        ? LocationStatusEnum.Pallet.ObjToInt()
                        : LocationStatusEnum.InStock.ObjToInt();
                _locationInfoService.Repository.UpdateData(targetLocationInfo);
                // 5.2 åŽŸè´§ä½é‡Šæ”¾ç©ºé—²
                int beforeOldLocationStatus = 0;
                if (oldLocationInfo != null)
                {
                    beforeOldLocationStatus = oldLocationInfo.LocationStatus;
                    oldLocationInfo.LocationStatus = LocationStatusEnum.Free.ObjToInt();
                    _locationInfoService.Repository.UpdateData(oldLocationInfo);
                }
                // 5.3 æ›´æ–°åº“存:绑定新货位 + æ¢å¤æ­£å¸¸çŠ¶æ€
                string oldLocationCode = stockInfo.LocationCode;
                stockInfo.LocationCode = targetLocationInfo.LocationCode;
                stockInfo.StockStatus = StockStatusEmun.入库完成.ObjToInt();
                stockInfo.LocationType = targetLocationInfo.LocationType;
                _stockRepository.UpdateData(stockInfo);
                // 5.4 ä»»åŠ¡æ ‡è®°ä¸ºå®Œæˆ
                task.TaskStatus = TaskStatusEnum.Finish.ObjToInt();
                var result = _task_HtyService.DeleteAndMoveIntoHty(task, OperateTypeEnum.自动完成);
                // æäº¤äº‹åŠ¡
                _unitOfWorkManage.CommitTran();
                // ä»»åŠ¡å½’æ¡£å¤±è´¥åˆ™åˆ é™¤
                if (!result)
                {
                    await Db.Deleteable(task).ExecuteCommandAsync();
                }
                // è®°å½•货位状态变更日志
                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($"CrossAreaRelocationTaskCompleted è®°å½•日志异常:{ex.Message}");
                }
                return content.OK("跨区域移库任务完成");
            }
            catch (Exception ex)
            {
                _unitOfWorkManage.RollbackTran();
                _logger.LogError($"CrossAreaRelocationTaskCompleted å¤„理失败:{ex.Message}", ex);
                return await Task.FromResult(WebResponseContent.Instance.Error($"跨区域移库任务处理失败:{ex.Message}"));
            }
        }
    }
}