using JSMachine.WMS.App.Dto;
using JSMachine.WMS.App.Dto.Enum;
using JSMachine.WMS.App.IService;
using JSMachine.WMS.Business.StockIn.IService;
using JSMachine.WMS.Business.StockIn.ServiceImpl.Strategy;
using JSMachine.WMS.Infrastructure.Helper;
using JSMachine.WMS.PLC.ModbusImpl.Elevator.Util;
using JSMachine.WMS.RPC.ErpRPC.Dto.In.XRBusinessResult;
using JSMachine.WMS.RPC.ErpRPC.Dto.Out.XRBusinessResult;
using JSMachine.WMS.RPC.ErpRPC.IService;
using NPOI.OpenXmlFormats.Dml.Chart;
namespace JSMachine.WMS.Business.StockIn.ServiceImpl
{
///
/// PDA入库业务类
///
public class StockInService : IStockInService
{
private IPaperStorageService _paperStorageService;
private IStorageRackService _storageRackService;
private IERPTaskService _erpTaskService;
private IAGVTaskService _agvTaskService;
private IElevatorPlcQueueService _elevatorPlcQueueService;
public StockInService(
IPaperStorageService paperStorageService,
IStorageRackService storageRackService,
IERPTaskService erpTaskService,
IAGVTaskService agvTaskService,
IElevatorPlcQueueService elevatorPlcQueueService
)
{
_paperStorageService = paperStorageService;
_storageRackService = storageRackService;
_erpTaskService = erpTaskService;
_agvTaskService = agvTaskService;
_elevatorPlcQueueService = elevatorPlcQueueService;
}
///
/// PDA入库
///
///
///
public async Task StockIn(PDAInParam stockInParam)
{
// 入库流程依次校验重复任务、物料和起点库位,再计算目标库位并创建任务。
//1.查询物料信息是否存在
//2.查询库位是否存在
//3.计算目标库位并锁定
//4.写入ErpTask表
bool existUnCompleteTask = await _erpTaskService.Exist(p =>
p.CreationTime > DateTime.Now.Date &&
(p.TaskType == TaskTypeEnum.PdaIn || p.TaskType==TaskTypeEnum.TailIn)&&
(p.TaskStatus == TaskStatusEnum.Initial || p.TaskStatus == TaskStatusEnum.InExecution) &&
p.BarCode == stockInParam.BarCode);
if (existUnCompleteTask)
{
LogHelper.Warn($"合格证号 {stockInParam.BarCode} 已有待入库的任务,请检查是否扫错");
return $"合格证号 {stockInParam.BarCode} 已有待入库的任务,请检查是否扫错";
}
MateriaInfoDto materiaInfo = await CheckMaterialInfo(stockInParam.BarCode);
if (materiaInfo == null)
{
string msg = $"未在ERP中查询到合格证号为 {stockInParam.BarCode} 的物料信息";
LogHelper.Warn(msg);
return msg;
}
StorageRackDto startStoragRack = await _storageRackService.GetSingalByExpression(p =>
p.StorageRackNo == stockInParam.StorageRackNo &&
!p.IsDisabled);
if (startStoragRack == null)
{
string msg = $"入库起点库位 {stockInParam.StorageRackNo} 不可用";
LogHelper.Warn(msg);
return msg;
}
//如果是尾托回库,需要自动计算任务楼层
if (stockInParam.TaskType == TaskTypeEnum.TailIn)
{
AGVTaskDto outTask = await _agvTaskService.GetSingalByExpression(p =>
p.BarCode == stockInParam.BarCode &&
(p.TaskType == TaskTypeEnum.SaleOut || p.TaskType == TaskTypeEnum.TransferStockOut) &&
!p.StartPositionCode.Contains("TSJ"),
p => p.CreationTime,
SqlSugar.OrderByType.Desc);
if (outTask == null)
{
string msg = $"合格证号 {stockInParam.BarCode} 批次 {materiaInfo.MateriaBatch} 没有对应的出库任务," +
$"因此不知道该物料原来所属楼层,请人工将该货物放置到合适的库位上,然后使用pda更新物料信息";
LogHelper.Error(msg);
return msg;
}
stockInParam.Floor = outTask.Floor;
}
//预先计算可用的库位(所有未禁用,空白库位-未完成的入库任务)
int usableWarehouseCout = await _storageRackService.Count(p =>
p.Floor == stockInParam.Floor &&
p.Transport == TransportEnum.NormalArea &&
!p.IsDisabled);
int unCompleteErpTaskCount = await _erpTaskService.Count(p =>
p.CreationTime > DateTime.Now.Date &&
(p.TaskType == TaskTypeEnum.PdaIn || p.TaskType == TaskTypeEnum.TailIn) &&
!(p.TaskStatus == TaskStatusEnum.Completed || p.TaskStatus == TaskStatusEnum.Cancelled)
);
if (usableWarehouseCout- unCompleteErpTaskCount <=0)
{
string msg = $"没有空余库位,无法入库";
LogHelper.Warn(msg);
return msg;
}
ERPTaskDto erpTask = CreateErpTask(stockInParam, materiaInfo);
bool bRet = await _erpTaskService.Add(erpTask);
if (!bRet)
{
string msg = $"数据库操作失败";
LogHelper.Warn(msg);
return msg;
}
return string.Empty;
}
///
/// 从ERPTask生成AgvTask(pda入库)
///
///
///
public async Task CreateAgvTaskFirstFloor(ERPTaskDto erpTask)
{
//1.入库到一楼寻找一楼库位
//2.入库到二楼寻找一楼提升机库位
StorageRackDto destWareHouse = await CalculateDestWarehouse(erpTask, erpTask.MateriaBatch, erpTask.Floor);
if (destWareHouse == null)
{
return false;
}
AGVTaskDto agvTask = new()
{
ErpTaskId = erpTask.Id,
BarCode = erpTask.BarCode,
OrderNo = erpTask.OrderNo,
CustomName = erpTask.CustomName,
MateriaName = erpTask.MateriaName,
MateriaType = erpTask.MateriaType,
MateriaNum = erpTask.ErpOrderNum,
MateriaBatch = erpTask.MateriaBatch,
MateriaCode = erpTask.MateriaCode,
TaskType = erpTask.TaskType,
TaskStatus = TaskStatusEnum.Initial,
Priority = PriorityEnum.High,
Floor = FloorEnum.FirstFloor,
StartPositionCode = erpTask.StorageRackNo,
EndPositionCode = destWareHouse.StorageRackNo,
ErpUploadStatus = destWareHouse.Transport == TransportEnum.Elevator ? ErpUploadStatusEnum.Unnecessary : ErpUploadStatusEnum.WaittingToUpload,
Transport = TransportEnum.NormalArea
};
destWareHouse.IsLock = true;
await _storageRackService.Lock(destWareHouse);
return await _agvTaskService.Add(agvTask);
}
private async Task CheckMaterialInfo(string barcode)
{
XRResultDto xRResult = await _paperStorageService.GetMateriaInfo(barcode);
if (xRResult?.status == 200)
return xRResult.data;
return null;
}
///
/// 计算目标库位
///
///
///
private async Task CalculateDestWarehouse(ERPTaskDto erpTask, string materiaBatch, FloorEnum floor)
{
//1.入库到一楼寻找一楼库位
//2.入库到二楼寻找一楼提升机库位
if (floor == FloorEnum.FirstFloor)
{
IStockInStrategy stockInStrategy = StrategyFactory.CreateStockInStrategy(TransportEnum.ManualArea, floor, materiaBatch);
StorageRackDto destWarehouse = await stockInStrategy.CalCulateWarehouse();
return destWarehouse;
}
StorageRackDto elevatorWarehouse = await ElevatorUtil.GetUsableElevatorChannel(erpTask.Id, FloorEnum.FirstFloor);
return elevatorWarehouse;
}
private ERPTaskDto CreateErpTask(PDAInParam pdaInParam, MateriaInfoDto materiaInfoDto)
{
ERPTaskDto eRPTaskDto = new()
{
StorageRackNo = pdaInParam.StorageRackNo,
OrderNo = materiaInfoDto.OrderNo,
BarCode = materiaInfoDto.BarCode,
MateriaName = materiaInfoDto.MateriaName,
ErpOrderNum = pdaInParam.TaskType == TaskTypeEnum.PdaIn ? int.Parse(materiaInfoDto.MateriaNum) : pdaInParam.MertialNum,
MateriaBatch = materiaInfoDto.MateriaBatch,
MateriaCode = materiaInfoDto.MateriaCode,
TaskStatus = TaskStatusEnum.Initial,
TaskType = pdaInParam.TaskType,
Floor = pdaInParam.Floor
};
return eRPTaskDto;
}
}
}