using Rhea.Common;
using Tiger.IBusiness;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Tiger.Model;
using static Tiger.Business.Biz;
using Tiger.Model.Entitys.MES.Position;
namespace Tiger.Business.MES.Transaction
{
///
/// MES岗位事务
///
public class Position : MESTransactionBase, IPosition
{
public IPosition Init(string id, string apiHost, string userCode, string postCode)
{
TransID = id;
UserCode = userCode;
ApiHost = apiHost;
PostCode = postCode;
CurPosition = Biz.Db.Queryable().Where(q => q.POST_CODE == postCode).First();
//if (CurPosition.IsNullOrEmpty()) throw new InvalidDataException($"MES.Transaction.Position.PositionNotExistsException", new Exception($"{postCode}|"));
if (CurPosition.IsNullOrEmpty()) throw new InvalidDataException($"岗位[{postCode}]不存在,请提交正确的岗位代码", new Exception($"{postCode}|"));
CurLine = Biz.Db.Queryable().Where(q => q.LINE_CODE == CurPosition.LINE_CODE).First();
//if (CurLine.IsNullOrEmpty()) throw new InvalidDataException($"MES.Transaction.Position.LineNotExistsException", new Exception($"{postCode}|{CurPosition.LINE_CODE}"));
if (CurLine.IsNullOrEmpty()) throw new InvalidDataException($"岗位[{postCode}]所属的产线[{CurPosition.LINE_CODE}]不存在,请先设置所属产线", new Exception($"{postCode}|{CurPosition.LINE_CODE}"));
CurWorkshop = Biz.Db.Queryable().Where(q => q.WS_CODE == CurLine.WS_CODE).First();
//if (CurWorkshop.IsNullOrEmpty()) throw new InvalidDataException($"MES.Transaction.Position.WorkshopNotExistsException", new Exception($"{postCode}|{CurLine.WS_CODE}"));
if (CurWorkshop.IsNullOrEmpty()) throw new InvalidDataException($"岗位[{postCode}]所属的车间[{CurLine.WS_CODE}]不存在,请先设置所属车间", new Exception($"{postCode}|{CurLine.WS_CODE}"));
CurFactory = Biz.Db.Queryable().Where(q => q.FTY_CODE == CurWorkshop.FTY_CODE).First();
//if (CurFactory.IsNullOrEmpty()) throw new InvalidDataException($"MES.Transaction.Position.FactoryNotExistsException", new Exception($"{postCode}|{CurWorkshop.FTY_CODE}"));
if (CurFactory.IsNullOrEmpty()) throw new InvalidDataException($"岗位[{postCode}]所属的工厂[{CurWorkshop.FTY_CODE}]不存在,请先设置所属工厂", new Exception($"{postCode}|{CurWorkshop.FTY_CODE}"));
//加载当前产线的班制
CurShiftSys = Biz.Db.Queryable().Where(q => q.SFTS_CODE == CurLine.SFTS_CODE).IncludesAllFirstLayer().IncludesAllSecondLayer(q => q.Shifts).First();
return this;
}
#region Propertys & Variables
public string UserCode { get; set; }
public string PostCode { get; set; }
public MES_FACTORY CurFactory { get; set; }
public MES_WORKSHOP CurWorkshop { get; set; }
public MES_LINE CurLine { get; set; }
public MES_POSITION CurPosition { get; set; }
public MES_SHIFT_SYS CurShiftSys { get; set; }
public WorkBatch CurBatch { get; set; }
public IWorkBatch WorkBatch => CurBatch;
public List CurWipSNs { get; set; } = new();
public string CurSN => (CurWipSNs.Any() ? (CurWipSNs.First().TRAY_SN.IsNullOrEmpty() ? CurWipSNs.First().SN : CurWipSNs.First().TRAY_SN) : "");
public List CurWipSNHiss { get; set; } = new();
public List CurDefects { get; set; } = new();
public Dictionary Context { get; set; } = new();
public List Steps { get; set; } = new();
public WorkStep CurStep { get; set; }
public List NextSteps { get; set; } = new();
public bool IsFinishNodeSteps => !Steps.Any(q => q.NodeType == IWorkStep.NodeTypes.Node && !q.IsFinished);
public bool IsFinishAllSteps => !Steps.Any() || !Steps.Any(q => !q.IsFinished);
//public int CurStep => Steps.Where(q => !q.IsFinished).OrderBy(q => q.Sequence).FirstOrDefault()?.Sequence ?? 0;
private DbClient CommitDB;
///
/// 是否需要临时存储数据库提交操作,待需要的时候再提交
///
public bool NeedTemporaryStoreDBCommitAction { get; set; } = false;
protected Dictionary> DBCommitList { get; set; } = new();
protected List NodeCommitList { get; set; } = new();
private Dictionary OperInfoDic = new();
#endregion Propertys & Variables
#region Functions
///
/// 获取提交数据的DbClient对象
///
///
public DbClient GetCommitDB()
{
return CommitDB ??= Biz.Db;
}
///
/// 选择工单
///
///
///
public async Task SelectOrder(WoInput input)
{
var action = new ApiAction();
try
{
if (!WoContext.ExistsBatch(input.OrderNo, CurLine.LINE_CODE))
{
var wo = await Biz.Db.Queryable().ByAuth(input.AuthOption).Where(q => q.ORDER_NO == input.OrderNo).FirstAsync();
//验证明细是否正确
if (wo.IsNullOrEmpty())
{
action.IsSuccessed = false;
//action.LocaleMsg = new($"工单[{input.OrderNo}]不存在", input.OrderNo);
action.LocaleMsg = new("MES.Transaction.Position.SelectOrder.EmptyException", input.OrderNo);
return action;
}
if (wo.STATUS != BIZ_MES_WO.STATUSs.Release.GetValue() && wo.STATUS != BIZ_MES_WO.STATUSs.Working.GetValue())
{
action.IsSuccessed = false;
//action.LocaleMsg = new($"工单[{input.OrderNo}]状态[{wo.STATUS.GetEnum().GetName()}]不能生产");
action.LocaleMsg = new("MES.Transaction.Position.SelectOrder.StatusException", input.OrderNo, wo.STATUS.GetEnum().GetName());
return action;
}
var batch = await Biz.Db.Queryable().ByAuth(input.AuthOption).Where(q => q.ORDER_NO == input.OrderNo && q.ACT_LINE == CurLine.LINE_CODE).FirstAsync();
if (batch.IsNullOrEmpty())
{
action.IsSuccessed = false;
//action.LocaleMsg = new($"工单[{input.OrderNo}]没有下发到产线状态[{CurLine.LINE_CODE}]");
action.LocaleMsg = new("MES.Transaction.Position.SelectOrder.LineException", input.OrderNo, CurLine.LINE_CODE);
return action;
}
if (batch.STATUS != BIZ_MES_WO_BATCH.STATUSs.Release.GetValue() && batch.STATUS != BIZ_MES_WO_BATCH.STATUSs.Working.GetValue())
{
action.IsSuccessed = false;
//action.LocaleMsg = new($"工单[{input.OrderNo}]状态[{wo.STATUS.GetEnum().GetName()}]不能生产");
action.LocaleMsg = new("MES.Transaction.Position.SelectOrder.StatusException", input.OrderNo, batch.STATUS.GetEnum().GetName());
return action;
}
var wb = new WorkBatch(input.OrderNo).Init(CurLine.LINE_CODE);
WoContext.WoBatchDic.Add(wb.Batch.BATCH_NO, wb);
}
CurBatch = WoContext.GetBatch(input.OrderNo, CurLine.LINE_CODE);
if (!OperInfoDic.ContainsKey(CurBatch.Batch.BATCH_NO))
{
OperInfoDic.Add(CurBatch.Batch.BATCH_NO, new());
}
action.Data = new { WorkOrder = CurBatch.WO, Bacth = CurBatch.Batch };
}
catch (Exception ex)
{
action.CatchExceptionWithLog(ex, $"采集工序:选择工单异常");
}
return action;
}
///
/// 获取当前时间所属的班制班次时段
///
public ShiftPeriod GetShiftPeriodForNow()
{
var time = DateTime.Now.ToString("HHmm").ToInt32();
foreach (var shift in CurShiftSys.Shifts)
{
var period = shift.Periods.Where(q => q.PRD_BEGIN <= time && time <= q.PRD_END).FirstOrDefault();
if (!period.IsNullOrEmpty())
{
var result = new ShiftPeriod();
result.ShiftSys = CurShiftSys;
result.Shift = shift;
result.Period = period;
return result;
}
}
return null;
}
///
/// 重置工序操作
///
///
public ApiAction Reset()
{
var action = new ApiAction();
ResetNode();
action.IsSuccessed = true;
action.LocaleMsg = new($"工序操作已重置,请重新扫描进站产品条码");
action.LocaleMsg = new("MES.Transaction.Position.ResetNode");
return action;
}
///
/// 重置当前工序,有需要则重写此方法
///
public virtual void ResetNode()
{
Steps.Clear();
CurWipSNs.Clear();
CurWipSNHiss.Clear();
CurStep = null;
CurDefects.Clear();
}
//获取当前的工序信息
protected OperInfo CurOperInfo(string locale)
{
OperInfo info = new();
if (CurBatch?.Batch?.BATCH_NO != null)
{
info = OperInfoDic[CurBatch.Batch.BATCH_NO ];
info.StepsInfo = Steps.Select(q => q.GetInfo(locale)).ToList();
}
return info;
}
///
/// 设置当前条码的工序信息
///
public OperInfo SetOperNodeInfo(OperInfo info)
{
if (CurWipSNs.Any())
{
info.CurNode = CurWipSNs.First().NODE_NAME;
info.NextNode = string.Join(",", CurBatch.GetNextNodes(CurWipSNs.First()).Select(q => q.NODE_NAME));
}
else
{
info.CurNode = " — ";
info.NextNode = " — ";
}
return info;
}
///
/// 生成传入工步后续的行为到工步列表
///
///
public void GenerateSteps(WorkStep parent)
{
//递归添加所有工步
AddNextActToSteps(parent);
//调整工步的序号
//while (CurBatch.Edges.Any(q => Steps.First(s => s.NodeID == q.SRC_NODE).Sequence <= Steps.First(s => s.NodeID == q.TGT_NODE).Sequence))
//{
// var edges = CurBatch.Edges.Where(q => Steps.First(s => s.NodeID == q.SRC_NODE).Sequence >= Steps.First(s => s.NodeID == q.TGT_NODE).Sequence).ToList();
// foreach (var edge in edges)
// {
// var source = Steps.First(s => s.NodeID == edge.SRC_NODE);
// var target = Steps.First(s => s.NodeID == edge.TGT_NODE);
// target.Sequence = source.Sequence + 1;
// }
//}
}
///
/// 添加节点的下一个行为到工步列表
///
///
private void AddNextActToSteps(WorkStep parent)
{
var edges = CurBatch.Edges.Where(q => q.SRC_NODE == parent.NodeID && CurBatch.NodeActs.Any(a => a.NODE_ID == parent.Node.ID && a.ID == q.TGT_NODE)).ToList();
foreach (var edge in edges)
{
var act = CurBatch.NodeActs.First(q => q.ID == edge.TGT_NODE);
if (Steps.Any(q => q.NodeID == act.ID))
{
var next = Steps.First(q => q.NodeID == act.ID);
next.Sequence = next.Sequence > parent.Sequence ? next.Sequence : (parent.Sequence + 1);
next.PrepNodeIDs.Add(parent.NodeID);
next.PrepNodeIDs.AddRange(parent.PrepNodeIDs);
next.PrepNodeIDs = next.PrepNodeIDs.Distinct().ToList();
AddNextActToSteps(next);
}
else
{
var next = new WorkStep(IWorkStep.NodeTypes.Action, this)
{
Name = act.ACT_NAME,
Sequence = parent.Sequence + 1,
Node = parent.Node,
OperSetting = CurBatch.NodeSets.FirstOrDefault(q => q.NODE_ID == parent.Node.ID),
NodeAct = act,
ActSetting = CurBatch.ActionSets.FirstOrDefault(q => q.ACT_ID == act.ID),
};
next.Init();
next.PrepNodeIDs.Add(parent.NodeID);
next.PrepNodeIDs.AddRange(parent.PrepNodeIDs);
next.PrepNodeIDs = next.PrepNodeIDs.Distinct().ToList();
Steps.Add(next);
AddNextActToSteps(next);
}
}
}
///
/// 根据传入的工步,返回下一步可执行的工步列表
///
///
public List GetNextSteps(WorkStep curStep)
{
var result = new List();
var nextSteps = Steps.Where(q => !q.IsFinished
&& CurBatch.Edges.Any(e => e.SRC_NODE == curStep.NodeID && e.TGT_NODE == q.NodeID)
).ToList();
//尝试将当前工步的后续工步添加到可以执行的工步列表
foreach (var step in nextSteps)
{
//查找有没有前置工步未完成,若有则不允许继续执行
if (!Steps.Any(q => step.PrepNodeIDs.Any(id => id == q.NodeID && !q.IsFinished)))
{
result.Add(step);
}
}
//如果当前工步没有可执行的后续工步,则在前置工步查找还有没有后续工步没完成的工步,有则执行
if (!result.Any() && Steps.Any())
{
//查找有没有前置工步未完成,若有则先完成未完成的前置工步
var prepIDs = curStep.PrepNodeIDs.Where(id => CurBatch.Edges.Any(e => e.SRC_NODE == id && Steps.Any(q => !q.IsFinished && e.TGT_NODE == q.NodeID))).ToList();
var prepSteps = Steps.Where(q => prepIDs.Contains(q.NodeID)).OrderByDescending(q => q.Sequence).ToList();
while (prepSteps.Any() && !result.Any())
{
var prep = prepSteps.First();
var prepNext = GetNextSteps(prep);
if (prepNext.Any())
{
result = prepNext;
}
else
{
prepSteps.Remove(prep);
}
}
}
return result.OrderBy(q => q.NodeAct.ACT_NAME).ToList();
}
///
/// 开始执行下一行为工步
///
///
public ApiAction BeginNextActionStep(SubmitInput input)
{
var result = new ApiAction(new SubmitOutput());
//设置后续可执行的工步列表
NextSteps = GetNextSteps(CurStep);
//尝试有没有可以直接开始的后续工步
foreach (var step in NextSteps)
{
//尝试执行后续工步
var canBegin = step.TryBegin(input);
//如果后续工步可以直接开始则直接执行
if (canBegin.IsSuccessed)
{
//更新当前执行工步为已开始工步
CurStep = step;
//更新后续可执行的工步列表
NextSteps = GetNextSteps(CurStep);
//返回结果到客户端
result = canBegin;
result.Data.SetValue(CurBatch, CurStep, CurStep?.ID, IsFinishAllSteps);
return result;
}
}
//没有可以直接开始的后续工步,根据后续工步返回ApiAction
result.Data.SetValue(CurBatch, CurStep, "", IsFinishAllSteps);
//没有可以直接开始的后续工步,根据后续可执行工步列表返回相应的操作提示
if (NextSteps.Count == 1)
{
result.LocaleMsg = NextSteps.First().GetBeginMsg();
}
else
{
result.LocaleMsg = new(T(L("MES.Transaction.Position.PleaseSelectNextStep"), input.Locale) + "\r\n" +
string.Join("\r\n", NextSteps.Select(q => " >> " + T(q.GetBeginMsg(), input.Locale))));
}
return result;
}
///
/// 保存工步的数据库提交操作到数据库
///
protected void SaveStepsCommitActionToDB()
{
//保存工步的数据库提交操作到提交操作列表
var commitList = new List();
foreach (var step in Steps.OrderBy(q => q.Sequence))
{
commitList.Add(step.DBSubmitAction);
}
DBCommitList.Add(CurSN, commitList);
//如果不需要临时存储数据库提交操作,则把提交操作列表提交到数据库
if (!NeedTemporaryStoreDBCommitAction)
{
//恢复临时存储标记为false
NeedTemporaryStoreDBCommitAction = false;
var dbTran = GetCommitDB().UseTran(() =>
{
//在同一个事务中保存所有工步的数据
foreach (var wipSn in DBCommitList.Keys)
{
foreach (var action in DBCommitList[wipSn])
{
action.Invoke();
}
}
});
if (dbTran.IsSuccess)
{
//保存成功则清空提交操作列表
DBCommitList.Clear();
}
else
{
//抛出异常
throw dbTran.ErrorException;
}
}
}
protected void DoSaveToDB()
{
var dbTran = GetCommitDB().UseTran(() =>
{
//在同一个事务中保存所有工步的数据
foreach (var step in Steps.OrderBy(q => q.Sequence))
{
step.DBSubmitAction.Invoke();
}
});
if (!dbTran.IsSuccess)
{
//抛出异常
throw dbTran.ErrorException;
}
}
#region 打印专用方法
///
/// 获取打印标签模板过程变量值
///
/// 过程变量列表
/// 标签模板
///
public BAS_LABEL_TEMP SetLabelVariables(List labelPVs, BAS_LABEL_TEMP label, IWorkAction action)
{
foreach (var item in label.Variables)
{
switch (item.VAR_TYPE.GetEnum())
{
case BAS_LABEL_VAR.VAR_TYPEs.Constant:
item.Value = item.VAR_VALUE;
break;
case BAS_LABEL_VAR.VAR_TYPEs.ProcessVariable:
item.Value = GetPrintProcessValue(labelPVs, item, action);
break;
case BAS_LABEL_VAR.VAR_TYPEs.DateVariable:
item.Value = DateTime.Now.ToString(item.VAR_VALUE);
break;
case BAS_LABEL_VAR.VAR_TYPEs.BarcodeGenerate:
item.Value = GetGeneratePValue(labelPVs, item);
break;
case BAS_LABEL_VAR.VAR_TYPEs.CustomVariable:
default:
item.Value = "";
break;
}
}
return label;
}
///
/// 获取打印标签模板过程变量值
///
/// 过程变量列表
/// 标签模板变量
///
public string GetPrintProcessValue(List labelPVs, BAS_LABEL_VAR lv, IWorkAction action)
{
var pv = labelPVs.FirstOrDefault(q => q.VAR_CODE == lv.VAR_VALUE);
if (!pv.IsNullOrEmpty())
{
switch (pv.VAR_TYPE.GetEnum())
{
case BAS_LABEL_PV.VAR_TYPEs.ServerMethod:
{
switch (pv.VAR_METHOD)
{
case "GetSN":
return CurSN;
case "GetBAS_ITEM":
return WorkBatch.Product.ToJson();
case "GetCustomer":
return WorkBatch.Batch.ToJson();
case "GetVarByWo":
return GetLabelVarWo(lv);
default:
return "";
}
}
case BAS_LABEL_PV.VAR_TYPEs.WebApi:
break;
case BAS_LABEL_PV.VAR_TYPEs.StoredProcedure:
break;
default:
break;
}
}
return "";
}
///
/// 获取根据条码规则生成标签模板的过程变量值
///
///
///
///
public string GetGeneratePValue(List labelPVs, BAS_LABEL_VAR lv)
{
var pv = labelPVs.FirstOrDefault(q => q.VAR_CODE == lv.VAR_VALUE);
if (!pv.IsNullOrEmpty())
{
switch (pv.VAR_TYPE.GetEnum())
{
case BAS_LABEL_PV.VAR_TYPEs.BarcodeGenerate:
{
switch (pv.VAR_METHOD)
{
case "GetCartonGenerate":
return Biz.CodeRule[lv.BARCODE_RULE ?? ""]?.Generate($"{WorkBatch.Batch.BATCH_NO}-{WorkBatch.Batch.PLAN_QTY}-").Data.ToString() ?? "";
case "GetHW21SNGenerate":
return Biz.CodeRule[lv.BARCODE_RULE ?? ""]?.Generate("SN:","05").Data.ToString() ?? "";
default:
return "";
}
}
default:
break;
}
}
return "";
}
///
/// 获取工单维护的模板变量
///
///
///
private string GetLabelVarWo(BAS_LABEL_VAR lv)
{
string result = "";
var labelVarwos = Biz.Db.Queryable().Where(x => x.LABEL_ID == lv.LABEL_ID && x.VAR_NAME == lv.VAR_NAME).ToList();
if (labelVarwos.Any(q => q.WORK_ORDER == WorkBatch.Batch.ORDER_NO))
{
result = labelVarwos.First(q => q.WORK_ORDER == WorkBatch.Batch.ORDER_NO).VAR_VALUE;
}
else
{
result = labelVarwos.Count > 0 ? labelVarwos[0].DEFAULT_VALUE : "";
}
return result;
}
#endregion
#endregion Functions
public override bool Close(bool needSaveHistoryLog = false)
{
//needSaveHistoryLog = true;
//保存操作日志
this.IsFinished = true;
return IsFinished ? base.Close(needSaveHistoryLog) : IsFinished;
}
}//endClass
}