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
{
///
/// 完成任务结算T+1
///
public class CompleteTaskSettlementT1Job(
IRepository rep,
IRepository repTaskInfoUser,
IRepository repEnterpriseWallet,
IRepository repEnterpriseWalletTransaction,
IRepository repUserWallet,
IRepository repUserWalletTransaction,
AlipayUtils alipayUtils
) : IJob
{
private readonly IRepository rep = rep;
private readonly IRepository repTaskInfoUser = repTaskInfoUser;
private readonly IRepository repEnterpriseWallet = repEnterpriseWallet;
private readonly IRepository repUserWallet = repUserWallet;
private readonly IRepository repUserWalletTransaction = repUserWalletTransaction;
private readonly AlipayUtils alipayUtils = alipayUtils;
[UnitOfWork(false)]
public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
{
var env = App.GetConfig("Environment");
if (env != "Local")
{
var tasks = await GetTasks(env);
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);
}
}
}
}
}
///
/// 更新用户钱包提现记录
///
///
///
///
///
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);
}
}
///
/// 添加用户钱包提现记录
///
///
///
///
///
private async Task 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;
}
///
/// 添加用户钱包收入记录
///
///
///
///
///
private async Task AddUserWalletTransactionIncome(List 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;
}
///
/// 添加企业钱包转账记录
///
///
///
///
///
private async Task 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;
}
///
/// 查询用户钱包
///
///
///
private async Task> GetUserWallets(List userIds)
{
var wallets = await repUserWallet.AsQueryable().AsNoTracking()
.Where(it => userIds.Contains(it.UserId))
.ToListAsync();
return wallets;
}
///
/// 查询企业钱包
///
///
///
private async Task> GetEnterpriseWallets(List 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;
}
///
/// 查询任务用户
///
///
///
private async Task> GetTaskUsers(List taskIds)
{
var taskUsers = await repTaskInfoUser
.Include(it => it.EnterpriseEmployee)
.Where(it =>
taskIds.Contains(it.TaskInfoId)
&& it.SettlementStatus == EnumTaskSettlementStatus.InProcess)
.ToListAsync();
return taskUsers;
}
///
/// 查询任务
///
///
///
private async Task> GetTasks(string env)
{
var now = DateTime.Now;
var q = rep.AsQueryable()
.Include(it => it.Enterprise)
.Where(it => it.SettlementStatus == EnumTaskSettlementStatus.InProcess);
var minTime = env == "Test"
? 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);
}
}
}
}