#region << 版 本 注 释 >>
|
/*----------------------------------------------------------------
|
* 命名空间:WIDESEA_TaskInfoService
|
* 创建者:胡童庆
|
* 创建时间:2024/8/2 16:13:36
|
* 版本:V1.0.0
|
* 描述:
|
*
|
* ----------------------------------------------------------------
|
* 修改人:
|
* 修改时间:
|
* 版本:V1.0.1
|
* 修改说明:
|
*
|
*----------------------------------------------------------------*/
|
#endregion << 版 本 注 释 >>
|
|
using AutoMapper;
|
using Dm.filter;
|
using MailKit.Search;
|
using Microsoft.Extensions.Logging;
|
using Newtonsoft.Json;
|
using Org.BouncyCastle.Asn1.Ocsp;
|
using Org.BouncyCastle.Asn1.Pkcs;
|
using SqlSugar;
|
using System.Reflection;
|
using System.Reflection.Emit;
|
using System.Threading.Tasks;
|
using System.Xml.Linq;
|
using WIDESEA_Common.CommonEnum;
|
using WIDESEA_Common.LocationEnum;
|
using WIDESEA_Common.OrderEnum;
|
using WIDESEA_Common.StockEnum;
|
using WIDESEA_Common.TaskEnum;
|
using WIDESEA_Common.WareHouseEnum;
|
using WIDESEA_Core;
|
using WIDESEA_Core.BaseRepository;
|
using WIDESEA_Core.BaseServices;
|
using WIDESEA_Core.Enums;
|
using WIDESEA_Core.Helper;
|
using WIDESEA_DTO.Allocate;
|
using WIDESEA_DTO.Basic;
|
using WIDESEA_DTO.Inbound;
|
using WIDESEA_DTO.Outbound;
|
using WIDESEA_DTO.Task;
|
using WIDESEA_IAllocateService;
|
using WIDESEA_IBasicService;
|
using WIDESEA_IInboundService;
|
using WIDESEA_IOutboundService;
|
using WIDESEA_IRecordService;
|
using WIDESEA_IStockService;
|
using WIDESEA_ITaskInfoService;
|
using WIDESEA_Model.Models;
|
|
namespace WIDESEA_TaskInfoService
|
{
|
public partial class TaskService : ServiceBase<Dt_Task, IRepository<Dt_Task>>, ITaskService
|
{
|
private readonly ILogger<TaskService> _logger;
|
private readonly IMapper _mapper;
|
private readonly IUnitOfWorkManage _unitOfWorkManage;
|
|
private readonly IRepository<Dt_StockInfo> _stockRepository;
|
private readonly ILocationInfoService _locationInfoService;
|
private readonly IInboundOrderService _inboundOrderService;
|
private readonly IInboundOrderDetailService _inboundOrderDetailService;
|
|
private readonly IOutboundOrderService _outboundOrderService;
|
private readonly IOutboundOrderDetailService _outboundOrderDetailService;
|
private readonly IOutStockLockInfoService _outStockLockInfoService;
|
private readonly ILocationStatusChangeRecordService _locationStatusChangeRecordService;
|
private readonly IESSApiService _eSSApiService;
|
private readonly IStockService _stockService;
|
private readonly IRecordService _recordService;
|
private readonly IAllocateService _allocateService;
|
private readonly IInvokeMESService _invokeMESService;
|
public IRepository<Dt_Task> Repository => BaseDal;
|
|
private Dictionary<string, SqlSugar.OrderByType> _taskOrderBy = new()
|
{
|
{nameof(Dt_Task.Grade),SqlSugar.OrderByType.Desc },
|
{nameof(Dt_Task.CreateDate),SqlSugar.OrderByType.Asc},
|
};
|
|
private Dictionary<string, string> stations = new Dictionary<string, string>
|
{
|
{"3-5","3-9" },
|
{"2-5","2-9" },
|
{"1-11","1-1" },
|
};
|
|
public List<int> TaskTypes => typeof(TaskTypeEnum).GetEnumIndexList();
|
|
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) : base(BaseDal)
|
{
|
_mapper = mapper;
|
_unitOfWorkManage = unitOfWorkManage;
|
_stockRepository = stockRepository;
|
_locationInfoService = locationInfoService;
|
_inboundOrderService = inboundOrderService;
|
_locationStatusChangeRecordService = locationStatusChangeRecordService;
|
_eSSApiService = eSSApiService;
|
_logger = logger;
|
_stockService = stockService;
|
_recordService = recordService;
|
_inboundOrderDetailService = inboundOrderDetailService;
|
_outboundOrderService = outboundOrderService;
|
_outboundOrderDetailService = outboundOrderDetailService;
|
_invokeMESService = invokeMESService;
|
_outStockLockInfoService = outStockLockInfoService;
|
_allocateService = allocateService;
|
}
|
|
|
/// <summary>
|
///
|
/// </summary>
|
/// <param name="taskNum"></param>
|
/// <returns></returns>
|
public async Task<WebResponseContent> TaskCompleted(string taskNum)
|
{
|
try
|
{
|
Dt_Task task;
|
|
if (int.TryParse(taskNum, out var newTaskNum))
|
{
|
task =await BaseDal.QueryFirstAsync(x => x.TaskNum == newTaskNum);
|
if (task == null)
|
{
|
return WebResponseContent.Instance.Error("未找到任务信息");
|
}
|
}
|
else
|
{
|
return WebResponseContent.Instance.Error("未找到任务信息");
|
}
|
_logger.LogInformation($"TaskService TaskCompleted: {JsonConvert.SerializeObject(task)} , {task.TaskType} ");
|
|
MethodInfo? methodInfo = GetType().GetMethod(((TaskTypeEnum)task.TaskType) + "TaskCompleted");
|
if (methodInfo != null)
|
{
|
object? taskResult = methodInfo.Invoke(this, new object[] { task });
|
if (taskResult is Task<WebResponseContent> asyncTask)
|
{
|
try
|
{
|
// 3. 异步等待 Task 完成,自动解析出 WebResponseContent
|
WebResponseContent responseContent = await asyncTask;
|
if (responseContent != null)
|
{
|
return responseContent;
|
}
|
}
|
catch (AggregateException ex)
|
{
|
_logger.LogError($"TaskService TaskCompleted taskResult: {ex.Message} ");
|
return WebResponseContent.Instance.Error(ex.Message);
|
}
|
catch(Exception ex)
|
{
|
_logger.LogError(ex, $"Unexpected error in {task.TaskType}");
|
return WebResponseContent.Instance.Error(ex.Message);
|
}
|
}
|
}
|
return WebResponseContent.Instance.Error("未找到任务类型对应业务处理逻辑");
|
}
|
catch (Exception ex)
|
{
|
_logger.LogError($"TaskService TaskCompleted: {ex.Message} ");
|
return WebResponseContent.Instance.Error(ex.Message);
|
}
|
}
|
/// <summary>
|
/// 入库完成
|
/// </summary>
|
/// <param name="task"></param>
|
/// <returns></returns>
|
public async Task<WebResponseContent> InboundTaskCompleted(Dt_Task task)
|
{
|
decimal beforeQuantity = 0;
|
|
//查库存
|
Dt_StockInfo stockInfo = _stockRepository.Db.Queryable<Dt_StockInfo>().Includes(x => x.Details).Where(x => x.PalletCode == task.PalletCode && x.WarehouseId == task.WarehouseId).First();
|
if (stockInfo == null)
|
{
|
return WebResponseContent.Instance.Error($"未找到托盘对应的组盘信息");
|
}
|
if (stockInfo.Details.Count == 0 && stockInfo.PalletType != PalletTypeEnum.Empty.ObjToInt())
|
{
|
return WebResponseContent.Instance.Error($"未找到该托盘库存明细信息");
|
}
|
//查货位
|
Dt_LocationInfo locationInfo = _locationInfoService.Repository.QueryFirst(x => x.LocationCode == task.TargetAddress);
|
if (locationInfo == null)
|
{
|
return WebResponseContent.Instance.Error($"未找到对应的终点货位信息");
|
}
|
|
var ordernos = stockInfo.Details.GroupBy(x => x.OrderNo).Select(o => o.Key).ToList();
|
var inboundOrders = _inboundOrderService.Repository.Db.Queryable<Dt_InboundOrder>().Where(x => ordernos.Contains(x.InboundOrderNo)).Includes(x => x.Details).ToList();
|
Dt_InboundOrderDetail? inboundOrderDetail = null;
|
|
foreach (var inboundOrder in inboundOrders)
|
{
|
//标准入库流程查找入库单据
|
if (inboundOrder != null && stockInfo.StockStatus == StockStatusEmun.入库确认.ObjToInt())
|
{
|
foreach (var item in stockInfo.Details.Where(x => x.OrderNo == inboundOrder.InboundOrderNo).ToList())
|
{
|
var inbounddetail = inboundOrder.Details.Where(x => x.lineNo == item.InboundOrderRowNo && x.Barcode == item.Barcode).FirstOrDefault();
|
if (inbounddetail != null)
|
{
|
inbounddetail.OverInQuantity += item.StockQuantity;
|
if (inbounddetail.OverInQuantity == inbounddetail.OrderQuantity)
|
{
|
inbounddetail.OrderDetailStatus = OrderDetailStatusEnum.Over.ObjToInt();
|
}
|
else if (inbounddetail.OrderDetailStatus == OrderDetailStatusEnum.New.ObjToInt())
|
{
|
inbounddetail.OrderDetailStatus = OrderDetailStatusEnum.Inbounding.ObjToInt();
|
}
|
_inboundOrderDetailService.UpdateData(inbounddetail);
|
}
|
}
|
if (inboundOrder.Details.Count == inboundOrder.Details.Where(x => x.OrderQuantity == x.OverInQuantity).Count())
|
{
|
inboundOrder.OrderStatus = InOrderStatusEnum.入库完成.ObjToInt();
|
}
|
else if (inboundOrder.OrderStatus == InOrderStatusEnum.未开始.ObjToInt())
|
{
|
inboundOrder.OrderStatus = InOrderStatusEnum.入库中.ObjToInt();
|
}
|
_inboundOrderService.UpdateData(inboundOrder);
|
}
|
}
|
stockInfo.LocationCode = task.TargetAddress;
|
stockInfo.StockStatus = StockStatusEmun.入库完成.ObjToInt();
|
stockInfo.Details.ForEach(x =>
|
{
|
x.Status = StockStatusEmun.入库完成.ObjToInt();
|
});
|
_stockService.StockInfoService.Repository.UpdateData(stockInfo);
|
_stockService.StockInfoDetailService.Repository.UpdateData(stockInfo.Details);
|
|
beforeQuantity = stockInfo.Details.Where(x => x.Id != 0).Sum(x => x.StockQuantity);
|
|
int beforeStatus = locationInfo.LocationStatus;
|
if (stockInfo.PalletType == PalletTypeEnum.Empty.ObjToInt())
|
{
|
locationInfo.LocationStatus = LocationStatusEnum.Pallet.ObjToInt();
|
}
|
else
|
{
|
locationInfo.LocationStatus = LocationStatusEnum.InStock.ObjToInt();
|
}
|
_locationInfoService.Repository.UpdateData(locationInfo);
|
|
task.TaskStatus = TaskStatusEnum.Finish.ObjToInt();
|
|
BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成);
|
|
_locationStatusChangeRecordService.AddLocationStatusChangeRecord(locationInfo, beforeStatus, StockChangeType.Inbound.ObjToInt(), "", task.TaskNum);
|
|
_recordService.StockQuantityChangeRecordService.AddStockChangeRecord(stockInfo, stockInfo.Details, beforeQuantity, stockInfo.Details.Sum(x => x.StockQuantity) + beforeQuantity, WIDESEA_Common.StockEnum.StockChangeType.MaterielGroup);
|
try
|
{
|
foreach (var inboundOrder in inboundOrders)
|
{
|
if (inboundOrder.OrderType == InOrderTypeEnum.Allocat.ObjToInt())//调拨入库
|
{
|
if (inboundOrder != null && inboundOrder.OrderStatus == InOrderStatusEnum.入库完成.ObjToInt())
|
{
|
var allocate = _allocateService.Repository.QueryData(x => x.OrderNo == inboundOrder.InboundOrderNo).First();
|
var feedmodel = new AllocateDto
|
{
|
ReqCode = Guid.NewGuid().ToString(),
|
ReqTime = DateTime.Now.ToString(),
|
BusinessType = "2",
|
FactoryArea = inboundOrder.FactoryArea,
|
OperationType = 1,
|
Operator = inboundOrder.Operator,
|
OrderNo = inboundOrder.UpperOrderNo,
|
fromWarehouse = allocate?.FromWarehouse ?? "",
|
toWarehouse = allocate?.ToWarehouse ?? "",
|
Details = new List<AllocateDtoDetail>()
|
|
};
|
|
var groupedData = inboundOrder.Details.GroupBy(item => new { item.MaterielCode, item.SupplyCode, item.BatchNo, item.lineNo, item.BarcodeUnit, item.WarehouseCode })
|
.Select(group => new AllocateDtoDetail
|
{
|
MaterialCode = group.Key.MaterielCode,
|
LineNo = group.Key.lineNo,
|
WarehouseCode = group.Key.WarehouseCode,
|
Qty = group.Sum(x => x.BarcodeQty),
|
// warehouseCode= "1072",
|
Unit = group.Key.BarcodeUnit,
|
Barcodes = group.Select(row => new BarcodeInfo
|
{
|
Barcode = row.Barcode,
|
Qty = row.BarcodeQty,
|
BatchNo = row.BatchNo,
|
SupplyCode = row.SupplyCode,
|
Unit = row.Unit
|
}).ToList()
|
}).ToList();
|
feedmodel.Details = groupedData;
|
|
var result = await _invokeMESService.FeedbackAllocate(feedmodel);
|
if (result != null && result.code == 200)
|
{
|
_inboundOrderService.Db.Updateable<Dt_InboundOrder>().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus = 1 })
|
.Where(it => it.Id == inboundOrder.Id).ExecuteCommand();
|
_inboundOrderDetailService.Db.Updateable<Dt_InboundOrderDetail>().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 1 })
|
.Where(it => it.OrderId == inboundOrder.Id).ExecuteCommand();
|
}
|
}
|
}
|
else if (inboundOrder.OrderType == InOrderTypeEnum.ReCheck.ObjToInt()) //重检入库
|
{
|
|
}
|
else
|
{
|
if (inboundOrder != null && inboundOrder.OrderStatus == InOrderStatusEnum.入库完成.ObjToInt())
|
{
|
var feedmodel = new FeedbackInboundRequestModel
|
{
|
reqCode = Guid.NewGuid().ToString(),
|
reqTime = DateTime.Now.ToString(),
|
business_type = inboundOrder.BusinessType,
|
factoryArea = inboundOrder.FactoryArea,
|
operationType = 1,
|
Operator = inboundOrder.Operator,
|
orderNo = inboundOrder.UpperOrderNo,
|
status = inboundOrder.OrderStatus,
|
details = new List<FeedbackInboundDetailsModel>()
|
|
};
|
|
var groupedData = inboundOrder.Details.GroupBy(item => new { item.MaterielCode, item.SupplyCode, item.BatchNo, item.lineNo, item.BarcodeUnit, item.WarehouseCode })
|
.Select(group => new FeedbackInboundDetailsModel
|
{
|
materialCode = group.Key.MaterielCode,
|
supplyCode = group.Key.SupplyCode,
|
batchNo = group.Key.BatchNo,
|
lineNo = group.Key.lineNo,
|
warehouseCode = group.Key.WarehouseCode,
|
qty = group.Sum(x => x.BarcodeQty),
|
// warehouseCode= "1072",
|
unit = group.Key.BarcodeUnit,
|
barcodes = group.Select(row => new FeedbackBarcodesModel
|
{
|
barcode = row.Barcode,
|
qty = row.BarcodeQty
|
}).ToList()
|
}).ToList();
|
feedmodel.details = groupedData;
|
|
var result = await _invokeMESService.FeedbackInbound(feedmodel);
|
if (result != null && result.code == 200)
|
{
|
_inboundOrderService.Db.Updateable<Dt_InboundOrder>().SetColumns(it => new Dt_InboundOrder { ReturnToMESStatus = 1 })
|
.Where(it => it.Id == inboundOrder.Id).ExecuteCommand();
|
_inboundOrderDetailService.Db.Updateable<Dt_InboundOrderDetail>().SetColumns(it => new Dt_InboundOrderDetail { ReturnToMESStatus = 1 })
|
.Where(it => it.OrderId == inboundOrder.Id).ExecuteCommand();
|
}
|
}
|
}
|
|
}
|
}
|
catch (Exception ex)
|
{
|
_logger.LogInformation("InboundTaskCompleted 回写MES失败: " + ex.Message);
|
}
|
|
return WebResponseContent.Instance.OK();
|
}
|
|
public async Task<WebResponseContent> OutboundTaskCompleted(Dt_Task task)
|
{
|
_logger.LogInformation($"TaskService OutboundTaskCompleted: {task.TaskNum}");
|
//查货位
|
Dt_LocationInfo locationInfo = _locationInfoService.Repository.QueryFirst(x => x.LocationCode == task.SourceAddress);
|
if (locationInfo == null)
|
{
|
return WebResponseContent.Instance.Error($"未找到对应的终点货位信息");
|
}
|
locationInfo.LocationStatus = LocationStatusEnum.Free.ObjToInt();
|
_locationInfoService.Repository.UpdateData(locationInfo);
|
|
var outloks =await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>().Where(x => x.TaskNum == task.TaskNum).ToListAsync();
|
|
var stockids = outloks.Select(x => x.StockId).ToList();
|
|
_stockService.StockInfoService.Db.Updateable<Dt_StockInfo>()
|
.SetColumns(it => new Dt_StockInfo
|
{
|
StockStatus = StockStatusEmun.出库锁定.ObjToInt()
|
})
|
.Where(it => stockids.Contains(it.Id))
|
.ExecuteCommand();
|
|
_stockService.StockInfoDetailService.Db.Updateable<Dt_StockInfoDetail>()
|
.SetColumns(it => new Dt_StockInfoDetail
|
{
|
Status = StockStatusEmun.出库锁定.ObjToInt()
|
})
|
.Where(it => stockids.Contains(it.StockId))
|
.ExecuteCommand();
|
|
|
|
return WebResponseContent.Instance.OK();
|
|
|
}
|
public async Task<WebResponseContent> InEmptyTaskCompleted(Dt_Task task)
|
{
|
|
WebResponseContent content = new WebResponseContent();
|
try
|
{
|
|
Dt_LocationInfo locationInfo = _locationInfoService.Repository.QueryFirst(x => x.LocationCode == task.TargetAddress);
|
if (locationInfo == null)
|
{
|
return content.Error($"未找到对应的终点货位信息");
|
}
|
Dt_StockInfo stockInfo = _stockRepository.Db.Queryable<Dt_StockInfo>().Where(x => x.PalletCode == task.PalletCode && x.WarehouseId == task.WarehouseId).First();
|
if (stockInfo == null)
|
{
|
return WebResponseContent.Instance.Error($"未找到托盘对应的组盘信息");
|
}
|
|
if (!string.IsNullOrEmpty(stockInfo.LocationCode))
|
{
|
return WebResponseContent.Instance.Error($"该托盘已绑定货位");
|
}
|
if (locationInfo.LocationStatus == LocationStatusEnum.InStock.ObjToInt())
|
{
|
return WebResponseContent.Instance.Error($"货位状态不正确");
|
}
|
|
|
var beforelocationStatus = locationInfo.LocationStatus;
|
locationInfo.LocationStatus = LocationStatusEnum.Pallet.ObjToInt();
|
_locationInfoService.Repository.UpdateData(locationInfo);
|
|
stockInfo.LocationCode = locationInfo.LocationCode;
|
stockInfo.PalletCode = task.PalletCode;
|
stockInfo.LocationCode = task.TargetAddress;
|
stockInfo.StockStatus = StockStatusEmun.入库完成.ObjToInt();
|
_stockRepository.UpdateData(stockInfo);
|
|
var outboundOrder = _outboundOrderService.Db.Queryable<Dt_OutboundOrder>().First(x => x.OrderNo == task.OrderNo);
|
|
task.TaskStatus = TaskStatusEnum.Finish.ObjToInt();
|
BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? WIDESEA_Core.Enums.OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成);
|
|
_locationStatusChangeRecordService.AddLocationStatusChangeRecord(locationInfo, beforelocationStatus, StockChangeType.Inbound.ObjToInt(), "", task.TaskNum);
|
|
|
if (outboundOrder != null)
|
{
|
await HandleOutboundOrderToMESCompletion(outboundOrder, outboundOrder.OrderNo);
|
}
|
else
|
{
|
_logger.LogInformation($"TaskService InEmptyTaskCompleted: {task.TaskNum} ,未找到出库单。 ");
|
}
|
|
return content;
|
}
|
catch (Exception ex)
|
{
|
return await Task.FromResult(WebResponseContent.Instance.Error(ex.Message));
|
}
|
}
|
|
public async Task<WebResponseContent> InPickTaskCompleted(Dt_Task task)
|
{
|
_logger.LogInformation($"TaskService InPickTaskCompleted: {task.TaskNum}");
|
try
|
{
|
//查库存
|
Dt_StockInfo stockInfo =await _stockRepository.Db.Queryable<Dt_StockInfo>().Includes(x => x.Details).Where(x => x.PalletCode == task.PalletCode).FirstAsync();
|
if (stockInfo == null)
|
{
|
_logger.LogInformation($"TaskService InPickTaskCompleted: 未找到托盘对应的组盘信息.{task.TaskNum}");
|
return WebResponseContent.Instance.Error($"未找到托盘对应的组盘信息");
|
}
|
if (stockInfo.Details.Count == 0 && stockInfo.PalletType != PalletTypeEnum.Empty.ObjToInt())
|
{
|
_logger.LogInformation($"TaskService InPickTaskCompleted: 未找到该托盘库存明细信息.{task.TaskNum}");
|
return WebResponseContent.Instance.Error($"未找到该托盘库存明细信息");
|
}
|
//查货位
|
Dt_LocationInfo locationInfo = _locationInfoService.Repository.QueryFirst(x => x.LocationCode == task.TargetAddress);
|
if (locationInfo == null)
|
{
|
_logger.LogInformation($"TaskService InPickTaskCompleted: 未找到对应的终点货位信息 {task.TaskNum}.");
|
return WebResponseContent.Instance.Error($"未找到对应的终点货位信息");
|
}
|
|
var beforelocationStatus = locationInfo.LocationStatus;
|
// 获取所有回库中的出库锁定记录
|
var returnLocks =await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
|
.Where(it => it.OrderNo == task.OrderNo && it.PalletCode == task.PalletCode && it.Status == (int)OutLockStockStatusEnum.回库中)
|
.ToListAsync();
|
// 更新出库锁定记录状态为回库完成
|
foreach (var lockInfo in returnLocks)
|
{
|
lockInfo.Status = (int)OutLockStockStatusEnum.已回库;
|
}
|
_outStockLockInfoService.Db.Updateable(returnLocks).ExecuteCommand();
|
|
stockInfo.LocationCode = task.TargetAddress;
|
stockInfo.StockStatus = StockStatusEmun.入库完成.ObjToInt();
|
if (stockInfo.Details != null && stockInfo.Details.Any())
|
{
|
stockInfo.Details.ForEach(x =>
|
{
|
x.Status = StockStatusEmun.入库完成.ObjToInt();
|
});
|
_stockService.StockInfoDetailService.Repository.UpdateData(stockInfo.Details);
|
}
|
|
_stockService.StockInfoService.Repository.UpdateData(stockInfo);
|
|
await ProcessStockDetailsForReturn(task, stockInfo.Id);
|
|
await DeleteZeroQuantityStockDetails(stockInfo.Id);
|
|
if (stockInfo.PalletType == PalletTypeEnum.Empty.ObjToInt())
|
{
|
locationInfo.LocationStatus = LocationStatusEnum.Pallet.ObjToInt();
|
}
|
else
|
{
|
locationInfo.LocationStatus = LocationStatusEnum.InStock.ObjToInt();
|
}
|
_locationInfoService.Repository.UpdateData(locationInfo);
|
var outboundOrder = _outboundOrderService.Db.Queryable<Dt_OutboundOrder>().First(x => x.OrderNo == task.OrderNo);
|
task.TaskStatus = TaskStatusEnum.Finish.ObjToInt();
|
|
BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成);
|
BaseDal.DeleteData(task);
|
_locationStatusChangeRecordService.AddLocationStatusChangeRecord(locationInfo, beforelocationStatus, StockChangeType.Inbound.ObjToInt(), "", task.TaskNum);
|
|
if (outboundOrder != null)
|
{
|
await HandleOutboundOrderToMESCompletion(outboundOrder, outboundOrder.OrderNo);
|
}
|
else
|
{
|
_logger.LogInformation($"TaskService InPickTaskCompleted: {task.TaskNum} ,未找到出库单。 ");
|
}
|
}
|
catch (Exception ex)
|
{
|
_logger.LogInformation($"TaskService InPickTaskCompleted: {task.TaskNum} , {ex.Message}");
|
}
|
return await Task.FromResult(WebResponseContent.Instance.OK());
|
}
|
|
|
private async Task HandleOutboundOrderToMESCompletion(Dt_OutboundOrder outboundOrder, string orderNo)
|
{
|
// 获取订单明细数据
|
var orderDetails = await _outboundOrderDetailService.Db.Queryable<Dt_OutboundOrderDetail>()
|
.LeftJoin<Dt_OutboundOrder>((d, o) => d.OrderId == o.Id)
|
.Where((d, o) => o.OrderNo == orderNo)
|
.Select((d, o) => d)
|
.ToListAsync();
|
|
var feedmodel = new FeedbackOutboundRequestModel
|
{
|
reqCode = Guid.NewGuid().ToString(),
|
reqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
|
business_type = outboundOrder.BusinessType,
|
factoryArea = outboundOrder.FactoryArea,
|
operationType = 1,
|
Operator = App.User.UserName,
|
orderNo = outboundOrder.UpperOrderNo,
|
documentsNO = outboundOrder.OrderNo,
|
status = outboundOrder.OrderStatus,
|
details = new List<FeedbackOutboundDetailsModel>()
|
};
|
|
// 使用订单明细的OverOutQuantity作为回传数量
|
foreach (var detail in orderDetails)
|
{
|
// 获取该明细对应的条码信息(从锁定记录)
|
var detailLocks = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
|
.Where(x => x.OrderNo == orderNo &&
|
x.OrderDetailId == detail.Id &&
|
x.Status == (int)OutLockStockStatusEnum.拣选完成)
|
.ToListAsync();
|
|
var detailModel = new FeedbackOutboundDetailsModel
|
{
|
materialCode = detail.MaterielCode,
|
lineNo = detail.lineNo, // 注意:这里可能需要调整字段名
|
warehouseCode = detail.WarehouseCode,
|
qty = detail.OverOutQuantity, // 使用订单明细的已出库数量
|
currentDeliveryQty = detail.OverOutQuantity,
|
unit = detail.Unit,
|
barcodes = detailLocks.Select(lockInfo => new WIDESEA_DTO.Outbound.BarcodesModel
|
{
|
barcode = lockInfo.CurrentBarcode,
|
supplyCode = lockInfo.SupplyCode,
|
batchNo = lockInfo.BatchNo,
|
unit = lockInfo.Unit,
|
qty = lockInfo.PickedQty // 条码级别的数量仍用锁定记录
|
}).ToList()
|
};
|
|
feedmodel.details.Add(detailModel);
|
}
|
|
var result = await _invokeMESService.FeedbackOutbound(feedmodel);
|
if (result != null && result.code == 200)
|
{
|
await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
|
.SetColumns(x => x.ReturnToMESStatus == 1)
|
.Where(x => x.OrderId == outboundOrder.Id)
|
.ExecuteCommandAsync();
|
|
await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
|
.SetColumns(x => x.ReturnToMESStatus == 1)
|
.Where(x => x.OrderNo == orderNo)
|
.ExecuteCommandAsync();
|
}
|
|
}
|
|
/// <summary>
|
/// 删除库存数为0的库存明细记录
|
/// </summary>
|
private async Task DeleteZeroQuantityStockDetails(int stockId)
|
{
|
try
|
{
|
// 删除库存数量为0的记录
|
var deleteCount = await _stockService.StockInfoDetailService.Db.Deleteable<Dt_StockInfoDetail>()
|
.Where(x => x.StockId == stockId &&
|
x.StockQuantity == 0 &&
|
(x.Status == StockStatusEmun.出库完成.ObjToInt() || x.Status ==
|
StockStatusEmun.入库完成.ObjToInt())) // 只删除已完成状态的零库存
|
.ExecuteCommandAsync();
|
|
if (deleteCount > 0)
|
{
|
_logger.LogInformation($"删除{deleteCount}条零库存明细记录 - StockId: {stockId}");
|
}
|
}
|
catch (Exception ex)
|
{
|
_logger.LogWarning($"删除零库存记录失败 - StockId: {stockId}, Error: {ex.Message}");
|
// 注意:删除失败不应该影响主流程,记录日志后继续
|
}
|
}
|
/// <summary>
|
/// 处理回库相关的所有库存明细状态变更
|
/// </summary>
|
private async Task ProcessStockDetailsForReturn(Dt_Task returnTask, int stockId)
|
{
|
// 获取该托盘下所有需要回库的库存明细
|
var stockDetails = await _stockService.StockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
|
.Where(x => x.StockId == stockId &&
|
x.StockQuantity > 0 &&
|
(x.Status == StockStatusEmun.出库锁定.ObjToInt() || x.Status ==
|
StockStatusEmun.入库确认.ObjToInt())) // 包括出库锁定和入库确认的
|
.ToListAsync();
|
|
foreach (var detail in stockDetails)
|
{
|
|
detail.Status = StockStatusEmun.入库完成.ObjToInt();
|
detail.OutboundQuantity = 0; // 清空出库数量
|
|
_logger.LogInformation($"更新库存明细状态 - 条码: {detail.Barcode}, 数量: {detail.StockQuantity}");
|
}
|
|
if (stockDetails.Any())
|
{
|
await _stockService.StockInfoDetailService.Db.Updateable(stockDetails).ExecuteCommandAsync();
|
_logger.LogInformation($"共更新{stockDetails.Count}个库存明细状态为入库完成");
|
}
|
}
|
public async Task<WebResponseContent> OutEmptyTaskCompleted(Dt_Task task)
|
{
|
WebResponseContent content = new WebResponseContent();
|
try
|
{
|
Dt_StockInfo stockInfo = _stockRepository.Db.Queryable<Dt_StockInfo>().Where(x => x.PalletCode == task.PalletCode).First();
|
if (stockInfo == null)
|
{
|
return WebResponseContent.Instance.Error($"未找到托盘对应的库存信息");
|
}
|
Dt_LocationInfo locationInfo = _locationInfoService.Repository.QueryFirst(x => x.LocationCode == task.SourceAddress);
|
|
if (locationInfo == null)
|
{
|
return content.Error($"未找到对应的终点货位信息");
|
}
|
|
|
int beforeStatus = locationInfo.LocationStatus;
|
|
locationInfo.LocationStatus = LocationStatusEnum.Free.ObjToInt();
|
|
_locationInfoService.Repository.UpdateData(locationInfo);
|
|
|
task.TaskStatus = TaskStatusEnum.Finish.ObjToInt();
|
BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成);
|
_stockService.StockInfoService.Repository.DeleteAndMoveIntoHty(stockInfo, App.User.UserId == 0 ? OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成);
|
_stockRepository.Db.Deleteable(stockInfo).ExecuteCommand();
|
|
_locationStatusChangeRecordService.AddLocationStatusChangeRecord(locationInfo, beforeStatus, StockChangeType.Outbound.ObjToInt(), stockInfo.Details.FirstOrDefault()?.OrderNo ?? "", task.TaskNum);
|
|
return await Task.FromResult(WebResponseContent.Instance.OK());
|
|
}
|
catch (Exception ex)
|
{
|
_logger.LogError($"TaskService OutEmptyTaskCompleted: {ex.Message} ");
|
return await Task.FromResult(WebResponseContent.Instance.Error(ex.Message));
|
}
|
}
|
|
|
|
|
/// <summary>
|
/// 回库完成回调
|
public async Task<WebResponseContent> BackToStockComplete(Dt_Task task)
|
{
|
try
|
{
|
_unitOfWorkManage.BeginTran();
|
|
// 获取相关的出库锁定信息
|
var lockInfos = await _outStockLockInfoService.Db.Queryable<Dt_OutStockLockInfo>()
|
.Where(x => x.TaskNum == task.TaskNum &&
|
x.Status == (int)OutLockStockStatusEnum.回库中)
|
.ToListAsync();
|
|
if (!lockInfos.Any())
|
return WebResponseContent.Instance.Error("未找到回库中的锁定信息");
|
|
// 恢复库存出库数量(回库的部分)
|
await RestoreStockOutboundQuantity(lockInfos);
|
|
// 更新出库单明细的锁定数量
|
var orderDetailGroups = lockInfos.GroupBy(x => x.OrderDetailId);
|
|
foreach (var group in orderDetailGroups)
|
{
|
var orderDetailId = group.Key;
|
var totalUnpicked = group.Sum(x => x.AssignQuantity - x.PickedQty);
|
|
if (totalUnpicked > 0)
|
{
|
var orderDetail = await _outboundOrderService.Db.Queryable<Dt_OutboundOrderDetail>()
|
.Where(x => x.Id == orderDetailId)
|
.FirstAsync();
|
orderDetail.LockQuantity -= totalUnpicked;
|
|
// 恢复状态
|
if (orderDetail.LockQuantity <= 0 && orderDetail.OverOutQuantity <= 0)
|
{
|
orderDetail.OrderDetailStatus = (int)OrderDetailStatusEnum.New;
|
}
|
else if (orderDetail.OverOutQuantity > 0)
|
{
|
orderDetail.OrderDetailStatus = (int)OrderDetailStatusEnum.AssignOverPartial;
|
}
|
|
await _outboundOrderService.Db.Updateable(orderDetail).ExecuteCommandAsync();
|
}
|
}
|
|
// 更新锁定信息状态为已回库
|
foreach (var lockInfo in lockInfos)
|
{
|
lockInfo.Status = (int)OutLockStockStatusEnum.已回库;
|
}
|
await _outStockLockInfoService.Db.Updateable(lockInfos).ExecuteCommandAsync();
|
|
// 6. 更新库存状态
|
var stockIds = lockInfos.Select(x => x.StockId).Distinct().ToList();
|
var stocks = await _stockService.StockInfoService.Db.Queryable<Dt_StockInfo>()
|
.Where(x => stockIds.Contains(x.Id))
|
.ToListAsync();
|
|
foreach (var stock in stocks)
|
{
|
stock.StockStatus = (int)StockStatusEmun.入库完成;
|
stock.LocationCode = task.TargetAddress; // 更新货位
|
}
|
await _stockService.StockInfoService.Db.Updateable(stocks).ExecuteCommandAsync();
|
|
// 7. 更新货位状态
|
var location = await _locationInfoService.Db.Queryable<Dt_LocationInfo>()
|
.Where(x => x.LocationCode == task.TargetAddress)
|
.FirstAsync();
|
if (location != null)
|
{
|
location.LocationStatus = (int)LocationStatusEnum.InStock;
|
await _locationInfoService.Db.Updateable(location).ExecuteCommandAsync();
|
}
|
|
// 更新任务状态为已完成
|
task.TaskStatus = (int)TaskStatusEnum.Finish;
|
|
await Db.Updateable(task).ExecuteCommandAsync();
|
|
_unitOfWorkManage.CommitTran();
|
|
return WebResponseContent.Instance.OK("回库完成", new
|
{
|
TaskNum = task.TaskNum,
|
PalletCode = task.PalletCode,
|
RestoredQuantity = lockInfos.Sum(x => x.AssignQuantity - x.PickedQty)
|
});
|
}
|
catch (Exception ex)
|
{
|
_unitOfWorkManage.RollbackTran();
|
return WebResponseContent.Instance.Error($"回库完成处理失败: {ex.Message}");
|
}
|
}
|
|
/// <summary>
|
/// 恢复库存出库数量(回库的部分)
|
/// </summary>
|
private async Task RestoreStockOutboundQuantity(List<Dt_OutStockLockInfo> lockInfos)
|
{
|
// 按库存ID和物料分组
|
var stockGroups = lockInfos.GroupBy(x => new { x.StockId, x.MaterielCode });
|
|
foreach (var group in stockGroups)
|
{
|
var stockId = group.Key.StockId;
|
var materielCode = group.Key.MaterielCode;
|
var totalUnpicked = group.Sum(x => x.AssignQuantity - x.PickedQty);
|
|
if (totalUnpicked <= 0) continue;
|
|
// 获取该物料在库存中的所有条码
|
var stockDetails = await _stockService.StockInfoDetailService.Db.Queryable<Dt_StockInfoDetail>()
|
.Where(x => x.StockId == stockId && x.MaterielCode == materielCode)
|
.ToListAsync();
|
|
if (!stockDetails.Any()) continue;
|
|
// 按出库数量的比例分配恢复数量
|
var totalOutbound = stockDetails.Sum(x => x.OutboundQuantity);
|
|
if (totalOutbound <= 0) continue;
|
|
foreach (var detail in stockDetails)
|
{
|
if (detail.OutboundQuantity <= 0) continue;
|
|
decimal ratio = detail.OutboundQuantity / totalOutbound;
|
decimal restoreAmount = Math.Min(detail.OutboundQuantity, totalUnpicked * ratio);
|
|
detail.OutboundQuantity -= restoreAmount;
|
await _stockService.StockInfoDetailService.Db.Updateable(detail).ExecuteCommandAsync();
|
}
|
}
|
}
|
|
}
|
}
|