You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Aucma.Scada/Aucma.Scada.Business/OutStoreBusiness.cs

419 lines
16 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using HighWayIot.Config;
using HighWayIot.Log4net;
using HighWayIot.Repository.domain;
using HighWayIot.Repository.service;
using HighWayIot.Repository.service.Impl;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Aucma.Scada.Business
{
public class OutStoreBusiness
{
private static readonly Lazy<OutStoreBusiness> lazy = new Lazy<OutStoreBusiness>(() => new OutStoreBusiness());
public static OutStoreBusiness Instance
{
get
{
return lazy.Value;
}
}
private LogHelper logHelper = LogHelper.Instance;
private AppConfig appConfig = AppConfig.Instance;
private IBaseSpaceInfoService _spaceInfoService = new BaseSpaceInfoServiceImpl();
private IRealTaskInfoService _taskInfoService = new RealTaskInfoServiceImpl();
private IBaseBomInfoService _bomInfoService = new BaseBomInfoServiceImpl();
private IBaseSpaceDetailService _spaceDetailService = new BaseSpaceDetailServiceImpl();
private AssemblyPlanBusiness assemblyPlanBusiness = AssemblyPlanBusiness.Instance;
private TaskHandleBusiness taskHandleBusiness = TaskHandleBusiness.Instance;
private Semaphore m_SendTaskSem = new Semaphore(0, 100000);
/// <summary>
/// 初始化出库任务
/// </summary>
/// <param name="message"></param>
public delegate void RefreshOutStoreTask(RealTaskInfo taskInfos);
public event RefreshOutStoreTask RefreshOutStoreTaskEvent;
/// <summary>
/// 扫码信息刷新
/// </summary>
/// <param name="materialCode"></param>
/// <param name="materialName"></param>
/// <param name="spaceName"></param>
/// <param name="storeCode"></param>
public delegate void RefreshScanMateriaCode(string materialCode, string materialName, string spaceName, string storeCode);
public event RefreshScanMateriaCode RefreshScanMateriaCodeEvent;
/// <summary>
/// 日志信息刷新
/// </summary>
/// <param name="message"></param>
public delegate void RefreshLogMessage(string message);
public event RefreshLogMessage RefreshLogMessageEvent;
public OutStoreBusiness()
{
assemblyPlanBusiness.NextPassExecutePlanInfoEvent += PlanHandle;
Task.Run(() =>
{
StartTimerPassDown();
});
}
/// <summary>
/// 接收下达的组装计划根据BOM获取需要出库的箱壳、内胆物料信息
/// </summary>
/// <param name="planInfo"></param>
private void PlanHandle(ExecutePlanInfo planInfo)
{
lock (string.Empty)
{
Task.Run(() =>
{
if (planInfo != null)
{
string taskCode = DateTime.Now.ToString("HH:mm:ss");
var shellBomInfo = _bomInfoService.GetChildenBomInfoByMaterialCode(planInfo.materialCode, appConfig.shellMaterialType);
var linerBomInfo = _bomInfoService.GetChildenBomInfoByMaterialCode(planInfo.materialCode, appConfig.linerMaterialType);
for (int i = 0; i < planInfo.planAmount-planInfo.completeAmount; i++)
{
OutStore(appConfig.shellStoreCode, shellBomInfo, planInfo.executePlanCode, taskCode);
Thread.Sleep(500);
OutStore(appConfig.linerStoreCode, linerBomInfo, planInfo.executePlanCode, taskCode);
Thread.Sleep(500);
}
}
});
}
}
/// <summary>
/// 解析计划创建出库任务
/// </summary>
/// <param name="storeCode"></param>
/// <param name="bomInfo"></param>
/// <param name="planCode"></param>
private void OutStore(string storeCode, BaseBomInfo bomInfo,string planCode,string taskCode)
{
try
{
PrintLogInfoMessage($"收到出库计划,物料码:{bomInfo.materialCode}");
BaseSpaceInfo spaceInfo = _spaceInfoService.OutStoreGetSpaceInfoByMaterialCode(storeCode, bomInfo.materialCode);
if (spaceInfo != null)
{
PrintLogInfoMessage($"匹配货道:{spaceInfo.spaceName}");
// RefreshScanMateriaCodeEvent?.Invoke(materiaclCode, materialType, spaceInfo.spaceName, storeCode); //刷新界面扫码信息
CreateOutStoreTask(spaceInfo, planCode, taskCode); //创建出库任务
}
else
{
//报警停线
}
}
catch (Exception ex)
{
PrintLogErrorMessage("出库业务异常", ex);
}
}
/// <summary>
/// 创建出库任务
/// </summary>
/// <param name="spaceInfo"></param>
private bool CreateOutStoreTask(BaseSpaceInfo spaceInfo, string planCode,string taksCode,int taskModel=0)
{
bool result = false;
try
{
//获取出库的货道明细物料信息
BaseSpaceDetail spaceDetail = GetSpaceDetailFirstOrderByCreatTime(spaceInfo);
if (spaceDetail != null)
{
#region 出库任务赋值
RealTaskInfo realTaskInfo = new RealTaskInfo();
realTaskInfo.planCode = planCode;
realTaskInfo.taskType = 2;
realTaskInfo.taskCode = taksCode;
realTaskInfo.taskModel = taskModel;
realTaskInfo.storeCode = spaceInfo.storeCode;
realTaskInfo.spaceCode = spaceInfo.spaceCode;
realTaskInfo.spaceName = spaceInfo.spaceName;
realTaskInfo.materialType = spaceDetail.materialName;
realTaskInfo.materialCode = spaceDetail.materialCode;
realTaskInfo.planAmount = 1;
realTaskInfo.taskStatus = 1;
realTaskInfo.createTime = DateTime.Now;
#endregion
result = _taskInfoService.AddTaskInfo(realTaskInfo);
if (result)
{
PrintLogInfoMessage("出库任务创建成功");
RefreshOutStoreTaskEvent?.Invoke(realTaskInfo);
UpdateSpaceAndDetial(spaceInfo, spaceDetail);
}
else
{
PrintLogInfoMessage("出库任务创建失败");
}
}
}catch(Exception ex)
{
PrintLogErrorMessage("出库任务创建异常", ex);
}
return result;
}
/// <summary>
/// 根据创建时间获取第一个货道明细
/// </summary>
/// <param name="spaceInfo"></param>
/// <returns></returns>
private BaseSpaceDetail GetSpaceDetailFirstOrderByCreatTime(BaseSpaceInfo spaceInfo)
{
BaseSpaceDetail spaceDetail = null;
try
{
List<BaseSpaceDetail> spaceDetails = _spaceDetailService.GetSpaceDetailsBySpaceCode(spaceInfo.storeCode, spaceInfo.spaceCode);
if (spaceDetails.Count > 0)
{
spaceDetails = spaceDetails.Where(x => x.isFlag != 1).ToList();
if (spaceDetails != null)
{
spaceDetail = spaceDetails.OrderBy(x => x.createTime).First();
}
}
}catch(Exception ex)
{
PrintLogErrorMessage("获取货道明细信息异常", ex);
}
return spaceDetail;
}
/// <summary>
/// 任务创建完成后修改货道信息及货道明细
/// </summary>
/// <param name="spaceInfo"></param>
/// <param name="spaceDetail"></param>
private void UpdateSpaceAndDetial(BaseSpaceInfo spaceInfo,BaseSpaceDetail spaceDetail,int detailIsFlag = 1,bool stockFlag = true)
{
//任务创建完成后修改货道库存、货道明细修改物料标识物料不可用
spaceDetail.isFlag = detailIsFlag;
var result = _spaceDetailService.UpdateSpaceDetail(spaceDetail);
if (stockFlag)
{
spaceInfo.spaceStock = spaceInfo.spaceStock > 0 ? spaceInfo.spaceStock - 1 : 0;
}
else
{
spaceInfo.spaceStock = spaceInfo.spaceStock + 1;
}
_spaceInfoService.UpdateSpaceInfo(spaceInfo);
}
#region 开启定时获取出库任务下发至PLC等待PLC执行反馈完成后再次下发
private System.Timers.Timer timer = new System.Timers.Timer(5000);
private void StartTimerPassDown()
{
//try
//{
// if (!timer.Enabled)
// {
// timer.Elapsed += new System.Timers.ElapsedEventHandler(PassDownTaskInfoByTimer);
// timer.AutoReset = true;
// timer.Enabled = false;
// timer.Start();
// PrintLogInfoMessage("StartTimerPassDown(),开启定时获取出库任务进行下发");
// }
//}
//catch (Exception ex)
//{
// PrintLogErrorMessage("开启定时下发出库任务异常", ex);
//}
}
/// <summary>
/// 依次获取任务队列进行下发
/// object sender, System.Timers.ElapsedEventArgs e
/// </summary>
/// <param name="source"></param>
/// <param name="e"></param>
private bool PassDownTaskInfoByTimer()
{
List<RealTaskInfo> realTasks = new List<RealTaskInfo>();
RealTaskInfo shellTask = _taskInfoService.GetTaskInfoByStoreCode(appConfig.shellStoreCode, 2);
RealTaskInfo linerTaks = _taskInfoService.GetTaskInfoByStoreCode(appConfig.linerStoreCode, 2);
if(shellTask != null && linerTaks != null)
{
if (shellTask.taskStatus != 2 && linerTaks.taskStatus != 2)
{
shellTask.taskStatus = 2;
linerTaks.taskStatus = 2;
realTasks.Add(shellTask);
realTasks.Add(linerTaks);
bool result = _taskInfoService.UpdateRangeTaskInfo(realTasks);
if (result)
{
GetAllRelese(m_SendTaskSem);
foreach (var item in realTasks)
{
RefreshScanMateriaCodeEvent?.Invoke(item.materialCode, item.materialType, item.spaceName, item.storeCode);
taskHandleBusiness.SendOutStoreTask(item);
}
if (m_SendTaskSem.WaitOne(5000, false))
{
return true;
}
else
{
return false;
}
}
}
}
return false;
}
#endregion
/// <summary>
/// 出库完成
/// </summary>
/// <param name="storeCode"></param>
/// <param name="spaceCode"></param>
/// <param name="materialType"></param>
private void OutStoreFinish(string taskCode)
{
try
{
var taskInfo = _taskInfoService.GetTaskInfoByTaskCode(taskCode);
if (taskInfo != null)
{
var spaceInfo = _spaceInfoService.GetSpaceInfoBySpaceCode(taskInfo.storeCode, taskInfo.spaceCode);
if (spaceInfo != null)
{
//读取PLC获取货道信息存放数量、在途数量
//spaceInfo.materialType = taskInfo.materialType;
_spaceInfoService.UpdateSpaceInfo(spaceInfo);
//读取PLC获取物料类型进行绑定
}
//清除任务信息
_taskInfoService.DeleteTaskInfo(taskCode);
}
}
catch (Exception ex)
{
PrintLogErrorMessage("出库完成逻辑处理异常", ex);
}
}
/// <summary>
/// 获取出库任务
/// </summary>
/// <returns></returns>
public List<RealTaskInfo> GetOutStoreTask()
{
var taskInfos = _taskInfoService.GetTaskInfosByStoreCode(new string[] { appConfig.shellStoreCode, appConfig.linerStoreCode }, appConfig.outstoreTaskType);
return taskInfos;
}
/// <summary>
/// 通过任务编号删除任务
///
/// 任务删除后是否需要还原库存,如果出库完成后减少库存则不需要
///
/// </summary>
/// <param name="taskCode"></param>
/// <returns></returns>
public bool DeleteTaskInfoByTaskCode(string taskCode)
{
return _taskInfoService.DeleteTaskInfo(taskCode);
}
/// <summary>
/// 根据货道手动出一个
/// </summary>
/// <param name="storeCode"></param>
/// <param name="spaceCode"></param>
/// <returns></returns>
public bool OutOnlyOneBySpaceCode(string storeCode,string spaceCode)
{
bool result = false;
try
{
BaseSpaceInfo spaceInfo = _spaceInfoService.GetSpaceInfoBySpaceCode(storeCode, spaceCode);
if(spaceInfo.spaceStock > 0)
{
result = this.CreateOutStoreTask(spaceInfo, System.Guid.NewGuid().ToString("N"), DateTime.Now.ToString("HH:mm:ss"), 1);
}
else
{
PrintLogInfoMessage($"仓库:{storeCode};货道:{spaceCode};出一个失败:库存不足");
}
}catch(Exception ex)
{
logHelper.Error("根据货道出一个异常", ex);
}
return result;
}
/// <summary>
/// 日志输出,界面刷新同时记录文件
/// </summary>
/// <param name="message"></param>
private void PrintLogInfoMessage(string message)
{
RefreshLogMessageEvent?.Invoke(message);
logHelper.Info(message);
}
/// <summary>
/// 异常日志输出
/// </summary>
/// <param name="message"></param>
/// <param name="ex"></param>
private void PrintLogErrorMessage(string message, Exception ex = null)
{
RefreshLogMessageEvent?.Invoke(message);
logHelper.Error(message, ex);
}
private void GetAllRelese(Semaphore sph)
{
bool res = sph.WaitOne(1, false);
if (res)
{
// LogHelper.RfidLog("信号量手动释放");
GetAllRelese(sph);
}
}
}
}