using Microsoft.Extensions.Configuration;
|
using WIDESEA_Common.LocationEnum;
|
using WIDESEA_Common.StockEnum;
|
using WIDESEA_Common.TaskEnum;
|
using WIDESEA_Core;
|
using WIDESEA_Core.Helper;
|
using WIDESEA_DTO.Task;
|
using WIDESEA_Model.Models;
|
|
namespace WIDESEA_TaskInfoService
|
{
|
public partial class TaskService
|
{
|
#region 自动出库任务
|
|
/// <summary>
|
/// 自动创建出库任务 - 查询到期库存并创建任务
|
/// </summary>
|
public async Task<WebResponseContent> CreateAutoOutboundTasksAsync()
|
{
|
try
|
{
|
// 1. 查询到期库存
|
var expiredStocks = await _stockInfoService.Repository
|
.QueryDataNavAsync(s => s.OutboundDate <= DateTime.Now
|
&& s.StockStatus == StockStatusEmun.入库完成.GetHashCode());
|
|
if (expiredStocks == null || !expiredStocks.Any())
|
{
|
return WebResponseContent.Instance.OK("无到期库存需要处理");
|
}
|
|
// 过滤有位置且位置有库存的记录
|
expiredStocks = expiredStocks
|
.Where(s => s.LocationDetails != null
|
&& s.LocationDetails.LocationStatus == LocationStatusEnum.InStock.GetHashCode())
|
.ToList();
|
|
if (!expiredStocks.Any())
|
{
|
return WebResponseContent.Instance.OK("无符合条件的到期库存");
|
}
|
|
// 2. 检查已存在的任务
|
var palletCodes = expiredStocks.Select(s => s.PalletCode).ToList();
|
var existingTasks = await Repository.QueryDataAsync(t =>
|
palletCodes.Contains(t.PalletCode)
|
&& (t.TaskStatus == TaskStatusEnum.New.GetHashCode()
|
|| t.TaskStatus == TaskStatusEnum.SC_Executing.GetHashCode()
|
|| t.TaskStatus == TaskInStatusEnum.InNew.GetHashCode()));
|
|
var processedPallets = existingTasks.Select(t => t.PalletCode).ToHashSet();
|
|
// 3. 筛选需要处理的库存
|
var stocksToProcess = expiredStocks
|
.Where(s => !processedPallets.Contains(s.PalletCode))
|
.ToList();
|
|
if (!stocksToProcess.Any())
|
{
|
return WebResponseContent.Instance.OK("所有到期库存已存在任务");
|
}
|
|
// 4. 获取配置的目标地址映射
|
var targetAddressMap = _configuration.GetSection("AutoOutboundTask:TargetAddresses")
|
.Get<Dictionary<string, List<string>>>()
|
?? new Dictionary<string, List<string>>();
|
|
// 5. 批量创建任务
|
var taskList = new List<Dt_Task>();
|
foreach (var stock in stocksToProcess)
|
{
|
// 根据巷道确定目标地址(优先根据 Remark 确定,Remark 为空则根据巷道配置)
|
var targetAddress = DetermineTargetAddressByRemark(
|
stock.Remark ?? "",
|
stock.LocationDetails?.RoadwayNo ?? "",
|
targetAddressMap);
|
|
var task = new Dt_Task
|
{
|
WarehouseId = stock.WarehouseId,
|
PalletCode = stock.PalletCode,
|
PalletType = stock.PalletType,
|
SourceAddress = stock.LocationCode,
|
CurrentAddress = stock.LocationCode,
|
NextAddress = targetAddress,
|
TargetAddress = targetAddress,
|
Roadway = stock.LocationDetails?.RoadwayNo ?? "",
|
TaskType = TaskTypeEnum.Outbound.GetHashCode(),
|
TaskStatus = TaskStatusEnum.New.GetHashCode(),
|
Grade = 1,
|
TaskNum = await BaseDal.GetTaskNo(),
|
Creater = "system_auto"
|
};
|
taskList.Add(task);
|
}
|
|
var transactionResult = await _unitOfWorkManage.BeginTranAsync(async () =>
|
{
|
var addResult = await BaseDal.AddDataAsync(taskList) > 0;
|
if (!addResult)
|
{
|
return WebResponseContent.Instance.Error($"批量创建任务失败,共 {taskList.Count} 个任务");
|
}
|
|
// 任务创建成功后,同步锁定库存和货位状态,避免重复分配
|
var stocksToUpdate = stocksToProcess
|
.Select(s =>
|
{
|
s.StockStatus = StockStatusEmun.出库锁定.GetHashCode();
|
return s;
|
})
|
.ToList();
|
|
var updateStockResult = await _stockInfoService.Repository.UpdateDataAsync(stocksToUpdate);
|
if (!updateStockResult)
|
{
|
return WebResponseContent.Instance.Error($"任务创建成功,但库存状态更新失败,共 {stocksToUpdate.Count} 条");
|
}
|
|
var locationsToUpdate = stocksToProcess
|
.Where(s => s.LocationDetails != null)
|
.GroupBy(s => s.LocationDetails.Id)
|
.Select(g =>
|
{
|
var location = g.First().LocationDetails;
|
location.LocationStatus = LocationStatusEnum.InStockLock.GetHashCode();
|
return location;
|
})
|
.ToList();
|
|
if (locationsToUpdate.Any())
|
{
|
var updateLocationResult = await _locationInfoService.Repository.UpdateDataAsync(locationsToUpdate);
|
if (!updateLocationResult)
|
{
|
return WebResponseContent.Instance.Error($"任务创建成功,但货位状态更新失败,共 {locationsToUpdate.Count} 条");
|
}
|
}
|
|
return WebResponseContent.Instance.OK();
|
});
|
if (!transactionResult.Status)
|
{
|
return transactionResult;
|
}
|
|
// 6. 通知 WCS(异步,不影响主流程)
|
_ = Task.Run(() =>
|
{
|
try
|
{
|
var wmstaskDtos = _mapper.Map<List<WMSTaskDTO>>(taskList);
|
_httpClientHelper.Post<WebResponseContent>(
|
"http://localhost:9292/api/Task/ReceiveTask",
|
wmstaskDtos.ToJson());
|
}
|
catch (Exception ex)
|
{
|
// WCS 通知失败不影响任务创建,记录日志即可
|
Console.WriteLine($"WCS 批量通知失败,任务数量: {taskList.Count}, 错误: {ex.Message}");
|
}
|
});
|
|
return WebResponseContent.Instance.OK($"成功创建 {taskList.Count} 个出库任务", taskList.Count);
|
}
|
catch (Exception ex)
|
{
|
return WebResponseContent.Instance.Error($"自动创建出库任务失败: {ex.Message}");
|
}
|
}
|
|
#endregion 自动出库任务
|
}
|
}
|