using Aop.Api.Domain;
|
using FlexJobApi.Core;
|
using Furion.DatabaseAccessor;
|
using Furion.DistributedIDGenerator;
|
using Furion.FriendlyException;
|
using Mapster;
|
using MediatR;
|
using Microsoft.EntityFrameworkCore;
|
using System;
|
using System.Collections.Generic;
|
using System.Linq;
|
using System.Text;
|
using System.Threading.Tasks;
|
using TaskInfo = FlexJobApi.Core.TaskInfo;
|
|
namespace FlexJobApi.FlexJobServer.Application
|
{
|
/// <summary>
|
/// 任务命令处理器
|
/// </summary>
|
public class TaskInfoCommandHandler(
|
IRepository<TaskInfo> rep,
|
IRepository<EnterpriseWallet> repEnterpriseWallet,
|
AlipayUtils alipayUtils
|
) :
|
IRequestHandler<SaveTaskInfoCommand, Guid>,
|
IRequestHandler<SetTaskInfoReleaseStatusCommand, int>,
|
IRequestHandler<SetTaskInfoRecommendStatusCommand, int>,
|
IRequestHandler<DeleteTaskInfoCommand, int>,
|
IRequestHandler<SureTaskSettlementOrderCommand, Guid>,
|
IRequestHandler<RevokeTaskSettlementOrderCommand, Guid>,
|
IRequestHandler<SureTaskSettlementCommand, Guid>
|
{
|
private readonly IRepository<TaskInfo> rep = rep;
|
private readonly IRepository<EnterpriseWallet> repEnterpriseWallet = repEnterpriseWallet;
|
private readonly AlipayUtils alipayUtils = alipayUtils;
|
|
/// <summary>
|
/// 保存任务
|
/// </summary>
|
/// <param name="request"></param>
|
/// <param name="cancellationToken"></param>
|
/// <returns></returns>
|
/// <exception cref="NotImplementedException"></exception>
|
[UnitOfWork]
|
public async Task<Guid> Handle(SaveTaskInfoCommand request, CancellationToken cancellationToken)
|
{
|
var logier = JwtUtils.GetCurrentLogier();
|
if (logier.EnterpriseId == null) throw Oops.Oh(EnumErrorCodeType.s400, "当前登录用户必须为企业用户才可以创建任务");
|
var entity = await request.SaveData<TaskInfo, SaveTaskInfoCommand>(
|
q =>
|
{
|
q = TaskInfoRepository.GetQueryable(rep, false)
|
.Include(it => it.Benefits)
|
.Include(it => it.CredentialLimits);
|
return q;
|
},
|
null,
|
(entity) =>
|
{
|
if (request.Id == null)
|
{
|
entity.EnterpriseId = logier.EnterpriseId.Value;
|
entity.Status = EnumTaskStatus.Wait;
|
entity.ReleaseStatus = EnumTaskReleaseStatus.InProcess;
|
entity.RecommendStatus = EnumTaskRecommendStatus.No;
|
BuildCode(entity).Wait();
|
}
|
request.Adapt(entity);
|
entity.Benefits = request.Benefits
|
.Select(it => new TaskInfoBenefit
|
{
|
BenefitCode = it
|
})
|
.ToList();
|
entity.CredentialLimits = request.CredentialLimits
|
.Select(it => new TaskInfoCredentialLimit
|
{
|
TypeCode = it
|
})
|
.ToList();
|
},
|
cancellationToken);
|
return entity.Id;
|
}
|
|
/// <summary>
|
/// 设置任务发布状态
|
/// </summary>
|
/// <param name="request"></param>
|
/// <param name="cancellationToken"></param>
|
/// <returns></returns>
|
public async Task<int> Handle(SetTaskInfoReleaseStatusCommand request, CancellationToken cancellationToken)
|
{
|
var entities = await TaskInfoRepository.GetQueryable(rep, false)
|
.Where(it => request.Ids.Contains(it.Id))
|
.ToListAsync();
|
foreach (var entity in entities)
|
{
|
entity.ReleaseStatus = request.ReleaseStatus;
|
}
|
await rep.UpdateAsync(entities);
|
return entities.Count;
|
}
|
|
/// <summary>
|
/// 设置任务是否推荐
|
/// </summary>
|
/// <param name="request"></param>
|
/// <param name="cancellationToken"></param>
|
/// <returns></returns>
|
public async Task<int> Handle(SetTaskInfoRecommendStatusCommand request, CancellationToken cancellationToken)
|
{
|
var entities = await TaskInfoRepository.GetQueryable(rep, false)
|
.Where(it => request.Ids.Contains(it.Id) && it.RecommendStatus != request.RecommendStatus)
|
.ToListAsync();
|
if (entities.IsNotNull())
|
{
|
foreach (var entity in entities)
|
{
|
entity.RecommendStatus = request.RecommendStatus;
|
if (entity.RecommendStatus == EnumTaskRecommendStatus.Yes)
|
{
|
entity.RecommendTime = DateTime.Now;
|
}
|
}
|
await rep.UpdateAsync(entities);
|
}
|
return entities.Count;
|
}
|
|
/// <summary>
|
/// 删除任务
|
/// </summary>
|
/// <param name="request"></param>
|
/// <param name="cancellationToken"></param>
|
/// <returns></returns>
|
public Task<int> Handle(DeleteTaskInfoCommand request, CancellationToken cancellationToken)
|
{
|
return request.DeleteData<TaskInfo>(
|
q =>
|
{
|
q = TaskInfoRepository.GetQueryable(rep, false);
|
if (q.AsNoTracking().Any(it => request.Ids.Contains(it.Id) && it.Status == EnumTaskStatus.Complete))
|
{
|
throw Oops.Oh(EnumErrorCodeType.s510, "已安排的任务无法删除");
|
}
|
return q;
|
}, cancellationToken);
|
}
|
|
/// <summary>
|
/// 确认结算单
|
/// </summary>
|
/// <param name="request"></param>
|
/// <param name="cancellationToken"></param>
|
/// <returns></returns>
|
public async Task<Guid> Handle(SureTaskSettlementOrderCommand request, CancellationToken cancellationToken)
|
{
|
var entity = await TaskInfoRepository.GetQueryable(rep, false)
|
.Include(it => it.TaskInfoUsers)
|
.Where(it => it.Id == request.TaskInfoId)
|
.FirstOrDefaultAsync();
|
if (entity == null) throw Oops.Oh(EnumErrorCodeType.s404, "任务");
|
if (entity.SettlementStatus == EnumTaskSettlementStatus.InProcess) throw Oops.Oh(EnumErrorCodeType.s510, "结算中不可修改,请先撤回");
|
if (entity.SettlementStatus == EnumTaskSettlementStatus.Completed) throw Oops.Oh(EnumErrorCodeType.s510, "已结算不可修改");
|
entity.SettlementOrderStatus = EnumTaskSettlementOrderStatus.Completed;
|
entity.SettlementOrderUrl = request.SettlementOrderUrl;
|
entity.SettlementOrderName = entity.SettlementOrderUrl.Substring(entity.SettlementOrderUrl.LastIndexOf("/") + 1);
|
entity.SettlementStatus = EnumTaskSettlementStatus.Wait;
|
entity.SettlementUserCount = request.TaskInfoUsers.Count;
|
entity.SettlementAmount = request.TaskInfoUsers.Sum(it => it.SettlementAmount ?? 0);
|
entity.ActualSettlementAmount = request.TaskInfoUsers.Sum(it => it.ActualSettlementAmount ?? 0);
|
foreach (var model in request.TaskInfoUsers)
|
{
|
var user = entity.TaskInfoUsers.FirstOrDefault(it => it.Id == model.Id);
|
if (user == null) throw Oops.Oh(EnumErrorCodeType.s404, $"灵工{model.Name}");
|
if (user.SettlementStatus == EnumTaskSettlementStatus.InProcess) throw Oops.Oh(EnumErrorCodeType.s510, $"{model.Name}结算中不可修改,请先撤回");
|
if (user.SettlementStatus == EnumTaskSettlementStatus.Completed) throw Oops.Oh(EnumErrorCodeType.s510, $"{model.Name}已结算不可修改");
|
if (user.CheckReceiveStatus != EnumTaskCheckReceiveStatus.Completed) throw Oops.Oh(EnumErrorCodeType.s510, $"{model.Name}未验收");
|
if (model.SettlementAmount < 0) throw Oops.Oh(EnumErrorCodeType.s510, $"{model.Name}结算金额不可负数");
|
if (model.ActualSettlementAmount < 0) throw Oops.Oh(EnumErrorCodeType.s510, $"{model.Name}实发金额不可负数");
|
if (model.ActualSettlementAmount > 0 && model.ActualSettlementAmount < 1) throw Oops.Oh(EnumErrorCodeType.s510, $"{model.Name}实发金额不可小于1元");
|
user.Bank = model.Bank;
|
user.BankBranch = model.BankBranch;
|
user.ReceiveAccount = model.ReceiveAccount;
|
user.SettlementAmount = model.SettlementAmount;
|
user.ActualSettlementAmount = model.ActualSettlementAmount;
|
user.SettlementStatus = EnumTaskSettlementStatus.Wait;
|
}
|
await rep.UpdateAsync(entity);
|
return entity.Id;
|
}
|
|
/// <summary>
|
/// 撤回结算
|
/// </summary>
|
/// <param name="request"></param>
|
/// <param name="cancellationToken"></param>
|
/// <returns></returns>
|
public async Task<Guid> Handle(RevokeTaskSettlementOrderCommand request, CancellationToken cancellationToken)
|
{
|
var entity = await TaskInfoRepository.GetQueryable(rep, false)
|
.Include(it => it.TaskInfoUsers)
|
.Where(it => it.Id == request.TaskInfoId)
|
.FirstOrDefaultAsync();
|
if (entity == null) throw Oops.Oh(EnumErrorCodeType.s404, "任务");
|
if (entity.SettlementStatus == EnumTaskSettlementStatus.Wait) throw Oops.Oh(EnumErrorCodeType.s510, "未开始结算,请先上传结算单并确认");
|
if (entity.SettlementStatus == EnumTaskSettlementStatus.Completed) throw Oops.Oh(EnumErrorCodeType.s510, "已结算不可撤回");
|
entity.SettlementStatus = EnumTaskSettlementStatus.Wait;
|
foreach (var user in entity.TaskInfoUsers)
|
{
|
if (user.SettlementStatus == EnumTaskSettlementStatus.InProcess)
|
{
|
user.SettlementStatus = EnumTaskSettlementStatus.Wait;
|
}
|
}
|
await rep.UpdateAsync(entity);
|
return entity.Id;
|
}
|
|
/// <summary>
|
/// 确认结算
|
/// </summary>
|
/// <param name="request"></param>
|
/// <param name="cancellationToken"></param>
|
/// <returns></returns>
|
public async Task<Guid> Handle(SureTaskSettlementCommand request, CancellationToken cancellationToken)
|
{
|
var logier = JwtUtils.GetCurrentLogier();
|
var entity = await TaskInfoRepository.GetQueryable(rep, false, logier)
|
.Include(it => it.TaskInfoUsers)
|
.Where(it => it.Id == request.TaskInfoId)
|
.FirstOrDefaultAsync();
|
if (entity == null) throw Oops.Oh(EnumErrorCodeType.s404, "任务");
|
if (entity.SettlementOrderStatus != EnumTaskSettlementOrderStatus.Completed) throw Oops.Oh(EnumErrorCodeType.s510, "请先上传结算单并确认");
|
if (entity.SettlementStatus == EnumTaskSettlementStatus.Wait) throw Oops.Oh(EnumErrorCodeType.s510, "未开始结算,请先上传结算单并确认");
|
if (entity.SettlementStatus == EnumTaskSettlementStatus.Completed) throw Oops.Oh(EnumErrorCodeType.s510, "已结算");
|
entity.SettlementStatus = EnumTaskSettlementStatus.InProcess;
|
entity.SettlementStartTime = DateTime.Now;
|
foreach (var user in entity.TaskInfoUsers)
|
{
|
if (user.SettlementStatus == EnumTaskSettlementStatus.Wait)
|
{
|
user.SettlementStatus = EnumTaskSettlementStatus.InProcess;
|
}
|
}
|
var wallet = await repEnterpriseWallet.AsQueryable()
|
.Where(it => it.EnterpriseId == entity.EnterpriseId && it.Access == EnumEnterpriseWalletAccess.Alipay)
|
.FirstOrDefaultAsync();
|
if (wallet == null) throw Oops.Oh(EnumErrorCodeType.s404, "企业钱包");
|
if (wallet.SignStatus != EnumEnterpriseWalletSignStatus.Normal) throw Oops.Oh(EnumErrorCodeType.s404, "企业钱包未签约");
|
if (wallet.AccountBookStatus != EnumEnterpriseWalletAccountBookStatus.Normal) throw Oops.Oh(EnumErrorCodeType.s404, "企业钱包记账本未开通");
|
var response = alipayUtils.FundAccountbookQuery(new AlipayFundAccountbookQueryModel
|
{
|
AccountBookId = wallet.AccountBookId,
|
SceneCode = "SATF_FUND_BOOK",
|
MerchantUserId = wallet.Code,
|
});
|
if (response.IsError) throw Oops.Oh(EnumErrorCodeType.s510, response.SubMsg ?? response.Msg);
|
wallet.Balance = response.AvailableAmount.ToDecimal() ?? 0;
|
await repEnterpriseWallet.UpdateAsync(wallet);
|
|
var amount = await TaskInfoRepository.GetQueryable(rep, false, logier)
|
.Where(it =>
|
it.EnterpriseId == entity.EnterpriseId
|
&& it.Id != request.TaskInfoId
|
&& it.SettlementStatus == EnumTaskSettlementStatus.InProcess
|
&& it.ActualSettlementAmount.HasValue)
|
.SumAsync(it => it.ActualSettlementAmount!.Value);
|
amount += entity.ActualSettlementAmount!.Value;
|
if (wallet.Balance < amount)
|
throw Oops.Oh(EnumErrorCodeType.s510, "企业钱包余额不足");
|
|
await rep.UpdateAsync(entity);
|
return entity.Id;
|
}
|
|
private async Task BuildCode(TaskInfo entity)
|
{
|
entity.Code = $"{DateTime.Now:yyyyMMddHHmm}{new Random(IDGen.NextID().GetHashCode()).Next(1000, 9999)}";
|
var exist = await rep.AsQueryable().AsNoTracking()
|
.AnyAsync(it => it.EnterpriseId == entity.EnterpriseId && it.Code == entity.Code);
|
if (exist) await BuildCode(entity);
|
}
|
}
|
}
|