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#

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;
1 month ago
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);
}
1 month ago
result = await CreateAndStartWorkflow(task, false);
if (!result.Succeeded)
return result;
if (updateFlag)
{
1 month ago
result = await SetTaskStatusAsync(new TaskUpdateRequest
{
BusinessId = request.BusinessId,
BusinessType = request.BusinessType,
TaskTypeName = request.TaskTypeName,
TaskStatus = TaskStatusEnum.Create
}, false);
if (!result.Succeeded)
return result;
1 month ago
}
else //费用审核需拆分任务
{
var instance = result.Data as FlowInstance;
var ids = FlowInstanceService.GetMarkers(instance).Select(long.Parse).ToArray();
var recvUserList = await FillInUserInfoAsync(ids);
1 month ago
var fee = await TenantDb.Queryable<FeeRecord>().Where(x => x.Id == request.BusinessId)
.Select(x => new
{
1 month ago
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 };
1 month ago
result = await ManagerService.InitTaskJob(copiedInfo);
if (!result.Succeeded)
{
1 month ago
await Db.Deleteable(instance).ExecuteCommandAsync();
return result;
}
}
}
1 month ago
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));
}
}
//获取指定业务的所有关联费用类任务
1 month ago
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();
}
}
}