using iWareSql;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using iWareSql.DBModel;
using XiGang.Core.Model;
using iWareSql.DataAccess;
using iWareCommon.Common.Globle;
using System.Threading;
using iWareCommon.Utils;
using iWareModel;
using iWareCC.Common.Helper;
namespace iWareCC
{
///
/// 出库计划任务分解线程
///
public class OutPlanTaskDecompose
{
///
/// 处理【下发中】的出库计划任务
///
public static void HandlerIssuingTask()
{
var errMsg = "";
bool result;
while (true)
{
Thread.Sleep(2000);//休眠2秒
try
{
if (SystemValue.isAllowRuning_HandlerIssuingTask && SystemValue.isStartedModel)
{
//查询状态=下发中的出库计划
var queryState1 = (int)OutPlanStateEnum.下发中;
var queryState2 = (int)OutPlanStateEnum.部分下发;
List planList = null;
var isAllowDecomposePlanTask = false;
using (DbModel context = new DbModel())
{
planList = context.Plan_OutTask.Where(x => x.PlanState == queryState1 || x.PlanState == queryState2).ToList();
if (planList != null && planList.Count > 0)
{
//屏蔽,这样每次只处理3个,会导致赵通他们板链线ecu刷数据 【EditBy shaocx,2022-08-12】
/*
//首先验证下是否允许下发
isAllowDecomposePlanTask = IsAllowDecomposePlanTask(context, ref errMsg);
if (isAllowDecomposePlanTask == false)
{
SystemWarningMsg._lbl_Alert_HandlerIssuingTask = errMsg;
continue;//继续下一个循环
}
//*/
}
}
if (planList != null && planList.Count > 0)
{
foreach (var item in planList)
{
errMsg = "";//重置
using (DbModel mycontext = new DbModel())
{
//建议:一次只执行一个出库计划,只要有一个计划成功创建了任务,该循环就跳出,目的是解决出库计划时若下发5个任务中,若其中4号任务不齐套,在5号及以后出库时4号任务刚好齐套,则将4号任务作为最高优先级插队进行出库 【EditBy shaocx,2022-08-10】
result = SingleOutPlanTaskHandler(mycontext, item, ref errMsg);
Log4NetHelper.WriteInfoLog(LogType.OutPlanTask, "处理【下发中】的出库计划任务=>" + errMsg);
SystemWarningMsg._lbl_Alert_HandlerIssuingTask = errMsg + "[处理任务" + item.PlanNo + "]";
if (result == true)
{
break;//跳出循环,直接执行循环的下一个过程 【EditBy shaocx,2022-08-10】
}
}
}
}
}
}
catch (Exception ex)
{
SystemWarningMsg._lbl_Alert_HandlerIssuingTask = "出现异常:" + ex.Message;
Log4NetHelper.WriteErrorLog(LogType.CCWCFService, "HandlerIssuingTask出现异常:" + ex.Message, ex);
}
}
}
///
///
///
///
///
///
/// true:表示已经找到库存,并创建好了任务,false:表示没有找到库存
private static bool SingleOutPlanTaskHandler(DbModel context, Plan_OutTask outTask, ref string errMsg)
{
bool fun_Result = false;
//注意:这里必须重新获取下对象,因为前面的方法中DbModel是不一样的,不是一个上下文,修改不了数据 【EditBy shaocx,2022-07-28】
Plan_OutTask new_outTask = context.Plan_OutTask.Where(x => x.Id == outTask.Id).First();
errMsg = "";
var queryState1 = (int)OutTaskDetailStateEnum.等待中;
var queryState2 = (int)OutTaskDetailStateEnum.缺料;
var detaiList = context.Plan_OutTaskDetail.Where(x =>
(x.OutTaskDetailState == queryState1 || x.OutTaskDetailState == queryState2)
&& x.M_PlanId == new_outTask.Id)
.OrderBy(x => x.CreateTime)//按照创建时间升序 【EditBy shaocx,2022-08-10】
.ThenBy(x => x.PlanSequence)//其次按照顺序升序,主要是给 按照按订货号出库的出库顺序来的 【EditBy shaocx,2024-01-31】
.ToList();
if (detaiList != null && detaiList.Count > 0)
{
//建议:一次只执行一次出库任务
foreach (var item in detaiList)
{
var result = SingleOutPlanDetailTaskHandlerForVirtual(context, new_outTask, item, ref errMsg);
//var result = false;//暂时先屏蔽读取虚拟库存的数据
if (result == false)
{//表示没有找到虚拟库存,就再去查 真实库存
result = SingleOutPlanDetailTaskHandler(context, new_outTask, item, ref errMsg);
if (result == false)
{//表示没有找到实际库存
}
else
{//表示找到了实际库存,并成功创建了任务
fun_Result = true;
break;//成功后就跳出循环
}
}
else
{//表示找到了虚拟出库,并成功创建了任务
fun_Result = true;
break;//成功后就跳出循环
}
}
}
else
{
//不予处理
}
return fun_Result;
}
///
/// 单个处理出库计划明细-真实库存中处理
///
///
///
///
///
/// true:表示已经找到库存,并创建好了任务,false:表示没有找到库存
private static bool SingleOutPlanDetailTaskHandler(DbModel context, Plan_OutTask outTask, Plan_OutTaskDetail outDetailTask, ref string errMsg)
{
errMsg = "";
var remark = "消费下发中的任务";
//1、搜索库存是否存在
var queliaoReason = "";
var findStore = StoreHandler.FindStoreForOutPlan(context, outDetailTask, ref errMsg, ref queliaoReason);
if (findStore == null)
{//表示查找库存失败
//更新Plan_OutTaskDetail表的OperationRemark值
var changeOutTaskDetailState = OutTaskDetailStateEnum.缺料;
outDetailTask.OutTaskDetailState = (int)changeOutTaskDetailState;
outDetailTask.OutTaskDetailStateName = changeOutTaskDetailState.ToString();//更新 状态为缺料 [EditBy shaocx,2022-08-24]
outDetailTask.OperationRemark = SysGloble.QUELIAO_STR;
//赋值缺料原因 【Editby shaocx,2022-10-24】
outDetailTask.Remark = MyExtendHelper.GetQueliaoReason(outDetailTask.Remark, queliaoReason);
outDetailTask.ModifyTime = DateTime.Now;
outDetailTask.ModifyBy = SysGloble.WCSSystem;
//重要:!提前生成顺序号 [EditBy shaocx,2022-08-24]
string taskSequenceGuid = "";
outDetailTask.MainTaskSequence = MainTaskHandler.GenerateTaskSequence(context, ref taskSequenceGuid);
outDetailTask.TaskSequenceGuid = taskSequenceGuid;
context.SaveChanges();
Log4NetHelper.WriteInfoLog(LogType.OutPlanTask, errMsg);
return false;
}
else
{//查找到库存
#region 事务处理
string taskSequenceGuid = "";
int myTaskSequence = GetLastOutTaskDetailTaskSequenceForQueLiao(context, outDetailTask, ref taskSequenceGuid);
using (var trans = context.Database.BeginTransaction())
{
try
{
var sourcePlace = StationHandler.GetPlaceByPlaceId(findStore.StationId, context);
//2、锁定库存
StationHandler.SetPlaceLockStatus(true, SysGloble.WCSSystem, ref sourcePlace, remark);
StationHandler.SetPlaceTaskDoingStatus(true, SysGloble.WCSSystem, ref sourcePlace, remark);
//3、创建出库任务
FunRetEntity addOutStoreTaskResult = MainTaskHandler.AddOutStoreTask(outDetailTask, findStore, context, MainTaskTypeEnum.自动出库, new SysUser()
{
ID = 0,
Name = SysGloble.WCSSystem
}, sourcePlace, myTaskSequence, taskSequenceGuid);
if (addOutStoreTaskResult.result == false)
{
errMsg = addOutStoreTaskResult.resMsg;
throw new Exception(errMsg);
}
//4、更新出库明细表
var mainTask = addOutStoreTaskResult.resData as Task_Main;
if (mainTask == null)
{
errMsg = "新建的主任务对象为NULL";
throw new Exception(errMsg);
}
outDetailTask.TaskSequenceGuid = mainTask.TaskSequenceGuid;//重要!保存TaskSequenceGuid值 【EditBy shaocx,2022-08-25】
outDetailTask.OperationRemark = "设备任务已创建";//注意:这里的OperationRemark一定要更新,因为缺料的时候我更新了,缺料的查询也用到了 【EditBy shaocx,2022-04-29】
outDetailTask.MainTaskId = mainTask.Id;
outDetailTask.MainTaskNo = mainTask.TaskNo;
outDetailTask.SerialNumber = findStore.SerialNumber;//保存序列号
outDetailTask.OrderNo = findStore.OrderNo;
outDetailTask.MaterialId = findStore.MaterialId;//保存物料信息
var changeOutTaskDetailState = OutTaskDetailStateEnum.设备任务待执行;
PlanOutTaskHandler.UpdateStateForOutTaskDetail(outDetailTask, changeOutTaskDetailState, remark);
//5、更新出库主表
SetPlanStateForPlan_OutTask(context, outTask, changeOutTaskDetailState, remark);
//清理之前残留的缺料的信息 【Editby shaocx,2022-10-24】
outDetailTask.Remark = MyExtendHelper.CleareQueliaoReason(outDetailTask.Remark);
////更改任务主表为任务已分解
////更新主表的任务状态
//var _changeTaskState = MainTaskStatusEnum.出库任务已分解;
//mainTask.TaskState = (int)_changeTaskState;
//mainTask.TaskStateName = _changeTaskState.ToString();
//保存数据库
context.SaveChanges();
trans.Commit();
return true;//找到了库存,并处理成功了
}
catch (Exception ex)
{
trans.Rollback();
SystemWarningMsg._lbl_Alert_HandlerIssuingTask = "SingleOutPlanDetailTaskHandler出现异常:" + ex.Message;
Log4NetHelper.WriteErrorLog(LogType.CCWCFService, "SingleOutPlanDetailTaskHandler 出现异常:" + ex.Message, ex);
throw ex;
}
}
#endregion
}
}
///
/// 单个处理出库计划明细-虚拟库存中处理 [Editby shaocx,2022-07-28]
///
///
///
///
///
/// true:表示找到虚拟库存,并处理成功了,false表示没有找到虚拟库存
private static bool SingleOutPlanDetailTaskHandlerForVirtual(DbModel context, Plan_OutTask outTask, Plan_OutTaskDetail outDetailTask, ref string errMsg)
{
errMsg = "";
var remark = "消费下发中的任务";
//1、搜索库存是否存在
var findVirtualStore = StoreHandler.FindStoreForOutPlanByVirtual(context, outDetailTask, ref errMsg);
if (findVirtualStore == null)
{//表示查找库存失败
return false;//表示在虚拟库存中没有找到库存
}
else
{//查找到库存
#region 事务处理
using (var trans = context.Database.BeginTransaction())
{
try
{
//1、库存移除
context.Wms_VirtualStore.Remove(findVirtualStore);
//findVirtualStore.IsDeleted = true;
//findVirtualStore.ModifyBy = "";
//findVirtualStore.OperationRemark = remark + "[锁定库存]";
//findVirtualStore.ModifyTime = DateTime.Now;
//2、创建虚拟出库任务,注意:任务状态必须是已完成,因为是虚拟出库
FunRetEntity addOutStoreTaskResult = MainTaskHandler.AddOutStoreTaskForVirtual(outDetailTask, findVirtualStore, context, MainTaskTypeEnum.自动出库, new SysUser()
{
ID = 0,
Name = SysGloble.WCSSystem
});
if (addOutStoreTaskResult.result == false)
{
errMsg = addOutStoreTaskResult.resMsg;
throw new Exception(errMsg);
}
//4、更新出库明细表
var mainTask = addOutStoreTaskResult.resData as Task_Main;
if (mainTask == null)
{
errMsg = "新建的主任务对象为NULL";
throw new Exception(errMsg);
}
outDetailTask.OperationRemark = "设备任务已创建,并完成";//注意:这里的OperationRemark一定要更新,因为缺料的时候我更新了,缺料的查询也用到了 【EditBy shaocx,2022-04-29】
outDetailTask.MainTaskId = mainTask.Id;
outDetailTask.MainTaskNo = mainTask.TaskNo;
outDetailTask.SerialNumber = findVirtualStore.SerialNumber;//保存序列号
outDetailTask.OrderNo = findVirtualStore.OrderNo;
outDetailTask.MaterialId = findVirtualStore.MaterialId;//保存物料信息
var changeOutTaskDetailState = OutTaskDetailStateEnum.完成;//注意:要变成 已完成
PlanOutTaskHandler.UpdateStateForOutTaskDetail(outDetailTask, changeOutTaskDetailState, remark);
//5、更新出库主表
SetPlanStateForPlan_OutTask(context, outTask, changeOutTaskDetailState, remark);
//保存数据库
context.SaveChanges();
trans.Commit();
return true;
}
catch (Exception ex)
{
trans.Rollback();
SystemWarningMsg._lbl_Alert_HandlerIssuingTask = "SingleOutPlanDetailTaskHandler出现异常:" + ex.Message;
Log4NetHelper.WriteErrorLog(LogType.CCWCFService, "SingleOutPlanDetailTaskHandler 出现异常:" + ex.Message, ex);
throw ex;
}
}
#endregion
}
}
private static void SetPlanStateForPlan_OutTask(DbModel context, Plan_OutTask outTask, OutTaskDetailStateEnum currnetChange, string remark)
{
//计算数量
var queryState1 = (int)OutTaskDetailStateEnum.完成;
var queryState2 = (int)OutTaskDetailStateEnum.执行中;
var allPlanList = context.Plan_OutTaskDetail.Where(x => x.M_PlanId == outTask.Id).ToList();
outTask.Qty = allPlanList.Count;//重新赋值总数量
var issued_planList = allPlanList.Where(x => x.OutTaskDetailState == queryState1 || x.OutTaskDetailState == queryState2).ToList();
int issued_planListCount = issued_planList.Count();
if (currnetChange == OutTaskDetailStateEnum.完成 || currnetChange == OutTaskDetailStateEnum.执行中)
{
//计入本次要修改的条数
//是否这里不需要+1,待测试 【重要!!!!!】
//issued_planListCount += 1;
}
OutPlanStateEnum changeOutTaskDetailState;
if (outTask.Qty <= issued_planListCount)
{//更新主表状态为 全部下发
changeOutTaskDetailState = OutPlanStateEnum.全部下发;
PlanOutTaskHandler.UpdateStateForOutTask(outTask, changeOutTaskDetailState, remark);
//修改齐套性为已齐套 [EditBy shaocx,2022-05-16]
outTask.IsPickFinished = true;
//更新计划进度
outTask.PlanRate = 100;
outTask.Qty_Finish = outTask.Qty;
outTask.Qty_NoFinish = 0;
}
else if (issued_planListCount > 0)
{
changeOutTaskDetailState = OutPlanStateEnum.部分下发;
PlanOutTaskHandler.UpdateStateForOutTask(outTask, changeOutTaskDetailState, remark);
//更新计划进度
//outTask.PlanRate = (issued_planListCount / allPlanList.Count()) * 100;
outTask.PlanRate = CSharpHelper.ExecPercentRetInt(issued_planListCount, outTask.Qty);
outTask.Qty_Finish = issued_planListCount;
outTask.Qty_NoFinish = outTask.Qty - issued_planListCount;
}
}
///
/// 是否允许继续分解任务计划 [EditBy shaocx,2022-08-11]
///
///
///
private static bool IsAllowDecomposePlanTask(DbModel context, ref string errMsg)
{
var queryState1 = (int)MainTaskStatusEnum.待出库;
var queryState2 = (int)MainTaskStatusEnum.出库任务已分解;
var queryState3 = (int)MainTaskStatusEnum.出库中;
var queryMaterialType = (int)MaterialTypeEnum.一般物料;
var queryInOutFlag = (int)MainInOutFlagEnum.出库;
var mainList = context.Task_Main.Where(x => (x.TaskState == queryState1 || x.TaskState == queryState2 || x.TaskState == queryState3) && x.MaterialType == queryMaterialType
&& x.InOutFlag == queryInOutFlag).ToList();
if (mainList != null && mainList.Count >= 3)
{//为什么是3,考虑到 1012+2个出库口都有发动机的情况
errMsg = "目前已有" + mainList.Count + "条出库任务未结束,不允许继续分解任务计划";
return false;
}
return true;
}
///
/// 缺料的数据,插队处理
///
///
///
///
private static int GetLastOutTaskDetailTaskSequenceForQueLiao(DbModel context, Plan_OutTaskDetail planDetail, ref string taskSequenceGuid)
{
if (planDetail.OutTaskDetailState == (int)OutTaskDetailStateEnum.缺料)
{//如果是缺料的话,就需要 插队处理 【EditBy shaocx,2022-08-24】
//首先要判断当前同一个TaskSequenceGuid是否都做完了,如果都做完了,那么他就要排到第一位优先执行,如果还没做完,就按照原先的顺序来。
taskSequenceGuid = planDetail.TaskSequenceGuid;
bool isNeedChaDui = PlanOutTaskHandler.IsNeedChaDuiCommonTaskSequenceGuid(context, taskSequenceGuid);
if (isNeedChaDui)
{
return 1;//插队处理
}
return Convert.ToInt32(planDetail.MainTaskSequence);//按照原先的节奏顺序走
}
return 0;//正常排序
}
}
}