using PlcSiemens.Core.Extension;
using ServiceCenter.Extensions;
using ServiceCenter.Logs;
using ServiceCenter.SqlSugars;
using SqlSugar;
using System.ComponentModel;
using WCS.Core;
using WCS.Entity;
using WCS.Entity.Protocol.Station;
using WCS.WorkEngineering.Extensions;
using WCS.WorkEngineering.Worlds;
using DeviceFlags = WCS.WorkEngineering.Extensions.DeviceFlags;
using TaskStatus = WCS.Entity.TaskStatus;
namespace WCS.WorkEngineering.Systems
{
///
/// 分流点
///
[BelongTo(typeof(SortingBranchWorld))]
[Description("环形库分流点")]
public class 环形库分流点 : DeviceSystem>
{
protected override bool ParallelDo => true;
protected override bool SaveLogsToFile => true;
public override void Do(Device obj)
{
if (obj.Data.VoucherNo != obj.Data2.VoucherNo) throw new KnownException($"凭证号不一致,DB520:{obj.Data.VoucherNo}-DB521:{obj.Data2.VoucherNo}", LogLevelEnum.High);
if (obj.Data3.Status.HasFlag(StationStatus.Run)) throw new KnownException("设备运行中", LogLevelEnum.Low);
if (!obj.Data3.Status.HasFlag(StationStatus.OT_Status)) throw new KnownException("站台货物信息与实际占用不一致", LogLevelEnum.Low);
if (obj.Data2.Request != 1) throw new KnownException("无请求", LogLevelEnum.Mid);
//处理异常任务
if (obj.Data2.TaskNumber == 1)
{
obj.Data.TaskNumber = 591;
obj.Data.GoodsStart = obj.Entity.Code.ToShort();
obj.Data.GoodsEnd = 591;
obj.Data.VoucherNo++;
World.Log($"执行记录:任务号[{591}]-[{obj.Data.VoucherNo}]");
}
var isPut = false;
short nextAdd = 0;
SqlSugarHelper.Do(_db =>
{
var db = _db.Default;
var taskInfo = db.Queryable().First(v => v.ID == obj.Data2.TaskNumber && v.Status == TaskStatus.WaitingToExecute) ?? throw new KnownException($"未找到对应的WCS任务{obj.Data2.TaskNumber}", LogLevelEnum.Mid);
switch (obj.Data4.Length)
{
case 9:
isPut = Allot09Or18(db, taskInfo, obj);
nextAdd = 455;
break;
case 18:
nextAdd = 442;
taskInfo.AddrNext = nextAdd.ToString();
taskInfo.Status = TaskStatus.FinishOfShunt;
taskInfo.EditTime = DateTime.Now;
taskInfo.WarehouseCode += "R";
taskInfo.AddrTo = "Robot";
taskInfo.GoodsType = obj.Data4.Length.ToInt();
db.Updateable(taskInfo).ExecuteCommand();
taskInfo.AddWCS_TASK_DTL(db, obj.Entity.Code, nextAdd.ToString(), "环形库分流");
isPut = true;
obj.Data.CmdType = StationCmd.Res6;
break;
case 50:
nextAdd = 424;
taskInfo.AddrNext = nextAdd.ToString();
taskInfo.Status = TaskStatus.FinishOfShunt;
taskInfo.EditTime = DateTime.Now;
taskInfo.WarehouseCode += "R";
taskInfo.AddrTo = "Robot";
taskInfo.GoodsType = obj.Data4.Length.ToInt();
db.Updateable(taskInfo).ExecuteCommand();
taskInfo.AddWCS_TASK_DTL(db, obj.Entity.Code, nextAdd.ToString(), "环形库分流");
isPut = true;
break;
case 34:
nextAdd = 433;
taskInfo.AddrNext = nextAdd.ToString();
taskInfo.Status = TaskStatus.FinishOfShunt;
taskInfo.EditTime = DateTime.Now;
taskInfo.WarehouseCode += "R";
taskInfo.AddrTo = "Robot";
taskInfo.GoodsType = obj.Data4.Length.ToInt();
db.Updateable(taskInfo).ExecuteCommand();
taskInfo.AddWCS_TASK_DTL(db, obj.Entity.Code, nextAdd.ToString(), "环形库分流");
isPut = true;
break;
}
});
if (!isPut) return;
obj.Data.TaskNumber = obj.Data2.TaskNumber;
obj.Data.GoodsStart = obj.Entity.Code.ToShort();
obj.Data.GoodsEnd = nextAdd;
obj.Data.VoucherNo++;
World.Log($"执行记录:任务号[{obj.Data2.TaskNumber}]-[{obj.Data.VoucherNo}]");
}
public override bool Select(Device dev)
{
return dev.HasFlag(DeviceFlags.环形库分流点);
}
///
/// 计算非零九或18的去向
///
///
///
///
///
public bool AllotNot09Or18(SqlSugarScopeProvider db, WCS_TaskInfo taskInfo, Device obj)
{
return false;
}
///
/// 计算09/18去向
///
///
///
///
///
public bool Allot09Or18(SqlSugarScopeProvider db, WCS_TaskInfo taskInfo, Device obj)
{
//TODO:暂时不来考虑动态计算可前往的目标
var nextAdd = taskInfo.WarehouseCode switch
{
"1N" => "455",
"1S" => "455",
"2N" => "455",
"2S" => "455",
"3N" => "455",
"3S" => "455",
_ => "0"
};
//获取这个地址的下一个地址集合
var cacheLineDevList = Device.All.First(x => x.Code == nextAdd).Targets.Where(x => x.HasFlag(DeviceFlags.桁架缓存放行点));
var cacheLineCodes = cacheLineDevList.Select(x => x.Code.ToShort());
var cacheLineList = db.Queryable().Includes(x => x.Locations).ToList();
#region 跟据缓存信息寻找可以到达的缓存点
//找到当前任务可用的缓存线信息
var cacheLine = cacheLineList.Where(x => x.Locations.Any(l => l is { InStock: false, IsEmpty: false })).FirstOrDefault(x => cacheLineCodes.Contains(x.LocationNo) && x.MatCodeList.Contains(taskInfo.MatCode) && !x.InStock);
if (cacheLine != null)//这个任务可以直接去一条线体,不需要新建缓存信息
{
//找到这条线体中序号最小的一条位信息 非空置且无货
var cacheLoc = cacheLine.Locations.Where(x => x is { InStock: false, IsEmpty: false }).MinBy(x => x.XYNo);
if (cacheLoc != null)
{
cacheLoc = db.Queryable().Single(x => x.Id == cacheLoc.Id);
cacheLoc.InStock = true;
cacheLoc.TaskId = taskInfo.ID;
cacheLoc.EditTime = DateTime.Now;
db.Updateable(cacheLoc).ExecuteCommand();
//WCS任务相关信息
taskInfo.Status = TaskStatus.FinishOfShunt;
taskInfo.AddrNext = cacheLine.LocationNo.ToString();
taskInfo.EditWho = "WCS";
taskInfo.EditTime = DateTime.Now;
taskInfo.GoodsType = obj.Data4.Length.ToInt();
db.Updateable(taskInfo).ExecuteCommand();
taskInfo.AddWCS_TASK_DTL(db, obj.Entity.Code, taskInfo.AddrNext, $"完成分库计算,目标地址:{cacheLine.LocationNo}");
return true;
}
}
#endregion 跟据缓存信息寻找可以到达的缓存点
#region 初始化一个信息的缓存信息
//TODO:暂时不处理就近分线的逻辑
var devCode = cacheLineDevList.Select(x => x.Code.ToShort()).FirstOrDefault(x => !cacheLineList.Select(s => s.LocationNo).Contains(x));
if (devCode == 0)
{
World.Log($"无可用线体:{taskInfo.ID}");
return false;
}
var result = false;
//未结束且包含当前物料编号的垛形,按时间排序,创建时间早的优先分配
var palletizingList = db.Queryable()
.Includes(x => x.Layers, r => r.Rows, l => l.Locs)
.Where(x => !x.Finish)
.Where(x => x.MatCodeList.Contains(taskInfo.MatCode))
.OrderBy(x => x.AddTime)
.ToList();
foreach (var palletizing in palletizingList)
{
//当前任务已经分配结束,进入下一次迭代
if (result) continue;
//未结束且包含当前物料编号的层,按层号排序,层号小的优先分配
var layers = palletizing.Layers.Where(x => x is { IsEmpty: false, Finish: false })
.Where(x => x.MatCodeList.Contains(taskInfo.MatCode))
.OrderBy(x => x.LayerNo)
.ToList();
//未找到可用层,进入下一次迭代
if (!layers.Any()) continue;
foreach (var layer in layers)
{
//当前任务已经分配结束,进入下一次迭代
if (result) continue;
//未结束,未预分配缓存线信息且包含当前物料编号的行,行号小的优先分配
var rows = layer.Rows.Where(x => x is { IsEmpty: false, Finish: false })
.Where(x => x.CacheLineId == 0)
.Where(x => x.MatCodeList.Contains(taskInfo.MatCode))
.ToList();
//未找到可用行,进入下一次迭代
if (!rows.Any()) continue;
var palletizingRow = rows.MinBy(x => x.RowNo);
//开始初始化缓存位信息
cacheLine = new WCS_CacheLine()
{
LocationNo = devCode,
AddTime = DateTime.Now,
PalletizingRowId = palletizingRow.Id,
InStock = false,
Put = false,
IsTruss = false,
MatCodeList = palletizingRow.MatCodeList
};
var res = db.Insertable(cacheLine).ExecuteReturnEntity();
palletizingRow = db.Queryable().Includes(x => x.Locs).Single(x => x.Id == palletizingRow.Id);
palletizingRow.Locs = palletizingRow.Locs.OrderBy(x => x.XYNo).ToList();
palletizingRow.CacheLineId = res.Id;
palletizingRow.EditTime = DateTime.Now;
db.Updateable(palletizingRow).ExecuteCommand();
for (var i = 0; i < palletizingRow.Locs.Count; i++)
{
var loc = new WCS_CacheLineLoc()
{
XYNo = palletizingRow.Locs[i].XYNo,
InStock = i == 0,
IsEmpty = palletizingRow.Locs[i].IsEmpty,
MatCode = palletizingRow.Locs[i].MatCode,
TaskId = i == 0 ? taskInfo.ID : 0,
CacheLineId = res.Id
};
db.Insertable(loc).ExecuteCommand();
}
taskInfo.Status = TaskStatus.FinishOfShunt;
taskInfo.AddrNext = devCode.ToString();
taskInfo.EditWho = "WCS";
taskInfo.EditTime = DateTime.Now;
taskInfo.GoodsType = obj.Data4.Length.ToInt();
db.Updateable(taskInfo).ExecuteCommand();
taskInfo.AddWCS_TASK_DTL(db, obj.Entity.Code, taskInfo.AddrNext, $"完成分库计算,目标地址:{cacheLine.LocationNo}");
result = true;
}
}
if (!result)
{
taskInfo.InitStackStructure(db);
}
return result;
////找到所有当前轮子可以去的垛形
//var palletizingList = db.Queryable()
// .Includes(x => x.Layers, r => r.Rows, l => l.Locs)
// .Where(x => x.MatCodeList.Contains(taskInfo.MatCode) && !x.Finish).ToList()
// .Where(x => x.Layers.SelectMany(x => x.Rows).Any(r => r.LineCode == null))
// .OrderBy(x => x.AddTime).ToList();
////如果没有对应的垛形信息就初始化一个垛形信息
//if (palletizingList.Count <= 0)
//{
// taskInfo.InitStackStructure(db);
// return false;
//}
//var b = palletizingList.Select(palletizing => palletizing.Layers
// .Where(x => !x.IsEmpty)
// .Where(x => !x.Finish)
// .Where(x => x.MatCodeList.Contains(taskInfo.MatCode))
// .Where(x => x.Rows.Any(r => r is { IsEmpty: false, Finish: false } && r.MatCodeList.Contains(taskInfo.MatCode) && r.CacheLineId == 0))
// .MinBy(x => x.LayerNo)).Where(x => x != null);
//foreach (var palletizingLayer in b)
//{
// //如果没有哪一层需要这个物料号,就初始化一个新的垛形信息
// if (palletizingLayer == null)
// {
// taskInfo.InitStackStructure(db);
// return false;
// }
// //再找行:未空置、未结束
// var palletizingRow = palletizingLayer.Rows.Where(x => x is { IsEmpty: false, Finish: false } && x.MatCodeList.Contains(taskInfo.MatCode) && x.CacheLineId == 0)
// .MinBy(x => x.RowNo);
// //如果没有哪一行需要这个物料号,就初始化一个新的垛形信息
// if (palletizingRow == null)
// {
// taskInfo.InitStackStructure(db);
// return false;
// }
// //走到这一步就表示没有哪一段线体缓存了当前物料,需要选一段新的线体进行缓存
// //TODO:暂时不处理就近分线的逻辑
// //获取一个当前可以使用的分配锁
// var devCode = cacheLineDevList.Select(x => x.Code.ToShort()).FirstOrDefault(x => !cacheLineList.Select(s => s.LocationNo).Contains(x));
// if (devCode == 0)
// {
// World.Log($"无可用线体:{taskInfo.ID}");
// return false;
// }
// //开始初始化缓存位信息
// cacheLine = new WCS_CacheLine()
// {
// LocationNo = devCode,
// AddTime = DateTime.Now,
// PalletizingRowId = palletizingRow.Id,
// InStock = false,
// Put = false,
// IsTruss = false,
// MatCodeList = palletizingRow.MatCodeList
// };
// var res = db.Insertable(cacheLine).ExecuteReturnEntity();
// palletizingRow = db.Queryable().Includes(x => x.Locs).Single(x => x.Id == palletizingRow.Id);
// palletizingRow.Locs = palletizingRow.Locs.OrderBy(x => x.XYNo).ToList();
// palletizingRow.CacheLineId = res.Id;
// palletizingRow.EditTime = DateTime.Now;
// db.Updateable(palletizingRow).ExecuteCommand();
// for (var i = 0; i < palletizingRow.Locs.Count; i++)
// {
// var loc = new WCS_CacheLineLoc()
// {
// XYNo = palletizingRow.Locs[i].XYNo,
// InStock = i == 0,
// IsEmpty = palletizingRow.Locs[i].IsEmpty,
// MatCode = palletizingRow.Locs[i].MatCode,
// TaskId = i == 0 ? taskInfo.ID : 0,
// CacheLineId = res.Id
// };
// db.Insertable(loc).ExecuteCommand();
// }
// taskInfo.Status = TaskStatus.FinishOfShunt;
// taskInfo.AddrNext = devCode.ToString();
// taskInfo.EditWho = "WCS";
// taskInfo.EditTime = DateTime.Now;
// taskInfo.GoodsType = obj.Data4.Length.ToInt();
// db.Updateable(taskInfo).ExecuteCommand();
// taskInfo.AddWCS_TASK_DTL(db, obj.Entity.Code, taskInfo.AddrNext, $"完成分库计算,目标地址:{cacheLine.LocationNo}");
// return true;
//}
#endregion 初始化一个信息的缓存信息
}
}
}