cjy 3 months ago
commit f56bb58a64

@ -1,11 +1,11 @@
namespace DS.Module.Core.Condition
{
public class ContitionContent
public class ConditionContent
{
/// <summary>
/// 逻辑操作符
/// </summary>
public string LogicalOperator { get; set; }
public string LogicalOperator { get; set; } = "and";
/// <summary>
/// 条件组
@ -15,7 +15,7 @@
/// <summary>
/// 条件组
/// </summary>
public List<ContitionContent> Groups { get; set; }
public List<ConditionContent>? Groups { get; set; }
/// <summary>
/// 数据源名称

@ -1,5 +1,4 @@
using DS.Module.Core.Data;
using Fasterflect;
namespace DS.Module.Core.Condition
{
@ -8,7 +7,7 @@ namespace DS.Module.Core.Condition
/// <summary>
/// 根据ContitionContent条件从数据上下文TaskFlowDataContext中取出指定数据然后判断条件是否符合
/// </summary>
public static bool IsPass(ContitionContent conditionContent, TaskFlowDataContext dataContext)
public static bool IsPass(ConditionContent conditionContent, TaskFlowDataContext dataContext)
{
bool? thisScopeResult = null;
@ -18,7 +17,7 @@ namespace DS.Module.Core.Condition
}
IDictionary<string, object>? dataDic = null;
if (dataContext.ContainsKey(conditionContent.SourceName))
if (!string.IsNullOrEmpty(conditionContent.SourceName) && dataContext.ContainsKey(conditionContent.SourceName))
{
dataDic = dataContext[conditionContent.SourceName] as IDictionary<string, object>;
}
@ -28,10 +27,9 @@ namespace DS.Module.Core.Condition
var itemResult = false;
string? valStr = null;
if (dataDic != null)
if (dataDic != null && dataDic.TryGetValue(item.Field, out object? objVal))
{
var obj = dataDic[item.Field];
valStr = obj?.ToString();
valStr = objVal?.ToString();
}
else if (dataContext.ContainsKey(item.Field))
{

@ -226,9 +226,9 @@ namespace DS.Module.Core
[Description("处理Draft")]
WAIT_DRAFT = 207,
/// <summary>
///
///
/// </summary>
[Description("单")]
[Description("单")]
WAIT_CHECKOUT_BILL = 208,
/// <summary>
/// 退舱
@ -286,7 +286,7 @@ namespace DS.Module.Core
/// <summary>
/// 报商检
/// </summary>
[Description("商检")]
[Description("商检")]
WAIT_SHANGJIAN = 308,
/// <summary>
/// 报COA
@ -304,10 +304,10 @@ namespace DS.Module.Core
[Description("拖车")]
WAIT_TUOCHE = 311,
/// <summary>
/// 保险
/// 保险
/// </summary>
[Description("保险")]
WAIT_Insurance = 312,
[Description("保险")]
WAIT_INSURANCE = 312,
/// <summary>
/// 出号
/// </summary>
@ -319,9 +319,9 @@ namespace DS.Module.Core
[Description("内点入货")]
WAIT_NDRH = 314,
/// <summary>
/// 快递
/// 快递
/// </summary>
[Description("快递")]
[Description("快递")]
WAIT_DELIVERY = 315,
/// <summary>
/// 箱使

@ -437,12 +437,12 @@ public class FlowInstanceService : ServiceBase, IFlowInstanceService
#endregion 或签
int nextNodeType = runtime.GetNextNodeType();
var serializerSettings = new JsonSerializerSettings
{
// 设置为驼峰命名
ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver()
};
instance.Content = JsonConvert.SerializeObject(runtime.ToFlowRoot(), Formatting.None, serializerSettings);
//var serializerSettings = new JsonSerializerSettings
//{
// // 设置为驼峰命名
// ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver()
//};
//instance.Content = JsonConvert.SerializeObject(runtime.ToFlowRoot(), Formatting.None, serializerSettings);
instance.Note = auditNote;
Db.Updateable(instance).ExecuteCommand();

@ -1,4 +1,5 @@
using System.Runtime.Serialization;
using System.ComponentModel.DataAnnotations;
using System.Runtime.Serialization;
using DS.Module.Core;
using DS.WMS.Core.Fee.Dtos;
@ -7,7 +8,7 @@ namespace DS.WMS.Core.Op.Dtos.TaskInteraction
/// <summary>
/// 任务审核请求
/// </summary>
public class TaskAuditRequest : AuditRequest
public class TaskAuditRequest : AuditRequest, IValidatableObject
{
/// <summary>
/// 任务类型名称
@ -19,5 +20,22 @@ namespace DS.WMS.Core.Op.Dtos.TaskInteraction
/// </summary>
[IgnoreDataMember]
public TaskBaseTypeEnum TaskType => string.IsNullOrEmpty(TaskTypeName) ? TaskBaseTypeEnum.NOT_SPECIFIED : Enum.Parse<TaskBaseTypeEnum>(TaskTypeName);
/// <summary>
/// 确定当前对象是否有效
/// </summary>
/// <param name="validationContext">验证上下文</param>
/// <returns></returns>
public virtual IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (string.IsNullOrEmpty(TaskTypeName))
{
yield return new ValidationResult($"参数 {nameof(TaskTypeName)} 不能为空");
}
else if (!Enum.TryParse(TaskTypeName, out TaskBaseTypeEnum taskType))
{
yield return new ValidationResult($"参数 {nameof(TaskTypeName)} 值不在有效枚举范围之内");
}
}
}
}

@ -49,7 +49,7 @@ namespace DS.WMS.Core.Op.Dtos.TaskInteraction
}
else if (!Enum.TryParse(TaskTypeName, out TaskBaseTypeEnum taskType))
{
yield return new ValidationResult($"参数 {nameof(TaskTypeName)} 值无效");
yield return new ValidationResult($"参数 {nameof(TaskTypeName)} 值不在有效枚举范围之内");
}
}
}

