using Admin.Core.Common.Config; using Admin.Core.Common; using Admin.Core.IService; using Admin.Core.Model; using Admin.Core.Service; using log4net; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Aucma.Core.Scanner; using static Aucma.Core.Scanner.ScannerService; using Admin.Core.Model.Model_New; using Quartz; using StackExchange.Profiling.Internal; using Aucma.Core.HwPLc; using System.Windows.Documents; using System.Timers; using NetTaste; using Org.BouncyCastle.Asn1.Tsp; using System.Printing; namespace Aucma.Core.BoxFoam.Business { public class InStoreBusiness { #region 单例实现 private static readonly InStoreBusiness lazy = new InStoreBusiness(); public static InStoreBusiness Instance { get { return lazy; } } #endregion /// /// 已下传的任务信息 /// private List TaskInfos = new List(); private Dictionary KeyValuePairs = new Dictionary(); #region 事件 /// /// 扫码信息刷新 /// /// 条码 /// 编码 /// 名称 /// 货到名称 public delegate Task RefreshDataGridDelegate(); public static event RefreshDataGridDelegate RefreshDataGridDelegateEvent; /// /// 扫码信息刷新 /// /// 条码 /// 编码 /// 名称 /// 货到名称 public delegate void RefreshScanMateriaCode(string materialBarCode, string materialCode, string materialName, string spaceName, string msg); public static event RefreshScanMateriaCode RefreshScanMateriaCodeEvent; /// /// 初始化入库任务 /// /// public delegate void RefreshInStoreTask(RealTaskInfo taskInfos); public static event RefreshInStoreTask RefreshInStoreTaskEvent; /// /// 日志信息刷新 /// /// public delegate void RefreshLogMessage(string message); public static event RefreshLogMessage RefreshLogMessageEvent; /// /// 入库日志事件 /// /// public delegate void LogDelegate(string msg); public static event LogDelegate LogDelegateEvent; #endregion private static readonly log4net.ILog logHelper = LogManager.GetLogger(typeof(InStoreBusiness)); private readonly IBaseSpaceInfoServices? _baseSpaceInfoServices = App.ServiceProvider.GetService(); private readonly IRealTaskInfoServices? _realTaskInfoService = App.ServiceProvider.GetService(); private readonly IProductPlanInfoServices? _productPlanInfoServices = App.ServiceProvider.GetService(); private readonly IRecordInStoreServices? _recordInstoreServices = App.ServiceProvider.GetService(); private readonly IBaseStoreInfoServices? _baseStoreInfoServices = App.ServiceProvider.GetService(); private readonly IBaseSpaceDetailServices? _baseSpaceDetailServices = App.ServiceProvider.GetService(); // 过点数据表,物料完成记录MaterialCompletion private readonly IMaterialCompletionServices? _iMaterialCompletionServices = App.ServiceProvider.GetService(); private readonly IPrintBarCodeServices? _printBarCodeServices = App.ServiceProvider.GetService(); private PlcSpaceConfig spaceConfig = PlcSpaceConfig.Instance; private readonly IBaseMaterialInfoServices? _baseMaterialInfoServices = App.ServiceProvider.GetService(); private SemaphoreSlim semaphore = new SemaphoreSlim(0); private string storeCode = Appsettings.app("StoreInfo", "BeforeStoreCode");//泡前库code private List allSpaces = null; private List spaceAddresses = new List(); private SemaphoreSlim _lock = new SemaphoreSlim(1); public void init() { allSpaces = _baseSpaceInfoServices.Query(x => x.StoreCode == storeCode); foreach (var space in allSpaces) { spaceAddresses.Add(spaceConfig.GetSpaceAddress(storeCode, space.SpaceCode)); } // 模拟入库 //Task.Run(() => //{ // Thread.Sleep(2000); // InStore("B24010181060282920011"); //}); //实时监测入库任务下发和入库任务完成 StartPassDownAndRealInstoreFinish(); } /// /// 定时器实时监测入库出库完成信号 /// /// public void RealInstoreFinish() { var obj = PlcHelper.siemensList.FirstOrDefault(d => d.EquipName.Equals("泡前库Plc")); if (obj != null && obj.plc.IsConnected) { foreach (SpaceAddress spaceAddress in spaceAddresses) { // 入库完成信号 if (obj.plc.ReadInt16(spaceAddress.inStoreFinish) == 1) { obj.plc.WriteInt16(spaceAddress.inStoreFinish, "0"); InStoreFinish(spaceAddress.spaceCode); } // 出库完成信号, if (obj.plc.ReadInt16(spaceAddress.outStoreFinish) == 1) { obj.plc.WriteInt16(spaceAddress.outStoreFinish, "0"); // 系统不控制出库,暂时未使用出库完成信号 } } } } /// ///实时监测入库任务下发和入库任务完成 /// public async void StartPassDownAndRealInstoreFinish() { Task.Run(() => { Thread.Sleep(3000); while (true) { PassDown(); Thread.Sleep(1000); } }); Task.Run(() => { Thread.Sleep(3000); while (true) { RealInstoreFinish(); Thread.Sleep(1000); } }); } /// /// 获取入库任务下发plc /// /// /// public void PassDown() { try { RealTaskInfo taskInfo = GetAwaitSendTask(storeCode); if (taskInfo != null) { logHelper.Info($"下发泡前入库任务:{taskInfo.TaskCode};仓库{taskInfo.StoreCode};货道:{taskInfo.SpaceCode}"); LogDelegateEvent?.Invoke($"下发泡前入库任务:{taskInfo.TaskCode};仓库{taskInfo.StoreCode};货道:{taskInfo.SpaceCode},等待plc反馈"); if (SendFoamTask_InStore(taskInfo)) { logHelper.Info($"泡前入库任务:{taskInfo.TaskCode};下发成功,等待PLC执行反馈"); semaphore.Wait(); //一直堵塞直到信号量释放 logHelper.Info($"箱壳入库任务:{taskInfo.TaskCode};开始执行"); LogDelegateEvent?.Invoke($"箱壳入库任务:{taskInfo.TaskCode};开始执行"); taskInfo.TaskStatus = 2; _realTaskInfoService.UpdateAsync(taskInfo); #region 更新在途数 BaseSpaceInfo spaceInfo = _baseSpaceInfoServices.Query(x => x.StoreCode == taskInfo.StoreCode && x.SpaceCode == taskInfo.SpaceCode).FirstOrDefault(); spaceInfo.OnRouteAmount += 1; _baseSpaceInfoServices.UpdateSpaceInfo(spaceInfo); #endregion RefreshDataGridDelegateEvent?.Invoke();//刷新datagrid 列表 // logHelper.Info($"泡后入库任务:{taskInfo.TaskCode};执行完成"); // 刷新入库任务列表 } else { logHelper.Info($"泡后入库任务:{taskInfo.TaskCode};下发失败,请排除PLC连接"); } } else { logHelper.Info("未获取到需要下发的泡后入库任务"); } } catch (Exception ex) { logHelper.Info("下发任务异常"); } } /// /// 获取待执行的入库任务 /// /// /// private RealTaskInfo GetAwaitSendTask(string storeCode) { RealTaskInfo taskInfo = null; try { taskInfo = _realTaskInfoService.Query(x => x.StoreCode == storeCode && x.TaskType == 1 && x.TaskStatus == 1).OrderBy(x => x.CreateTime).FirstOrDefault(); } catch (Exception ex) { logHelper.Info("获取待执行的入库任务异常", ex); } return taskInfo; } #region 入库 /// /// 入库,扫码器委托触发 /// /// 仓库编号 /// 物料条码 public async Task InStore(string materialBarCode) { try { logHelper.Info($"扫码成功,物料条码:{materialBarCode}"); LogDelegateEvent?.Invoke($"扫码成功,物料条码:{materialBarCode}"); var taskList = await _realTaskInfoService.QueryAsync(d => d.MaterialCode.Equals(materialBarCode) && d.StoreCode == storeCode); if (taskList.Count() > 0) { LogDelegateEvent?.Invoke($"物料条码[{materialBarCode}],任务创建失败,该物料入库任务已存在!"); return; } string materialType = SubString(materialBarCode);//截取中间物料条码 BaseSpaceInfo spaceInfo = await GetSpaceInfoByMaterialType(storeCode, materialType); if (spaceInfo != null) { logHelper.Info($"匹配货道:{spaceInfo.ToJson()}"); LogDelegateEvent?.Invoke($"匹配货道:{spaceInfo.ToJson()}"); string message = $"箱体码[{materialBarCode}], 入{spaceInfo.SpaceName},入库中...."; PrintBarCode print = await _printBarCodeServices.FirstAsync(x => x.MaterialBarcode == materialBarCode); RefreshScanMateriaCodeEvent?.Invoke(materialBarCode, materialType, print.MaterialName, spaceInfo.SpaceName, message); //刷新界面扫码信息 var result = await CreateInStoreTask(spaceInfo, materialBarCode); //创建入库任务 if (result) { #region 更新过点数据 //MaterialCompletion completion = new MaterialCompletion(); //completion.OrderCode = print.OrderCode; //completion.MaterialBarcode = materialBarCode; //completion.MaterialCode = print.MaterialCode; //completion.MaterialName = print.MaterialName; //completion.StationName = "1003"; //completion.CompleteDate = DateTime.Now; //await _iMaterialCompletionServices.AddAsync(completion); #endregion RefreshDataGridDelegateEvent?.Invoke(); await _baseSpaceInfoServices.UpdateSpaceInfo(spaceInfo); } } else { //报警停线 } } catch (Exception ex) { logHelper.Error($"入库业务异常:{ex}"); } } #region 创建入库任务 /// /// 创建入库任务 /// /// private async Task CreateInStoreTask(BaseSpaceInfo spaceInfo, string materialCode) { bool result = false; try { //生成入库任务依次下发至PLC RealTaskInfo realTaskInfo = new RealTaskInfo(); realTaskInfo.TaskType = 1; realTaskInfo.TaskCode = System.Guid.NewGuid().ToString("N").Substring(0, 6); realTaskInfo.SpaceName = spaceInfo.SpaceName; realTaskInfo.StoreCode = spaceInfo.StoreCode; realTaskInfo.SpaceCode = spaceInfo.SpaceCode; realTaskInfo.MaterialType = spaceInfo.MaterialType; realTaskInfo.MaterialCode = materialCode; realTaskInfo.PlanAmount = 1; realTaskInfo.TaskStatus = 1; //任务状态:1 - 待执行;2 - 执行中;3 - 完成 realTaskInfo.CreateTime = DateTime.Now; int flag = await _realTaskInfoService.AddAsync(realTaskInfo); if (flag > 0) { logHelper.Info("入库任务创建成功"); LogDelegateEvent?.Invoke($"[{materialCode}]入库任务创建成功"); RefreshInStoreTaskEvent?.Invoke(realTaskInfo);//刷新datagrid 列表 result = true; } else { logHelper.Info("入库任务创建失败"); LogDelegateEvent?.Invoke($"[{materialCode}]入库任务创建失败"); result = false; } } catch (Exception ex) { logHelper.Info($"入库任务创建异常:{ex.Message}"); result = false; } return result; } #endregion /// 筛选货道 /// /// /// /// private async Task GetSpaceInfoByMaterialType(string storeCode, string materialType) { BaseSpaceInfo result = null; try { // List info = _spaceInfoService.GetBaseSpaceInfosByMaterialType(storeCode, materialType); List info = await _baseSpaceInfoServices.InStoreGetSpaceInfoByMaterialType(storeCode, materialType); if (info != null) { if (info.Count > 0) { foreach (BaseSpaceInfo item in info) { var spaceInfo = ReadSpaceInfoByPlc(item); item.SpaceStock = spaceInfo.SpaceStock; // item.OnRouteAmount = spaceInfo.OnRouteAmount; // item.SpaceStatus = spaceInfo.SpaceStatus; } info = info.Where(x => x.SpaceStatus == 1 && x.SpaceCapacity > (x.SpaceStock + x.OnRouteAmount)).ToList(); if(info.Count > 0) { result = info.OrderByDescending(x => x.SpaceStock).OrderBy(x => x.SpaceCode).First(); } } } } catch (Exception ex) { logHelper.Info("货道信息读取异常", ex); } return result; } /// /// 通过PLC获取货道信息 /// /// /// public BaseSpaceInfo ReadSpaceInfoByPlc(BaseSpaceInfo spaceInfo) { var obj = PlcHelper.siemensList.FirstOrDefault(d => d.EquipName.Equals("泡前库Plc")); if (obj != null && obj.plc.IsConnected) { SpaceAddress spaceAddress = spaceConfig.GetSpaceAddress(spaceInfo.StoreCode, spaceInfo.SpaceCode); spaceInfo.SpaceStock = obj.plc.ReadInt16(spaceAddress.onStore); // spaceInfo.OnRouteAmount = obj.plc.ReadInt32(spaceAddress.onRoute); // spaceInfo.SpaceStatus = obj.plc.ReadInt32(spaceAddress.spaceStatus); } return spaceInfo; } #endregion #region 截取物料编码 public string SubString(string barCode) { string result = string.Empty; if (!string.IsNullOrEmpty(barCode)) { result = barCode.Substring(7, 10); } return result; } #endregion #region 泡前入库任务下发处理 public bool SendFoamTask_InStore(RealTaskInfo taskInfo) { bool result = false; try { SpaceAddress spaceAddress = spaceConfig.GetSpaceAddress(storeCode, taskInfo.SpaceCode); var obj = PlcHelper.siemensList.FirstOrDefault(d => d.EquipName.Equals("泡前库Plc")); if (obj != null && obj.plc.IsConnected) { //写入应答字 obj.plc.WriteInt16("DB200.2", "1"); //写入货道物料类型 obj.plc.WriteString(spaceAddress.materialType, taskInfo.MaterialType); //写入货道号 obj.plc.WriteInt16("DB200.0", taskInfo.SpaceCode.Substring(7,1)); //写入完成后读取反馈号进行复位 ReadShellAnswer_InStore(taskInfo); result = true; } else { logHelper.Info($"仓库{taskInfo.StoreCode};PLC未连接"); } } catch (Exception ex) { logHelper.Error("泡后入库任务下发异常", ex); } return result; } /// /// 读取泡前入库应答 /// private void ReadShellAnswer_InStore(RealTaskInfo taskInfo) { lock (string.Empty) { bool isFlag = true; var obj = PlcHelper.siemensList.FirstOrDefault(d => d.EquipName.Equals("泡前库Plc")); try { Task.Run(() => { if (obj != null && obj.plc.IsConnected) { do { //读取PLC反馈号,上位机清空写入的入库内容 if (obj.plc.ReadInt16("DB200.86") == 2) { obj.plc.WriteInt16("DB200.86", "0"); //-------------plc清 //写入货道号 obj.plc.WriteInt16("DB200.0", "0"); // 写入应答字 obj.plc.WriteInt16("DB200.2", "0"); //写入货道物料类型 // obj.plc.WriteInt16(spaceAddress.materialType, taskInfo.MaterialType); //---------------------- isFlag = false; InStoreAnswer(taskInfo.TaskCode); // TaskInfos.Add(taskInfo); // ReadShellFinish_InStore(taskCode); } Thread.Sleep(500); } while (isFlag); } else { logHelper.Info("PLC未连接"); } }); } catch (Exception ex) { logHelper.Error("读取泡后入库应答字异常", ex); } } } /// /// 泡前库执行反馈 /// private void InStoreAnswer(string taskCode) { LogDelegateEvent?.Invoke($"泡前库应答成功,自动释放信号量,进行下发新任务"); logHelper.Info("泡前库应答成功,自动释放信号量,进行下发新任务"); // InStoreFinish(taskCode); semaphore.Release(); } #endregion /// /// 入库完成 /// /// /// /// private async void InStoreFinish(string spaceCode) { try { List tasks = await _realTaskInfoService.QueryAsync(x => x.StoreCode == storeCode && x.SpaceCode == spaceCode && x.TaskStatus == 2); RealTaskInfo taskInfo = tasks.OrderBy(x => x.CreateTime).FirstOrDefault(); if (taskInfo != null) { BaseSpaceInfo spaceInfo = await _baseSpaceInfoServices.GetSpaceInfoBySpaceCode(taskInfo.StoreCode, taskInfo.SpaceCode); if (spaceInfo != null) { spaceInfo.MaterialType = taskInfo.MaterialType; //读取PLC获取货道信息:存放数量、在途数量, #region Add By wenjy 2023-10-30 13:44:00 通过PLC获取货道信息 var item = ReadSpaceInfoByPlc(spaceInfo); spaceInfo.SpaceStock = item.SpaceStock; // 入库完成,在途减1 spaceInfo.OnRouteAmount -= 1; #endregion await _baseSpaceInfoServices.UpdateSpaceInfo(spaceInfo); #region 添加货道明细 不控制出库,暂时未添加明细 BaseSpaceDetail spaceDetail = new BaseSpaceDetail(); spaceDetail.MaterialType = taskInfo.MaterialType; spaceDetail.MaterialCode = taskInfo.MaterialCode; spaceDetail.MaterialName = await GetMaterialName(taskInfo.MaterialType); spaceDetail.StoreCode = spaceInfo.StoreCode; spaceDetail.SpaceCode = spaceInfo.SpaceCode; spaceDetail.MaterialAmount = 1; //await _baseSpaceDetailServices.InsertSpaceDetail(spaceDetail); #endregion #region 添加入库记录 RecordInStore recordInstore = new RecordInStore(); recordInstore.StoreCode = taskInfo.StoreCode; recordInstore.SpaceCode = taskInfo.SpaceCode; recordInstore.MaterialCode = taskInfo.MaterialCode; recordInstore.MaterialType = taskInfo.MaterialType; recordInstore.MaterialName = await GetMaterialName(taskInfo.MaterialType); recordInstore.InStoreAmount = 1; recordInstore.InStoreTime = DateTime.Now; recordInstore.BarCodeCode = taskInfo.MaterialCode; #endregion bool result = await _recordInstoreServices.SaveRecordToDb(recordInstore, taskInfo, spaceInfo, spaceDetail); if (result) { LogDelegateEvent?.Invoke($"入库完成,更新数据库成功"); } else { LogDelegateEvent?.Invoke($"更新数据库异常"); } } ////清除任务信息 //await _realTaskInfoService.DeleteTaskInfo(taskCode, storeCode); } } catch (Exception ex) { logHelper.Info("入库完成逻辑处理异常", ex); } } /// ///获取物料名称 /// /// /// public async Task GetMaterialName(string materialType) { string materialName = string.Empty; BaseMaterialInfo info = await _baseMaterialInfoServices.FirstAsync(x => x.MaterialType == materialType); if (info != null) { materialName = info.MaterialName; } return materialName; } #region PLC 任务处理表 /// /// PLC 任务处理表 /// /// 仓库编码 /// 物料编码 /// public async Task MaterialEnterStore(string storeCode, string materialBarCode = "B20231082080029650001") { //扫描入库信号,入库完成 try { var taskList = await _realTaskInfoService.QueryAsync(d => d.MaterialType.Equals(materialBarCode) && d.StoreCode == storeCode); if (taskList.Count() == 0) return; var obj = taskList.FirstOrDefault(); var mCode = materialBarCode.Substring(7, 10);//物料条码 //删除任务表、更新货道、添加入库明细、添加入库记录 var planInfoList = await _productPlanInfoServices.QueryAsync(d => d.MaterialCode.Equals(mCode));//计划 if (planInfoList.Count() == 0) { logHelper.Error($"物料计划信息为空!"); return; } var baseStoreInfolist = await _baseStoreInfoServices.QueryAsync(d => d.StoreCode.Equals(obj.StoreCode));//仓库 if (baseStoreInfolist.Count() == 0) { logHelper.Error($"仓库信息为空!"); return; } var baseSpacelist = await _baseSpaceInfoServices.QueryAsync(d => d.SpaceCode.Equals(obj.SpaceCode)); if (taskList.Count() == 0) { LogDelegateEvent?.Invoke($"物料[{materialBarCode}],入库记录条码重复异常!"); logHelper.Error($"货道信息为空!"); return; } var baseSpaceDetailList = await _baseSpaceDetailServices.QueryAsync(d => d.MaterialCode.Equals(obj.MaterialCode));//货到详情 if (baseSpaceDetailList.Count() != 0) { logHelper.Error($"货到信息存在重复物料!"); return; } var baseSpace = baseSpacelist.FirstOrDefault(); var planInfo = planInfoList.FirstOrDefault(); var baseStoreInfo = baseStoreInfolist.FirstOrDefault(); baseSpace.SpaceStock = baseSpace.SpaceStock + 1; baseSpace.OnRouteAmount = 0; //入库记录表 RecordInStore recordInstore = new RecordInStore(); recordInstore.StoreCode = storeCode; recordInstore.StoreArea = baseStoreInfo.StoreArea; recordInstore.SpaceCode = baseSpace.SpaceCode; recordInstore.MaterialType = baseSpace.MaterialType; recordInstore.MaterialCode = mCode; recordInstore.InStoreTime = DateTime.Now; recordInstore.BarCodeCode = materialBarCode; recordInstore.MaterialName = planInfo.MaterialName; recordInstore.EntryPattern = 0; recordInstore.IsFlag = 0; recordInstore.CreatedTime = DateTime.Now; //入库详情表 BaseSpaceDetail baseDetail = new BaseSpaceDetail(); baseDetail.StoreCode = storeCode; baseDetail.SpaceCode = baseSpace.SpaceCode; baseDetail.MaterialCode = materialBarCode; baseDetail.MaterialName = planInfo.MaterialName; baseDetail.MaterialAmount = 1; baseDetail.CreatedTime = DateTime.Now; bool result = await _recordInstoreServices.SaveRecordToDb(recordInstore, obj, baseSpace, baseDetail); if (result) { string message = $"物料[{planInfo.MaterialName}], 入{baseSpace.SpaceName},入库成功!"; RefreshScanMateriaCodeEvent?.Invoke(obj.MaterialCode, materialBarCode, planInfo.MaterialName, baseSpace.SpaceName, message); //刷新界面扫码信息 LogDelegateEvent?.Invoke($"物料[{planInfo.MaterialName}], 入库[{baseSpace.SpaceName}]成功!"); RefreshDataGridDelegateEvent?.Invoke(); } else { LogDelegateEvent?.Invoke($"物料[{planInfo.MaterialName}], 入库[{baseSpace.SpaceName}]失败,任务回滚!"); logHelper.Error($"物料[{planInfo.MaterialName}], 入库[{baseSpace.SpaceName}]失败,任务回滚!"); } } catch (Exception ex) { logHelper.Error($"入库数据处理异常:{ex.Message}"); } } #endregion } }