You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

492 lines
20 KiB
C#

using DS.Module.Core;
using DS.Module.Core.Extensions;
using DS.Module.Core.Helpers;
using DS.WMS.Core.Fee.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.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.Sys.Entity;
using DS.WMS.Core.TaskPlat.Dtos;
using DS.WMS.Core.TaskPlat.Interface;
using Masuit.Tools.Systems;
using Microsoft.Extensions.DependencyInjection;
using SqlSugar;
namespace DS.WMS.Core.Op.Method.TaskInteraction
{
/// <summary>
/// 任务交互服务
/// </summary>
public abstract class TaskService : ServiceBase, ITaskService
{
const long PERMISSION_ID = 1815294400855674880;
/// <summary>
/// 任务管理服务
/// </summary>
protected ITaskManageService ManagerService { get; private set; }
/// <summary>
/// 工作流服务
/// </summary>
protected Lazy<IClientFlowInstanceService> FlowService { get; private set; }
/// <summary>
/// 初始化
/// </summary>
/// <param name="provider"></param>
protected TaskService(IServiceProvider provider) : base(provider)
{
ManagerService = provider.GetRequiredService<ITaskManageService>();
FlowService = new Lazy<IClientFlowInstanceService>(provider.GetRequiredService<IClientFlowInstanceService>());
}
/// <summary>
/// 获取给定任务的下一任务类型
/// </summary>
/// <param name="current">任务信息</param>
/// <returns></returns>
internal static TaskBaseTypeEnum? GetNextType(BusinessTask current)
{
if (current.TaskType == TaskBaseTypeEnum.WAIT_CHECKOUT_BILL) //流程的最后一步
return null;
int currentTypeVal = (int)current.TaskType;
if (currentTypeVal >= 300) //300开始的枚举值为可选服务项目不存在前后关联性
return null;
return (TaskBaseTypeEnum)(currentTypeVal + 1);
}
/// <summary>
/// 确保任务交互模块已授权
/// </summary>
/// <returns></returns>
protected virtual async Task<bool> EnsureModuleAuthorized()
{
//if (!await Db.Queryable<SysPermissionTenant>().AnyAsync(x => x.PermissionId == PERMISSION_ID))
// return false;
long tid = long.Parse(User.TenantId);
var authStr = await Db.Queryable<SysTenantPermissionAuth>().Where(x => x.PermissionId == PERMISSION_ID && x.TenantId == tid &&
SqlFunc.Subqueryable<SysPermissionTenant>().Where(spt => spt.PermissionId == x.PermissionId).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>
/// <returns></returns>
public async Task<DataResult> SubmitAuditAsync(TaskRequest request)
{
var task = await GetQuery(request.BusinessId, request.BusinessType, TaskBaseTypeEnum.WAIT_ORDER_AUDIT).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 || task.TaskStatus == TaskStatusEnum.Create)
{
//创建&启动工作流
var result = await Create_StartWorkflow(task);
if (!result.Succeeded)
return result;
if (task.TaskStatus != TaskStatusEnum.Create)
{
await TenantDb.Updateable<BusinessTask>().SetColumns(x => x.TaskStatus == TaskStatusEnum.Create)
.Where(x => x.BusinessId == request.BusinessId &&
x.BusinessType == request.BusinessType && x.TaskType == TaskBaseTypeEnum.WAIT_ORDER_AUDIT)
.ExecuteCommandAsync();
}
return result;
}
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskStatusNotSupported));
}
/// <summary>
/// 任务审核
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public async Task<DataResult> AuditAsync(AuditRequest request)
{
long id = request.Ids[0];
var task = await GetQuery(id, request.BusinessType.Value, TaskBaseTypeEnum.WAIT_ORDER_AUDIT).FirstAsync();
if (task == null)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.EmptyData));
if (task.TaskStatus == TaskStatusEnum.Complete)
{
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskCompleted));
}
else if (task.TaskStatus != TaskStatusEnum.Create && task.TaskStatus != TaskStatusEnum.Pending)
{
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskAuditStatusError));
}
if (task.FlowId == null)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.FlowNotFound));
return FlowService.Value.AuditFlowInstance(new FlowAuditInfo
{
AuditNote = request.Remark,
Status = request.Result,
Instance = await Db.Queryable<FlowInstance>().FirstAsync(x => x.Id == task.FlowId.Value)
});
}
/// <summary>
/// 创建关联任务
/// </summary>
/// <param name="request"></param>
/// <param name="useTransaction">是否使用事务</param>
/// <returns></returns>
public async Task<DataResult> CreateTaskAsync(TaskCreationRequest request, bool useTransaction = true)
{
if (!await EnsureModuleAuthorized())
return DataResult.SuccessedWithDesc(nameof(MultiLanguageConst.ModuleUnauthorized));
var task = await GetQuery(request.BusinessId, request.BusinessType, request.TaskType).FirstAsync();
if (task != null && task.TaskStatus != TaskStatusEnum.Cancel)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskExists));
long tenatId = long.Parse(User.TenantId);
string tenatName = Db.Queryable<SysTenant>().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
}
};
if (request.RecvUserIdList == null || request.RecvUserIdList.Length == 0)
{
info.Main.RecvUserInfoList = [new RecvUserInfo { RecvUserId = long.Parse(User.UserId), RecvUserName = User.UserName }];
}
else
{
info.Main.RecvUserInfoList = await GetRecvUsers(request.RecvUserIdList);
}
if (info.Main.TaskTitle.IsNullOrEmpty())
{
var biz = await TenantDb.Queryable<SeaExport>().Select(x => new
{
x.Id,
x.MBLNO,
x.Vessel,
x.Voyno,
x.ETD,
}).FirstAsync(x => x.Id == request.BusinessId);
info.Main.TaskDesp = info.Main.TaskTitle = $"{request.TaskType.GetDescription()} {biz.Vessel} {biz.Voyno} ETD:{biz.ETD?.ToString("yyyy-MM-dd")} BLNo:{biz.MBLNO}";
}
if (useTransaction)
await TenantDb.Ado.BeginTranAsync();
try
{
var 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)),
CreateBy = long.Parse(User.UserId),
CreateTime = DateTime.Now
};
task.NextType = GetNextType(task);
await TenantDb.Insertable(task).ExecuteCommandAsync();
//待审核,需创建工作流
if (task.TaskType == TaskBaseTypeEnum.WAIT_ORDER_AUDIT)
{
result = await Create_StartWorkflow(task);
if (!result.Succeeded)
return result;
}
result = await OnTaskCreated(task);
if (!result.Succeeded)
return result;
if (useTransaction)
await TenantDb.Ado.CommitTranAsync();
return result;
}
catch (Exception ex)
{
if (useTransaction)
await TenantDb.Ado.RollbackTranAsync();
await ex.LogAsync(Db);
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
}
}
/// <summary>
/// 创建并启动审批工作流
/// </summary>
/// <param name="task"></param>
/// <returns></returns>
protected internal async Task<DataResult> Create_StartWorkflow(BusinessTask task)
{
var template = await FindTemplateAsync(AuditType.SeaExport);
if (template == null)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TemplateNotFound));
var result = FlowService.Value.CreateFlowInstance(new CreateFlowInstanceReq
{
BusinessId = task.BusinessId,
BusinessType = BusinessType.OceanShippingExport,
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();
result = FlowService.Value.StartFlowInstance(instance.Id.ToString());
instance = result.Data as FlowInstance;
if (result.Succeeded)
{
string[] ids = FlowInstanceService.GetNextMarkers(instance);
//变更任务接收人为审批执行人
await UpdateReceiverAsync(new MakerChangedCallback
{
BusinessId = task.BusinessId,
BusinessType = task.BusinessType,
InstanceId = instance.Id,
Type = instance.Type,
NextUserId = ids.Select(long.Parse).ToArray()
});
}
}
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 async Task<DataResult> SetTaskStatusAsync(TaskUpdateRequest request, bool useTransaction = true)
{
if (!await EnsureModuleAuthorized())
return DataResult.SuccessedWithDesc(nameof(MultiLanguageConst.ModuleUnauthorized));
if (useTransaction)
await TenantDb.Ado.BeginTranAsync();
try
{
var result = await ManagerService.SetTaskStatus(request.BusinessId, request.TaskType, request.TaskStatus, DateTime.Now);
if (!result.Succeeded)
return result;
BusinessTask 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.Cancel)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskCancelled));
//触发任务状态变更通知
if (task.TaskStatus != request.TaskStatus)
await OnTaskStatusChanged(request);
//更新当前任务状态
task.TaskStatus = request.TaskStatus;
if (task.TaskType == TaskBaseTypeEnum.WAIT_ORDER_AUDIT)
task.FlowId = null;
await TenantDb.Updateable(task).UpdateColumns(x => new { x.TaskStatus, x.FlowId }).ExecuteCommandAsync();
if (task.TaskStatus == TaskStatusEnum.Complete)
{
//若存在下一任务,则继续创建
if (task.NextType.HasValue && request.AutoCreateNext)
{
var req = new TaskCreationRequest
{
BusinessId = request.BusinessId,
BusinessType = request.BusinessType,
TaskType = task.NextType.Value,
RecvUserIdList = task.RecvUserIdArray,
};
await CreateTaskAsync(req, false);
}
}
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="callback">回调信息</param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"><paramref name="callback"/>为null时引发</exception>
public virtual async Task UpdateReceiverAsync(MakerChangedCallback callback)
{
ArgumentNullException.ThrowIfNull(callback, nameof(callback));
if (callback.NextUserId == null)
return;
var users = await GetRecvUsers(callback.NextUserId);
var result = await ManagerService.TransferTask(callback.BusinessId, TaskBaseTypeEnum.WAIT_ORDER_AUDIT, users);
if (!result.Succeeded)
{
await new ApplicationException($"任务API({nameof(ManagerService.TransferTask)})调用失败:" + result.Message).LogAsync(Db);
return;
}
string recvUser = string.Join(',', callback.NextUserId);
await TenantDb.Updateable<BusinessTask>().Where(x => x.BusinessId == callback.BusinessId &&
x.BusinessType == callback.BusinessType && x.TaskType == TaskBaseTypeEnum.WAIT_ORDER_AUDIT)
.SetColumns(x => x.RecvUsers == recvUser)
.ExecuteCommandAsync();
}
/// <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));
//根据审批结果更新任务状态
await SetTaskStatusAsync(new TaskUpdateRequest
{
BusinessId = callback.BusinessId,
BusinessType = callback.BusinessType.Value,
TaskType = TaskBaseTypeEnum.WAIT_ORDER_AUDIT,
TaskStatus = callback.FlowStatus == FlowStatusEnum.Approve ? TaskStatusEnum.Complete : TaskStatusEnum.Pending,
AutoCreateNext = callback.FlowStatus == FlowStatusEnum.Approve
});
if (callback.FlowStatus == FlowStatusEnum.Reject)
{
//创建审单驳回任务以进行通知
var task = await GetQuery(callback.BusinessId, callback.BusinessType.Value, TaskBaseTypeEnum.WAIT_ORDER_AUDIT).FirstAsync();
await CreateTaskAsync(new TaskCreationRequest
{
BusinessId = callback.BusinessId,
BusinessType = callback.BusinessType.GetValueOrDefault(),
TaskType = TaskBaseTypeEnum.ORDER_AUDIT_REJECTED,
RecvUserIdList = [task.CreateBy] //通知任务发起人
});
}
}
/// <summary>
/// 获取指定类型的业务关联任务
/// </summary>
/// <param name="id">业务ID</param>
/// <param name="businessType">业务类型</param>
/// <param name="taskType">任务类型</param>
/// <returns></returns>
protected internal ISugarQueryable<BusinessTask> GetQuery(long id, BusinessType businessType, TaskBaseTypeEnum taskType)
{
return TenantDb.Queryable<BusinessTask>().Where(x =>
x.BusinessId == id && x.BusinessType == businessType && x.TaskType == taskType);
}
/// <summary>
/// 获取任务接收用户列表
/// </summary>
/// <param name="ids">用户ID</param>
/// <returns></returns>
protected internal async Task<List<RecvUserInfo>> GetRecvUsers(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();
}
}
}