山东雷驰
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

215 lines
9.9 KiB

using AutoMapper;
using Kean.Domain.Task.Commands;
using Kean.Domain.Task.Enums;
using Kean.Domain.Task.Events;
using Kean.Domain.Task.Models;
using Kean.Domain.Task.Repositories;
using Kean.Domain.Task.SharedServices.Proxies;
using Kean.Infrastructure.Configuration;
using System;
using System.Linq;
using System.Threading;
namespace Kean.Domain.Task.CommandHandlers
{
/// <summary>
/// 创建下架命令处理程序
/// </summary>
public sealed class OutfeedCommandHandler : CommandHandler<OutfeedCommand>
{
private readonly ICommandBus _commandBus; // 命令总线
private readonly INotification _notifications; // 总线通知
private readonly IMapper _mapper; // 模型映射
private readonly ITaskRepository _taskRepository; // 任务仓库
private readonly IWarehouseRepository _warehouseRepository; // 库房仓库
private readonly BarcodeInterpreter _barcodeInterpreter; // 条码解释器
private readonly BarcodeValidator _barcodeValidator; // 条码验证器
private readonly StockProxy _stockProxy; // 仓储域代理
/// <summary>
/// 依赖注入
/// </summary>
public OutfeedCommandHandler(
ICommandBus commandBus,
INotification notifications,
IMapper mapper,
ITaskRepository taskRepository,
IWarehouseRepository warehouseRepository,
BarcodeInterpreter barcodeInterpreter,
BarcodeValidator barcodeValidator,
StockProxy stockProxy)
{
_commandBus = commandBus;
_notifications = notifications;
_mapper = mapper;
_taskRepository = taskRepository;
_warehouseRepository = warehouseRepository;
_barcodeInterpreter = barcodeInterpreter;
_barcodeValidator = barcodeValidator;
_stockProxy = stockProxy;
}
/// <summary>
/// 处理程序
/// </summary>
public override async System.Threading.Tasks.Task Handle(OutfeedCommand command, CancellationToken cancellationToken)
{
if (command.ValidationResult.IsValid)
{
// 条码格式校验
if (!await _barcodeValidator.Validate(command.Barcode))
{
await _commandBus.Notify(nameof(command.Barcode), "条码格式不正确", command.Barcode,
cancellationToken: cancellationToken);
return;
}
// 任务重复
if (await _taskRepository.HasTask(command.Barcode))
{
await _commandBus.Notify(nameof(command.Barcode), "托盘正在执行任务", command.Barcode,
cancellationToken: cancellationToken);
return;
}
var pallet = await _barcodeInterpreter.Interpret(command.Barcode);
// 获取库存位置
var cell = await _stockProxy.GetCell(command.Barcode);
if (!cell.HasValue)
{
await _commandBus.Notify(nameof(command.Barcode), "库存不存在", command.Barcode,
cancellationToken: cancellationToken);
return;
}
var original = await _warehouseRepository.GetCellById(cell.Value);
// 可用的货位
if (original.State != CellState.Enabled)
{
await _commandBus.Notify(nameof(command.Barcode), "库存位置不合法", command.Barcode,
cancellationToken: cancellationToken);
return;
}
// 获取目标位置
var destinationCache = command.Destination switch
{
int i when i > 100000 => await _warehouseRepository.GetCacheByArea(i),
int i when i < 100000 => await _warehouseRepository.GetStationById(i),
long i => await _warehouseRepository.GetCacheByArea((int)i),
string s when s.StartsWith("name:") => await _warehouseRepository.GetStationByName(s[5..], command.Warehouse),
string s when s.StartsWith("device:") => await _warehouseRepository.GetStationByDevice(s[7..], command.Warehouse),
string s when s.StartsWith("cache:") => await _warehouseRepository.GetCacheByCode(s[6..]),
Station s => s,
_ => null
};
var destination = destinationCache;
//转换为实际出库站台
if (destinationCache.Group == "Trans")
{
if (!destinationCache.Pallet.Contains(command.Barcode.Substring(0,3)))
{
await _commandBus.Notify(nameof(command.Destination), "托盘类型与出库站台不匹配,请检查出库站台", command.Destination, cancellationToken: cancellationToken);
return;
}
destination = await _warehouseRepository.GetOutStationByCell(original.Id, destinationCache.Area);
if (destination == null)
{
var destinationIgnorePath = await _warehouseRepository.GetOutStationByCellIgnorePath(original.Id, destinationCache.Area);
if (destinationIgnorePath == null)
{
await _commandBus.Notify(nameof(command.Destination), "未找到出库站台", command.Destination, cancellationToken: cancellationToken);
}
else
{
await _commandBus.Notify(nameof(command.Destination), "设备故障导致无法出库", command.Destination, cancellationToken: cancellationToken);
}
return;
}
}
//// 获取目标位置
//var destination = command.Destination switch
//{
// int i => await _warehouseRepository.GetStationById(i),
// long i => await _warehouseRepository.GetStationById((int)i),
// string s when s.StartsWith("name:") => await _warehouseRepository.GetStationByName(s[5..], command.Warehouse),
// string s when s.StartsWith("device:") => await _warehouseRepository.GetStationByDevice(s[7..], command.Warehouse),
// Station s => s,
// _ => null
//};
//// 目标位置可用性
//if (destination?.Warehouse != command.Warehouse
// || destination.AllowOut != true
// || destination.Pallet?.Contains(pallet) == false
// || destination.Spec?.Adaptive(await _stockProxy.GetSpec(command.Barcode) ?? original.Spec) == false)
//{
// await _commandBus.Notify(nameof(command.Destination), "目标位置不正确", command.Destination,
// cancellationToken: cancellationToken);
// return;
//}
// 时间戳
command.Timestamp ??= DateTime.Now;
// 切点事件
var event0 = _mapper.Map<OutfeedExecutingEvent>(command);
event0.Original = original;
event0.Destination = destination;
await _commandBus.Trigger(event0, cancellationToken);
if (!_notifications.Any())
{
// 锁定库存位置
await _warehouseRepository.LockCell(original.Id);
// 非手动模式下的双深干涉处理
if (!command.Manual)
{
var avert = new AvertCommand
{
Cell = original,
Behavior = AvertCommand.Leaving,
Priority = command.Priority,
Previous = command.Previous,
Timestamp = command.Timestamp
};
await _commandBus.Execute(avert, cancellationToken);
if (_notifications.Any())
{
return;
}
if (avert.Id.HasValue)
{
command.Previous = avert.Id;
}
}
// 创建任务
var task = _mapper.Map<Models.Task>(command);
if (task.Barcode.Substring(2, 1) == "G")
{
task.Type = TaskType.Outfeed;
}
else
{
task.Type = TaskType.ApplyOut;
}
task.Original = original.Id;
task.Destination = destination.Id;
Output(nameof(command.Id), await _taskRepository.CreateTask(task));
// 成功事件
var event1 = _mapper.Map<OutfeedSuccessEvent>(command);
event1.Original = original;
event1.Destination = destination;
await _commandBus.Trigger(event1, cancellationToken);
// 手动
if (command.Manual && !_notifications.Any())
{
await _commandBus.Execute(new CompleteCommand { Id = command.Id }, cancellationToken);
}
}
}
else
{
await _commandBus.Notify(command.ValidationResult,
cancellationToken: cancellationToken);
}
}
}
}