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.

462 lines
21 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using DS.Module.Core;
using DS.WMS.Core.Fee.Entity;
using DS.WMS.Core.Flow.Dtos;
using DS.WMS.Core.Flow.Entity;
using DS.WMS.Core.Flow.Method;
using DS.WMS.Core.Op.Entity;
using DS.WMS.Core.TaskInteraction.Dtos;
using DS.WMS.Core.TaskInteraction.Entity;
using DS.WMS.Core.TaskInteraction.Interface;
using DS.WMS.Core.TaskPlat.Dtos;
using Mapster;
using Masuit.Tools;
using Masuit.Tools.Systems;
namespace DS.WMS.Core.TaskInteraction.Method
{
/// <summary>
/// 费用审核任务
/// </summary>
public sealed class FeeTaskService : TaskService, IFeeTaskService
{
internal static readonly TaskBaseTypeEnum[] FeeTypes = [TaskBaseTypeEnum.FEE_AUDIT, TaskBaseTypeEnum.FEE_MODIFY_AUDIT, TaskBaseTypeEnum.FEE_DELETE_AUDIT];
/// <summary>
/// 初始化
/// </summary>
/// <param name="provider"></param>
public FeeTaskService(IServiceProvider provider) : base(provider)
{
}
/// <summary>
/// 创建关联任务
/// </summary>
/// <param name="request"></param>
/// <param name="useTransaction">是否使用事务</param>
/// <returns></returns>
public override 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));
}
DataResult result = DataResult.Success;
bool updateFlag = false;
var task = await GetQuery(request.BusinessId, request.BusinessType, request.TaskType).FirstAsync();
if (task != null && AuditTaskTypes.Contains(request.TaskType) && (task.TaskStatus == TaskStatusEnum.Pending || task.TaskStatus == TaskStatusEnum.Cancel))
updateFlag = true;
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);
}
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);
}
result = await CreateAndStartWorkflow(task, false);
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;
}
else //费用审核需拆分任务
{
var instance = result.Data as FlowInstance;
var ids = FlowInstanceService.GetMarkers(instance).Select(long.Parse).ToArray();
var recvUserList = await FillInUserInfoAsync(ids);
var fee = await TenantDb.Queryable<FeeRecord>().Where(x => x.Id == request.BusinessId)
.Select(x => new
{
x.Id,
x.BusinessId,
x.BusinessType
}).FirstAsync();
foreach (var item in recvUserList)
{
var copiedInfo = info.DeepClone();
copiedInfo.Head.BSNO = fee.BusinessId; //替换为费用关联的订单ID
copiedInfo.Main.RecvUserInfoList.Clear();
copiedInfo.Main.RecvUserInfoList.Add(item);
copiedInfo.Main.ExtData = new { fee.BusinessType, FeeId = fee.Id };
result = await ManagerService.InitTaskJob(copiedInfo);
if (!result.Succeeded)
{
await Db.Deleteable(instance).ExecuteCommandAsync();
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="request"></param>
/// <param name="useTransaction">是否使用事务</param>
/// <returns></returns>
public override 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();
//记录日志
await LogService.WriteLogAsync(request);
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 override 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));
}
DataResult result = DataResult.Success;
await TenantDb.Ado.BeginTranAsync();
try
{
var flowIds = tasks.Select(x => x.FlowId.Value);
var flowInstances = await Db.Queryable<FlowInstance>().Where(x => flowIds.Contains(x.Id)).ToListAsync();
foreach (var instance in flowInstances)
{
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 };
}
var fees = await TenantDb.Queryable<FeeRecord>().Where(x => request.Ids.Contains(x.Id))
.Select(x => new
{
x.BusinessId,
x.BusinessType,
x.Id
}).ToListAsync();
var bizList = fees.GroupBy(x => new { x.BusinessId, x.BusinessType }).ToList();
foreach (var biz in bizList)
{
var relativeFeeIds = biz.Select(x => x.Id).ToArray();
var relativeTasks = await GetFeeTasks(biz.Key.BusinessType, [biz.Key.BusinessId], relativeFeeIds);
if (relativeTasks.All(x => x.TaskStatus == TaskStatusEnum.Complete))
{
var userIdList = tasks.Where(x => relativeFeeIds.Contains(x.BusinessId)).SelectMany(x => x.RecvUserIdArray).Distinct().ToList();
//在此将费用关联的主任务设置为完成状态
result = await ManagerService.SetTaskStatusWithBsno(biz.Key.BusinessId, request.TaskType, TaskStatusEnum.Complete, DateTime.Now, false, userIdList: userIdList);
if (!result.Succeeded)
return result;
}
}
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="request"></param>
/// <param name="useTransaction">是否使用事务</param>
/// <returns></returns>
public override 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
{
var fees = await TenantDb.Queryable<FeeRecord>().Where(x => request.Ids.Contains(x.Id))
.Select(x => new
{
x.BusinessId,
x.BusinessType,
x.Id
}).ToListAsync();
var bizList = fees.GroupBy(x => new { x.BusinessId, x.BusinessType }).ToList();
foreach (var biz in bizList)
{
var relativeFeeIds = biz.Select(x => x.Id).ToArray();
var relativeTasks = await GetFeeTasks(biz.Key.BusinessType, [biz.Key.BusinessId], relativeFeeIds);
if (relativeTasks.All(x => x.TaskStatus == TaskStatusEnum.Cancel))
{
//在此将费用关联的主任务设置为完成状态
result = await ManagerService.SetTaskStatusWithBsno(biz.Key.BusinessId, request.TaskType, TaskStatusEnum.Cancel, DateTime.Now, false, userIdList: [.. task.RecvUserIdArray]);
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
});
result = await FlowService.Value.WithdrawAsync([task.FlowId.Value], "用户撤销审核");
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));
}
}
//获取指定业务的所有关联费用类任务
async Task<List<BusinessTask>> GetFeeTasks(BusinessType bsType, long[] bsIds, params long[] excludeFeeIds)
{
return await TenantDb.Queryable<BusinessTask>()
.InnerJoin<FeeRecord>((t, f) => t.BusinessId == f.Id)
.Where((t, f) => bsIds.Contains(f.BusinessId) && f.BusinessType == bsType && FeeTypes.Contains(t.TaskType) && t.RecvUsers.Contains(User.UserId) && t.TaskStatus != TaskStatusEnum.Cancel)
.WhereIF(excludeFeeIds.Length > 0, (t, f) => !excludeFeeIds.Contains(f.Id))
.Select((t, f) => new BusinessTask
{
Id = t.Id,
BusinessId = t.BusinessId,
TaskType = t.TaskType,
TaskStatus = t.TaskStatus,
RecvUsers = t.RecvUsers
}).ToListAsync();
}
}
}