|
|
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();
|
|
|
}
|
|
|
}
|
|
|
}
|