using System.Text;
using DS.Module.Core;
using DS.Module.Core.Data;
using DS.Module.Core.Helpers;
using DS.Module.DjyRulesEngine;
using DS.WMS.Core.Application.Dtos;
using DS.WMS.Core.Flow.Dtos;
using DS.WMS.Core.Flow.Entity;
using DS.WMS.Core.Flow.Interface;
using DS.WMS.Core.Flow.Method;
using DS.WMS.Core.Info.Interface;
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.TaskInteraction;
using DS.WMS.Core.Op.Method.TaskInteraction.ActionSelector;
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;
using Mapster;
using Masuit.Tools;
using Masuit.Tools.Systems;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using SqlSugar;
namespace DS.WMS.Core.Op.Method.TaskInteraction
{
///
/// 任务交互服务
///
public class TaskService : ServiceBase, ITaskService
{
const long PERMISSION_ID = 1815294400855674880;
///
/// 获取支持审核的任务类型
///
public static readonly TaskBaseTypeEnum[] AuditTaskTypes;
static readonly ApiFox Api;
static TaskService()
{
var dic = EnumExt.GetDictionary(typeof(TaskBaseTypeEnum));
var enumValues = dic.Where(x => x.Key != -1).GroupBy(x => Math.Abs(x.Key)).Select(x => new
{
Value = x.Key,
Count = x.Count()
}).Where(x => x.Count > 1);
AuditTaskTypes = enumValues.Select(x => (TaskBaseTypeEnum)Math.Abs(x.Value)).Distinct().ToArray();
Api = new ApiFox();
}
///
/// 确定任务类型是否为业务订单任务
///
/// 任务类型
///
public static bool IsOrderType(TaskBaseTypeEnum taskType)
{
int val = (int)taskType;
return val >= 200 && val <= 399;
}
///
/// 返回审核任务类型所对应的驳回类型
///
/// 审核任务类型
///
public static TaskBaseTypeEnum? GetRejectedType(TaskBaseTypeEnum auditTaskType)
{
if (!AuditTaskTypes.Contains(auditTaskType))
return null;
int negativeVal = -(int)auditTaskType;
return (TaskBaseTypeEnum)negativeVal;
}
///
/// 任务管理服务
///
protected ITaskManageService ManagerService { get; private set; }
///
/// 日志服务
///
protected ITaskLogService LogService { get; private set; }
///
/// 任务分配
///
protected ITaskAllocationService TaskAllocationService { get; private set; }
///
/// 工作流服务
///
protected Lazy FlowService { get; private set; }
///
/// 动作服务
///
protected IActionManagerService ActionService { get; private set; }
readonly Lazy ClientParamService;
///
/// 规则库服务
///
protected Lazy RuleEngineService { get; private set; }
readonly IConfiguration configuration;
///
/// 初始化
///
///
public TaskService(IServiceProvider provider) : base(provider)
{
ManagerService = provider.GetRequiredService();
LogService = provider.GetRequiredService();
TaskAllocationService = provider.GetRequiredService();
ActionService = provider.GetRequiredService();
configuration = provider.GetRequiredService();
ClientParamService = new Lazy(provider.GetRequiredService());
FlowService = new Lazy(provider.GetRequiredService());
RuleEngineService = new Lazy(provider.GetRequiredService());
TenantDb.QueryFilter.Clear();
}
///
/// 批量创建关联任务
///
///
/// 是否使用事务
///
public async Task CreateMultipleTaskAsync(TaskCreationRequest request, bool useTransaction = true)
{
var ids = request.Ids;
ids ??= [request.BusinessId];
List strList = [];
DataResult result;
for (int i = 0; i < ids.Length; i++)
{
request.BusinessId = ids[i];
result = await CreateTaskAsync(request, useTransaction);
if (!result.Succeeded)
{
if (result.Data == null)
return result;
strList.Add(result.Data.ToString()!);
}
}
if (strList.Count == 0)
return DataResult.Success;
return DataResult.Failed(string.Format(
MultiLanguageConst.GetDescription(MultiLanguageConst.OrderTaskSubmitted), string.Join("、", strList)));
}
///
/// 创建关联任务
///
///
/// 是否使用事务
///
public async Task CreateTaskAsync(TaskCreationRequest request, bool useTransaction = true)
{
if (!await HasAuthorizedAsync())
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.ModuleUnauthorized));
if (request.HasCabin.GetValueOrDefault() && request.BusinessType.HasValue)
{
//如果为现舱,获取下一任务类型进行创建
var nextType = await GetNextTypeAsync(request.BusinessId, request.BusinessType.Value, request.TaskType, request.HasCabin);
if (nextType.HasValue)
request.TaskTypeName = nextType.Value.ToString();
}
DataResult result = DataResult.Success;
bool updateFlag = false;
var task = await GetQuery(request.BusinessId, request.BusinessType, request.TaskType).FirstAsync();
if (task != null)
{
//可审核任务类型允许挂起或取消的任务重新提交
if (AuditTaskTypes.Contains(request.TaskType) && (task.TaskStatus == TaskStatusEnum.Pending || task.TaskStatus == TaskStatusEnum.Cancel))
{
updateFlag = true;
}
else //其他任务类型返回已存在提示
{
if (IsOrderType(request.TaskType))
{
string custNO = await TenantDb.Queryable().Where(x => x.Id == request.BusinessId)
.Select(x => x.CustomerNo).FirstAsync();
result = DataResult.Failed(string.Format(
MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.OrderTaskSubmitted)) + request.TaskType.GetDescription(), custNO));
result.Data = custNO;
return result;
}
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskExists));
}
}
if (request.TaskType == TaskBaseTypeEnum.WAIT_ORDER_AUDIT)
{
result = await CheckRulesAsync(request.BusinessId, request.BusinessType.Value, RuleEngineType.COMMON_ORDER_AUDIT);
if (!result.Succeeded)
return result;
}
if (useTransaction)
await TenantDb.Ado.BeginTranAsync();
try
{
if (task == null)
{
long tenatId = long.Parse(User.TenantId);
string tenatName = Db.Queryable().Where(x => x.Id == tenatId).Select(x => x.Name).First();
var info = new TaskManageOrderMessageInfo
{
Head = new TaskManageOrderMessageHeadInfo
{
GID = Guid.NewGuid().ToString(),
BSNO = request.BusinessId,
MessageType = "WORK_FLOW_TASK",
SenderId = "WorkFlow",
SenderName = "工作流平台",
ReceiverId = "TaskManage",
ReceiverName = "任务管理平台",
Version = "1.0",
RequestDate = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
RequestAction = "Add"
},
Main = new TaskManageOrderMessageMainInfo
{
TaskType = request.TaskType,
TaskSource = TaskSourceEnum.WORK_FLOW,
TaskTitle = request.TaskTitle,
TaskDesp = request.TaskDescription,
TaskUserId = User.UserId,
TaskUserName = User.UserName,
TaskTenatId = tenatId,
TaskTenatName = tenatName,
IsCheckExistsByTaskType = true
}
};
if ((request.RecvUserIdList == null || request.RecvUserIdList.Length == 0) && IsOrderType(request.TaskType))
{
//根据配置获取默认接收人
info.Main.RecvUserInfoList = await GetRecvUsersAsync(request.BusinessId, request.BusinessType, request.TaskType);
}
else if (AuditTaskTypes.Contains(request.TaskType))
{
//审核类型默认为提交人,生成工作流后替换为工作流执行人
info.Main.RecvUserInfoList = await FillInUserInfoAsync(long.Parse(User.UserId));
}
else
{
info.Main.RecvUserInfoList = await FillInUserInfoAsync(request.RecvUserIdList);
}
//if (info.Main.RecvUserInfoList == null || info.Main.RecvUserInfoList.Count == 0)
// return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskReceiverNotFound));
//仅为业务订单任务自动填充任务标题/描述
if (info.Main.TaskTitle.IsNullOrEmpty() && IsOrderType(request.TaskType))
{
var biz = await TenantDb.Queryable().Select(x => new
{
x.Id,
x.CustomerNo,
x.MBLNO,
x.Vessel,
x.Voyno,
x.ETD,
x.DischargePortId,
x.DischargePortCode,
x.DischargePort,
x.LoadPortId,
x.LoadPortCode,
x.LoadPort,
x.CarrierId,
x.Carrier,
//x.BookingNo,
//x.HBLNO,
//x.CustomerNum,
}).FirstAsync(x => x.Id == request.BusinessId);
info.Main.TaskTitle = $"【{request.TaskType.GetDescription()}】{biz?.CustomerNo} {biz?.Vessel} {biz?.Voyno} ETD:{biz?.ETD?.ToString("yyyy-MM-dd")}";
info.Main.CustomerNo = biz?.CustomerNo;
info.Main.MBlNo = biz?.MBLNO;
info.Main.ETD = biz?.ETD;
info.Main.PortDischarge = biz?.DischargePort;
info.Main.PortDischargeCode = biz?.DischargePortCode;
info.Main.PortDischargeId = biz?.DischargePortId;
info.Main.PortLoad = biz?.LoadPort;
info.Main.PortLoadId = biz?.LoadPortId;
info.Main.PortLoadCode = biz?.LoadPortCode;
info.Main.CarrierId = biz?.Carrier;
info.Main.CarrierPK = biz?.CarrierId;
//info.Main.HBLNO = biz?.HBLNO;
//info.Main.BookingNo = biz?.BookingNo;
//info.Main.CustomsNum = biz?.CustomerNum;
}
info.Main.TaskDesp = info.Main.TaskDesp ?? info.Main.TaskTitle;
result = await ManagerService.InitTaskJob(info);
if (!result.Succeeded)
return result;
task = new BusinessTask
{
BusinessId = request.BusinessId,
BusinessType = request.BusinessType,
TaskType = request.TaskType,
TaskStatus = TaskStatusEnum.Create,
RecvUsers = string.Join(',', info.Main.RecvUserInfoList.Select(x => x.RecvUserId)) ?? string.Empty,
NextType = request.NextType,
CreateBy = long.Parse(User.UserId),
CreateTime = DateTime.Now
};
if (IsOrderType(request.TaskType) && !task.NextType.HasValue)
task.NextType = await GetNextTypeAsync(task);
await TenantDb.Insertable(task).ExecuteCommandAsync();
result = await OnTaskCreated(task);
if (!result.Succeeded)
return result;
//记录日志
await LogService.WriteLogAsync(task);
}
//审核任务需创建工作流
if (AuditTaskTypes.Contains(request.TaskType))
{
result = await CreateAndStartWorkflow(task);
if (!result.Succeeded)
return result;
if (updateFlag)
{
result = await SetTaskStatusAsync(new TaskUpdateRequest
{
BusinessId = request.BusinessId,
BusinessType = request.BusinessType,
TaskTypeName = request.TaskTypeName,
TaskStatus = TaskStatusEnum.Create
}, false);
if (!result.Succeeded)
return result;
}
}
if (useTransaction)
await TenantDb.Ado.CommitTranAsync();
return DataResult.Success;
}
catch (Exception ex)
{
if (useTransaction)
await TenantDb.Ado.RollbackTranAsync();
await ex.LogAsync(Db);
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
}
}
///
/// 创建并启动审批工作流
///
///
/// 同时变更任务执行人
///
protected internal async Task CreateAndStartWorkflow(BusinessTask task, bool changeMarker = true)
{
var template = await FindTemplateAsync(task.TaskType);
if (template == null)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TemplateNotFound));
var result = FlowService.Value.CreateFlowInstance(new CreateFlowInstanceReq
{
BusinessId = task.BusinessId,
BusinessType = task.BusinessType,
TemplateId = template.Id
});
//创建并启动实例
if (result.Succeeded)
{
var instance = result.Data as FlowInstance;
task.FlowId = instance!.Id;
await TenantDb.Updateable(task).UpdateColumns(x => x.FlowId).ExecuteCommandAsync();
if (instance.FlowStatus == FlowStatusEnum.Approve)
{
await SetTaskStatusAsync(new TaskUpdateRequest
{
BusinessId = task.BusinessId,
BusinessType = task.BusinessType,
RejectReason = instance.Note,
TaskTypeName = task.TaskType.ToString(),
TaskStatus = TaskStatusEnum.Complete
}, false);
}
else
{
result = FlowService.Value.StartFlowInstance(instance.Id.ToString());
instance = result.Data as FlowInstance;
if (result.Succeeded && changeMarker)
{
string[] ids = FlowInstanceService.GetMarkers(instance);
//变更任务接收人为所有审批执行人
var users = await FillInUserInfoAsync(ids.Select(long.Parse).ToArray());
result = await ManagerService.TransferTask(task.BusinessId, task.TaskType, users, TenantDb);
if (result.Succeeded)
{
task.RecvUsers = string.Join(",", ids);
await TenantDb.Updateable(task).UpdateColumns(x => x.RecvUsers).ExecuteCommandAsync();
}
}
}
result.Data = instance;
}
return result;
}
///
/// 当任务创建时调用
///
///
///
protected virtual Task OnTaskCreated(BusinessTask task)
{
return Task.FromResult(DataResult.Success);
}
///
/// 设置任务状态
///
///
/// 是否使用事务
///
public async Task SetTaskStatusAsync(TaskUpdateRequest request, bool useTransaction = true)
{
if (!await HasAuthorizedAsync())
return DataResult.FailedWithDesc(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.ModuleUnauthorized)));
if (useTransaction)
await TenantDb.Ado.BeginTranAsync();
try
{
BusinessTask task = await GetQuery(request.BusinessId, request.BusinessType, request.TaskType).FirstAsync();
if (task == null)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskNotExists));
if (task.TaskStatus == TaskStatusEnum.Complete)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskCompleted));
//if (task.TaskStatus == TaskStatusEnum.Cancel)
// return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskCancelled));
var result = await ManagerService.SetTaskStatusWithBsno(request.BusinessId, request.TaskType, request.TaskStatus, DateTime.Now);
if (!result.Succeeded)
return DataResult.Failed(result.Message, result.MultiCode);
//触发任务状态变更通知
if (task.TaskStatus != request.TaskStatus)
await OnTaskStatusChanged(request);
task.RejectReason = request.RejectReason;
//更新当前任务状态
task.TaskStatus = request.TaskStatus;
await TenantDb.Updateable(task).UpdateColumns(x => new { x.TaskStatus, x.RejectReason }).ExecuteCommandAsync();
if (task.TaskStatus == TaskStatusEnum.Complete && task.NextType.HasValue && request.AutoCreateNext)
{
//存在下一任务,则继续创建
var req = new TaskCreationRequest
{
BusinessId = request.BusinessId,
BusinessType = request.BusinessType,
TaskTypeName = task.NextType.Value.ToString()
};
result = await CreateTaskAsync(req, false);
if (!result.Succeeded)
return DataResult.Failed("创建下一关联任务时返回错误:" + result.Message, result.MultiCode);
}
//记录日志
await LogService.WriteLogAsync(request);
if (useTransaction)
await TenantDb.Ado.CommitTranAsync();
if (task.TaskStatus == TaskStatusEnum.Complete)//目前限制任务完成才触发
{
Dictionary? dic = null;
if (task.NextType == TaskBaseTypeEnum.WAIT_BOOKING)
{
dic = new Dictionary();
var param = await ClientParamService.Value.GetParamAsync(task.BusinessId, BookingSelector.Booking_Route,
(x, y) => x.CustomerId == y.ForwarderId);
dic[TaskFlowDataNameConst.ClientParam] = param;
}
await ActionService.TriggerActionAsync(task, additionalData: dic);
}
return DataResult.Success;
}
catch (Exception ex)
{
if (useTransaction)
await TenantDb.Ado.RollbackTranAsync();
await ex.LogAsync(Db);
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
}
}
///
/// 当任务状态发生变化时调用
///
///
///
protected virtual Task OnTaskStatusChanged(TaskUpdateRequest request)
{
return Task.CompletedTask;
}
///
/// 获取业务的任务信息
///
/// 业务ID
/// 业务类型
/// 任务类型
///
public async Task>> GetTasks(long id, BusinessType? businessType, params TaskBaseTypeEnum[] types)
{
var list = await TenantDb.Queryable().Where(x => x.BusinessId == id)
.WhereIF(businessType.HasValue, x => x.BusinessType == businessType)
.WhereIF(types != null && types.Length > 0, x => types.Contains(x.TaskType))
.Select().ToListAsync();
var result = DataResult>.Success(list);
result.Count = list.Count;
return result;
}
///
/// 返回指定类型的任务是否已存在
///
/// 业务ID
/// 业务类型
/// 任务类型
///
public async Task> ExistsAsync(long id, BusinessType businessType, TaskBaseTypeEnum type)
{
var value = await TenantDb.Queryable().AnyAsync(x =>
x.BusinessId == id && x.BusinessType == businessType && x.TaskType == type);
return DataResult.Success(value);
}
///
/// 返回任务交互模块是否已授权
///
///
public virtual async Task HasAuthorizedAsync()
{
long tid = long.Parse(User.TenantId);
var authStr = await Db.Queryable().ClearFilter(typeof(ITenantId)).Where(x => x.PermissionId == PERMISSION_ID && x.TenantId == tid &&
SqlFunc.Subqueryable().Where(spt => spt.PermissionId == x.PermissionId && x.TenantId == tid).Any())
.Select(x => x.AuthNum).FirstAsync();
if (authStr.IsNullOrEmpty())
return false;
var appSecret = await Db.Queryable().Where(x => x.Id == tid).Select(x => x.AppSecret).FirstAsync();
return int.TryParse(EncrypteHelper.DecryptData(authStr, appSecret), out int authNum) && authNum > 0;
}
///
/// 发起任务审核
///
///
/// 是否使用事务
///
public async Task SubmitAuditAsync(TaskRequest request, bool useTransaction = true)
{
var task = await GetQuery(request.BusinessId, request.BusinessType, request.TaskType).FirstAsync();
if (task == null)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.EmptyData));
if (task.TaskStatus == TaskStatusEnum.Complete)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskCompleted));
if (task.TaskStatus == TaskStatusEnum.Pending)
{
DataResult result;
if (task.TaskType == TaskBaseTypeEnum.WAIT_ORDER_AUDIT)
{
result = await CheckRulesAsync(request.BusinessId, request.BusinessType.Value, RuleEngineType.COMMON_ORDER_AUDIT);
if (!result.Succeeded)
return result;
}
if (useTransaction)
await TenantDb.Ado.BeginTranAsync();
try
{
var req = new TaskUpdateRequest
{
AutoCreateNext = false,
BusinessId = request.BusinessId,
BusinessType = request.BusinessType,
TaskStatus = TaskStatusEnum.Create,
TaskTypeName = request.TaskTypeName
};
//重置任务为待处理
result = await SetTaskStatusAsync(req, false);
if (!result.Succeeded)
return DataResult.Failed(result.Message, result.MultiCode);
//创建&启动工作流
var result2 = await CreateAndStartWorkflow(task, false);
if (!result2.Succeeded)
return result2;
await TenantDb.Updateable().SetColumns(x => x.TaskStatus == TaskStatusEnum.Create)
.Where(x => x.BusinessId == request.BusinessId && x.BusinessType == request.BusinessType && x.TaskType == request.TaskType)
.ExecuteCommandAsync();
//记录日志
await LogService.WriteLogAsync(req, "重新审批");
if (useTransaction)
await TenantDb.Ado.CommitTranAsync();
return result2;
}
catch (Exception ex)
{
if (useTransaction)
await TenantDb.Ado.RollbackTranAsync();
await ex.LogAsync(Db);
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
}
}
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskStatusNotSupported));
}
///
/// 撤销审核任务
///
///
/// 是否使用事务
///
public async Task WithdrawAsync(TaskRequest request, bool useTransaction = true)
{
if (!AuditTaskTypes.Contains(request.TaskType))
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskTypeNotSupported));
var task = await GetQuery(request.BusinessId, request.BusinessType, request.TaskType).Select(x => new
{
x.Id,
x.TaskStatus,
x.FlowId
}).FirstAsync();
if (task == null)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.EmptyData));
if (task.TaskStatus == TaskStatusEnum.Complete)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskCompleted));
if (!task.FlowId.HasValue)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.NotInFlows));
DateTime dt = DateTime.Now;
if (useTransaction)
await TenantDb.Ado.BeginTranAsync();
try
{
var result = await ManagerService.SetTaskStatusWithBsno(request.BusinessId, request.TaskType, TaskStatusEnum.Cancel, dt);
if (!result.Succeeded)
return result;
result = await FlowService.Value.WithdrawAsync([task.FlowId.Value], "用户撤销审核");
if (!result.Succeeded)
return result;
await TenantDb.Updateable().Where(x => x.Id == task.Id).SetColumns(
x => x.TaskStatus == TaskStatusEnum.Cancel).ExecuteCommandAsync();
await LogService.WriteLogAsync(new BusinessTaskLog
{
ActionType = ActionType.StatusChanged,
AuditStatus = FlowStatusEnum.Draft,
BusinessId = request.BusinessId,
BusinessType = request.BusinessType,
CreateBy = long.Parse(User.UserId),
CreateTime = dt,
TaskStatus = TaskStatusEnum.Cancel,
TaskType = request.TaskType
});
if (request.TaskType == TaskBaseTypeEnum.WAIT_ORDER_AUDIT)
{
await TenantDb.Updateable().SetColumns(x => x.BusinessStatusName == null)
.Where(x => x.Id == request.BusinessId).ExecuteCommandAsync();
}
if (useTransaction)
await TenantDb.Ado.CommitTranAsync();
return DataResult.Success;
}
catch (Exception ex)
{
if (useTransaction)
await TenantDb.Ado.RollbackTranAsync();
await ex.LogAsync(Db);
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
}
}
///
/// 任务审核
///
///
public async Task AuditAsync(TaskAuditRequest request)
{
var tasks = await TenantDb.Queryable().Where(x => x.TaskType == request.TaskType && request.Ids.Contains(x.BusinessId))
.WhereIF(request.BusinessType.HasValue, x => x.BusinessType == request.BusinessType.Value).ToListAsync();
if (tasks.Count == 0)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskNotExists));
if (tasks.Count != request.Ids.Length)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskCountNotMatch));
if (tasks.Exists(x => x.TaskStatus == TaskStatusEnum.Complete))
{
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskCompleted));
}
else if (tasks.Exists(x => x.TaskStatus != TaskStatusEnum.Create && x.TaskStatus != TaskStatusEnum.Pending))
{
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskAuditStatusError));
}
if (tasks.Exists(x => x.FlowId == null))
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.FlowNotFound));
//审核前判断是否为此任务的处理人
//var hasAuthor = await ManagerService.HasTaskHandleAuthorityWithBsno(tasks.Select(x => (x.BusinessId, x.TaskType)));
//if (!hasAuthor.Succeeded && hasAuthor.Data?.Count > 0)
//{
// if (tasks.Count == 1)
// {
// return DataResult.Failed(string.Format(
// MultiLanguageConst.GetDescription(MultiLanguageConst.TaskNotHaveAuthorSingle), string.Join("、", hasAuthor.Data)));
// }
// else
// {
// return DataResult.Failed(string.Format(
// MultiLanguageConst.GetDescription(MultiLanguageConst.TaskNotHaveAuthor), string.Join("、", hasAuthor.Data!)));
// }
//}
DataResult result = DataResult.Success;
var flowIds = tasks.Select(x => x.FlowId.Value);
var flowInstances = await Db.Queryable().Where(x => flowIds.Contains(x.Id)).ToListAsync();
foreach (var instance in flowInstances)
{
//如果当前审批为终审,则调用规则库进行校验
if (request.TaskType == TaskBaseTypeEnum.WAIT_ORDER_AUDIT && instance.GetMarkerList().Length == 1)
{
result = await CheckRulesAsync(instance.BusinessId, request.BusinessType.GetValueOrDefault(), RuleEngineType.COMMON_OCEAN_BOOKING);
if (!result.Succeeded)
return result;
}
result = FlowService.Value.AuditFlowInstance(new FlowAuditInfo
{
AuditNote = request.Remark,
Status = request.Result,
Instance = instance
});
if (!result.Succeeded)
return result;
var req = new TaskUpdateRequest
{
BusinessId = instance.BusinessId,
BusinessType = instance.BusinessType,
RejectReason = request.Remark,
TaskTypeName = request.TaskType.ToString(),
TaskStatus = request.Result == 1 ? TaskStatusEnum.Complete : TaskStatusEnum.Pending,
AutoCreateNext = true
};
//根据审批结果更新任务状态
await SetTaskStatusAsync(req);
if (instance.FlowStatus == FlowStatusEnum.Approve)
{
//终审通过且任务类型为审单,则生成费用
if (request.TaskType == TaskBaseTypeEnum.WAIT_ORDER_AUDIT && instance.IsCompleted)
{
UriBuilder builder = new(configuration["FeeService:BaseUrl"])
{
Path = configuration["FeeService:GenerateFees"]
};
string url = builder.ToString();
if (string.IsNullOrEmpty(url))
{
await LogService.WriteLogAsync(req, "未在配置文件中配置费用服务URL,无法根据费用模板生成费用");
continue;
}
string json = JsonConvert.SerializeObject(new BizItem
{
Id = req.BusinessId,
BusinessType = req.BusinessType.GetValueOrDefault()
});
Api.SendRequestAsync(HttpMethod.Post, url, json);
}
}
else if (instance.FlowStatus == FlowStatusEnum.Reject)
{
result.Message = MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.TaskRejected));
}
if (IsOrderType(request.TaskType))
result.Data = new { instance.IsCompleted, instance.FlowStatus };
}
return result;
}
///
/// 通知审批执行人变更
///
/// 回调信息
///
/// 为null时引发
public virtual async Task MarkerChangedAsync(MarkerChangedCallback callback)
{
ArgumentNullException.ThrowIfNull(callback, nameof(callback));
long userId = long.Parse(User.UserId);
var users = await FillInUserInfoAsync(userId);
var dt = DateTime.Now;
await ManagerService.SetTaskUserStatus(
callback.BusinessId,
callback.AuditType.GetValueOrDefault(),
TaskStatusEnum.Complete,
//callback.Status == FlowStatusEnum.Approve ? TaskStatusEnum.Complete : TaskStatusEnum.Pending
dt,
users);
//记录日志
await LogService.WriteLogAsync(new BusinessTaskLog
{
ActionType = ActionType.Audit,
AuditStatus = callback.Status,
BusinessId = callback.BusinessId,
BusinessType = callback.BusinessType.Value,
CreateBy = userId,
CreateTime = dt,
TaskStatus = TaskStatusEnum.Complete,
TaskType = callback.AuditType.GetValueOrDefault(),
RecvUsers = users.Count > 0 ? users[0].RecvUserName : null
});
}
///
/// 审批完成回调更新
///
/// 回调信息
///
/// 为null时引发
public virtual async Task UpdateBusinessAsync(FlowCallback callback)
{
ArgumentNullException.ThrowIfNull(callback, nameof(callback));
if (callback.AuditType == null || callback.BusinessType == null)
return;
string remark = "终审完成,审批结果为:" + callback.FlowStatus.GetDescription();
if (callback.FlowStatus == FlowStatusEnum.Reject)
{
var task = await GetQuery(callback.BusinessId, callback.BusinessType, callback.AuditType.Value).FirstAsync();
var request = new TaskCreationRequest
{
BusinessId = callback.BusinessId,
BusinessType = callback.BusinessType,
TaskTypeName = GetRejectedType(callback.AuditType.Value).ToString(),
RecvUserIdList = [task.CreateBy] //通知任务发起人
};
//创建驳回任务以进行通知
await CreateTaskAsync(request);
//更新任务描述为驳回原因
await SetTaskBaseDescription(callback.BusinessId, request.TaskType, callback.RejectReason!);
remark += ";驳回原因:" + callback.RejectReason;
}
long userId = long.Parse(User.UserId);
var users = await FillInUserInfoAsync(userId);
//记录日志
await LogService.WriteLogAsync(new BusinessTaskLog
{
ActionType = ActionType.Audit,
AuditStatus = callback.FlowStatus,
BusinessId = callback.BusinessId,
BusinessType = callback.BusinessType,
CreateBy = userId,
CreateTime = DateTime.Now,
TaskStatus = callback.FlowStatus == FlowStatusEnum.Approve ? TaskStatusEnum.Complete : TaskStatusEnum.Pending,
TaskType = callback.AuditType.GetValueOrDefault(),
RecvUsers = users.Count > 0 ? users[0].RecvUserName : null,
Remark = remark
});
}
async Task CheckRulesAsync(long bsId, BusinessType businessType, RuleEngineType ruleType)
{
var rulesReq = new RuleEngineReq();
var order = await TenantDb.Queryable().Where(x => x.Id == bsId).FirstAsync();
rulesReq.Main.BusinessInfo = order.Adapt();
rulesReq.Main.ProjectCode = [ruleType.ToString()];
var ruleResult = await RuleEngineService.Value.ExecuteSeaExportAuditRulesAsync(rulesReq);
if (string.Equals(ruleResult.Succ, bool.FalseString, StringComparison.OrdinalIgnoreCase))
{
return DataResult.Failed(ruleResult.Msg);
}
else if (ruleResult.Extra.DetailList?.Count > 0)
{
StringBuilder sb = new StringBuilder();
foreach (var item in ruleResult?.Extra.DetailList)
sb.Append(item.ResultName);
return DataResult.Failed(sb.ToString());
}
return DataResult.Success;
}
///
/// 获取给定任务的下一任务类型
///
/// 当前任务对象
///
protected async Task GetNextTypeAsync(BusinessTask current)
{
return await GetNextTypeAsync(current.BusinessId, current.BusinessType, current.TaskType);
}
///
/// 获取给定任务的下一任务类型
///
/// 业务ID
/// 业务类型
/// 当前任务类型
/// 是否现舱
///
protected async Task GetNextTypeAsync(long bsId, BusinessType? businessType, TaskBaseTypeEnum currentType, bool? hasCabin = null)
{
object? order = null;
if (businessType.HasValue)
order = await ActionService.GetBusinessDataAsync(bsId, businessType.Value);
TaskFlowRuner flowRuner = new(TenantDb, ServiceProvider);
var dataContext = new TaskFlowDataContext(
(TaskFlowDataNameConst.Business, order),
(nameof(hasCabin), hasCabin.HasValue ? hasCabin.ToString() : string.Empty)
);
return await flowRuner.GetWorkFlowNextConfigByTaskType(TaskBaseTypeEnum.WORK_FLOW_MAIN, dataContext, currentType);
}
///
/// 获取指定类型的业务关联任务
///
/// 业务ID
/// 业务类型
/// 任务类型
///
protected internal ISugarQueryable GetQuery(long id, BusinessType? businessType, params TaskBaseTypeEnum[] taskTypes)
{
return TenantDb.Queryable().Where(x => x.BusinessId == id)
.WhereIF(businessType.HasValue, x => x.BusinessType == businessType)
.WhereIF(taskTypes != null && taskTypes.Length > 0, x => taskTypes.Contains(x.TaskType));
}
///
/// 获取指定业务ID的任务
///
/// 任务类型
/// 业务类型
/// 业务ID
///
protected internal ISugarQueryable GetQuery(TaskBaseTypeEnum taskType, BusinessType? businessType, params long[] ids)
{
return TenantDb.Queryable().Where(x => x.TaskType == taskType && ids.Contains(x.BusinessId))
.WhereIF(businessType.HasValue, x => x.BusinessType == businessType);
}
///
/// 从任务配置中获取接收用户列表
///
/// 业务ID
/// 业务类型
/// 任务类型
///
protected internal async Task> GetRecvUsersAsync(long id, BusinessType? businessType, TaskBaseTypeEnum taskType)
{
var dic = await GetRecvUsersAsync(id, businessType, [taskType]);
return dic?.Count > 0 ? dic.FirstOrDefault().Value : [];
}
///
/// 从任务配置中获取接收用户列表
///
/// 业务ID
/// 业务类型
/// 任务类型
///
protected internal async Task>> GetRecvUsersAsync(long id, BusinessType? businessType, List taskTypes)
{
object? biz = null;
if (businessType.HasValue)
biz = await ActionService.GetBusinessDataAsync(id, businessType.Value);
var result = await TaskAllocationService.GetAllotUserBySeaExportId(taskTypes, id, new TaskFlowDataContext(
(TaskFlowDataNameConst.Business, biz)
));
return result.Succeeded ? result.Data : [];
}
internal async Task> FillInUserInfoAsync(params long[] ids)
{
return await Db.Queryable().Where(x => ids.Contains(x.Id)).Select(
x => new RecvUserInfo { RecvUserId = x.Id, RecvUserName = x.UserName }).ToListAsync();
}
///
/// 删除任务
///
/// 业务ID
/// 业务类型
/// 备注
/// 任务类型,不指定任务类型则删除全部任务
///
public async Task DeleteAsync(long id, BusinessType? businessType, string? remark = null, params TaskBaseTypeEnum[] taskTypes)
{
if (!await HasAuthorizedAsync())
return DataResult.SuccessedWithDesc(nameof(MultiLanguageConst.ModuleUnauthorized));
string[]? typeNames = taskTypes?.Select(x => x.ToString()).ToArray();
int rows = 0;
await TenantDb.Ado.BeginTranAsync();
try
{
rows = await Db.Deleteable().Where(x => x.BusinessId == id)
.WhereIF(businessType.HasValue, x => x.BusinessType == businessType)
.WhereIF(taskTypes != null && taskTypes.Length > 0, x => taskTypes.Contains(x.AuditType.Value))
.ExecuteCommandAsync();
rows += await TenantDb.Deleteable().Where(x => SqlFunc.Subqueryable().Where(
y => x.TaskId == y.Id && y.TASK_SOURCE == "WORK_FLOW" && y.OUT_BS_NO == id)
.WhereIF(typeNames != null && typeNames.Length > 0, x => typeNames.Contains(x.TASK_TYPE))
.Any()).ExecuteCommandAsync();
rows += await TenantDb.Deleteable().Where(x => x.TASK_SOURCE == "WORK_FLOW" && x.OUT_BS_NO == id)
.WhereIF(typeNames != null && typeNames.Length > 0, x => typeNames.Contains(x.TASK_TYPE))
.ExecuteCommandAsync();
rows += await TenantDb.Deleteable().Where(x => x.BusinessId == id)
.WhereIF(businessType.HasValue, x => x.BusinessType == businessType)
.WhereIF(typeNames != null && typeNames.Length > 0, x => taskTypes.Contains(x.TaskType))
.ExecuteCommandAsync();
if (string.IsNullOrEmpty(remark))
remark = "删除任务" + (typeNames != null && typeNames.Length > 0 ? $"【{string.Join(",", typeNames)}】,受影响行数:" + rows : string.Empty);
await LogService.WriteLogAsync(new BusinessTaskLog
{
BusinessId = id,
BusinessType = businessType,
ActionType = ActionType.Delete,
CreateBy = long.Parse(User.UserId),
CreateTime = DateTime.Now,
TaskType = TaskBaseTypeEnum.NOT_SPECIFIED,
Remark = remark
});
await TenantDb.Ado.CommitTranAsync();
return DataResult.Success;
}
catch (Exception ex)
{
await TenantDb.Ado.RollbackTranAsync();
await ex.LogAsync(Db);
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
}
}
///
/// 更新任务台描述
///
///
/// 业务ID
/// 任务类型
/// 描述信息
public async Task SetTaskBaseDescription(long id, TaskBaseTypeEnum taskType, string description)
{
await ManagerService.SetTaskBaseInfoPropertyWithBsno(id, taskType, x => x.TASK_DESP == description);
}
}
///
/// 校验规则类型
///
public enum RuleEngineType
{
///
/// 订单提交审核
///
COMMON_ORDER_AUDIT,
///
/// 订舱
///
COMMON_OCEAN_BOOKING
}
}