using Aop.Api.Domain;
|
using Azure;
|
using Furion;
|
using Furion.DatabaseAccessor;
|
using Furion.DistributedIDGenerator;
|
using Furion.FriendlyException;
|
using Furion.Schedule;
|
using Microsoft.EntityFrameworkCore;
|
using StackExchange.Redis;
|
using System;
|
using System.Collections.Generic;
|
using System.Linq;
|
using System.Text;
|
using System.Threading;
|
using System.Threading.Tasks;
|
using static Microsoft.AspNetCore.Razor.Language.TagHelperMetadata;
|
|
namespace FlexJobApi.Core
|
{
|
/// <summary>
|
/// 完成任务结算T+1
|
/// </summary>
|
public class CompleteTaskSettlementT1Job(
|
IRepository<TaskInfo> rep,
|
IRepository<TaskInfoUser> repTaskInfoUser,
|
IRepository<EnterpriseWallet> repEnterpriseWallet,
|
IRepository<EnterpriseWalletTransaction> repEnterpriseWalletTransaction,
|
IRepository<UserWallet> repUserWallet,
|
IRepository<UserWalletTransaction> repUserWalletTransaction,
|
AlipayUtils alipayUtils
|
) : IJob
|
{
|
private readonly IRepository<TaskInfo> rep = rep;
|
private readonly IRepository<TaskInfoUser> repTaskInfoUser = repTaskInfoUser;
|
private readonly IRepository<EnterpriseWallet> repEnterpriseWallet = repEnterpriseWallet;
|
private readonly IRepository<UserWallet> repUserWallet = repUserWallet;
|
private readonly IRepository<UserWalletTransaction> repUserWalletTransaction = repUserWalletTransaction;
|
private readonly AlipayUtils alipayUtils = alipayUtils;
|
|
[UnitOfWork(false)]
|
public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
|
{
|
var env = App.GetConfig<string>("Environment");
|
if (env != "Local")
|
{
|
var tasks = await GetTasks();
|
var enterpriseIds = tasks.DistinctSelect(it => it.EnterpriseId);
|
var taskIds = tasks.DistinctSelect(it => it.Id);
|
var taskUsers = await GetTaskUsers(taskIds);
|
var userIds = taskUsers.DistinctSelect(it => it.EnterpriseEmployee.UserId.Value);
|
var userWallets = await GetUserWallets(userIds);
|
var enterpriseWallets = await GetEnterpriseWallets(enterpriseIds);
|
if (tasks.IsNotNull())
|
{
|
foreach (var task in tasks)
|
{
|
var enterpriseWallet = enterpriseWallets.FirstOrDefault(it => it.EnterpriseId == task.EnterpriseId);
|
|
task.SettlementStatus = EnumTaskSettlementStatus.Completed;
|
task.SettlementTime = DateTime.Now;
|
await rep.UpdateNowAsync(task);
|
|
var users = taskUsers.Where(it => it.TaskInfoId == task.Id).ToList();
|
foreach (var user in users)
|
{
|
user.SettlementStatus = EnumTaskSettlementStatus.Completed;
|
user.SettlementTime = DateTime.Now;
|
await repTaskInfoUser.UpdateNowAsync(user);
|
|
var userWallet = await AddUserWalletTransactionIncome(userWallets, task, user);
|
|
var withdraw = await AddUserWalletTransactionWithdraw(userWallet, task, user);
|
|
var transfer = await AddEnterpriseWalletTransactionTransfer(enterpriseWallet, task, user);
|
|
await UpdateUserWalletTransactionWithdraw(userWallet, withdraw, transfer);
|
}
|
}
|
}
|
}
|
}
|
|
/// <summary>
|
/// 更新用户钱包提现记录
|
/// </summary>
|
/// <param name="wallet"></param>
|
/// <param name="withdraw"></param>
|
/// <param name="transfer"></param>
|
/// <returns></returns>
|
private async Task UpdateUserWalletTransactionWithdraw(UserWallet wallet, UserWalletTransaction withdraw, EnterpriseWalletTransaction transfer)
|
{
|
withdraw.EnterpriseWalletTransactionId = transfer.Id;
|
withdraw.TransactionStatus = transfer.TransactionStatus;
|
withdraw.TransDate = transfer.TransDate;
|
if (withdraw.TransactionStatus == EnumWalletTransactionStatus.Success)
|
{
|
withdraw.ActualAmount = withdraw.Amount;
|
}
|
else
|
{
|
withdraw.ActualAmount = 0;
|
|
var order = new UserWalletTransaction();
|
order.WalletId = wallet.Id;
|
order.Type = EnumUserWalletTransactionType.Income;
|
order.OperatorUserId = withdraw.OperatorUserId;
|
order.OperatorTime = withdraw.OperatorTime;
|
order.Title = $"收入-提现失败退款";
|
order.Amount = withdraw.Amount;
|
order.ActualAmount = order.Amount;
|
order.Balance = wallet.Balance;
|
order.AfterBalance = wallet.Balance + order.Amount;
|
order.TransDate = DateTime.Now;
|
order.TransactionStatus = EnumWalletTransactionStatus.Success;
|
await SetCode(order);
|
await repUserWalletTransaction.InsertNowAsync(order);
|
|
wallet.Balance = order.AfterBalance;
|
await repUserWallet.UpdateNowAsync(wallet);
|
}
|
}
|
|
/// <summary>
|
/// 添加用户钱包提现记录
|
/// </summary>
|
/// <param name="wallet"></param>
|
/// <param name="task"></param>
|
/// <param name="user"></param>
|
/// <returns></returns>
|
private async Task<UserWalletTransaction> AddUserWalletTransactionWithdraw(UserWallet wallet, TaskInfo task, TaskInfoUser user)
|
{
|
wallet.Balance -= user.ActualSettlementAmount ?? 0;
|
await repUserWallet.UpdateNowAsync(wallet);
|
|
var order = new UserWalletTransaction();
|
order.WalletId = wallet.Id;
|
order.Type = EnumUserWalletTransactionType.Withdraw;
|
order.OperatorUserId = task.SettlementOperatorUserId;
|
order.OperatorTime = task.SettlementStartTime;
|
order.Title = $"提现-支付宝提现";
|
order.Amount = user.ActualSettlementAmount ?? 0;
|
order.Balance = wallet.Balance;
|
order.AfterBalance = wallet.Balance - order.Amount;
|
order.ReceiveName = user.ReceiveName;
|
order.ReceiveAccount = user.ReceiveAccount;
|
order.TransDate = DateTime.Now;
|
order.TransactionStatus = EnumWalletTransactionStatus.Dealing;
|
await SetCode(order);
|
await repUserWalletTransaction.InsertNowAsync(order);
|
return order;
|
}
|
|
/// <summary>
|
/// 添加用户钱包收入记录
|
/// </summary>
|
/// <param name="wallets"></param>
|
/// <param name="task"></param>
|
/// <param name="user"></param>
|
/// <returns></returns>
|
private async Task<UserWallet> AddUserWalletTransactionIncome(List<UserWallet> wallets, TaskInfo task, TaskInfoUser user)
|
{
|
var wallet = wallets.FirstOrDefault(it => it.UserId == user.EnterpriseEmployee.UserId);
|
if (wallet == null)
|
{
|
wallet = new UserWallet();
|
wallet.UserId = user.EnterpriseEmployee.UserId.Value;
|
await repUserWallet.InsertNowAsync(wallet);
|
}
|
var order = new UserWalletTransaction();
|
order.WalletId = wallet.Id;
|
order.Type = EnumUserWalletTransactionType.Income;
|
order.TaskUserId = user.Id;
|
order.EnterpriseName = task.Enterprise.EnterpriseName;
|
order.SettlementTime = user.SettlementTime;
|
order.SettlementAmount = user.SettlementAmount;
|
order.OperatorUserId = task.SettlementOperatorUserId;
|
order.OperatorTime = task.SettlementStartTime;
|
order.Title = $"收入-{order.EnterpriseName}";
|
order.Amount = user.ActualSettlementAmount ?? 0;
|
order.ActualAmount = order.Amount;
|
order.Balance = wallet.Balance;
|
order.AfterBalance = wallet.Balance + order.Amount;
|
order.TransDate = DateTime.Now;
|
order.TransactionStatus = EnumWalletTransactionStatus.Success;
|
await SetCode(order);
|
await repUserWalletTransaction.InsertNowAsync(order);
|
|
wallet.Balance = order.AfterBalance;
|
await repUserWallet.UpdateNowAsync(wallet);
|
|
return wallet;
|
}
|
|
/// <summary>
|
/// 添加企业钱包转账记录
|
/// </summary>
|
/// <param name="wallet"></param>
|
/// <param name="task"></param>
|
/// <param name="user"></param>
|
/// <returns></returns>
|
private async Task<EnterpriseWalletTransaction> AddEnterpriseWalletTransactionTransfer(EnterpriseWallet wallet, TaskInfo task, TaskInfoUser user)
|
{
|
var order = new EnterpriseWalletTransaction();
|
order.Type = EnumEnterpriseWalletTransactionType.Transfer;
|
order.WalletId = wallet.Id;
|
order.TaskUserId = user.Id;
|
order.Amount = user.ActualSettlementAmount ?? 0;
|
order.Remark = user.SettlementRemark;
|
order.ProductCode = "SINGLE_TRANSFER_NO_PWD";
|
order.BizScene = "ENTRUST_TRANSFER";
|
order.TransactionStatus = EnumWalletTransactionStatus.WaitSubmit;
|
order.Balance = wallet.Balance;
|
order.AfterBalance = wallet.Balance - order.Amount;
|
order.OperatorUserId = task.SettlementOperatorUserId;
|
order.OperatorTime = task.SettlementStartTime;
|
order.ReceiveUserId = user.EnterpriseEmployee.UserId;
|
order.ReceiveName = user.ReceiveName;
|
order.ReceiveAccount = user.ReceiveAccount;
|
await SetCode(order);
|
await repEnterpriseWalletTransaction.InsertNowAsync(order);
|
|
var response = alipayUtils.FundTransUniTransfer(new AlipayFundTransUniTransferModel
|
{
|
OutBizNo = order.Code,
|
TransAmount = order.Amount.ToString(),
|
ProductCode = order.ProductCode,
|
BizScene = order.BizScene,
|
PayeeInfo = new Participant
|
{
|
IdentityType = "ALIPAY_LOGON_ID",
|
Identity = order.ReceiveAccount,
|
Name = order.ReceiveName,
|
},
|
PayerInfo = new Participant
|
{
|
IdentityType = "ACCOUNT_BOOK_ID",
|
Identity = wallet.AccountBookId,
|
ExtInfo = new
|
{
|
agreement_no = wallet.AgreementNo,
|
}.ToJson(),
|
},
|
OrderTitle = order.Remark,
|
Remark = order.Remark,
|
BusinessParams = new
|
{
|
withdraw_timeliness = "T0"
|
}.ToJson()
|
}, "/api/user/enterpriseWallet/alipayFundTransOrderChangedNotify");
|
if (response.IsError)
|
{
|
order.ErrorCode = response.Code;
|
order.FailReason = response.SubMsg ?? response.Msg;
|
await repEnterpriseWalletTransaction.UpdateNowAsync(order);
|
}
|
else
|
{
|
order.OrderId = response.OrderId;
|
order.PayFundOrderId = response.PayFundOrderId;
|
order.SettleSerialNo = response.SettleSerialNo;
|
order.TransDate = response.TransDate.ToDateTime();
|
order.Link = response.Link;
|
order.Status = response.Status;
|
order.SubStatus = response.SubStatus;
|
order.TransactionStatus = response.Status == "SUCCESS"
|
? EnumWalletTransactionStatus.Success
|
: response.Status == "DEALING"
|
? EnumWalletTransactionStatus.Dealing
|
: response.Status == "REFUND"
|
? EnumWalletTransactionStatus.Refund
|
: EnumWalletTransactionStatus.Fail;
|
await repEnterpriseWalletTransaction.UpdateNowAsync(order);
|
}
|
return order;
|
}
|
|
/// <summary>
|
/// 查询用户钱包
|
/// </summary>
|
/// <param name="userIds"></param>
|
/// <returns></returns>
|
private async Task<List<UserWallet>> GetUserWallets(List<Guid> userIds)
|
{
|
var wallets = await repUserWallet.AsQueryable().AsNoTracking()
|
.Where(it => userIds.Contains(it.UserId))
|
.ToListAsync();
|
return wallets;
|
}
|
|
/// <summary>
|
/// 查询企业钱包
|
/// </summary>
|
/// <param name="enterpriseIds"></param>
|
/// <returns></returns>
|
private async Task<List<EnterpriseWallet>> GetEnterpriseWallets(List<Guid> enterpriseIds)
|
{
|
var wallets = await repEnterpriseWallet.AsQueryable()
|
.Where(it => enterpriseIds.Contains(it.EnterpriseId) && it.Access == EnumEnterpriseWalletAccess.Alipay)
|
.ToListAsync();
|
foreach (var wallet in wallets)
|
{
|
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.UpdateNowAsync(wallet);
|
}
|
return wallets;
|
}
|
|
/// <summary>
|
/// 查询任务用户
|
/// </summary>
|
/// <param name="taskIds"></param>
|
/// <returns></returns>
|
private async Task<List<TaskInfoUser>> GetTaskUsers(List<Guid> taskIds)
|
{
|
var taskUsers = await repTaskInfoUser
|
.Include(it => it.EnterpriseEmployee)
|
.Where(it =>
|
taskIds.Contains(it.TaskInfoId)
|
&& it.SettlementStatus == EnumTaskSettlementStatus.InProcess)
|
.ToListAsync();
|
return taskUsers;
|
}
|
|
/// <summary>
|
/// 查询任务
|
/// </summary>
|
/// <param name="env"></param>
|
/// <returns></returns>
|
private async Task<List<TaskInfo>> GetTasks()
|
{
|
var now = DateTime.Now;
|
var q = rep.AsQueryable()
|
.Include(it => it.Enterprise)
|
.Where(it => it.SettlementStatus == EnumTaskSettlementStatus.InProcess);
|
var minTime = App.GetConfig<string>("Task:SettlementTime") == "T0"
|
? now.AddMinutes(-5)
|
: now.AddDays(-1);
|
q = q.Where(it => it.SettlementStartTime.HasValue && it.SettlementStartTime < minTime);
|
var tasks = await q.ToListAsync();
|
return tasks;
|
}
|
|
private async Task SetCode(EnterpriseWalletTransaction entity)
|
{
|
entity.Code = $"{DateTime.Now:yyyyMMddHHmmss}{new Random(IDGen.NextID().GetHashCode()).Next(1000, 9999)}";
|
var exist = await repEnterpriseWalletTransaction.AsQueryable().AsNoTracking()
|
.AnyAsync(it => it.Code == entity.Code);
|
if (exist)
|
{
|
await SetCode(entity);
|
}
|
}
|
|
private async Task SetCode(UserWalletTransaction entity)
|
{
|
entity.Code = $"{DateTime.Now:yyyyMMddHHmmss}{new Random(IDGen.NextID().GetHashCode()).Next(1000, 9999)}";
|
var exist = await repUserWalletTransaction.AsQueryable().AsNoTracking()
|
.AnyAsync(it => it.Code == entity.Code);
|
if (exist)
|
{
|
await SetCode(entity);
|
}
|
}
|
|
}
|
}
|