@ -1,5 +1,4 @@
using DS.Module.Core;
using DS.Module.Core.Data;
using DS.Module.Core.Extensions;
using SqlSugar;
@ -83,5 +82,11 @@ namespace DS.WMS.Core.Op.Entity.TaskInteraction
/// </summary>
[SugarColumn(ColumnDescription = "审批驳回理由", Length = 200, IsNullable = true)]
public string? RejectReason { get; set; }
/// <summary>
/// 下一任务配置ID
/// </summary>
[SugarColumn(ColumnDescription = "下一任务配置ID", IsNullable = true)]
public long? NextId { get; set; }
}
}

@ -1,5 +1,7 @@
using DS.Module.Core;
using DS.Module.Core.Condition;
using DS.Module.Core.Data;
using DS.WMS.Core.Op.Dtos.TaskInteraction;
using DS.WMS.Core.Op.Entity;
using DS.WMS.Core.Op.Entity.TaskInteraction;
@ -10,6 +12,23 @@ namespace DS.WMS.Core.Op.Interface.TaskInteraction
/// </summary>
public interface IActionManagerService
{
/// <summary>
/// 根据指定条件返回是否匹配的结果
/// </summary>
/// <param name="request">任务请求</param>
/// <param name="conditions">匹配条件</param>
/// <returns></returns>
Task<bool> IsMatchAsync(TaskRequest request, IEnumerable<ConditionContent> conditions);
/// <summary>
/// 获取所需业务数据
/// </summary>
/// <param name="businessId">业务ID</param>
/// <param name="businessType">业务类型</param>
/// <param name="conditions">条件字段</param>
/// <returns></returns>
Task<dynamic?> GetBusinessDataAsync(long businessId, BusinessType businessType, IEnumerable<ConditionContent> conditions);
/// <summary>
/// 获取所需业务数据
/// </summary>
@ -17,7 +36,7 @@ namespace DS.WMS.Core.Op.Interface.TaskInteraction
/// <param name="businessType">业务类型</param>
/// <param name="fields">返回字段列表</param>
/// <returns></returns>
dynamic? GetBusinessData(long businessId, BusinessType businessType, params string[] fields);
Task<dynamic?> GetBusinessDataAsync(long businessId, BusinessType businessType, params string[] fields);
/// <summary>
/// 执行特定动作

@ -4,8 +4,11 @@ using DS.WMS.Core.Op.Interface.TaskInteraction;
using Masuit.Tools.Systems;
using Microsoft.Extensions.DependencyInjection;
namespace DS.WMS.Core.Op.Method.TaskInteraction.ActionExecutor
namespace DS.WMS.Core.Op.Method.TaskInteraction.ActionExecutor.Booking
{
/// <summary>
/// 订舱动作
/// </summary>
public class BookingActionExecutor : DefaultActionExecutor
{
internal const TaskBaseTypeEnum Booking_TaskType = TaskBaseTypeEnum.WAIT_BOOKING;

@ -4,7 +4,7 @@ using DS.WMS.Core.Op.Interface;
using Masuit.Tools.Systems;
using Microsoft.Extensions.DependencyInjection;
namespace DS.WMS.Core.Op.Method.TaskInteraction.ActionExecutor
namespace DS.WMS.Core.Op.Method.TaskInteraction.ActionExecutor.Booking
{
/// <summary>
/// 用于发送EDI的执行器

@ -6,7 +6,7 @@ using Masuit.Tools.Systems;
using Microsoft.Extensions.DependencyInjection;
using SqlSugar;
namespace DS.WMS.Core.Op.Method.TaskInteraction.ActionExecutor
namespace DS.WMS.Core.Op.Method.TaskInteraction.ActionExecutor.Booking
{
/// <summary>
/// 用于邮件发送的执行器
@ -31,7 +31,7 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction.ActionExecutor
var taskMailService = context.ServiceProvider.GetRequiredService<ITaskMailService>();
MailService mailService = new(context.ServiceProvider);
BusinessTaskMail? mailConfig = null;
if (context.AdditionalData.TryGetValue(nameof(BusinessTaskMail.Id), out var id))
if (context.AdditionalData.TryGetValue(nameof(BusinessTaskMail) + "." + nameof(BusinessTaskMail.Id), out var id))
{
if (id == null)
{
@ -41,7 +41,7 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction.ActionExecutor
var idVal = (long)Convert.ChangeType(id, typeof(long));
mailConfig = (await taskMailService.GetAsync(idVal)).Data;
}
else if (context.AdditionalData.TryGetValue(nameof(BusinessTaskMail.Name), out var name))
else if (context.AdditionalData.TryGetValue(nameof(BusinessTaskMail) + "." + nameof(BusinessTaskMail.Name), out var name))
{
var mailName = name as string;
if (mailName.IsNullOrEmpty())

@ -4,6 +4,9 @@ using DS.WMS.Core.Op.Interface.TaskInteraction;
namespace DS.WMS.Core.Op.Method.TaskInteraction.ActionExecutor
{
/// <summary>
/// 默认动作执行器
/// </summary>
public class DefaultActionExecutor : IActionExecutor
{
internal static readonly ApiFox Api;
@ -13,6 +16,11 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction.ActionExecutor
Api = new ApiFox();
}
/// <summary>
/// 执行空的动作
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public virtual Task ExecuteAsync(ActionExecutionContext context)
{
return Task.CompletedTask;

@ -0,0 +1,91 @@
using System.ComponentModel;
using DS.WMS.Core.Op.Dtos.TaskInteraction;
using DS.WMS.Core.Op.Entity.TaskInteraction;
using DS.WMS.Core.Op.Interface;
using DS.WMS.Core.Op.Interface.TaskInteraction;
using Microsoft.Extensions.DependencyInjection;
namespace DS.WMS.Core.Op.Method.TaskInteraction.ActionExecutor.SpaceRelease
{
/// <summary>
/// 放舱动作
/// </summary>
public class SpaceReleaseActionExecutor : DefaultActionExecutor
{
public override async Task ExecuteAsync(ActionExecutionContext context)
{
if (!context.AdditionalData.TryGetValue("ActionType", out object? val))
return;
SpaceReleaseActionType actionType = (SpaceReleaseActionType)Convert.ChangeType(val, typeof(int));
if (actionType == SpaceReleaseActionType.None)
return;
var opService = context.ServiceProvider.GetRequiredService<ISeaExportService>();
var logService = context.ServiceProvider.GetRequiredService<ITaskLogService>();
if (actionType.HasFlag(SpaceReleaseActionType.ShippingOrder))
await SendShippingOrderAsync(opService, logService, context.TaskInfo);
}
//下货纸
internal async Task SendShippingOrderAsync(ISeaExportService opService, ITaskLogService logService, BusinessTask task)
{
var result = await opService.SendXHZ(task.BusinessId.ToString());
if (!result.Succeeded)
{
await logService.WriteLogAsync(task, "发送下货纸失败:" + result.Message);
}
}
//入货通知
internal async Task SendIncomingNotification(IOpBusinessYardService opService, ITaskLogService logService, BusinessTask task)
{
var result = opService.GetBusinessYardByKeyId(task.BusinessId.ToString());
if (!result.Succeeded)
{
await logService.WriteLogAsync(task, "获取入货通知数据源失败:" + result.Message);
return;
}
}
////转发BC
//internal async Task RelayBC(ISeaExportService opService, ITaskLogService logService, BusinessTask task)
//{
//}
}
/// <summary>
/// 放舱动作类型
/// </summary>
[Flags]
public enum SpaceReleaseActionType
{
/// <summary>
/// 未设置
/// </summary>
None = 0,
/// <summary>
/// 下货纸
/// </summary>
[Description("下货纸")]
ShippingOrder = 1 << 0,
/// <summary>
/// 入货通知
/// </summary>
[Description("入货通知")]
IncomingNotification = 1 << 1,
/// <summary>
/// 转发BC
/// </summary>
[Description("船东BC")]
RelayBC = 1 << 2
}
}

@ -1,15 +1,16 @@
using DS.Module.Core;
using DS.Module.Core.Condition;
using DS.Module.Core.Data;
using DS.WMS.Core.Op.Dtos.TaskInteraction;
using DS.WMS.Core.Op.Entity;
using DS.WMS.Core.Op.Entity.TaskInteraction;
using DS.WMS.Core.Op.Interface;
using DS.WMS.Core.Op.Interface.TaskInteraction;
using DS.WMS.Core.TaskPlat;
using Masuit.Tools;
using SqlSugar;
using Fasterflect;
using Masuit.Tools;
using Microsoft.Extensions.DependencyInjection;
using DS.WMS.Core.Op.Entity;
using DS.WMS.Core.Op.Interface;
using SqlSugar;
namespace DS.WMS.Core.Op.Method.TaskInteraction
{
@ -18,11 +19,79 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
/// </summary>
public class ActionManagerService : ServiceBase, IActionManagerService
{
ITaskLogService LogService;
/// <summary>
/// 初始化
/// </summary>
public ActionManagerService(IServiceProvider serviceProvider) : base(serviceProvider)
{
LogService = serviceProvider.GetRequiredService<ITaskLogService>();
}
/// <summary>
/// 根据指定条件返回是否匹配的结果
/// </summary>
/// <param name="request">任务请求</param>
/// <param name="conditions">匹配条件</param>
/// <returns></returns>
public async Task<bool> IsMatchAsync(TaskRequest request, IEnumerable<ConditionContent> conditions)
{
ArgumentNullException.ThrowIfNull(request, nameof(request));
ArgumentNullException.ThrowIfNull(conditions, nameof(conditions));
var biz = await GetBusinessDataAsync(request.BusinessId, request.BusinessType, conditions);
if (biz != null)
{
TaskFlowDataContext dataContext = new(
(TaskFlowDataNameConst.Business, biz)
);
//循环匹配
foreach (var item in conditions)
{
if (ConditionHelper.IsPass(item, dataContext))
{
var logEntity = new BusinessTaskLog
{
ActionType = ActionType.Create,
BusinessId = request.BusinessId,
BusinessType = request.BusinessType,
TaskType = request.TaskType,
CreateBy = long.Parse(User.UserId),
CreateTime = DateTime.Now,
Remark = $"符合设定条件,已跳过任务的创建"
};
await LogService.WriteLogAsync(logEntity);
return true;
}
}
}
return false;
}
/// <summary>
/// 获取所需业务数据
/// </summary>
/// <param name="businessId">业务ID</param>
/// <param name="businessType">业务类型</param>
/// <param name="conditions">条件字段</param>
/// <returns></returns>
public async Task<dynamic?> GetBusinessDataAsync(long businessId, BusinessType businessType, IEnumerable<ConditionContent> conditions)
{
ArgumentNullException.ThrowIfNull(conditions, nameof(conditions));
HashSet<string> fields = [];
foreach (var item in conditions)
{
if (item.Conditions != null)
fields.AddRange(item.Conditions.Select(x => x.Field));
if (item.Groups != null)
fields.AddRange(item.Groups.SelectMany(x => x.Conditions.Select(x => x.Field)));
}
return await GetBusinessDataAsync(businessId, businessType, fields.ToArray());
}
/// <summary>
@ -32,7 +101,7 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
/// <param name="businessType">业务类型</param>
/// <param name="fields">返回字段列表</param>
/// <returns></returns>
public dynamic? GetBusinessData(long businessId, BusinessType businessType, params string[] fields)
public async Task<dynamic?> GetBusinessDataAsync(long businessId, BusinessType businessType, params string[] fields)
{
object? biz = null;
switch (businessType)
@ -46,7 +115,7 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
else
{
var selectors = fields.Select(x => new SelectModel { FieldName = x }).ToList();
biz = TenantDb.Queryable<object>().AS("op_sea_export").Where("Id=@Id", new { Id = businessId }).Select(selectors).First();
biz = await TenantDb.Queryable<object>().AS("op_sea_export").Where("Id=@Id", new { Id = businessId }).Select(selectors).FirstAsync();
}
break;
@ -70,17 +139,22 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
if (businessTask.TaskStatus != TaskStatusEnum.Complete)
return;
var biz = GetBusinessData(businessTask.BusinessId, businessTask.BusinessType);
//var biz = GetBusinessDataAsync(businessTask.BusinessId, businessTask.BusinessType);
// 执行自动化操作
TaskFlowDataContext dataContext = new(
(TaskFlowDataNameConst.BusinessTask, businessTask),
(TaskFlowDataNameConst.Business, biz)
(TaskFlowDataNameConst.BusinessTask, businessTask)
//(TaskFlowDataNameConst.Business, biz)
);
TaskFlowRuner taskFlow = new(TenantDb, ServiceProvider);
await taskFlow.RunWithBsno(businessTask.TaskType, businessTask.BusinessId, dataContext);
}
/// <summary>
/// 执行动作
/// </summary>
/// <param name="dataContext"></param>
/// <returns></returns>
public async Task ExecuteAsync(TaskFlowDataContext dataContext)
{
ArgumentNullException.ThrowIfNull(dataContext, nameof(dataContext));
@ -93,30 +167,36 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
foreach (var key in dataContext.Keys)
context.AdditionalData[key] = dataContext[key];
string selectorType = dataContext.GetOrDefault<string>("SelectorType");
if (selectorType.IsNullOrEmpty())
var typeName = dataContext.GetOrDefault<string>("TypeName");
if (typeName.IsNullOrEmpty())
return;
Type? t = Type.GetType(selectorType, true, false);
Type? t = Type.GetType(typeName, true, false);
if (t == null)
{
await new ApplicationException($"未能获取类型【{selectorType}】的信息").LogAsync(Db);
await new ApplicationException($"未能获取类型【{typeName}】的信息").LogAsync(Db);
return;
}
IActionSelector? selector = ConstructorExtensions.CreateInstance(t) as IActionSelector;
if (selector == null)
IActionExecutor currentExecutor = null;
if (ConstructorExtensions.CreateInstance(t) is IActionSelector selector)
{
await new ApplicationException($"未能创建执行选择器【{t.AssemblyQualifiedName}】的实例").LogAsync(Db);
return;
currentExecutor = await selector.GetActionExecutor(context);
}
else if (ConstructorExtensions.CreateInstance(t) is IActionExecutor executor)
{
currentExecutor = executor;
}
var executor = await selector.GetActionExecutor(context);
if (executor != null)
if (currentExecutor == null)
{
executor.ExecuteAsync(context);
var logService = context.ServiceProvider.GetRequiredService<ITaskLogService>();
await logService.WriteLogAsync(context.TaskInfo, $"开始运行后台任务({executor.GetType().FullName}...");
await new ApplicationException($"未能创建类型【{t.AssemblyQualifiedName}】的实例").LogAsync(Db);
return;
}
await currentExecutor.ExecuteAsync(context);
var logService = context.ServiceProvider.GetRequiredService<ITaskLogService>();
await logService.WriteLogAsync(context.TaskInfo, $"开始运行后台任务({currentExecutor.GetType().FullName}...");
}
public async Task<DataResult> TriggerTest(TaskBaseTypeEnum taskType, long? id)

@ -7,12 +7,13 @@ using DS.WMS.Core.Op.Entity;
using DS.WMS.Core.Op.Entity.TaskInteraction;
using DS.WMS.Core.Op.Interface.TaskInteraction;
using DS.WMS.Core.Op.Method.TaskInteraction.ActionExecutor;
using DS.WMS.Core.Op.Method.TaskInteraction.ActionExecutor.Booking;
using Microsoft.Extensions.DependencyInjection;
namespace DS.WMS.Core.Op.Method.TaskInteraction.ActionSelector
{
/// <summary>
/// 订舱
/// 订舱选择器
/// </summary>
public class BookingSelector : IActionSelector
{
@ -20,7 +21,6 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction.ActionSelector
public async Task<IActionExecutor> GetActionExecutor(ActionExecutionContext context)
{
//var db = context.ServiceProvider.GetRequiredService<ISqlSugarClient>();
var saasService = context.ServiceProvider.GetRequiredService<ISaasDbService>();
var user = context.ServiceProvider.GetRequiredService<IUser>();
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);

@ -17,6 +17,7 @@ using DS.Module.Core;
using Masuit.Tools;
using Masuit.Tools.Systems;
using DS.WMS.Core.Op.Entity;
using DS.WMS.Core.Op.Method.TaskInteraction.ActionExecutor.Booking;
namespace DS.WMS.Core.Op.Method.TaskInteraction
{

@ -1,4 +1,5 @@
using DS.Module.Core;
using DS.Module.Core.Data;
using DS.Module.Core.Extensions;
using DS.Module.DjyServiceStatus;
using DS.WMS.Core.Op.Dtos.TaskInteraction;
@ -47,7 +48,7 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
var taskLogList = new List<BusinessTaskLog>();
var first = request.First();
var defaultUsers = await GetRecvUsers(first.RecvUserIdList);
var defaultUsers = await GetRecvUsersAsync(first.RecvUserIdList);
var biz = await TenantDb.Queryable<SeaExport>().Select(x => new
{
x.Id,
@ -58,9 +59,10 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
x.ETD,
}).FirstAsync(x => x.Id == first.BusinessId);
var dic = await GetRecvUsersAsync(first.BusinessId, first.BusinessType, request.Select(x => x.TaskType).ToList());
foreach (var item in request)
{
var recvUsers = await GetRecvUsersFromConfig(item.BusinessId, item.BusinessType, item.TaskType);
var recvUsers = dic[item.TaskType];
var info = new TaskManageOrderMessageInfo
{
Head = new TaskManageOrderMessageHeadInfo
@ -122,23 +124,38 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
}
/// <summary>
/// 当任务状态发生变化时调用
/// 创建关联子任务
/// </summary>
/// <param name="request"></param>
/// <param name="dataContext"></param>
/// <returns></returns>
protected override async Task OnTaskStatusChanged(TaskUpdateRequest request)
{
//放舱结束,根据业务所选服务,生成子任务
if (request.TaskType == TaskBaseTypeEnum.WAIT_SPACE_RELEASE && request.TaskStatus == TaskStatusEnum.Complete)
public async Task CreateSubTaskAsync(TaskFlowDataContext dataContext)
{
var task = await GetQuery(request.BusinessId, request.BusinessType, request.TaskType).FirstAsync();
if (task != null)
if (dataContext[TaskFlowDataNameConst.BusinessTask] is BusinessTask task
&& task.TaskStatus == TaskStatusEnum.Complete)
{
var list = await GetSubRequestAsync(request.BusinessId, request.BusinessType, task.RecvUserIdArray);
var list = await GetSubRequestAsync(task.BusinessId, task.BusinessType, task.RecvUserIdArray);
await CreateSubTaskAsync(list.FindAll(x => x.TaskType != TaskBaseTypeEnum.NOT_SPECIFIED).OrderBy(x => x.TaskType));
}
}
}
///// <summary>
///// 当任务状态发生变化时调用
///// </summary>
///// <param name="request"></param>
///// <returns></returns>
//protected override async Task OnTaskStatusChanged(TaskUpdateRequest request)
//{
// //放舱结束,根据业务所选服务,生成子任务
// if (request.TaskType == TaskBaseTypeEnum.WAIT_SPACE_RELEASE && request.TaskStatus == TaskStatusEnum.Complete)
// {
// var task = await GetQuery(request.BusinessId, request.BusinessType, request.TaskType).FirstAsync();
// if (task != null)
// {
// var list = await GetSubRequestAsync(request.BusinessId, request.BusinessType, task.RecvUserIdArray);
// await CreateSubTaskAsync(list.FindAll(x => x.TaskType != TaskBaseTypeEnum.NOT_SPECIFIED).OrderBy(x => x.TaskType));
// }
// }
//}
internal async Task<List<TaskCreationRequest>> GetSubRequestAsync(long id, BusinessType businessType, params long[]? recvUsers)
{
@ -172,7 +189,7 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
else if (svcName == "拖车")
dto.TaskTypeName = TaskBaseTypeEnum.WAIT_TUOCHE.ToString();
else if (svcName == "保险")
dto.TaskTypeName = TaskBaseTypeEnum.WAIT_Insurance.ToString();
dto.TaskTypeName = TaskBaseTypeEnum.WAIT_INSURANCE.ToString();
else if (svcName == "出号")
dto.TaskTypeName = TaskBaseTypeEnum.WAIT_CHUHAO.ToString();
else if (svcName == "内点入货")
@ -202,28 +219,5 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
return extArray.Where(x => x["isYield"].Value<bool>()).Select(x => x["projectName"]?.Value<string>() ?? string.Empty).ToArray();
}
//public override async Task MarkerChangedAsync(MarkerChangedCallback callback)
//{
// if (callback.Type != AuditType.SeaExport)
// return;
// await base.MarkerChangedAsync(callback);
//}
///// <summary>
///// 审批完成回调更新
///// </summary>
///// <param name="callback">回调信息</param>
///// <returns></returns>
//public override async Task UpdateBusinessAsync(FlowCallback callback)
//{
// if (callback.Type != AuditType.SeaExport)
// return;
// await base.UpdateBusinessAsync(callback);
// //todo:海运出口主表信息
//}
}
}

@ -11,6 +11,7 @@ using DS.WMS.Core.Op.Entity;
using DS.WMS.Core.Op.Entity.TaskInteraction;
using DS.WMS.Core.Op.Interface.TaskInteraction;
using DS.WMS.Core.Sys.Entity;
using DS.WMS.Core.TaskPlat;
using DS.WMS.Core.TaskPlat.Dtos;
using DS.WMS.Core.TaskPlat.Entity;
using DS.WMS.Core.TaskPlat.Interface;
@ -76,18 +77,23 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
/// <summary>
/// 获取给定任务的下一任务类型
/// </summary>
/// <param name="current">任务信息</param>
/// <param name="current"></param>
/// <returns></returns>
internal static TaskBaseTypeEnum? GetNextType(BusinessTask current)
public async Task<TaskBaseTypeEnum?> GetNextTypeAsync(BusinessTask current)
{
if (current.TaskType == TaskBaseTypeEnum.NOT_SPECIFIED || current.TaskType == TaskBaseTypeEnum.WAIT_CHECKOUT_BILL) //流程的最后一步
return null;
TaskFlowRuner flowRuner = new TaskFlowRuner(TenantDb, ServiceProvider);
int currentTypeVal = (int)current.TaskType;
if (currentTypeVal >= 300) //300开始的枚举值为可选服务项目不存在前后关联性
return null;
var result = await flowRuner.GetWorkFlowNextConfig(new TaskFlowDataContext(
), current.NextId);
return (TaskBaseTypeEnum)(currentTypeVal + 1);
if (result.HasValue)
{
current.NextId = result.Value.configId;
return result.Value.taskType;
}
return null;
}
/// <summary>
@ -252,8 +258,8 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
if (task != null && task.TaskStatus != TaskStatusEnum.Cancel)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskExists));
//if (await ShouldSkipAsync(request))
// return DataResult.Success;
if (await ShouldSkipAsync(request))
return DataResult.Success;
long tenatId = long.Parse(User.TenantId);
string tenatName = Db.Queryable<SysTenant>().Where(x => x.Id == tenatId).Select(x => x.Name).First();
@ -289,12 +295,12 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
if (request.RecvUserIdList == null || request.RecvUserIdList.Length == 0)
{
//根据配置获取默认接收人
info.Main.RecvUserInfoList = await GetRecvUsersFromConfig(request.BusinessId, request.BusinessType, request.TaskType);
info.Main.RecvUserInfoList = await GetRecvUsersAsync(request.BusinessId, request.BusinessType, request.TaskType);
if (info.Main.RecvUserInfoList == null || info.Main.RecvUserInfoList.Count == 0)
{
if (AuditTaskTypes.Contains(request.TaskType))
{
info.Main.RecvUserInfoList = await GetRecvUsers(long.Parse(User.UserId));
info.Main.RecvUserInfoList = await GetRecvUsersAsync(long.Parse(User.UserId));
}
else
{
@ -304,7 +310,7 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
}
else
{
info.Main.RecvUserInfoList = await GetRecvUsers(request.RecvUserIdList);
info.Main.RecvUserInfoList = await GetRecvUsersAsync(request.RecvUserIdList);
}
if (info.Main.TaskTitle.IsNullOrEmpty())
@ -341,7 +347,7 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
CreateBy = long.Parse(User.UserId),
CreateTime = DateTime.Now
};
task.NextType = GetNextType(task);
task.NextType = await GetNextTypeAsync(task);
await TenantDb.Insertable(task).ExecuteCommandAsync();
//审核任务需创建工作流
@ -380,47 +386,11 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
.Select(x => new { x.Id, x.SourceName, x.MatchCondition }).ToListAsync();
if (configList.Count > 0)
{
var conditionList = configList.Select(x => new { x.Id, x.SourceName, MatchCondition = JsonConvert.DeserializeObject<ContitionContent>(x.MatchCondition) }).ToList();
HashSet<string> fields = [];
var conditionList = configList.Select(x => new { x.Id, x.SourceName, MatchCondition = JsonConvert.DeserializeObject<ConditionContent>(x.MatchCondition) }).ToList();
foreach (var item in conditionList)
{
if (item.MatchCondition.Conditions != null)
fields.AddRange(item.MatchCondition.Conditions.Select(x => x.Field));
item.MatchCondition.SourceName = item.SourceName;
if (item.MatchCondition.Groups != null)
fields.AddRange(item.MatchCondition.Groups.SelectMany(x => x.Conditions.Select(x => x.Field)));
}
var biz = ActionService.Value.GetBusinessData(request.BusinessId, request.BusinessType, fields.ToArray());
if (biz != null)
{
//循环匹配
foreach (var item in configList)
{
var content = conditionList.Find(x => x.Id == item.Id)?.MatchCondition;
if (content == null)
continue;
content.SourceName = item.SourceName;
TaskFlowDataContext dataContext = new(
(TaskFlowDataNameConst.Business, biz)
);
if (ConditionHelper.IsPass(content, dataContext))
{
var logEntity = new BusinessTaskLog
{
ActionType = ActionType.Create,
BusinessId = request.BusinessId,
BusinessType = request.BusinessType,
TaskType = request.TaskType,
CreateBy = long.Parse(User.UserId),
CreateTime = DateTime.Now,
Remark = $"符合设定条件({item.Id}),已跳过任务的创建"
};
await LogService.WriteLogAsync(logEntity);
return true;
}
}
}
return await ActionService.Value.IsMatchAsync(request, conditionList.Select(x => x.MatchCondition));
}
return false;
@ -459,7 +429,7 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
{
string[] ids = FlowInstanceService.GetMarkers(instance);
//变更任务接收人为所有审批执行人
var users = await GetRecvUsers(ids.Select(long.Parse).ToArray());
var users = await GetRecvUsersAsync(ids.Select(long.Parse).ToArray());
result = await ManagerService.TransferTask(task.BusinessId, task.TaskType, users);
if (result.Succeeded)
{
@ -546,8 +516,8 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
if (useTransaction)
await TenantDb.Ado.CommitTranAsync();
//ActionService.Value.TriggerAction(task);
return DataResult<TaskBaseTypeEnum?>.Success(task.TaskStatus == TaskStatusEnum.Complete ? GetNextType(task) : null);
ActionService.Value.TriggerAction(task);
return DataResult<TaskBaseTypeEnum?>.Success(task.TaskStatus == TaskStatusEnum.Complete ? await GetNextTypeAsync(task) : null);
}
catch (Exception ex)
{
@ -580,7 +550,7 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
ArgumentNullException.ThrowIfNull(callback, nameof(callback));
long userId = long.Parse(User.UserId);
var users = await GetRecvUsers(userId);
var users = await GetRecvUsersAsync(userId);
var dt = DateTime.Now;
var taskType = TypeMappings.Where(x => x.Value == callback.Type.GetValueOrDefault()).Select(x => x.Key).FirstOrDefault();
@ -630,7 +600,7 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
await SetTaskStatusAsync(req);
long userId = long.Parse(User.UserId);
var users = await GetRecvUsers(userId);
var users = await GetRecvUsersAsync(userId);
string remark = "终审完成,审批结果为:" + callback.FlowStatus.GetDescription();
if (callback.FlowStatus == FlowStatusEnum.Reject)
@ -685,10 +655,29 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
/// <param name="businessType">业务类型</param>
/// <param name="taskType">任务类型</param>
/// <returns></returns>
protected internal async Task<List<RecvUserInfo>?> GetRecvUsersFromConfig(long id, BusinessType businessType, TaskBaseTypeEnum taskType)
protected internal async Task<List<RecvUserInfo>> GetRecvUsersAsync(long id, BusinessType businessType, TaskBaseTypeEnum taskType)
{
//var biz = ActionService.Value.GetBusinessDataAsync(id, businessType);
//var result = await TaskAllocationService.Value.GetAllotUserBySeaExportId(taskType, id, new TaskFlowDataContext(
// (TaskFlowDataNameConst.Business, biz)
// ));
//return result.Succeeded ? result.Data : [];
var dic = await GetRecvUsersAsync(id, businessType, [taskType]);
return dic?.Count > 0 ? dic.FirstOrDefault().Value : [];
}
/// <summary>
/// 从任务配置中获取接收用户列表
/// </summary>
/// <param name="id">业务ID</param>
/// <param name="businessType">业务类型</param>
/// <param name="taskTypes">任务类型</param>
/// <returns></returns>
protected internal async Task<Dictionary<TaskBaseTypeEnum, List<RecvUserInfo>>> GetRecvUsersAsync(long id, BusinessType businessType, List<TaskBaseTypeEnum> taskTypes)
{
var biz = ActionService.Value.GetBusinessData(id, businessType);
var result = await TaskAllocationService.Value.GetAllotUserBySeaExportId(taskType, id, new TaskFlowDataContext(
var biz = ActionService.Value.GetBusinessDataAsync(id, businessType);
var result = await TaskAllocationService.Value.GetAllotUserBySeaExportId(taskTypes, id, new TaskFlowDataContext(
(TaskFlowDataNameConst.Business, biz)
));
return result.Succeeded ? result.Data : [];
@ -699,7 +688,7 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
/// </summary>
/// <param name="ids">用户ID</param>
/// <returns></returns>
protected internal async Task<List<RecvUserInfo>> GetRecvUsers(params long[] ids)
protected internal async Task<List<RecvUserInfo>> GetRecvUsersAsync(params long[] ids)
{
return await Db.Queryable<SysUser>().Where(x => ids.Contains(x.Id)).Select(
x => new RecvUserInfo { RecvUserId = x.Id, RecvUserName = x.UserName }).ToListAsync();

@ -40,6 +40,12 @@ namespace DS.WMS.Core.TaskPlat.Entity
[SugarColumn(ColumnDescription = "所属主入口流程主键", IsNullable = true)]
public long? MainConfigId { get; set; }
///// <summary>
///// 下一流程主键
///// </summary>
//[SugarColumn(ColumnDescription = "下一流程主键", IsNullable = true)]
//public long? NextConfigId { get; set; }
/// <summary>
/// 父项流程主键
/// </summary>

@ -3,6 +3,7 @@ using DS.Module.Core.Condition;
using DS.Module.Core.Data;
using DS.Module.SqlSugar;
using DS.Module.UserModule;
using DS.WMS.Core.Op.Dtos;
using DS.WMS.Core.Op.Entity;
using DS.WMS.Core.Sys.Interface;
using DS.WMS.Core.Sys.Method;
@ -10,6 +11,7 @@ using DS.WMS.Core.TaskPlat.Dtos;
using DS.WMS.Core.TaskPlat.Entity;
using DS.WMS.Core.TaskPlat.Interface;
using LanguageExt.Pipes;
using Mapster;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using SqlSugar;
@ -255,7 +257,7 @@ namespace DS.WMS.Core.TaskPlat.Method
}
else
{
var contitionContent = JsonConvert.DeserializeObject<ContitionContent>(item.Condition)!;
var contitionContent = JsonConvert.DeserializeObject<ConditionContent>(item.Condition)!;
if (ConditionHelper.IsPass(contitionContent, dataContext))
{
allotTargetList.Add(item);
@ -273,7 +275,8 @@ namespace DS.WMS.Core.TaskPlat.Method
var tenantDb = saasDbService.GetBizDbScopeById(user.TenantId);
if (dataContext.ContainsKey(TaskFlowDataNameConst.Business))
{
order = dataContext.Get<SeaExport>(TaskFlowDataNameConst.Business);
var orderDto = dataContext.Get<SeaExportRes>(TaskFlowDataNameConst.Business);
order = orderDto.Adapt<SeaExport>();
}
else
{
@ -385,7 +388,7 @@ namespace DS.WMS.Core.TaskPlat.Method
}
else
{
var contitionContent = JsonConvert.DeserializeObject<ContitionContent>(allotItem.Condition)!;
var contitionContent = JsonConvert.DeserializeObject<ConditionContent>(allotItem.Condition)!;
if (ConditionHelper.IsPass(contitionContent, dataContext))
{
itemResult.Add(allotItem);
@ -403,7 +406,8 @@ namespace DS.WMS.Core.TaskPlat.Method
var tenantDb = saasDbService.GetBizDbScopeById(user.TenantId);
if (dataContext.ContainsKey(TaskFlowDataNameConst.Business))
{
order = dataContext.Get<SeaExport>(TaskFlowDataNameConst.Business);
var orderDto = dataContext.Get<SeaExportRes>(TaskFlowDataNameConst.Business);
order = orderDto.Adapt<SeaExport>();
}
else
{

@ -81,7 +81,7 @@ namespace DS.WMS.Core.TaskPlat
var conditionItem = allConditionList.FirstOrDefault(x => x.ConfigId == configItem.Id);
if (conditionItem != null && !string.IsNullOrEmpty(conditionItem.Content))
{
var contitionContent = JsonConvert.DeserializeObject<ContitionContent>(conditionItem.Content)!;
var contitionContent = JsonConvert.DeserializeObject<ConditionContent>(conditionItem.Content)!;
var oldValue = configMatchCount[configItem.Id];
if (ConditionHelper.IsPass(contitionContent, dataContext))
@ -179,7 +179,7 @@ namespace DS.WMS.Core.TaskPlat
continue;
}
var contitionContent = JsonConvert.DeserializeObject<ContitionContent>(condition.Content)!;
var contitionContent = JsonConvert.DeserializeObject<ConditionContent>(condition.Content)!;
if (ConditionHelper.IsPass(contitionContent, dataContext))
{
matchedConfigList.Add(waitMatchConfigItem);
@ -357,6 +357,85 @@ namespace DS.WMS.Core.TaskPlat
.FirstAsync();
return await Run(taskBaseType, taskId, dataContext);
}
/// <summary>
/// 根据当前节点Id获取工作流下一个任务类型
/// </summary>
/// <param name="dataContext"></param>
/// <param name="currentConfigId">当前执行的配置Id如果为空则返回首个任务类型</param>
/// <returns>下一个任务类型下一节点Id</returns>
public async Task<(TaskBaseTypeEnum taskType, long configId)?> GetWorkFlowNextConfig(TaskFlowDataContext dataContext, long? currentConfigId = null)
{
var allConfigList = await tenantDb.Queryable<TaskFlowConfig>()
.Where(t => t.MainConfigId == SqlFunc.Subqueryable<TaskFlowConfig>().Where(x => x.IsMain && x.TaskType == "WORK_FLOW").Select(x => x.Id))
.OrderBy(t => t.Id)
.ToListAsync();
if (allConfigList.Count == 0) return null;
List<TaskFlowConfig> waitMatchConfigList = new();
if (currentConfigId == null)
{
waitMatchConfigList.Add(allConfigList.First(x => x.IsMain));
}
else
{
var currentConfig = allConfigList.FirstOrDefault(x => x.Id == currentConfigId);
if (currentConfig == null) return null;
waitMatchConfigList.AddRange(allConfigList.Where(x => x.ParentConfigId == currentConfig.Id));
}
if (waitMatchConfigList.Count == 0) return null;
var configIdList = waitMatchConfigList.Select(x => x.Id);
var conditionList = await tenantDb.Queryable<TaskFlowCondition>()
.Where(x => configIdList.Contains(x.ConfigId))
.ToListAsync();
var matchedConfigList = new List<TaskFlowConfig>();
foreach (var item in waitMatchConfigList)
{
var condition = conditionList.FirstOrDefault(x => x.ConfigId == item.Id);
if (condition == null || string.IsNullOrEmpty(condition.Content))
{
matchedConfigList.Add(item);
}
else
{
var contitionContent = JsonConvert.DeserializeObject<ConditionContent>(condition.Content)!;
if (ConditionHelper.IsPass(contitionContent, dataContext))
{
matchedConfigList.Add(item);
}
}
}
TaskFlowConfig? executeConfig = null;
if (matchedConfigList.Count == 1)
{
executeConfig = matchedConfigList[0];
}
else if (matchedConfigList.Count > 1)
{
executeConfig = matchedConfigList.FirstOrDefault(x => x.IsMoreMatchDefault);
}
if (executeConfig == null)
{
executeConfig = waitMatchConfigList.FirstOrDefault(x => x.IsUnMatchDefault);
}
if (executeConfig == null) return null;
var taskType = await tenantDb.Queryable<TaskFlowModule>().Where(x => x.Id == executeConfig.ExecuteModuleId).Select(x => x.TaskType).FirstAsync();
if (taskType != null && Enum.TryParse(typeof(TaskBaseTypeEnum), taskType, out object? temp))
{
return ((TaskBaseTypeEnum)temp, executeConfig.Id);
}
return null;
}
static string WriteLog(string throwMsg, Exception ex)
{
return string.Format("【自定义错误】:{0} \r\n【异常类型】{1} \r\n【异常信息】{2} \r\n【堆栈调用】{3}", new object[]

@ -94,6 +94,9 @@ namespace DS.WMS.OpApi.Controllers
[HttpPost, Route("SubmitAudit")]
public async Task<DataResult> SubmitAuditAsync(TaskRequest request)
{
if (!ModelState.IsValid)
return DataResult.Failed(ModelState.GetErrorMessage(), MultiLanguageConst.IllegalRequest);
return await taskService.SubmitAuditAsync(request);
}
@ -105,6 +108,9 @@ namespace DS.WMS.OpApi.Controllers
[HttpPost, Route("Audit")]
public async virtual Task<DataResult> AuditAsync([FromBody] TaskAuditRequest request)
{
if (!ModelState.IsValid)
return DataResult.Failed(ModelState.GetErrorMessage(), MultiLanguageConst.IllegalRequest);
return await taskService.AuditAsync(request);
}
@ -126,7 +132,7 @@ namespace DS.WMS.OpApi.Controllers
/// <param name="callback">回调信息</param>
/// <returns></returns>
[HttpPost, Route("MarkerChanged")]
public virtual async Task<IActionResult> MarkerChangedAsync([FromBody] MarkerChangedCallback callback)
public async Task<IActionResult> MarkerChangedAsync([FromBody] MarkerChangedCallback callback)
{
await taskService.MarkerChangedAsync(callback);
return StatusCode((int)HttpStatusCode.NoContent);

@ -8,7 +8,7 @@ namespace DS.WMS.OpApi.Controllers
/// <summary>
/// 预订舱马士基API即期订舱
/// </summary>
public class SpaceBookingMSKAPISpotController : Controller
public class SpaceBookingMSKAPISpotController : ApiController
{
private readonly ISpaceBookingMSKSPOTAPIService _spaceBookingMSKSPOTAPIService;

@ -1,5 +1,6 @@
using System.Reflection;
using DS.Module.Core;
using DS.Module.Core.Data;
using DS.Module.Core.Extensions;
using DS.Module.SqlSugar;
using DS.WMS.Core.Check.Entity;
@ -8,6 +9,7 @@ using DS.WMS.Core.Info.Entity;
using DS.WMS.Core.Op.Entity;
using DS.WMS.Core.Op.Entity.BookingSlot;
using DS.WMS.Core.Sys.Entity;
using DS.WMS.Core.TaskPlat;
using DS.WMS.Core.TaskPlat.Entity;
using Mapster;
using Masuit.Tools.Strings;
@ -251,4 +253,18 @@ public class SaasTest
//tenantDb.CodeFirst.InitTables(typeof(TaskFlowLogDetail));
Assert.True(true);
}
[Fact]
public async Task ZxfTest()
{
var tenantDb = saasService.GetBizDbScopeById("1819549542425694208");
var order = await tenantDb.Queryable<SeaExport>().FirstAsync(x => x.Id == 1816649497120477184);
TaskFlowDataContext dataContext = new(
(TaskFlowDataNameConst.Business, order)
);
TaskFlowRuner runer = new TaskFlowRuner(tenantDb, _serviceProvider);
var result =await runer.GetWorkFlowNextConfig(dataContext, null);
}
}
Loading…
Cancel
Save