sunpengfei
2 天以前 1c1761d54822e8bc89744e8e4e5c9d22db4a461d
FlexJobApi.Core/Jobs/CompleteTaskSettlementT1Job.cs
@@ -1,10 +1,12 @@
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;
@@ -23,12 +25,16 @@
            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)]
@@ -37,39 +43,19 @@
            var env = App.GetConfig<string>("Environment");
            if (env != "Local")
            {
                var now = DateTime.Now;
                var q = rep.AsQueryable()
                    .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();
                var tasks = await GetTasks();
                var enterpriseIds = tasks.DistinctSelect(it => it.EnterpriseId);
                var taskIds = tasks.DistinctSelect(it => it.Id);
                var taskUsers = await repTaskInfoUser
                    .Where(it => taskIds.Contains(it.TaskInfoId) && it.SettlementStatus == EnumTaskSettlementStatus.InProcess)
                    .ToListAsync();
                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);
                }
                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 wallet = wallets.FirstOrDefault(it => it.EnterpriseId == task.EnterpriseId);
                        var enterpriseWallet = enterpriseWallets.FirstOrDefault(it => it.EnterpriseId == task.EnterpriseId);
                        task.SettlementStatus = EnumTaskSettlementStatus.Completed;
                        task.SettlementTime = DateTime.Now;
                        await rep.UpdateNowAsync(task);
@@ -81,79 +67,286 @@
                            user.SettlementTime = DateTime.Now;
                            await repTaskInfoUser.UpdateNowAsync(user);
                            var order = new EnterpriseWalletTransaction();
                            order.Type = EnumEnterpriseWalletTransactionType.Recharge;
                            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 = EnumEnterpriseWalletTransactionStatus.WaitSubmit;
                            order.Balance = wallet.Balance;
                            order.ReceiveName = user.ReceiveName;
                            order.ReceiveAccount = user.ReceiveAccount;
                            await SetCode(order);
                            await repEnterpriseWalletTransaction.InsertNowAsync(order);
                            var userWallet = await AddUserWalletTransactionIncome(userWallets, task, user);
                            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"
                                    ? EnumEnterpriseWalletTransactionStatus.Success
                                    : response.Status == "DEALING"
                                    ? EnumEnterpriseWalletTransactionStatus.Dealing
                                    : response.Status == "REFUND"
                                    ? EnumEnterpriseWalletTransactionStatus.Refund
                                    : EnumEnterpriseWalletTransactionStatus.Fail;
                                await repEnterpriseWalletTransaction.UpdateNowAsync(order);
                            }
                            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)}";
@@ -165,5 +358,16 @@
            }
        }
        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);
            }
        }
    }
}