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