|
|
using System.Text;
|
|
|
using DS.Module.Core;
|
|
|
using DS.Module.Core.Data;
|
|
|
using DS.Module.Core.Helpers;
|
|
|
using DS.Module.DjyRulesEngine;
|
|
|
using DS.Module.DjyServiceStatus;
|
|
|
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.Invoice.Dtos;
|
|
|
using DS.WMS.Core.Op.Dtos;
|
|
|
using DS.WMS.Core.Op.Entity;
|
|
|
using DS.WMS.Core.Op.Interface;
|
|
|
using DS.WMS.Core.Sys.Entity;
|
|
|
using DS.WMS.Core.TaskInteraction.Dtos;
|
|
|
using DS.WMS.Core.TaskInteraction.Entity;
|
|
|
using DS.WMS.Core.TaskInteraction.Interface;
|
|
|
using DS.WMS.Core.TaskInteraction.Method.ActionSelector;
|
|
|
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.DependencyInjection;
|
|
|
using SqlSugar;
|
|
|
|
|
|
namespace DS.WMS.Core.TaskInteraction.Method
|
|
|
{
|
|
|
/// <summary>
|
|
|
/// 任务交互服务
|
|
|
/// </summary>
|
|
|
public class TaskService : ServiceBase, ITaskService, IAuditTaskService
|
|
|
{
|
|
|
const long PERMISSION_ID = 1815294400855674880;
|
|
|
|
|
|
/// <summary>
|
|
|
/// 获取支持审核的任务类型
|
|
|
/// </summary>
|
|
|
public static readonly TaskBaseTypeEnum[] AuditTaskTypes;
|
|
|
|
|
|
/// <summary>
|
|
|
/// 通过任务台创建,而非通过工作流创建的任务类型,需手动调用函数来创建驳回任务,且重新提交时不创建工作流
|
|
|
/// </summary>
|
|
|
static readonly TaskBaseTypeEnum[] AuditTaskTypesManualReject;
|
|
|
|
|
|
static TaskService()
|
|
|
{
|
|
|
var dic = typeof(TaskBaseTypeEnum).GetDictionary();
|
|
|
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);
|
|
|
|
|
|
AuditTaskTypesManualReject = [TaskBaseTypeEnum.WAIT_SI];
|
|
|
|
|
|
// 这里把非工作流创建任务类型排除一下,防止虽然需要审核但是不需要创建工作流的任务创建工作流
|
|
|
AuditTaskTypes = enumValues.Select(x => (TaskBaseTypeEnum)Math.Abs(x.Value)).Distinct().Except(AuditTaskTypesManualReject).ToArray();
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 确定任务类型是否为业务订单任务
|
|
|
/// </summary>
|
|
|
/// <param name="taskType">任务类型</param>
|
|
|
/// <returns></returns>
|
|
|
public static bool IsOrderType(TaskBaseTypeEnum taskType)
|
|
|
{
|
|
|
int val = (int)taskType;
|
|
|
return val >= 200 && val <= 399;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 返回审核任务类型所对应的驳回类型
|
|
|
/// </summary>
|
|
|
/// <param name="auditTaskType">审核任务类型</param>
|
|
|
/// <returns></returns>
|
|
|
public static TaskBaseTypeEnum? GetRejectedType(TaskBaseTypeEnum auditTaskType)
|
|
|
{
|
|
|
if (!AuditTaskTypes.Contains(auditTaskType))
|
|
|
return null;
|
|
|
|
|
|
int negativeVal = -(int)auditTaskType;
|
|
|
return (TaskBaseTypeEnum)negativeVal;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 任务管理服务
|
|
|
/// </summary>
|
|
|
protected ITaskManageService ManagerService { get; private set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 日志服务
|
|
|
/// </summary>
|
|
|
protected ITaskLogService LogService { get; private set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 任务分配
|
|
|
/// </summary>
|
|
|
protected Lazy<ITaskAllocationService> TaskAllocationService { get; private set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 工作流服务
|
|
|
/// </summary>
|
|
|
protected Lazy<IClientFlowInstanceService> FlowService { get; private set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 动作服务
|
|
|
/// </summary>
|
|
|
protected IActionManagerService ActionService { get; private set; }
|
|
|
|
|
|
readonly Lazy<IClientParamService> ClientParamService;
|
|
|
|
|
|
/// <summary>
|
|
|
/// 规则库服务
|
|
|
/// </summary>
|
|
|
protected Lazy<IRuleEngineService> RuleEngineService { get; private set; }
|
|
|
/// <summary>
|
|
|
/// 海运出口公共服务
|
|
|
/// </summary>
|
|
|
protected Lazy<ISeaExportCommonService> seaComService { get; private set; }
|
|
|
/// <summary>
|
|
|
/// 大简云服务状态服务
|
|
|
/// </summary>
|
|
|
protected Lazy<IDjyServiceStatusService> djyStatusService { get; private set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 初始化
|
|
|
/// </summary>
|
|
|
/// <param name="provider"></param>
|
|
|
public TaskService(IServiceProvider provider) : base(provider)
|
|
|
{
|
|
|
ManagerService = provider.GetRequiredService<ITaskManageService>();
|
|
|
LogService = provider.GetRequiredService<ITaskLogService>();
|
|
|
ActionService = provider.GetRequiredService<IActionManagerService>();
|
|
|
|
|
|
TaskAllocationService = new Lazy<ITaskAllocationService>(provider.GetRequiredService<ITaskAllocationService>());
|
|
|
ClientParamService = new Lazy<IClientParamService>(provider.GetRequiredService<IClientParamService>());
|
|
|
FlowService = new Lazy<IClientFlowInstanceService>(provider.GetRequiredService<IClientFlowInstanceService>());
|
|
|
RuleEngineService = new Lazy<IRuleEngineService>(provider.GetRequiredService<IRuleEngineService>());
|
|
|
seaComService = new Lazy<ISeaExportCommonService>(provider.GetRequiredService<ISeaExportCommonService>());
|
|
|
djyStatusService = new Lazy<IDjyServiceStatusService>(provider.GetRequiredService<IDjyServiceStatusService>());
|
|
|
TenantDb.QueryFilter.Clear<IOrgId>();
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 批量创建关联任务
|
|
|
/// </summary>
|
|
|
/// <param name="request"></param>
|
|
|
/// <param name="useTransaction">是否使用事务</param>
|
|
|
/// <returns></returns>
|
|
|
public virtual async Task<DataResult> CreateMultipleTaskAsync(TaskCreationRequest request, bool useTransaction = true)
|
|
|
{
|
|
|
var ids = request.Ids;
|
|
|
ids ??= [request.BusinessId];
|
|
|
|
|
|
List<string> 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)));
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 创建关联任务
|
|
|
/// </summary>
|
|
|
/// <param name="request"></param>
|
|
|
/// <param name="useTransaction">是否使用事务</param>
|
|
|
/// <returns></returns>
|
|
|
public virtual async Task<DataResult> CreateTaskAsync(TaskCreationRequest request, bool useTransaction = true)
|
|
|
{
|
|
|
if (!await HasAuthorizedAsync())
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.ModuleUnauthorized));
|
|
|
|
|
|
////检查步骤类型是否重复
|
|
|
//if (request.Steps?.Count > 0)
|
|
|
//{
|
|
|
// if (request.Steps.Where(x => x.Type != StepType.NotSpecified).GroupBy(x => x.Type).Select(x => x.Key).Count() > 1)
|
|
|
// return DataResult.FailedWithDesc(nameof(MultiLanguageConst.DuplicateStepType));
|
|
|
|
|
|
// if (request.Steps.Any(x => x.Type == StepType.NotSpecified && string.IsNullOrEmpty(x.Name)))
|
|
|
// return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TypeOrName));
|
|
|
//}
|
|
|
|
|
|
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<SeaExport>().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;
|
|
|
}
|
|
|
|
|
|
long userId = long.Parse(User.UserId);
|
|
|
DateTime dtNow = DateTime.Now;
|
|
|
|
|
|
if (useTransaction)
|
|
|
await TenantDb.Ado.BeginTranAsync();
|
|
|
try
|
|
|
{
|
|
|
TaskManageOrderMessageInfo? info = null;
|
|
|
if (task == null)
|
|
|
{
|
|
|
info = await CreateMessageAsync(request);
|
|
|
|
|
|
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);
|
|
|
}
|
|
|
|
|
|
result = await ManagerService.InitTaskJob(info);
|
|
|
if (!result.Succeeded)
|
|
|
return result;
|
|
|
|
|
|
task = new BusinessTask
|
|
|
{
|
|
|
ParentId = request.ParentId,
|
|
|
BusinessId = request.BusinessId,
|
|
|
BusinessType = request.BusinessType,
|
|
|
ParentBusinessId = request.ParentBusinessId,
|
|
|
TaskType = request.TaskType,
|
|
|
TaskStatus = TaskStatusEnum.Create,
|
|
|
RecvUsers = string.Join(',', info.Main.RecvUserInfoList.Select(x => x.RecvUserId)) ?? string.Empty,
|
|
|
NextType = request.NextType,
|
|
|
CreateBy = userId,
|
|
|
CreateTime = dtNow
|
|
|
};
|
|
|
|
|
|
if (IsOrderType(request.TaskType) && !task.NextType.HasValue)
|
|
|
task.NextType = await GetNextTypeAsync(task);
|
|
|
|
|
|
await TenantDb.Insertable(task).ExecuteCommandAsync();
|
|
|
if (request.Steps?.Count > 0)
|
|
|
{
|
|
|
var steps = request.Steps.Select(x => new TaskStep
|
|
|
{
|
|
|
TaskId = task.Id,
|
|
|
IsCompleted = x.IsCompleted,
|
|
|
Name = x.Name,
|
|
|
Type = x.Type,
|
|
|
Priority = x.Priority ?? request.Steps.IndexOf(x),
|
|
|
CreateBy = userId,
|
|
|
CreateTime = dtNow
|
|
|
}).ToList();
|
|
|
|
|
|
await TenantDb.Insertable(steps).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();
|
|
|
|
|
|
if (result.Data is FlowInstance instance)
|
|
|
await Db.Deleteable(instance).ExecuteCommandAsync();
|
|
|
|
|
|
await ex.LogAsync(Db);
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 创建并启动审批工作流
|
|
|
/// </summary>
|
|
|
/// <param name="task"></param>
|
|
|
/// <param name="changeMarker">同时变更任务执行人</param>
|
|
|
/// <returns></returns>
|
|
|
protected async Task<DataResult> 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;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 当任务创建时调用
|
|
|
/// </summary>
|
|
|
/// <param name="task"></param>
|
|
|
/// <returns></returns>
|
|
|
protected virtual Task<DataResult> OnTaskCreated(BusinessTask task)
|
|
|
{
|
|
|
return Task.FromResult(DataResult.Success);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 设置任务状态
|
|
|
/// </summary>
|
|
|
/// <param name="request"></param>
|
|
|
/// <param name="useTransaction">是否使用事务</param>
|
|
|
/// <returns></returns>
|
|
|
public virtual async Task<DataResult> 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 (request.TaskStatus == TaskStatusEnum.Complete && await TenantDb.Queryable<BusinessTask>().AnyAsync(x => x.ParentId == task.Id && x.TaskStatus != request.TaskStatus))
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.UnfinishedItems));
|
|
|
|
|
|
////检查是否有未完成的任务步骤
|
|
|
//var steps = await TenantDb.Queryable<TaskStep>().Where(x => x.TaskId == task.Id && !x.IsCompleted)
|
|
|
// .Select(x => new { x.Type, x.Name }).ToListAsync();
|
|
|
//if (steps.Count > 0)
|
|
|
// return DataResult.Failed(
|
|
|
// MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.UnfinishedItems)) + ":" + string.Join("|", steps.Select(x => x.Type == StepType.NotSpecified ? x.Name : x.Type.GetDescription())),
|
|
|
// nameof(MultiLanguageConst.UnfinishedItems));
|
|
|
|
|
|
//触发任务状态变更通知
|
|
|
if (task.TaskStatus != request.TaskStatus)
|
|
|
await OnTaskStatusChanged(request);
|
|
|
|
|
|
task.UpdateBy = long.Parse(User.UserId);
|
|
|
task.UpdateTime = DateTime.Now;
|
|
|
task.RejectReason = request.RejectReason;
|
|
|
//更新当前任务状态
|
|
|
task.TaskStatus = request.TaskStatus;
|
|
|
await TenantDb.Updateable(task).UpdateColumns(x => new
|
|
|
{
|
|
|
x.TaskStatus,
|
|
|
x.RejectReason,
|
|
|
x.UpdateBy,
|
|
|
x.UpdateTime
|
|
|
}).ExecuteCommandAsync();
|
|
|
|
|
|
DataResult result;
|
|
|
if (request.ParentId.HasValue || request.ParentBusinessId.HasValue) //设置子任务状态
|
|
|
{
|
|
|
var parentTask = await TenantDb.Queryable<BusinessTask>().Where(x => x.BusinessType == request.BusinessType)
|
|
|
.WhereIF(request.ParentId.HasValue, x => x.Id == request.ParentId)
|
|
|
.WhereIF(request.ParentBusinessId.HasValue, x => x.BusinessId == request.ParentBusinessId && x.TaskType == request.ParentTaskType)
|
|
|
.Select(x => new
|
|
|
{
|
|
|
x.BusinessId,
|
|
|
x.TaskType
|
|
|
}).FirstAsync();
|
|
|
if (parentTask == null)
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.MainTaskNotFound));
|
|
|
|
|
|
result = await ManagerService.SetTaskStatusWithBsno(
|
|
|
parentTask.BusinessId, parentTask.TaskType,
|
|
|
request.TaskStatus, DateTime.Now, false, request.TaskDesc,
|
|
|
childBsno: request.BusinessId,
|
|
|
childTaskBaseTypeEnum: request.TaskType);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
result = await ManagerService.SetTaskStatusWithBsno(request.BusinessId, request.TaskType, request.TaskStatus, DateTime.Now, false, request.TaskDesc);
|
|
|
}
|
|
|
|
|
|
if (!result.Succeeded)
|
|
|
return DataResult.Failed(result.Message, result.MultiCode);
|
|
|
|
|
|
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 && IsOrderType(request.TaskType))//目前限制任务完成才触发
|
|
|
{
|
|
|
Dictionary<string, object>? dic = null;
|
|
|
if (task.NextType == TaskBaseTypeEnum.WAIT_BOOKING)
|
|
|
{
|
|
|
dic = [];
|
|
|
var param = await ClientParamService.Value.GetParamAsync<string>(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));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 设置任务步骤状态
|
|
|
/// </summary>
|
|
|
/// <param name="request"></param>
|
|
|
/// <param name="useTransaction">是否使用事务</param>
|
|
|
/// <returns></returns>
|
|
|
public virtual async Task<DataResult> SetStepsAsync(TaskRequest request, bool useTransaction = true)
|
|
|
{
|
|
|
if (!await HasAuthorizedAsync())
|
|
|
return DataResult.FailedWithDesc(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.ModuleUnauthorized)));
|
|
|
|
|
|
if (request.Steps == null || request.Steps.Count == 0)
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.SubTaskCannotNull));
|
|
|
|
|
|
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 (useTransaction)
|
|
|
await TenantDb.Ado.BeginTranAsync();
|
|
|
try
|
|
|
{
|
|
|
var allSteps = await TenantDb.Queryable<TaskStep>().Where(x => x.TaskId == task.Id && !x.IsCompleted).OrderBy(x => x.Priority)
|
|
|
.Select(x => new TaskStep
|
|
|
{
|
|
|
Id = x.Id,
|
|
|
Type = x.Type,
|
|
|
Name = x.Name,
|
|
|
IsCompleted = x.IsCompleted,
|
|
|
Priority = x.Priority
|
|
|
}).ToListAsync();
|
|
|
if (allSteps.Count == 0)
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskCompleted));
|
|
|
|
|
|
//获取未完成的优先级最高的步骤
|
|
|
var topSteps = allSteps.Where(x => !x.IsCompleted).GroupBy(x => x.Priority).OrderBy(x => x.Key).FirstOrDefault();
|
|
|
|
|
|
var stepTypes = request.Steps.Select(x => x.Type);
|
|
|
List<TaskStep> steps = [];
|
|
|
long userId = long.Parse(User.UserId);
|
|
|
DateTime dtNow = DateTime.Now;
|
|
|
foreach (var item in allSteps)
|
|
|
{
|
|
|
var reqStep = item.Id == 0 ?
|
|
|
request.Steps.Find(x => x.Type == item.Type || (x.Type == StepType.NotSpecified && x.Name == item.Name)) :
|
|
|
request.Steps.Find(x => x.Id == item.Id);
|
|
|
if (reqStep == null)
|
|
|
continue;
|
|
|
|
|
|
if (topSteps.Any(x => x.Priority > item.Priority))
|
|
|
return DataResult.Failed(
|
|
|
MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.HigherUnfinishedItems)) + ":" + string.Join("|", topSteps.Select(x => x.Type == StepType.NotSpecified ? x.Name : x.Type.GetDescription())),
|
|
|
nameof(MultiLanguageConst.HigherUnfinishedItems));
|
|
|
|
|
|
item.SetValue(reqStep.Value);
|
|
|
item.IsCompleted = reqStep.IsCompleted;
|
|
|
item.UpdateBy = userId;
|
|
|
item.UpdateTime = dtNow;
|
|
|
steps.Add(item);
|
|
|
}
|
|
|
|
|
|
await TenantDb.Updateable(steps).UpdateColumns(x => new
|
|
|
{
|
|
|
x.Value,
|
|
|
x.IsCompleted,
|
|
|
x.UpdateBy,
|
|
|
x.UpdateTime
|
|
|
}).ExecuteCommandAsync();
|
|
|
|
|
|
if (request.AutoSync && allSteps.Count > 0 && allSteps.Count == allSteps.Count(x => x.IsCompleted))
|
|
|
{
|
|
|
DataResult result = await SetTaskStatusAsync(new TaskUpdateRequest
|
|
|
{
|
|
|
ParentId = request.ParentId,
|
|
|
BusinessId = request.BusinessId,
|
|
|
BusinessType = request.BusinessType,
|
|
|
TaskTypeName = request.TaskTypeName,
|
|
|
TaskStatus = TaskStatusEnum.Complete
|
|
|
}, 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));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 当任务状态发生变化时调用
|
|
|
/// </summary>
|
|
|
/// <param name="request"></param>
|
|
|
/// <returns></returns>
|
|
|
protected virtual Task OnTaskStatusChanged(TaskUpdateRequest request)
|
|
|
{
|
|
|
return Task.CompletedTask;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 获取任务信息
|
|
|
/// </summary>
|
|
|
/// <param name="bsId">业务ID</param>
|
|
|
/// <param name="businessType">业务类型</param>
|
|
|
/// <param name="withSubTask">是否获取子任务</param>
|
|
|
/// <param name="types">任务类型</param>
|
|
|
/// <returns></returns>
|
|
|
public async Task<DataResult<List<BusinessTask>>> GetTasks(long bsId, BusinessType? businessType, bool withSubTask, params TaskBaseTypeEnum[] types)
|
|
|
{
|
|
|
var list = await TenantDb.Queryable<BusinessTask>().Includes(x => x.Steps).Where(x => x.BusinessId == bsId)
|
|
|
.WhereIF(businessType.HasValue, x => x.BusinessType == businessType)
|
|
|
.WhereIF(types != null && types.Length > 0, x => types.Contains(x.TaskType))
|
|
|
.ToListAsync();
|
|
|
|
|
|
if (list.Count > 0 && withSubTask)
|
|
|
{
|
|
|
var ids = list.Select(x => x.Id);
|
|
|
var list2 = await TenantDb.Queryable<BusinessTask>().Includes(x => x.Steps)
|
|
|
.Where(x => x.ParentId.HasValue && ids.Contains(x.ParentId.Value)).ToListAsync();
|
|
|
|
|
|
foreach (var item in list)
|
|
|
item.SubTasks = list2.FindAll(x => x.ParentId == item.Id);
|
|
|
}
|
|
|
|
|
|
var result = DataResult<List<BusinessTask>>.Success(list);
|
|
|
result.Count = list.Count;
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 返回指定类型的任务是否已存在
|
|
|
/// </summary>
|
|
|
/// <param name="bsId">业务ID</param>
|
|
|
/// <param name="businessType">业务类型</param>
|
|
|
/// <param name="type">任务类型</param>
|
|
|
/// <returns></returns>
|
|
|
public async Task<DataResult<bool>> ExistsAsync(long bsId, BusinessType businessType, TaskBaseTypeEnum type)
|
|
|
{
|
|
|
var value = await TenantDb.Queryable<BusinessTask>().AnyAsync(x =>
|
|
|
x.BusinessId == bsId && x.BusinessType == businessType && x.TaskType == type);
|
|
|
return DataResult<bool>.Success(value);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 返回任务交互模块是否已授权
|
|
|
/// </summary>
|
|
|
/// <returns></returns>
|
|
|
public async Task<bool> HasAuthorizedAsync()
|
|
|
{
|
|
|
long tid = long.Parse(User.TenantId);
|
|
|
var authStr = await Db.Queryable<SysTenantPermissionAuth>().ClearFilter(typeof(ITenantId)).Where(x => x.PermissionId == PERMISSION_ID && x.TenantId == tid &&
|
|
|
SqlFunc.Subqueryable<SysPermissionTenant>().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<SysTenant>().Where(x => x.Id == tid).Select(x => x.AppSecret).FirstAsync();
|
|
|
return int.TryParse(EncrypteHelper.DecryptData(authStr, appSecret), out int authNum) && authNum > 0;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 重新发起任务审核
|
|
|
/// </summary>
|
|
|
/// <param name="request"></param>
|
|
|
/// <param name="useTransaction">是否使用事务</param>
|
|
|
/// <returns></returns>
|
|
|
public virtual async Task<DataResult> 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);
|
|
|
|
|
|
//创建&启动工作流
|
|
|
DataResult result2;
|
|
|
if (!AuditTaskTypesManualReject.Contains(request.TaskType))
|
|
|
{
|
|
|
result2 = await CreateAndStartWorkflow(task, false);
|
|
|
if (!result2.Succeeded)
|
|
|
return result2;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
result2 = DataResult.Successed("操作成功", MultiLanguageConst.OperationSuccess);
|
|
|
}
|
|
|
|
|
|
await TenantDb.Updateable<BusinessTask>().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));
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 撤销审核任务
|
|
|
/// </summary>
|
|
|
/// <param name="request"></param>
|
|
|
/// <param name="useTransaction">是否使用事务</param>
|
|
|
/// <returns></returns>
|
|
|
public virtual async Task<DataResult> 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 BusinessTask
|
|
|
{
|
|
|
Id = x.Id,
|
|
|
TaskStatus = x.TaskStatus,
|
|
|
FlowId = x.FlowId,
|
|
|
RecvUsers = x.RecvUsers
|
|
|
}).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));
|
|
|
|
|
|
DataResult result;
|
|
|
DateTime dt = DateTime.Now;
|
|
|
long userId = long.Parse(User.UserId);
|
|
|
if (useTransaction)
|
|
|
await TenantDb.Ado.BeginTranAsync();
|
|
|
try
|
|
|
{
|
|
|
result = await ManagerService.SetTaskStatusWithBsno(request.BusinessId, request.TaskType, TaskStatusEnum.Cancel, dt, false);
|
|
|
if (!result.Succeeded)
|
|
|
return result;
|
|
|
|
|
|
result = await FlowService.Value.WithdrawAsync([task.FlowId.Value], "用户撤销审核");
|
|
|
if (!result.Succeeded)
|
|
|
return result;
|
|
|
|
|
|
await TenantDb.Updateable<BusinessTask>().Where(x => x.Id == task.Id)
|
|
|
.SetColumns(x => x.TaskStatus == TaskStatusEnum.Cancel)
|
|
|
.SetColumns(x => x.UpdateBy == userId)
|
|
|
.SetColumns(x => x.UpdateTime == dt)
|
|
|
.ExecuteCommandAsync();
|
|
|
await LogService.WriteLogAsync(new BusinessTaskLog
|
|
|
{
|
|
|
ActionType = ActionType.StatusChanged,
|
|
|
AuditStatus = FlowStatusEnum.Draft,
|
|
|
BusinessId = request.BusinessId,
|
|
|
BusinessType = request.BusinessType,
|
|
|
CreateBy = userId,
|
|
|
CreateTime = dt,
|
|
|
TaskStatus = TaskStatusEnum.Cancel,
|
|
|
TaskType = request.TaskType
|
|
|
});
|
|
|
//海运出口撤销审单 更新状态等操作
|
|
|
if (request.TaskType == TaskBaseTypeEnum.WAIT_ORDER_AUDIT)
|
|
|
{
|
|
|
//await TenantDb.Updateable<SeaExport>().SetColumns(x => x.BusinessStatusName == null)
|
|
|
//.Where(x => x.Id == request.BusinessId).ExecuteCommandAsync();
|
|
|
|
|
|
//删除提交货物状态
|
|
|
var goodsStatus = TenantDb.Queryable<BookingGoodsStatus>().First(x => x.StatusCode == "TIJIAO" && x.BusinessId == request.BusinessId);
|
|
|
if (goodsStatus != null)
|
|
|
await TenantDb.Updateable(goodsStatus).ExecuteCommandAsync();
|
|
|
|
|
|
var order = TenantDb.Queryable<SeaExport>().Filter(null, true).First(x => x.Id == request.BusinessId);
|
|
|
var oldOrder = order.Adapt<SeaExport>();
|
|
|
order.BusinessStatusName = string.Empty;
|
|
|
order.BusinessStatus = string.Empty;
|
|
|
await TenantDb.Updateable(order).UpdateColumns(x => new
|
|
|
{
|
|
|
x.BusinessStatusName,
|
|
|
x.BusinessStatus
|
|
|
}).EnableDiffLogEvent().ExecuteCommandAsync();
|
|
|
// 记录日志
|
|
|
await seaComService.Value.SaveSeaExportLogAsync(new SeaExportSaveLog()
|
|
|
{
|
|
|
OperateType = "Update",
|
|
|
OldOrder = oldOrder,
|
|
|
NewOrder = order,
|
|
|
SourceCode = "WithdrawAsync",
|
|
|
SourceName = "撤销审单更新",
|
|
|
}, TenantDb);
|
|
|
|
|
|
//更新大简云货物状态
|
|
|
var pushModel = new EmbedServiceProjectStatusDto
|
|
|
{
|
|
|
businessId = request.BusinessId.ToString(),
|
|
|
SourceType = 1,
|
|
|
StatusCodes = new List<EmbedServiceProjectStatusDetailDto> {
|
|
|
new EmbedServiceProjectStatusDetailDto{
|
|
|
StatusCode = "TIJIAO"
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
|
|
|
await djyStatusService.Value.CancelServiceStatus(pushModel);
|
|
|
|
|
|
}
|
|
|
|
|
|
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));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 任务审核
|
|
|
/// </summary>
|
|
|
/// <param name="request"></param>
|
|
|
public virtual async Task<DataResult> AuditAsync(TaskAuditRequest request)
|
|
|
{
|
|
|
var tasks = await TenantDb.Queryable<BusinessTask>().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 => !AuditTaskTypesManualReject.Contains(x.TaskType) && x.FlowId == null))
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.FlowNotFound));
|
|
|
|
|
|
DataResult result = DataResult.Success;
|
|
|
await TenantDb.Ado.BeginTranAsync();
|
|
|
try
|
|
|
{
|
|
|
var flowIds = tasks.Where(x => !AuditTaskTypesManualReject.Contains(x.TaskType)).Select(x => x.FlowId.Value);
|
|
|
var flowInstances = await Db.Queryable<FlowInstance>().Where(x => flowIds.Contains(x.Id)).ToListAsync();
|
|
|
foreach (var instance in flowInstances)
|
|
|
{
|
|
|
//如果当前审批为终审,则调用规则库进行校验
|
|
|
if (request.Result == 1 && 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 = await FlowService.Value.AuditAsync(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, false);
|
|
|
|
|
|
if (instance.FlowStatus == FlowStatusEnum.Reject)
|
|
|
result.Message = MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.TaskRejected));
|
|
|
|
|
|
if (IsOrderType(request.TaskType))
|
|
|
result.Data = new { instance.IsCompleted, instance.FlowStatus };
|
|
|
}
|
|
|
|
|
|
if (request.Result == 2)
|
|
|
{
|
|
|
var manualRejectTask = tasks.Where(x => AuditTaskTypesManualReject.Contains(x.TaskType)).ToList();
|
|
|
foreach (var item in manualRejectTask)
|
|
|
{
|
|
|
// 驳回工作流创建的任务时会自动通过http创建驳回任务,但是驳回非工作流创建的任务不会自动创建驳回任务,所以在下面手动调用
|
|
|
var req = new TaskUpdateRequest
|
|
|
{
|
|
|
BusinessId = item.BusinessId,
|
|
|
BusinessType = request.BusinessType.GetValueOrDefault(),
|
|
|
RejectReason = request.Remark,
|
|
|
TaskTypeName = request.TaskType.ToString(),
|
|
|
TaskStatus = request.Result == 1 ? TaskStatusEnum.Complete : TaskStatusEnum.Pending,
|
|
|
AutoCreateNext = false
|
|
|
};
|
|
|
//根据审批结果更新任务状态
|
|
|
await SetTaskStatusAsync(req);
|
|
|
|
|
|
// 创建相应的驳回任务
|
|
|
await UpdateBusinessAsync(new FlowCallback()
|
|
|
{
|
|
|
AuditType = request.TaskType,
|
|
|
BusinessId = item.BusinessId,
|
|
|
BusinessType = request.BusinessType.GetValueOrDefault(),
|
|
|
FlowStatus = FlowStatusEnum.Reject,
|
|
|
InstanceId = 0,
|
|
|
RejectReason = request.Remark,
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
|
|
|
await TenantDb.Ado.CommitTranAsync();
|
|
|
return result;
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
await TenantDb.Ado.RollbackTranAsync();
|
|
|
await ex.LogAsync(Db);
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 通知审批执行人变更
|
|
|
/// </summary>
|
|
|
/// <param name="callback">回调信息</param>
|
|
|
/// <returns></returns>
|
|
|
/// <exception cref="ArgumentNullException"><paramref name="callback"/>为null时引发</exception>
|
|
|
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
|
|
|
});
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 审批完成回调更新
|
|
|
/// </summary>
|
|
|
/// <param name="callback">回调信息</param>
|
|
|
/// <returns></returns>
|
|
|
/// <exception cref="ArgumentNullException"><paramref name="callback"/>为null时引发</exception>
|
|
|
public virtual async Task UpdateBusinessAsync(FlowCallback callback)
|
|
|
{
|
|
|
ArgumentNullException.ThrowIfNull(callback, nameof(callback));
|
|
|
if (callback.AuditType == 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, false);
|
|
|
|
|
|
//更新任务描述为驳回原因
|
|
|
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
|
|
|
});
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 创建任务台消息
|
|
|
/// </summary>
|
|
|
/// <param name="request">任务创建请求</param>
|
|
|
/// <returns>任务台消息</returns>
|
|
|
protected async Task<TaskManageOrderMessageInfo> CreateMessageAsync(TaskCreationRequest request)
|
|
|
{
|
|
|
var info = new TaskManageOrderMessageInfo
|
|
|
{
|
|
|
Head = new TaskManageOrderMessageHeadInfo
|
|
|
{
|
|
|
GID = Guid.NewGuid().ToString(),
|
|
|
BSNO = request.ParentBusinessId ?? request.BusinessId,
|
|
|
MessageType = "WORK_FLOW_TASK",
|
|
|
SenderId = "WorkFlow",
|
|
|
SenderName = "工作流平台",
|
|
|
ReceiverId = "TaskManage",
|
|
|
ReceiverName = "任务管理平台",
|
|
|
RequestDate = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
|
|
|
IsChild = request.ParentBusinessId.HasValue,
|
|
|
ChildBSNO = request.ParentBusinessId.HasValue ? request.BusinessId : 0
|
|
|
},
|
|
|
Main = new TaskManageOrderMessageMainInfo
|
|
|
{
|
|
|
TaskType = request.ParentTaskType ?? request.TaskType,
|
|
|
TaskSource = TaskSourceEnum.WORK_FLOW,
|
|
|
TaskTitle = request.TaskTitle,
|
|
|
TaskDesp = request.TaskDescription,
|
|
|
TaskUserId = User.UserId,
|
|
|
TaskUserName = User.UserName,
|
|
|
TaskTenatId = long.Parse(User.TenantId),
|
|
|
TaskTenatName = User.TenantName,
|
|
|
IsCheckExistsByTaskType = true,
|
|
|
ChildTaskType = request.TaskType
|
|
|
}
|
|
|
};
|
|
|
|
|
|
//仅为业务订单任务自动填充任务标题/描述
|
|
|
if (info.Main.TaskTitle.IsNullOrEmpty() && IsOrderType(request.TaskType))
|
|
|
{
|
|
|
var biz = await TenantDb.Queryable<SeaExport>().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;
|
|
|
|
|
|
return info;
|
|
|
}
|
|
|
|
|
|
async Task<DataResult> CheckRulesAsync(long bsId, BusinessType businessType, RuleEngineType ruleType)
|
|
|
{
|
|
|
var rulesReq = new RuleEngineReq();
|
|
|
var order = await TenantDb.Queryable<SeaExport>().Where(x => x.Id == bsId).FirstAsync();
|
|
|
rulesReq.Main.BusinessInfo = order.Adapt<RulesEngineOrderBookingMainBusinessInfo>();
|
|
|
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;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 获取给定任务的下一任务类型
|
|
|
/// </summary>
|
|
|
/// <param name="current">当前任务对象</param>
|
|
|
/// <returns></returns>
|
|
|
protected async Task<TaskBaseTypeEnum?> GetNextTypeAsync(BusinessTask current)
|
|
|
{
|
|
|
return await GetNextTypeAsync(current.BusinessId, current.BusinessType, current.TaskType);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 获取给定任务的下一任务类型
|
|
|
/// </summary>
|
|
|
/// <param name="bsId">业务ID</param>
|
|
|
/// <param name="businessType">业务类型</param>
|
|
|
/// <param name="currentType">当前任务类型</param>
|
|
|
/// <param name="hasCabin">是否现舱</param>
|
|
|
/// <returns></returns>
|
|
|
protected async Task<TaskBaseTypeEnum?> 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);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 获取指定类型的业务关联任务
|
|
|
/// </summary>
|
|
|
/// <param name="id">业务ID</param>
|
|
|
/// <param name="businessType">业务类型</param>
|
|
|
/// <param name="taskTypes">任务类型</param>
|
|
|
/// <returns></returns>
|
|
|
protected internal ISugarQueryable<BusinessTask> GetQuery(long id, BusinessType? businessType, params TaskBaseTypeEnum[] taskTypes)
|
|
|
{
|
|
|
return TenantDb.Queryable<BusinessTask>().Where(x => x.BusinessId == id)
|
|
|
.WhereIF(businessType.HasValue, x => x.BusinessType == businessType)
|
|
|
.WhereIF(taskTypes != null && taskTypes.Length > 0, x => taskTypes.Contains(x.TaskType));
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 从任务配置中获取接收用户列表
|
|
|
/// </summary>
|
|
|
/// <param name="id">业务ID</param>
|
|
|
/// <param name="businessType">业务类型</param>
|
|
|
/// <param name="taskType">任务类型</param>
|
|
|
/// <returns></returns>
|
|
|
protected internal async Task<List<RecvUserInfo>> GetRecvUsersAsync(long id, BusinessType? businessType, TaskBaseTypeEnum taskType)
|
|
|
{
|
|
|
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)
|
|
|
{
|
|
|
object? biz = null;
|
|
|
if (businessType.HasValue)
|
|
|
biz = await ActionService.GetBusinessDataAsync(id, businessType.Value);
|
|
|
|
|
|
var result = await TaskAllocationService.Value.GetAllotUserBySeaExportId(taskTypes, id, new TaskFlowDataContext(
|
|
|
(TaskFlowDataNameConst.Business, biz)
|
|
|
));
|
|
|
return result.Succeeded ? result.Data : [];
|
|
|
}
|
|
|
|
|
|
internal async Task<List<RecvUserInfo>> FillInUserInfoAsync(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();
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 删除任务
|
|
|
/// </summary>
|
|
|
/// <param name="id">业务ID</param>
|
|
|
/// <param name="businessType">业务类型</param>
|
|
|
/// <param name="remark">备注</param>
|
|
|
/// <param name="taskTypes">任务类型,不指定任务类型则删除全部任务</param>
|
|
|
/// <returns></returns>
|
|
|
public async Task<DataResult> 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<FlowInstance>().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<TaskBaseAllocation>().Where(x => SqlFunc.Subqueryable<TaskBaseInfo>().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<TaskBaseInfo>().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<TaskStep>().Where(x => SqlFunc.Subqueryable<BusinessTask>()
|
|
|
.Where(y => x.TaskId == y.BusinessId || x.TaskId == y.ParentBusinessId)
|
|
|
.WhereIF(businessType.HasValue, y => y.BusinessType == businessType)
|
|
|
.WhereIF(typeNames != null && typeNames.Length > 0, y => taskTypes.Contains(y.TaskType))
|
|
|
.Any()).ExecuteCommandAsync();
|
|
|
|
|
|
rows += await TenantDb.Deleteable<BusinessTask>().Where(x => x.BusinessId == id || x.ParentBusinessId == 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));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 更新任务台描述
|
|
|
/// </summary>
|
|
|
/// <returns></returns>
|
|
|
/// <param name="id">业务ID</param>
|
|
|
/// <param name="taskType">任务类型</param>
|
|
|
/// <param name="description">描述信息</param>
|
|
|
public async Task SetTaskBaseDescription(long id, TaskBaseTypeEnum taskType, string description)
|
|
|
{
|
|
|
await ManagerService.SetTaskBaseInfoPropertyWithBsno(id, taskType, null, null, x => x.TASK_DESP == description);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 校验规则类型
|
|
|
/// </summary>
|
|
|
public enum RuleEngineType
|
|
|
{
|
|
|
/// <summary>
|
|
|
/// 订单提交审核
|
|
|
/// </summary>
|
|
|
COMMON_ORDER_AUDIT,
|
|
|
|
|
|
/// <summary>
|
|
|
/// 订舱
|
|
|
/// </summary>
|
|
|
COMMON_OCEAN_BOOKING
|
|
|
}
|
|
|
}
|