using Furion.DependencyInjection; using Furion.DistributedIDGenerator; using Furion.DynamicApiController; using Furion.FriendlyException; using Furion.JsonSerialization; using Google.Protobuf.Collections; using Mapster; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Myshipping.Application.Entity; using Myshipping.Core; using Myshipping.Core.Entity; using NPOI.OpenXmlFormats.Vml; using NPOI.SS.Formula.Functions; using NPOI.SS.Formula.PTG; using Org.BouncyCastle.Asn1.Tsp; using Org.BouncyCastle.Ocsp; using StackExchange.Profiling.Internal; using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Text; using System.Threading.Tasks; namespace Myshipping.Application { /// /// 服务流程管理 /// [AllowAnonymous, ApiDescriptionSettings("Application", Name = "ServiceWorkFlowManage", Order = 20)] public class ServiceWorkFlowManageService : IServiceWorkFlowManageService, IDynamicApiController, ITransient { private readonly ILogger _logger; private readonly SqlSugarRepository _serviceWorkFlowBaseRepository; private readonly SqlSugarRepository _serviceWorkFlowActivitiesInfoRepository; private readonly SqlSugarRepository _serviceWorkFlowProjectRelationRepository; private readonly SqlSugarRepository _serviceWorkFlowActivitiesRelationRepository; private readonly SqlSugarRepository _serviceWorkFlowActivitiesSubRelationRepository; private readonly SqlSugarRepository _serviceWorkFlowReleaseInfoRepository; private readonly SqlSugarRepository _serviceWorkFlowRunInfoRepository; private readonly SqlSugarRepository _serviceWorkFlowRunActivitiesInfoRepository; private readonly SqlSugarRepository _statusSkuBaseInfoRepository; private readonly SqlSugarRepository _sysUserRepository; private readonly SqlSugarRepository _serviceProjectBaseInfoRepository; private readonly SqlSugarRepository _serviceWorkFlowRunLogInfoRepository; private readonly ICache _cache; private readonly CacheOptions _cacheOptions; private readonly IServiceWorkFlowBaseService _serviceWorkFlowBaseService; const string CONST_CACHE_ENABLE_PROJECT = "service_project_list_enable"; const string CONST_CACHE_ENABLE_PROJECT_STATUS = "service_project_status_list_enable"; const string CONST_CACHE_ENABLE_STATUS = "service_status_list_enable"; public ServiceWorkFlowManageService(SqlSugarRepository serviceWorkFlowBaseRepository, ILogger logger, SqlSugarRepository serviceWorkFlowActivitiesInfoRepository, SqlSugarRepository serviceWorkFlowProjectRelationRepository, SqlSugarRepository serviceWorkFlowActivitiesRelationRepository, SqlSugarRepository serviceWorkFlowActivitiesSubRelationRepository, SqlSugarRepository serviceWorkFlowReleaseInfoRepository, SqlSugarRepository serviceWorkFlowRunInfoRepository, SqlSugarRepository serviceWorkFlowRunActivitiesInfoRepository, SqlSugarRepository statusSkuBaseInfoRepository, IServiceWorkFlowBaseService serviceWorkFlowBaseService, SqlSugarRepository sysUserRepository, SqlSugarRepository serviceProjectBaseInfoRepository, SqlSugarRepository serviceWorkFlowRunLogInfoRepository, IOptions cacheOptions, Func resolveNamed) { _serviceWorkFlowBaseRepository = serviceWorkFlowBaseRepository; _serviceWorkFlowActivitiesInfoRepository = serviceWorkFlowActivitiesInfoRepository; _serviceWorkFlowProjectRelationRepository = serviceWorkFlowProjectRelationRepository; _serviceWorkFlowActivitiesRelationRepository = serviceWorkFlowActivitiesRelationRepository; _logger = logger; _serviceWorkFlowActivitiesSubRelationRepository = serviceWorkFlowActivitiesSubRelationRepository; _serviceWorkFlowReleaseInfoRepository = serviceWorkFlowReleaseInfoRepository; _serviceWorkFlowRunInfoRepository = serviceWorkFlowRunInfoRepository; _serviceWorkFlowRunActivitiesInfoRepository = serviceWorkFlowRunActivitiesInfoRepository; _statusSkuBaseInfoRepository = statusSkuBaseInfoRepository; _serviceWorkFlowBaseService = serviceWorkFlowBaseService; _sysUserRepository = sysUserRepository; _serviceProjectBaseInfoRepository = serviceProjectBaseInfoRepository; _serviceWorkFlowRunLogInfoRepository = serviceWorkFlowRunLogInfoRepository; _cacheOptions = cacheOptions.Value; _cache = resolveNamed(_cacheOptions.CacheType.ToString(), default) as ICache; } #region 推送状态 /// /// 推送状态 /// /// 服务流程详情 /// 返回回执 [HttpPost("/ServiceWorkFlowManage/PushStatus")] public async Task PushStatus([FromBody] TrackingMessageInfo info) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); string batchNo = IDGen.NextID().ToString(); _logger.LogInformation("批次={no} 接收推送状态 msg={msg}", batchNo, JSON.Serialize(info)); try { /* 1、首先判断业务的主键,如果存在则需要提取所有主键下的服务流程活动,来更新。 2、状态可以批量处理。 */ if (info.Main == null) { _logger.LogInformation("批次={no} 接收推送状态错误 报文Main不能为空", batchNo); throw Oops.Oh($"报文Main不能为空", typeof(InvalidOperationException)); } if (string.IsNullOrWhiteSpace(info.Main.BusiSystemCode)) { _logger.LogInformation("批次={no} 接收推送状态错误 报文Main的业务系统代码不能为空", batchNo); throw Oops.Oh($"报文Main的业务系统代码不能为空", typeof(InvalidOperationException)); } if (string.IsNullOrWhiteSpace(info.Main.BusiId)) { _logger.LogInformation("批次={no} 接收推送状态错误 报文Main的业务主键不能为空", batchNo); throw Oops.Oh($"报文Main的业务主键不能为空", typeof(InvalidOperationException)); } if (info.Head != null && (string.IsNullOrWhiteSpace(info.Head.RequestAction) || !info.Head.RequestAction.Equals("AddOrModify",StringComparison.OrdinalIgnoreCase))) { _logger.LogInformation("批次={no} 报文Head的请求操作类型不能为空并且必需等于AddOrModify", batchNo); throw Oops.Oh($"报文Head的请求操作类型不能为空并且必需等于AddOrModify", typeof(InvalidOperationException)); } if (info.Main.StatusList == null || info.Main.StatusList.Count == 0) { _logger.LogInformation("批次={no} 接收推送状态错误 报文Main的状态列表不能为空,并且至少需要提供一个以上的状态信息", batchNo); throw Oops.Oh($"报文Main的状态列表不能为空,并且至少需要提供一个以上的状态信息", typeof(InvalidOperationException)); } //校验状态代码是否一致,不一致直接返回错误不允许推送 var statusArg = info.Main.StatusList.Select(a => a?.StatusCode.ToUpper()) .Where(a => !string.IsNullOrWhiteSpace(a)).Distinct().ToArray(); if (statusArg.Length == 0) { _logger.LogInformation("批次={no} 报文Main的状态列表至少需要提供一个以上的状态信息", batchNo); throw Oops.Oh($"报文Main的状态列表至少需要提供一个以上的状态信息", typeof(InvalidOperationException)); } UserTendDto userTendInfo = GetUserTendInfo(info.Main.RecvUserId); //检索状态对应所有的服务流程,如果已经提取到的状态数量与推送的不一致,提示错误不能入库s var skuList = _statusSkuBaseInfoRepository.AsQueryable().Filter(null, true) .LeftJoin((sts, act) => sts.PK_ID == act.STATUS_SKU_ID) .LeftJoin((sts,act,rela)=> act.PK_ID == rela.SERVICE_ACTIVITIES_ID) .LeftJoin((sts, act, rela,wf)=> rela.SERVICE_WORKFLOW_ID == wf.PK_ID && rela.WF_VERSION == wf.RELEASE_VERSION) .Where((sts, act) => statusArg.Contains(sts.STATUS_SKU_CODE) && !sts.IsDeleted && sts.IS_ENABLE == 1 && !act.IsDeleted) .Select((sts, act,rela,wf) => new { Sku = sts, Act = act, Rela = rela,WF = wf }).ToList(); //推送状态与已有状态进行匹配 var reqStatusList = info.Main.StatusList.GroupJoin(skuList, l => l.StatusCode, r => r.Sku.STATUS_SKU_CODE, (l, r) => { var currList = r.ToList(); if (currList.Count > 0) return new { Exists = true, Sku = currList.FirstOrDefault().Sku,Act = currList.FirstOrDefault().Act,Req = l }; return new { Exists = false, Sku = new StatusSkuBaseInfo(), Act = new ServiceWorkFlowActivitiesInfo(),Req = l }; }).ToList(); //如果有不存在的状态则提示无法入库 if (reqStatusList.Any(a => !a.Exists)) { var errList = reqStatusList.Where(a => !a.Exists) .Select(a => a.Req.StatusCode).ToArray(); string errMsg = $"以下状态不存在 {(string.Join(",", errList))} 不能入库"; _logger.LogInformation("批次={no} {msg}", batchNo, errMsg); throw Oops.Oh(errMsg, typeof(InvalidOperationException)); } //先从运行表按主键获取运行主表和活动表 var runList = _serviceWorkFlowRunInfoRepository.AsQueryable().Filter(null, true) .LeftJoin( (m, s) => m.PK_ID == s.RUN_ID) .Where((m, s) => m.BUSI_ID == info.Main.BusiId && m.BUSI_SYSTEM_CODE.Equals(info.Main.BusiSystemCode) && !m.IsDeleted && !s.IsDeleted) .Select((m, s) => new { main = m, sub = s }).ToList(); var wfList = skuList.Select(a => a.WF) .Distinct().ToList(); var checkList = wfList.GroupJoin(runList, l => l.PK_ID, r => r.main.SERVICE_WF_ID, (l, r) => { var currList = r.ToList(); if (currList.Count > 0) { return new { Exists = true, WF = l }; } return new { Exists = false, WF = l }; }).ToList(); if(checkList.Any(a=>a.Exists)) { reqStatusList.ForEach(async reqMd => { var currRun = runList.FirstOrDefault(x => x.sub.PK_ID == reqMd.Act.PK_ID); var currRunAct = currRun.sub; currRunAct.ACT_DATE = reqMd.Req.StatusDate; currRunAct.IS_YIELD = 1; await _serviceWorkFlowRunActivitiesInfoRepository.AsUpdateable(currRunAct).UpdateColumns(it => new { it.ACT_DATE, it.IS_YIELD, }).ExecuteCommandAsync(); }); } if (checkList.Any(a => !a.Exists)) { var noExistsList = checkList.Where(l => !l.Exists).Select(a=>a.WF.PK_ID).Distinct().ToList(); //状态关联的服务流程与运行表中的服务流程对应,对已经有的进行更新,对未进入运行表的进行写入 var actArg = reqStatusList.Select(a => a.Act.PK_ID).ToArray(); //根据服务流程活动获取所有相关的服务流程 var wfRlt = _serviceWorkFlowBaseService.GetServiceWorkFlowListByActivities(actArg).GetAwaiter().GetResult(); if (!wfRlt.succ) { string errMsg = $"获取服务流程失败,原因:{wfRlt.msg}"; _logger.LogInformation("批次={no} {msg}", batchNo, errMsg); throw Oops.Oh(errMsg, typeof(InvalidOperationException)); } var list = JSON.Deserialize>(JSON.Serialize(wfRlt.ext)); if(list.Count > 0) list = list.Where(a=> noExistsList.Contains( a.PKId)).ToList(); DateTime nowDate = DateTime.Now; list.ForEach(async wf => { ServiceWorkFlowRunInfo serviceWorkFlowRunInfo = new ServiceWorkFlowRunInfo { PK_ID = IDGen.NextID().ToString(), SERVICE_WF_ID = wf.PKId, BUSI_SYSTEM_CODE = info.Main.BusiSystemCode.ToUpper(), BUSI_ID = info.Main.BusiId.ToUpper(), MBL_NO = info.Main?.MBlNo.ToUpper(), VESSEL_VOYNO = info.Main?.VesselVoyno.ToUpper(), ORDER_NO = info.Main?.OrderNo, STATUS = TaskStatusEnum.Create.ToString(), RELEASE_VERSION = wf.ReleaseVersion, ACTIVITIES_NUM = wf.StatusNum, CreatedTime = nowDate, UpdatedTime = nowDate, CreatedUserId = userTendInfo.userId, CreatedUserName = userTendInfo.userName, TenantId = userTendInfo.tendId, TenantName = userTendInfo.tenantName, SERVICE_PROJECT_CODE = wf.ServiceProject.ServiceProjectCode, SERVICE_PROJECT_NAME = wf.ServiceProject.ServiceProjectName, }; await _serviceWorkFlowRunInfoRepository.InsertAsync(serviceWorkFlowRunInfo); int endNum = wf.StatusSkuList.Max(sku => sku.SortNo); string lastActId = string.Empty; wf.StatusSkuList.ForEach(async sku => { var currReq = reqStatusList.FirstOrDefault(x => x.Act.PK_ID == sku.PKId); ServiceWorkFlowRunActivitiesInfo activitiesRunInfo = new ServiceWorkFlowRunActivitiesInfo { PK_ID = IDGen.NextID().ToString(), RUN_ID = serviceWorkFlowRunInfo.PK_ID, EXEC_SORT_NO = sku.SortNo, IS_START = sku.SortNo == 1 ? 1 : 0, IS_END = sku.SortNo == endNum ? 1 : 0, ACT_ID = sku.PKId, STATUS_SKU_CODE = sku.statusSkuBase.StatusSKUCode, STATUS_SKU_ID = sku.StatusSKUId, SHOW_NAME = sku.ShowName, IS_SUB = 0, IS_SUB_JUST = 0, IS_YIELD = 0, CreatedTime = nowDate, UpdatedTime = nowDate, CreatedUserId = userTendInfo.userId, CreatedUserName = userTendInfo.userName, TenantId = userTendInfo.tendId, TenantName = userTendInfo.tenantName, IsDeleted = false, SOURCE_TYPE = "AUTO" }; if (currReq != null) { activitiesRunInfo.ACT_DATE = currReq.Req.StatusDate; activitiesRunInfo.ACT_VAL = currReq.Req.StatusVal; activitiesRunInfo.IS_YIELD = 1; } if (!string.IsNullOrWhiteSpace(lastActId)) activitiesRunInfo.NEXT_ACT_ID = lastActId; await _serviceWorkFlowRunActivitiesInfoRepository.InsertAsync(activitiesRunInfo); lastActId = activitiesRunInfo.PK_ID; if (sku.IsContainsSub == 1) { string lastSubActId = string.Empty; sku.SubList.ForEach(async sub => { var currSubReq = reqStatusList.FirstOrDefault(x => x.Act.PK_ID == sub.PKId); ServiceWorkFlowRunActivitiesInfo activitiesSubRunInfo = new ServiceWorkFlowRunActivitiesInfo { PK_ID = IDGen.NextID().ToString(), RUN_ID = serviceWorkFlowRunInfo.PK_ID, EXEC_SORT_NO = sub.SortNo, IS_START = sub.SortNo == 1 ? 1 : 0, IS_END = sub.SortNo == endNum ? 1 : 0, ACT_ID = sub.PKId, STATUS_SKU_CODE = sub.statusSkuBase.StatusSKUCode, STATUS_SKU_ID = sub.StatusSKUId, SHOW_NAME = sub.ShowName, IS_SUB = 1, IS_SUB_JUST = 1, IS_YIELD = 0, CreatedTime = nowDate, UpdatedTime = nowDate, CreatedUserId = userTendInfo.userId, CreatedUserName = userTendInfo.userName, TenantId = userTendInfo.tendId, TenantName = userTendInfo.tenantName, IsDeleted = false, SOURCE_TYPE = "AUTO", PARENT_ID = activitiesRunInfo.PK_ID }; if (currSubReq != null) { activitiesSubRunInfo.ACT_DATE = currSubReq.Req.StatusDate; activitiesSubRunInfo.ACT_VAL = currSubReq.Req.StatusVal; activitiesSubRunInfo.IS_YIELD = 1; } if (!string.IsNullOrWhiteSpace(lastSubActId)) activitiesSubRunInfo.NEXT_ACT_ID = lastSubActId; await _serviceWorkFlowRunActivitiesInfoRepository.InsertAsync(activitiesSubRunInfo); lastSubActId = activitiesSubRunInfo.PK_ID; }); } }); }); } result.succ = true; result.msg = "推送成功"; } catch (Exception ex) { result.succ = false; result.msg = $"推送状态失败,原因:{ex.Message}"; } return result; } #endregion #region 单票单服务项目查询 /// /// 单票单服务项目查询 /// /// 查询服务流程详情 /// 返回回执 [HttpPost("/ServiceWorkFlowManage/QuerySingleBusinessPerServiceProject")] public async Task QuerySingleBusinessPerServiceProject(TrackingQueryMessageInfo info) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); string batchNo = IDGen.NextID().ToString(); _logger.LogInformation("批次={no} 单票单服务项目查询 msg={msg}", batchNo, JSON.Serialize(info)); try { var runList = _serviceWorkFlowRunInfoRepository.AsQueryable().Filter(null, true) .LeftJoin((m, s) => m.PK_ID == s.RUN_ID) .LeftJoin((m, s, rela) => m.SERVICE_WF_ID == rela.SERVICE_WORKFLOW_ID && m.RELEASE_VERSION == rela.WF_VERSION) .LeftJoin((m, s, rela, p) => rela.SERVICE_PROJECT_ID == p.PK_ID) .Where((m, s, rela, p) => m.BUSI_SYSTEM_CODE == info.Main.BusiSystemCode && m.BUSI_ID == info.Main.BusiId && info.Main.ServiceProjectCodeList.Contains(p.SERVICE_PROJECT_CODE)) .Select((m, s) => new { Run = m, Sub = s }).ToList(); var resultList = runList.GroupBy(a=>a.Run.PK_ID) .Select(a => { var currList = a.ToList(); var runInfo = currList.FirstOrDefault().Run; var showModel = new ServiceWorkFlowRunDto(); showModel.PKId = runInfo.PK_ID; showModel.ServiceProjectCode = runInfo.SERVICE_PROJECT_CODE; showModel.ServiceProjectName = runInfo.SERVICE_PROJECT_NAME; showModel.ActivitiesList = currList.Where(t => t.Sub.IS_SUB == 0) .Select(t => { var runModel = new ServiceWorkFlowActivitiesRunDto { PKId = t.Sub.PK_ID, ActDate = t.Sub.ACT_DATE, ActId = t.Sub.ACT_ID, ExecSortNo = t.Sub.EXEC_SORT_NO, ActVal = t.Sub.ACT_VAL, IsStart = t.Sub.IS_START, IsEnd = t.Sub.IS_END, IsYield = t.Sub.IS_YIELD, RunId = t.Sub.RUN_ID, ShowName = t.Sub.SHOW_NAME, SourceType = t.Sub.SOURCE_TYPE, StatusSKUCode = t.Sub.STATUS_SKU_CODE, StatusSKUId = t.Sub.STATUS_SKU_ID }; return runModel; }).ToList(); var subList = currList.Where(t => t.Sub.IS_SUB == 1) .Select(t => t.Sub).ToList(); showModel.ActivitiesList = showModel.ActivitiesList.GroupJoin(subList, l => l.PKId, r => r.PARENT_ID, (l, r) => { var currList = r.ToList(); if (currList.Count > 0) { l.SubList = currList.Select(x => { var subModel = new ServiceWorkFlowActivitiesRunSubDto { PKId = x.PK_ID, ActDate = x.ACT_DATE, ActId = x.ACT_ID, ExecSortNo = x.EXEC_SORT_NO, ActVal = x.ACT_VAL, IsStart = x.IS_START, IsEnd = x.IS_END, IsYield = x.IS_YIELD, RunId = x.RUN_ID, ShowName = x.SHOW_NAME, SourceType = x.SOURCE_TYPE, StatusSKUCode = x.STATUS_SKU_CODE, StatusSKUId = x.STATUS_SKU_ID }; return subModel; }).OrderBy(x=>x.ExecSortNo).ToList(); } return l; }).OrderBy(t => t.ExecSortNo).ToList(); return showModel; }).ToList(); result.succ = true; result.ext = resultList; } catch (Exception ex) { result.succ = false; result.msg = $"单票单服务项目查询失败,原因:{ex.Message}"; } return result; } #endregion #region 单票所有相关服务项目查询 /// /// 单票所有相关服务项目查询 /// /// 查询服务流程详情 /// 返回回执 [HttpPost("/ServiceWorkFlowManage/QuerySingleBusinessAll")] public async Task QuerySingleBusinessAll(TrackingQueryMessageInfo info) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); string batchNo = IDGen.NextID().ToString(); _logger.LogInformation("批次={no} 单票所有相关服务项目查询 msg={msg}", batchNo, JSON.Serialize(info)); try { var runList = _serviceWorkFlowRunInfoRepository.AsQueryable().Filter(null, true) .LeftJoin((m, s) => m.PK_ID == s.RUN_ID) .Where((m, s) => m.BUSI_SYSTEM_CODE == info.Main.BusiSystemCode && m.BUSI_ID == info.Main.BusiId) .Select((m, s) => new { Run = m, Sub = s }).ToList(); var resultList = runList.GroupBy(a => a.Run.PK_ID) .Select(a => { var currList = a.ToList(); var runInfo = currList.FirstOrDefault().Run; var showModel = new ServiceWorkFlowRunDto(); showModel.PKId = runInfo.PK_ID; showModel.ServiceProjectCode = runInfo.SERVICE_PROJECT_CODE; showModel.ServiceProjectName = runInfo.SERVICE_PROJECT_NAME; showModel.ActivitiesList = currList.Where(t => t.Sub.IS_SUB == 0) .Select(t => { var runModel = new ServiceWorkFlowActivitiesRunDto { PKId = t.Sub.PK_ID, ActDate = t.Sub.ACT_DATE, ActId = t.Sub.ACT_ID, ExecSortNo = t.Sub.EXEC_SORT_NO, ActVal = t.Sub.ACT_VAL, IsStart = t.Sub.IS_START, IsEnd = t.Sub.IS_END, IsYield = t.Sub.IS_YIELD, RunId = t.Sub.RUN_ID, ShowName = t.Sub.SHOW_NAME, SourceType = t.Sub.SOURCE_TYPE, StatusSKUCode = t.Sub.STATUS_SKU_CODE, StatusSKUId = t.Sub.STATUS_SKU_ID }; return runModel; }).ToList(); var subList = currList.Where(t => t.Sub.IS_SUB == 1) .Select(t => t.Sub).ToList(); showModel.ActivitiesList = showModel.ActivitiesList.GroupJoin(subList, l => l.PKId, r => r.PARENT_ID, (l, r) => { var currList = r.ToList(); if (currList.Count > 0) { l.SubList = currList.Select(x => { var subModel = new ServiceWorkFlowActivitiesRunSubDto { PKId = x.PK_ID, ActDate = x.ACT_DATE, ActId = x.ACT_ID, ExecSortNo = x.EXEC_SORT_NO, ActVal = x.ACT_VAL, IsStart = x.IS_START, IsEnd = x.IS_END, IsYield = x.IS_YIELD, RunId = x.RUN_ID, ShowName = x.SHOW_NAME, SourceType = x.SOURCE_TYPE, StatusSKUCode = x.STATUS_SKU_CODE, StatusSKUId = x.STATUS_SKU_ID }; return subModel; }).OrderBy(x => x.ExecSortNo).ToList(); } return l; }).OrderBy(t => t.ExecSortNo).ToList(); return showModel; }).ToList(); result.succ = true; result.ext = resultList; } catch (Exception ex) { result.succ = false; result.msg = $"单票所有相关服务项目查询失败,原因:{ex.Message}"; } return result; } #endregion /// /// 取消状态 /// /// 服务流程报文详情 /// 返回回执 [HttpPost("/ServiceWorkFlowManage/CancelStatus")] public async Task CancelStatus(TrackingMessageInfo info) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); string batchNo = IDGen.NextID().ToString(); _logger.LogInformation("批次={no} 接收推送状态 msg={msg}", batchNo, JSON.Serialize(info)); try { /* 1、首先判断业务的主键,如果存在则需要提取所有主键下的服务流程活动,来更新。 2、状态可以批量处理。 */ if (info.Main == null) { _logger.LogInformation("批次={no} 接收推送状态错误 报文Main不能为空", batchNo); throw Oops.Oh($"报文Main不能为空", typeof(InvalidOperationException)); } if (string.IsNullOrWhiteSpace(info.Main.BusiSystemCode)) { _logger.LogInformation("批次={no} 接收推送状态错误 报文Main的业务系统代码不能为空", batchNo); throw Oops.Oh($"报文Main的业务系统代码不能为空", typeof(InvalidOperationException)); } if (string.IsNullOrWhiteSpace(info.Main.BusiId)) { _logger.LogInformation("批次={no} 接收推送状态错误 报文Main的业务主键不能为空", batchNo); throw Oops.Oh($"报文Main的业务主键不能为空", typeof(InvalidOperationException)); } if (info.Main.StatusList == null || info.Main.StatusList.Count == 0) { _logger.LogInformation("批次={no} 接收推送状态错误 报文Main的状态列表不能为空,并且至少需要提供一个以上的状态信息", batchNo); throw Oops.Oh($"报文Main的状态列表不能为空,并且至少需要提供一个以上的状态信息", typeof(InvalidOperationException)); } //校验状态代码是否一致,不一致直接返回错误不允许推送 var statusArg = info.Main.StatusList.Select(a => a?.StatusCode.ToUpper()) .Where(a => !string.IsNullOrWhiteSpace(a)).Distinct().ToArray(); if (statusArg.Length == 0) { _logger.LogInformation("批次={no} 报文Main的状态列表至少需要提供一个以上的状态信息", batchNo); throw Oops.Oh($"报文Main的状态列表至少需要提供一个以上的状态信息", typeof(InvalidOperationException)); } UserTendDto userTendInfo = GetUserTendInfo(info.Main.RecvUserId); //检索状态对应所有的服务流程,如果已经提取到的状态数量与推送的不一致,提示错误不能入库s var skuList = _statusSkuBaseInfoRepository.AsQueryable().Filter(null, true) .LeftJoin((sts, act) => sts.PK_ID == act.STATUS_SKU_ID) .LeftJoin((sts, act, rela) => act.PK_ID == rela.SERVICE_ACTIVITIES_ID) .LeftJoin((sts, act, rela, wf) => rela.SERVICE_WORKFLOW_ID == wf.PK_ID && rela.WF_VERSION == wf.RELEASE_VERSION) .Where((sts, act) => statusArg.Contains(sts.STATUS_SKU_CODE) && !sts.IsDeleted && sts.IS_ENABLE == 1 && !act.IsDeleted) .Select((sts, act, rela, wf) => new { Sku = sts, Act = act, Rela = rela, WF = wf }).ToList(); //推送状态与已有状态进行匹配 var reqStatusList = info.Main.StatusList.GroupJoin(skuList, l => l.StatusCode, r => r.Sku.STATUS_SKU_CODE, (l, r) => { var currList = r.ToList(); if (currList.Count > 0) return new { Exists = true, Sku = currList.FirstOrDefault().Sku, Act = currList.FirstOrDefault().Act, Req = l }; return new { Exists = false, Sku = new StatusSkuBaseInfo(), Act = new ServiceWorkFlowActivitiesInfo(), Req = l }; }).ToList(); //如果有不存在的状态则提示无法入库 if (reqStatusList.Any(a => !a.Exists)) { var errList = reqStatusList.Where(a => !a.Exists) .Select(a => a.Req.StatusCode).ToArray(); string errMsg = $"以下状态不存在 {(string.Join(",", errList))} 不能入库"; _logger.LogInformation("批次={no} {msg}", batchNo, errMsg); throw Oops.Oh(errMsg, typeof(InvalidOperationException)); } //先从运行表按主键获取运行主表和活动表 var runList = _serviceWorkFlowRunInfoRepository.AsQueryable().Filter(null, true) .LeftJoin( (m, s) => m.PK_ID == s.RUN_ID) .Where((m, s) => m.BUSI_ID == info.Main.BusiId && m.BUSI_SYSTEM_CODE.Equals(info.Main.BusiSystemCode) && !m.IsDeleted && !s.IsDeleted) .Select((m, s) => new { main = m, sub = s }).ToList(); var wfList = skuList.Select(a => a.WF) .Distinct().ToList(); var checkList = wfList.GroupJoin(runList, l => l.PK_ID, r => r.main.SERVICE_WF_ID, (l, r) => { var currList = r.ToList(); if (currList.Count > 0) { return new { Exists = true, WF = l }; } return new { Exists = false, WF = l }; }).ToList(); if (checkList.Any(a => a.Exists)) { reqStatusList.ForEach(async reqMd => { var currRun = runList.FirstOrDefault(x => x.sub.PK_ID == reqMd.Act.PK_ID); var currRunAct = currRun.sub; currRunAct.ACT_DATE = reqMd.Req.StatusDate; currRunAct.IS_YIELD = 1; await _serviceWorkFlowRunActivitiesInfoRepository.AsUpdateable(currRunAct).UpdateColumns(it => new { it.ACT_DATE, it.IS_YIELD, }).ExecuteCommandAsync(); }); } if (checkList.Any(a => !a.Exists)) { var noExistsList = checkList.Where(l => !l.Exists).Select(a => a.WF.PK_ID).Distinct().ToList(); //状态关联的服务流程与运行表中的服务流程对应,对已经有的进行更新,对未进入运行表的进行写入 var actArg = reqStatusList.Select(a => a.Act.PK_ID).ToArray(); //根据服务流程活动获取所有相关的服务流程 var wfRlt = _serviceWorkFlowBaseService.GetServiceWorkFlowListByActivities(actArg).GetAwaiter().GetResult(); if (!wfRlt.succ) { string errMsg = $"获取服务流程失败,原因:{wfRlt.msg}"; _logger.LogInformation("批次={no} {msg}", batchNo, errMsg); throw Oops.Oh(errMsg, typeof(InvalidOperationException)); } var list = JSON.Deserialize>(JSON.Serialize(wfRlt.ext)); if (list.Count > 0) list = list.Where(a => noExistsList.Contains(a.PKId)).ToList(); DateTime nowDate = DateTime.Now; list.ForEach(async wf => { ServiceWorkFlowRunInfo serviceWorkFlowRunInfo = new ServiceWorkFlowRunInfo { PK_ID = IDGen.NextID().ToString(), SERVICE_WF_ID = wf.PKId, BUSI_SYSTEM_CODE = info.Main.BusiSystemCode.ToUpper(), BUSI_ID = info.Main.BusiId.ToUpper(), MBL_NO = info.Main?.MBlNo.ToUpper(), VESSEL_VOYNO = info.Main?.VesselVoyno.ToUpper(), ORDER_NO = info.Main?.OrderNo, STATUS = TaskStatusEnum.Create.ToString(), RELEASE_VERSION = wf.ReleaseVersion, ACTIVITIES_NUM = wf.StatusNum, CreatedTime = nowDate, UpdatedTime = nowDate, CreatedUserId = userTendInfo.userId, CreatedUserName = userTendInfo.userName, TenantId = userTendInfo.tendId, TenantName = userTendInfo.tenantName, SERVICE_PROJECT_CODE = wf.ServiceProject.ServiceProjectCode, SERVICE_PROJECT_NAME = wf.ServiceProject.ServiceProjectName, }; await _serviceWorkFlowRunInfoRepository.InsertAsync(serviceWorkFlowRunInfo); int endNum = wf.StatusSkuList.Max(sku => sku.SortNo); string lastActId = string.Empty; wf.StatusSkuList.ForEach(async sku => { var currReq = reqStatusList.FirstOrDefault(x => x.Act.PK_ID == sku.PKId); ServiceWorkFlowRunActivitiesInfo activitiesRunInfo = new ServiceWorkFlowRunActivitiesInfo { PK_ID = IDGen.NextID().ToString(), RUN_ID = serviceWorkFlowRunInfo.PK_ID, EXEC_SORT_NO = sku.SortNo, IS_START = sku.SortNo == 1 ? 1 : 0, IS_END = sku.SortNo == endNum ? 1 : 0, ACT_ID = sku.PKId, STATUS_SKU_CODE = sku.statusSkuBase.StatusSKUCode, STATUS_SKU_ID = sku.StatusSKUId, SHOW_NAME = sku.ShowName, IS_SUB = 0, IS_SUB_JUST = 0, IS_YIELD = 0, CreatedTime = nowDate, UpdatedTime = nowDate, CreatedUserId = userTendInfo.userId, CreatedUserName = userTendInfo.userName, TenantId = userTendInfo.tendId, TenantName = userTendInfo.tenantName, IsDeleted = false, SOURCE_TYPE = "AUTO" }; if (currReq != null) { activitiesRunInfo.ACT_DATE = currReq.Req.StatusDate; activitiesRunInfo.ACT_VAL = currReq.Req.StatusVal; activitiesRunInfo.IS_YIELD = 1; } if (!string.IsNullOrWhiteSpace(lastActId)) activitiesRunInfo.NEXT_ACT_ID = lastActId; await _serviceWorkFlowRunActivitiesInfoRepository.InsertAsync(activitiesRunInfo); lastActId = activitiesRunInfo.PK_ID; if (sku.IsContainsSub == 1) { string lastSubActId = string.Empty; sku.SubList.ForEach(async sub => { var currSubReq = reqStatusList.FirstOrDefault(x => x.Act.PK_ID == sub.PKId); ServiceWorkFlowRunActivitiesInfo activitiesSubRunInfo = new ServiceWorkFlowRunActivitiesInfo { PK_ID = IDGen.NextID().ToString(), RUN_ID = serviceWorkFlowRunInfo.PK_ID, EXEC_SORT_NO = sub.SortNo, IS_START = sub.SortNo == 1 ? 1 : 0, IS_END = sub.SortNo == endNum ? 1 : 0, ACT_ID = sub.PKId, STATUS_SKU_CODE = sub.statusSkuBase.StatusSKUCode, STATUS_SKU_ID = sub.StatusSKUId, SHOW_NAME = sub.ShowName, IS_SUB = 1, IS_SUB_JUST = 1, IS_YIELD = 0, CreatedTime = nowDate, UpdatedTime = nowDate, CreatedUserId = userTendInfo.userId, CreatedUserName = userTendInfo.userName, TenantId = userTendInfo.tendId, TenantName = userTendInfo.tenantName, IsDeleted = false, SOURCE_TYPE = "AUTO", PARENT_ID = activitiesRunInfo.PK_ID }; if (currSubReq != null) { activitiesSubRunInfo.ACT_DATE = currSubReq.Req.StatusDate; activitiesSubRunInfo.ACT_VAL = currSubReq.Req.StatusVal; activitiesSubRunInfo.IS_YIELD = 1; } if (!string.IsNullOrWhiteSpace(lastSubActId)) activitiesSubRunInfo.NEXT_ACT_ID = lastSubActId; await _serviceWorkFlowRunActivitiesInfoRepository.InsertAsync(activitiesSubRunInfo); lastSubActId = activitiesSubRunInfo.PK_ID; }); } }); }); } result.succ = true; result.msg = "推送成功"; } catch (Exception ex) { result.succ = false; result.msg = $"推送状态失败,原因:{ex.Message}"; } return result; } #region 查询订舱表查询用户和租户信息 /// /// 查询订舱表查询用户和租户信息 /// /// 大简云用户ID /// 大简云用户邮箱 /// 返回用户和租户信息 private UserTendDto GetUserTendInfoByDJYUserId(string djyUserId, string djyUserEmail) { UserTendDto userTendDto = null; //这里因为接口是不做授权验证的,所以这里直接写的动态sql提取了用户和租户信息 var userTendInfo = _sysUserRepository.EntityContext.Queryable("user").AS("sys_user") .AddJoinInfo("sys_tenant", "ten", "user.TenantId=ten.Id") .Where("user.DjyUserId=@id and user.Email like '%" + djyUserEmail + "%'", new { id = djyUserId }) .Select("user.Id as UserId,user.Name as UserName,ten.Id as TendId,ten.Name as TendName").First(); if (userTendInfo == null || userTendInfo.TendId == null) throw Oops.Oh("当前用户详情获取失败,请确认{0}赋值是否准确", nameof(TaskManageOrderMessageInfo.Main.TaskUserId)); userTendDto = new UserTendDto { userId = long.Parse(userTendInfo.UserId.ToString()), userName = userTendInfo.UserName.ToString(), tendId = long.Parse(userTendInfo.TendId.ToString()), tenantName = userTendInfo.TendName.ToString() }; return userTendDto; } #endregion #region 查询订舱表查询用户和租户信息 /// /// 查询订舱表查询用户和租户信息 /// /// 用户ID /// 返回用户和租户信息 private UserTendDto GetUserTendInfo(string userId) { UserTendDto userTendDto = null; //这里因为接口是不做授权验证的,所以这里直接写的动态sql提取了用户和租户信息 var userTendInfo = _sysUserRepository.EntityContext.Queryable("user").AS("sys_user") .AddJoinInfo("sys_tenant", "ten", "user.TenantId=ten.Id") .Where("user.Id=@id", new { id = long.Parse(userId) }) .Select("user.Id as UserId,user.Name as UserName,ten.Id as TendId,ten.Name as TendName").First(); if (userTendInfo == null || userTendInfo.TendId == null) throw Oops.Oh("当前用户详情获取失败,请确认{0}赋值是否准确", nameof(TaskManageOrderMessageInfo.Main.TaskUserId)); userTendDto = new UserTendDto { userId = long.Parse(userTendInfo.UserId.ToString()), userName = userTendInfo.UserName.ToString(), tendId = long.Parse(userTendInfo.TendId.ToString()), tenantName = userTendInfo.TendName.ToString() }; return userTendDto; } #endregion /// /// 查询当前租户下可用服务项目与状态详情 /// /// 查询服务项目请求报文 /// 返回回执 [HttpPost("/ServiceWorkFlowManage/QueryServiceInfo")] public async Task QueryServiceInfo([FromBody] TrackingQueryMessageInfo info) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); string batchNo = IDGen.NextID().ToString(); _logger.LogInformation("批次={no} 查询当前租户下可用服务项目 msg={msg}", batchNo, JSON.Serialize(info)); try { /* 1、检索按照租户检索已经发布的服务流程。 2、根据枚举 info.Main.QueryType来判断返回哪些数据。 3、只返回服务项目。 4、只返回服务项目下的服务状态。 5、优先通过缓存获取结果。 */ if (info.Main.QueryType == TrackingQueryTypeEnum.QUERY_SERVICE_PROJECT) { var projectList = await _serviceWorkFlowBaseService.GetEnableProjectList(info.Main.TenantId); if (info.Main.QueryServiceProjectCode != null && info.Main.QueryServiceProjectCode.Length > 0) { result.ext = projectList.Where(a => info.Main.QueryServiceProjectCode.Contains(a.ServiceProjectCode)) .OrderBy(a => a.SortNo).ToList(); } else { result.ext = projectList; } } else if (info.Main.QueryType == TrackingQueryTypeEnum.QUERY_SERVICE_PROJECT_STATUS) { var statusList = await _serviceWorkFlowBaseService.GetEnableProjectList(info.Main.TenantId); if (info.Main.QueryServiceProjectCode != null && info.Main.QueryServiceProjectCode.Length > 0) { result.ext = statusList.Where(a => info.Main.QueryServiceProjectCode.Contains(a.ServiceProjectCode)) .OrderBy(a => a.SortNo).ToList(); } else { result.ext = statusList; } } result.succ = true; } catch (Exception ex) { result.succ = false; result.msg = $"查询服务项目失败,原因:{ex.Message}"; } return result; } } }